C ++プロジェクト構成(gtest、cmake、doxygenを使用)


123

私はプログラミング全般に慣れていないので、C ++で単純なベクトルクラスを作成することから始めることにしました。ただし、後でワークフローを変更するのではなく、最初から良い習慣を身に付けたいと思います。

現在、ファイルは2つvector3.hppとしかありませんvector3.cpp。このプロジェクトは、私がすべてに慣れるにつれてゆっくりと成長し始め(一般的な線形代数ライブラリーのようになります)、後で人生を楽にするために「標準」プロジェクトレイアウトを採用したいと思います。だから周りを見回した後、私はhppとcppファイルを整理しようとする2つの方法を見つけました、最初のものは:

project
└── src
    ├── vector3.hpp
    └── vector3.cpp

そして二番目の存在:

project
├── inc
   └── project
       └── vector3.hpp
└── src
    └── vector3.cpp

あなたはどちらを勧めますか、そしてその理由は?

次に、コードの単体テストにGoogle C ++ Testing Frameworkを使用したいと思います。かなり使いやすいようです。あなたは、例えば、私のコードでこれをバンドル示唆くださいinc/gtestまたはcontrib/gtestフォルダ?バンドルされている場合、fuse_gtest_files.pyスクリプトを使用して数やファイルを減らすか、そのままにしておくことをお勧めしますか?バンドルされていない場合、この依存関係はどのように処理されますか?

テストを書くことになると、これらは一般的にどのように編成されますか?各クラス(test_vector3.cppたとえば)ごとに1つのcppファイルを作成することを考えていましたが、すべてを簡単に一緒に実行できるようにすべて1つのバイナリにコンパイルしましたか?

gtestライブラリは一般にcmakeとmakeを使用してビルドされるので、私のプロジェクトもこのようにビルドするのは理にかなっていると思いましたか?次のプロジェクトレイアウトを使用することにした場合:

├── CMakeLists.txt
├── contrib
   └── gtest
       ├── gtest-all.cc
       └── gtest.h
├── docs
   └── Doxyfile
├── inc
   └── project
       └── vector3.cpp
├── src
   └── vector3.cpp
└── test
    └── test_vector3.cpp

CMakeLists.txtライブラリだけ、またはライブラリとテストのいずれかを構築できるようにするにはどうすればよいですか?また、buildbinディレクトリを持つかなりの数のプロジェクトを見てきました。ビルドはビルドディレクトリで行われ、その後バイナリがbinディレクトリに移動されますか?テストのバイナリとライブラリは同じ場所にありますか?または、次のように構造化する方が理にかなっていますか。

test
├── bin
├── build
└── src
    └── test_vector3.cpp

また、コードをドキュメント化するためにdoxygenを使用したいと思います。これをcmakeおよびmakeで自動的に実行することは可能ですか?

非常に多くの質問で申し訳ありませんが、私はこれらの種類の質問に満足に答えるC ++の本を見つけていません。


6
すばらしい質問ですが、Stack OverflowのQ&A形式には適していないと思います。でも答えにはとても興味があります。+1とfav
ルチアングリゴー

1
これらは非常に大きな問題です。それをいくつかの小さな質問に分けて、相互にリンクを張る方が良いかもしれません。とにかく最後の部分に答える:CMakeでは、srcディレクトリの内部と外部のどちらをビルドするかを選択できます(外部をお勧めします)。そして、はい、CMakeでdoxygenを自動的に使用できます。
mistapink

回答:


84

C ++ビルドシステムは少し黒ずんだアートであり、プロジェクトが古いほど奇妙なものを見つけることができるので、多くの質問が出てくるのは驚くことではありません。質問を1つずつ説明し、C ++ライブラリの構築に関する一般的な事項について説明します。

ディレクトリ内のヘッダーとcppファイルを分離する。これは、実際のアプリケーションではなくライブラリとして使用されることになっているコンポーネントを構築する場合にのみ不可欠です。ヘッダーは、ユーザーが提供するものと対話するための基礎であり、インストールする必要があります。これは、それらがサブディレクトリにある必要があり(多くのヘッダーが最終的にトップレベルに/usr/include/なることを望まない)、ヘッダーはそのような設定で自分自身を含めることができる必要があることを意味します。

