【原创】Linux下编译链接中常见问题总结
前言
一直以来对Linux下编译链接产生的问题没有好好重视起来,出现问题就度娘一下,很多时候的确是在搜索帮助下解决了BUG,但由于对原因不求甚解,没有细细研究,结果总是在遇到在BUG时弄得手忙脚乱得。
甚至有时候为了一个问题查了半天的资料,好不容易解决了,却因为没有记录下来或者没有弄清楚真实原因,结果第二次碰到还是要去重复前次的折腾,很是尴尬无奈。
虽然,同样的错误信息,其产生的原因不一而足,但是,总结一下终归是好的,使不知变知之,只要不在同一件事情上重复同样的错误,发现的问题越多,解决的问题越多,未知的问题也就越少,不是吗?
针对Linux下编译链接的问题,网络上不乏有牛人经典的原创好文,不得不说,现在网络的发达让人们:不足出户,就可以万事不求人。废话少说,言归正传罢:
一,解决思路
总结了一下当BUG出现时,一般解决的思路:
(1)仔细查看BUG信息
很多问题可以从BUG信息本身就可以知晓原因的,不要忽略这个基础而有有效的方法。
(2)深入挖掘BUG信息上现的提示信息,
这是产生BUG的依据,深入研究一下具体细节,往往可以分析到BUG产生的原因。
(3)寻求同事及网络的帮助,找到答案。
二,几个概念:
2.1) 环境变量:LD_LIBRARY_PATH
用于指定动态库的除了默认目录之外的其它搜索目录,
注意:LD_LIBRARY_PATH最后如果带":"号则意味着多出一个搜索目录,这个目录代表的是运行程序的当前目录。
LD_LIBRARY_PATH=path1:path2:path3
与
LD_LIBRARY_PATH=path1:path2:path3:
是有区别的,区别就在后者多了一个搜索路径:当前路径
2.2)多级嵌套依赖:
如果LibA引用(依赖)LibB,我们说LibA是“引用库”,LibB是“被引用库”。
如果“被引用库”是内部库,那么在制作“引用库”时只需要把“被引用库”包含进来即可。
如果“被引用库”是外部库,那么在制作“引用库”时要把“被引用库”和其所依赖的库一起包含进来,不然当“被引用库”做“引用库”用时,会出现找不到库的问题。
举例来说:
这里为了表述方便,这里[]内容为内部程序及库,{}内容为外部依赖库,并把加载依赖库Lib的App简写成: App(Lib),
现在有一个级嵌套依赖关系:[InnerApp<1-N>] --> [InnnerLib] --> {OuterLib} -->{outerLibDep<1-N>}
InnerLib1(OuterLib) is OK ==》 InnerApp(InnerLib) is NG
InnerLib1(OuterLib, OuterLibDep<1-N>) is OK ==》 InnerApp(InnerLib) is OK
2.3)头文件与库文件的搜索目录
这里只说结论:
库文件的默认搜索目录:
结论:
动态库的搜索路径搜索的先后顺序是,(大致是这样子):
1.编译目标代码时指定的动态库搜索路径;
2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
3.配置文件/etc/ld.so.conf中指定的动态库搜索路径;
4.默认的动态库搜索路径/lib;
5.默认的动态库搜索路径/usr/lib。
应注意动态库搜寻路径并不包括当前文件夹,所以当即使可执行文件和其所需的so文件在同一文件夹,也会出现找不到so的问题,类同#include <header_file>不搜索当前目录
头文件的默认搜索目录:
1.由参数-I指定的路径(指定路径有多个路径时,按指定路径的顺序搜索)
2.然后找gcc的环境变量 C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH
3.再找内定目录
/usr/include
/usr/local/include
/usr/lib/gcc-lib/i386-linux/2.95.2/include
/usr/lib/gcc-lib/i386-linux/2.95.2/../../../../include/g++-3
/usr/lib/gcc-lib/i386-linux/2.95.2/../../../../i386-linux/include
库文件,但是如果装gcc的时候,是有给定的prefix的话,那么就是
/usr/include
prefix/include
prefix/xxx-xxx-xxx-gnulibc/include
prefix/lib/gcc-lib/xxxx-xxx-xxx-gnulibc/2.8.1/include
三,几种常见的链接错误及产生原因
3.1) undefined reference to symbol '<AAA>::<func>'
说明:引用符号未定义,
原因:编译选项中-l参数加载的依赖库不全,因为库文件不存在,所以找不到库中的任何接口。
如果依赖库接口是被库间接调用,你可以查看“被引用库”的-l选项,如果没有依赖库的话就加进来。
3.2) /usr/bin/ld: <AAA>: undefined reference '<BBB>::<func>'
说明:引用接口未定义。
原因1:编译选项问题:
-l中遗漏了该库,也就是没有库的lib文件,
-l中库名有白字,当然也找不到.so文件了。
备注:在添加-l选项下,头文件和库文件都存在了,这至少保证了文件资源是没有问题的,
如果编译器找不到Lib文件的话,将会提示,/usr/bin/ld: cannot find -lpkg,这时候你再添加-L选项指定库目录即可
原因2:库.h文件与库.so文件不匹配,.h文件有接口声明,但.so文件没有做接口实现。
造成这种原因有很多种因素:
(1).h文件没问题,.so文件有问题
.so文件存在于多个目录且版本不同,系统在搜索.so文件时优先在错误的目录下找到了.so文件,引发在链接阶段报错。
(2).so文件没问题,.h文件有问题
在修改代码时,如果不小心更改了.so所依赖的.h文件,这也会在链接或运行阶段引发一些莫名其妙的异常。。
(3)跨系统移植时库移植不完整,
比如说centos的程序放到rhel上运行,copy了库文件却没有copy头文件,用centos的ACE.so文件与rhel的ACE.h文件匹配就会出现这种问题。
原因3:引用的接口未导出
造成这种原因也有很多种因素:
(1)跨语言调用接口,
比如说在C++应用程序中调用C语言库,就要在调用接口前添加导出符号("extern C"),不然会引起匹配问题。
(2) 接口未导出,
比如说你在接口声明处没有添加导出符号("extern"),外部程序调用时该接口时当然是找不到了。
检查一下声明和定义是否一致,哪怕是函数中的参数类型不一致,是否只有只有声明没有定义,缺少其中任何一样,接口一样是无法正常导出的。
辅助命令:ldd 检查依赖库及对应目录
3.3)/usr/bin/ld: warning: <AAA>.so, needed by <BBB>.so, not found (try using -rpath or -rpath-link)
说明:多级嵌套依赖:
原因:见概念一节内容
3.4)symbol lookup error: ../lib/xxx.so: undefined symbol:<AAA_>
说明:找不到接口符号
原因:在so库中没有找到某接口符号,ldd一下,检查App的依赖库,目录及版本是否正确?
【原创】Linux下编译链接中常见问题总结的更多相关文章
- [转载]linux下编译php中configure参数具体含义
编译N次了 原来这么回事 原文地址:linux下编译php中configure参数具体含义作者:捷心特 php编译参数的含义 ./configure –prefix=/usr/local/php ...
- [原创]Linux 下 redis 链接一次
刚接触 Linux ,在 Linux 下安装 redis 链接redis 出现了以下问题 Could not connect to Redis at 127.0.0.1:6379: Connecti ...
- Linux下编译安装qemu和libvirt
目录 [hide] 1 安装qemu 1.1 qemu介绍 1.2 下载源文件 1.3 编译安装 2 安装libvirt 2.1 libvirt介绍 2.2 下载libvirt 2.3 编译安装 3 ...
- Linux下编译安装qemu和libvirt【转】
转自:http://www.cnblogs.com/findumars/p/5679742.html 目录 [hide] 1 安装qemu 1.1 qemu介绍 1.2 下载源文件 1.3 编译安装 ...
- linux下编译qt5.6.0静态库——configure配置
linux下编译qt5.6.0静态库 linux下编译qt5.6.0静态库 configure生成makefile 安装选项 Configure选项 第三方库: 附加选项: QNX/Blackberr ...
- 程序的链接和装入及Linux下动态链接的实现
http://www.ibm.com/developerworks/cn/linux/l-dynlink/ 程序的链接和装入及Linux下动态链接的实现 程序的链接和装入存在着多种方法,而如今最为流行 ...
- Linux 下编译、安装、配置 QT
转自Linux 下编译.安装.配置 QT 注意:编译安装耗时费力,且很容易出错,要不断调整编译参数,不推荐使用,否则这将会是一个纠结痛苦的过程. 打算做嵌入式图像处理,计划方案嵌入式Linux+Ope ...
- linux下编译eXosip、osip,以及UAC和UAS的例子
从网站上看到了这样的一篇博文 :Windows下编译eXosip.osip,以及UAC和UAS的例子 (链接:http://www.cnblogs.com/dyllove98/archive/2013 ...
- linux下编译qt5.6.0静态库——configure配置(超详细,有每一个模块的说明)(乌合之众)
linux下编译qt5.6.0静态库 linux下编译qt5.6.0静态库 configure生成makefile 安装选项 Configure选项 第三方库: 附加选项: QNX/Blackberr ...
随机推荐
- DIV CSS设计时IE6、IE7、FF 与兼容性有关的特性(转载的)
在网站设计的时候,应该注意css样式兼容不同浏览器问题,特别是对完全使用DIV CSS设计的网,就应该更注意IE6 IE7 FF对CSS样式的兼容,不然,你的网乱可能出去不想出现的效果! 所有浏览器 ...
- IOS 的loadView 及使用loadView中初始化View注意的问题。(死循环并不可怕)
在XCode 4.2后,我基本上的应用都不使用Xib文件了,虽然xib文件有很多好趣,可以快速免代码构建视窗,可以减少好多代码构建带来的麻烦,其实能用xib还是不错的,主要是我的机器打开xib来编辑时 ...
- 在Ogre中加载自己的资源包
转自:http://www.cnblogs.com/minggoddess/archive/2011/02/19/1958472.html 由于数据保护的需要,一款游戏一般都会有自己独有的资源包,这样 ...
- SSIS ->> Null & Null Functions
SSIS不支持值为NULL的变量.每种类型的变量都有自己的默认值. 做了一个测试,用一个Execute SQL Task输出一个NULL值给A变量,然后把A变量传到到另外一个Execute SQL T ...
- sublime3运行lua
{ "cmd": ["/usr/local/bin/lua", "$file"], "file_regex": &quo ...
- 通过xrdp实现远程桌面连接Windows Azure linux虚拟机
本文以Oracle Linux 6.4虚拟机为示例(22及3389端口必须打开,分别用于SSH及RDP连接) 1.在安装xrdp之前,首先需要安装一些必要的包,如: # yum -y install ...
- Failed to load unit 'HGCM' (VERR_INVALID_PARAMETER)
1 清除状态: clear the state, 显示 边上有个 清楚 按钮,作用相当于重启虚拟机 restart
- java中参数传递
一.参数是基本类型 相当于C++传值调用,方法中的形参是实参的副本. 二.参数是类类型 类类型的参数在方法调用中,相当于C++中的传址调用.形参是实参引用同一个对象.所有形参修改则实参也修改了 三.总 ...
- git subtree有效管理公共第三方lib
如果你的项目中有很多第三方的lib,你希望使用它,并且也希望可能对该lib做修改并且贡献到原始的项目中去,或者你的项目希望模块化,分为几个repo单独维护,那么git subtree就是一个选择.gi ...
- UVa 11137 (完全背包方案数) Ingenuous Cubrency
题意:用13.23……k3这些数加起来组成n,输出总方案数 d(i, j)表示前i个数构成j的方案数则有 d(i, j) = d(i-1, j) + d(i, j - i3) 可以像01背包那样用滚动 ...