关于静态库和动态库
之前的篇章我们已经讲到了c语言的gcc,可以查看先关文章 《Linux c 开发 – gcc》
1. 静态库。
静态库都是lib**.a格式的文件。利用静态库编译的可执行文件会相对比较大,因为静态库会把整个库都整合进目标代码中。
使用静态库有一个好处,可执行文件编译成功后,是独立的可执行文件,而不需要依赖于任何外部的函数库支持。
我们知道,目标文件一般都是由多个*.o的文件连接编译而成。而静态库lib**.a 你可以把它当成由多个.o文件组成的打包文件。
2. 动态库。
动态库都是以lib*.so格式的文件。动态函数库在编译的时候并不会被编译到目标代码中。你程序调用到动态函数库中的函数的时候才会去调用。
动态库的好处:编译生成的可执行文件比较小;动态函数库可以自由升级,现有的库并不需要跟着重新编译。
liunx下面有两个目录就放动态库 /lib /usr/lib
示例代码
我们先写一个示例代码:
main.c
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include "sum.h" #include "get.h" //入口主函数 int main() { int x = 10; int y = 20; int z = sum(&x, &y); puts("This is Main"); printf("Z:%d\n", z); x = 20; z = get(&x, &y); printf("Z:%d\n", z); return 1; }
val.c和val.c
#include <stdio.h>#include <stdlib.h>#include <unistd.h>int val(int *x);
#include "val.h"int val(int *x) {puts("This is Value==");printf("X:%d \n", *x);return 0;}
sum.h和sum.c
#include <stdio.h>#include <stdlib.h>#include <unistd.h>int sum(int *x, int *y);
#include "sum.h"#include "val.h"int sum(int *x, int *y) {val(x);puts("This is SUM Method!=========HDH");return *x + *y;}
get.h和get.c
#include <stdio.h>#include <stdlib.h>#include <unistd.h>int get(int *x, int *y);
#include "get.h"int get(int *x, int *y) {puts("This is get");return (*x) * (*y);}
如果我们按照先编译成.o文件,然后连接生成目标可执行文件,我们会发现这个过程是比较痛苦的:
[admin@localhost test_c4]$ lsget.c get.h libtest.a main.c sum.c sum.h val.c val.h[admin@localhost test_c4]$ rm -rf libtest.a [admin@localhost test_c4]$ lsget.c get.h main.c sum.c sum.h val.c val.h[admin@localhost test_c4]$ gcc -o get.o -c get.c[admin@localhost test_c4]$ gcc -o val.o -c val.c[admin@localhost test_c4]$ gcc -o sum.o -c sum.c[admin@localhost test_c4]$ gcc -o main.o -c main.c[admin@localhost test_c4]$ gcc -o main main.o val.o sum.o get.o[admin@localhost test_c4]$ lsget.c get.h get.o main main.c main.o sum.c sum.h sum.o val.c val.h val.o[admin@localhost test_c4]$ ./main This is Value==X:10 This is SUM Method!=========HDHThis is MainZ:30This is getZ:400
静态库
我们将sum.c val.c get.c文件生成静态库libtest.a。
1. 首先先要生成.o的文件
gcc -c sum.c val.c get.c
2. 然后通过静态库生成命令ar -rsv,生成libtest.a文件
ar -rsv libtest.a sum.o val.o get.o
结果:
[admin@localhost test_c4]$ ar -rsv libtest.a sum.o val.o get.oar: 正在创建 libtest.aa - sum.oa - val.oa - get.o[admin@localhost test_c4]$ lsget.c get.h get.o libtest.a main.c sum.c sum.h sum.o val.c val.h val.o
3. 我们可以通过ar -t命令,查看有多少个.o文件
ar -t libtest.a
结果:
[admin@localhost test_c4]$ ar -t libtest.a sum.oval.oget.o
4. 通过连接静态库方式生成可执行文件。
-L:命令主要用于搜索当前的目录。
-l test:就是调用我们的libtest.a静态库。我们调用libevent和线程,-l event -l pthread都是一样的方式。
gcc -o main main.c -L ./ -l test
另外一种方式,直接输入静态库的文件名称:
gcc main.c -o main ./libtest.a
动态库
动态库是指lib*.so的文件。
1. 首先我们需要通过gcc -O -fpic -shared -o 命令来生成libtest.so这个动态库。
gcc -O -fpic -shared -o libtest.so sum.c val.c get.c
2. 我们需要使用动态库来编译main可执行文件。
gcc main.c -o main ./libtest.so
结果:
[admin@localhost test_c4]$ lsget.c get.h libtest.a libtest.so main main.c sum.c sum.h val.c val.h[admin@localhost test_c4]$ ./main This is Value==X:10 This is SUM Method!=========HDHThis is MainZ:30This is getZ:400
3. 如果我们改变动态库的名称,则./main就不能运行了,因为main文件依赖于libtest.so文件。
[admin@localhost test_c4]$ mv libtest.so libtest2.so[admin@localhost test_c4]$ ./main ./main: error while loading shared libraries: ./libtest.so: cannot open shared object file: No such file or directory
4. 动态库的查看命令 ldd
ldd libtest2.so
结果:
[admin@localhost test_c4]$ ldd libtest2.so linux-vdso.so.1 => (0x00007fff4c5fe000)libc.so.6 => /lib64/libc.so.6 (0x00007fb2eaabe000)/lib64/ld-linux-x86-64.so.2 (0x00007fb2eb08b000)
5. 上面的方式是隐式调用,我们也可以通过代码的方式显示调用libtest.so动态库。
显示调用需要4个函数支持:
dlopen:打开动态库
dlsym:获取动态库地址
dlerror:捕捉错误信息
doclose:关闭动态库
具体使用,这边不讲解了。
不敢面对自己的不完美,总是担心自己的失败,