└── prj
    ├── include
       └── prj
           ├── header2.h
           └── header.h
    └── src
        └── x.cpp

インクルードパスが機能し、インストールターゲットに簡単なグロビングを使用できるため、うまく機能します。

依存関係のバンドル:これは、依存関係を見つけて構成するビルドシステムの機能と、単一バージョンへのコードの依存関係に大きく依存すると思います。また、ユーザーの能力やプラットフォームへの依存関係の容易さにも依存します。CMakeにはfind_package、Google Test用のスクリプトが付属しています。これにより、物事がずっと簡単になります。必要なときだけ同梱し、それ以外は避けます。

ビルド方法:ソース内ビルドを避けます。CMakeは、ソースビルドを簡単にして、生活を非常に簡単にします。

CTestを使用してシステムのテストを実行することもできます(GTestの組み込みサポートも付属しています)。ディレクトリのレイアウトとテスト組織の重要な決定は次のとおりです。最終的にサブプロジェクトが発生しますか?その場合、CMakeListsを設定するときにさらに作業が必要で、サブプロジェクトをサブディレクトリに分割し、それぞれに独自のincludesrcファイルを含める必要があります。おそらく、独自のdoxygenも実行して出力します(複数のdoxygenプロジェクトを組み合わせることは可能ですが、簡単ではない)。

あなたはこのようなものになるでしょう:

└── prj
    ├── CMakeLists.txt <-- (1)
    ├── include
       └── prj
           ├── header2.hpp
           └── header.hpp
    ├── src
       ├── CMakeLists.txt <-- (2)
       └── x.cpp
    └── test
        ├── CMakeLists.txt <-- (3)
        ├── data
           └── testdata.yyy
        └── testcase.cpp

どこ

  • (1)依存関係、プラットフォーム固有、および出力パスを構成します
  • (2)ビルドするライブラリを構成します
  • (3)テスト実行可能ファイルとテストケースを構成します

サブコンポーネントがある場合は、別の階層を追加して、サブプロジェクトごとに上のツリーを使用することをお勧めします。次に、サブコンポーネントがそれらの依存関係を検索して構成するのか、それともトップレベルで行うのかを決定する必要があるため、事態は複雑になります。これはケースバイケースで決定する必要があります。

Doxygen:doxygenの構成ダンスを何とかした後、CMake add_custom_commandを使用してドキュメントターゲットを追加するのは簡単です。

これが私のプロジェクトの最終的な方法であり、いくつかの非常に類似したプロジェクトを見てきましたが、もちろんこれですべてが解決するわけではありません。

補遺ある時点でconfig.hpp 、バージョン定義を含むファイルを生成し、バージョン管理識別子(GitハッシュまたはSVNリビジョン番号)の定義を生成することができます。CMakeには、その情報の検索を自動化し、ファイルを生成するモジュールがあります。CMakeを使用configure_fileして、テンプレートファイル内の変数を内で定義された変数に置き換えることができますCMakeLists.txt

ライブラリを構築している場合は__declspec、MSVCとvisibilityGCC / clangの属性など、コンパイラ間の違いを正しく理解するためのエクスポート定義も必要です。


2
いい答えですが、プロジェクト名の付いた追加のサブディレクトリ「/prj/include/prj/foo.hpp」にヘッダーファイルを配置する必要がある理由はまだわかりません。なぜ「/prj/include/foo.hpp」だけではないのですか?私は、インストール時にインストールディレクトリを再ジグする機会があると想定しています。そのため、インストール時に<INSTALL_DIR> /include/prj/foo.hppを取得しますか、それともCMakeでは難しいですか?
William Payne

6
@William CPackで実際に行うのは難しいです。また、ソースファイル内のインクルードはどのように見えますか?それらがインストールされているバージョンの「header.hpp」だけの場合、「/ usr / include」ではなく「/ usr / include / prj /」がインクルードパスにある必要があります。
pmr 2013

37

手始めに、無視できないディレクトリの従来の名前がいくつかあります。これらは、Unixファイルシステムでの長い伝統に基づいています。これらは:

trunk
├── bin     : for all executables (applications)
├── lib     : for all other binaries (static and shared libraries (.so or .dll))
├── include : for all header files
├── src     : for source files
└── doc     : for documentation

