简体   繁体   English

是否可以告诉 linker 使用带有一些重复符号的库,就好像这些符号实际上是不同的一样?

[英]Is it possible to tell a linker to use libraries with some duplicated symbols as if the symbols were actually different?

We are distributing four different static libraries to customers:我们正在向客户分发四种不同的 static 库:

  • Library A: contains some common functions but also some embedded common libraries from linux which are not intended to be exposed to the customer, but to other of our libraries (so we need to export the symbols)库 A:包含一些常用函数,但也包含来自 linux 的一些嵌入式通用库,这些库不打算公开给客户,而是公开给我们的其他库(因此我们需要导出符号)
  • Library B: has some unresolved symbols, to be found on library A库 B:有一些未解析的符号,可以在库 A 中找到
  • Library C: has some unresolved symbols, to be found on library A库 C:有一些未解析的符号,可在库 A 中找到
  • Library D: has some unresolved symbols, to be found on library A库 D:有一些未解析的符号,可在库 A 中找到

The issue is that some customers are also using other libraries in their projects (let's call it X) that include duplicated symbols from A, leading to unexpected crashes (but those may be a different version, so they cannot use A).问题是一些客户也在他们的项目中使用其他库(我们称之为 X),其中包含来自 A 的重复符号,导致意外崩溃(但这些可能是不同的版本,因此他们不能使用 A)。 We do not control these libraries (X), as they are prebuilt open source projects.我们不控制这些库 (X),因为它们是预构建的开源项目。

We cannot distribute all our libraries linked together (stripping the common libraries symbols) as this would be a waste of resources.我们不能分发所有链接在一起的库(剥离公共库符号),因为这会浪费资源。 Some customers only need C or B or D (together with A).有些客户只需要C或B或D(连同A)。

We cannot distribute B/C/D with locally static linked A because some customers may be using C and B. This would lead again to wasted resources as when they link their project they will end up with two copies of A.我们不能用本地 static 链接 A 分发 B/C/D,因为一些客户可能正在使用 C 和 B。这将再次导致资源浪费,因为当他们链接他们的项目时,他们最终会得到 A 的两个副本。

Is there any way for our customers to tell the linker that when they are linking against X, A and B, the symbols in A should only be used when resolving undefined symbols in B?有没有办法让我们的客户告诉linker,当他们链接X,A和B时,A中的符号只能在解析B中未定义的符号时使用? Eg例如

lld -o myprogram main.o helper1.o -L. -lX -lA -lB

should use A only for the unresolved symbols in B, but never for the unresolved symbols in helper1.o.应该只将 A 用于 B 中未解析的符号,但绝不能用于 helper1.o 中的未解析符号。 Is there any combination of flags to achieve so?是否有任何标志组合可以实现这一目标?

We already considered renaming or prefixing symbols in A, but all the libraries are huge and the process is not trivial.我们已经考虑过对 A 中的符号进行重命名或前缀,但所有的库都非常庞大,而且这个过程并不简单。 Also refactoring the code in A to include namespaces is far from trivial.重构 A 中的代码以包含名称空间也绝非易事。

Tried different compiler flags, but none of them helped.尝试了不同的编译器标志,但都没有帮助。 I went through linker documentation and found nothing.我浏览了 linker 文档,但一无所获。

Is there any way for our customers to tell the linker that when they are linking against X, A and B, the symbols in A should only be used when resolving undefined symbols in B?有没有办法让我们的客户告诉linker,当他们链接X,A和B时,A中的符号只能在解析B中未定义的符号时使用?

No.不。

A common solution to the problem you have is to prefix all non-static symbols in libA.a with a unique prefix (eg your_company_A_foo() instead of foo() ).您遇到的问题的一个常见解决方案是为libA.a中的所有非静态符号添加唯一前缀(例如your_company_A_foo()而不是foo() )。 This makes symbol collisions with other libraries exceedingly unlikely.这使得符号与其他库发生冲突的可能性极小。

And a common way to do that is to define your functions using a macro, eg一种常见的方法是使用宏定义函数,例如

#define PFX_A(name) my_prefix_a_ ## name

int PFX_A(foo) () { return 42; }
int PFX_A(bar) () { return 24; }

Above code defines my_prefix_a_foo() and my_prefix_a_bar() when compiled:上面的代码在编译时定义了my_prefix_a_foo()my_prefix_a_bar()

$ nm f.o
000000000000000b T my_prefix_a_bar
0000000000000000 T my_prefix_a_foo

During local testing / development you could even remove the prefix completely if desired.在本地测试/开发期间,如果需要,您甚至可以完全删除前缀。

This also makes it easy to ship "version 2" of libA.a and guarantee that old (version 1) libB.a will never be linked with new libA.a -- just change the prefix to include "v2" in it.这也使得发布libA.a的“版本 2”变得容易,并保证旧的(版本 1) libB.a永远不会与新的libA.a链接——只需更改前缀以在其中包含“v2”。

Update:更新:

The issue is that A is a huge library (including its own version of some popular linux libraries).问题是 A 是一个巨大的库(包括它自己的一些流行的 linux 库版本)。

  1. I hope you've talked to your lawyers -- popular Linux libraries tend to be covered by GPL, and this may be considered a re-distribution, which would require you to take steps to comply with GPL.我希望你已经和你的律师谈过了——流行的 Linux 图书馆往往被 GPL 覆盖,这可能被认为是重新分发,这将需要你采取措施遵守 GPL。
  2. You can still rename all the global symbols in libA.a to have a unique prefix.仍然可以重命名libA.a中的所有全局符号,使其具有唯一的前缀。 You just do that using objcopy --prefix-symbol=your_company_A instead of doing it at the source level.您只需使用objcopy --prefix-symbol=your_company_A而不是在源代码级别执行此操作。

Example:例子:

$ gcc -c f.c
$ objcopy --prefix-symbol=my_prefix_a_ f.o f2.o
$ nm f.o f2.o

f.o:
000000000000000b T bar
0000000000000000 T foo

f2.o:
000000000000000b T my_prefix_a_bar
0000000000000000 T my_prefix_a_foo

PS聚苯乙烯

lld -o myprogram main.o helper1.o -L. -lX -lA -lB

You should never link any user-level code with ld (or lld ) on UNIX -- always use appropriate compiler driver ( gcc or g++ or clang ).你不应该在UNIX上将任何用户级代码与ld (或lld )链接——总是使用适当的编译器驱动程序( gccg++clang )。 The link command using ld directly is almost never correct (above link line certainly isn't), as you'll discover when some common feature (like C++ destructors or thread-local storage) mysteriously doesn't work.直接使用ld的链接命令几乎永远不会正确(链接行上方肯定不正确),因为您会发现某些常见功能(如C++析构函数或线程本地存储)神秘地不起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM