9

ここで説明されているものに基づいて、自己登録型の抽象ファクトリを使用してテストしてきました。

https://stackoverflow.com/a/582456

私のすべてのテストケースで、それは魔法のように機能し、私が望んでいた機能と再利用を提供します。

私のプロジェクトで cmake を使用してこのファクトリにリンクするのは非常にトリッキーです (ただし、ar の問題のようです)。

リンクされた例と同じbase.hpp、derivedb.hpp/cpp、および同等のderiveda.hpp/cppがあります。主に、単純にファクトリをインスタンス化し、「DerivedA」と「DeriveddB」を使用して createInstance() を 2 回呼び出します。

次の行で作成された実行可能ファイル:

g++ -o testFactory main.cpp derivedb.o deriveda.o

期待どおりに動作します。派生クラスをライブラリに移動すると (cmake を使用しますが、ar だけでもテストしました)、リンクに失敗します。

ar cr libbase.a deriveda.o derivedb.o
g++ -o testFactory libbase.a main.cpp

最初の静的インスタンス化のみを呼び出し (derivedA.cpp から)、2 番目の静的インスタンス化は呼び出しません。つまり、

// deriveda.cpp (if listed first in the "ar" line, this gets called)
DerivedRegister<DerivedA> DerivedA::reg("DerivedA");

// derivedb.cpp (if listed second in the "ar" line, this does not get called)
DerivedRegister<DerivedB> DerivedB::reg("DerivedB");

ar 行で 2 つを交換すると、派生した b.cpp 静的インスタンス化のみが呼び出され、派生した a.cpp インスタンス化は呼び出されないことに注意してください。

C++ で静的変数をうまく処理できない ar または静的ライブラリで何か不足していますか?

4

1 に答える 1

11

直観に反して、リンク コマンドにアーカイブを含めることは、アーカイブにあるすべてのオブジェクト ファイルを含めることと同じではありません。未定義のシンボルを解決するために必要なアーカイブ内のオブジェクト ファイルのみが含まれます。これは、動的リンクがなく、ライブラリ全体 (C ライブラリを考えてください) が各実行可能ファイルに複製されることを考えると、良いことです。ld(1) マンページ (Linux では GNU ld) の説明は次のとおりです。

リンカーは、コマンド ラインで指定された場所で、アーカイブを 1 回だけ検索します。アーカイブが、コマンド ラインでアーカイブの前に表示されたオブジェクトで未定義のシンボルを定義している場合、リンカーはアーカイブから適切なファイルをインクルードします。ただし、後でコマンド ラインに表示されるオブジェクト内の未定義のシンボルによって、リンカーがアーカイブを再度検索することはありません。

残念ながら、リンクされた実行可能ファイルにアーカイブのすべてのメンバーを含める標準的な方法はありません。Linux では使用できg++ -Wl,-whole-archive、Mac OS X では使用できますg++ -all_load

したがって、GNU binutils ld では、link コマンドは次のようになります。

g++ -o testFactory -Wl,-whole-archive libbase.a -Wl,-no-whole-archive main.cpp

これ-Wl,-no-whole-archiveにより、g++ によって生成された最終的なリンク コマンドで後で表示されるアーカイブは、通常の方法でリンクされます。

于 2012-04-09T22:13:50.187 に答える