目录
最近在移植一个项目,从windows移植到Linux,在解决掉编译前期问题后,在链接的时候碰到了各种的“ undefined reference to ”问题。
检查所依赖的.h文件是否 #include <>
首先检查所依赖的.h文件是否 #include“xxx.h”
链接时缺少了相关的目标文件(.o)或者库文件(.so)
造成这种情况的原因比较多:
忘记指定目标文件(.o);
忘记指定链接库(-L /xxx/yyy/ -lA);
遗漏指定链接库(B动态库依赖A动态库,链接忘记指定A动态库 -lA)
fun.h
#ifndef __FUN_H__ #define __FUN_H__ int fun(); #endif
fun.cpp
#include "fun.h" int fun() { return 0; }
fun1.h
#ifndef __FUN1_H__ #define __FUN1_H__ int fun1(); #endif
fun1.cpp
#include "fun.h" int fun1() { return fun(); }
缺少链接库
root@localhost:~/test# g++ -fpic -shared fun.cpp -o libfun.so root@localhost:~/test# g++ -fpic -shared fun1.cpp -o libfun1.so root@localhost:~/test# g++ main.cpp -o main -L ./ -I ./ -lfun1 .//libfun1.so: undefined reference to `fun()' collect2: error: ld returned 1 exit status
正确的编译
root@localhost:~/test# g++ -fpic -shared fun.cpp -o libfun.so root@localhost:~/test# g++ -fpic -shared fun1.cpp -o libfun1.so root@localhost:~/test# g++ main.cpp -o main -L ./ -I ./ -lfun1 -lfun root@localhost:~/test#
动态库依赖顺序
上边的例子libfun1.so依赖libfun.so ,编译时错误的顺序会导致“ undefined reference to ”;越基础的库越要放到后边。
错误的顺序
root@localhost:~/test# g++ main.cpp -o main -L ./ -I ./ -lfun -lfun1 .//libfun1.so: undefined reference to `fun()' collect2: error: ld returned 1 exit status
正确的顺序
root@localhost:~/test# g++ main.cpp -o main -L ./ -I ./ -lfun1 -lfun
头文件有函数声明,但cpp文件没有实现
移植项目的时候,有些基础库虽然头文件有函数声明,但动态库没有实现。
稍微修改一下fun1.h 和main.cpp
fun1.h
#ifndef __FUN1_H__ #define __FUN1_H__ int fun1(); int fun2(); #endif
main.cpp
#include <fun1.h> int main() { fun2(); }
编译
root@localhost:~/test# g++ -fpic -shared fun.cpp -o libfun.so root@localhost:~/test# g++ -fpic -shared fun1.cpp -o libfun1.so root@localhost:~/test# g++ main.cpp -o main -L ./ -I ./ -lfun1 -lfun /tmp/cc23ESs7.o: In function `main': main.cpp:(.text+0x5): undefined reference to `fun2()' collect2: error: ld returned 1 exit status
用别人的库时,往往没有源文件,这时候就要利用nm命令或者objdump命令查看.so是否包含报错的符号
root@localhost:~/test# nm libfun.so | grep fun 00000000000007f4 t _GLOBAL__sub_I_fun.cpp 00000000000007a0 T _Z3funv root@localhost:~/test# nm libfun.so | grep fun | c++filt 00000000000007f4 t _GLOBAL__sub_I_fun.cpp 00000000000007a0 T fun()
这里会发现并没有fun2()函数实现,只有fun()的定义。
gcc 和 g++的编译 extern “C”{}
c++支持函数重载,编译器在编译c++代码对函数名的修饰和 编译C代码对函数名的修饰是不一样的。
在使用纯c编译的动态库引用头文件时要加上:
extern "C" { #include "func.h" }
在自己编写动态库时,也要注意头文件和cpp文件的 extern “C” {} 所包含的内容要对应起来。
fun1.h
#ifndef __FUN1_H__ #define __FUN1_H__ #ifdef __cplusplus extern "C" { #endif int fun1(); int fun2(); #ifdef __cplusplus } #endif #endif
fun1.cpp
#include "fun.h" #ifdef __cplusplus extern "C" { #endif int fun1() { return fun(); } #ifdef __cplusplus } #endif int fun2() { return 0; }
main.cpp
int main() { fun2(); }
编译
root@localhost:~/test# g++ -fpic -shared fun.cpp -o libfun.so root@localhost:~/test# g++ -fpic -shared fun1.cpp -o libfun1.so root@localhost:~/test# g++ main.cpp -o main -L ./ -I ./ -lfun1 -lfun /tmp/ccQNCmKt.o: In function `main': main.cpp:(.text+0xa): undefined reference to `fun2' collect2: error: ld returned 1 exit status
root@localhost:~/test# nm libfun1.so | grep fun 000000000000085f t _GLOBAL__sub_I_fun1.cpp U _Z3funv 000000000000080b T _Z4fun2v 0000000000000800 T fun1
头文件中fun2()在extern “C”{}里,而实现不在extern “C” {}中, 链接时查找不到fun2,因为声明是C( fun2 ),而实现是C++(_Z4fun2v)
这样的问题只要注意C++用纯C编译的库时引用头文件用extern “C” {}包含;自己编写动态库时头文件和实现文件extern “C” {}包含的内容要对应。