CMake の add_subdirectory() 関数の基本的な使い方

2024-12-18

CMake の add_subdirectory() 関数

CMake の add_subdirectory() 関数は、プロジェクトのディレクトリ構造を階層的に管理するために使用される重要な関数です。この関数を使うことで、メインの CMakeLists.txt ファイルからサブディレクトリ内の CMakeLists.txt ファイルを読み込み、そのサブディレクトリ内のターゲットをビルドプロセスに組み込むことができます。

基本的な使い方

add_subdirectory(subdirectory_name [binary_dir])
  • binary_dir (オプション): サブディレクトリのビルド出力ディレクトリを指定します。省略すると、デフォルトのビルドディレクトリが使用されます。
  • subdirectory_name: サブディレクトリの相対パスを指定します。


# トップレベルの CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyProject)

# サブディレクトリ "src" を追加
add_subdirectory(src)

この例では、src ディレクトリ内の CMakeLists.txt ファイルが読み込まれ、そのディレクトリ内のターゲットがビルドプロセスに追加されます。

サブディレクトリ内の CMakeLists.txt

# src/CMakeLists.txt
add_executable(my_executable main.cpp)

利点

  • ビルドプロセスの簡素化
    トップレベルの CMakeLists.txt ファイルでサブディレクトリを追加するだけで、ビルドプロセスを自動化できます。
  • 再利用性
    サブディレクトリ内の CMakeLists.txt ファイルは、他のプロジェクトでも再利用することができます。
  • モジュール化
    プロジェクトを複数のサブディレクトリに分割することで、コードの整理と管理が容易になります。
  • サブディレクトリを追加すると、CMake は新しいスコープを作成します。そのため、サブディレクトリ内で定義された変数や関数は、親ディレクトリから直接アクセスできません。
  • サブディレクトリ内の CMakeLists.txt ファイルは、そのディレクトリ内に存在する必要があります。


CMake の add_subdirectory() 関数に関する一般的なエラーとトラブルシューティング

add_subdirectory() 関数は強力なツールですが、誤用や設定ミスによりさまざまなエラーが発生する可能性があります。以下に、一般的なエラーとトラブルシューティングの方法を説明します。

サブディレクトリの CMakeLists.txt ファイルが見つからない

  • 解決方法
    • サブディレクトリ内に CMakeLists.txt ファイルを作成します。
    • add_subdirectory() 関数の引数を正しいパスに修正します。
  • 原因
    指定されたサブディレクトリに CMakeLists.txt ファイルが存在しないか、パスが間違っている。

サブディレクトリ内のターゲットがビルドされない

  • 解決方法
    • サブディレクトリ内の CMakeLists.txt ファイルでターゲットを適切に定義します。例えば、ライブラリであれば add_library()、実行ファイルであれば add_executable() を使用します。
    • ビルドシステムの設定を確認します。例えば、ビルドタイプやコンパイラの設定が正しいかチェックします。
  • 原因
    サブディレクトリ内の CMakeLists.txt ファイルでターゲットが正しく定義されていない、またはビルドシステムの設定に問題がある。

ビルドディレクトリの競合

  • 解決方法
    • add_subdirectory() 関数のオプション引数 binary_dir を使用して、各サブディレクトリに個別のビルドディレクトリを指定します。
  • 原因
    複数のサブディレクトリが同じビルドディレクトリを使用しようとしている。

変数スコープの問題

  • 解決方法
    • サブディレクトリ内で必要な変数を親ディレクトリから渡すか、共通の変数を定義して共有します。
  • 原因
    サブディレクトリ内の CMakeLists.txt ファイルで定義された変数が親ディレクトリからアクセスできない。

