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,内容例如以下

#include<stdio.h>
int main()
{
printf("call hello()");
hello();
}

编译 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

这样,再运行就成功了。

注:

LD_LIBRARY_PATH:该环境变量主要用于指定查找共享库(动态链接库)时除了默认路径之外的其它路径。当运行函数动态链接.so时,假设此文件不在缺省文件夹下‘/lib’
and ‘/usr/lib’.那么就须要指定环境变量LD_LIBRARY_PATH。

假如如今须要在已有的环境变量上加入新的路径名,则採用例如以下方式:

LD_LIBRARY_PATH=NEWDIRS:$LD_LIBRARY_PATH.(NEWDIRS是新的路径串)

显式调用

显式调用须要包括头文件#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 编译使用动态链接库和静态链接库的方法的更多相关文章

  1. [转载]GCC 编译使用动态链接库和静态链接库--及先后顺序----及环境变量设置总结

    来自http://blog.csdn.net/benpaobagzb/article/details/51364005 GCC 编译使用动态链接库和静态链接库 1 库的分类 根据链接时期的不同,库又有 ...

  2. GCC 编译使用动态链接库和静态链接库

    1 库的分类 根据链接时期的不同,库又有静态库和动态库之分. 静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行. 有 ...

  3. 【转】gcc 编译使用动态链接库和静态链接库

    1 库的分类 根据链接时期的不同,库又有静态库和动态库之分. 静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行. 有 ...

  4. 利用GCC编译器生成动态链接库和静态链接库

    转载请标明:http://www.cnblogs.com/winifred-tang94/ 1.编译过程 gcc –fPIC –c xxx.c 其中-fPIC是通知gcc编译器产生位置独立的目标代码. ...

  5. Linux GCC编译使用动态、静态链接库 (转)

    原文出处:http://blog.csdn.net/a600423444/article/details/7206015 在windows下动态链接库是以.dll后缀的文件,二在Linux中,是以.s ...

  6. Linux 动态链接库包含静态链接库的方法

    今天老司机们在讨论一个编译问题  A是一个静态库  C是一个动态库  B是运行程序,能不能将A打包到C 然后B只需要链接C 就可以了. 这个问题我以前在出来zlib库版本冲突的时候有点印象,所以写了个 ...

  7. Linux下动态链接库和静态链接库

    第一部分:编译过程 先了解一下linux下C代码的编译过程,C代码的编译,一般分成四个阶段,包括:预编译,编译,汇编和链接,这四个阶段的分工是 预处理过程,负责头文件展开,宏替换,条件编译的选择,删除 ...

  8. Qt 共享库(动态链接库)和静态链接库的创建及调用

    前言: 编译器 Qt Creator, 系统环境 win7 64 位 1.创建共享库: 新建文件或项目->选择 Library 和 c++ 库->选择共享库->下一步(工程名为 sh ...

  9. GCC编译过程与动态链接库和静态链接库

    1. 库的介绍 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常. 本质上来说库是一种可执行代码的二进制形式,可 ...

随机推荐

  1. dede修改移动文档的js

    dede后台弹框修改: 想做个类似文章列表的移动功能,弹框,然后修改成功到表 先在list.js里复制一份moveArc的方法,到archives_do.php里复制一份moveArchives的方法 ...

  2. mysql-5.6.17-winx64 免安装 配置

    [client] default_character_set=utf8 port=3306 [mysql] # 设置mysql客户端默认字符集 default_character_set=utf8 [ ...

  3. mongodb 限制ip访问

    <pre name="code" class="python">一.限制访问IP和端口 MongoDB可以限制只允许某一特定IP来访问,只要在启动时 ...

  4. IT第十九天 - 继承、接口、多态、面向对象的编程思想

    IT第十九天 上午 继承 1.一般情况下,子类在继承父类时,会调用父类中的无参构造方法,即默认的构造方法:如果在父类中只写了有参的构造方法,这时如果在子类中继承时,就会出现报错,原因是子类继承父类时无 ...

  5. 飘逸的python - 简单探索time模块

    time模块中方法众多,不过在了解本质和联系之后,就会发现其实很简单. 在python中可以用3种方式来表达时间.看似很乱,其实就只是这3种变来变去来回转换而已. 1.时间戳 2.时间tuple,由9 ...

  6. delphi DCC32命令行方式编译delphi工程源码

    本文链接地址:http://blog.csdn.net/sushengmiyan/article/details/10284879 作者:苏生米沿 Borland出品的Delphi,在TIOBE公布的 ...

  7. Gstreamer中加入�x265编解码器

    官方的当前gstreamer版本号还不支持x265编解码,因此要加入�x265,须要自己编译.本文基于gstreamer1.3.3版进行编译安装.须要首先自己编译gstreamer1.3.3,以及对应 ...

  8. javascript特效:会随着鼠标而动的眼睛

    这个特效非常简单,其中眼球和眼珠都是特定的图片.只要掌握好距离坐标就没问题.我就直接贴代码,有兴趣的朋友可以自己复制下来运行一下,下面的眼睛图像就是我的文件用到的图像,比较难看..我就把我的代码贴出来 ...

  9. ceph之crush map

    编辑crush map: 1.获取crush map: 2.反编译crush map: 3.至少编辑一个设备,桶, 规则: 4.重新编译crush map: 5.重新注入crush map: 获取cr ...

  10. 静态化 - 伪静态技术(Apache Rewrite 实现)

    打开apache的配置文件httpd.conf 找到 #LoadModule rewrite_module modules/mod_rewrite.so 把前面#去掉.没有则添加,但必选独占一行,使a ...