はじめに
みなさん、こんにちは。今回はポリシーについて書いていきます。
ポリシーとはなにか?
ポリシーとは、互換性維持のために過去の挙動を保持する機構のことで、CMake 2.4 から導入されました。このポリシーには様々な種類があり、挙動ごとにCMP<NNNN>
という識別子が割り振られます。そして、それぞれ必要に応じて "古い挙動"を表すOLD
、"新しい挙動"を表すNEW
に設定されます。主な用途として、古いCMakeでしか動作しないプロジェクトを最新のCMakeで動かしたい場合に使用します。
以下、ポリシーの使用方法について述べていきます。
ポリシーの取得
ポリシーの取得には、cmake_policy(GET)
コマンドを使用します。
cmake_policy(GET <policy-id> <output-variable>)
<policy-id>
はポリシーの識別子CMP<NNNN>
を指定し、<output-variable>
には代入したい変数名を指定します。この変数にはOLD
もしくはNEW
が代入されますが、指定のバージョンで導入されていないポリシーを指定した場合は、空文字列が代入されます。
cmake_minimum_required(VERSION 3.0.2)
cmake_policy(GET CMP0007 behavior)
message("CMP0007: ${behavior}") # CMP0007: NEW
ポリシーの設定
ポリシーの設定方法には、以下に示す2種類があります。
個別に指定
ポリシーを個別に設定するには、cmake_policy(SET)
コマンドを使用します。
cmake_policy(SET <policy-id> <behavior>)
<policy-id>
はポリシーの識別子CMP<NNNN>
を指定し、<behavior>
には、OLD
もしくはNEW
を指定します。
cmake_minimum_required(VERSION 3.0.2)
cmake_policy(GET CMP0007 behavior)
message("CMP0007: ${behavior}") # CMP0007: NEW
cmake_policy(SET CMP0007 OLD)
cmake_policy(GET CMP0007 behavior)
message("CMP0007: ${behavior}") # CMP0007: OLD
CMake のバージョンで指定
cmake_policy(VERSION)
コマンドを使用すると、CMake のバージョンにもとづいて一括で設定できます。
cmake_policy(VERSION <cmake-version>)
<cmake-version>
にはCMakeのバージョンをmajor[.minor[.patch[.tweak]]]
というフォーマットで指定します。そうすると、指定したバージョンまでに導入されたすべてのポリシーがNEW
に設定されます(導入されていないポリシーには空文字列が設定されます)。
cmake_minimum_required(VERSION 3.0.2)
cmake_policy(GET CMP0007 cmp0007_behavior)
cmake_policy(GET CMP0050 cmp0050_behavior)
message("CMP0007: ${cmp0007_behavior}") # CMP0007: NEW
message("CMP0050: ${cmp0050_behavior}") # CMP0050: NEW
cmake_policy(VERSION 2.8)
cmake_policy(GET CMP0007 cmp0007_behavior)
cmake_policy(GET CMP0050 cmp0050_behavior)
message("CMP0007: ${cmp0007_behavior}") # CMP0007: NEW
message("CMP0050: ${cmp0050_behavior}") # CMP0050:
また、このコマンドは CMake スクリプトの動作する下限バージョンを指定するcmake_minimum_required(VERSION)
コマンド内部でも呼び出されます。このコマンドを使用すると、指定したバージョンがCMAKE_MINIMUM_REQUIRED_VERSION
変数に設定されるので、こちらの方が使い勝手が良いかもしれません。
ポリシーのデフォルト値
ポリシーはCMAKE_POLICY_DEFAULT_CMP<NNNN>
キャッシュ変数を用いて、デフォルト値を設定することができます。たとえば、ポリシーCMP0050
は CMake 3.0 から導入されたポリシーなので、CMake 2.8 で動作させても、新しい挙動で動作しません。しかし、キャッシュ変数CMAKE_POLICY_DEFAULT_CMP0050
をNEW
に設定すると、CMake 2.8 でも新しい挙動で動作するようになります。
set(CMAKE_POLICY_DEFAULT_CMP0050 NEW CACHE STRING "" FORCE)
cmake_minimum_required(VERSION 2.8)
cmake_policy(GET CMP0050 current_behavior)
message("CMP0050: ${current_behavior}") # CMP0050: NEW
unset(CMAKE_POLICY_DEFAULT_CMP0050 CACHE)
cmake_minimum_required(VERSION 2.8)
cmake_policy(GET CMP0050 current_behavior)
message("CMP0050: ${current_behavior}") # CMP0050:
このCMAKE_POLICY_DEFAULT_CMP<NNNN>
キャッシュ変数は、コマンドラインにて設定することが強く奨励されているので、通常は以下のように-D
オプションを用いて、コマンドラインから設定することになります。
$ cmake -DCMAKE_POLICY_DEFAULT_CMP0050=NEW .
ポリシーが存在しているかどうか
ポリシーの取得・設定には、cmake_policy(GET)
コマンド、およびcmake_policy(SET)
コマンドを用いますが、存在しないポリシーを指定するとエラーになってしまいます。
こんなときは、CMake: 条件分岐 で示した、if(POLICY)
コマンドを使用することで、存在するときのみに処理を実行することができます。
if(POLICY CMP0100)
cmake_policy(SET CMP0100 NEW)
endif()
ポリシーのスコープ
ポリシーはcmake_policy(PUSH)
コマンドおよびcmake_policy(POP)
コマンドを用いてスコープを生成することができます。これによって、ポリシーの変更による影響を最小限度に抑えることができます。また、これらのコマンドは対になっていなければなりません。
ポリシーのスコープは、変数のスコープと同様に親スコープから設定を引き継ぎ、子スコープでのポリシーの変更が親スコープに影響することはありません。
cmake_minimum_required(VERSION 3.0.2)
cmake_policy(GET CMP0050 current_behavior)
message("CMP0050: ${current_behavior}") # CMP0050: NEW
cmake_policy(PUSH)
cmake_policy(SET CMP0050 OLD)
cmake_policy(GET CMP0050 current_behavior)
message("CMP0050: ${current_behavior}") # CMP0050: OLD
cmake_policy(POP)
cmake_policy(GET CMP0050 current_behavior)
message("CMP0050: ${current_behavior}") # CMP0050: NEW
また、include()
コマンドとfind_package()
コマンドは、自動的にスコープを生成するので、呼び出し元のポリシーが変更されることはありません。しかし、NO_POLICY_SCOPE
オプションをこれらのコマンドに付与すると、スコープの生成を抑制することができます。これによって、呼び出し元のポリシーの設定を変更することが目的のモジュールを作成することができます。
コマンド定義におけるポリシー
function()
やmacro()
といったコマンド定義を行うコマンドでは、コマンド定義時のポリシーの設定を保持するので注意が必要です。
cmake_minimum_required(VERSION 3.0.2)
function(display_cmp0007_behavior)
cmake_policy(GET CMP0007 current_behavior)
message("CMP0007: ${current_behavior}")
endfunction()
display_cmp0007_behavior() # CMP0007: NEW
cmake_policy(SET CMP0007 OLD)
display_cmp0007_behavior() # CMP0007: NEW
ポリシーの種類と例
CMake 3.0.2 現在CMP0000
からCMP0050
までの51種類のポリシーがあり、cmake-policies(7) — CMake 3.0.2 Documentation, All Policies にその一覧があります。
大量のポリシーがありますが、一例としてCMP0007
を見てみましょう。このポリシーではlist()
コマンドの挙動を管理しています。list()
コマンドは、古い挙動ではリストの空要素を認識しませんが、新しい挙動では空要素を認識します。
function(verify_cmp0007 behavior)
cmake_policy(SET CMP0007 ${behavior})
cmake_policy(GET CMP0007 current_behavior)
message("CMP0007: ${current_behavior}")
set(list_value "a;b;;c")
list(LENGTH list_value length)
message("list: ${list_value}")
message("length: ${length}")
message("")
endfunction()
verify_cmp0007(OLD) #[[
CMP0007: OLD
list: a;b;;c
length: 3
]]
verify_cmp0007(NEW) #[[
CMP0007: NEW
list: a;b;;c
length: 4
]]
おわりに
以上、ポリシーでした。外部ライブラリの CMake スクリプトを自分のプロジェクトの CMakeスクリプトで使用するときに活躍するでしょう。
明日は、mrk_21 さんの『CMake: スクリプトモード』です。