我知道有点晚了,但我想给出更详细的答案,解释为什么会发生这种情况,以及其他解决方案如何帮助。
一个可行的解决方案是:像之前一样使用b.depends += a
,或者使用CONFIG += ordered
并且在b
中添加PRE_TARGETDEPS += ...
。(顺便说一句:不建议使用ordered,因为它可能会极大地减慢构建速度,并且通常被认为是不好的实践)
简而言之: 这种特殊组合需要的原因是:在子目录项目中app.depends = lib_mylib
确保在启动应用程序之前始终先构建库,而PRE_TARGETDEPS
确保每次库更改时都会重新构建应用程序。
长说明:
要理解为什么这样做有效,我们需要了解qmake如何处理子目录。 qmake是一个Makefile生成器,这意味着它只会创建Makefile。所以所有的依赖关系排序必须使用make提供的方法。首先,我们必须理解make的工作方式。
在make中,依赖关系相对简单:
some_target: dep1 dep2 dep3
some_command
这意味着如果您想创建
some_target
,make将首先以未指定的顺序创建
dep1
、
dep2
和
dep3
,一旦这三个都完成后,执行
some_command
。
然而,make会针对文件进行优化。考虑以下情况:
hello.txt:
echo "creating hello"
echo "hello" > hello.txt
hello2.txt: hello.txt
echo "creating hello2"
echo "hello2" > hello2.txt
运行make命令将创建两个文件并打印两个消息。第二次运行不会有任何操作。原因是make跟踪已经创建的文件和文件更改。由于hello.txt已经存在,它不会再次创建。由于hello.txt没有更改,因此无需再次创建hello2.txt。如果你现在外部更改hello.txt的内容并再次运行make,则hello2.txt将重新创建,并且您将看到该消息。
现在对于子目录项目,这变得有点复杂,因为我们现在需要在多个不同的makefile之间建立依赖关系!这通常通过递归调用make来解决。对于您的示例,qmake创建以下代码(简化):
lib_mylib: FORCE
$(MAKE) lib_mylib/Makefile
app: lib_mylib FORCE
$(MAKE) app/Makefile
这段代码将会按照预期创建lib_mylib
(阻塞式,即只有整个库被构建完成后才会完成lib_mylib
的构建),然后再创建app
。使用FORCE
依赖项确保该命令始终运行,即使目标已经存在。
了解了这些基础知识后,我们现在可以重构qmake的运行过程。使用b.depends += a
将生成如上所示的代码 - 它确保所有依赖项按正确顺序构建,但没有其他作用!使用有序配置将自动创建这些依赖规则,因此它们的工作方式在逻辑上没有区别。
然而,这还不足以在lib_mylib
更改时重新构建app
。它只确保在make开始构建app
之前构建lib_mylib
。
为了重新构建app
,我们使用PRE_TARGETDEPS
- 这将向应用程序makefile中的make目标添加一个依赖项,如上所示。
app.exe: mylib.lib:
#linker code
这意味着每次更改
lib_mylib
时,
app
也会被重建。但是,在没有有序配置的情况下使用此功能可能会失败,因为 make 可能会首先尝试构建
app
(如果 lib 没有更改,则什么都不做,或者如果 lib 不存在则会失败),然后重新构建
lib_mylib
。再次运行 make 将重建
app
,但这相当不方便。
所以,这就是为什么我们需要将这两者结合起来。我们需要控制不同 makefile 的执行顺序,并引用另一个 makefile 创建的工件 - 这正是这些命令所做的事情。