在 Qt Creator 中自动重建依赖关系

Automatically rebuild dependencies in Qt Creator

Qt Creator (4.6.1) 快把我逼疯了。我的申请分为 3 个部分:

当我更改库中的文件并重建应用程序时,编译器不会重新编译库,而是链接到旧版本的库。

此外,当我更改库、重新编译它然后编译应用程序时,没有编译发生,因为它使用缓存的应用程序。

有设置可以改变吗?这是我的项目文件:

TEMPLATE = subdirs

SUBDIRS += \
    app \
    lib_mylib \
    tests

app.depends = lib_mylib
tests.depends = lib_mylib

lib 构建为静态库:

TEMPLATE = lib
TARGET = mylib
CONFIG += staticlib

我已经使用 CONFIG += ordered、DEPENDPATH 和 PRE_TARGETDEPS 来解决同样的问题。它适用于 linux 和 MSVC 的胜利。试试吧。

在您的项目 pro 文件中添加:

CONFIG += ordered

P.S.: 你的库应该首先列出。喜欢:

SUBDIRS += \
    lib \
    app \
    tests

在您的 exe .pro 文件中添加正确的路径:

DEPENDPATH += $$PWD/../lib
PRE_TARGETDEPS += $$OUT_PWD/../lib/liblib.a

更多选项和标志待发现here

我知道这有点晚了,但我想给出更广泛的答案,为什么会发生这种情况以及其他解决方案究竟有何帮助。

一个可行的解决方案是:您可以像以前一样使用 b.depends += aCONFIG += ordered 添加 PRE_TARGETDEPS += ...b. (旁注:不推荐使用 ordered,因为它会大大减慢您的构建速度并且通常被认为是不好的做法)

TL;DR: 需要这种特殊组合的原因:subdirs 项目中的 app.depends = lib_mylib 确保在构建应用程序之前始终构建库是启动,PRE_TARGETDEPS 确保每次库更改时应用程序实际上正在重新构建。


详细解释:

要了解为什么会这样,我们需要了解 qmake 如何处理子目录。 qmake 是一个 Makefile 生成器,这意味着它只会创建 makefile。所以所有的依赖排序都必须使用 make prodives 方法来完成。要了解发生了什么,我们必须首先了解 make 的工作原理。

在make中,依赖比较简单:

some_target: dep1 dep2 dep3
    some_command

意味着如果你想创建some_target,make会先创建dep1dep2dep3未指定的顺序。完成所有 3 个后,将执行 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 并且您将看到消息。

现在对于 subdirs 项目,这变得有点复杂,因为我们现在需要多个不同的 makefile 之间的依赖关系!这通常通过递归调用来解决。对于您的示例,qmake 创建以下代码(简化):

lib_mylib: FORCE
    $(MAKE) lib_mylib/Makefile

app: lib_mylib FORCE
    $(MAKE) app/Makefile

如预期的那样,此代码将首先创建 lib_mylib(阻塞,即 lib_mylib 将仅在构建整个库后完成),然后再创建 appFORCE 依赖性确保此命令始终是 运行,即使目标已经存在。


有了这些基础知识,我们现在可以重建 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。 运行 进行第二次重建 app - 但那很不方便。

所以,这就是我们需要将这两者结合起来的原因。我们需要控制不同 makefile 的执行顺序,并从其他 makefile 引用创建的工件 - 而这正是这些命令所做的。

不管我尝试过的冗长且易于理解的解释

TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS += \
    dynamiclib \
    staticlib \
    testlibs

对于我的小而短的项目,它对我有用。