库文件依赖顺序

GCC在链接时对依赖库的顺序是敏感的,被依赖的库必须放在后面,比如liba.a依赖libb.a,必须写成liba.a libb.a,否则链接将出错。在库比较多依赖关系比较复杂或者相互依赖或者自己不清楚的情况下,可以使用下面的选项来强制GCC重复查找依赖库:

g++ -o tt tt.o -Xlinker "-(" -lws2_32 -lclsocketd -Xlinker "-)"

强符号和弱符号

在链接中,如果多个目标文件中含有相同名字的全局符号的定义,链接器是怎么进行处理的?这里就涉及到强符号和弱符号的问题,编译器默认函数和初始化了的全局变量为强符号,未初始化的全局变量为弱符号,强符号和弱符号都是针对定义来说的,不是针对符号的引用。链接器会按照如下规则处理重复定义的全局符号:

规则1:不允许强符号被多次定义,否则链接器报符号重定义错误。

规则2:如果一个符号在某个目标文件中是强符号,在其它文件中都是弱符号,那么选择强符号。

规则3:如果弱符号在所有目标文件中都是弱符号,那么选择占用空间最大的一个。

我们可以通过GCC的__atrribute__((weak))来定义任何一个强符号为弱符号,如:

__atrribute__((weak)) weak = 1;

链接时如果未找到某个符号的定义,链接器就会报符号未定义错误,这种被称为强引用。与之对应的还有一种弱引用,如果弱引用的符号未定义,链接器对该引用不报错。我们可以使用GCC中的__attribute__((weakref))这个关键字来声明对一个外部函数的引用为弱引用,如:

__attribute__((weakref)) void foo();

int main()

{

if (foo) foo();

}

这种弱符号和弱引用对库来说十分有用,比如库中定义的弱符号可以被用户定位的强符号所覆盖,从而使程序使用自定义版本的库函数;或者程序可以对某些扩展功能模块的引用定义为弱引用,如果我们去掉了某些功能模块,那么程序也可以正常链接,只是缺少了相应的功能,这使得程序功能更容易裁剪和组合。

全局符号介入

在动态链接中,链接器按照各个模块之间的依赖关系,对各个共享对象进行装载并且将它们的符号并入到全局符号表时,如果两个不同的模块定义了同一个符号,会出现什么结果呢?这个问题涉及到共享对象全局对象介入,即一个共享对象里面的全局对象会被另一个共享对象的同名全局符号覆盖。Linux下的动态链接器的处理规则是这样的:当一个符号需要被加入全局符号表时,如果相同的符号名已经存在,则后加入的符号被忽略。

共享库版本

Linux使用共享库版本的方法来解决共享库的兼容性问题,它规定共享库的文件命名规则如下:

libname.so.x.y.z

x表示主版本号,主版本号表示库的重大升级,不同主版本号之间是不兼容的。

y表示次版本号,次版本号表示库的增量升级,即新增一些新的接口符号,且保持原来的符号不变。在主版本号相同的情况下,高的此版本号的库向下兼容低的次版本号的库。

z表示发布版本号,发布版本号表示库的一些错误修正、性能改进等,并不添加任何新的接口,也不对接口进行更改。相同主版本号、次版本号的共享库之间完全兼容。

Linux采用一种叫做SO-NAME的命令机制来记录共享库的依赖关系。每个共享库都有一个对应的SO-NAME,这个SO-NAME即共享库的文件名去掉次版本号和发布版本号,保留主版本号。比如一个共享库叫做libfoo.so.2.6.1,那么它的SO-NAME就是libfoo.so.2。系统会为每个共享库在它所在的目录创建一个跟SO-NAME相同的并且指向它的软链接,这个软链接会指向目录中主版本号相同、次版本号和发布版本号最新的共享库。

在编译输出ELF文件时,将被依赖共享库的SO-NAME保存到.dynamic中,这样当动态链接器进行共享库依赖文件查找时,就会根据系统中各种共享目录中的 SO-NAME软链接自动定向到所兼容的最新版本的共享库。

