问题描述
在编译时遇到:
|
|
但检查发现不是头文件未包含,和未链接导致的错误,
错误原因挺有意思,记录之。
debug过程
- 第一反应是没有把库链接上
- 所以检查Makefile
$(CXX) $(CFLAGS) $(LIB) -o $@ $^$(LIB)里链接上了需要的库
- 故检查头文件
- 确认包含了头文件
- 头文件在makefile中也正确
- 并且undefined reference to `NS_XXXX:XXXX’
- 在g++错误提示里带上了命名空间,这部分都是在头文件里声明的,所以说明头文件正确包含了
- 怀疑库有问题?
- 网络上建议我用nm命令查看so的符号表,看看这个函数是否正常,于是nm -D 库文件,查看了下,结果函数正常的,包含了提示的那些接口。
- 说明库是没问题的
- 那就还是链接问题
- 怀疑是库路径不对,或者gcc没找到正确的库??
- 尝试改动makefile,
链接一个无关的不存在的库 -lxxx- 编译提示找不到库
- 说明,如果库不存在,或路径里找不到,都会报找不到库的错
- 怀疑是库路径不对,或者gcc没找到正确的库??
- 将链接的那个库去掉,不链接了
- 发现报错没有变
- 说明这个库压根 就没有链接上
- 虽然命令写对了,路径也是对的,但g++编译时就是没有链接上这个库
- 问题定位了,google之,虽然之前也google,但是问题没有定位准确,google也是出不来正确的结果
- “c++ 链接动态库 报错,没链上”
- 得到答案:
- 相同的链接库链接时的编译命令,在不同的Linux平台下的不同的gcc版本下表现出不同的效果。它们的代码是一样的,链接的库都是一样的,命令也是一样的,一个是链接成功,而另一个是报错,提示有未定义的引用,即”undefined reference to xxxx”。这类问题报错一般是缺少链接库提示的,只要添加上-lxxx添加上了libxxx即可解决,最多再添加-L/path/to/lib添加正确的搜索库的路径,但我遇到的情况还是不能解决。其实,提示“未定义的引用”说明具有这个函数定义的库没有链接成功,仔细排查后发现,在某些gcc版本下,原来这个居然和链接库在编译或链接的命令中的位置是有关系的。
- 原因就是,-lxxx这个指令放在了test_gcc.c的前面,对于Redhat的高版本的gcc,这个是没有问题的,而对于Ubuntu下的较低版本的问题,就出现问题,必须将链接的库放在需要链接的对象(xxx.c或xxx.o)的后面,gcc才能正确的去链接,编译命令改为:
gcc test_gcc.c -lxxx
这样就都没有问题了,所以在编写Makefile或者写编译链接命令时,均把链接库写在后面就可以保证兼容了。
reference原文
这几天在执行一些Makefile的时候发现,相同的链接库链接时的编译命令,在不同的Linux平台下的不同的gcc版本下表现出不同的效果。它们的代码是一样的,链接的库都是一样的,命令也是一样的,一个是链接成功,而另一个是报错,提示有未定义的引用,即”undefined reference to xxxx”。这类问题报错一般是缺少链接库提示的,只要添加上-lxxx添加上了libxxx即可解决,最多再添加-L/path/to/lib添加正确的搜索库的路径,但我遇到的情况还是不能解决。其实,提示“未定义的引用”说明具有这个函数定义的库没有链接成功,仔细排查后发现,在某些gcc版本下,原来这个居然和链接库在编译或链接的命令中的位置是有关系的。
我们在两个不同平台环境下编译,系统分别为64位Ubuntu和64位Redhat,均使用gcc –version分别显示为:
Ubuntu
gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Redhat
gcc (GCC) 4.8.5
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
编译生成命令均使用:
gcc -lpthread test_gcc.c
Redhat正常通过并且正确运行,而Ubuntu则显示:
|
|
原因就是,-lpthread这个指令放在了test_gcc.c的前面,对于Redhat的高版本的gcc,这个是没有问题的,而对于Ubuntu下的较低版本的问题,就出现问题,必须将链接的库放在需要链接的对象(xxx.c或xxx.o)的后面,gcc才能正确的去链接,编译命令改为:
gcc test_gcc.c -lpthread
这样就都没有问题了,所以在编写Makefile或者写编译链接命令时,均把链接库写在后面就可以保证兼容了。
结论
所以,在使用gcc等编译命令时,如果出现这类错误,可考虑命令中各类成分的位置问题。
特别的,Makefile中有默认的隐式推导规则,比如由很多xxx.o去生成可执行目标的时候,它也有相对应的宏变量来链接上库的,很可能直接就把链接库写在了需要链接对象的前面,造成了出现“未定义的引用”错误,所以咱们为了清晰明了,还是别用隐式推导规则了(谁知道各版本的make是否一致呢),自己手写编译链接命令的好。