少なくともトップレベルでは、この基本的なレイアウトを守ることをお勧めします。

ヘッダーファイルとソースファイル(cpp)の分割については、どちらの方法もかなり一般的です。ただし、私はそれらを一緒に保持することを好む傾向があり、ファイルを一緒に持つことは日常のタスクではより実際的です。また、すべてのコードが1つの最上位trunk/src/フォルダー(フォルダー)の下にある場合、トップレベルの他のすべてのフォルダー(bin、lib、include、doc、およびおそらくいくつかのテストフォルダー)に加えて、ソース外ビルドの「ビルド」ディレクトリは、ビルドプロセスで生成されたファイルのみを含むすべてのフォルダーです。したがって、バージョン管理システム/サーバー(GitやSVNなど)の下に保管する必要があるのは、srcフォルダーのみ、またはそれよりもはるかに良い方法です。

そして、宛先システムにヘッダーファイルをインストールすることになると(最終的にライブラリを配布したい場合)、CMakeにはファイルをインストールするためのコマンドがあります(暗黙的に「インストール」ターゲットを作成し、「make install」を実行します)。すべてのヘッダーを/usr/include/ディレクトリに配置するために使用できます。この目的のために、次のcmakeマクロを使用します。

# custom macro to register some headers as target for installation:
#  setup_headers("/path/to/header/something.h" "/relative/install/path")
macro(setup_headers HEADER_FILES HEADER_PATH)
  foreach(CURRENT_HEADER_FILE ${HEADER_FILES})
    install(FILES "${SRCROOT}${CURRENT_HEADER_FILE}" DESTINATION "${INCLUDEROOT}${HEADER_PATH}")
  endforeach(CURRENT_HEADER_FILE)
endmacro(setup_headers)

どこでSRCROOT私はsrcフォルダに設定されていることcmakeの変数であり、INCLUDEROOT私は、ヘッダーに行く必要がどこに設定することをcmakeの変数です。もちろん、これを実行する方法は他にもたくさんありますが、私の方法は最善ではないと確信しています。重要なのは、ターゲットシステムにヘッダーをインストールするだけでよいという理由だけでヘッダーとソースを分割する理由はないということです。特にCMake(またはCPack)では、ヘッダーを選択して構成するのが非常に簡単です。別のディレクトリに置く必要なくインストールできます。そして、これはほとんどの図書館で見たものです。

引用:次に、コードの単体テストにGoogle C ++テストフレームワークを使用したいと思います。これを私のコードと一緒に、たとえば「inc / gtest」または「contrib / gtest」フォルダーにバンドルすることをお勧めしますか?バンドルされている場合は、fuse_gtest_files.pyスクリプトを使用してファイルの数を減らすか、そのままにしておくことをお勧めしますか?バンドルされていない場合、この依存関係はどのように処理されますか?

ライブラリに依存関係をバンドルしないでください。これは一般にかなりひどい考えであり、それを実行するライブラリを構築しようとして立ち往生しているときはいつも嫌いです。それはあなたの最後の手段であり、落とし穴に気をつけるべきです。多くの場合、ひどい開発環境(Windowsなど)を対象にしている、または問題のライブラリ(依存関係)の古い(非推奨)バージョンしかサポートしていないため、依存関係をライブラリにバンドルします。主な落とし穴は、バンドルされた依存関係が同じライブラリ/アプリケーションのすでにインストールされているバージョンと衝突する可能性があることです(たとえば、gtestをバンドルしましたが、ライブラリをビルドしようとしている人には、新しい(または古い)バージョンのgtestがすでにインストールされています。 2人は衝突し、その人に非常に厄介な頭痛を与えるかもしれません)。だから、私が言ったように、あなた自身の責任でそれをしてください、そして最後の手段としてだけ言います。ライブラリをコンパイルする前に、いくつかの依存関係をインストールするように人々に依頼することは、バンドルされている依存関係と既存のインストールとの間の衝突を解決しようとするよりもはるかに害が少ないです。

引用:テストを書くことになると、これらは一般的にどのように編成されますか?クラスごとに1つのcppファイル(たとえば、test_vector3.cpp)があると考えていましたが、すべてを1つのバイナリにコンパイルして、簡単に一緒に実行できるようにしましたか?

