私の Linux ボックスには、2 つのライブラリがあります。
libfoo1.a and libfoo2.a
両方とも実装が含まれています
void foo(int)
私のメインプログラムはfooを呼び出します:
int main() { foo(1); return 0; }
g ++を使用してプログラムを2つの方法でコンパイルしました
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 実装は、キャッシュ調整された順次実装よりも優れているようです。
投稿が長くなって申し訳ありません。