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

时间:2010-05-10 09:42:10

标签: c++ shared-libraries libtool

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

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

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

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

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

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

3 个答案:

答案 0 :(得分:2)

我知道你说由于决定执行哪个,你不能使用两个可执行文件,但是根据在配置中选择的版本,你不能在可执行文件之间来回exec吗?

答案 1 :(得分: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

<小时/> 关于此处使用的链接器选项的信息很少:

  

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

     

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

答案 2 :(得分: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。