用于构建共享库的'soname'选项是什么?

Sam*_*uel 48 linux gcc shared-libraries

我学会了" 程序库HOWTO ".它提到soname用于管理如下的版本.

gcc -shared -fPIC -Wl,-soname,libfoo.so.1  -o libfoo.so.1.0.0 foo.c
ln -s libfoo.so.1.0.0  libfoo.so.1
ln -s libfoo.so.1 libfoo.so
Run Code Online (Sandbox Code Playgroud)

我得到的信息是,如果soname没有设置.它将等于libfoo.so.1.0.0,请参阅此处的答案.

我发现它也可以在没有soname的情况下工作,就像下面一样

 gcc -shared -fPIC -o libfoo.so.1.0.0 foo.c
 ln -s libfoo.so.1.0.0  libfoo.so.1
 ln -s libfoo.so.1 libfoo.so
Run Code Online (Sandbox Code Playgroud)

所以我认为唯一有用的一点是,soname当您使用readelf -d libfoo.so命令检查时,该选项可以告诉您共享库的版本.

它还能做什么?

phi*_*rdy 49

soname用于指示您的库支持的二进制api兼容性.

SONAME链接器在编译时使用它来从库文件中确定实际的目标库版本.gcc -l NAME将寻找lib NAME.so链接或文件然后捕获它肯定会更具体的SONAME(ex libnuke.so链接到包含SONAME libnuke.so.0的libnuke.so.0.1.4).

在运行时,它将与此链接,然后设置为ELF动态部分NEEDED,然后应该存在具有此名称(或其链接)的库.在运行时SONAME被忽略,因此只有链接或文件存在就足够了.

备注:SONAME仅在链接/构建时强制执行,而不是在运行时强制执行.

使用'objdump -p file | grep SONAME'可以看到库的'SONAME'.使用'objdump -p file | grep NEEDED'可以看到'NEEDED'的二进制文件.

[编辑]警告以下是一般性评论,而不是在Linux中部署的评论.最后看到.

假设你有一个libnuke.so.1.2名称的库,你开发了一个新的libnuke库:

  • 如果您的新库是以前没有api更改的修复,您应该保持相同的soname,增加文件名的版本.即文件将是libnuke.so.1.2.1但是soname仍然是libnuke.so.1.2.
  • 如果你有一个新的库只添加了新的功能,但没有破坏功能,并且仍然与之前兼容,你想使用与之前相同的soname加上一个新的后缀,如.1.即文件和soname将是libnuke.so.1.2.1.任何与libnuke.1.2链接的程序仍然适用于那个程序.与libnuke.1.2.1相关联的新程序只适用于那个(直到新的颠覆来自libnuke.1.2.1.1).
  • 如果你的新库与任何libnuke:libnuke.so.2不兼容
  • 如果您的新库与旧版本兼容:libnuke.so.1.3 [即仍与libnuke.so.1兼容]

[编辑]完成:linux案例.

在linux现实生活中SONAME作为一种特定形式:lib [NAME] [API-VERSION] .so.[major-version] major-version只有一个整数值,在每个主要库变化时都会增加.默认情况下,API-VERSION为空

ex libnuke.so.0

然后真正的文件名包括次要版本和颠覆ex:libnuke.so.0.1.5

我认为不提供soname是一种不好的做法,因为重命名文件会改变它的行为.


igo*_*ack 6

您在命名传统 libname.{a}.{b}.{c} 时创建了一个名为 libx.1.0.0 的动态库

{a} stand for primary version, should changes when APIs changes(which making things incompatible).
{b} stand for sub version, should changes by adding APIs.
{c} stand for mirror version, should changes by bug fixing or optimizing
Run Code Online (Sandbox Code Playgroud)

现在您要发布 libx.1.2.0,并且您需要声明 libx.1.2.0 与 libx.1.0.0 兼容,因为只需添加函数并且人们的可执行文件不会崩溃,只需像过去一样链接它:

将 libx.1.0.0 和 libx.1.2.0 设置为具有相同的 soname,例如 libx.1

这就是 soname 所做的。


Bug*_*ler 5

这是一个支持Johann Klasek's answer的例子。

简而言之,运行时需要 SONAME。在编译时,只需要链接器名称或真实名称(例如g++ main.cpp -L. -laddg++ main.cpp -L. -l:libadd.so.1.1)。链接器名称和真实名称的定义遵循Program Library HOWTO: 3. 共享库

源树:

??? add.cpp
??? add.h
??? main.cpp
??? Makefile
Run Code Online (Sandbox Code Playgroud)

生成文件:

SOURCE_FILE=add.cpp
# main.cpp includes `add.h`, whose implementation is `add.cpp`
MAIN_FILE=main.cpp
SONAME=libadd.so.1
REAL_NAME=libadd.so.1.1
LINKER_NAME=libadd.so
OUTPUT_FILE=a.out

all:
   g++ -shared -fPIC -Wl,-soname,${SONAME} -o ${REAL_NAME} ${SOURCE_FILE}
   ln -s ${REAL_NAME} ${LINKER_NAME}
   g++ main.cpp -I. -L. -ladd -o ${OUTPUT_FILE} 
   # Same as `ldconfig -n .`, creates a symbolic link
   ln -s ${REAL_NAME} ${SONAME}
   #./a.out: error while loading shared libraries: libadd.so.1: cannot open 
   # shared object file: No such file or directory
   LD_LIBRARY_PATH=. ./${OUTPUT_FILE}
clean:
   rm ${SONAME} ${REAL_NAME} ${LINKER_NAME} ${OUTPUT_FILE}
Run Code Online (Sandbox Code Playgroud)