CMake: 便利なコマンド・変数

  • 40
    いいね
  • 1
    コメント
この記事は最終更新日から1年以上が経過しています。

はじめに

みなさん、こんにちは。今回は CMake スクリプトを記述する上で便利なコマンドや変数について紹介していきます。

list()コマンド

リストの長さ取得や追加など、リスト操作の便利な機能を提供するコマンドです。CMake: リストで詳しく述べられています。

file()コマンド

file()コマンドは、各種ファイル操作やファイルの検索に加えて、ダウンロードやアップロード機能など様々な機能を提供します。よく使いそうな機能を下記に示します。

ファイル生成・削除と入出力

WRITE・APPEND

file(WRITE <filename> [<content1> ...])
file(APPEND <filename> [<content1> ...])

WRITEはファイル<filename>に指定した文字列<content1> ...を出力します。このとき、指定したファイルが存在しない場合は作成します。APPENDはファイル末尾への追加となります。

file(WRITE hoge.txt a b c) #[[
  $ cat hoge.txt
  abc
]]
file(APPEND hoge.txt a b c) #[[
  $ cat hoge.txt
  abcabc
]]

READ

file(READ <filename> <variable> [LIMIT <length>] [OFFSET <offset>] [HEX])

ファイル<filename>を変数<variable>に読み込みます。HEXオプションが付与されると16進表記のバイト列として読み込みます。また、読み込む範囲を<offset>..(<offset> + <length> - 1)で指定できます。

$ echo abc > hoge.txt
file(READ hoge.txt content) # abc
file(READ hoge.txt content HEX) # 616263
file(READ hoge.txt content LIMIT 2 OFFSET 1) # bc

MAKE_DIRECTORY

file(MAKE_DIRECTORY [<directory1> ...])

ディレクトリ<directory1> ...を作成します。

REMOVE・REMOVE_RECURSE

file(REMOVE [<file1> ...])
file(REMOVE_RECURSE [<file1> ...])

ファイル<file1> ...を削除します。ディレクトリを削除するためにはREMOVE_RECURSEを使用します。

ファイルの探索と取得

GLOB・GLOB_RECURSE

file(GLOB <variable> [RELATIVE <path>] [<globbing_expressions>]...)
file(GLOB_RECURSE <variable> [RELATIVE <path>]
     [FOLLOW_SYMLINKS] [<globbing_expressions>]...)

指定されたGLOBパターン<globbing_expressions>にマッチするファイルを探索し、その一覧をリストとして変数<variable>に格納します。このとき絶対パスで格納されますが、RELATIVE <path>が指定されていると、このパスからの相対パスとなります。add_executable()などに指定する依存ソースファイルの一覧を取得するのに使い、おそらくfile()コマンドの中でもっともよく使うことになるでしょう。以下の正規表現のメタ文字に似たものが使えます。

  • 任意の文字の0回以上の繰り返し*
  • 任意の文字?
  • ブラケット内で指定された文字[ ]とその範囲-
/path/to/
├── CMakeLists.txt
├── test1.txt
└── .txt
file(GLOB files *.txt)      # /path/to/CMakeListx.txt;/path/to/test1.txt;/path/to/.txt
file(GLOB files test1*.txt) # /path/to/test1.txt
file(GLOB files [t-z]*.txt) # /path/to/test1.txt
file(GLOB files test?.txt)  # /path/to/test1.txt

ファイル情報の取得

MD5・SHA1・SHA224・SHA256・SHA384・SHA512

file(<MD5|SHA1|SHA224|SHA256|SHA384|SHA512> <filename> <variable>)

指定のハッシュ関数により、ファイル<filename>のダイジェストを生成し、変数<variable>に出力します。

パスの変換

RELATIVE_PATH

file(RELATIVE_PATH <variable> <directory> <file>)

基準となるパス<directory>からの対象のパス<file>への相対パスを変数<variable>に格納します。

ファイルのダウンロード

DOWNLOAD

file(DOWNLOAD <url> file [INACTIVITY_TIMEOUT <timeout>]
     [TIMEOUT <timeout>] [STATUS <status>] [LOG <log>] [SHOW_PROGRESS]
     [EXPECTED_HASH ALGO=<value>] [EXPECTED_MD5 <sum>]
     [TLS_VERIFY on|off] [TLS_CAINFO <file>])

指定したURL<url>のリソースをファイル<file>にダウンロードします。外部プロジェクトやデータなどをダウンロードするのに使用するでしょう。


これ以外のコマンドについては、file — CMake 3.0.2 Documentation に記述されています。

get_filename_component()コマンド

get_filename_component(<variable> <path> <comp> [CACHE])

