在 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 += a
或 CONFIG += 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会先创建dep1
、dep2
和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
将生成如上代码 - 它确保所有依赖项都以正确的顺序构建,但没有别的!使用有序配置将简单地自动创建那些依赖规则,因此它们的工作方式没有逻辑上的区别。
但是,这不足以在 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
对于我的小而短的项目,它对我有用。
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 += a
或 CONFIG += 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会先创建dep1
、dep2
和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
将生成如上代码 - 它确保所有依赖项都以正确的顺序构建,但没有别的!使用有序配置将简单地自动创建那些依赖规则,因此它们的工作方式没有逻辑上的区别。
但是,这不足以在 lib_mylib
更改时实际重建 app
。它只确保在 make 开始构建 app
.
lib_mylib
为了重建 app
,我们使用 PRE_TARGETDEPS
- 这会向应用程序 makefile
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
对于我的小而短的项目,它对我有用。