GCC 编译使用动态链接库和静态链接库的方法
1 库的分类
依据链接时期的不同,库又有静态库和动态库之分。
静态库是在链接阶段被链接的。所以生成的可执行文件就不受库的影响了。即使库被删除了,程序依旧能够成功执行。
有别于静态库,动态库的链接是在程序执行的时候被链接的。所以,即使程序编译完,库仍须保留在系统上,以供程序执行时调用。
2 静态库和动态库的比較
链接静态库事实上从某种意义上来说也是一种粘贴复制。仅仅只是它操作的对象是目标代码而不是源代码而已。由于静态库被链接后库就直接嵌入可运行文件里了,这样就带来了两个问题。
首先就是系统空间被浪费了。这是显而易见的,想象一下,假设多个程序链接了同一个库,则每个生成的可运行文件就都会有一个库的副本,必定会浪费系统空间。
再者,人非圣贤,即使是精心调试的库,也难免会有错。一旦发现了库中有bug,拯救起来就比較麻烦了。必须一一把链接该库的程序找出来。然后又一次编译。
而动态库的出现正弥补了静态库的以上弊端。
由于动态库是在程序执行时被链接的,所以磁盘上仅仅须保留一份副本,因此节约了磁盘空间。假设发现了bug或要升级也非常easy,仅仅要用新的库把原来的替换掉即可了。
那么。是不是静态库就一无是处了呢?
答曰:非也非也。不是有句话么:存在即是合理。
静态库既然没有湮没在滔滔的历史长河中,就必定有它的用武之地。想象一下这种情况:假设你用libpcap库编了一个程序,要给被人执行,而他的系统上没有装pcap库。该怎么解决呢?最简单的办法就是编译该程序时把全部要链接的库都链接它们的静态库。这样。就能够在别人的系统上直接执行该程序了。
所谓有得必有失。正由于动态库在程序执行时被链接。故程序的执行速度和链接静态库的版本号相比必定会打折扣。
然而瑕不掩瑜,动态库的不足相对于它带来的优点在现今硬件下简直是微不足道的,所以链接程序在链接时通常是优先链接动态库的。除非用-static參数指定链接静态库。
3 动态链接库
隐式调用
1. 创建动态链接库
#include<stdio.h>
void hello()
{
printf("hello world/n");
}
用命令gcc -fPIC -shared hello.c -o libhello.so编译为动态库。
能够看到。当前文件夹下多了一个文件libhello.so。
gcc參数
-shared:
该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号)。不用该标志外部程序无法连接。
相当于一个可运行文件
-fpic:
表示编译为位置独立的代码。不用此选项的话编译后的代码是位置相关的所以动态加载时是通过代码拷贝的方式来满足不同进程的须要,而不能达到真正代码段共享的目的。
2. 再编辑一个測试文件test.c,内容例如以下
编译 gcc test.c -lhello
-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
这样,再运行就成功了。
注:
and ‘/usr/lib’.那么就须要指定环境变量LD_LIBRARY_PATH。 假如如今须要在已有的环境变量上加入新的路径名,则採用例如以下方式:
显式调用
显式调用须要包括头文件#include <dlfcn.h>。
涉及到以下几个函数:dlopen()、dlsym()、dlerror()、dlclose()。
dlopen()函数以指定模式打开指定的动态链接库文件,并返回一个句柄给dlsym()的调用进程。
使用dlclose()来卸载打开的库。当动态链接库操作函数运行失败时,dlerror能够返回出错信息,返回值为NULL时表示操作函数运行成功。
编译时候要增加 -ldl (指定dl库)
详细的函数原型例如以下:
void *dlopen(const char *filename, int flag); char *dlerror(void); void *dlsym(void *handle, const char *symbol); int dlclose(void *handle);
dlopen以指定模式打开指定的动态连接库文件。并返回一个句柄给调用进程,dlerror返回出现的错误,dlsym通过句柄和连接符名称获取函数名或者变量名,dlclose来卸载打开的库。
如果已经生成libcaculate.so库,里面定义了add(),sub(),mul(),div()等函数。这里给出调用演示样例:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h> //动态链接库路径
#define LIB_CACULATE_PATH "./libcaculate.so" //函数指针
typedef int (*CAC_FUNC)(int, int); int main()
{
void *handle;
char *error;
CAC_FUNC cac_func = NULL; //打开动态链接库
handle = dlopen(LIB_CACULATE_PATH, RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
} //清除之前存在的错误
dlerror(); //获取一个函数
*(void **) (&cac_func) = dlsym(handle, "add");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
printf("add: %d\n", (*cac_func)(2,7)); cac_func = (CAC_FUNC)dlsym(handle, "sub");
printf("sub: %d\n", cac_func(9,2)); cac_func = (CAC_FUNC)dlsym(handle, "mul");
printf("mul: %d\n", cac_func(3,2)); cac_func = (CAC_FUNC)dlsym(handle, "div");
printf("div: %d\n", cac_func(8,2)); //关闭动态链接库
dlclose(handle);
exit(EXIT_SUCCESS);
}
4 静态链接库
仍使用刚才的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了LD_LIBRARY_PATH
GCC 编译使用动态链接库和静态链接库的方法的更多相关文章
- [转载]GCC 编译使用动态链接库和静态链接库--及先后顺序----及环境变量设置总结
来自http://blog.csdn.net/benpaobagzb/article/details/51364005 GCC 编译使用动态链接库和静态链接库 1 库的分类 根据链接时期的不同,库又有 ...
- GCC 编译使用动态链接库和静态链接库
1 库的分类 根据链接时期的不同,库又有静态库和动态库之分. 静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行. 有 ...
- 【转】gcc 编译使用动态链接库和静态链接库
1 库的分类 根据链接时期的不同,库又有静态库和动态库之分. 静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行. 有 ...
- 利用GCC编译器生成动态链接库和静态链接库
转载请标明:http://www.cnblogs.com/winifred-tang94/ 1.编译过程 gcc –fPIC –c xxx.c 其中-fPIC是通知gcc编译器产生位置独立的目标代码. ...
- Linux GCC编译使用动态、静态链接库 (转)
原文出处:http://blog.csdn.net/a600423444/article/details/7206015 在windows下动态链接库是以.dll后缀的文件,二在Linux中,是以.s ...
- Linux 动态链接库包含静态链接库的方法
今天老司机们在讨论一个编译问题 A是一个静态库 C是一个动态库 B是运行程序,能不能将A打包到C 然后B只需要链接C 就可以了. 这个问题我以前在出来zlib库版本冲突的时候有点印象,所以写了个 ...
- Linux下动态链接库和静态链接库
第一部分:编译过程 先了解一下linux下C代码的编译过程,C代码的编译,一般分成四个阶段,包括:预编译,编译,汇编和链接,这四个阶段的分工是 预处理过程,负责头文件展开,宏替换,条件编译的选择,删除 ...
- Qt 共享库(动态链接库)和静态链接库的创建及调用
前言: 编译器 Qt Creator, 系统环境 win7 64 位 1.创建共享库: 新建文件或项目->选择 Library 和 c++ 库->选择共享库->下一步(工程名为 sh ...
- GCC编译过程与动态链接库和静态链接库
1. 库的介绍 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常. 本质上来说库是一种可执行代码的二进制形式,可 ...
随机推荐
- WebService开发实例(Axis2实现,无需安装,快速实现)
曾经做过的项目里涉及Android客户端向服务器发送请求,服务器访问数据库获得数据并返回给Android客户端.当时Android客户端与服务器的通信已经实现,我只负责客户端布局和数据呈现的部分,近日 ...
- C++惯用法:通过成员模板实现隐式转换(Coercion 强迫 by Member Template)
Intent To increase the flexibility of a class template's interface by allowing the class template to ...
- cocos2d-x游戏开发系列教程-超级玛丽10-怪物与马里奥冲突检测
在超级玛丽游戏中,马里奥在移动,怪物也在移动,当他们遇见时,需要判断是马里奥身亡还是怪物身亡. 这个判断的代码在怪物类的检测函数实现中. 比如蘑菇怪的冲突检测函数: bool CMMonsterMus ...
- Code(容斥,好题)
Code Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Submi ...
- UVA 10057 A mid-summer night's dream. 仲夏夜之梦 求中位数
题意:求中位数,以及能成为中位数的数的个数,以及选择不同中位数中间的可能性. 也就是说当数组个数为奇数时,中位数就只有一个,中间那个以及中位数相等的数都能成为中位数,选择的中位数就只有一种可能:如果为 ...
- ognl--数据运转的催化剂
原文链接:http://struts2.group.iteye.com/group/wiki/1353-ognl-catalyst-for-data-operation-in-struts2 首先让我 ...
- android getDecorView()的作用
decorView是window中的最顶层view,可以从window中通过getDecorView获取到decorView.通过decorView获取到程序显示的区域,包括标题栏,但不包括状态栏.间 ...
- JavaScript 、ECMAScript、commonJS 发展历史 与标准化发展
本文介绍下JavaScript和 ECMAScript的诞生及发展历史,以及标准化过程. 一.JavaScript诞生 1994年,网景公司(Netscape)发布了Navigator浏览器0.9版. ...
- docker 学习笔记20:docker守护进程的配置与启动
安装好docker后,需要启动docker守护进程.有多种启动方式. 一.服务的方式 因为docker守护进程被安装成服务.所以,可以通过服务的方式启停docker守护进程,包括查看状态. sudo ...
- ubuntu 安装python,easy_install和pip
ubuntu12.04默认安装的python为 ms@ubuntums:~$ pythonPython 2.7.3 (default, Aug 1 2012, 05:16:07) 我需要用python ...