web-dev-qa-db-ja.com

サブディレクトリを含むCMake

CMakeを使用して正しくコンパイルするようにプロジェクトをセットアップしようとしています。

私のディレクトリは次のようになります。

root
 |- bin
 |   |- // Where I want to build CMake from - using 'cmake ..'
 |- build
 |   |-
 |- include
 |   |- database
 |   |    |- database.h
 |- src
     |- database
     |    |- database.cpp
     |- main
          |- main.cpp

私のサブディレクトリは、私のプロジェクトが大きくなり、CMakeを学ぶことをお勧めします。現時点では、src /内のサブディレクトリなしでCMakeを動作させることしかできません。ただし、このプロジェクトが多くのサブディレクトリに成長することを期待しています。

.cppファイルを含む各ディレクトリ内に複数のCMakeLists.txtが必要ですか?誰かが私を正しい方向に向けることができますか?

ありがとうございました!

13
Van

プロジェクトに複数のCMakeLists.txtは必要ないようです。複数のCMakeLists.txtを複数回使用する目的は複数ありますが、プロジェクトに収まらないようです。たとえば、1つの利点は階層構造であるため、異なるunitsを分離できます個別に、最終的にリンクされます。

ルートにtestsという別のディレクトリがある場合、状況を考慮してください。そのディレクトリには、コンパイルするかどうかを開発者に選択させる単体テストが含まれています。その場合、1つのCMakeLists.txtをtestsに配置し、プライマリCMakeLists.txtで add_subdirectory(tests) を使用してこれを有効にします。

if(testing_enabled)
    add_subdirectory(tests)
endif()

testsには、別のCMakeLists.txtがあります。このようにして、懸念を分離します。単体テストの開発は、プロジェクトの開発とは独立しており、ビルドプロセスも独立しています。

別の例

ユーザーが選択できるライブラリが2つある場合の状況を考慮してください。この場合、rootに2つのディレクトリ、lib1およびlib2。これで、プライマリCMakeLists.txtで次のようなことができます。

if(IWantLib1)
    add_subdirectory(lib1)
else()
    add_subdirectory(lib2)
endif()

そして両方lib1およびlib2ディレクトリにはCMakeLists.txtが含まれています。

11

2つの主要なアプローチの詳細な説明については この記事 を参照しますが、このようなプロジェクトを構築する方法はいくつかあります。

  • 最上位にある1つのCMakeLists.txtファイル。すべてのソースファイルがすべての異なるサブディレクトリにリストされます。通常、これは非常に単純なプロジェクトでのみ表示されます。
  • 各ディレクトリに1つのCMakeLists.txtファイルがあり、それぞれがadd_subdirectory()を使用して親によって持ち込まれます。このアプローチは非常に一般的です。
  • 最上位の1つのCMakeLists.txtファイル。各サブディレクトリには、独自のソースファイルとターゲットをリストする独自のファイルがあります。最上位のCMakeLists.txtファイルは、include()でサブディレクトリファイルを取り込みます。あまり一般的ではありませんが、他の2つよりも利点があります。

それぞれに長所と短所があります。最上位のCMakeLists.txtファイルを1つだけにすることは、ファイルとサブディレクトリが非常に少ない場合にのみお勧めします。プロジェクトが大きくなると、すべてを最上位に保持することが多すぎて、結果のCMakeLists.txtファイルを追跡しにくくなる可能性があります。また、ファイルの追加または削除の変更が特定のディレクトリに制限されないという欠点もあります。大したことではないように思えるかもしれませんが、プロジェクトで複数の人が作業していて、プロジェクトのどの部分が他の人の変更に影響するかを簡単に確認したい場合(例:git履歴内)、それは難しくなります。これは、両方のファイルを追加/削除し、それによって最上位のCMakeLists.txtファイルを変更し、競合の可能性がある場合に特に当てはまります。

プロジェクトのサイズが自明ではなくなると、ほとんどの場合、各サブディレクトリにCMakeLists.txtファイルを追加し、add_subdirectory()を使用してそれらをすべてまとめます。 @TheQuantumPhysicistの答えは、これがどのように役立つかを示す良い例ですので、ここではそれらの詳細のほとんどを繰り返しません。この構造は、ビルドツリーのセクション全体を簡単にオン/オフする機能を提供しますが、さらに重要なことに、各サブディレクトリに独自の変数スコープを与えます。これは、ソースツリーの一部に変数などを設定したいが、それらの変更を別の部分に表示させたくない場合に重要になります(複雑なディレクトリ構造の1つのセクションにのみ適用したいコンパイラフラグを考えてください)。

各サブディレクトリがinclude()によってもたらされるファイルを提供する1つの最上位CMakeLists.txtファイルの3番目のオプションはあまり一般的ではありませんが、各サブディレクトリで1つのCMakeLists.txtファイルを使用することに類似しています。どちらも、ディレクトリ内のファイルに関する詳細をCMakeLists.txtまたはそのディレクトリ内の他の同様の名前のファイルにローカライズします。したがって、変更はマージが容易になり、バージョン管理履歴などで理解しやすくなります。この3番目のアプローチで許可されないことの1つは、target_link_libraries()を使用するときにtarget_sources() ] _は、各サブディレクトリのソースファイルを指定します。この回答の冒頭にリンクされている記事では、target_sources()が有利な理由について詳しく説明し、多くのプロジェクトでこの3番目の方法が望ましい理由の中心にあります。

最後に、ビルドツリーをソースツリー内に配置する習慣を身に付けないことをお勧めします。むしろ、ビルドツリーをソースツリーの兄弟として作成します。ビルドがソースツリーに影響を与えないようにします。必要なのは、誰かがソースツリーに、ビルドツリーに使用したものと同じ名前のディレクトリを作成して、問題を引き起こすことです(これは何度も見ました!)。デバッグビルド用とリリースビルド用など、1つのソースツリーに複数のビルドツリーを設定することもできます。そのため、これらをソースツリーの外部に置くことで、ソースツリーの混乱を抑えることができます。

18
Craig Scott