【转】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) 文件没 ...
随机推荐
- Delete PeopleSoft Query From the Database
There could be different reasons why a PeopleSoft developer would like to delete a query from the da ...
- [leetcode]_Merge Two Sorted Lists
题目:合并两个有序单链表 思路:一开始想复杂了,以为必须在原链表上修改(绕来绕去还AC了,但是思路相当绕),其实没有,按照正常地合并两个数组同样的方法也对. 代码: public ListNode m ...
- ASP.NET中application对象
ASP.NET中application对象的使用. Application对象的应用 1.使用Application对象保存信息 (1).使用Application对象保存信息 Applicat ...
- 如何让dapper支持oracle游标呢?
Dapper是一个轻型的ORM类.它有啥优点.缺点相信很多朋友都知道了,园里也有很多朋友都有相关介绍,这里就不多废话. 如果玩过Oracle都知道,存储过程基本都是通过游标返回数据的,但是dapper ...
- mini2440裸机之MMU(二)(mmu.c) (转)
分类: 嵌入式 http://blog.chinaunix.net/uid-26435987-id-3082166.html(转) /********************************* ...
- .NET String.Format 方法 线程安全问题
碰到这个问题 是在和淘宝做信息交互的时候, 接收别人N年前的代码. 代码逻辑很简单,就是取得信息 数据库查询 响应请求返回结果. 最近淘宝的人反映说 N多账户使用的是一个单号.理论上来说 是应该每次 ...
- AngularJs记录学习01
<!doctype html> <html ng-app="myapp"> <head> <meta http-equiv="C ...
- python笔记第二天
上节内容回顾和补充 编程语言 高级 低级 Python种类 JavaPython cPython ***** pypy 字节码 和 机器码 Python程序: 1. 终端: C:\python35\p ...
- [terry笔记]Oracle会话追踪(一):SQL_TRACE&EVENT 10046
SQL_TRACE/10046 事件是 Oracle 提供的用于进行 SQL 跟踪的手段,在日常的数据库问题诊断和解决中是非常常用的方法.但其生成的trace文件需要tkprof工具生成一个可供人 ...
- selenium+python cooking用法 (转)
selenium-webdriver(python)--cookie处理 driver.get_cookies() 获得cookie信息 add_cookie(cookie_dict) 向cooki ...