将自定义命令添加到 qmake 中的现有目标

Adding custom commands to existing targets in qmake

有没有办法在 .pro 文件中指定要添加到 Makefile 中的标准目标的额外命令qmake 生成?例如,考虑 distclean,可能需要额外的命令来:

我想使用普通目标而不是自定义目标,因为我希望它在我的工作流程中完全透明。也就是说(再次以 distclean 为例),我不想...

我发现 How to add custom targets in a qmake generated Makefile?, but this describes adding custom targets (which is already documented, even back in 4.6) 而不是向现有目标添加规则。虽然它确实包含一些提示,但它们都需要添加新的自定义目标,因为在 Makefile 中多次指定相同的目标会替换(而不是添加)来自先前目标的命令。

我唯一真正想到的尝试是将 target.commands += new commands 添加到 .pro 文件中作为一个疯狂的猜测(例如 distclean.commands += rm \"*~\") .这没有效果。

如何使用 qmake 透明地将自定义命令添加到现有目标?


对于 distclean 示例:虽然 maintainer-clean 也在 "standard target"列表,在实践中我发现它很少被使用,并且在任何情况下 qmake 都不会默认生成它;我觉得不合适

有两种直接的方法可以实现这一点,具体取决于您希望解决方案的独立性/可移植性以及您希望对命令执行顺序的宽松程度。


选项 1

第一个选项是在 .pro 文件中为新命令创建一个自定义目标,然后将该目标作为先决条件添加到您正在修改的标准目标中。回到 distclean 示例,假设您想添加一个命令来删除所有 *~ 文件:

  1. 在您的 .pro 文件中创建自定义目标。请注意,您必须转义 .pro 文件中的引号和斜杠。例如,添加:

    extraclean.commands = find . -name \"*~\" -exec rm -v {} \;
    
  2. 将此目标添加为您正在修改的目标的依赖项:

    distclean.depends = extraclean
    

    这还不会真正修改 distclean 规则,因为此方法不能用于修改现有规则。然而...

  3. 将新目标和正在修改的目标都添加为额外目标:

    QMAKE_EXTRA_TARGETS += distclean extraclean
    

    这会将 distclean 的第二个规范添加到 Makefile,但这是可行的,因为 you can add dependencies to existing targets in make in separate rules, even though you can't add commands that way。如果您还要在 .pro 文件中指定 distclean.commands,您将通过替换其默认配方来破坏现有的 distclean

因此,将所有内容放在 .pro 文件中:

extraclean.commands = find . -name \"*~\" -exec rm -v {} \;
distclean.depends = extraclean
QMAKE_EXTRA_TARGETS += distclean extraclean

其中 extraclean 是一些带有您要添加的命令的自定义目标,distclean 是您希望修改的现有目标。

优点:

  • 完全独立于 .pro 文件中。
  • 尽可能便携,将实际的 Makefile 语法和生成保留到 qmake.

缺点:

  • 您的新命令没有附加到现有的配方。相反,它们发生在满足所有先决条件目标之后,但 现有配方之前。在 distclean 示例中,对于我使用的 qmake 版本,这会将命令放在源代码树清理之后但在 Makefile 本身被删除之前(这是默认配方采取的唯一行动)。这不是本示例的问题,但对您来说可能是个问题。

选项 2

第二个选项是更改 qmake 生成的 Makefile 的名称,并创建您自己的自定义 Makefile 推迟 到生成的,而不是包含 + 覆盖它。这也是一个简单的选择;虽然不像选项 1 那样独立,但它使您能够在默认生成的配方之前和之后执行命令。

您不想包含 + 覆盖现有的 Makefile,因为您不想替换默认配方。如果这样做,您必须重新实现默认值,但这可能是一个问题,因为默认值可能会更改(并且您必须跟上更改)。最好让qmake做尽可能多的工作,不要重复它的工作。

为此:

  1. 首先,更改qmake生成的文件名。这可以通过在 .pro 文件中添加这样一行来完成:

    MAKEFILE = RealMakefile
    

    这将导致 qmake 输出 RealMakefile 而不是 Makefile.

  2. 下一步是使用您的自定义命令创建您自己的 Makefile。但是,这里有一些注意事项。首先,一个完整的例子,再次使用 distclean。在名为 Makefile:

    的文件中
    .DEFAULT_GOAL := all
    
    %:
        @$(MAKE) -f RealMakefile $@
    
    distclean:
        @$(MAKE) -f RealMakefile $@ 
        @find . -name "*~" -exec rm -v {} \;
    

    关于此的一些说明:

    • 我们设置 .DEFAULT_GOAL,否则 distclean 将成为默认值。如果您对 .DEFAULT_GOAL 不满意,另一种方法是使用 @$(MAKE) -f RealMakefile $@ 作为配方指定 all 规则。
    • % 目标匹配未在此 Makefile 中另外定义的任何目标。它只是将处理委托给 RealMakefile.
    • distclean 目标是我们添加命令的地方。我们仍然需要委托给 RealMakefile,但可以在发生之前和之后添加其他命令。

优点:

  • 对命令顺序的更多控制。命令可以在默认配方之前和之后添加。

缺点:

  • .pro.
  • 中不是独立的
  • 不便携:它不会将所有 Makefile 代保留到 qmake,而且我实际上不确定哪些部分是特定于 GNU make 在这里(欢迎评论)。

所以,虽然这个答案可能有点长,但这两种方法都非常简单。除非命令执行顺序有问题,否则我更喜欢选项 1。

另一种解决方案是将要删除的文件添加到 QMAKE_CLEANQMAKE_DISTCLEAN qmake 变量中。

build_tests {
    TINYORM_SQLITE_DATABASE = $$quote($$TINYORM_BUILD_TREE/tests/q_tinyorm_test_1.sqlite3)

    QMAKE_CLEAN = $$TINYORM_SQLITE_DATABASE
    QMAKE_DISTCLEAN = $$TINYORM_SQLITE_DATABASE
}

它只是相关的,你知道什么时候要删除文件,所以在这种情况下,你不能使用 rm 命令或某种通配。