在动态库中包装不同版本的静态库

问题描述 投票:4回答:3

在我的项目中,第三方依赖于静态库(从现在开始称为libsomething)。最近,libsomething已经出现在另一个版本中。我的任务是为我的软件提供旧版和新版的支持。在任何给定时间,只有一个版本的libsomething在运行时使用,但是哪个版本应该可以在程序运行之间进行配置。

我在WinXP上使用MSVC2005,第二个目标是准备切换到Linux和GCC。

由于libsomething的两个版本都使用相同的符号,因此将它们连接到我的可执行文件是不可能的,因为两个版本的符号将在链接时发生冲突。

虽然我可以创建两个可执行文件(一个链接旧版本,另一个使用新版本),但我无法决定在最终部署环境中调用哪个可执行文件(遗留原因)。

我提出了为每个版本的libsomething创建动态库包装的想法,并根据某些配置文件在运行时链接它们。使用MSCV,这将意味着沿着使用LoadLibrary()GetProcAddress()等的道路,而在Linux上,我将不得不使用dlopen()dlsym()

据我所知,使用libtool(即libtldl)包含此平台依赖项以使用共享库。这是一条合适的道路吗?是否有更好的(或至少是不同的)方式? libtldl的替代品是否作为开源存在?

c++ shared-libraries libtool
3个回答
0
投票

已经有几年了,但我想提一下完整性的另一种解决方案。您可以为所有必需的函数生成简单的存根,而不是手动dlopendlsym,并在第一次调用(或程序启动时)决定需要哪个库版本,加载它并解析地址。

您可以编写专门为您的项目定制的脚本或使用Implib.so工具:

# This will generate mylib.so.init.c and mylib.so.tramp.S
# which implement stubs. These need to be linked to your
# executable.
$ implib-gen.py mylib.so

Implib.so仅适用于Linux,但应该很容易适应Windows。


2
投票

我知道你说你不能使用两个可执行文件,因为决定执行哪个,但你不能在可执行文件之间来回exec,具体取决于在配置中选择哪个版本?


2
投票

在Linux上,您可以更轻松地链接到共享库并使用符号链接来更正版本 - IMO比使用dlopen() + dlsym()更容易。

因此,您将为库的旧版本和新版本创建共享库:

g++ -shared -o libshared.so.1.1 -Wl,-soname=libshared.so.1 -L. -Wl,--whole-archive libstatic.a.old -Wl,-no-whole-archive

g++ -shared -o libshared.so.1.2 -Wl,-soname=libshared.so.1 -L. -Wl,--whole-archive libstatic.a.new -Wl,-no-whole-archive

创建符号链接:

ln -s libshared.so.1.1 libshared.so.1
ln -s libshared.so.1 libshared.so

构建应用程序,将其链接到旧版本的库。我想两个版本都是二进制兼容的(ABI没有坏掉),但新版本可能有一些新的符号。

g++ -o myapp myapp.cpp -L. -lshared

由于共享库的SONAMElibshared.so.1,您的应用程序将依赖于它并将在libshared.so.1/etc/ld.so.conf的路径中搜索LD_LIBRARY_PATH

在运行应用程序之前,您可以将libshared.so.1符号链接设置为指向libshared.so.1.2libshared.so.1.1


Little info about the linker options used here:

--whole归档 对于--whole-archive选项后命令行中提到的每个归档,请在链接中包含归档中的每个目标文件,而不是在归档中搜索所需的目标文件。这通常用于将存档文件转换为共享库,从而强制将每个对象包含在生成的共享库中。此选项可能不止一次使用。 从gcc使用此选项时的两个注意事项:首先,gcc不知道此选项,因此您必须使用-Wl,-whole-archive。其次,不要忘记在归档列表之后使用-Wl,-no-whole-archive,因为gcc会将自己的归档列表添加到您的链接中,您可能也不希望此标记也影响这些归档。

-soname =名称 创建ELF共享对象时,将内部DT_SONAME字段设置为指定的名称。当可执行文件与具有DT_SONAME字段的共享对象链接时,则在运行可执行文件时,动态链接器将尝试加载由DT_SONAME字段指定的共享对象,而不是使用为链接器指定的文件名。

© www.soinside.com 2019 - 2024. All rights reserved.