Files
BlogPosts/Collection/YoudaoyunNotes/02C语言/15-静态库与动态库.md

4.3 KiB
Raw Blame History

一、静态库和动态库

  • 库文件与源文件的关系是C语言源代码文件是可以直接阅读且可以直观的了解其内部的实现原理库文件依然属于源码文件但是编程人员无法阅读。

  • 如果我们不想将源码(函数的实现)展现给别人,但又需要给别人提供源码所实现的关键功能,就可以将这些源码文件封装成库文件,只提供给使用者对应的头文件和库文件即可。既可以使他人使用自己编写的代码,又能保护自己的知识产权,同时又能方便自己升级与维护。

  • 库文件的一般格式为

  • 动态库libxxx.so(libxxx.so.2.1.0)

  • 静态库libxxx.a

1、动态库

  • Linux中的动态库的后缀为.so前缀为lib即libxxx.soxxx是库的名字libmylib.sowindows的动态库的后缀为.dll等

1制作动态库

gcc  -shared  -fPIC  -o  libhello.so    hello.c     -I../include/
 不加 -fPIC 生成的动态库,“ 生成动态库时假定它被加载在地址 0 处。加载时它会被加载到一个地址base这时要进行一次重定位relocation把代码、数据段中所有的地址加上这个 base 的值。这样代码运行时就能使用正确的地址了。”
  加上 fPIC 选项生成的动态库,是位置与无关的,这样的代码本身就能被放到线性地址空间的任意位置,无需修改就能正确执行。
  通常的方法是获取指令指针的值,加上一个偏移得到全局变量 / 函数的地址。
  加 fPIC 选项的源文件对于它引用的函数头文件编写有很宽松的尺度。比如只需要包含某个声明的函数的头文件,即使没有相应的 C 文件来实现,编译成 so 库照样可以通过。

2使用动态库

编译:

gcc     -o   ./bin/hello    ./src/main.c     -I ./include/  -L ./lib/  -lhello

说明:

-I 告诉编译器头文件的路径
-L 告诉编译器库文件的路径
-l 链接库文件名如libhello.so去头去尾hello

库的名字是libmylib.so链接时就写-lmylib

运行:

报错:

解决方法:

第一种:指定库路径,但只对当前终端有效(绝对路径)

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:****/lib

第二种:将库文件拷贝到系统库目录中(/lib  or  /usr/lib

cp  libfun.so  /usr/lib

第三种:将添加环境变量的指令写入当前终端脚本种"~/.bashrc"

2、静态库

Linux中的动态库的后缀为.a前缀为lib即libxxx.axxx是库的名字libmylib.a

windows的动态库的后缀为.lib

1制作静态库

①先生成.o文件

gcc  -o  hello.o -c hello.c  -I ../include/

②生成静态库

ar  rc   libhello.a  hello.o

2使用静态库

编译:

gcc -o ./bin/target ./src/main.c -I ./include/ -L ./lib/ -lphoto

说明:

-I 告诉编译器头文件的路径
-L 告诉编译器库文件的路径
-l 链接库文件名,如libhello.so去头去尾hello

库的名字是libmylib.aa链接时就写-lmylib

运行:

./target

  • 静态库和动态库的区别:

  • 静态库生成的可执行文件运行时不再需要依赖静态库文件,因为静态库会直接参与编译因此可执行文件较大,不方便维护和升级(升级功能必须程序编译整个工程得到新的可执行程序方可使用新功能)。

  • 动态库生成的可执行文件运行时还需要依赖动态库文件,因为动态库只链接而不参与编译因此可执行文夹较小,方便维护和升级(程序函数名字返回值与参数列表不改变的情况下只修改函数功能不需要重新编译整个工程,只需呀编译这个文件生成新的动态库替换原来的动态库即可使用新的功能(或者将库文件的名字带上版本号使用链接文件的形式生成库文件<lib****.so>))。