c++ - 共享对象文件中的版本号

标签 c++ linux gcc compiler-construction shared-libraries

我正在使用 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 中的数字)(当然,假设系统中安装并使用了以前的版本)。

文件名中的第 2 和第 3 个数字允许对系统中的库进行多个较小的修订,可通过简单的符号链接(symbolic link)更新在系统范围内切换。

在链接时,您可以将 .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)

它显然找不到它,但这就是符号链接(symbolic link)的用途:

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 字段,它表示有多少主要版本向后兼容当前版本

推荐阅读:

关于c++ - 共享对象文件中的版本号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5760111/

相关文章:

C++ MFC SQLite sqlite3_exec 回调

c++ - 将 ntp 时间设置为特定时区

linux - 通过 Bash 从 Cisco C40 获取输出

C++ 开始()和结束()

c++ - 有没有办法 "statically"将共享的 .so(或 .o)库插入可执行文件?

c++ - 使用 fstream 加载二进制文件

Javascript 函数作为从 C++ 定义的 QML 属性

linux - 亚马逊 linux AMI 与 Ubuntu

windows - Mac OS X 上的/proc/self/cmdline/GetCommandLine 是什么?

c - va_list 参数未按预期工作