参考了不少资料,其中最靠谱是这个:http://www.mingw.org/wiki/librarypathhowto

和http://www.kaizou.org/2015/01/linux-libraries/

经过线上实际验证,GCC编译、链接、运行时库查找顺序如下,这个顺序真实可信,网上很多说法有些地方都是有些问题的,

导致遇到问题时总是不确定到底是哪里出了问题,花了不少时间,绝知此事要躬行。

略微让人头疼的是,没有找到官方文档清晰说明什么情况下该如何查找依赖库目录,链接时查找直接依赖库和间接依赖库的方式

差别挺大。。。

一、概括GCC链接时搜索直接依赖库的先后顺序:

1、LDFLAGS选项 -L 参数指定的路径。
2、系统环境变量 LIBRARY_PATH(某些系统或编译器下可能无效)。
3、gcc安装时自身配置的搜索路径,gcc --print-search-dir | grep libraries 可查看,

一般会包含该版本gcc必需的库而不一定包含当前系统库路径,链接时会以-L参数形式传递给ld。

4、ld安装时自身配置的搜索路径,ld -verbose | grep SEARCH_DIR 可查看,

gcc通过调用collect2工具调用ld。

To summarize, when linking an executable against a static library, you need to specify explicitly all dependencies towards shared libraries introduced by the static library on the link command.

二、概括GCC链接时搜索间接依赖库(直接依赖库的依赖库)的先后顺序:(即secondary dependencies)

特别说明:搜索直接依赖库的链接查找顺序同样适用于编译生成动态的( shared)、可重定位(relocatable)目标的情形。

特别说明:本条目所列链接顺序仅适用于编译生成非动态的( non-shared)、非可重定位(non-relocatable)目标的情形,比如生成二进制可执行程序,ld手册中有明确说明,是否适合其它情形不确定。在此种情形下,查找一个依赖库自身的依赖库时,-L参数指定的搜索目录无效(至少某些情况下是如此),这不同于链接一个二进制时查找直接依赖目录的顺序。
(1) 参考linux man手册 ld说明:https://linux.die.net/man/1/ld  “-rpath-link=dir”章节
(2)参考同样问题的分析:http://www.kaizou.org/2015/01/linux-libraries/
链接时对于依赖库中依赖的搜索顺序如下(摘自ld手册):

-rpath-link=dir

When using ELF or SunOS, one shared library may require another. This happens when an "ld -shared" link includes a shared library as one of the input files.

When the linker encounters such a dependency when doing a non-shared, non-relocatable link, it will automatically try to locate the required shared library and include it in the link, if it is not included explicitly. In such a case, the -rpath-link option specifies the first set of directories to search. The -rpath-link option may specify a sequence of directory names either by specifying a list of names separated by colons, or by appearing multiple times.

This option should be used with caution as it overrides the search path that may have been hard compiled into a shared library. In such a case it is possible to use unintentionally a different search path than the runtime linker would do.

The linker uses the following search paths to locate required shared libraries:

(1)  Any directories specified by -rpath-link options.

(2) Any directories specified by -rpath options. The difference between -rpath and -rpath-link is that directories specified by -rpath options are included in the executable and used at runtime, whereas the -rpath-link option is only effective at link time. Searching -rpath in this way is only supported by native linkers and cross linkers which have been configured with the --with-sysroot option.

(3) On an ELF system, for native linkers, if the -rpath and -rpath-link options were not used, search the contents of the environment variable "LD_RUN_PATH".

(4) On SunOS, if the -rpath option was not used, search any directories specified using -L options.

(5) For a native linker, the search the contents of the environment variable "LD_LIBRARY_PATH".

(6) For a native ELF linker, the directories in "DT_RUNPATH" or "DT_RPATH" of a shared library are searched for shared libraries needed by it. The "DT_RPATH" entries are ignored if "DT_RUNPATH"entries exist.

(7) The default directories, normally /lib and /usr/lib.(这里应该是指 ld -verbose | grep SEARCH_DIR显示的搜索目录)

(8) For a native linker on an ELF system, if the file /etc/ld.so.conf exists, the list of directories found in that file.

If the required shared library is not found, the linker will issue a warning and continue with the link.

“Ok, this is not crystal-clear, but what it actually means is that when specifying the path for a secondary dependency, you should not use -L but -rpath-link

To summarize, when linking an executable against:

  • static library, you need to specify all dependencies towards other shared libraries this static library depends on explicitly on the link command.

  • shared library, you don’t need to specify dependencies towards other shared libraries this shared library depends on, but you may need to specify the path to these libraries on the link command using the -rpath/-rpath-link options.

