使用一个虚构的例子来讲解。
系统: Debian GNU/Linux 12 (bookworm)
编译器: g++ (Debian 12.2.0-14) 12.2.0
基础
现在我想要编写一个程序,从命令行读取数字,计算该数字的平方根,并打印出结果。程序名字为calcSqrt
,假想的使用效果如下:
为了实现该程序,我编写了一个数学函数库MathFunctions
,程序 calcSqrt
调用其中的函数 MathFunctions::sqrt()
来计算平方根。
根据上述描述,最终得到的代码如下:
calcSqrt.cpp
MathFunctions/MathFunctions.h
MathFunctions/MathFunctions.cpp
编译运行程序:
非常完美地实现了想要的效果。
静态库
现在我想要把MathFunctions
制作成静态库,原因是这个库里含有商业机密,我想要的效果是,在我分发给别人后,别人只能使用该库,而无法看到实现代码。
制作静态库
通用的“公式”为:g++ -c -o lib库名.a 代码文件列表
。
运行上述命令,得到静态库libMathFunctions.a
。
各选项解释如下:
-c
: 告诉编译器只进行编译,而不进行链接。
-o
: 指定生成的目标文件的文件名。
使用静态库
通用的“公式”为:g++ 选项 代码文件列表 -l 库名 -L 库文件所在目录名
。
运行上述命令,成功生成目标程序calcSqrt
,和前面一样。
动态库
使用静态库,生成的目标程序二进制文件包含静态库的代码,程序体积会比较大。如果有多个程序都使用某个静态库,那么在这些程序中就会存在多份该库的拷贝,有点浪费空间。如果库代码更新了,使用该静态库的程序也需要重新编译,有点麻烦。
如果使用动态库,就没有这样的烦恼了。如果一个程序使用了一个动态库,在该程序运行的时候才会链接到该库。
制作动态库
通用的“公式”为:g++ -fPIC -shared -o lib库名.so 代码文件列表
运行上述命令,得到动态库libMathFunctions.so
。
各选项解释如下:
-fPIC
: 告诉编译器生成位置无关代码(Position Independent Code)。
-shared
: 告诉编译器生成一个共享库。
使用动态库
命令和使用静态库时一样。通用的“公式”为:g++ 选项 代码文件列表 -l 库名 -L 库文件所在目录名
。
运行上述命令,成功生成目标程序calcSqrt
,和前面一样。
运行生成的目标程序calcSqrt
,有如下提示:
意思是找不到动态库文件libMathFunctions.so
在哪。设置环境变量LD_LIBRARY_PATH
:
然后再次运行程序,这次成功运行:
疑问
既然使用动态库和使用静态库的命令一样,那么,如果同时存在动态库和静态库,程序是会使用动态库,还是会使用静态库呢?也就是,如果同时存在libMathFunctions.so
和libMathFunctions.a
,程序会链接哪个?
答案是,程序会优先使用动态库。
通过比较编译生成的程序文件大小来证明:
观察到,当同时存在动态库和静态库时,生成的可执行程序calcSqrt
的文件大小与使用动态库时生成的可执行程序文件大小相同。证明,当同时存在动态库和静态库时,编译器优先使用动态库。