动态库与静态库
静态库与动态库
我的博客
蒋炎岩老师的操作系统课程
本文例来自《深入理解计算机系统》英文书为《Computer Systems A Programmer's Perspective》即 CS APP.
静态库
源文件
main.c
#include <stdio.h>
#include "vector.h"
int x[2] = {1, 2};
int y[2] = {3, 4};
int z[2];
int main(void)
{
addvec(x, y, z, 2);
printf("z = [%d %d] \r\n", z[0], z[1]);
return 0;
}
静态链接源文件 addvec.c
,multvec.c
-
addvec.c
int addcnt = 0; void addvec(int *x, int *y, int *z, int n) { int i; addcnt++; for(i = 0; i < n;i++) { z[i] = x[i] + y[i]; } }
-
multvec.c
int multcnt = 0; void multvec(int *x, int *y, int *z, int n) { int i; multcnt++; for(i = 0; i < n; i++) { z[i] = x[i] * y[i]; } }
头文件 vector.h
#ifndef __VECTOR_H
#define __VECTOR_H
void addvec(int *x, int *y, int *z, int n);
void multvec(int *x, int *y, int *z, int n);
#endif
目录结构如下:
arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ ls
addvec.c main.c multvec.c vector.h
生成静态库
在源码路径下执行如下命令,首先编译汇编源文件,生成目标文件,再使用目标文件生成静态库 libvector.a
:
arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ gcc -c addvec.c multvec.c
arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ ar rcs libvector.a addvec.o multvec.o
此时目录下有如下文件:
arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ ls
addvec.c addvec.o libvector.a main.c multvec.c multvec.o vector.h
链接生成可执行文件
执行如下命令首先编译 main.c
文件,再链接静态库,生成可执行文件 prog
:
arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ gcc -c main.c
arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ gcc -static -o prog main.o ./libvector.a
此时目录下有如下文件:
arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ ls
addvec.c addvec.o libvector.a main.c main.o multvec.c multvec.o prog vector.h
执行可执行文件
现在可执行生成的可执行文件,因为是静态链接,可执行文件包含所有自己需要的内容,这个可执行文件可以拷贝到本机的任意位置执行,也可以拷贝到相同环境的设备上去执行:
arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ ./prog
z = [4 6]
可以查看这个文件所包含的内容:
arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ size prog
text data bss dec hex filename
762186 20772 6112 789070 c0a4e prog
动态库
动态库例子中使用的源码与静态库中的一样。
生成动态链接库
执行如下命令生成动态链接库 libvector.so
:
arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ gcc -shared -fpic -o libvector.so addvec.c multvec.c
此时目录下有:
arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ ls
addvec.c libvector.so main.c multvec.c vector.h
生成可执行文件
执行如下命令生成依赖于动态库的可执行文件 prog1
:
arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ gcc -o prog1 main.c ./libvector.so
此时目录下有文件:
arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ ls
addvec.c libvector.so main.c multvec.c prog1 vector.h
执行可执行文件
在动态库同级目录下可以运行刚才生成的可执行文件:
arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ ./prog1
z = [4 6]
因为我们在编译可执行文件的时候,使用了 ./libvector.so
这样的字样,因此它的二进制文件中包含 ./libvector.so
这样的内容,执行这一可执行文件,它会在本级目录下查找这一动态库,因此可以执行。
如果使用如下的编译命令:
arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ gcc -o prog1 main.c libvector.so
此时,即便在 libvector.so
同级目录下,这一文件也不能执行:
arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ ./prog1
./prog1: error while loading shared libraries: libvector.so: cannot open shared object file: No such file or directory
可以将这个动态库导入到环境变量 LD_LIBRARY_PATH
,中:
export LD_LIBRARY_PATH="/home/arv/lib_temp/dynamic_lib:$LD_LIBRARY_PATH"
此时,可以在任意位置执行这个新的可执行文件了:
arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ ./prog1
z = [4 6]
arv@arv-OptiPlex-7090:~/lib_temp/another_dir$ ./prog1
z = [4 6]
查看文件内容
arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ size prog1
text data bss dec hex filename
1720 640 16 2376 948 prog1
使用我们的动态库
dll.c
源码
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int x[2] = {1, 2};
int y[2] = {3, 4};
int z[2];
int main()
{
void *handle;
void (*addvec)(int *, int *, int *, int);
char *error;
/* 注意到,因为之前我们已经将动态库导入到环境变量了 */
handle = dlopen("libvector.so", RTLD_LAZY);
if(!handle)
{
fprintf(stderr, "%s\r\n", dlerror());
exit(1);
}
addvec = dlsym(handle, "addvec");
if((error = dlerror()) != NULL)
{
fprintf(stderr, "%s\r\n", dlerror());
exit(1);
}
addvec(x, y, z, 2);
printf("z = [%d %d]\r\n", z[0], z[1]);
if(dlclose(handle) <0)
{
fprintf(stderr, "%s\r\n", dlerror());
exit(1);
}
return 0;
}
生成可执行文件
arv@arv-OptiPlex-7090:~/lib_temp/another_dir$ gcc -rdynamic -o prog2 dll.c -ldl
执行可执行文件
arv@arv-OptiPlex-7090:~/lib_temp/another_dir$ ./prog2
z = [4 6]
查看系统调用过程
可以通过如下的小工具,分别查看静态库与动态库的可执行文件在执行时,所做的系统调用过程:
strace prog