将不同版本的静态库包装在动态库中
在我的项目中,存在对来自第 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我知道您说过由于决定执行哪个可执行文件而无法使用两个可执行文件,但是您不能根据配置时选择的版本在可执行文件之间来回
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?在 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
创建符号链接:
构建您的应用程序,将其链接到旧版本的库。我想这两个版本都是二进制兼容的(ABI 没有损坏),但新版本可能有一些新符号。
g++ -o myapp myapp.cpp -L。 -lshared
由于共享库的
SONAME
是libshared.so.1
,您的应用程序将依赖它并搜索libshared.so.1
> 在/etc/ld.so.conf
或LD_LIBRARY_PATH
的路径中 在运行应用程序之前,您可以设置
libshared.so.1
符号链接指向libshared.so.1.2
或libshared.so.1.1
。Little info about the linker options used here:
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:
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
islibshared.so.1
your application will depend on it and will searchlibshared.so.1
in paths from/etc/ld.so.conf
orLD_LIBRARY_PATH
Before you run your application you may set the
libshared.so.1
symlink to point tolibshared.so.1.2
orlibshared.so.1.1
.Little info about the linker options used here:
已经过去几年了,但为了完整性,我想提一下另一个解决方案。您可以为所有必要的函数生成简单的存根,而不是手动 dlopen 和 dlsym ,并在第一次调用时(或程序启动时)决定需要哪个库版本,加载它并解析地址。
您可以编写专门为您的项目定制的脚本或使用 Implib.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
anddlsym
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:
Implib.so is Linux-only atm but should be easily adaptable to Windows.