Linux 用于构建共享库的“soname”选项是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12637841/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 14:27:33  来源:igfitidea点击:

What is the 'soname' option for building shared libraries for?

linuxgccshared-libraries

提问by Samuel

I learned the "Program Library HOWTO". It mention that using sonameto manage the version like follow.

我学习了“程序库HOWTO”。它提到使用soname像follow一样管理版本。

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

And I get the information that if the sonameis not set. it will be equal to libfoo.so.1.0.0 ,see the answer from here.

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

And I find that it also can work without soname , like following

而且我发现它也可以在没有 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

So I think that the only one useful point is that the sonameoption can tell you the version of the shared library when you use readelf -d libfoo.socommand to check it.

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

What else can it do?

它还能做什么?

采纳答案by philippe lhardy

soname is used to indicate what binary api compatibility your library support.

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

SONAMEis used at compilation time by linker to determine from the library file what actual target library version. gcc -lNAMEwill seek for libNAME.so link or file then capture its SONAME that will certainly be more specific ( ex libnuke.so links to libnuke.so.0.1.4 that contains SONAME libnuke.so.0 ).

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

At run time it will link with this is then set into ELF dynamic section NEEDED, then a library with this name ( or a link to it ) should exists. At Run time SONAMEis disregarded, so only the link or the file existence is enough.

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

Remark: SONAME is enforced only at link/build time and not at run time.

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

'SONAME' of library can be seen with 'objdump -p file |grep SONAME'. 'NEEDED' of binaries can be seen with 'objdump -p file |grep NEEDED'.

可以使用“objdump -p file |grep SONAME”查看库的“SONAME”。可以使用“objdump -p file |grep NEEDED”查看二进制文件的“NEEDED”。

[EDIT] WARNING Following is a general remark, not the one deployed in linux. See at the end.

[编辑] 警告以下是一般性评论,而不是部署在 linux 中的评论。见最后。

Let's assume you have a library with libnuke.so.1.2 name and you develop a new libnuke library :

假设您有一个名为 libnuke.so.1.2 的库,并且您开发了一个新的 libnuke 库:

  • if your new library is a fix from previous without api change, you should just keep same soname, increase the version of filename. ie file will be libnuke.so.1.2.1 but soname will still be libnuke.so.1.2.
  • if you have a new library that only added new function but didn't break functionality and is still compatible with previous you would like to use same soname than previous plus a new suffix like .1. ie file and soname will be libnuke.so.1.2.1. Any program linked with libnuke.1.2 will still work with that one. New programs linked with libnuke.1.2.1 will only work with that one ( until new subversion come like libnuke.1.2.1.1 ).
  • if your new library is not compatible with any libnuke : libnuke.so.2
  • if your new library is compatible with bare old version : libnuke.so.1.3 [ ie still compatible with libnuke.so.1?]
  • 如果您的新库是以前的修复程序,没有更改 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 相关联的新程序仅适用于该程序(直到新的 subversion 像 libnuke.1.2.1.1 一样出现)。
  • 如果您的新库与任何 libnuke 不兼容:libnuke.so.2
  • 如果您的新库与旧版本兼容:libnuke.so.1.3 [即仍然与 libnuke.so.1 兼容?]

[EDIT] to complete : linux case.

[编辑] 完成:linux 案例。

In linux real life SONAME as a specific form : lib[NAME][API-VERSION].so.[major-version] major-version is only one integer value that increase at each major library change. API-VERSION is empty by default

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

ex libnuke.so.0

前 libnuke.so.0

Then real filename include minor versions and subversions ex : libnuke.so.0.1.5

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

I think that not providing a soname is a bad practice since renaming of file will change its behavior.

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

回答by Johann Klasek

Another aspect: At least on Linux the SONAME entry provides a hint for the runtime-linker system on how to create appropriate links in /lib, /lib64 etc. Running the command ldconfig tries to create a symbolic link named with SONAME which is also taken into the run-time linker cache. The newest one of the libraries tagging the same SONAME wins the link-race. If some software relies on the specific SONAME and you want to renew a library you have to provide this SONAME to get ldconfig stick on this new library (if ldconfig is used to rebuild the cache and the links). E.g. libssl.so.6 and libcrypto.so.6 are such cases.

另一个方面:至少在 Linux 上,SONAME 条目为运行时链接器系统提供了有关如何在 /lib、/lib64 等中创建适当链接的提示。运行命令 ldconfig 尝试创建一个以 SONAME 命名的符号链接,该链接也被采用进入运行时链接器缓存。标记相同 SONAME 的最新库之一赢得了链接竞赛。如果某些软件依赖于特定的 SONAME 并且您想要更新库,则必须提供此 SONAME 以使 ldconfig 粘在这个新库上(如果 ldconfig 用于重建缓存和链接)。例如 libssl.so.6 和 libcrypto.so.6 就是这种情况。

回答by Lw Cui

Let's assume libA.so depends on libB.so, and they all in a directory(of course the directory cannot be found by dynamic linker). If you didn't set sonamethen dlopendoesn't work:

让我们假设 libA.so 依赖于 libB.so,并且它们都在一个目录中(当然动态链接器无法找到该目录)。如果您没有设置,sonamedlopen不起作用:

auto pB = dlopen("./libB.so", RTLD_LAZY | RTLD_GLOBAL);
auto pA = dlopen("./libA.so", RTLD_LAZY | RTLD_GLOBAL);

Because runtime linker cannot find libB.so, so pAis set to NULL.

因为运行时链接器找不到libB.so,所以pA设置为NULL

In this case sonamewill save you from hell...

在这种情况下,soname将把你从地狱中拯救出来......

回答by BugKiller

Here is an example supporting Johann Klasek's answer.

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

In short, SONAME is needed at run time. At compilation time, only a linker name or real name is needed (e.g. g++ main.cpp -L. -laddor g++ main.cpp -L. -l:libadd.so.1.1). The definitons of linker name and real name follow Program Library HOWTO: 3. Shared Libraries.

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

Source tree:

源树:

├── add.cpp
├── add.h
├── main.cpp
└── Makefile

Makefile:

生成文件:

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}

回答by igoneHyman

You created a dynamic library named libx.1.0.0 in naming tradition libname.{a}.{b}.{c}

您在命名传统 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

Now you are releasing libx.1.2.0, and you need to declare that libx.1.2.0 is compatible with libx.1.0.0 since just adding functions and people's executable would not crashes, just link it like in the old time by:

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

Setting libx.1.0.0 and libx.1.2.0 to have the same soname, for example libx.1

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

This's what soname does.

这就是 soname 所做的。