は、そのgtest
テストケース 行方不明になり、ライブラリを静的アプリケーションのビルドにリンクされていることを収集します。また、 GNUツールチェーンが使用されています。
問題の動作の原因は簡単です。テスト には、 TEST(X, just_a_passing_test)
が含まれているライブラリの参照は含まれていません。そのため、リンカーはのいずれかをリンクして、 オブジェクトファイルをリンクしてプログラムにリンクさせる必要はありません。そうではありません。そのため、ランタイムには実行可能ファイル内にそのテストが存在しないため、 gtest
が見つかりません。
GNU形式の静的ライブラリは、ハウスキーピングヘッダーブロックとグローバルシンボルテーブルで飾られたオブジェクトファイルのアーカイブ です。
ザ・OPは、問題のライブラリに にプログラム内の任意のパブリックシンボルをアドホック参照を符号化することにより、彼は「魔法」のプログラムにその テストケースを強いることができることを発見しました。
魔法はありません。そのパブリックシンボルへの参照を満たすために、リンカーは であり、オブジェクトファイルをライブラリからリンクする必要があります。これは、シンボルの定義を としています。そして、OPは、図書館が.cpp
から であることを伝えます。したがって、ライブラリにはオブジェクトファイルが1つしかなく、 にはテストケースの定義も含まれています。 リンケージ内のそのオブジェクトファイルでは、テストケースはプログラム内にあります。
コンパイルオプションでGCCからclangに切り替えると、OPは同じ目的を達成するためにもっと尊敬できる方法を探して無駄になりました。コンパイラは とは関係ありません。 GCCまたはclangの場合、システムリンカーによってリンクされます(ld
)(ただし、それを置き換えるために異常な対策が取られていない限り)。
静的ライブラリのオブジェクトファイルをオブジェクトファイルにリンクするには、ld
を入手する方がいいでしょうか?
あります。で、ld
に
g++ -o app -L/path/to/the/libcool/archive -lcool
この代表団コマンドラインを:問題プログラムがapp
で、問題の静的ライブラリは、次にapp
リンク通常のGCCコマンドラインは、関連 ポイントで、これに似ている libcool.a
であると言います追加のリンカーオプション、および ライブラリは、自身が見つかったシステムのデフォルトであるとみなします。
リンカーが-lcool
と考えられるようになると、というアーカイブ/path/to/the/libcool/archive/libcool.a
の要求であることがわかります。次に、 の未解決のシンボル参照がこの時点でまだlibcool.a
のオブジェクトファイルでコンパイルされているかどうかを、 と判断します。 anyがある場合、それらのオブジェクトファイルはapp
にリンクされます。そうでなければ、 をlibcool.a
から何もリンクせずに渡します。
libcool.a
には、にリンクするシンボル定義がありますが、app
はそれらを参照していません。その場合、 が参照されていなくても、libcool.a
からオブジェクトファイルをリンクするためにリンカーに を伝えることができます。より正確には、我々は そうのように、それを行うためにリンカに指示するg++
を伝えることができます。
g++ -o app -L/path/to/the/libcool/archive -Wl,--whole-archive -lcool -Wl,-no-whole-archive
もの-Wl,...
オプションが...
ld
にオプションを渡すg++
を教えてください。 --whole-archive
オプションを指定すると、 が参照されるかどうかに関わらず、その後のアーカイブからのすべてのオブジェクトファイルを後で通知するまでリンクするように指示されます。 -no-whole-archive
は、 ld
にそれをやめ、通常どおりビジネスを再開するよう指示します。
g++
コマンドラインの最後にあるように、-Wl,-no-whole-archive
が重複しているように見えることがあります。しかし、そうではありません。 g++
は、ld
に渡す前に、システムのデフォルトライブラリ をコマンドラインに追加することを覚えておいてください。あなたは間違いなく --whole-archive
がデフォルトのライブラリがリンクされているときに有効にしたくないです。 (複数の定義エラーでリンケージが失敗します)。
は、問題の場合には、この溶液を適用し、TEST(X, just_a_passing_test)
は、そのテストを定義するオブジェクトファイルに、いくつかのノーオペレーション 参照を行うためのプログラムを強制のハックすることなく、実行されます。
一般的なケースでは、この解決策には明らかな欠点があります。何か参照されていないオブジェクトファイルのリンクを強制したい のライブラリがある場合は、という実際に以外の参照されていないオブジェクトファイルの束が 含まれています。 --whole-archive
もそれらのすべてをリンクしており、プログラム内で膨らんでいるだけです。
--whole-archive
ソリューションは、ノーオペレーション参照 ハックより立派かもしれないが、それは立派ではありません。それも見て尊敬していません。
実際の解決策は、合理的なことを行うことです。 リンカでプログラム内の何かの定義をリンクさせる場合は、は、 のリンカーからの秘密を保持しません。少なくともはの定義が使用されることを期待している各コンパイル単位内のものをと宣言します。
class X_just_a_passing_test_Test : public ::testing::Test {
public:
X_just_a_passing_test_Test() {}
private:
virtual void TestBody();
static ::testing::TestInfo* const test_info_ __attribute__ ((unused));
X_just_a_passing_test_Test(X_just_a_passing_test_Test const &);
void operator=(X_just_a_passing_test_Test const &);
};
(プラスtest_info_
の静的初期化子と:gtest
テストケースとの合理的なことをやって
はTEST(X, just_a_passing_test)
のようなgtest
マクロは、この場合にクラス定義、 に展開 という理解を必要としますTestBody()
の定義)。
TEST_F
,TEST_P
変異体についても同様である。したがって、これらの マクロを、コードに がクラス定義に適用されるのと同じ制約と期待で展開することができます。この光で
あなたはcool.h
で定義されたライブラリlibcool
、cool.cpp
に実装し、そのためのgtest
ユニットテストをしたい、tests.cpp
に実装されたテストプログラムtests
によって実行されるようにしている場合、合理的なものは次のとおりです。 -
- はそれで
cool_test.h
#include "cool.h"
、ヘッダファイルを書く
#include <gtest/gtest.h>
がその中にあります。
- は、コンパイル
- 、
tests.cpp
でそれに
#include "cool_test.h"
をごlibcool
テストケースを定義し、libcool
とlibgtest
とのリンクtests.cpp
そして、あなたはOPが何をしたかしないだろう、なぜそれは明らかです。あなたはtests.cpp
でcool.cpp
としない範囲内、tests.cpp
によって必要とされている クラス、およびcool.cpp
で必要ないを定義しないでしょう。すぐに彼らに痛みを実行すること
他にどのようにあなたは一人一人のための実行可能ファイルをせずに、ライブラリをテストするだろう、 :ので
OPは、ライブラリ でテストケースを定義に対するアドバイスを嫌うました。経験則として
私はユニットテスト済みであることをライブラリごとgtest
実行 を維持するための練習をお勧めします:すぐにそれらを実行すると、当たり前の自動化ツール などmake
と無痛であり、それは取得するはるかに良いです図書館ごとの合否判定は よりも多くの図書館の評決に過ぎません。しかし、あなたはまだ 異議には何もありませんことを行うにはしたくない場合:詳細な情報についてlibcool
、libcooler
、libcoolest
とlibgtest
おかげで
コンパイルとリンク。これは私の疑惑を確認するのに役立ちます。最終的に私は単体テストを実行するために各ライブラリの実行可能なターゲットを使用しました。 – NitrousUK
+50良い例で素晴らしい答え! –
私の場合は、StaticライブラリからMach-OタイプのリロケータブルオブジェクトファイルへのXcodeの変更を手助けしました –