CMakeポリシーCMP0040: add_custom_command() のターゲット制御


CMakeポリシー CMP0040 は、add_custom_command() コマンドの TARGET シグネチャで指定されたターゲットに関する動作を制御します。このポリシーは、CMake バージョン 3.0 で導入されました。

旧動作 (CMake 2.8.12 以下)

  • 対象ターゲットが存在しない、または現在のディレクトリ外で定義されている場合、add_custom_command() は警告なしに無視していました。

新動作 (CMake 3.0 以降)

  • 対象ターゲットが存在しない、または現在のディレクトリ外で定義されている場合、add_custom_command() はエラーを報告します。

影響

このポリシー変更は、add_custom_command() を使用してターゲットにカスタムコマンドを関連付ける既存の CMake プロジェクトに影響を与える可能性があります。

対処

以下のいずれかの方法でこのポリシー変更に対処できます。

  1. 対象ターゲットが存在することを確認する

    add_custom_command() を使用する前に、対象ターゲットが存在し、現在のディレクトリで定義されていることを確認してください。

  2. CMakeポリシーを設定する

    cmake_policy コマンドを使用して、このポリシーの動作を明示的に設定できます。

    cmake_policy(SET CMP0040 OLD)
    

    これにより、CMake は旧動作を使用し、ターゲットが存在しない場合でもカスタムコマンドを無視します。

  3. CMake バージョンをアップグレードする

    CMake 3.2.3 以降を使用している場合は、このポリシー変更に関する警告が表示されます。警告を回避するには、CMake を最新バージョンにアップグレードしてください。

以下の例は、CMP0040 ポリシーが設定されている場合にエラーを報告するCMake スクリプトを示しています。

cmake_minimum_required(VERSION 3.0)

project(myproject)

add_custom_command(TARGET mytarget
                   COMMAND ${CMAKE_COMMAND} -E message "Hello, world!")

message(FATAL_ERROR "This will cause an error due to CMP0040")

このスクリプトを実行すると、以下のエラーが表示されます。

CMake Error at CMakeLists.txt:8:
  Target 'mytarget' is not defined in the current directory.
  • ポリシーを変更する前に、潜在的な影響を評価することが重要です。
  • このポリシーは、CMake のビルドシステムの整合性と信頼性を向上させるために導入されました。


cmake_minimum_required(VERSION 3.0)

project(myproject)

add_executable(mytarget mytarget.cpp)

add_custom_command(TARGET mytarget
                   COMMAND ${CMAKE_COMMAND} -E message "Hello, world!")

このスクリプトでは、add_executable() コマンドを使用して mytarget という名前のターゲットをまず定義します。その後、add_custom_command() コマンドを使用して、そのターゲットにカスタムコマンドを関連付けます。このカスタムコマンドは、CMake_COMMAND 変数を使用して Hello, world! というメッセージを出力します。

例2: CMakeポリシーを設定する

以下の例は、cmake_policy コマンドを使用して CMP0040 ポリシーの動作を明示的に設定する方法を示しています。

cmake_minimum_required(VERSION 3.0)

project(myproject)

cmake_policy(SET CMP0040 OLD)

add_custom_command(TARGET mytarget
                   COMMAND ${CMAKE_COMMAND} -E message "Hello, world!")

このスクリプトでは、cmake_policy() コマンドを使用して CMP0040 ポリシーを OLD に設定します。これにより、CMake は旧動作を使用し、ターゲットが存在しない場合でもカスタムコマンドを無視します。

例3: CMake バージョンをアップグレードする

以下の例は、CMake バージョンをアップグレードして CMP0040 ポリシーに関する警告を回避する方法を示しています。

# CMake 3.2.3 以下を使用している場合

curl -LO https://mirrors.ustc.edu.cn/cmake/files/release/latest/cmake-linux-x86_64.tar.gz
tar -xf cmake-linux-x86_64.tar.gz
export PATH=/path/to/new/cmake/bin:$PATH

# CMake 3.2.3 以降を使用している場合

cmake --version

この例では、まず最新の CMake バイナリファイルをダウンロードして解凍します。その後、PATH 環境変数に新しい CMake バイナリディレクトリを追加します。最後に、cmake --version コマンドを実行して、インストールされた CMake バージョンを確認します。

  • 実際の使用例では、より複雑なロジックや条件処理が必要になる場合があります。
  • これらの例は、CMP0040 ポリシーに関連する基本的なシナリオのみを示しています。


代替方法

CMP0040 ポリシーの変更に対処するには、以下の代替方法を検討することができます。

ターゲットの存在を確認する

add_custom_command() を使用する前に、対象ターゲットが存在し、現在のディレクトリで定義されていることを確認する最も簡単な方法は、以下のコードを使用することです。

if(TARGET ${TARGET})
  add_custom_command(TARGET ${TARGET}
                     COMMAND ${CMAKE_COMMAND} -E message "Hello, world!")
else()
  message(WARNING "Target '${TARGET}' does not exist or is defined outside the current directory.")
endif()

このコードは、TARGET 変数の値を使用してターゲットが存在するかどうかを確認します。ターゲットが存在する場合、add_custom_command() コマンドを使用してそのターゲットにカスタムコマンドを関連付けます。ターゲットが存在しない場合、警告メッセージが表示されます。

CMAKE_CURRENT_TARGET 変数を使用する

CMAKE_CURRENT_TARGET 変数は、現在処理されているターゲットを参照します。この変数を使用して、add_custom_command() コマンドにターゲットを渡すことができます。

add_custom_command(TARGET ${CMAKE_CURRENT_TARGET}
                   COMMAND ${CMAKE_COMMAND} -E message "Hello, world!")

このコードは、CMAKE_CURRENT_TARGET 変数の値を使用して、add_custom_command() コマンドに現在のターゲットを渡します。

カスタムコマンドを add_executable() または add_library() コマンド内で定義する

add_executable() または add_library() コマンドは、ターゲットにカスタムコマンドを関連付けるための別の方法を提供します。

add_executable(mytarget mytarget.cpp)

add_custom_command(COMMAND ${CMAKE_COMMAND} -E message "Hello, world!")
target_link_libraries(mytarget custom_command)

この例では、add_executable() コマンドを使用して mytarget という名前のターゲットを定義します。その後、add_custom_command() コマンドを使用してカスタムコマンドを定義します。最後に、target_link_libraries() コマンドを使用して、カスタムコマンドをターゲットにリンクします。

CMakeLists.txt スクリプトを修正する

CMP0040 ポリシー変更の影響を受けている既存の CMakeLists.txt スクリプトを修正することもできます。

  • 具体的な状況に応じて、最適な代替方法を選択してください。
  • 上記の代替方法は、それぞれ異なる動作と利点があります。