静态库和动态库

一. 定义:

静态库:这类库的名字一般是libxxx.a,xxx为库的名字。利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了。当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译。

动态库:这类库的名字一般是libxxx.M.N.so,同样的xxx为库的名字,M是库的主版本号,N是库的副版本号。当然也可以不要版本号,但名字必须有。相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。linux系统有几个重要的目录存放相应的函数库,如/lib /usr/lib。

当要使用静态的程序库时,连接器会找出程序所需的函数,然后将它们拷贝到执行文件,由于这种拷贝是完整的,所以一旦连接成功,静态程序库也就不再需要了。然而,对动态库而言,就不是这样。动态库会在执行程序内留下一个标记指明当程序执行时,首先必须载入这个库。由于动态库节省空间,linux下进行连接的缺省操作是首先连接动态库,也就是说,如果同时存在静态和动态库,不特别指定的话,将与动态库相连接。

二. 静态库

制作静态链接库:

1.准备两个源码文件st1.cpp和st2.cpp,用它们来制作库libmytest.a

xzj@xzj-VirtualBox:~/development_test/static_lib_test$ cat st1.cpp 
#include <iostream>
using namespace std;
void display1()
{
    cout<<"This is my first static library!!!"<<endl;
}
xzj@xzj-VirtualBox:~/development_test/static_lib_test$ cat st2.cpp 
#include <iostream>
using namespace std;
void display2()
{
    cout<<"This is my second static library"<<endl;
}

2.把两个源码文件生成目标文件

xzj@xzj-VirtualBox:~/development_test/static_lib_test$ g++ -c st1.cpp  st2.cpp 
xzj@xzj-VirtualBox:~/development_test/static_lib_test$ ll
总用量 24
drwxrwxr-x 2 xzj xzj 4096 7  16 15:39 ./
drwxrwxr-x 7 xzj xzj 4096 7  16 15:26 ../
-rw-rw-r-- 1 xzj xzj  115 7  16 15:35 st1.cpp
-rw-rw-r-- 1 xzj xzj 2680 7  16 15:39 st1.o
-rw-rw-r-- 1 xzj xzj  113 7  16 15:35 st2.cpp
-rw-rw-r-- 1 xzj xzj 2680 7  16 15:39 st2.o

3.使用ar -rsv libmytest.a st1.o st2.o制作静态库

xzj@xzj-VirtualBox:~/development_test/static_lib_test$ ar -rsv libmytest.a st1.o st2.o
ar: 正在创建 libmytest.a
a - st1.o
a - st2.o
xzj@xzj-VirtualBox:~/development_test/static_lib_test$ ll
总用量 32
drwxrwxr-x 2 xzj xzj 4096 7  16 15:42 ./
drwxrwxr-x 7 xzj xzj 4096 7  16 15:26 ../
-rw-rw-r-- 1 xzj xzj 5586 7  16 15:42 libmytest.a
-rw-rw-r-- 1 xzj xzj  115 7  16 15:35 st1.cpp
-rw-rw-r-- 1 xzj xzj 2680 7  16 15:39 st1.o
-rw-rw-r-- 1 xzj xzj  113 7  16 15:35 st2.cpp
-rw-rw-r-- 1 xzj xzj 2680 7  16 15:39 st2.o
用file命令查看其属性,发现它确实是归档压缩文件
xzj@xzj-VirtualBox:~/development_test/static_lib_test$ file libmytest.a 
libmytest.a: current ar archive
用ar -t libmytest.a可以查看一个静态库包含了那些obj文件:
xzj@xzj-VirtualBox:~/development_test/static_lib_test$ ar -t libmytest.a 
st1.o
st2.o

4.写个测试程序来调用库libmytest.a中所提供的两个接口display1()和display2()。

xzj@xzj-VirtualBox:~/development_test/static_lib_test$ cat main.cpp 
void display1();
void display2();
int main()
{
    display1();
    display2();
    return 0;
}

xzj@xzj-VirtualBox:~/development_test/static_lib_test$ g++ -o run main.cpp  -L./  -lmytest
xzj@xzj-VirtualBox:~/development_test/static_lib_test$ ll
总用量 48
drwxrwxr-x 2 xzj xzj 4096 7  16 15:54 ./
drwxrwxr-x 7 xzj xzj 4096 7  16 15:26 ../
-rw-rw-r-- 1 xzj xzj 5586 7  16 15:42 libmytest.a
-rw-rw-r-- 1 xzj xzj   95 7  16 15:53 main.cpp
-rwxrwxr-x 1 xzj xzj 9424 7  16 15:54 run* 
-rw-rw-r-- 1 xzj xzj  115 7  16 15:35 st1.cpp
-rw-rw-r-- 1 xzj xzj 2680 7  16 15:39 st1.o
-rw-rw-r-- 1 xzj xzj  113 7  16 15:35 st2.cpp
-rw-rw-r-- 1 xzj xzj 2680 7  16 15:39 st2.o

