一、什么是库
库:简单地说,库就是模块。在系统中是一个二进制文件,它由 .c(没有main)文件编译而来,其他的程序就是使用这个库中的函数,其中库又分为静态库和动态库。不同的操作系统对应库文件的格式不同。由于库文件是二进制文件,所以不能够看到函数的实现过程,只能调用函数,比较安全。
windows:
xxx.lib(静态库)
xxx.dll(动态库)——(dynamic link library)
linux:
libxxx.a(静态库)
libxxx.so(静态库)
二、静态库
静态库是将 xxx.c 文件编译生成一个 lib库名.a 的二进制文件,当你需要使用这个库中的某个函数的时候直接调用这个库中的函数即可。
gcc在编译代码的时候会将你的文件和库最终编译生成一个二进制的文件(把库也放到可执行程序中了),可执行程序的体积比较大,但是在执行可执行程序的时候,就不需要找库文件了(可执行文件可以单独执行),所以使用静态库编译的程序执行效率比动态库的高。
静态库的创建步骤:
1.编写源文件(.c / .cpp)
2.通过 gcc -c xxx.c -o xxx.o 编译生成目标文件(.o)
3.使用 ar -cr libxxx.a xxx.o 命令归档目标文件,生成静态库
4.配合静态库写一个头文件,文件里的内容就是提供给调用者使用的函数、变量或者类的声明
注:ar命令不但可以创建静态库,也可以修改或提取已有静态库中的信息。其基本用法如下:
ar [option] libxxx.a xx1.o xx2.o xx3.o
xx1.o xx2.o为静态库的目标代码文件,可以有多个。option常见的选项如下:
-c:创建一个库,无论库是否存在,都会创建
-s:创建目标文件索引
-r:在库中插入模块,如插入的模块名已经在库中存在,则将会替换。如果有一个模块不存在,将会保存,并不会替换其他同名模块
-t:显示库文件中有哪些目标文件。仅仅显示
-tv:显示库文件有哪些目标文件。包括文件名、时间、大小等
-s:显示静态库文件中的索引表
静态库的使用:
-L :指定库的路径
-l :链接要使用的库(其中lib和.a不需要显示写出,编译器会自动去寻找。这也就是为什么库命名的时候要以lib开头。)
-I :指定头文件的路径
gcc main.c -L . -ladd -I .
三、动态库
动态库是将 xxx.c 文件编译生成一个 lib库名.so 的二进制文件,当你需要使用这个库中的某个函数的时候直接调用这个库中的函数即可。
gcc在编译代码的时候会将你的文件和库中函数的符号表编译生成一个二进制的文件,可执行程序的体积比较小,但是在执行可执行程序的时候,必须去找 lib库名.so 的文件,效率比静态库的低。一个动态库可以被多个程序共享,动态库又叫共享库。
注:在Linux系统下进行的链接,默认是先链接动态库,如果同时存在静态库和动态库,如果不特别指出,将与动态库链接。这样有助于节省空间。
动态库的创建步骤:
1.编写源文件(.c / .cpp)
2.通过 gcc -fPIC -c add.c -o add.o 编译生成目标文件(.o)
3.使用 gcc -shared add.o -o libadd.so 命令归档目标文件,生成动态库
4.配合静态库写一个头文件,文件里的内容就是提供给调用者使用的函数、变量或者类的声明
注:PIC全称是Position Independent Code。在Linux系统下编译共享库时,必须加上这个参数,否则在链接的时候将会报错。因为共享库文件可能会被不同的进程加载到不同的位置上,如果共享对象中的指令使用了绝对地址、外部模块地址等,那么该库在被加载的时候,就需要修改地址,这样就不能实现多进程共享一份物理内存。
-fPCI:位置无关代码,忽略文件的位置
-shared:生成动态库
gcc -fPIC -shared add.c -o libadd.so
动态库的使用:
-L :指定库的路径
-l :链接要使用的库
-I :指定头文件的路径
gcc main.c -L . -ladd -I .
但是,这样执行会发现错误:
执行依赖动态库程序时候错误的解决方法
1.在命令行指定库的路径(LD_LIBRARY_PATH)
export LD_LIBRARY_PATH=../lib
注:上述的解决方法只在当前终端生效
2.将上述的库放在系统库的路径下(/lib /usr/lib/)
sudo mv libadd.so /lib
3.修改系统的库的配置文件
sudo vi /etc/ld.so.conf.d/libc.conf //修改系统的配置文件
sudo ldconfig //让配置文件生效