【转】GCC编译使用动态链接库
1 库的分类
根据链接时期的不同,库又有静态库和动态库之分。
静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行。
有别于静态库,动态库的链接是在程序执行的时候被链接的。所以,即使程序编译完,库仍须保留在系统上,以供程序运行时调用。(TODO:链接动态库时链接阶段到底做了什么)
2 静态库和动态库的比较
链接静态库其实从某种意义上来说也是一种粘贴复制,只不过它操作的对象是目标代码而不是源码而已。因为静态库被链接后库就直接嵌入可执行文件中了,这样就带来了两个问题。
首先就是系统空间被浪费了。这是显而易见的,想象一下,如果多个程序链接了同一个库,则每一个生成的可执行文件就都会有一个库的副本,必然会浪费系统空间。
再者,人非圣贤,即使是精心调试的库,也难免会有错。一旦发现了库中有bug,挽救起来就比较麻烦了。必须一一把链接该库的程序找出来,然后重新编译。
而动态库的出现正弥补了静态库的以上弊端。因为动态库是在程序运行时被链接的,所以磁盘上只须保留一份副本,因此节约了磁盘空间。如果发现了bug或要升级也很简单,只要用新的库把原来的替换掉就行了。
那么,是不是静态库就一无是处了呢?
答曰:非也非也。不是有句话么:存在即是合理。静态库既然没有湮没在滔滔的历史长河中,就必然有它的用武之地。想象一下这样的情况:如果你用libpcap库编了一个程序,要给被人运行,而他的系统上没有装pcap库,该怎么解决呢?最简单的办法就是编译该程序时把所有要链接的库都链接它们的静态库,这样,就可以在别人的系统上直接运行该程序了。
所谓有得必有失,正因为动态库在程序运行时被链接,故程序的运行速度和链接静态库的版本相比必然会打折扣。然而瑕不掩瑜,动态库的不足相对于它带来的好处在现今硬件下简直是微不足道的,所以链接程序在链接时一般是优先链接动态库的,除非用-static参数指定链接静态库。
动态链接库
1. 创建动态链接库
void hello()
{
printf("hello world/n");
}
用命令gcc -shared hello.c -o libhello.so -fPIC编译为动态库。可以看到,当前目录下多了一个文件libhello.so。fPIC告诉编译器产生与位置无关代码(Position-Independent Code),则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。
【转载者注:so是Linux下动态链接库的后缀,ld对此后缀是敏感的,不可以改成如dll等其他后缀.又由于gcc -c在不加-o来指定文件名的情况下,不管其他参数如何,都会生成xxxxx.o文件,因此编译链接库时必须用-o指定一个名为xxxx.so的文件名。】
2. 再编辑一个测试文件test.c,内容如下
int main()
{
printf("call hello()");
hello();
}
编译 gcc test.c -lhello (转载者注:-lxxxxx 中间没有空格,是告诉gcc要去找libxxxxx.so这个库,而libxxxxx.so文件名是gcc去生成的,是固定格式,不可更改。)
-l 选项告诉编译器要使用hello这个库。奇怪的地方是动态库的名字是libhello.so,这里却使用hello.
但这样还不行,编译会出错。
In function `main':
test.c:(.text+0x1d): undefined reference to `hello'
collect2: ld returned 1 exit status
这是因为hello这个库在我们自己的路径中,编译器找不到。
需要使用-L选项,告诉hello库的位置
gcc test.c -lhello -L. -o test
-L. 告诉编译器在当前目录中查找库文件
3. 编译成功后执行./test, 仍然出错
说找不到库
有两种方法:
一、可以把当前路径加入 /etc/ld.so.conf中然后运行ldconfig,或者以当前路径为参数运行ldconfig(要有root权限才行)。
二、把当前路径加入环境变量LD_LIBRARY_PATH中
当然,如果你觉得不会引起混乱的话,可以直接把该库拷入/lib,/usr/lib/等位置(无可避免,这样做也要有权限),这样链接器和加载器就都可以准确的找到该库了。
我们采用第二种方法:
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
这样,再执行就成功了。
下面再讲讲静态链接库
仍使用刚才的hello.c和test.c。
1. gcc -c hello.c 注意这里没有使用-shared选项
2. 把目标文件归档 ar -r libhello.a hello.o
程序 ar 配合参数 -r 创建一个新库 libhello.a 并将命令行中列出的对象文件插入。采用这种方法,如果库不存在的话,参数 -r 将创建一个新的库,而如果库存在的话,将用新的模块替换原来的模块。
3. 在程序中链接静态库
gcc test.c -lhello -L. -static -o hello.static
或者 gcc test.c libhello.a -L. -o hello.static
生成的hello.static就不再依赖libhello.a了
两个有用的命令
file程序是用来判断文件类型的,在file命令下,所有文件都会原形毕露的。
顺便说一个技巧。有时在 windows下用浏览器下载tar.gz或tar.bz2文件,后缀名会变成奇怪的tar.tar,到Linux有些新手就不知怎么解压了。但 Linux下的文件类型并不受文件后缀名的影响,所以我们可以先用命令file xxx.tar.tar看一下文件类型,然后用tar加适当的参数解压。
另外,还可以借助程序ldd实用程序来判断。
ldd是用来打印目标程序(由命令行参数指定)所链接的所有动态库的信息的,如果目标程序没有链接动态库,则打印“not a dynamic executable”,ldd的用法请参考manpage。
【转】GCC编译使用动态链接库的更多相关文章
- [转载]GCC 编译使用动态链接库和静态链接库--及先后顺序----及环境变量设置总结
来自http://blog.csdn.net/benpaobagzb/article/details/51364005 GCC 编译使用动态链接库和静态链接库 1 库的分类 根据链接时期的不同,库又有 ...
- GCC 编译使用动态链接库和静态链接库
1 库的分类 根据链接时期的不同,库又有静态库和动态库之分. 静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行. 有 ...
- GCC 编译使用动态链接库和静态链接库的方法
1 库的分类 依据链接时期的不同,库又有静态库和动态库之分. 静态库是在链接阶段被链接的.所以生成的可执行文件就不受库的影响了.即使库被删除了,程序依旧能够成功执行. 有别于静态库,动态库的链接是在程 ...
- 【转】gcc 编译使用动态链接库和静态链接库
1 库的分类 根据链接时期的不同,库又有静态库和动态库之分. 静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行. 有 ...
- GCC 编译使用动态链接库 LD
可以把当前路径加入 /etc/ld.so.conf中然后运行ldconfig,或者以当前路径为参数运行ldconfig 2.把当前路径加入环境变量LD_LIBRARY_PATH中3. 如果你觉得不会引 ...
- GCC编译过程与动态链接库和静态链接库
1. 库的介绍 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常. 本质上来说库是一种可执行代码的二进制形式,可 ...
- gcc编译动态链接库
以下是windows环境下用gcc编译动态链接库的尝试过程. 环境准备 编译使用的MinGW,64位的官网可以找到下载地址. 项目建立及代码编写 在任意地方新建一个目录,保存这个项目,然后新建一个c源 ...
- GCC编译C代码
C程序的编译过程 常用文件的后缀名: gcc编译c代码 1.gcc 常用编译选项: 2.gcc编译方法 testc.c: #include <stdio.h> int main ...
- gcc编译时对'xxxx'未定义的引用问题
gcc编译时对’xxxx’未定义的引用问题 gcc编译时对’xxxx’未定义的引用问题 原因 解决办法 gcc 依赖顺序问题 在使用gcc编译的时候有时候会碰到这样的问题,编译为.o(obj) 文件没 ...
随机推荐
- luigi学习9--执行模型
luigi的执行和触发模型非常简单. 一.luigi的执行模型 当你执行一个luigi的工作流的时候,worker调度所有的task,并且执行task在一个单独的进程中. 这种scheme最大的好处是 ...
- MongoDB的安装小结
正在做毕业设计,想尝试着用mongoDB来做数据库,之前没有接触过,然后,就在网上找资料,自己捣鼓,弄了好久才算上真正的把它安上,好心累.... 网上有很多安装教程,大同小异,这里呢,我只是想记录一下 ...
- Linux 服务器如何设置文件和文件夹的读写权限
修改文件可读写属性的方法 例如:把index.htm 文件修改为可写可读可执行: chmod 777 index.htm 要修改目录下所有文件属性可写可读可执行: chmod 777 *.* 该命令中 ...
- jquery 匹配select下拉框与列表框
今天工作中用到 GrapyCity 的 wijmo ui 控件. 要给系统中所有类型的控件加统一样式 用法 $("input [type='text']").wijtext(); ...
- activiti
http://activiti.org/designer/archived/ eclipse plugin
- Ruby判断文件是否存在
flag = FileTest::exist?("LochNessMonster") flag = FileTest::exists?("UFO") # exi ...
- angularjs2 学习笔记(二) 组件
angular2 组件 首先了解angular2 组件的含义 angular2的应用就是一系列组件的集合 我们需要创建可复用的组件供多个组件重复使用 组件是嵌套的,实际应用中组件是相互嵌套使用的 组件 ...
- 重命名Oracle数据库的表空间(Renaming a Tablespace)
重命名一个表空间时,Oracle会在数据字典.控制文件和数据文件的头部更新这个表空间名. 注意,重命名一个表空间不会重命名相关联的数据文件. 重命名代码示例如下: SQL> alter tabl ...
- 算法系列9《MD5》
MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致.是计算机广泛使用的杂凑算法之一(又译摘要算法.哈希算法),主流编程语言普遍已有MD5实现. ...
- oracle 11g 表空间使用率
Oracle数据库表空间使用量查询: select b.file_name 物理文件名,b.tablespace_name 表空间,b.bytes/1024/1024 大小M,(b.bytes-sum ...