get_filename_component()コマンドはファイル名や拡張子、ディレクトリなど指定したパス<path>の構成要素<comp>を取得し、変数<variable>に格納します。指定できる構成要素は以下のとおりです。

  • ディレクトリのパスDIRECTORY
  • ファイル名NAME
  • 拡張子EXT
  • 拡張子を除いたファイル名NAME_WE
  • 絶対パスABSOLUTE
  • シンボリックリンクのリンク先の絶対パスREALPATH
/path/to/
├── script.cmake
└── script-alias.cmake -> script.cmake
get_filename_component(result "/path/to/script.cmake" DIRECTORY) # /path/to
get_filename_component(result "/path/to/script.cmake" NAME)      # script.cmake
get_filename_component(result "/path/to/script.cmake" EXT)       # .cmake
get_filename_component(result "/path/to/script.cmake" NAME_WE)   # script
get_filename_component(result "script.cmake" ABSOLUTE)           # /path/to/script.cmake
get_filename_component(result "script-alias.cmake" REALPATH)     # /path/to/script.cmake

configure_file()コマンド

configure_file(<input> <output>
               [COPYONLY] [ESCAPE_QUOTES] [@ONLY]
               [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])

configure_file()コマンドは、元となるファイルからファイルに埋め込まれた変数を展開し、新しいファイルを生成する、いわゆるテンプレートエンジンの機能を提供するコマンドです。

@osamu0329 さんの CMake:configure_fileコマンド で詳しく解説されています。

string()コマンド

string()コマンドは、各種文字列処理を行うためのコマンドです。よく使いそうな機能を下記に示します。

文字列の探索と置換

REGEX MATCH・REGEX MATCHALL

string(REGEX MATCH <regexp> <variable> <input1> [...])
string(REGEX MATCHALL <regexp> <variable> <input1> [...])

文字列<input1> ...が正規表現<regexp>にマッチするかを判定し、マッチした場合は、マッチした部分の文字列が変数<variable>に格納されます。REGEX MATCHでは最初にマッチした部分しか格納されませんが、REGEX MATCHALLではマッチした部分すべてがリストとして格納されます。

REGEX REPLACE・REPLACE

string(REGEX REPLACE <pattern> <replace> <variable> <input> [...])
string(REPLACE <pattern> <replace> <variable> <input> [...])

文字列inputでパターン<pattern>と一致した部分を文字列<replace>で置換します。REGEX REPLACEREPLACEの違いは正規表現が使えるかどうかです。また、REGEX REPLACEの場合、置換する文字列<replace>の中で\1の形で後方参照することができます。

SUBSTRING

string(SUBSTRING <string> <begin> <length> <variable>)

文字列<string>の中から<begin>..(<begin> + <length>)の範囲の文字列を変数<variable>に格納します。

文字列の情報取得

MD5・SHA1・SHA224・SHA256・SHA384・SHA512

string(<MD5|SHA1|SHA224|SHA256|SHA384|SHA512> <variable> <input>)

file(<MD5|SHA1|SHA224|SHA256|SHA384|SHA512>)と同じですが、こちらはファイルの内容ではなく、任意の文字列を指定します。

LENGTH

string(LENGTH <string> <variable>)

文字列<string>の長さを変数<variable>に格納します。

文字列の変換

STRIP

string(STRIP <string> <variable>)

文字列<string>の両端から空白文字を削除し、変数<variable>に格納します。

TOUPPER・TOLOWER

string(TOUPPER <string> <variable>)
string(TOLOWER <string> <variable>)

文字列<string>をすべて大文字/小文字にして、変数<variable>に格納します。

文字列の生成

CONFIGURE

string(CONFIGURE <string> <variable>
       [@ONLY] [ESCAPE_QUOTES])

configure_file()コマンドと同様の動作をしますが、こちらはファイルではなく任意の文字列<string>に対して処理を行い、その結果を変数<variable>に出力します。

RANDOM

string(RANDOM [LENGTH <length>] [ALPHABET <alphabet>]
       [RANDOM_SEED <seed>] <variable>)

乱数を生成し、変数<variable>に格納します。

TIMESTAMP

string(TIMESTAMP <variable> [<string>] [UTC])

ファイル<filename>のタイムスタンプを変数<variable>に出力します。通常はローカル時間(たとえばJST)ですが、UTCオプションを指定すると標準時間となります。また、<format>により、任意のフォーマットに変換できます。指定できるフォーマットは下記のとおりとなります。

  • 年(4桁)%Y
  • 年(2桁)%y
  • 月(01-12)%m
  • 日(01-31)%d
  • 日(001-336)%j
  • 週(00-53)%U
  • 曜日(0-6)%w
  • 時(00-24)%H
  • 時(00-12)%I
  • 分(00-59)%M
  • 秒(00-60)%S

これ以外のコマンドについては、string — CMake 3.0.2 Documentation に記述されています。

math()コマンド

math(EXPR <variable> <expr>)