Note however that expressing, discovering and adding implicit libraries dependencies is typically a feature of your build system (autotoolscmake), as demonstrated in my samples.”

二、概括GCC运行时库的搜索库先后顺序:
1、程序自身的RPATH(Library rpath), readelf -d bin可查看,在链接时通过-rpath参数写入程序ELF结构信息中,
而传入链接器中默认的-rpath参数是来自安装gcc时配置的文件specs(其中的配置项linker)。
2、编译时LDFLAGS选项 -L 参数指定的路径。
3、系统环境变量LD_LIBRARY_PATH。
4、在 /etc/ld.so.conf.d/ 目录下的配置文件指定的动态库绝对路径(通过ldconfig生效,一般是非root用户时使用)。
5、gcc安装时自身配置的搜索路径,gcc --print-search-dir | grep libraries 可查看,一般会包含该版本gcc必需的库
而不一定包含当前系统库路径。
三、补充说明:
1、在链接和运行查找库的过程中,只要找到同名的库则不管该库是否兼容均停止查找,
即便兼容的库可能出现在靠后的搜索路径中。
2、安装高版本gcc时一般是直接解压已经编译好的gcc,然后直接复制一份至新的路径下,
bcloud就是这么做的,可能是为了便于恢复编译环境吧。
3、如果系统自带的是低版本gcc,而需要使用高版本gcc编译程序,如果该程序依赖了非系统库(低版本gcc编译),
如果这个非系统库的安装目录下恰好有和高版本gcc依赖的库同名的库,那么为了能够使用这个非系统库,
这时高版本gcc编译时很可能会出现问题,必需保证链接器在查找库时,查找高版本gcc自身库一定要先于任意系统库(或任意库)所在的目录
原因是高版本gcc应该是改进了相当一部分系统库,和当前低版本系统库并不兼容,而对于兼容的那些库,高版本gcc库可以直接使用当前系统库。 

  • You can pass the -v option to gcc so that it shows you how it invokes the linker. In fact, it normally does not invoke ld directly, but indirectly via a tool called collect2 (which lives in one of its internal directories), which in turn invokes ld. That will show you what -L options are being used.
  • You can add -Wl,--verbose to the gcc options to make it pass --verbose through to the linker, to see the linker script as described above.

四、库版本号

如果 major version number不一致,说明库的ABI接口是不兼容的,不同major version 库之间不能相互引用或依赖,相同major version一般是可以相互引用和依赖的,但工作时具体行为是否正确需要进一步验证。

Linux上的shared library有三个名字,分别是:

  • 共享库本身的文件名(real name)

    其通常包含完整的版本号,比如:libmath.so.1.1.1234 。lib是Linux库的约定前缀,math是共享库名字,so是共享库的后缀名,1.1.1234的是共享库的版本号,由主版本号+小版本号+build号组成。主版本号,代表当前动态库的版本,如果共享库的接口发生变化,那么这个版本号就要加1;后面的两个版本号(小版本号和 build号)是用来指示库的更新迭代号,表示在接口没有改变的情况下,由于需求发生变化等因素,开发的新代码。

  • 共享库的soname(Short for shared object name)

    用来告诉应用程序,在加载共享库的时候,应该使用的文件名。其格式为lib + math + .so + (major version number) 其只包含主版本号,换句话说,也就是只要共享库的接口没有变,soname就能与real name保持一致,因为主版本号一样。所以在库的real name的小版本号和 build号发生改变时,应用程序仍然可以通过soname得知,要使用的是哪个real name。

  • 共享库的链接名(link name)

    是专门为应用程序在编译时的链接阶段而用的名字。这个名字就是lib + math +.so ,比如libmath.so。其是不带任何版本信息的。在共享库的编译过程中,编译器将生成一个共享库及real name,同时将共享库的soname写在共享库文件里的文件头里面。可以用命令readelf -d sharelibrary | grep soname查看。 在应用程序引用共享库时,链接选项里面用的是共享库的link name。通过link名字找到对应的real name动态库,并且把其中的soname提取出来,写在应用程序自己的文件头的共享库字段里面。当应用程序运行时,就会通过soname,结合动态链接程序(ld.so),在给定的路径下加载real name的共享库。

以上。

