Who are you?

Linux中的函数库

这篇文档主要对Linux系统中静态库和动态库进行一个比较系统的学习。

Linux下的函数库

分类

linux下的库有两种:静态库和共享库(动态库)。

二者的不同点在于代码被载入的时刻不同:

  • 静态库的代码在编译过程中已经被载入可执行程序,运行时将不再需要该静态库,因此体积较大。
  • 共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。

命名

在linux下,库文件一般放在/usr/lib和/lib下,

  • 静态库的名字一般为libxxxx.a,其中xxxx是该lib的名称

  • 动态库的名字一般为libxxxx.so.major.minor,xxxx是该lib的名称,major是主版本号, minor是副版本号

    动态库的三个名字:

    • “real name”:实际的文件名,这是实际生成的库文件,一般命名为libXXX.so.X.Y.Z

      其中XXX是自定义的名字,后面的X,Y,Z是用数字表示的版本号

      • X是主版本号,一般在库的接口发生改变,无法兼容的时候,更新这个数字
      • Y是次版本号,如果接口没有改变,只是升级算法,或者增加新接口,更新这个数字
      • Z是build版本号,一般每升级一次加1,也可以省略
    • “soname”:共享库的一个特殊的名字,在每个共享库生成的时候,一般会指定这个名字

      一般命名为libXXX.so.X,其实就是上面的real name去掉最后两个版本号

      每一个程序,在编译的时候,会指定一个他需要的共享库的soname,程序在启动的时候,由系统自动找到一个合适的共享库来使用

      从前面可以看出,X是主版本号,一般接口有改变,无法保持兼容,才会更改这个数字,所以,soname就要指定这个数字,避免由于接口改变导致运行错误

    • “link name”:这个是在编译可执行程序的时候,使用的名字,如果要自己编译程序,就需要关心这个名字。比如我们在编译需要用到数学库的程序时,需要加上-lm参数,这个参数的意义就是,编译器会去寻找libm.so这个共享库(或者libm.a这个静态库,这个不是本文重点),这里的libm.so就是link name,命名的规则很明显,就是把soname后面的版本也去掉,只保留libXXX.so

    • 一般用readelf -d libXXX.so.X.Y.Z来查看一个共享库文件的soname,其实real namesoname真正的对应关系是用这个命令来看的

Static Library

创建

详细创建过程可以参见:Linux编译器学习

1
2
3
4
5
# 创建
gcc hello.c -o hello.o #这里没有使用-shared
ar -r libhello.a hello.o #这里的ar相当于tar的作用,将多个目标打包。
# 编译链接
gcc main.c -lhello -L. -static -o main #-static也可以不加

Shared Library

创建

详细创建过程可以参见:Linux编译器学习

1
2
3
4
5
6
7
# 创建
gcc -fPIC -shared hello.c -o libhello.so
# 编译链接
gcc main.c -L. -lhello -o main
# 运行
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
./main

注意:

  1. 创建时的选项-fpic-shared,其中-fpic还有-fPIC形式,区别在于-fPIC生成的库比较大,比较通用,-fpic生成的可能受平台限制较大
  2. 编译链接时需要指定位置,可以使用-L或是添加环境变量LIBRARY_PATH的方式来将相关库文件包含到搜索路径中,然后还需要通过-l指定函数库,使用到gcc非标准内置函数库时需要加上-lm选项
  3. 运行前需要将库函数添加到路径中,一般都是通过改变LD_LIBRARY_PATH来实现路径的包含,更多可见Linux环境变量及编译器库路径
  4. 可以通过自带的ldd命令来分析动态库的链接情况,如果目标程序没有链接动态库,则打印“not a dynamic executable”

对于Gfortran的一些建议

  1. -l library 选项的命令行顺序

    • -llibrary 选项放置在任一 .f.for.F.f95.o 文件之后。
    • 如果调用了 libx 中的函数,并且这些函数引用了 liby 中的函数,则将 -lx 置于 -ly 之前。
  2. -L dir

    只有将其放在它所应用的 –llibrary 选项之前,该选项才有用。

  3. 库搜索路径和顺序-动态链接

    • 在生成时指定动态库:

      1
      f95 program.f -R/home/proj/libs -L/home/proj/libs -lmylib

      生成可执行文件时,链接程序会在可执行文件本身中记录共享库的路径。这些搜索路径可以用 -Rpath 选项指定。这一点与 -Ldir 选项相反,该选项在生成时指示到哪里查找 -llibrary 选项所指定的库,但不会将该路径记录到二进制可执行文件中。

    • 在运行时指定动态库:修改LD_LIBRARY_PATH

参考: