为什么在重建时构建后,源代码中的更改并不总是反映在机器代码中?

时间:2011-03-29 09:28:40

标签: c++ qt build

有时当我更改Qt项目中的代码(使用mingw32的Qt Creator 2.1.0)时,更改在构建之后不会反映在生成的机器代码中。这种情况主要发生在我更改构造函数中的默认值或方法/构造函数中的参数顺序时。通常,完全重建会修复(但需要几分钟)。

我通过在构建之前删除生成的可执行文件或库来帮助自己,这似乎在大多数时间都有帮助。这是否意味着在链接目标文件时会出现问题?

我来自java / .net,我习惯了不同的行为。如果有人能解释我的错误和/或指向一些相关文章,我会很高兴。

谢谢!

4 个答案:

答案 0 :(得分:15)

通常,在标题更改后,应重建包含该标题的所有源文件。 但是,qmake在这方面有点特殊,你需要为当前目录以外的包含文件夹设置DEPENDPATH。例如,如果你有

INCLUDEPATH += somepath_in_my_project

还要添加

DEPENDPATH += some_path_in_my_project

仅使用DEPENDPATH,如果some_path_in_my_project中的某些标题发生更改(如果它们包含该标题),则会重建.pro文件构建的文件!

我建议为每个INCLUDEPATH行添加一个相同的DEPENDPATH行,除非你包含一些你不希望改变的系统目录。

修改

静态链接qmake时存在类似的问题:如果静态lib foo.a发生更改,则不会重新链接与其链接的二进制文件。这是QMake中的一个错误,没有生成正确的依赖项。

我在以前的项目中找到的解决方法:

static:unix:TARGETDEPS += path_to_my/somestaticlib.a
static:win32:TARGETDEPS += path_to_my/somestaticlib.lib

修改编辑:

从某个时间开始(Qt 5?),上面的代码应该使用POST_TARGETDEPS而不是TARGETDEPS。

答案 1 :(得分:3)

最常见的情况是破坏的依赖关系。在函数的默认参数的特定情况下,它们在调用位置被解析,因此如果您只是重新编译该函数,则代码将完全相同。您需要重新编译调用者。如果项目中的依赖项不正确并且构建系统没有检测到它需要重新编译调用者,并且只重新编译被调用者,那么您将看到该效果。

分析依赖关系并修复它们。

示例:

// what you write                  // what the compiler generates
void foo( int i = 0 ) {}           void foo( int i ) {} // default removed
int main() {                       int main() {
   foo();                             foo( 0 );         // compiler injected
}                                  }

答案 2 :(得分:3)

如果要在项目文件中列出所有相关的头文件,则不应该这样做。但实际上它总是发生,因为QMAKE是错误的(它已经知道依赖关系生成多年未固定的问题)。所以最好清理它并重新编译或使用Cmake。此外,QMAKE对源文件和头文件之间的依赖关系一无所知(并且几乎没有检测到任何内容),这可能会导致类似的问题。

答案 3 :(得分:-1)

如果您的Makefile(或您的道德等同于Makefile)缺少相关信息,那么您可能会获得不同步的构建。对于#include "header.h"的每个文件,您需要确保Makefileheader.h作为对该文件的依赖。

以下是Makefile我得到的一小部分:

parser_yacc.c parser_yacc.h: parser_yacc.y parser.h
        $(YACC) $(YFLAGS) -o parser_yacc.c parser_yacc.y

parser_lex.c: parser_lex.l parser_yacc.h parser.h
        $(LEX) ${LEXFLAGS} -o$@ $<

parser_lex.o: parser_lex.c parser.h parser_yacc.h
        $(CC) $(EXTRA_CFLAGS) -c -o $@ $<

parser_misc.o: parser_misc.c parser.h parser_yacc.h af_names.h cap_names.h
        $(CC) $(EXTRA_CFLAGS) -c -o $@ $<

每个目标文件显然取决于相应的源文件和头文件。如果我们忘记了cap_names.h,则在修改parser_misc.o时不会重建cap_names.h。虫子随之而来。

我担心修复过程冗长乏味:检查每个文件,列出其依赖项,并向Makefile添加缺少的依赖项。在Linux平台上,您可以使用strace(1)工具来发现编译器在编译每个源文件时需要打开哪些文件,并改进与该列表的依赖关系。我不知道Windows上是否存在任何类似的工具,但在潜水之前花几分钟寻找一个工具是值得的。