Posted at
CMakeDay 17

CMake: モジュール

More than 3 years have passed since last update.


はじめに

みなさん、こんにちは。今回はモジュールについて書いていきます。


モジュールとは何か?

モジュールとは、定義したコマンドなどを複数のスクリプトで再利用するためのもので、include()コマンドやfind_package()コマンドなどで読み込まれます。


/path/to/module.cmake

function(func)

message(func)
endfunction()

include(/path/to/module.cmake)

func() # func

また、モジュール内の各コマンドは読み込み元の文脈で評価されるので、モジュール内での変数の設定は読み込み元に影響します。


/path/to/module.cmake

set(value 2)


set(value 1)

message("value: ${value}") # value: 1
include(/path/to/module.cmake)
message("value: ${value}") # value: 2


include() コマンド

モジュールを読み込む方法はいくつかありますが、本エントリーではinclude()コマンドについて述べます。

include()コマンドとはモジュールを読み込む基本的な方法で、定義は以下となります。


include(<file|module> [OPTIONAL] [RESULT_VARIABLE <VAR>]

[NO_POLICY_SCOPE])

include — CMake 3.0.2 Documentation



モジュールの指定

使用するモジュールの指定は<file|module>引数で行いますが、これには以下の2つの方法があります。


絶対パスで指定

モジュールのファイルへの絶対パスで指定する方法です。

include(/path/to/module.cmake)


モジュール名で指定

モジュール名で指定する方法です。モジュール名とは、変数(もしくはキャッシュ変数)CMAKE_MODULE_PATHに登録されているパスからモジュールへの相対パスで、拡張子.cmakeを除去したものです。

set(CMAKE_MODULE_PATH /path/to)

include(module)

set(CMAKE_MODULE_PATH /path)
include(to/module)

また、変数CMAKE_MODULE_PATHには複数のパスをリストとして設定することが可能です。この場合、リストの先頭から線形探索していき、最初に見つかったモジュールをロードします。

# /path/to

# ├── module.cmake
# └── dir
# └── module.cmake

set(CMAKE_MODULE_PATH /path/to /path/to/dir)
include(module) # /path/to/module.cmake
include(dir/module) # /path/to/dir/module.cmake

set(CMAKE_MODULE_PATH /path/to/dir /path/to)
include(module) # /path/to/dir/module.cmake
include(dir/module) # /path/to/dir/module.cmake

ここで注意したいのは、CMake が提供している標準モジュールは最後に探索されるということです。つまり、標準モジュールと同名のモジュールがCMAKE_MODULE_PATHの中に存在する場合、その標準モジュールは隠蔽されてしまいます。

# /path/to

# └── Documentation.cmake

include(Documentation) # 標準ライブラリ Documentation

set(CMAKE_MODULE_PATH /path/to)
include(Documentation) # /path/to/Documentation.cmake


OPTIONAL オプション

OPTIONALオプションを付与すると、モジュールが見つからない場合でもエラーになりません。

include(/not/existing/module.cmake) # エラー

include(/not/existing/module.cmake OPTIONAL) # OK


RESULT_VARIABLE オプション

RESULT_VARIABLEオプションを付与すると、ロードしたモジュールの絶対パスが指定の変数に設定されます。

set(CMAKE_MODULE_PATH /path/to)

include(module RESULT_VARIABLE module_path)
message("module_path: ${module_path}") # module_path: /path/to/module.cmake

また、OPTIONALオプションも付与し、かつ指定したモジュールが見つからない場合には、指定の変数にNOTFOUNDが設定されます。

include(/not/existing/module.cmake OPTIONAL RESULT_VARIABLE module_path)

message("module_path: ${module_path}") # module_path: NOTFOUND


NO_POLICY_SCOPE オプション

include()コマンドは、ポリシースコープを生成するので、モジュール内でのポリシーの設定が呼び出し元に影響することはありません。


/path/to/module.cmake

cmake_policy(GET CMP0007 cmp0007_behavior)

message("cmp0007_behavior: ${cmp0007_behavior}")

cmake_policy(SET CMP0007 OLD)

cmake_policy(GET CMP0007 cmp0007_behavior)
message("cmp0007_behavior: ${cmp0007_behavior}")


cmake_policy(GET CMP0007 cmp0007_behavior)

message("cmp0007_behavior: ${cmp0007_behavior}") # cmp0007_behavior: NEW

include(/path/to/module.cmake) #[[
cmp0007_behavior: NEW
cmp0007_behavior: OLD
]]

cmake_policy(GET CMP0007 cmp0007_behavior)
message("cmp0007_behavior: ${cmp0007_behavior}") # cmp0007_behavior: NEW

しかし、NO_POLICY_SCOPEオプションを付与すると、ポリシースコープを生成しなくなるので、モジュール内でのポリシーの設定が呼び出し元に影響します。

cmake_policy(GET CMP0007 cmp0007_behavior)

message("cmp0007_behavior: ${cmp0007_behavior}") # cmp0007_behavior: NEW

include(/path/to/module.cmake NO_POLICY_SCOPE) #[[
cmp0007_behavior: NEW
cmp0007_behavior: OLD
]]

cmake_policy(GET CMP0007 cmp0007_behavior)
message("cmp0007_behavior: ${cmp0007_behavior}") # cmp0007_behavior: OLD

このオプションは、ポリシーの設定を目的とするモジュールをロードするときに必要となるでしょう。


なお、include()コマンドは同じモジュールを何回でも読み込むことに注意してください。


/path/to/module.cmake

set(value 1)

message(module)

include(/path/to/module.cmake) # module

message("value: ${value}") # value: 1
set(value 2)
message("value: ${value}") # value: 2

include(/path/to/module.cmake) # module
message("value: ${value}") # value: 1


モジュールの種類

モジュールには、自分や第三者が作成したものの他に、CMake が標準で提供しているものが多数あります。この標準モジュールの詳細は、cmake-modules(7) にあります。


おわりに

以上、モジュールでした。よく使う共通の処理をモジュールとしておくことで、コードを再利用することができます。

明日は、mrk_21 さんの『CMake: Generator Expressions』です。