使用makefile编译C ++代码时遇到一个奇怪的问题。代码首先编译完美。然后我将一个函数参数更改为“const”。如果我然后编译,当代码尝试使用我将参数更改为const的函数时,我将收到错误消息。这可以通过删除所有.o文件然后再次编译来解决,但我很好奇是什么原因导致了这个问题。我的文件是:
MyClass.h
class MyClass {
public:
void fun(double*const c);
};
MyClass.cpp
#include "MyClass.h"
void MyClass::fun(double *const c){
};
Main.cpp的
#include "MyClass.h"
int main(int argc,char* argv[]) {
MyClass foo;
double *bar=new double[2];
foo.fun(bar);
};
生成文件
all: main
main: Main.o MyClass.o
g++ -o a.out Main.o MyClass.o
Main.o: Main.cpp
g++ -c Main.cpp
MyClass.o: MyClass.cpp
g++ -c MyClass.cpp
如果我现在第一次运行make
,一切正常。但后来我将fun
的签名更改为fun(const double *const c)
,收到错误消息
Main.cpp:(.text+0x3b): undefined reference to `MyClass::fun(double*)'
collect2: error: ld returned 1 exit status
Makefile:6: recipe for target 'main' failed
make: *** [main] Error 1
但是,如果我删除所有.o文件然后再次运行make
,它就会编译。
答案 0 :(得分:3)
规则
main.o: Main.cpp
表示main.o
目标文件仅取决于Main.cpp
源文件。 但是 它实际上取决于另一个文件:MyClass.h
头文件。
目标名称的大小写也存在错误。
以上两个问题意味着当您更改头文件MyClass.h
以更新函数签名时,将不会重新创建Main.o
目标文件并仍引用旧函数。
所以规则应该是
Main.o: Main.cpp MyClass.h
当您更改头文件时,该添加将导致Main.o
目标文件被重新编译。
此更改也应针对MyClass.o
目标。
另请注意,main
目标使用MyClass.o
作为依赖项,但在链接时使用MyClass.cpp
源文件,而不是目标文件
目标的名称也应该是生成的文件的名称(例如您的a.out
)。
答案 1 :(得分:0)
问题是,你的Makefile坏了:它忽略了.o
文件不仅依赖于相应的.cpp
文件,还依赖于.h
文件的事实包括。正确的Makefile规则必须包含所有依赖项,包括直接或间接包含的.h
文件。
由于Makefile不完整,make
在定义更改时没有重新编译函数的调用站点,因此陈旧对象仍引用非const函数。由于C ++名称更改,链接器在行为中捕获了它,错误在C中没有被注意到!
为了解决这个问题,我建议花一两个小时阅读这个article on automatic dependency generation,并在Makefile中实现它提供的一些解决方案。完成此操作后,您可能只需将现有解决方案复制到未来项目的Makefile中,否则就会忘记问题。