依存関係の解決問題

  • 解決方法
    • target_link_libraries() 関数を使用して、ターゲット間の依存関係を明示的に設定します。
  • 原因
    サブディレクトリ内のターゲットが他のターゲットに依存しているが、依存関係が正しく設定されていない。
  • デバッグモードを使用します
    CMake のデバッグモードを使用すると、ビルドプロセスをステップごとに追跡することができます。
  • シンプルな例から始めます
    複雑なプロジェクトをいきなり作成するのではなく、小さな例から始めて徐々に機能を追加していくと、問題を特定しやすくなります。
  • CMake のドキュメントを参照します
    CMake の公式ドキュメントには詳細な情報とトラブルシューティングのガイドラインがあります。
  • エラーメッセージを注意深く読みます
    エラーメッセージには問題の原因や解決方法に関するヒントが含まれていることが多いです。


CMake の add_subdirectory() 関数の例題解説

基本的な例

# トップレベルの CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyProject)

add_subdirectory(src)

サブディレクトリ内の CMakeLists.txt

# src/CMakeLists.txt
add_executable(my_executable main.cpp)

この例では、src ディレクトリ内の main.cpp ファイルから実行ファイル my_executable が作成されます。

複数のサブディレクトリを持つプロジェクト

# トップレベルの CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyProject)

add_subdirectory(src)
add_subdirectory(tests)

この例では、src ディレクトリと tests ディレクトリ内の CMakeLists.txt ファイルが読み込まれます。これにより、ソースコードとテストコードを別々のディレクトリに整理することができます。

サブディレクトリ間の依存関係

# トップレベルの CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyProject)

add_subdirectory(lib)
add_subdirectory(app)
# lib/CMakeLists.txt
add_library(my_library src/my_library.cpp)
# app/CMakeLists.txt
add_executable(my_app main.cpp)
target_link_libraries(my_app my_library)

この例では、app ディレクトリ内の my_app 実行ファイルが lib ディレクトリ内の my_library ライブラリに依存しています。target_link_libraries() 関数を使用して、この依存関係を明示的に設定しています。

サブディレクトリにビルドディレクトリを指定

add_subdirectory(src build)

この例では、src ディレクトリ内のターゲットは build ディレクトリにビルドされます。



CMake の add_subdirectory() 関数の代替方法

add_subdirectory() 関数は、CMake プロジェクトのディレクトリ構造を階層的に管理する一般的な方法ですが、特定の状況によっては、他の手法も検討することができます。

インクルードディレクトリの追加

  • 方法
    • include_directories() 関数を使用して、サブディレクトリのヘッダーファイルのパスを追加します。
    • サブディレクトリ内のソースコードファイルを直接トップレベルの CMakeLists.txt ファイルで指定します。
  • 適合するケース
    サブディレクトリ内のソースコードを直接コンパイルする必要がある場合。


# トップレベルの CMakeLists.txt
include_directories(src)

add_executable(my_executable main.cpp src/my_module.cpp)

外部プロジェクトのインポート

  • 方法
    • add_subdirectory() 関数を使用して、サブディレクトリ内の CMakeLists.txt ファイルを読み込みます。
    • install() 関数を使用して、ビルドされたライブラリや実行ファイルをインストールディレクトリにコピーします。
    • find_package() 関数を使用して、インストールされたパッケージを他のプロジェクトから利用します。
  • 適合するケース
    サブディレクトリ内のプロジェクトを独立したライブラリや実行ファイルとしてビルドし、他のプロジェクトから利用したい場合。


# トップレベルの CMakeLists.txt
add_subdirectory(my_library)

find_package(my_library REQUIRED)

add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE my_library::my_library)

カスタムビルドシステムの使用

  • 方法
    • CMake のスクリプト言語を使用して、カスタムビルドステップを定義します。
    • execute_process() 関数を使用して、外部のビルドツールやスクリプトを実行します。
  • 適合するケース
    CMake の標準的な機能では対応できない複雑なビルドプロセスが必要な場合。

注意

これらの代替方法は、プロジェクトの規模や複雑さ、ビルドプロセスの要件に応じて選択する必要があります。一般的には、add_subdirectory() 関数が最もシンプルで効果的な方法ですが、特定の状況では、他の手法がより適している場合があります。