在我的 linux 机器上,我有 2 个库:
libfoo1.a and libfoo2.a
它们都包含一个实现
void foo(int)
我的主程序调用 foo:
int main() { foo(1); return 0; }
我使用 g++ 以两种方式编译了程序
g++ main.cpp libfoo1.a libfoo2.a -o a1.out
g++ main.cpp libfoo2.a libfoo1.a -o a2.out
当我运行程序时,a1 显然使用了 libfoo1.a 中的 foo() 实现,而 a2 显然使用了 libfoo2。也就是说,g++ 链接了它首先看到的任何 foo() 。
我的问题(最后)是,这种“贪婪”链接策略实际上是在 C++ 标准中指定的吗?或者不同的编译器/平台会以实现定义的方式表现不同吗?
PS:把这个问题放在实际的上下文中,我真的很喜欢这个 g++ 示例的工作方式。在我的实际应用程序中,我有一个旧版 libfoo2,它实现了许多(很多!)功能,但我想在 libfoo1 中为其中的少数提供新的实现。一方面,我可以在 libfoo1 中编写一个全新的接口,实现我的少数,然后将其余部分委托给 libfoo2。但是,如果我可以依靠链接器为我完成它(即使对于像 icc 这样的非 g++ 编译器),我宁愿避免编写所有委托代码。
PPS:把它放在真正的实际上下文中,libfoo2 是 blas,而 libfoo1 是它的一些例程的自制 OpenMP 实现。我还没准备好为 MKL 掏腰包。ATLAS 不会对我要调用的函数进行多线程处理。它非常擅长多线程 GEMM,但我需要一些来自 LAPACK 的更奇特的例程也很快(zsptrf / zsptrs / zspr)。看来,我对这些例程的缓存无知 OpenMP 实现比它的缓存调整顺序实现做得更好。
对不起,帖子的长度。