我正在使用 GCC 从一组 C++ 源文件构建一个共享对象文件。 有关构建
.so
文件的所有示例教程均显示使用 .so
后缀后的版本号创建的文件。 例如:
gcc -shared -Wl,-soname,libmean.so.1 -o libmean.so.1.0.1 calc_mean.o
这将生成
.so
文件 libmean.so.1.0.1
此外,如果我浏览本地计算机上的
/usr/lib
目录,我会看到许多 .so
文件末尾都有版本号。
但是,当我编译共享对象文件并将其放入
/usr/lib
中时,如果我在末尾添加版本号,链接器将无法找到它。 如果我删除版本号,它就可以正常工作。 我真的不在乎是否添加版本号,我只是不明白为什么这似乎是一个常见的约定,但这会导致共享库无法与链接器一起使用。 那么,这是怎么回事? 为什么约定将版本号放在 .so
文件名的末尾?
附加版本号,以便您可以在系统中共存多个不兼容的库版本。每次以不兼容的方式更改 API 时,都应该增加主版本号(
soname
中的数字)(当然,假设系统中安装并使用了以前的版本)。
文件名中的第二个和第三个数字允许对系统中的库进行多次较小的修订,可通过简单的符号链接更新在系统范围内进行切换。
在链接时,您可以将
.so
文件名作为链接器参数,而不是 -l
选项。 ldd 足够聪明,可以从中提取 soname
,以这种方式链接的二进制文件使用它来查找库。
例如,让我们编译该库并使用它测试二进制文件:
czajnik@czajnik:~/z$ gcc -shared -Wl,-soname,libtest.so.2 -o libtest.so.2.3.4 a.c
czajnik@czajnik:~/z$ gcc -o test b.c -L. ./libtest.so.2.3.4
您可以使用 ldd 来验证二进制文件现在正在寻找
libtest.so.2
:
czajnik@czajnik:~/z$ LD_LIBRARY_PATH=. ldd ./test
linux-gate.so.1 => (0x002c1000)
libtest.so.2 => not found
libc.so.6 => /lib/libc.so.6 (0x00446000)
/lib/ld-linux.so.2 (0x00a28000)
显然找不到它,但这就是符号链接的用途:
czajnik@czajnik:~/z$ ln -s libtest.so.2.3.4 libtest.so.2
czajnik@czajnik:~/z$ LD_LIBRARY_PATH=. ldd ./test
linux-gate.so.1 => (0x00d75000)
libtest.so.2 => ./libtest.so.2 (0x00e31000)
libc.so.6 => /lib/libc.so.6 (0x00a5e000)
/lib/ld-linux.so.2 (0x00378000)
更新: 以上所有内容都是正确的,但我自己并不知道版本号第三部分的含义。直到最近,我还认为这只是一个补丁号(或类似的东西)。错误的!对于 libtool 它有特殊的含义。
第三个组件是 age 字段,它表示 有多少个主要版本与当前版本向后兼容。
推荐阅读: