# 一、静态库和动态库 - 库文件与源文件的关系是:C语言源代码文件是可以直接阅读且可以直观的了解其内部的实现原理,库文件依然属于源码文件,但是编程人员无法阅读。 - 如果我们不想将源码(函数的实现)展现给别人,但又需要给别人提供源码所实现的关键功能,就可以将这些源码文件封装成库文件,只提供给使用者对应的头文件和库文件即可。既可以使他人使用自己编写的代码,又能保护自己的知识产权,同时又能方便自己升级与维护。 - 库文件的一般格式为 - 动态库:libxxx.so(libxxx.so.2.1.0) - 静态库:libxxx.a ## 1、动态库 - Linux中的动态库的后缀为.so,前缀为lib,即libxxx.so,xxx是库的名字,如:libmylib.so;windows的动态库的后缀为.dll等 (1)制作动态库 ```shell gcc  -shared  -fPIC  -o  libhello.so  hello.c  -I../include/ ``` > 不加 -fPIC 生成的动态库,“ 生成动态库时假定它被加载在地址 0 处。加载时它会被加载到一个地址(base),这时要进行一次重定位(relocation),把代码、数据段中所有的地址加上这个 base 的值。这样代码运行时就能使用正确的地址了。” > 加上 fPIC 选项生成的动态库,是位置与无关的,这样的代码本身就能被放到线性地址空间的任意位置,无需修改就能正确执行。 > 通常的方法是获取指令指针的值,加上一个偏移得到全局变量 / 函数的地址。 > 加 fPIC 选项的源文件对于它引用的函数头文件编写有很宽松的尺度。比如只需要包含某个声明的函数的头文件,即使没有相应的 C 文件来实现,编译成 so 库照样可以通过。 (2)使用动态库 编译: ```shell gcc -o ./bin/hello ./src/main.c -I ./include/ -L ./lib/ -lhello ``` 说明: ``` -I 告诉编译器头文件的路径 -L 告诉编译器库文件的路径 -l 链接库文件名,如libhello.so去头去尾hello ``` 如:库的名字是libmylib.so,链接时就写-lmylib 运行: ![](images/WEBRESOURCE4684b7496c77366547f869ae2b65b6d7image.png) 报错: ![](images/WEBRESOURCE79d40806b934939775f7460001a79cbbimage.png) 解决方法: 第一种:指定库路径,但只对当前终端有效(绝对路径) export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:****/lib 第二种:将库文件拷贝到系统库目录中(/lib  or  /usr/lib) cp  libfun.so  /usr/lib 第三种:将添加环境变量的指令写入当前终端脚本种"~/.bashrc" 2、静态库 Linux中的动态库的后缀为.a,前缀为lib,即libxxx.a,xxx是库的名字,如:libmylib.a windows的动态库的后缀为.lib (1)制作静态库 ①先生成.o文件 ``` gcc -o hello.o -c hello.c  -I ../include/ ``` ②生成静态库 ```shell ar  rc   libhello.a  hello.o ``` (2)使用静态库 编译: ``` gcc -o ./bin/target ./src/main.c -I ./include/ -L ./lib/ -lphoto ``` 说明: ```c -I 告诉编译器头文件的路径 -L 告诉编译器库文件的路径 -l 链接库文件名,如libhello.so去头去尾hello ``` 如:库的名字是libmylib.aa,链接时就写-lmylib 运行: ./target ![](images/WEBRESOURCE809cda2ce0aa92b5b344707c1d4a3629image.png) ![](images/WEBRESOURCE598297eb23f470b37d35d6d3f1451fe9image.png) ![](images/WEBRESOURCE11280c9480d3c2eee39d2dc737f123cfimage.png) - 静态库和动态库的区别: - 静态库生成的可执行文件运行时不再需要依赖静态库文件,因为静态库会直接参与编译因此可执行文件较大,不方便维护和升级(升级功能必须程序编译整个工程得到新的可执行程序方可使用新功能)。 - 动态库生成的可执行文件运行时还需要依赖动态库文件,因为动态库只链接而不参与编译因此可执行文夹较小,方便维护和升级(程序函数名字返回值与参数列表不改变的情况下只修改函数功能不需要重新编译整个工程,只需呀编译这个文件生成新的动态库替换原来的动态库即可使用新的功能(或者将库文件的名字带上版本号使用链接文件的形式生成库文件))。 ![](images/WEBRESOURCE048d46d9bb04ceb46b8fe1f3cc419d92image.png)