Linux下编译、使用静态库和动态库 自己测过的
每个程序实质上都会链接到一个或者多个的库。比如使用C函数的程序会链接到C运行时库,GUI程序会链接到窗口库等等。无论哪种情况,你都会要决定是链接到静态库(static libary)还是动态库(dynamic libary)。
链接到静态库会使你的程序臃肿,并且难以升级,但是可能会比较容易部署。
而链接到动态库会使你的程序轻便,并且易于升级,但是会难以部署。
静态库
静态库也就相当于是把一系列的object文件放在同一个文件中(类似windows中的.lib文件)。当你提供一个静态库给链接器时,连接器将会搜索静态库,从中找到他所需要的object文件,提取出他们,将他们链接到你的程序中,就像你直接提供那些文件一样。
如何创建静态库呢?你可以使用ar命令来创建。
下面我们举个例子:
test/lib/test1.c
#include <stdio.h>
int hello_world1()
{
printf("hello world1\n");
return 1;
}
test/lib/test2.c
#include <stdio.h>
void hello_world2()
{
printf(" hello world2\n");
}
test/app.c
#include <stdio.h>
int main()
{
hello_world1();
}
现在我们编译他们进入目录test/lib
$gcc -c test1.c
$gcc -c test2.c
$ls
test1.c test1.o test2.c test2.o
$ar cr libtest.a test1.o test2.o
$ls
libtest.a test1.c test1.o test2.c test2.o
cr标志告诉ar将object文件封装(archive),我们可以使用nm -s 命令来查看.a文件的内容
$nm -s libtest.a
Archive index:
hello_world1 in test1.o
hello_world2 in test2.o
test1.o:
00000000 T hello_world1
U puts
test2.o:
00000000 T hello_world2
U puts
现在让我们编译主程序
首先退出lib目录
$cd ..
$gcc -o app app.c -Llib -ltest
-L指定了lib的搜索路径,-l指定了链接的库的名字-ltest也就是链接libtest.a
(这里编译会出错,因为mian.cpp中的函数没有声明,需要在函数的前面做个声明)
$./app
hello world1
hello_world1()被从libtest.a中找到并链接过来了,于是整个的过程中没有出现问题。
动态库
动 态库(static lib)也可一也可以成为共享库(shared lib),一般的后缀名是.so。动态库与静态库有点类似,他们都是一系列的object文件的集合,只是他们的组织方式不同。同样他们的链接方式也是不 同的,动态库只在执行是链接使用,并不把相应的部分编译入程序中,在使用是一个库可以被多个程序使用故可称为共享库,而静态库将会整合到程序中,链接时各 程序使用自己的库。
下面我们来介绍如何创建动态库,还是之前的三个文件,同样的布局,进入lib目录
$gcc -c -fPIC test1.c
$gcc -c -fPIC test2.c
-fPIC告诉gcc将源代码编译成共享的object文件,PIC(Position-Independent Code)非位置依赖性代码。
$gcc -shared -fPIC -o libtest.so test1.o test2.o
将两个文件整合为共享库libtest.so
退出lib目录
$cd ..
$gcc -o app app.c -Llib -ltest
$./app
./app: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory
啊哈,我们在这里遇到一个error没找到libtest.so,说明我们的编译成功了,libtest.so成为了一个shared libary。程序之所以不能运行是因为libtest.so不在默认的搜索路径上
怎样才能让他跑呢?
$LD_LIBRARY_PATH=$PWD/lib ./app
hello world1
我们在自己指定链接的路径,他找到了我们的libtest.so文件,并且链接成功了。
我们回过头看看,发现使用静态库和使用动态库编译成目标程序使用的gcc命令完全一样,那当静态库和动态库同名时,gcc命令会使用哪个库文件呢?抱着对问题必究到底的心情,来试试看。先删除除.c和.h外的 所有文件,恢复成我们刚刚编辑完举例程序状态。
在来创建静态库文件libtest.a和动态库文件libtest.so。
# gcc -c test1.c
# gcc -c test2.c
# ar cr libtest.a test1.o test2.o
# gcc -shared -fPCI -o libtest.so test1.o test2.o
通过上述最后一条ls命令,可以发现静态库文件libtest.a和动态库文件libtest.so都已经生成,并都在当前目录中。然后,我们运行gcc命令来使用函数生成目标文件app,并运行程序 app。
#gcc -o app app.c -Llib -ltest
# ./app
./app: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory
#
从程序app运行的结果中很容易知道,当Linux静态库和Linux动态库同名时, gcc命令将优先使用动态库。
库文件在连接(静态库和共享库)和运行(仅限于使用共享库的程序)时被使用,其搜索路径是在系统中进行设置的。一般 Linux 系统把 /lib 和 /usr/lib 两个目录作为默认的库搜索路径,所以使用这两个目录中的库时不需要进行设置搜索路径即可直接使用。对于处于默认库搜索路径之外的库,需要将库的位置添加到库的搜索路径之中。设置库文件的搜索路径有下列两种方式,可任选其一使用:
(1). 在 /etc/ld.so.conf 文件中添加库的搜索路径。(或者在/etc/ld.so.conf.d 下新建一个.conf文件,将搜索路径一行一个加入-junziyang)
将自己可能存放库文件的路径都加入到/etc/ld.so.conf中是明智的选择添加方法也极其简单,将库文件的绝对路径直接写进去就OK了,一行一个。例如:
/usr/X11R6/lib
/usr/local/lib
/opt/lib
需要注意的是:这种搜索路径的设置方式对于程序连接时的库(包括共享库和静态库)的定位已经足够了,但是对于使用了共享库的程序的执行还是不够的。这是因为为了加快程序执行时对共享库的定位速度,避免使用搜索路径查找共享库的低效率,所以是直接读取库列表文件 /etc/ld.so.cache 从中进行搜索的。/etc/ld.so.cache 是一个非文本的数据文件,不能直接编辑,它是根据 /etc/ld.so.conf 中设置的搜索路径由 /sbin/ldconfig 命令将这些搜索路径下的共享库文件集中在一起而生成的(ldconfig 命令要以 root 权限执行)。
因此,为了保证程序执行时对库的定位,在 /etc/ld.so.conf 中进行了库搜索路径的设置之后,还必须要运行 /sbin/ldconfig 命令更新 /etc/ld.so.cache 文件之后才可以。ldconfig ,简单的说,它的作用就是将/etc/ld.so.conf列出的路径下的库文件缓存到/etc/ld.so.cache 以供使用。因此当安装完一些库文件,(例如刚安装好glib),或者修改ld.so.conf增加新的库路径后,需要运行一下 /sbin/ldconfig使所有的库文件都被缓存到ld.so.cache中,如果没做,即使库文件明明就在/usr/lib下的,也是不会被使用的,结果编译过程中抱错,缺少xxx库,去查看发现明明就在那放着,搞的想大骂computer蠢猪一个。
在程序连接时,对于库文件(静态库和共享库)的搜索路径,除了上面的设置方式之外,还可以通过 -L 参数显式指定。因为用 -L 设置的路径将被优先搜索,所以在连接的时候通常都会以这种方式直接指定要连接的库的路径。
这种设置方式需要 root 权限,以改变 /etc/ld.so.conf 文件并执行 /sbin/ldconfig 命令。而且,当系统重新启动后,所有的基于 GTK2 的程序在运行时都将使用新安装的 GTK+ 库。不幸的是,由于 GTK+ 版本的改变,这有时会给应用程序带来兼容性的问题,造成某些程序运行不正常。为了避免出现上面的这些情况,在 GTK+ 及其依赖库的安装过程中对于库的搜索路径的设置将采用另一种方式进行。这种设置方式不需要 root 权限,设置也简单。
(2). 在环境变量 LD_LIBRARY_PATH 中指明库的搜索路径。
设置方式:
export LD_LIBRARY_PATH=/opt/gtk/lib:$LD_LIBRARY_PATH
可以用下面的命令查看 LD_LIBRAY_PATH 的设置内容:
echo $LD_LIBRARY_PATH
至此,库的两种设置就完成了。
Linux下编译、使用静态库和动态库 自己测过的的更多相关文章
- Linux 下Python调用C++编写的动态库
在工程中用到使用Python调用C++编写的动态库,结果报如下错误: OSError: ./extract_str.so: undefined symbol: _ZNSt8ios_base4InitD ...
- 使用CMake在Linux下编译tinyxml静态库
环境:CentOS6.6+tinyxml_2_6_21.下载并解压tinyxml_2_6_2.zip unzip tinyxml_2_6_2.zip 2.在tinyxml文件夹里创建一个CMakeLi ...
- Linux下Gcc生成和使用静态库和动态库详解(转)
一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同( ...
- 在Linux下如何使用GCC编译程序、简单生成 静态库及动态库
最近在编写的一个Apache kafka 的C/C++客户端,,在看他写的 example中,他的编译是用librdkafka++.a和librdkafka.a 静态库编译的,,,而我们这 ...
- linux下编译qt5.6.0静态库——configure配置
linux下编译qt5.6.0静态库 linux下编译qt5.6.0静态库 configure生成makefile 安装选项 Configure选项 第三方库: 附加选项: QNX/Blackberr ...
- Linux下Gcc生成和使用静态库和动态库详解
参考文章:http://blog.chinaunix.net/uid-23592843-id-223539.html 一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库 ...
- [转]Linux下用gcc/g++生成静态库和动态库(Z)
Linux下用gcc/g++生成静态库和动态库(Z) 2012-07-24 16:45:10| 分类: linux | 标签:链接库 linux g++ gcc |举报|字号 订阅 ...
- linux下的共享库(动态库)和静态库
1.什么是库在windows平台和linux平台下都大量存在着库.本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行.由于windows和linux的本质不同,因此二者库的二进制是不 ...
- linux下编译qt5.6.0静态库——configure配置(超详细,有每一个模块的说明)(乌合之众)
linux下编译qt5.6.0静态库 linux下编译qt5.6.0静态库 configure生成makefile 安装选项 Configure选项 第三方库: 附加选项: QNX/Blackberr ...
随机推荐
- 解决kylin报错:java.lang.ArrayIndexOutOfBoundsException: -1
报错信息: -- ::, INFO [pool--thread-] cli.DictionaryGeneratorCLI: : Building snapshot of ENERGON_DM.DM_D ...
- 获取easyui calendar 属性
<div id="cc" class="easyui-calendar" style="width:250px;height:250px;&qu ...
- 漏洞预警 | ECShop全系列版本远程代码执行高危漏洞
2018年9月1日,阿里云态势感知发布预警,近日利用ECShop全系列版本的远程代码执行漏洞进行批量化攻击量呈上升趋势.该漏洞利用简单且危害较大,黑客可通过WEB攻击直接获得服务器权限. 漏洞原理 该 ...
- Orchard运用 - 学习资源分享
这段时间研究Orchard,看到一些资源十分有用. 比如国内还是有些牛人在分享心得,在此也广播一下给新手: JustRun对Orchard的一些代码分析 Orchard源码分析 Orchard中文社区 ...
- 倾斜摄影三维建模软件photoscan教程 [转]
PhotoScan是一款基于影响自动生成高质量三维模型的优秀软件,这对于3D建模需求来说实在是一把利器. PhotoScan无需设置初始值,无须相机检校,它根据最新的多视图三维重建技术,可对任意照片进 ...
- C++对C的改进(2)
本文地址:http://www.cnblogs.com/archimedes/p/cpp-change2.html,转载请注明源地址 区别一:原型声明的区别 原型声明的概念: 函数要先定义再使用,如果 ...
- [AngularJS] Angular 1.3 new $q constructor
<!DOCTYPE html> <html ng-app="app"> <head lang="en"> <meta ...
- T-SQL 之 表变量和临时表
一.表变量 表变量在SQL Server 2000中首次被引入.表变量的具体定义包括列定义,列名,数据类型和约束.而在表变量中可以使用的约束包括主键约束,唯一约束,NULL约束和CHECK约束(外键约 ...
- HDU 4757
可持久化trie树.不会可持久化数据结构的话推荐先看陈立杰的论文.先掌握可持久化线段树和可持久化trie树. //可持久化trie树,题目已知一棵树,每个点有点权,询问一对点路径上点权与给定值异或的最 ...
- Net作业调度(一) -Quartz.Net入门 Quartz表达式生成器 [转]
背景 很多时候,项目需要在不同个时刻,执行一个或很多个不同的作业. Windows执行计划这时并不能很好的满足需求了. 这时候需要一个更为强大,方便管理,集部署的作业调度了. 介绍 Quartz一个开 ...