CMake: 究極のターゲット探索ガイド – BUILDSYSTEM_TARGETS の限界を超えてあらゆるターゲットを網羅


CMakeの「Properties: Directories」における「BUILDSYSTEM_TARGETS」プロパティは、ディレクトリ内に add_library(), add_executable(), または add_custom_target() コマンドで追加されたビルドシステムターゲットのリストを保持します。これは読み取り専用プロパティであり、インポートされたターゲットやエイリアスターゲットは含まれませんが、インターフェースライブラリは含まれます。

利点

  • ディレクトリ内のターゲットを操作するカスタムCMakeロジックを作成する際に役立ちます。
  • 特定のターゲットに依存する他のターゲットを特定するのに役立ちます。
  • サブディレクトリ内のターゲットを簡単に一覧表示できます。

使用方法

get_property() コマンドを使用して、ディレクトリの BUILDSYSTEM_TARGETS プロパティを取得できます。

get_property(targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS)

このコマンドは、targets 変数にセミコロンで区切られたターゲット名のリストを格納します。

以下の例は、mytarget という名前のターゲットが CMakeLists.txt ファイルが存在するディレクトリに追加された場合、BUILDSYSTEM_TARGETS プロパティの使用方法を示しています。

add_executable(mytarget main.cpp)

get_property(targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS)
message(STATUS "Targets in this directory: ${targets}")

この例は、次の出力を生成します。

Targets in this directory: mytarget
  • ターゲットの依存関係を特定するには、target_link_libraries() コマンドを使用することもできます。
  • BUILDSYSTEM_TARGETS プロパティは、CMake 3.7 以降でのみ使用可能です。


cmake_minimum_required(VERSION 3.7)

project(myproject)

add_subdirectory(subdirectory1)
add_subdirectory(subdirectory2)

get_property(targets1 DIRECTORY subdirectory1 PROPERTY BUILDSYSTEM_TARGETS)
message(STATUS "Targets in subdirectory1: ${targets1}")

get_property(targets2 DIRECTORY subdirectory2 PROPERTY BUILDSYSTEM_TARGETS)
message(STATUS "Targets in subdirectory2: ${targets2}")

このコードは次の出力を生成します。

Targets in subdirectory1: mytarget1
Targets in subdirectory2: mytarget2

例2: 特定のターゲットに依存する他のターゲットを特定する

この例では、mytarget という名前のターゲットに依存する他のターゲットを特定するCMakeコードを示します。

cmake_minimum_required(VERSION 3.7)

project(myproject)

add_executable(mytarget main.cpp)
add_executable(mytarget2 main2.cpp target_link_libraries(mytarget))

get_property(dependent_targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS)

foreach(target IN LISTS dependent_targets)
    if(NOT TARGET ${target} EQUAL mytarget)
        message(STATUS "Target ${target} depends on mytarget")
    endif()
endforeach()
Target mytarget2 depends on mytarget

例3: ディレクトリ内のターゲットを操作するカスタムCMakeロジックを作成する

この例では、サブディレクトリ内のすべてのターゲットに対してカスタムアクションを実行するCMakeコードを示します。

cmake_minimum_required(VERSION 3.7)

project(myproject)

add_subdirectory(subdirectory1)
add_subdirectory(subdirectory2)

function(process_target target)
    message(STATUS "Processing target: ${target}")
    # カスタムアクションをここに追加
    # 例:ターゲットのソースファイルをビルドディレクトリにコピーする
    file(COPY ${target}_sources ${CMAKE_BINARY_DIR}/src/${target})
endfunction()

get_property(targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS)

foreach(target IN LISTS targets)
    if(NOT TARGET ${target} EQUAL myproject)
        process_target(${target})
    endif()
endforeach()

このコードは、サブディレクトリ内のすべてのターゲットに対して次の出力を生成します。

Processing target: mytarget1
Processing target: mytarget2


CMakeの「Properties: Directories」における「BUILDSYSTEM_TARGETS」プロパティは、ディレクトリ内に add_library(), add_executable(), または add_custom_target() コマンドで追加されたビルドシステムターゲットのリストを保持します。しかし、このプロパティにはいくつかの制限があります。

  • インポートされたターゲットやエイリアスターゲットは含まれません。
  • 読み取り専用であるため、直接変更することはできません。

これらの制限により、特定の状況では「BUILDSYSTEM_TARGETS」プロパティが不十分な場合があります。そのような場合は、以下の代替方法を検討してください。

代替方法

  1. GLOB コマンドを使用する

GLOB コマンドを使用して、ディレクトリ内のすべてのターゲットファイル(CMakeLists.txt ファイルを含む)を検索できます。

glob(targets "*.cmake")

このコマンドは、targets 変数にターゲットファイルのパスを含むリストを格納します。その後、各ターゲットファイルに対して parse_cmake_lists() コマンドを使用して、ターゲットを抽出できます。

foreach(target_file IN LISTS targets)
    parse_cmake_lists(${target_file})
    get_property(target_names DIRECTORY ${target_file} PROPERTY TARGETS)
    foreach(target_name IN LISTS target_names)
        # ターゲット操作
    endforeach()
endforeach()

**2. CMAKE_TARGET_LIST_DIR 変数を使用する

CMAKE_TARGET_LIST_DIR 変数は、現在のディレクトリ内のターゲットのリストを保持します。この変数は、add_library(), add_executable(), または add_custom_target() コマンドが呼び出されるたびに更新されます。

message(STATUS "Targets in this directory: ${CMAKE_TARGET_LIST_DIR}")

この方法は、現在のディレクトリ内のターゲットのみを取得する場合に便利です。

**3. カスタムロジックを使用する

上記の方法が不十分な場合は、カスタムロジックを使用してディレクトリ内のターゲットを特定できます。これは、複雑なターゲット構造を持つプロジェクトの場合に役立ちます。

以下の例は、subdirectory という名前のサブディレクトリ内のすべてのターゲットを一覧表示するCMakeコードを示します。

cmake_minimum_required(VERSION 3.7)

project(myproject)

add_subdirectory(subdirectory)

function(get_targets directory)
    file(GLOB target_files "${directory}/*.cmake")
    foreach(target_file IN LISTS target_files)
        parse_cmake_lists(${target_file})
        get_property(target_names DIRECTORY ${target_file} PROPERTY TARGETS)
        foreach(target_name IN LISTS target_names)
            list(APPEND targets ${target_name})
        endforeach()
    endforeach()
endfunction()

get_targets(subdirectory)
message(STATUS "Targets in subdirectory: ${targets}")

このコードは、subdirectory サブディレクトリ内のすべてのターゲットを targets 変数に格納します。