GCC编译、链接、运行时库查找顺序(最真实可信)相关推荐

  1. g++编译后运行时无法链接动态库的解决方法

    问题发现: $ g++ -Wall -o hellobrowser.exec hellobrowser.c -I/usr/local/include -L/usr/local/lib -lmicroh ...

  2. 交叉编译指定运行时库路径_运行时vs编译时类路径

    交叉编译指定运行时库路径 这确实应该是一个简单的区别,但是我一直在回答有关Stackoverflow的许多类似问题,并且经常有人误解此事. 那么,什么是类路径? 应用程序所需的一组所有类(以及带有类的 ...

  3. WebAssembly运行时库(WASM runtime:wasmer 或 wasmtime)\将rust官方demo猜数字编译为WASI目标并使用Wasmer运行

    文章目录 WebAssembly运行时库(wasmer 或 wasmtime.wasmer-go) 一.引子 1. 什么是WASI 2. 有哪些优秀的 WebAssembly 运行时? 二.wasme ...

  4. GCC 编译链接命令用法

    Contents 一.简介... 2 二.简单编译... 2 2.1预处理... 2 2.2编译为汇编代码(Compilation). 3 2.3汇编(Assembly). 3 2.4连接(Linki ...

  5. Gcc编译链接及常用选项总结

    转载文章:http://www.franktly.com 前言 GNU CC(简称Gcc)是GNU项目中符合ANSI C标准的编译系统,能够编译用C.C++和Object- C等语言编写的程序.Gcc ...

  6. 动态库、静态库、运行时库、引入库之间的区别

    动态库.静态库.运行时库.引入库之间的区别 杂集.捡对口味的看看吧. 转自:http://lingualspark.blog.sohu.com/94785899.html 运行时库:Unix中一个典型 ...

  7. /MD, /MDD, /ML, /MT,/MTD(使用运行时库)

    1. VC编译选项 多线程(/MT) 多线程调试(/MTd) 多线程 DLL (/MD) 多线程调试 DLL (/MDd) 2. C 运行时库                              ...

  8. /MD, /MDD, /ML, /MT,/MTD(使用运行时库) .

    1. VC编译选项 多线程(/MT) 多线程调试(/MTd) 多线程 DLL (/MD) 多线程调试 DLL (/MDd) 2. C 运行时库                              ...

  9. VC运行时库(/MD、/MT等)

    VC项目属性→配置属性→C/C++→代码生成→运行时库 可以采用的方式有:多线程(/MT).多线程调试(/MTd).多线程DLL(/MD).多线程调试DLL(/MDd).单线程(/ML).单线程调试( ...

最新文章

  1. Python将classification_report的结论转化为字典(dict)形式并提取模型的灵敏度(sensitivity)、特异度(specificity)、PPV和NPV指标、混淆矩阵图
  2. TensorFlow MNIST最佳实践
  3. Java VS .NET:Java与.NET的特点对比
  4. 各个版本通道_绝地求生各个参数对画面的影响,软硬件优化帧数,拒绝做睁眼瞎...
  5. 安装mq的时候,计算机用户名是中文名的解决办法
  6. python中变量不需要事先声明_python 变量搜寻顺序法则LEGB之E注意事项
  7. Mr.J--学习五子棋的艰苦之路
  8. 在矩池云上复现 CVPR 2018 LearningToCompare_FSL 环境
  9. NAT、远程访问和站点间***集成
  10. MySQL一次查几万条数据,【mysql】一次插入几万条数据应该怎么做优化
  11. SAP OLE中常用的一些方法和属性
  12. 30套精选程序员个人简历模板.zip
  13. Mac电脑没声音了怎么办?
  14. Vue入门学习总结一:Vue定义
  15. WPF/WinForm 如何生成单文件的EXE
  16. python做交易软件_我用Python做了个量化交易工具!
  17. Android DES,AES,RSA加密实现
  18. 宣传python的顺口溜-Python3内置函数——reversed() = 翻转我的世界
  19. pfamscan 的使用_使用 HMMER 进行 PFAM 注释
  20. 影子系统2008 出现:c0000174,错误位置在11.分区表错误

热门文章

  1. system.img解包打包工具
  2. UVA 10189 Minesweeper
  3. 信用有多重要?欠款200元,多付4万利息!(附逾期补救办法)
  4. 纯JavaScript 实现JSON数据导出到Excel(支持多个Sheet页)
  5. googlemap中添加指南针图标
  6. 教师计算机能力提升工程总结,博达中学校教师信息技术应用能力提升工程工作总结...
  7. 搭建一个游戏平台运营团队都需要什么?
  8. linux面试常问问题
  9. 哪些手机写作软件比较好用?3款优秀的手机写作软件让笔者更舒心
  10. Ghost 博客系统终极安装教程,装不上来打我!