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

发布于 2024-09-01 02:47:13 字数 716 浏览 8 评论 0原文

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

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

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

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

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

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

In my project there is a dependency on a static library (just called libsomething from now on) from a 3rd party. Recently, libsomething has become available in another version. My task is to provide my software with support for the old and the new version. Only one version of libsomething is used at run-time at any given time, but which version this is should be configurable between program runs.

I am using MSVC2005 on WinXP, a secondary objective is to become prepared to switch over to Linux and GCC.

Since both versions of libsomething are using the same symbols, linking them both into my executable is out of the question as the symbols of both versions are going to clash all over at link-time.

While I could create two executables (one linking against the old version, the other one using the new version), I cannot implement a decision on which executable to call in the final deployment environment (legacy reasons).

I came up with the idea of creating a dynamic library wrapper for each version of libsomething and linking them at run-time depending on some config file. With MSCV, this would mean going down the road of using LoadLibrary(), GetProcAddress(), etc., while on Linux I would have to use dlopen() and dlsym().

I understand that using libtool (i.e., libtldl) is wrapping this platform-dependency for using shared libraries. Is this an appropriate path to follow? Are there better (or, at least, different) ways? Do alternatives for libtldl exist as open-source?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

坏尐絯 2024-09-08 02:47:13

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

I know you said you couldn't use two executables due to the decision of which to execute, but couldn't you exec back and forth between executables depending on which version is selected at configuration?

爱你是孤单的心事 2024-09-08 02:47:13

在 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


Little info about the linker options used here:

--整个存档
对于 --whole-archive 选项后命令行中提到的每个存档,将存档中的每个目标文件包含在
链接,而不是在存档中搜索所需的目标文件。这通常用于将存档文件转换为共享文件
库,强制每个对象都包含在生成的共享库中。该选项可以多次使用。

在 gcc 中使用此选项时有两个注意事项:首先,gcc 不知道此选项,因此您必须使用 -Wl,-whole-archive。
其次,不要忘记在档案列表后使用 -Wl,-no-whole-archive,因为 gcc 会将其自己的档案列表添加到您的档案列表中。
链接,您可能不希望此标志也影响那些。

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

On Linux it would be easier for you to link to shared library and use symlinks to correct version - IMO it's much easier than using dlopen() + dlsym().

Thus you would create shared libraries for the old and new versions of your library:

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

and

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

Create the symlinks:

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

Build your application, linking it to the old version of the library. I suppose both versions are binary compatible (ABI not broken), but the new one could have some new symbols.

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

Since shared library's SONAME is libshared.so.1 your application will depend on it and will search libshared.so.1 in paths from /etc/ld.so.conf or LD_LIBRARY_PATH

Before you run your application you may set the libshared.so.1 symlink to point to libshared.so.1.2 or libshared.so.1.1.


Little info about the linker options used here:

--whole-archive
For each archive mentioned on the command line after the --whole-archive option, include every object file in the archive in the
link, rather than searching the archive for the required object files. This is normally used to turn an archive file into a shared
library, forcing every object to be included in the resulting shared library. This option may be used more than once.

Two notes when using this option from gcc: First, gcc doesn't know about this option, so you have to use -Wl,-whole-archive.
Second, don't forget to use -Wl,-no-whole-archive after your list of archives, because gcc will add its own list of archives to your
link and you may not want this flag to affect those as well.

-soname=name
When creating an ELF shared object, set the internal DT_SONAME field to the specified name. When an executable is linked with a
shared object which has a DT_SONAME field, then when the executable is run the dynamic linker will attempt to load the shared object
specified by the DT_SONAME field rather than the using the file name given to the linker.

乄_柒ぐ汐 2024-09-08 02:47:13

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

您可以编写专门为您的项目定制的脚本或使用 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。

It has been few years now but I'd like to mention another solution for completeness. Instead of manual dlopen and dlsym you could generate simple stubs for all necessary functions and on first call (or at program startup) decide which library version is needed, load it and resolve the addresses.

You could write a script specifically tailored for your project or use Implib.so tool:

# 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 is Linux-only atm but should be easily adaptable to Windows.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文