CMakeの構文調べてみた


https://cmake.org/cmake/help/v3.0/manual/cmake-language.7.html#grammar-token-newline
で、CMakeの構文しらべてみたのでメモ。

全体の構文

file         ::=  file_element*
file_element ::=  command_invocation line_ending |
                  (bracket_comment|space)* line_ending
line_ending  ::=  line_comment? newline
space        ::=  <match '[ \t]+'>
newline      ::=  <match '\n'>
  • fileは、file_elementの繰り返し
  • file_elementは下記のいずれか
    • コマンド呼び出し+ line_ending
    • bracket_commentと空白の任意の繰り返し + line_ending
  • line_endingは、行コメント`` + 改行

ざっくりまとめると コメント以外はコマンド呼び出しですよということ。
条件分岐もif()else()のように全てコマンド呼び出しの形となっている。

コマンド呼び出しの構文

command_invocation  ::=  space* identifier space* '(' arguments ')'
identifier          ::=  <match '[A-Za-z_][A-Za-z0-9_]*'>
arguments           ::=  argument? separated_arguments*
separated_arguments ::=  separation+ argument? |
                         separation* '(' arguments ')'
separation          ::=  space | line_ending

コマンド呼び出しは下記の形

  • コマンド名(引数) の形。(hoge(arg)の形)。
  • コマンド名の前後に空白が入っていてもよい。
  • コマンド名の先頭はアルファベット or アンダーバー。2文字目以降は数字でもOK。
  • 引数無しも可。
  • 引数は複数でも可。
  • 複数の引数の間は、空白または改行で区切られる。
  • 引数はネストして()で囲われている場合もある

コマンドの引数

argument ::= bracket_argument | quoted_argument | unquoted_argument

コマンドの引数には

  • bracket引数
  • quated引数
  • unquated引数

の3種類がある。

bracket引数

bracket_argument ::=  bracket_open bracket_content bracket_close
bracket_open     ::=  '[' '='{len} '['
bracket_content  ::=  <any text not containing a bracket_close
                       of the same {len} as the bracket_open>
bracket_close    ::=  ']' '='{len} ']'
  • ブラケット引数は、[[bracket_content]] もしくは[=[bracket_content]=] もしくは [==[bracket_content]==] 、、、の形
  • bracket_contentには、対応する「とじかっこ」以外の任意の文字列を含むことができる。

通常は

message([[
複数行にわたる文字列を
引数にいれたいぞ]])

のように、"[["、"]]"を使えば良い。
「"]]"を引数に入れたい」 という、超マニアックな要求がある場合にのみ

message([=[
こうすれば]]も含めることができるぞ]=])

のように、[=[などを使う。

ブラケット引数はver 3.0より前では使えないので注意。

quated引数

quoted_argument     ::=  '"' quoted_element* '"'
quoted_element      ::=  <any character except '\' or '"'> |
                         escape_sequence |
                         quoted_continuation
quoted_continuation ::=  '\' newline
  • ダブルクオーテーション"で囲まれた引数
  • \"以外のすべての文字と、エスケープシーケンスを含むことができる。
  • \の直後に改行することで、改行後も連続できる

unquated 引数

unquoted_argument ::=  unquoted_element+ | unquoted_legacy
unquoted_element  ::=  <any character except whitespace or one of '()#"\'> |
                       escape_sequence
unquoted_legacy   ::=  <see note in text>
  • かっこで囲われてない引数。
  • 空白、()#\を含まない(エスケープされている場合をのぞく。
  • ただし、過去の経緯によりダブルクオーテーションで囲われている文字列や、$()で囲われた文字列もエラーにはならない。

エスケープシーケンス

escape_sequence  ::=  escape_identity | escape_encoded | escape_semicolon
escape_identity  ::=  '\(' | '\)' | '\#' | '\"' | '\ ' |
                      '\\' | '\$' | '\@' | '\^'
escape_encoded   ::=  '\t' | '\r' | '\n'
escape_semicolon ::=  '\;'
記号   意味
'\t'  タブ文字
'\r' 同じ行の先頭に戻る
'\n'  改行、復帰
'\;' ';'文字
'\(' '('文字
'\)' ')'文字
'\#' '#'文字
'\"' '"'文字
'\ ' ' '文字(空白文字)
'\\\' '\'文字
'\$' '$'文字
'\@' '@'文字
'\^' ';'文字

変数の参照

変数は、quqted 引数とunquated 引数の中で、${valuable}の形式で参照される。bracket argumentの中では${}で囲んでも変数展開されない。

コメント

コメントは #で開始される。
ただし、以下の場合はコメント開始されない
- bracket引数の中
- quated引数の中
- unquqted引数の中で、なおかつ\でエスケープされている場合

bracketコメント

bracket_comment ::= '#' bracket_argument

# の直後にbracket引数の形が続く場合、bracket引数の終了までがコメントとなる。
これにより、複数行にわたるコメントを作ることが可能。
(C言語の/* */ に相当)。

行コメント

line_comment ::=  '#' <any text not starting in a bracket_argument
                       and not containing a newline>

C言語// に相当。

制御構造

条件分岐

if()elseif()else()endif()で条件分岐可能。

Loop

foreach()endforeach()while()endwhile()break()でループを組むことが可能。

コマンド定義

macro()endmacro()function()endfunction()でコマンド定義が可能。

変数

  • set()で値を代入、unset()で解除できる。
  • 変数は、大文字/小文字 を区別する。(コマンドと違うので注意)
  • 変数は任意の文字で作れるが、英数字と_-だけで作ることを推奨。
  • 基本的には変数の型は文字列(数値型はない)だが、コマンドによっては文字列を他の型と認識する (例えば、if()trueという文字を「真」として認識する。

変数のスコープ

変数には3種類のスコープがある

Function スコープ

  • function()コマンドによって作られるコマンド内のスコープ
  • コマンド内でset()/unset()された変数はコマンドの外からは見えない。

Directory スコープ

  • 各ディレクトリのCMakeLists.txtを処理するときのスコープ。(つまり、最も普通のスコープ)
  • 各ディレクトリのCMakeLists.txtを処理開始する前に、親ディレクトリのCMakeLists.txtで定義されていた全ての変数がコピーされる。

Persistent キャッシュ

  • 最もグローバルなスコープ。CMakeをなんども繰り返しても保存されている特殊な変数。
  • set()/unset() でCACHEオプションをつけるなどの方法で書き換え可能

変数の評価は、Function スコープ -> Directory スコープ -> Persistent キャッシュ の順に行われる。

リスト

Unquated 引数の評価時などでは、;で区切られた文字列はリストとして扱われる。
;そのものをリスト内の文字列に服見たい場合は\;のようにエスケープする。

なお、リストは「単純なユースケース」を意図して設計されているので、複雑なデータ処理に使うべきではない。