GCC链接的几个注意点
库文件依赖顺序
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链接的几个注意点的更多相关文章
- gcc链接g++编译生成的静态库和动态库的makefile示例
使用c++开发程序或者库时,将库提供给其他人使用. 然而使用者是使用c开发的程序,链接g++编译生成的库时,于链接gcc生成的库,有所不同. 首先是静态库,以链接g++编译生成的libmylib.a为 ...
- GCC链接库的一个坑:动态库存在却提示未定义动态库的函数
背景 在GCC中已经指定链接库,然而编译时却提示动态库函数未定义! 测试出现的错误提示如下: [GMPY@13:48 tmp]$gcc -o test -L. -lmylib test.c /tmp/ ...
- Linux gcc链接动态库出错:LIBRARY_PATH和LD_LIBRARY_PATH的区别
昨天在自己的CentOs7.1上写makefile的时候,发现在一个C程序在编译并链接一个已生成好的lib动态库的时候出错.链接命令大概是这样的: [root@typecodes tcpmsg]# g ...
- gcc链接非标准(non-standard)命名库
标准命名库: -lnamespace 标准链接库以lib开头, 并以so/a结尾. example gcc test.c -o test -L. -lhello 非标准命名库: -l:libname ...
- GCC链接时库顺序问题
GCC或G++在编译链接时,如果命令行中含有库,则要特别注意了.根据<C专家编程>5.3节中的提示,GCC在链接时对命令行时的处理顺序是从左到右.证据是GCC的MAN: -l librar ...
- 【图片+代码】:GCC 链接过程中的【重定位】过程分析
作 者:道哥,10+年嵌入式开发老兵,专注于:C/C++.嵌入式.Linux. 关注下方公众号,回复[书籍],获取 Linux.嵌入式领域经典书籍:回复[PDF],获取所有原创文章( PDF 格式). ...
- gcc链接参数--whole-archive的作用
// a.h extern void foo(); // a.cpp #include <stdio.h> void foo() { printf("foo\n"); ...
- g++/gcc 链接头文件 库 PATH
转自http://blog.csdn.net/kankan231/article/details/24243871 在Linux下编译链接或运行c/c++程序时可能会遇到找不到头文件,找不到库文件的错 ...
- gcc 链接非标准名称库
一般库的标准名称是libxxx.so或者libxxx.a, 如果没有, 也可以搞个linkname出来, 那就可以直接用 "-lxxx" 来链接了, 但要是你想直接用realnam ...
随机推荐
- ReSharper 10.0.0.1 Ultimate 完美破解补丁使用方法
转自:http://www.leavescn.com/Page/Content.aspx?id=94 ReSharper 10.0.0.1 Ultimate 完美破解补丁使用方法,本资源来自互联网,感 ...
- hdu3001Travelling
参考了别人的代码 https://blog.csdn.net/u010372095/article/details/38474721 深感自己的弱小 这是tsp问题,和基本的tsp问题没什么大的区 ...
- day11_雷神_udp、多进程等
day11 1.网络编程 1.1 udp协议 client端 import json import socket server_addr = ('127.0.0.1',9090) sk = socke ...
- Android RxJava zip 操作符
不说话,直接举例 // zip 2 observables Observable.zip(Observable.just(0), Observable.just(0), BiFunction { t1 ...
- rabbitmq基础学习+springboot结合rabbitmq实现回调确认confirm
rabbitmq集群docker快速搭建 https://blog.csdn.net/u011058700/article/details/78708767 rabbitmq原理博客 https:// ...
- kubernetes集群搭建(2):docker私有仓库
kubernetes集群搭建(1):环境准备 中各节点已经安装好了docker,请确认docker已启动并正常运行 1.通过命令启动私库 docker run -d -p 5000:5000 --pr ...
- 凉凉了,Eureka 宣布闭源,Spring Cloud 何去何从?
今年 Dubbo 活了,并且被 Apache 收了.同时很不幸,Spring Cloud 下的 Netflix Eureka 组件项目居然宣布闭源了.. 已经从 Dubbo 迁移至 Spring Cl ...
- Spring Boot Tomcat配置详解
参数配置容器 server.xx开头的是所有servlet容器通用的配置,server.tomcat.xx开头的是tomcat特有的参数,其它类似. 所有参数绑定配置类:org.springframe ...
- .NET手记-Autofac进阶(注册的概念 Registering Concepts)
通过创建ContainerBuilder并配置暴露的service(接口或者类型)来使用Autofac注册我们的组件. 组件(Components) 可以通过反射, 对象实例,或者lambda表达式来 ...
- Go语言标准库之time
Go语言标准库之time 时间的格式化和解析 格式化 Format Go语言和其他语言的时间格式化的方式不同,Go语言格式化的方式更直观,其他的语言一般是yyyy-mm-dd package main ...