私の意見では、クラスごとに1つのcppファイル(またはクラスと関数の小さなまとまりのあるグループ)がより一般的で実用的です。ただし、「すべてを一緒に実行できるようにする」ためだけにすべてを1つのバイナリにコンパイルしないでください。それは本当に悪い考えです。一般に、コーディングに関しては、合理的な範囲で分割する必要があります。単体テストの場合、1つのバイナリですべてのテストを実行することは望ましくありません。これは、ライブラリ内の何かに少しでも変更を加えると、その単体テストプログラムがほぼ完全に再コンパイルされる可能性があるためです。 、そしてそれは再コンパイルを待って失われた分/時間です。単純なスキームに固執するだけです。1ユニット= 1ユニットテストプログラム。そして、

引用:gtestライブラリは一般にcmakeとmakeを使用してビルドされるので、私のプロジェクトもこのようにビルドするのは理にかなっていると思いましたか?次のプロジェクトレイアウトを使用することにした場合:

私はむしろこのレイアウトをお勧めします:

trunk
├── bin
├── lib
   └── project
       └── libvector3.so
       └── libvector3.a        products of installation / building
├── docs
   └── Doxyfile
├── include
   └── project
       └── vector3.hpp
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

├── src
   └── CMakeLists.txt
   └── Doxyfile.in
   └── project                 part of version-control / source-distribution
       └── CMakeLists.txt
       └── vector3.hpp
       └── vector3.cpp
       └── test
           └── test_vector3.cpp
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

├── build
└── test                        working directories for building / testing
    └── test_vector3

