我可以强制动态库链接到特定的动态库依赖项吗?

Dun*_*nes 2 c autotools shared-libraries dynamic-linking static-linking

我正在构建一个动态库libfoo.so,该库取决于libcrypto.so

在我的自动工具Makefile.am文件中,我有这样一行:

libfoo_la_LIBADD += -L${OPENSSL_DIR}/lib -lcrypto
Run Code Online (Sandbox Code Playgroud)

其中$OPENSSL_DIR缺省为/usr,但可以通过使被覆盖--with-openssl-dir=/whatever

我如何确保(仅)libfoo.so使用一个可执行文件而无需构建或运行该可执行文件的人来使用或摆弄?${OPENSSL_DIR}/lib/libcrypto.sorpathLD_LIBRARY_PATH

就目前情况而言,我可以构建libfoo并通过--with-openssl-dir=/usr/local/openssl-special,并且构建良好。但是,当我运行ldd libfoo.so,它只是指向libcrypto.so/usr/lib

我能想到的唯一解决方案是静态链接libcrypto.alibfoo.so。还有其他可能的方法吗?

Joh*_*ger 5

运行时动态链接的详细信息因平台而异。自动工具可以在某种程度上使您与之隔离,但是如果您关心细节(显然是您这样做的),则可能不足以让自动工具为您选择。

话虽如此,但您似乎在排除所有可能性:

  • 确保在运行时获得在构建时链接的特定实现的最可靠方法是静态链接。但是你说你不想那样。

  • 如果改用动态库,则在运行时依靠动态链接器将库实现与可执行文件相关联。在这种情况下,对于如何将DL定向到特定的库实现,有两种常规选择:

    1. 通过信息存储在程序/库的二进制文件中。您正在使用的术语表明基于ELF的系统,对于ELF共享对象,则是RPATH和/或RUNPATH传达有关在哪里寻找所需库的信息。没有与单个库要求相关联的路径信息;它们仅由SONAME标识。但是您说您不想使用RPATH*,因此我想也不要RUNPATH

    2. 通过静态或动态配置的动态链接器。这是LD_LIBRARY_PATH进入的地方,但是您说您不想使用它。动态链接器通常还具有一个或多个配置文件,例如/etc/ld.so.conf。您可以在此处指定要搜索的库目录,并稍加注意,以搜索它们的顺序。

然后,可以通过更新动态链接程序的配置文件,使它首先搜索所需的路径,来使所需的库实现链接到应用程序。但是,这会影响整个系统,而且很脆弱。

或者,根据依赖项的性质的详细信息,您可以为所需的libcrypto版本提供不同的SONAME。实际上,就静态和动态链接器而言,这将使其成为一个不同的对象(例如 libdjcrypto)。但这是有风险的,因为如果您的库同时具有对libcrypto的直接和间接依赖关系,或者如果使用您的库的程序通过另一路径依赖于libcrypto,那么您将在运行时(动态地)链接两个库,并且可能甚至使用两个函数,具体取决于每个调用的来源。

请注意,如果您也静态链接库,则上述问题也应该引起您的注意。如果这libcrypto在您的库中留下了任何间接的动态依赖关系,或者在使用该库的程序中有来自其他来源的任何动态依赖关系,那么您最终将同时使用多个版本的libcrypto。

底线

对于一个可执行,最好的选择是:(1)全静态键或(2)(对于ELF)RPATH/ LD_LIBRARY_PATH/ RUNPATH,确保所有的部件需要经由相同的目标库SONAME。我倾向于提供一个set的包装脚本LD_LIBRARY_PATH,以使其作用范围狭窄。

对于可重用的,“不要这样做”可能是最好的选择。使用另一个库的两个不同版本(在本例中为libcrypto)同时结束程序的可能性很高,这使得所有可用选项都没有吸引力。当然,除非您同意同一程序使用多个库版本,否则在这种情况下,静态链接和RPATH/ RUNPATH(但不是LD_LIBRARY_PATH)是您最佳的选择。


*请注意,至少某些版本的libtool用户习惯于添加RPATH条目,无论您是否要求它们-都需要提防。您可能需要修补安装在项目中的libtool脚本,以避免这种情况。