结果调用成功:
xzj@xzj-VirtualBox:~/development_test/static_lib_test$ ./run
This is my first static library!!!
This is my second static library

三. 动态库

动态库的后缀为*.so。在Linux发行版中大多数的动态库基本都位于/usr/lib和/lib目录下。在开发和使用我们自己动态库之前,请容许我先落里罗嗦的跟大家唠叨唠叨Linux下和动态库相关的事儿吧。

有时候当我们的应用程序无法运行时,它会提示我们说它找不到什么样的库,或者哪个库的版本又不合它胃口了等等之类的话。那么应用程序它是怎么知道需要哪些库的呢?我们前面已几个学了个很棒的命令ldd,用就是用来查看一个文件到底依赖了那些so库文件。

Linux系统中动态链接库的配置文件一般在/etc/ld.so.conf文件内,它里面存放的内容是可以被Linux共享的动态联库所在的目录的名字。我的系统中,该文件的内容如下:

xzj@xzj-VirtualBox:/etc$ cat /etc/ld.so.conf
include /etc/ld.so.conf.d/*.conf

然后/etc/ld.so.conf.d/目录下存放了很多*.conf文件,如下:

xzj@xzj-VirtualBox:/etc$ ls /etc/ld.so.conf.d/
fakeroot-x86_64-linux-gnu.conf  libc.conf                  x86_64-linux-gnu_GL.conf
i386-linux-gnu.conf             x86_64-linux-gnu.conf      zz_i386-biarch-compat.conf
i386-linux-gnu_GL.conf          x86_64-linux-gnu_EGL.conf  zz_x32-biarch-compat.conf


其中每个conf文件代表了一种应用的库配置内容,以libc为例:
xzj@xzj-VirtualBox:/etc$ cat /etc/ld.so.conf.d/libc.conf 
# libc default configuration
/usr/local/lib



在/etc目录下还存在一个名叫ld.so.cache的文件。从名字来看,我们知道它肯定是动态链接库的什么缓存文件。
xzj@xzj-VirtualBox:/etc$ ls -l |grep ld.so.cache
-rw-r--r--  1 root root   125054 7月  16 09:09 ld.so.cache

为了使得动态链接库可以被系统使用,当我们修改了/etc/ld.so.conf或/etc/ld.so.conf.d/目录下的任何文件,或者往那些目录下拷贝了新的动态链接库文件时,都需要运行一个很重要的命令:ldconfig,该命令位于/sbin目录下,主要的用途就是负责搜索/lib和/usr/lib,以及配置文件/etc/ld.so.conf里所列的目录下搜索可用的动态链接库文件,然后创建处动态加载程序/lib/ld-linux.so.2所需要的连接和(默认)缓存文件/etc/ld.so.cache(此文件里保存着已经排好序的动态链接库名字列表)。

也就是说:当用户在某个目录下面创建或拷贝了一个动态链接库,若想使其被系统共享,可以执行一下"ldconfig目录名"这个命令。此命令的功能在于让ldconfig将指定目录下的动态链接库被系统共享起来,即:在缓存文件/etc/ld.so.cache中追加进指定目录下的共享库。请注意:如果此目录不在/lib,/usr/lib及/etc/ld.so.conf文件所列的目录里面,则再次单独运行ldconfig时,此目录下的动态链接库可能不被系统共享了。单独运行ldconfig时,它只会搜索/lib、/usr/lib以及在/etc/ld.so.conf文件里所列的目录,用它们来重建/etc/ld.so.cache。(不懂!)

因此,等会儿我们自己开发的共享库就可以将其拷贝到/lib、/etc/lib目录里,又或者修改/etc/ld.so.conf文件将我们自己的库路径添加到该文件中,再执行ldconfig命令。

动态库实战

我们有一个头文件my_so_test.h和三个源文件test_hubei.cpp、test_wuhan.cpp、man.cpp:

root@siaphisprb02234:/usr1/j30008655/test_demon/demon2# ls -l
total 16
-rw-r--r-- 1 root root 181 Jan 25 17:40 main.cpp
-rw-r--r-- 1 root root  90 Jan 25 09:44 my_so_test.h
-rw-r--r-- 1 root root 130 Jan 25 17:40 test_hubei.cpp
-rw-r--r-- 1 root root 132 Jan 25 17:07 test_wuhan.cpproot@siaphisprb02234:/usr1/j30008655/test_demon/demon2# cat main.cpp 
# include "my_so_test.h"
#include <iostream>
using namespace std;
void test_hubei();
void test_wuhan();
int main()
{
    test_hubei();
    test_wuhan();
 
    return 0;
}
root@siaphisprb02234:/usr1/j30008655/test_demon/demon2# cat my_so_test.h 
#ifndef MY_SO_TEST_H
#define MY_SO_TEST_H
void test_hubei();
void test_wuhan();
#endif
root@siaphisprb02234:/usr1/j30008655/test_demon/demon2# cat test_hubei.cpp 
#include "my_so_test.h"
#include <iostream>
using namespace std;
void test_hubei()
{
    cout<<"欢迎来到湖北"<<endl;
}
root@siaphisprb02234:/usr1/j30008655/test_demon/demon2# cat test_wuhan.cpp 
#include "my_so_test.h"
#include <iostream>
using namespace std;
void test_wuhan()
{
    cout<<"欢迎来到武汉"<<endl;
}
root@siaphisprb02234:/usr1/j30008655/test_demon/demon2# 

生产.so文件的方法:
root@siaphisprb02234:/usr1/j30008655/test_demon/demon2# g++ test_hubei.cpp  test_wuhan.cpp  -fPIC  -shared -o libtest.so
root@siaphisprb02234:/usr1/j30008655/test_demon/demon2# ls -l
total 28
-rwxr-xr-x 1 root root 8752 Jan 25 17:41 libtest.so
-rw-r--r-- 1 root root  181 Jan 25 17:40 main.cpp
-rw-r--r-- 1 root root   90 Jan 25 09:44 my_so_test.h
-rw-r--r-- 1 root root  130 Jan 25 17:40 test_hubei.cpp
-rw-r--r-- 1 root root  132 Jan 25 17:07 test_wuhan.cpp

动态链接库的使用有两种方法

用法一:动态链接。

root@siaphisprb02234:/usr1/j30008655/test_demon/demon2# g++ main.cpp -o run -L. -ltest
root@siaphisprb02234:/usr1/j30008655/test_demon/demon2# ls -l
total 40
-rwxr-xr-x 1 root root 8752 Jan 25 18:34 libtest.so
-rw-r--r-- 1 root root  181 Jan 25 17:40 main.cpp
-rw-r--r-- 1 root root   90 Jan 25 09:44 my_so_test.h
-rwxr-xr-x 1 root root 8712 Jan 25 18:34 run
-rw-r--r-- 1 root root  130 Jan 25 17:40 test_hubei.cpp
-rw-r--r-- 1 root root  132 Jan 25 17:07 test_wuhan.cpp
root@siaphisprb02234:/usr1/j30008655/test_demon/demon2# ./run 
./run: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directoryroot@siaphisprb02234:/usr1/j30008655/test_demon/demon2# ldd run
    linux-vdso.so.1 (0x00007ffe7be26000)
    libachk.so => /lib/libachk.so (0x00007f90781ce000)
    libtest.so => not found    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9077b32000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9077741000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f907753d000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f907731e000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f9077116000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9076d78000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f90780bd000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9076b60000)
root@siaphisprb02234:/usr1/j30008655/test_demon/demon2# 

这里我们注意,ldd的输出表示我们的libtest.so动态库没有找到。因为我们的libtest.so既不在/etc/ld.so.cache里,又不在/lib、/usr/lib或/etc/ld.so.conf所指定的任何一个目录中。參看文章<>。

用法二:动态加载。

动态加载是非常灵活的,它依赖于一套Linux提供的标准API来完成。在源程序里,你可以很自如的运用API来加载、使用、释放so库资源。以下函数在代码中使用需要包含头文件:dlfcn.h

函数原型说明
const char *dlerror(void)当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。
void *dlopen(const char *filename, int flag)用于打开指定名字(filename)的动态链接库,并返回操作句柄。调用失败时,将返回NULL值,否则返回的是操作句柄。
void *dlsym(void *handle, char *symbol)根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函数的执行代码地址。由此地址,可以带参数执行相应的函数。
int dlclose (void *handle)用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。2.2在程序中使用动态链接库函数。

1. void *dlopen(const char *filename, int flag)

参数filenam:如果名字不以“/”开头,则非绝对路径名,将按下列先后顺序查找该文件。

(1)用户环境变量中的LD_LIBRARY_PATH的值;

(2)动态链接缓冲文件/etc/ld.so.cache

(3)目录/lib,/usr/lib

参数flag:表示在什么时候解决未定义的符号(调用)。取值有两个:

(1)RTLD_LAZY : 表明在动态链接库的函数代码执行时解决。

(2)RTLD_NOW :表明在dlopen返回前就解决所有未定义的符号,一旦未解决,dlopen将返回错误。

#include "my_so_test.h"
#include <stdio.h>
#include <dlfcn.h>
#include <cstdlib>
extern "C"
{
    void (*fn)(void);
}


int main(int argc, char const *argv[])
{
	void *handle = dlopen("./libtest.so",RTLD_LAZY);
	/*const char *err = dlerror();
	if(err !=NULL){
		perror("could not open shared object!");
	}*/
	if (NULL != handle) {
		/* code */
		printf("nihao\n");

	}
	fn = (void (*)(void))dlsym(handle,"test_hubei");
	fn();
	
	dlclose(handle);
	return 0;
}

执行结果:

xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ g++ test_hubei.cpp  test_wuhan.cpp test_xiaogan.cpp -fPIC  -shared -o libtest.so
xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ g++ -o mmain_run mmain.cpp  -rdynamic -ldl
xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ ./mmain_run 
nihao
欢迎来到湖北!
欢迎来到武汉!!
欢迎来到孝感!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值