CMakeLists.txtの再帰的検索とサブディレクトリの追加

はじめに

CMakeを使用したプロジェクトのビルド設定では、CMakeLists.txtファイルを用いてプロジェクト構成を定義する。特に、大規模なプロジェクトや階層構造が深いプロジェクトの場合、カレントディレクトリとそのサブディレクトリ内にあるすべてのCMakeLists.txtファイルを検索し、それらをプロジェクトのサブディレクトリとして追加する方法が役立つらしい。

以下に再帰的にCMakeLists.txtファイルを検索し、サブディレクトリを追加する一例を示す。

実例と解説

cmake_minimum_required(VERSION 3.x)
project (your_project_name)

file(GLOB_RECURSE TEST_LISTS
        RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
        */CMakeLists.txt)

foreach(list ${TEST_LISTS})
    get_filename_component(dir ${list} PATH)
    add_subdirectory(${dir})
endforeach()

このCMakeLists.txtファイルは以下の処理を行っている。

  1. 必要な最低限のCMakeバージョンを指定
  2. プロジェクト名を指定
  3. カレントディレクトリから再帰的にCMakeLists.txtファイルを検索し、結果を変数に格納
  4. 検索したCMakeLists.txtファイルに対してループを実行
  5. 現在のループで処理されているCMakeLists.txtファイルのディレクトリ名を取得
  6. ディレクトリをサブディレクトリとして追加
  7. ループを終了

この方法を使用することで、ディレクトリ構造内のすべてのCMakeLists.txtファイルが自動的に処理され、プロジェクトのビルド設定が生成される。

もうちょっと具体的に解説

このCMakeLists.txtファイルは、以下の処理を行っている。 (チャットGPT-4さんの説明)

  1. cmake_minimum_required(VERSION 3.x)は、このプロジェクトで必要な最低限のCMakeバージョンを3.xに指定しています。これにより、古いバージョンのCMakeを使用している場合は、エラーメッセージが表示されます。

  2. project(your_project_name)は、プロジェクト名をyour_project_nameに指定しています。

  3. file(GLOB_RECURSE TEST_LISTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} */CMakeLists.txt)は、GLOB_RECURSEを使って、カレントディレクトリ(${CMAKE_CURRENT_SOURCE_DIR})から再帰的にCMakeLists.txtファイルを検索し、結果をTEST_LISTS変数に格納しています。RELATIVEオプションは、結果のパスをカレントディレクトリを基準にした相対パスにするために使用されています。

    1. file: CMakeの file コマンドは、ファイルやディレクトリに関する操作を実行するために使用されます。これには、ファイルの読み書き、ディレクトリの作成、およびファイルの検索などが含まれます。
    2. GLOB_RECURSE: file コマンドの GLOB_RECURSE オプションは、指定されたパターンに一致するファイルを再帰的に検索します。つまり、カレントディレクトリとそのサブディレクトリ内のすべてのファイルを検索対象とします。
    3. TEST_LISTS: 検索されたファイルの結果を格納する変数名です。この例では、TEST_LISTSという変数に検索結果が格納されます。
    4. RELATIVE: RELATIVE オプションは、検索結果のファイルパスを、${CMAKE_CURRENT_SOURCE_DIR} からの相対パスとして取得することを指定します。これにより、絶対パスではなく相対パスを扱うことができます。
    5. ${CMAKE_CURRENT_SOURCE_DIR}: 現在のソースディレクトリへのパスを表す変数です。CMakeLists.txtファイルがあるディレクトリを指します。
    6. /CMakeLists.txt: 検索するファイルのパターンを指定します。この場合、すべてのサブディレクトリにある CMakeLists.txt ファイルを検索対象とします。

    このコマンドを実行すると、カレントディレクトリとそのすべてのサブディレクトリから CMakeLists.txt ファイルを再帰的に検索し、相対パスTEST_LISTS という変数に格納します。この変数は、後続の foreach ループで処理され、各サブディレクトリがプロジェクトに追加されます。

  4. foreach(list ${TEST_LISTS})は、TEST_LISTSに格納されたすべてのCMakeLists.txtファイルに対してループを実行します。

    • foreach(list ${TEST_LISTS}): TEST_LISTS 変数に格納された各ファイルパスに対してループを開始します。ループ内では、list という変数に現在のファイルパスが格納されます。
  5. get_filename_component(dir ${list} PATH)は、現在のループで処理されているCMakeLists.txtファイルのディレクトリ名を取得し、dir変数に格納しています。

    • get_filename_component(dir ${list} PATH): get_filename_component コマンドは、ファイルパスから特定のコンポーネントを取得するために使用されます。この場合、PATH オプションを使用してファイルパスからディレクトリ部分を抽出し、dir という変数に格納しています。
  6. add_subdirectory(${dir})は、dirで指定されたディレクトリをサブディレクトリとして追加します。これにより、そのディレクトリ内のCMakeLists.txtファイルが処理されます。

    • add_subdirectory(${dir}): add_subdirectory コマンドは、指定されたディレクトリを現在のプロジェクトにサブディレクトリとして追加します。このコマンドは、${dir} で指定されたディレクトリにある CMakeLists.txt を処理し、そのディレクトリ内のプロジェクト構成を現在のプロジェクトにマージします。
  7. endforeach()は、foreachループを終了します。

このCMakeLists.txtファイルの目的は、カレントディレクトリとそのサブディレクトリ内にあるすべてのCMakeLists.txtファイルを検索し、それらをプロジェクトのサブディレクトリとして追加することです。これにより、ディレクトリ構造内のすべてのCMakeLists.txtファイルが自動的に処理され、プロジェクトのビルド設定が生成されます。