ここで注意すべき点がいくつかあります。まず、srcディレクトリのサブディレクトリはインクルードディレクトリのサブディレクトリをミラーリングする必要があります。これは、物事を直感的に保つためです(また、サブディレクトリ構造を適度にフラット(浅い)に保つようにしてください。多くの場合、何よりも面倒です。第2に、「include」ディレクトリは単なるインストールディレクトリであり、その内容はsrcディレクトリから選択されたヘッダーだけです。

第3に、CMakeシステムは、トップレベルの1つのCMakeLists.txtファイルとしてではなく、ソースサブディレクトリに配布されることを目的としています。これは物事をローカルに保ち、それは良いことです(物事を独立した部分に分割する精神で)。新しいソース、新しいヘッダー、または新しいテストプログラムを追加する場合、必要なのは、問題のサブディレクトリにある1つの小さくてシンプルなCMakeLists.txtファイルを編集することだけです。これにより、ディレクトリを簡単に再構築することもできます(CMakeListはローカルであり、移動するサブディレクトリに含まれています)。最上位のCMakeListsには、宛先ディレクトリ、カスタムコマンド(またはマクロ)のセットアップ、システムにインストールされているパッケージの検索など、ほとんどの最上位の構成が含まれている必要があります。下位レベルのCMakeListsには、ヘッダー、ソース、

引用:CMakeLists.txtは、ライブラリだけ、またはライブラリとテストのいずれかを構築できるようにどのように見える必要がありますか?

基本的な答えは、CMakeを使用すると、特定のターゲットを「すべて」(「make」と入力すると作成される)から明確に除外でき、特定のターゲットのバンドルを作成することもできます。ここではCMakeチュートリアルを行うことはできませんが、自分で調べるのはかなり簡単です。ただし、この特定のケースでは、もちろん、CTestを使用することをお勧めします。これは、CMakeListsファイルで使用できる追加のコマンドセットであり、ユニットとしてマークされている多数のターゲット(プログラム)を登録します。テスト。したがって、CMakeはすべてのテストをビルドの特別なカテゴリに配置し、それがまさにあなたが求めていたものなので、問題は解決されました。

引用:また、ビルド広告とbinディレクトリを持つかなりの数のプロジェクトを見てきました。ビルドはビルドディレクトリで行われ、その後バイナリがbinディレクトリに移動されますか?テストのバイナリとライブラリは同じ場所にありますか?または、次のように構成する方が理にかなっていますか。

ソースの外にビルドディレクトリを作成すること( "out-of-source"ビルド)は実際に唯一の正気なことであり、最近では事実上の標準となっています。したがって、CMakeの人々が推奨するように、またこれまでに出会ったすべてのプログラマーがそうであるように、ソースディレクトリの外に、別の「ビルド」ディレクトリを用意してください。binディレクトリに関しては、まあ、それは慣例であり、この投稿の冒頭で述べたように、これに固執することはおそらく良い考えです。

引用:私の​​コードを文書化するためにdoxygenも使用したいと思います。これをcmakeおよびmakeで自動的に実行することは可能ですか?

はい。それは不可能ではありません、それは素晴らしいです。どれだけ豪華にしたいかに応じて、いくつかの可能性があります。CMakeにはDoxygen用のモジュール(つまりfind_package(Doxygen))があり、一部のファイルでDoxygenを実行するターゲットを登録できます。Doxyfileのバージョン番号を更新したり、ソースファイルの日付/作成者のスタンプを自動的に入力したりするなど、もっと手の込んだことをしたい場合は、CMake kung-fuを使用すればすべて可能です。一般的に、これを行うには、トークンを見つけてCMakeの解析コマンドで置き換えるソースDoxyfile(たとえば、上記のフォルダーレイアウトに配置した「Doxyfile.in」)を保持する必要があります。で、私のトップレベルのCMakeListsファイル、あなたはcmakeの-たDoxygen一緒にいくつかの空想のことを行いますCMakeのカンフーのそのような作品を見つけるでしょう。


だからmain.cpp行くべきtrunk/binですか?
UgniusMalūkas18年

17

プロジェクトの構造化

私は一般的に以下を支持します:

├── CMakeLists.txt
|
├── docs/
│   └── Doxyfile
|
├── include/
│   └── project/
│       └── vector3.hpp
|
├── src/
    └── project/
        └── vector3.cpp
        └── test/
            └── test_vector3.cpp

これは、ライブラリに対して明確に定義された一連のAPIファイルがあることを意味し、構造は、ライブラリのクライアントが実行することを意味します

#include "project/vector3.hpp"

それほど明確ではない

#include "vector3.hpp"


/ srcツリーの構造が/ includeツリーの構造と一致するのが好きですが、それは個人的な好みです。ただし、プロジェクトが/ include / project内のサブディレクトリを含むように拡張する場合、通常は/ srcツリー内のサブディレクトリと一致させると役立ちます。

テストでは、テストするファイルに「近づけて」おくことをお勧めします。最終的に/ src内にサブディレクトリがある場合、特定のファイルのテストコードを見つけたい場合、他の人がフォローするのは非常に簡単です。


テスト中

次に、コードを単体テストするためにGoogle C ++テストフレームワークを使用したいと思います。

Gtestは確かに使いやすく、その機能の点でかなり包括的です。gmockと一緒に使用してその機能を拡張することは非常に簡単ですが、gmockを使用した私自身の経験はそれほど好ましくありません。私はこれが自分の欠点につながる可能性があることを受け入れる準備ができていますが、gmockテストは作成が難しく、壊れやすく、保守が難しい傾向があります。gmock棺の大きな釘は、スマートポインタではうまく機能しないことです。

これは巨大な質問への非常に些細で主観的な答えです(おそらくSOには属していません)。

これを私のコードと一緒に、たとえば「inc / gtest」または「contrib / gtest」フォルダーにバンドルすることをお勧めしますか?バンドルされている場合は、fuse_gtest_files.pyスクリプトを使用してファイルの数を減らすか、そのままにしておくことをお勧めしますか?バンドルされていない場合、この依存関係はどのように処理されますか?

私はCMakeのExternalProject_Addモジュールを使用することを好みます。これにより、gtestのソースコードをリポジトリに保存したり、どこにでもインストールしたりする必要がなくなります。これはダウンロードされ、ビルドツリーに自動的にビルドされます。

詳細については、こちらの回答をご覧ください。

テストを書くことになると、これらは一般的にどのように編成されますか?クラスごとに1つのcppファイル(たとえば、test_vector3.cpp)があると考えていましたが、すべてを1つのバイナリにコンパイルして、簡単に一緒に実行できるようにしましたか?

良い計画。


建物

私はCMakeのファンですが、テスト関連の質問と同様に、SOはおそらくそのような主観的な問題について意見を求めるのに最適な場所ではありません。

CMakeLists.txtは、ライブラリのみ、またはライブラリとテストのいずれかを構築できるようにどのように見える必要がありますか?

add_library(ProjectLibrary <All library sources and headers>)
add_executable(ProjectTest <All test files>)
target_link_libraries(ProjectTest ProjectLibrary)

ライブラリはターゲット「ProjectLibrary」として表示され、テストスイートはターゲット「ProjectTest」として表示されます。ライブラリをテストexeの依存関係として指定することにより、テストexeをビルドすると、ライブラリが古くなっている場合に自動的に再構築されます。

また、私はビルド広告とbinディレクトリを持つかなりの数のプロジェクトを見てきました。ビルドはビルドディレクトリで行われ、その後バイナリがbinディレクトリに移動されますか?テストのバイナリとライブラリは同じ場所にありますか?

CMakeは「アウトオブソース」ビルドを推奨しています。つまり、プロジェクトの外に独自のビルドディレクトリを作成し、そこからCMakeを実行します。これは、ビルドファイルでソースツリーを「汚染」することを回避し、vcsを使用している場合は非常に望ましい方法です。

あなたはでき建て一度バイナリが移動したり、別のディレクトリにコピーされることを指定したり、それらを別のディレクトリにデフォルトで作成されていることが、必要は一般的にありません。CMakeは、必要に応じてプロジェクトをインストールする包括的な方法を提供します。または、他のCMakeプロジェクトがプロジェクトの関連ファイルを簡単に「検索」できるようにします。

CMtestがgtestテストを見つけて実行するための独自のサポートに関しては、プロジェクトの一部としてgtestをビルドする場合、これはほとんど不適切です。このFindGtestモジュールは、gtestがプロジェクトの外部で個別にビルドされた場合に使用するように設計されています。

CMakeは独自のテストフレームワーク(CTest)を提供します。理想的には、すべてのgtestケースがCTestケースとして追加されます。

ただし、個々のctestケースとしてgtestケースを簡単に追加できるようにGTEST_ADD_TESTSによって提供さFindGtestれるマクロは、TESTおよび以外のgtestのマクロに対しては機能しないという点で多少欠けていますTEST_F付加価値タイプパラメータ化用いた試験TEST_PTYPED_TEST_Pなどがすべてで処理されていません。

問題は私が知っている簡単な解決策を持っていません。gtestケースのリストを取得する最も堅牢な方法は、フラグを指定してテストexeを実行することです--gtest_list_tests。ただし、これはexeがビルドされた後にのみ実行できるため、CMakeはこれを利用できません。これには2つの選択肢があります。CMakeはC ++コードを解析してテストの名前を推測する必要があります(すべてのgtestマクロ、コメントアウトされたテスト、無効化されたテストを考慮に入れる場合は、極端ではない)、またはテストケースを手動でCMakeLists.txtファイル。

また、コードをドキュメント化するためにdoxygenを使用したいと思います。これをcmakeおよびmakeで自動的に実行することは可能ですか?

はい-この面での経験はありませんが。CMakeはFindDoxygenこの目的のために提供します。


6

他の(優れた)回答に加えて、私が比較的大規模なプロジェクトで使用してきた構造について説明します。
他の回答で述べられていることを繰り返すだけなので、Doxygenについてのサブ質問には触れません。


根拠

モジュール性と保守性のために、プロジェクトは小さなユニットのセットとして編成されています。わかりやすくするために、X = A、B、CなどのようにUnitXという名前を付けます(ただし、一般的な名前を付けることができます)。ディレクトリ構造は、この選択を反映するように編成され、必要に応じてユニットをグループ化できます。

解決

基本的なディレクトリレイアウトは次のとおりです(ユニットの内容については後で詳しく説明します)。

project
├── CMakeLists.txt
├── UnitA
├── UnitB
├── GroupA
   └── CMakeLists.txt
   └── GroupB
       └── CMakeLists.txt
       └── UnitC
       └── UnitD
   └── UnitE

project/CMakeLists.txt 次のものを含めることができます。

cmake_minimum_required(VERSION 3.0.2)
project(project)
enable_testing() # This will be necessary for testing (details below)

add_subdirectory(UnitA)
add_subdirectory(UnitB)
add_subdirectory(GroupA)

project/GroupA/CMakeLists.txt

add_subdirectory(GroupB)
add_subdirectory(UnitE)

project/GroupB/CMakeLists.txt

add_subdirectory(UnitC)
add_subdirectory(UnitD)

ここで、さまざまなユニットの構造を見てみましょう(例として、UnitDを取り上げましょう)。

project/GroupA/GroupB/UnitD
├── README.md
├── CMakeLists.txt
├── lib
   └── CMakeLists.txt
   └── UnitD
       └── ClassA.h
       └── ClassA.cpp
       └── ClassB.h
       └── ClassB.cpp
├── test
   └── CMakeLists.txt
   └── ClassATest.cpp
   └── ClassBTest.cpp
   └── [main.cpp]

さまざまなコンポーネント:

  • ソース(.cpp)とヘッダー(.h)が同じフォルダーにあるのが好きです。これにより、ディレクトリ階層の重複が回避され、メンテナンスが容易になります。インストールの場合、ヘッダーファイルをフィルターするだけで問題ありません(特にCMakeの場合)。
  • ディレクトリの役割は、UnitD後ででファイルを含めることを許可することです#include <UnitD/ClassA.h>。また、本機を設置する際は、そのままディレクトリ構造をそのままコピーすることができます。ソースファイルをサブディレクトリに整理することもできます。
  • READMEユニットの内容を要約し、それに関する有用な情報を指定するファイルが好きです。
  • CMakeLists.txt 単純に含めることができます:

    add_subdirectory(lib)
    add_subdirectory(test)
  • lib/CMakeLists.txt

    project(UnitD)
    
    set(headers
        UnitD/ClassA.h
        UnitD/ClassB.h
        )
    
    set(sources
        UnitD/ClassA.cpp
        UnitD/ClassB.cpp    
        )
    
    add_library(${TARGET_NAME} STATIC ${headers} ${sources})
    
    # INSTALL_INTERFACE: folder to which you will install a directory UnitD containing the headers
    target_include_directories(UnitD
                               PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
                               PUBLIC $<INSTALL_INTERFACE:include/SomeDir>
                               )
    
    target_link_libraries(UnitD
                          PUBLIC UnitA
                          PRIVATE UnitC
                          )

    ここでは、我々がディレクトリを含めたいとCMakeのを伝えるために必要がないことに注意UnitAし、UnitCこれらのユニットを構成するときに、これはすでに指定されていたとして、。また、PUBLIC依存するすべてのターゲットUnitDに、UnitA依存関係を自動的に含める必要があることを通知しますが、その場合はUnitC必要ありません(PRIVATE)。

  • test/CMakeLists.txt (GTestを使用する場合は、以下を参照してください):

    project(UnitDTests)
    
    add_executable(UnitDTests
                   ClassATest.cpp
                   ClassBTest.cpp
                   [main.cpp]
                   )
    
    target_link_libraries(UnitDTests
                          PUBLIC UnitD
    )
    
    add_test(
            NAME UnitDTests
            COMMAND UnitDTests
    )

GoogleTestの使用

Google Testの場合、最も簡単なのは、そのソースがソースディレクトリのどこかに存在する場合ですが、実際にそこに追加する必要はありません。私はこのプロジェクトを使用してプロジェクトを自動的にダウンロードしてきました。テストターゲットが複数ある場合でも、その使用方法を関数にラップして、ダウンロードが1回だけになるようにします。

このCMake関数は次のとおりです。

function(import_gtest)
  include (DownloadProject)
  if (NOT TARGET gmock_main)
    include(DownloadProject)
    download_project(PROJ                googletest
                     GIT_REPOSITORY      https://github.com/google/googletest.git
                     GIT_TAG             release-1.8.0
                     UPDATE_DISCONNECTED 1
                     )
    set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) # Prevent GoogleTest from overriding our compiler/linker options when building with Visual Studio
    add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR} EXCLUDE_FROM_ALL)
  endif()
endfunction()

そして、テストターゲットの1つで使用したい場合は、次の行をに追加しますCMakeLists.txt(これは上記の例の場合ですtest/CMakeLists.txt)。

import_gtest()
target_link_libraries(UnitDTests gtest_main gmock_main)

あなたはGtestとcmakeでそこでやった素敵な「ハック」!有用!:)
Tanasis
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.