web-dev-qa-db-ja.com

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

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

現在、2つのファイルしかないvector3.hppおよびvector3.cpp。私はすべてに精通するにつれて、このプロジェクトはゆっくりと成長し始めます(一般的な線形代数ライブラリのようになります)。そのため、hppファイルとcppファイルを整理する方法を2つ見つけました。最初の方法は次のとおりです。

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

そして2つ目は:

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

どちらをお勧めしますか?その理由は何ですか?

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

テストの作成に関しては、これらは一般的にどのように構成されていますか?私はクラスごとに1つのcppファイルを持っていると考えていました(test_vector3.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は、ライブラリだけをビルドするか、ライブラリとテストをビルドできるようにする必要がありますか?また、buildディレクトリとbinディレクトリを持つプロジェクトをかなり見ました。ビルドはビルドディレクトリで行われ、バイナリはbinディレクトリに移動しましたか?テスト用のバイナリとライブラリは同じ場所にありますか?または、次のように構成する方が意味がありますか?

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

また、doxygenを使用してコードを文書化したいと思います。これをcmakeとmakeで自動的に実行することは可能ですか?

非常に多くの質問で申し訳ありませんが、これらのタイプの質問に十分に答えるC++に関する本を見つけていません。

112
rozzy

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

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

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

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

依存関係のバンドル:これは、依存関係を見つけて構成するビルドシステムの能力と、単一バージョンに対するコードの依存度に大きく依存していると思います。また、ユーザーの能力と、プラットフォームにインストールする依存関係がどれだけ簡単かにも依存します。 CMakeには、Google Test用のfind_packageスクリプトが付属しています。これにより、作業が非常に簡単になります。必要な場合にのみバンドルし、それ以外の場合は回避します。

ビルド方法:ソース内ビルドを避けます。 CMakeを使用すると、ソースビルドを簡単に作成でき、作業がずっと簡単になります。

また、CTestを使用してシステムのテストを実行することも想定しています(GTestの組み込みサポートも付属しています)。ディレクトリレイアウトとテスト構成の重要な決定は次のとおりです。サブプロジェクトになりますか?その場合、CMakeListsを設定するときにさらに作業が必要であり、サブプロジェクトをサブディレクトリに分割する必要があります。各サブディレクトリにはincludeおよびsrcファイルがあります。独自の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を使用してdocターゲットを追加するのは簡単です。

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

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

ライブラリを構築している場合は、コンパイラ間の違いを正しく取得するためにエクスポート定義も必要になります。 MSVCの__declspecおよびGCC/clangのvisibility属性。

76
pmr

手始めとして、無視できないディレクトリにはいくつかの従来の名前があります。これらは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、および場合によってはテストフォルダー)が最上部にあることがわかります。レベルは、アウトソースビルドの「ビルド」ディレクトリに加えて、ビルドプロセスで生成されるファイル以外は何も含まないすべてのフォルダーです。したがって、srcフォルダのみをバックアップする必要があります。または、バージョン管理システム/サーバー(GitやSVNなど)で管理する必要があります。

そして、最終的にライブラリを配布したい場合、宛先システムにヘッダーファイルをインストールする場合、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++ Testing Frameworkを使用して、コードのユニットテストを行います。かなり使いやすいようです。これを私のコード、たとえば「inc/gtest」または「contrib/gtest」フォルダーにバンドルすることをお勧めしますか?バンドルされている場合、Fuse_gtest_files.pyスクリプトを使用して数またはファイルを減らすか、そのままにしておくことをお勧めしますか?バンドルされていない場合、この依存関係はどのように処理されますか?

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

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

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

引用: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ディレクトリのサブディレクトリは、includeディレクトリのサブディレクトリをミラーリングする必要があります。これは、物事を直感的に保つためです(また、サブディレクトリ構造を合理的にフラット(浅い)に保つようにしてください多くの場合、何よりも手間がかかります)。第二に、 "include"ディレクトリは単なるインストールディレクトリであり、その内容はsrcディレクトリから選択されたヘッダーになります。

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

引用:CMakeLists.txtは、ライブラリのみ、またはライブラリとテストをビルドするために、どのように見える必要がありますか?

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

引用:また、build ad a binディレクトリを持つプロジェクトをかなり見ました。ビルドはビルドディレクトリで行われ、バイナリはbinディレクトリに移動しましたか?テスト用のバイナリとライブラリは同じ場所にありますか?または、次のように構成する方が意味がありますか?

ソースの外にビルドディレクトリを作成する( "out-of-source"ビルド)のは、本当に正しいことであり、最近では事実上の標準になっています。ですから、CMakeの人々が推奨するように、そして私がこれまでに会ったすべてのプログラマーがそうであるように、ソースディレクトリの外側に別の「build」ディレクトリを必ず持ってください。 binディレクトリに関しては、これは慣習であり、この投稿の冒頭で述べたように、おそらくこれに固執することをお勧めします。

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

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

37
Mikael Persson

プロジェクトの構造化

私は一般的に以下を好むでしょう:

├── 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++ Testing Frameworkを使用したいと思います。かなり使いやすいようです。

Gtestは実際に使用するのが簡単であり、その機能に関してかなり包括的なものです。 gmock と一緒に使用してその機能を簡単に拡張できますが、gmockでの私自身の経験はあまり好ましくありませんでした。これは私自身の欠点にまで及んでいる可能性があることを受け入れる準備ができていますが、gmockテストは作成するのがより難しく、壊れやすく/維持が難しい傾向があります。 gmockのinにある大きな爪は、スマートポインターではニースが実際には再生されないことです。

これは、巨大な質問に対する非常に些細で主観的な答えです(おそらくS.O.に属していません)。

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

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

私の ここで詳細に対処する回答 を参照してください。

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

いい計画。


建物

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

ライブラリだけを構築するか、ライブラリとテストを構築するために、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をビルドすると、ライブラリが古くなった場合に自動的に再構築されます。

また、build ad a binディレクトリを持つプロジェクトをかなり見ました。ビルドはビルドディレクトリで行われ、バイナリはbinディレクトリに移動しましたか?テスト用のバイナリとライブラリは同じ場所にありますか?

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

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

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

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

しかし、FindGtestによって提供されるGTEST_ADD_TESTSマクロは、個々のctestケースとしてgtestケースを簡単に追加できるようにするため、TEST以外のgtestのマクロでは機能せず、 TEST_F値- または Type-parameterisedTEST_PTYPED_TEST_Pなどを使用したテストはまったく処理されません。

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

また、コードを文書化するためにdoxygenを使用したいと思います。これをcmakeとmakeで自動的に実行することは可能ですか?

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

17
Fraser

他の(優れた)回答に加えて、比較的大規模プロジェクトに使用している構造について説明します。
他の回答で述べられていることを繰り返すだけなので、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)
5
oLen