GCC链接的几个注意点的更多相关文章

  1. gcc链接g++编译生成的静态库和动态库的makefile示例

    使用c++开发程序或者库时,将库提供给其他人使用. 然而使用者是使用c开发的程序,链接g++编译生成的库时,于链接gcc生成的库,有所不同. 首先是静态库,以链接g++编译生成的libmylib.a为 ...

  2. GCC链接库的一个坑:动态库存在却提示未定义动态库的函数

    背景 在GCC中已经指定链接库,然而编译时却提示动态库函数未定义! 测试出现的错误提示如下: [GMPY@13:48 tmp]$gcc -o test -L. -lmylib test.c /tmp/ ...

  3. Linux gcc链接动态库出错:LIBRARY_PATH和LD_LIBRARY_PATH的区别

    昨天在自己的CentOs7.1上写makefile的时候,发现在一个C程序在编译并链接一个已生成好的lib动态库的时候出错.链接命令大概是这样的: [root@typecodes tcpmsg]# g ...

  4. gcc链接非标准(non-standard)命名库

    标准命名库: -lnamespace 标准链接库以lib开头, 并以so/a结尾. example gcc test.c -o test -L. -lhello 非标准命名库: -l:libname ...

  5. GCC链接时库顺序问题

    GCC或G++在编译链接时,如果命令行中含有库,则要特别注意了.根据<C专家编程>5.3节中的提示,GCC在链接时对命令行时的处理顺序是从左到右.证据是GCC的MAN: -l librar ...

  6. 【图片+代码】:GCC 链接过程中的【重定位】过程分析

    作 者:道哥,10+年嵌入式开发老兵,专注于:C/C++.嵌入式.Linux. 关注下方公众号,回复[书籍],获取 Linux.嵌入式领域经典书籍:回复[PDF],获取所有原创文章( PDF 格式). ...

  7. gcc链接参数--whole-archive的作用

    // a.h extern void foo(); // a.cpp #include <stdio.h> void foo() { printf("foo\n"); ...

  8. g++/gcc 链接头文件 库 PATH

    转自http://blog.csdn.net/kankan231/article/details/24243871 在Linux下编译链接或运行c/c++程序时可能会遇到找不到头文件,找不到库文件的错 ...

  9. gcc 链接非标准名称库

    一般库的标准名称是libxxx.so或者libxxx.a, 如果没有, 也可以搞个linkname出来, 那就可以直接用 "-lxxx" 来链接了, 但要是你想直接用realnam ...

随机推荐

  1. delegate的Invoke和BeginInvoke方法

    C#中的控件和delegate委托方法都有Invoke和BeginInvoke方法,控件的这两个方法网上讲得很多, 这里就不多说了,下面讲一下delegate的Invoke和BeginInvoke方法 ...

  2. [Project] MiniSearch文本检索简介

    1. 预处理过程 预处理主要用来事先生成程序在运行过程中可能用到的数据,以便加速处理时间. 预处理的过程主要生成程序所需的三个文件:网页库文件,网页位置信息文件和倒排索引文件. 网页库文件 其中网页库 ...

  3. Javascript高级编程学习笔记(6)—— 流程控制语句

    话不多说,我们直接开始进入今天的主题 流程控制语句 首先什么是流程控制语句呢? 顾名思义,就是控制流程的语句. 在JS中语句定义了ECMAScript中的主要语法,让我们可以使用一系列的关键字来完成指 ...

  4. 使用 PLSQL 连接 Oracle9i 数据库

    昨天用了Navicate连接Oracle数据库,不停的掉线,然后死机,只能重启Navicate,没办法,还是用回plsql吧,重装了一遍(之前重装系统后,电脑自带的公司原有的软件没啦) 先安装了Ora ...

  5. Liferay7 BPM门户开发之5: Activiti和Spring集成

    参考文档: https://github.com/jbarrez/spring-boot-with-activiti-examplehttps://github.com/sxyx2008/spring ...

  6. [EXP]Apache Tika-server < 1.18 - Command Injection

    #################################################################################################### ...

  7. JavaScript中的 this全面解析

    上一章我们排除了一些对this的错误认识和知道了this是在调用函数时被绑定的,完全取决于函数的调用位置.先介绍两个概念:调用位置和调用栈. 调用栈:就是为了到达当前执行位置所调用的所有函数. 调用位 ...

  8. 21天打造分布式爬虫-Spider类爬取糗事百科(七)

    7.1.糗事百科 安装 pip install pypiwin32 pip install Twisted-18.7.0-cp36-cp36m-win_amd64.whl pip install sc ...

  9. .NetCore使用skywalking实现实时性能监控

    一.简介 很久之前写了一篇 <.Net Core 2.0+ InfluxDB+Grafana+App Metrics 实现跨平台的实时性能监控>关于NetCore性能监控的文章,使用Inf ...

  10. 从零开始学 Web 之 移动Web(七)Bootstrap

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...