4

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

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

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

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

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

我知道 using libtool(ie, libtldl) 正在包装此平台依赖性以使用共享库。这是一条合适的路径吗?有更好的(或者至少是不同的)方法吗?libtldl是否存在开源的替代方案?

4

3 回答 3

2

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

于 2010-05-10T15:09:04.580 回答
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.confLD_LIBRARY_PATH

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


关于此处使用的链接器选项的少量信息:

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

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

于 2010-05-12T10:05:14.637 回答
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 的 atm,但应该很容易适应 Windows。

于 2017-12-07T10:39:38.697 回答