Posted at
CMakeDay 10

CMake: キャッシュ変数と環境変数

More than 3 years have passed since last update.


はじめに

みなさん、こんにちは。CMakeの変数には、いままで使用してきたものの他に、キャッシュ変数と環境変数というものが存在します。今回は、これらについて書いていきます。


キャッシュ変数

キャッシュ変数とは、文字通りキャッシュされた変数のことで、値がキャッシュファイルに保存されています。そのため、キャッシュファイルが削除されるまで存在し続けます。主な用途として、使用するコンパイラや、依存ライブラリのパスなどの格納です。これらは、CMakeの実行毎に設定する必要はないので、キャッシュ変数を用いて永続化します。また、キャッシュ変数は、通常の変数と違って、スクリプトのどこからでも参照・設定ができます。

このキャッシュ変数の操作方法は以下のようになっています。


生成・代入

キャッシュ変数の生成や代入には、set()コマンドのCACHEオプションを用います。

set(<variable> <value> [...] CACHE <type> <docstring> [FORCE])

変数名<variable>および値<value> ...の指定に関しては、通常の変数と同様ですが、その直後にキャッシュ変数であることを示すCACHEオプション、キャッシュ変数の種類<type>、説明用テキスト<docstring>が必要になります。キャッシュ変数の種類<type>および説明用テキスト<docstring>は、キャッシュファイル編集ツールであるcmake-guiccmakeのためのもので、変数の性質に関与するものではありません。キャッシュ変数の種類<type>は編集用のフォームを生成するためのヒント情報で、説明用テキスト<docstring>はそのラベルとなります。キャッシュ変数の種類<type>は以下の値をとります。


生成されるフォーム

FILEPATH
ファイル選択ダイアログ

PATH
ディレクトリ選択ダイアログ

STRING
入力フォーム

BOOL
ON/OFFスイッチ

INTERNAL
フォームなし

上記のように、指定しなければいけない値が多い、という以外にも、キャッシュ変数には普通の変数にはない特徴をもっています。その一つが生成はできるが変更はできない、というものです。たとえば以下の例を見てください。

set(cache_value 1 CACHE STRING description)

message("cache_value: ${cache_value}") # cache_value: 1

set(cache_value 2 CACHE STRING description)
message("cache_value: ${cache_value}") # cache_value: 1

上記において、2回目のset()ではキャッシュ変数cache_value2を代入しているにもかかわらず、値は1のままです。おそらく、ユーザーがcmake-guiなどのツールで編集した値を、CMakeが勝手に上書きしないためだと思われます。

ですが、時には強制的に上書きしたいときもあります。この場合は、set()コマンドにFORCEオプションを付与することによりこれが可能になります。

set(cache_value 1 CACHE STRING description)

message("cache_value: ${cache_value}") # cache_value: 1

set(cache_value 2 CACHE STRING description FORCE)
message("cache_value: ${cache_value}") # cache_value: 2

さきほどの例とは異なり、2回目のset()で代入した値が、実際にセットされています。

しかし、変数の種類がINTERNALである場合に限り、上のルールは適用されません。FORCEオプションを付与しなくても変更することができます。

set(cache_value 1 CACHE INTERNAL description)

message("cache_value: ${cache_value}") # cache_value: 1

set(cache_value 2 CACHE INTERNAL description)
message("cache_value: ${cache_value}") # cache_value: 2

これは、変数の種類がINTERNALの場合は、FORCEオプションが暗黙的に付与されているからです。このタイプのキャッシュ変数は、cmake-guiなどのツールでは表示されないので、上書きしないように保護する必要がないからだと思われます。


削除

キャッシュ変数の削除には、unset()コマンドにset()コマンドのときと同様にCACHEオプションを付与することで行えます。

unset(<variable> CACHE)

CACHEオプションがついている以外は普通の変数のときと同じように使用できます。


参照

キャッシュ変数の参照には、通常の変数と同様の${}を使う方法と、$CACHE{}の2種類があります。

set(cache_value 1 CACHE STRING description)

message("\${cache_value}: ${cache_value}") # ${cache_value}: 1
message("\$CACHE{cache_value}: $CACHE{cache_value}") # $CACHE{cache_value}: 1

これらは、基本的に同じ動作を行いますが、キャッシュ変数と同名の通常の変数が存在したときの動作が異なります。この場合、通常の変数と同様の形式、${}を用いたときは、キャッシュ変数ではなく通常の変数の値を参照します。

set(cache_value 1 CACHE STRING description)

set(cache_value 2)
message("\${cache_value}: ${cache_value}") # ${cache_value}: 2
message("\$CACHE{cache_value}: $CACHE{cache_value}") # $CACHE{cache_value}: 1

しかし、その後再度キャッシュ変数をset()すると、この同名の通常の変数は削除され、再びキャッシュ変数が参照できるようになります。このときに、種類がINTERNALでないのなら、FORCEオプションを付与しなければならないことに注意してください。

set(cache_value 1 CACHE STRING description)

set(cache_value 2)
message("\${cache_value}: ${cache_value}") # ${cache_value}: 2
message("\$CACHE{cache_value}: $CACHE{cache_value}") # $CACHE{cache_value}: 1

set(cache_value 1 CACHE STRING description FORCE)
message("\${cache_value}: ${cache_value}") # ${cache_value}: 1
message("\$CACHE{cache_value}: $CACHE{cache_value}") # $CACHE{cache_value}: 1

この規則は複雑ですが、いくつかの例で役に立ちます。たとえば、コンパイラオプションのキャッシュ変数の値を、あるサブディレクトリで違うものに上書きしたい場合です。キャッシュ変数はどこからでも変更できるので、サブディレクトリでの値の変更はすべてのディレクトリに影響します。これを回避するために同名の通常の変数に上書きしたい値をセットし、${}の形で参照することによって、値を上書きしつつも影響をサブディレクトリ内に留めることが可能となります。


CMakeLists

set(CMAKE_CXX_FLAGS "-std=gnu++14 -stdlib=libc++ -Wall -Wextra" CACHE STRING

[[Flags used by the compiler during all build types.]] FORCE)

message("CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}") # -std=gnu++14 -stdlib=libc++ -Wall -Wextra
add_subdirectory(subdir)
message("CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}") # -std=gnu++14 -stdlib=libc++ -Wall -Wextra



subdir/CMakeLists

set(CMAKE_CXX_FLAGS "$CACHE{CMAKE_CXX_FLAGS} -Wno-unused-parameter")

message("CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}") # -std=gnu++14 -stdlib=libc++ -Wall -Wextra -Wno-unused-parameter


環境変数

CMakeは、OSの環境変数の参照と設定も行うことができます。キャッシュ変数同様に、どこからでも参照・設定ができます。

環境変数の操作は以下のようになっています。


生成・代入

環境変数の生成・代入は、キャッシュ変数の時とは違い通常の変数と同じように行います。ただし、変数名の指定にはENV{}という形式でなければなりません。

set(ENV{<variable>} <value> [...])


削除

環境変数の削除も通常の変数同様に行います。ここでも変数名の指定にはENV{}としなければなりません。

unset(ENV{<variable>})


参照

環境変数の参照には、$ENV{}を使用します。

set(ENV{PATH} /usr/local/bin)

message("PATH: $ENV{PATH}") # /usr/local/bin


おわりに

以上、キャッシュ変数と環境変数でした。キャッシュ変数の規則はなかなか複雑なので注意する必要があります。

明日は、osamu0329 さんの『out-of-sourceビルドについて』です。