さよなら迷い道! CMake ポリシー CMP0021 で INCLUDE_DIRECTORIES の相対パスをスッキリ解決


CMakeポリシーCMP0021は、INCLUDE_DIRECTORIES ターゲットプロパティにおける相対パスの処理方法を制御します。このポリシーは、CMake 2.8 で導入され、CMake 3.29.4 以降では動作が変更されました。

旧動作(CMake 2.8 ~ 3.29.3)

このポリシーが設定されていない場合、または OLD に設定されている場合、CMake は INCLUDE_DIRECTORIES ターゲットプロパティで指定された相対パスを、プロジェクトディレクトリを基準とした相対パスとして解釈します。

例:

target_include_directories(mytarget PRIVATE include)

上記の例では、mytarget ターゲットは project_directory/include ディレクトリにあるヘッダーファイルにアクセスできます。

新動作(CMake 3.29.4 以降)

このポリシーが NEW に設定されている場合、CMake は INCLUDE_DIRECTORIES ターゲットプロパティで指定された相対パスを、ソースファイルの親ディレクトリを基準とした相対パスとして解釈します。

target_include_directories(mytarget PRIVATE include)

上記の例では、mytarget ターゲットは、ソースファイルの親ディレクトリにある include ディレクトリにあるヘッダーファイルにアクセスできます。

変更の理由

この変更は、CMake の動作をより一貫性のあるものにし、予期せぬ動作を防ぐために行われました。相対パスをソースファイルの親ディレクトリを基準として解釈することで、異なるディレクトリ構造を持つプロジェクト間で移植性を向上させることができます。

影響を受けるプロジェクト

このポリシーの変更は、INCLUDE_DIRECTORIES ターゲットプロパティで相対パスを使用しているプロジェクトに影響を与えます。影響を受けるプロジェクトを修正するには、以下のいずれかの方法を実行する必要があります。

  • ソースファイルの親ディレクトリにある include ディレクトリにヘッダーファイルを移動します。
  • INCLUDE_DIRECTORIES ターゲットプロパティで絶対パスを使用します。
  • cmake_policy コマンドを使用してポリシーを NEW に設定します。

推奨事項

将来的に互換性を保つために、cmake_policy コマンドを使用してポリシーを NEW に設定することをお勧めします。

  • このポリシーの旧動作は、将来の CMake バージョンで非推奨となり、削除される可能性があります。
  • このポリシーは、CMake 3.16.3 以降で警告を発し、設定されていない場合は旧動作を使用します。


# CMakeLists.txt

cmake_minimum_required(VERSION 3.0)

project(myproject)

target_include_directories(mytarget PRIVATE include)

add_executable(myprogram main.cpp)
target_link_libraries(myprogram mytarget)

新動作の例

# CMakeLists.txt

cmake_minimum_required(VERSION 3.29.4)

project(myproject)

cmake_policy(CMP0021 NEW)

target_include_directories(mytarget PRIVATE include)

add_executable(myprogram main.cpp)
target_link_libraries(myprogram mytarget)

上記の例では、mytarget ターゲットは、ソースファイル main.cpp の親ディレクトリにある include ディレクトリにあるヘッダーファイルにアクセスできます。

絶対パスを使用する例

# CMakeLists.txt

cmake_minimum_required(VERSION 3.0)

project(myproject)

target_include_directories(mytarget PRIVATE /path/to/include)

add_executable(myprogram main.cpp)
target_link_libraries(myprogram mytarget)

上記の例では、mytarget ターゲットは /path/to/include ディレクトリにあるヘッダーファイルにアクセスできます。

ヘッダーファイルを移動する例

# project_directory/src/main.cpp

#include "include/myheader.h"

int main() {
  // ...
}
# project_directory/include/myheader.h

// ...

上記の例では、mytarget ターゲットは project_directory/src ディレクトリにある include ディレクトリにあるヘッダーファイル myheader.h にアクセスできます。



cmake_policy コマンドを使用する

cmake_policy コマンドを使用して、ポリシーを NEW に設定することで、CMake が相対パスをソースファイルの親ディレクトリを基準として解釈するようにすることができます。

cmake_policy(CMP0021 NEW)

この方法は、最も簡単で、将来の CMake バージョンとの互換性を保つことができます。

INCLUDE_DIRECTORIES ターゲットプロパティで絶対パスを使用する

INCLUDE_DIRECTORIES ターゲットプロパティで絶対パスを使用することで、CMake が相対パスの解釈方法に左右されないようにすることができます。

target_include_directories(mytarget PRIVATE /path/to/include)

この方法は、常に確実に動作しますが、プロジェクトの移植性を低くする可能性があります。

ソースファイルの親ディレクトリにある include ディレクトリにヘッダーファイルを移動する

ソースファイルの親ディレクトリにある include ディレクトリにヘッダーファイルを移動することで、CMake が相対パスを正しく解釈できるようにすることができます。

# project_directory/src/main.cpp

#include "include/myheader.h"

int main() {
  // ...
}
# project_directory/include/myheader.h

// ...

この方法は、プロジェクトの構造を変更する必要があり、すべてのヘッダーファイルがソースファイルの親ディレクトリにある include ディレクトリにあることを確認する必要があります。

サードパーティのライブラリを使用する

add_subdirectory コマンドを使用してサードパーティのライブラリを追加する場合、CMake はそのライブラリの include ディレクトリを自動的に検索します。この場合、CMP0021 ポリシーの影響を受けません。

add_subdirectory(thirdparty_lib)

この方法は、サードパーティのライブラリを使用している場合に有効です。

カスタム CMake モジュールを使用する

カスタム CMake モジュールを作成して、INCLUDE_DIRECTORIES ターゲットプロパティで指定された相対パスを処理することができます。このモジュールは、ソースファイルの親ディレクトリを基準とした相対パスを解釈するように設計することができます。

この方法は、高度な制御が必要な場合に有効ですが、複雑でメンテナンスが困難になる可能性があります。

最適な代替方法の選択

最適な代替方法は、プロジェクトの要件と状況によって異なります。一般的には、cmake_policy コマンドを使用するのが最も簡単で、将来の CMake バージョンとの互換性を保つことができます。

  • CMake の将来のバージョでは、CMP0021 ポリシーの動作がさらに変更される可能性があります。
  • プロジェクトが他のプロジェクトに依存している場合は、依存プロジェクトもポリシー設定を一致させる必要があります。
  • プロジェクトに複数の CMakeLists.txt ファイルがある場合は、すべてのファイルでポリシー設定を一致させる必要があります。