有没有办法在.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
的例子,假设您想添加一个命令来删除所有*~文件:
-
在.pr文件中创建自定义目标。请注意,您必须对.pro文件中的引号和斜杠进行转义。例如,添加:
extraclean.commands = find . -name "*~" -exec rm -v {} \;
-
添加此目标作为您正在修改的目标的依赖项:
distclean.depends = extraclean
这实际上还不会修改
distclean
规则,因为此方法不能用于修改现有规则。然而 -
添加你的新目标和你正在修改的目标作为额外目标:
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
做尽可能多的工作,不要重复它的工作。
为此:
首先,更改
qmake
生成的文件的名称。这可以通过在.pro文件中添加这样一行来实现:MAKEFILE = RealMakefile
这将导致
qmake
输出RealMakefile,而不是Makefile。下一步是使用自定义命令创建自己的
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中未另行定义的任何目标匹配。它只是将处理委托给RealMakefiledistclean
目标是我们添加命令的地方。我们仍然需要委托RealMakefile,但在此之前和之后都可以添加其他命令
- 我们设置
优点:
- 对命令顺序的更多控制。可以在默认配方之前和之后添加命令
缺点:
- 在.pro中不是自包含的
- 不那么可移植:它并没有将Makefile的所有生成都留给
qmake
,而且我实际上也不确定GNUmake
的特定部分是什么(欢迎评论)
因此,虽然这个答案可能有点长,但这两种方法都非常简单。除非命令执行顺序有问题,否则我更喜欢选项1。
另一个解决方案是将要删除的文件添加到QMAKE_CLEAN
和QMAKE_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
命令或某种globbing。