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



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

  • 删除*~文件
  • 从源树中清除运行时生成的输出文件
  • 等等

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

  • 。。。需要在多项目设置中了解某些Makefiles使用自定义规则而不是distclean
  • 。。。文档自定义规则,即使对于独立项目也是如此,因为distclean已经是众所周知且直观的

我发现如何在qmake生成的Makefile中添加自定义目标?,但这描述了添加自定义目标(早在4.6中就有文档记录),而不是向现有目标添加规则。虽然它确实包含一些提示,但所有提示都需要添加新的自定义目标,因为在Makefile中多次指定同一目标会替换(而不是添加)上一个目标的命令。

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

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


对于distclean示例:虽然maintainer-clean也在"标准目标"列表上,但在实践中,我发现它很少使用,而且在任何情况下,qmake默认不会生成它;我认为它不合适

有两种简单的方法可以实现这一点,这取决于您希望解决方案的自包含性/可移植性以及您希望对命令执行顺序的宽容程度。


选项1

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

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

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

    distclean.depends = extraclean
    

    这实际上还不会修改distclean规则,因为此方法不能用于修改现有规则。然而

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

    QMAKE_EXTRA_TARGETS += distclean extraclean
    

    这将向Makefile添加distclean的第二个规范,但这是有效的,因为您可以在单独的规则中向make中的现有目标添加依赖项,即使您不能以这种方式添加命令。如果您也要在.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,而且我实际上也不确定GNUmake的特定部分是什么(欢迎评论)

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

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

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命令或某种globbing。

最新更新