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

时间:2019-05-15 11:21:34

标签: c shared-libraries static-linking autotools dynamic-linking

我正在建立一个动态库libfoo.so,该库依赖于libcrypto.so

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

libfoo_la_LIBADD += -L${OPENSSL_DIR}/lib -lcrypto

其中$OPENSSL_DIR默认为/usr,但可以通过传递--with-openssl-dir=/whatever来覆盖。

我如何确保使用libfoo.so的可执行文件使用${OPENSSL_DIR}/lib/libcrypto.so(仅)没有建造或运行该可执行文件的人必须使用rpath或小提琴与LD_LIBRARY_PATH

按目前的情况,我可以构建libfoo并通过--with-openssl-dir=/usr/local/openssl-special,它可以正常运行。但是当我运行ldd libfoo.so时,它仅指向libcrypto.so中的/usr/lib

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

1 个答案:

答案 0 :(得分:4)

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

尽管如此,您似乎排除了所有 种可能性:

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

  • 如果您改为使用动态库,则可以在运行时依靠动态链接器将库实现与可执行文件相关联。在这种情况下,如何将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 / {{1} },确保所有组件都通过相同的RUNPATH需要目标库。我倾向于提供一个设置SONAME的包装器脚本,以使其作用范围狭窄。

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


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