首页 > 解决方案 > 在 Qt Creator 中自动重建依赖项

问题描述

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

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

此外,当我更改库、重新编译它然后编译应用程序时,不会进行编译,因为它使用缓存的应用程序。

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

TEMPLATE = subdirs

SUBDIRS += \
    app \
    lib_mylib \
    tests

app.depends = lib_mylib
tests.depends = lib_mylib

该库被构建为一个静态库:

TEMPLATE = lib
TARGET = mylib
CONFIG += staticlib

标签: qtcompilationdependenciesqt-creator

解决方案


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

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

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


长解释:

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

在make中,依赖比较简单:

some_target: dep1 dep2 dep3
    some_command

意味着如果你想创建some_target,make 将创建dep1dep2并且dep3首先,以未指定的顺序。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只有在构建整个库后才会完成),然后再创建app。依赖确保此FORCE命令始终运行,即使目标已存在。


考虑到这些基础知识,我们现在可以重构 qmake 发生的事情。使用b.depends += a将生成上述代码 - 它确保所有依赖项都以正确的顺序构建,但仅此而已!使用有序配置将简单地自动创建这些依赖规则,因此它们的工作方式没有逻辑差异。

但是,这还不足以applib_mylib更改时实际重建。它只确保lib_mylib在 make 开始构建之前构建app

为了重建app,我们使用PRE_TARGETDEPS- 这将如前所示的依赖项添加到应用程序 makefile 中的 make 目标。

app.exe: mylib.lib:
    #linker code

这意味着每次lib_mylib更改时,app现在也会重新构建。但是,在没有有序配置的情况下使用它可能会失败,因为 make 可能会首先尝试构建app(它要么什么都不做,因为 lib 没有更改,或者如果 lib 不存在则将失败),然后再重新构建lib_mylib。第二次运行 make 也将重建app- 但那相当不方便。

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


推荐阅读