静态库会被链接到可执行文件中,所以运行速度更快,也便于移植。但是会增大文件的体积,浪费内存,并且更新、部署、发布麻烦。
动态库可以实现库的共享,可以控制何时加载库,节省了内存。但是加载相对较慢,发布程序时必须提供依赖的动态库。
两者各有优缺点,需要在工作中灵活选用。
静态库的制作和使用
1. 静态库的制作
假设项目的目录结构如图,我们希望把几个包含了加减乘除计算函数的 .c 文件制作成静态库。首先需要把 .c 文件编译成 .o 文件,在src文件夹中输入命令 gcc -c add.c sub.c mult.c div.c -I ../include
其中 -I ../include 的意思是从当前目录的上一级目录中的include中寻找头文件
编译成功后,生成了4个 .o 文件,此时需要把这4个 .o 文件打包成静态库文件。输入命令 ar rcs libcalc.a add.o sub.o mult.o div.o
此时会在当前文件夹中生成 libcalc.a 文件,这就是静态库。我们把它移动到项目的 lib 文件夹下,输入命令 mv libcalc.a ../lib
2. 静态库的使用
接下来,我们的 main.c 需要调用到库中的函数,输入命令 gcc main.c -o app -I ./include -L ./lib -l calc
其中 -I 指定了头文件的位置,-L 指定了静态库的位置,-l 指定了库名(注意去掉前缀 lib 和后缀 .a )
执行命令后,就生成了可执行文件 app
动态库的制作和使用
1. 动态库的制作
第一步和静态库类似,先对 .c 文件编译生成 .o 文件,但需要注意的是要额外加一个 -fpic 参数,否则无法制作动态库。
输入命令 gcc -c -fpic add.c sub.c mult.c div.c,生成4个 .o 文件
第二步是把4个 .o 文件生成动态库文件。
输入 gcc -shared add.o sub.o mult.o div.o -o libcalc.so, 动态库的命名规范为lib*.so, 其中*是自己取的库名。
2. 动态库的使用
把动态库文件放到项目中,例如下图的项目结构,放到lib文件夹中
在 main.c 目录中输入 gcc main.c -o app -I ./include -L ./lib -l calc
参数和静态库的使用类似,-I 指明头文件的位置,-L 指明库文件的文职,-l 指明使用的库名
执行后就生成了可执行文件 app,但此时运行 app 会报错,提示加载动态库出错。原因是可执行文件在使用到动态库时,必须知道动态库的位置,并将它加载到内存中的。我们输入 ldd app 命令,可以查看 app 依赖的动态库的状态:
可以看到 libcalc.so 没有找到,而其它几个已经在内存中了。那么系统是去哪里找动态库的呢?按先后顺序,有以下几个位置:DT_RPATH段、环境变量LD_LIBRARY_PATH、/etc/ld.so.cache文件列表、/lib、/usr/lib,所以把动态库配置到上述位置中的一个,就可以解决问题。
1. 添加环境变量(用户级)
在linux的home目录下,编辑.bashrc文件,在文件末尾增加一行:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"动态库的绝对路径,去掉引号"
含义是在原来环境变量的末尾,拼接上我们动态库所在的地址。
修改后保存退出,然后输入命令 source .bashrc 来进行更新
2. 添加环境变量(系统级)
和上面类似,只是修改的文件不同,修改 /etc/profile 文件,同样是在末尾增加上面那行内容,保存并更新
3. /etc/ld.so.cache
修改/etc/ld.so.conf文件:
在文件末尾加上一行:内容是动态库的绝对路径,保存并退出
输入命令 sudo ldconfig 来更新修改
4. /lib 或者 /usr/lib
把动态库文件放到上述两个目录中的任意一个里即可。但不建议使用这种方式,因为这两个文件夹里已经存在很多库文件了,容易引起冲突或者覆盖。