web-dev-qa-db-ja.com

プロジェクトの複数の入り口

私の質問はC++に関連していますが、実際にはJavaからのものです。

私がプログラミングをしていたときJava基本の「テスト」クラスから派生した複数のクラスがありました。それらの目的は物事をテストすることでした-テストを実行する(単体テスト/単体テストではない)。

テストを実行するために、public static void mainすべてのクラスで。したがって、そのようなテストを実行することは、Eclipse/Netbeansで実行をクリックすることでした。

この質問は多分IDEに依存しています。実際にはメイクファイルに要約されますが、C++ IDEで同様の構造を維持することは可能ですか?

実際に私の質問は:テストをどのように扱いますか?

テストを実行するため、またはテストごとに異なるビルド構成を作成するために、いくつかのスイッチ/列挙型ステートメントを含む巨大なメイン​​メソッドを配置しますか、またはこれに対する異なるソリューションを持っていますか?

この質問では簡単な答えが得られないことはわかっていますが、自分で何かを選択できるように、それをどのように処理するか知りたいです。

4
luke1985

簡単に言えば、「CやC++では、Javaほど簡単にはできません。」

各クラスは独自の名前空間であり、理論上は完全に自己完結型であるため、Javaを使用すると、すべてのクラスにmain()メソッドを配置する必要がなくなります。クラスでJVMを呼び出すと、実行するmain()が含まれるネームスペースがわかります。したがって、たとえば、_Java Foo_は、実際には「run Foo.main()」を意味します。

ネイティブオブジェクトにコンパイルする言語は、そのようには機能しません。ほとんどのシステムには、実行可能ファイルにリンクされる少しのコードがあり、フライト前の準備を少し行い、main()を呼び出し、intを渡してオペレーティングシステムに返します。終了コードとして。 (多くのUnixシステムでは、そのコードは_crt0.o_、または「Cランタイムゼロ」と呼ばれるファイルにあります。)リンカーは、実行時に代替main()関数を渡す簡単な方法がありませんそれらすべてを事前に縫い付けます。

CまたはC++で同様のことを達成したい場合は、いくつかの選択肢があります。

1つの方法は、プリプロセッサを使用してmain()が行う通常のことを覆し、シンボルが定義されている場合はメソッドを直接呼び出すことです。

_class Foo {
  public:
    static void test() { // Your Test Here }
};

int main() {
#ifdef TEST_CLASS
  TEST_CLASS ## ::test();
#else
  // Do whatever main() usually does
#endif
}
_

次に、これを機能させるには、IDE define _TEST_CLASS_を実行、再コンパイル、実行するテストの対象となるクラスの名前に定義する必要があります。

もう1つの方法は、すべてのオブジェクトを共有ライブラリにコンパイルし、Cにエクスポートされたシンボルを追加して、テストを実行することです。次に、ダイナミックローダーを使用して、実行するテストのシンボルを探し出し、呼び出す小さなプログラムが必要です。これをどのように行うかは、システムに大きく依存し、標準には根拠がないため、推奨することも、その方法を詳しく説明することもしません。

1
Blrfl

あなたはすでに受け入れられた答えを持っていますが、答えは不完全だと思います(特に、それはできない Javaのように簡単に複数のアプリケーションエントリポイントを定義したため)。

C++で同じコード/モジュールに複数のエントリポイントを実装するには、次のようにします。

  • エントリポイントごとに新しいcppファイルを作成します(つまり、main-app.cpp、io-tests.cpp、db-tests.cpp、network-tests.cppなど)。

  • 各ファイルは、独自のメイン関数を定義する必要があります。

  • ビルドシステムでは、各ファイルに個別のバイナリターゲットが必要です(ファイルを作成しますか?)。

  • 必要に応じてターゲットをビルドして実行します。

基本的には、複数のmain関数をそれぞれ独自のファイルに記述するのと同じくらい簡単です。

このソリューションは、main()関数(上記の例では、「main-app.cpp」で定義されている関数)ができるだけ薄い場合に最適に機能します。

適切な実装は次のようになります。

main-app.cpp:

#include <application.hpp>

int main(int, char**) {
    application app(std::cin, std::cout); // run application with std i/o
    return app.run();
}

db-tests.cpp:

#include <database.hpp>    // tested class
#include <unit-tests.hpp>  // unit testing fw

int main(int, char**) {
    database_test_suite suite;
    return suite.run();
}

これらのファイルの両方を一緒にコンパイルするターゲットはありません(したがって、mainの複数の定義でリンカーエラーは発生しません)。

2
utnapistim