math()コマンドは、四則演算やビット演算を行うコマンドです。<expr>に式を指定し、<variable>に出力される変数を指定します。math()コマンドでは、以下の演算が可能です。また、括弧()も使用できます。

  • 可算+
  • 減算-
  • 乗算*
  • 除算/
  • 剰余%
  • ビット和|
  • ビット積&
  • ビット排他的論理和^
  • 右シフト>>
  • 左シフト<<

注意点として、負の数を指定するとエラーになってしまうようです。また、ビット否定~が使えるはずですが、同じくエラーになってしまいます。

math(EXPR result "1 + 1")           # 2
math(EXPR result "1 - 5")           # -4
math(EXPR result "2 * 3")           # 6
math(EXPR result "2 * 3 + (2 + 4)") # 12
math(EXPR result "1 << 3")          # 8
math(EXPR result "8 >> 2")          # 2
math(EXPR result "12 % 10")         # 2
math(EXPR result "8 | 15")          # 15
math(EXPR result "8 & 15")          # 8

math(EXPR result "-1 + 2") # エラー
math(EXPR result "~1")     # エラー

execute_process()コマンド

execute_process(COMMAND <cmd1> [<arg1> ...]]
                [COMMAND <cmd2> [<arg2> ...] [...]]
                [WORKING_DIRECTORY <directory>]
                [TIMEOUT <seconds>]
                [RESULT_VARIABLE <variable>]
                [OUTPUT_VARIABLE <variable>]
                [ERROR_VARIABLE <variable>]
                [INPUT_FILE <file>]
                [OUTPUT_FILE <file>]
                [ERROR_FILE <file>]
                [OUTPUT_QUIET]
                [ERROR_QUIET]
                [OUTPUT_STRIP_TRAILING_WHITESPACE]
                [ERROR_STRIP_TRAILING_WHITESPACE])

execute_process()コマンドは、外部コマンドを実行するコマンドです。

set(build_dir ${CMAKE_CURRENT_LIST_DIR}/build)
file(MAKE_DIRECTORY ${build_dir})
execute_process(
  COMMAND ${CMAKE_COMMAND} ..
  WORKING_DIRECTORY ${build_dir}
)

cmake_host_system_information()コマンド

cmake_host_system_information(RESULT <variable> QUERY <key> ...)

cmake_host_system_information()とは、メモリ量やCPUのコア数、ホスト名などシステム情報を取得するコマンドです。QUERY <key> ...に取得したい情報を指定し、<variable>に出力する変数を指定します。指定できる情報には以下があります。なお、<key>を複数指定した場合は、対応する値がリストとして格納されます。

  • CPUの論理コア数NUMBER_OF_LOGICAL_CORES
  • CPUの物理コア数NUMBER_OF_PHYSICAL_CORES
  • ホスト名HOSTNAME
  • ドメイン名FQDN
  • 全仮想メモリ量TOTAL_VIRTUAL_MEMORY
  • 空き仮想メモリ量AVAILABLE_VIRTUAL_MEMORY
  • 全メモリ量TOTAL_PHYSICAL_MEMORY
  • 空きメモリ量AVAILABLE_PHYSICAL_MEMORY

中でもコア数を示すNUMBER_OF_LOGICAL_CORESNUMBER_OF_PHYSICAL_CORESは、makeコマンドやctestコマンドの並列数の指定によく使うでしょう。

cmake_host_system_information(RESULT cores QUERY NUMBER_OF_LOGICAL_CORES)
execute_process(COMMAND make -j ${cores})
execute_process(COMMAND ctest -j ${cores})

CMAKE_COMMAND・CMAKE_CTEST_COMMAND 変数

これらの変数は、cmakeコマンドやctestコマンドのフルパスを返します。

message("CMAKE_COMMAND: ${CMAKE_COMMAND}") # /usr/bin/cmake
message("CMAKE_CTEST_COMMAND: ${CMAKE_CTEST_COMMAND}") # /usr/bin/ctest

CMAKE_CURRENT_LIST_FILE・CMAKE_CURRENT_LIST_DIR 変数

これらの変数は、現在のCMakeスクリプトファイルのディレクトリ・パスを返します。スクリプトモードでよく使うでしょう。

message("CMAKE_CURRENT_LIST_FILE: ${CMAKE_CURRENT_LIST_FILE}") # /path/to/current.cmake
message("CMAKE_CURRENT_LIST_DIR: ${CMAKE_CURRENT_LIST_DIR}") # /path/to

おわりに

以上、CMake スクリプトで使う便利なコマンド・変数でした。これらのコマンドは必須ではありませんが、CMake スクリプトを書く上で便利に使用することができるでしょう。

明日は、mrk_21 さんの『CMake でのメタプログラミングとその応用』です。

この投稿は CMake Advent Calendar 201423日目の記事です。