解决make编译链接动态库错误:libxx.so: undefined reference to xx
最近在写一个Makefile,调试时遇到了libsrcpbl.so: undefined reference to gcProgramName
的问题。在这个Makefile脚本里面,终极目标是通过链接一个自定义的动态库libsrcpbl.so
生成一个ELF目标文件。
由于链接生成libsrcpbl.so动态库的.o文件比较多,无法定位具体的错误程序文件和位置,所以折腾了较长时间。
1 场景再现
为了能快速定位出错的位置,自己写了一个很简单的测试程序test.c,该程序调用了libsrcpbl.so动态库中的一个自定义的公共头文件pbl_global.h
。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
接着使用make
命令编译链接生成目标ELF文件test,但是在ld链接自定义的动态库libsrcpbl.so的时候报错。为了减少干扰
,还可以把pbl_global.h头文件引用去掉。也就是tst.c中是一个及其普通的程序,与libsrcpbl.so中的数据完全没关系,但是还是报出同样的错误:
[root@typecodes test]# make
gcc -std=c99 -D_GNU_SOURCE -g -Wall -I /root/gcc_test/tcp_msg/include/ -I /root/gcc_test/tcp_msg/include/CommAPI/ -I /root/gcc_test/tcp_msg/include/pbl/ -o /root/gcc_test/tcp_msg/src/test/tst.o -c tst.c
g++ -std=c99 -D_GNU_SOURCE /root/gcc_test/tcp_msg/src/test/tst.o -L /root/gcc_test/tcp_msg/lib -lsrcpbl -Xlinker "-(" -Xlinker "-)" -o /root/gcc_test/tcp_msg/bin/test
/root/gcc_test/tcp_msg/lib/libsrcpbl.so: undefined reference to `gcProgramName'
collect2: error: ld returned 1 exit status
make: *** [/root/gcc_test/tcp_msg/bin/test] Error 1
2 查找 libsrcpbl.so: undefined reference to gcProgramName 的原因
通过make显示的内容,基本判断Makefile文件是正确的。用nm libsrcpbl.so
命令查看一下链接的动态库,结果如下:
##### 使用nm查看动态库
[root@typecodes test]# nm -A /root/gcc_test/tcp_msg/lib/libsrcpbl.so|grep gcProgramName
/root/gcc_test/tcp_msg/lib/libsrcpbl.so: U gcProgramName
[root@typecodes test]#
根据上图中的信息,结合前文《Unix系统中nm命令展示目标文件符号的方法》nm命令的man手册关于符号U
的说明,推测可能原因:libsrcpbl.so动态库文件中存在gcProgramName符号(即变量),需要从test.o对象文件中链接进来,但是test.c程序中没有定义gcProgramName变量,所以报错了。
于是查看原工程中的头文件pbl_global.h,果然发现了gcProgramName是一个外部全局变量,其声明如下:
extern char gcProgramName[20 + 1];
接着发现生成这个libsrcpbl.so动态库的一个源程序中,通过引用头文件pbl_global.h,然后直接使用了这个外部全局变量gcProgramName,因此需要在tst.c对这个变量进行定义。
2 解决方法
找到原因后,解决就很简单了:只要在test.c程序中定义这个外部全局变量gcProgramName即可。
1 2 3 4 5 6 7 8 9 10 11 |
|
最后重新make一下,链接生成ELF文件成功!
4 总结
在make编译链接某个动态库lxx.so时,如果报libxx.so: undefined reference to xx
的话,很可能是由下面两种原因引起的。Unix/Linux系统中使用nm
、objdump
和readelf
命令可以辅助调试目标文件。
1、链接的动态库中存在只做了声明的自定义的函数/全局变量,但是在其它对象文件中没有实现定义;
2、链接生成的目标文件中引用了某动态库的自定义函数/全局变量,但是没有通过`-lXX`选项链接进来。
Comments »