C语言 用一些相同的符号链接两个共享库
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6538501/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Linking two shared libraries with some of the same symbols
提问by drewag
I link with two different shared libraries. Both libraries define some symbols that share a name but have different implementations. I can't make each library use its own implementation over the other.
我链接了两个不同的共享库。这两个库都定义了一些共享名称但具有不同实现的符号。我不能让每个库使用自己的实现而不是其他库。
For example, both libraries define a global function bar()that each calls internally. Library one calls it from foo1()and library two calls it from foo2().
例如,两个库都定义了一个全局函数bar(),每个函数都在内部调用。库一从 调用它foo1(),库二从 调用它foo2()。
Lib1.so:
Lib1.so:
T bar
T foo1() // calls bar()
Lib2.so:
Lib2.so:
T bar
T foo2() // calls bar()
If I link my application against Lib1.so and then Lib2.so the bar implementation from Lib1.so is called even when calling foo2(). If on the other hand, I link my application against Lib2.so and then Lib1.so, then bar is always called from Lib2.so.
如果我将我的应用程序链接到 Lib1.so 和 Lib2.so,则即使在调用foo2(). 另一方面,如果我将我的应用程序链接到 Lib2.so,然后链接到 Lib1.so,那么 bar 总是从 Lib2.so 调用。
Is there a way to make a library always prefer its own implementation above any other library?
有没有办法让一个库总是比任何其他库更喜欢它自己的实现?
回答by ninjalj
There are several ways to solve this:
有几种方法可以解决这个问题:
Pass
-Bsymbolicor-Bsymbolic-functionsto the linker. This has a global effect: every reference to a global symbol (of function type for-Bsymbolic-functions) that can be resolved to a symbol in the library is resolved to that symbol. With this you lose the ability to interpose internal library calls to those symbols using LD_PRELOAD. The symbols are still exported, so they can be referenced from outside the library.Use a version scriptto mark symbols as localto the library, e.g. use something like:
{local: bar;};and pass--version-script=versionfileto the linker. The symbols are notexported.Mark symbols with an approppiate visibility(GCC info page for visibility), which will be either hidden, internal, or protected. protectedvisibility symbols are exported as
.protected, hiddensymbols are not exported, and internalsymbols are not exportedand you compromise not to call them from outside the library, even indirectly through function pointers.
传递
-Bsymbolic或-Bsymbolic-functions到链接器。这具有全局效果:对-Bsymbolic-functions可以解析为库中符号的全局符号(函数类型 for )的每个引用都解析为该符号。这样您就无法使用 LD_PRELOAD 将内部库调用插入到这些符号中。符号仍然是导出的,因此可以从库外部引用它们。使用版本脚本将符号标记为库的本地符号,例如使用类似:
{local: bar;};并传递--version-script=versionfile给链接器。不导出符号。标记具有适当可见性的符号(可见性的GCC 信息页面),这将是hidden、internal或protected。受保护的可见性符号导出为
.protected,隐藏符号不导出,内部符号不导出,您妥协不从库外部调用它们,甚至通过函数指针间接调用它们。
You can check which symbols are exported with objdump -T.
您可以使用objdump -T.
回答by bmargulies
You will have to create two 'wrapper' shared libs, one for each of your existing libs. Each one should be built with a --dynamic-list that lists only a few non-conflicting symbols that define an API. You will also need -Bsymbolic to avoid any global combination.
您必须创建两个“包装器”共享库,每个现有库一个。每个都应使用 --dynamic-list 构建,该列表仅列出定义 API 的几个非冲突符号。您还需要 -Bsymbolic 以避免任何全局组合。
It might be less stressful to access the resulting libs via dlopen with suitable options, as well.
使用合适的选项通过 dlopen 访问生成的库可能会减轻压力。
回答by Tom
Another way to solve this problem is using macro to change namespace.
解决此问题的另一种方法是使用宏更改命名空间。
Prerequisites
先决条件
- All elements (functions, classes, global variables, ...) are in a namespace.
- The library doesn't heavily depend on macros in headers.
- 所有元素(函数、类、全局变量等)都在一个命名空间中。
- 该库并不严重依赖标头中的宏。
Solution
解决方案
- When compiling the library, define macro with namespace name to define it to something different. For example if the namespace is LibNS, use
-DLibNS=LibNSv1for one case and-DLibNS=LibNSv2for the other. When using libraries in the code, define macro according your current situation;
#define LibNS LibNSv1 #include "my_lib.h" #undef LibNS
- 编译库时,使用命名空间名称定义宏以将其定义为不同的东西。例如,如果命名空间是 LibNS,则分别
-DLibNS=LibNSv1用于一种情况和-DLibNS=LibNSv2另一种情况。 在代码中使用库时,根据自己的情况定义宏;
#define LibNS LibNSv1 #include "my_lib.h" #undef LibNS
Reasons why use this instead of other solutions
使用它而不是其他解决方案的原因
- When the problematic library is used (at least partially) in header files (for example templates, inlines, ...); when you include them in your executable's code, resolver doesn't have idea whether these functions should be called from Lib1.so or Lib2.so.
- Your compiler has poor/none support for other solutions (shouldn't happen with our intel/amd 32/64 bit CPUs, but it seems from Google search that some other platforms might have the problem).
- 当有问题的库(至少部分)在头文件(例如模板、内联等)中使用时;当您将它们包含在可执行文件的代码中时,解析器不知道应该从 Lib1.so 还是 Lib2.so 调用这些函数。
- 您的编译器对其他解决方案的支持很差/不支持(我们的 intel/amd 32/64 位 CPU 不应该发生这种情况,但从 Google 搜索看来,其他一些平台可能有问题)。
Potential problems
潜在问题
- It might be problematic to use both version in one cpp file of your executable;
#include "my_lib.h"probably uses macro to protect against multiple-inclusion and undefining them to avoid this might cause lots of different problems (library author might change the macro name in the future, header defines some other macros, etc.). - The name
LibNSmight be used for something else in the library (variable, function, etc.); in that case, this name will be also changed toLibNSv1orLibNSv2. This might lead to other problems depending on the library and how it's used.
- 在可执行文件的一个 cpp 文件中同时使用这两个版本可能会有问题;
#include "my_lib.h"可能使用宏来防止多重包含并取消定义它们以避免这可能会导致许多不同的问题(库作者将来可能会更改宏名称,标头定义了一些其他宏等)。 - 该名称
LibNS可能用于库中的其他内容(变量、函数等);在这种情况下,此名称也将更改为LibNSv1或LibNSv2。这可能会导致其他问题,具体取决于库及其使用方式。
Notes
笔记
- This isn't meant to replace currently accepted answer (from ninjalj; feel free to copy-paste it), but extend it with another approach.
- Main reason why I posted this answer is that I encountered this problem today, but answer didn't help due to problematic code being in header files.
- My source: https://spin.atomicobject.com/2014/06/03/static-linking-c-plus-plus/
- 这并不是要取代当前接受的答案(来自 ninjalj;随意复制粘贴),而是用另一种方法扩展它。
- 我发布这个答案的主要原因是我今天遇到了这个问题,但由于头文件中有问题的代码,答案没有帮助。
- 我的来源:https: //spin.atomicobject.com/2014/06/03/static-linking-c-plus-plus/

