Posted at
CMakeDay 5

CMake: リスト

More than 3 years have passed since last update.


はじめに

みなさん、こんにちは。今回はリストについて書いていきます。


リストは値のコレクション型

前回の記事で、変数には文字列型しかないと言いましたが、いくつかの文脈で文字列以外に解釈されることがあります。リストもその一つで、Unquated Argument で値をセミコロン;で区切り、a;b;cといった形をとると、値がそれぞれabcからなるコレクションとして認識されます。


リストの変数への代入

リストはset()コマンドを使って変数に代入することができます。

set(list_value a;b;c)

message("${list_value}") # a;b;c

また、;で区切らずに、値を複数渡してもリストとして代入できます。

set(list_value a b c)

message("${list_value}") # a;b;c

複数のリストを渡すと、連結されます。

set(list_value a b c;d "e;f")

message("${list_value}") # a;b;c;d;e;f


リストに使えない文字

リストには以下の文字を含めることはできません。


  • [

  • ]

また、区切り文字の;を含めたい場合は、エスケープしなければなりません。


リストとコマンド引数

実は、コマンドを呼び出すときにリストを渡すと、あたかも複数の引数が渡されたかのように振る舞います。

message(a;b;c) # abc

つまり、以下と同様の動作になります。

message(a b c) # abc

これは、変数に格納されている場合でも同様です。

set(list_value a;b;c)

message(${list_value}) # abc

この動作が意図したものでないのなら、Quated Argument か Bracket Argument を使用します。

message("a;b;c") # a;b;c

message([[a;b;c]]) # a;b;c

set(list_value a;b;c)
message("${list_value}") # a;b;c


リストを操作するコマンド

リストには、list()というリスト操作のための便利なコマンドが組み込みで用意されています。このlist()コマンドは、第一引数にコマンドを指定することで様々な動作を行います。リストの変更をするものは破壊的変更をします。また、リストのインデックスを要求するものは以下のことに注意します。


  • インデックスは0から始まる

  • 負の値を指定すると末尾からのインデックスとなる

  • 末尾のインデックスは-1であり、-0ではない


list(LENGTH <list> <output variable>)

リスト<list>の長さを、<output variable>変数に代入します。

set(list_value a;b;c)

list(LENGTH list_value list_length)
message(${list_length}) # 3


list(GET <list> <element index> [<element index> ...] <output variable>)

リスト<list>からインデックス<element index> ...の値を持つリストを<output variable>に代入します。

set(list_value a;b;c;d)

list(GET list_value 0 value)
message(${value}) # a

list(GET list_value 0 -1 2 value)
message("${value}") # a;d;c


list(APPEND <list> [<element> ...])

リスト<list>の末尾に値<element> ...を追加します。

set(list_value a;b)

list(APPEND list_value c d)
message("${list_value}") # a;b;c;d


list(FIND <list> <value> <output variable>)

リスト<list>の中の値<value>の最初のインデックスを<output variable>に代入します。このとき、指定した値がリストになければ-1が代入されます。

set(list_value a;b;b;c)

list(FIND list_value b index)
message("${index}") # 1

list(FIND list_value d index)
message("${index}") # -1


list(INSERT <list> <element_index> <element> [<element> ...])

リスト<list>のインデックス<element_index><element> ...を挿入します。

set(list_value a;b;c)

list(INSERT list_value 2 b2)
message("${list_value}") # a;b;b2;c

list(INSERT list_value 3 b3 b4 b5)
message("${list_value}") # a;b;b2;b3;b4;b5;c


list(REMOVE_ITEM <list> <value> [<value> ...])

リスト<list>から値<value> ...をすべて削除します。

set(list_value a;b;c;b;c;d)

list(REMOVE_ITEM list_value b)
message("${list_value}") # a;c;c;d

list(REMOVE_ITEM list_value a c)
message("${list_value}") # d


list(REMOVE_AT <list> <index> [<index> ...])

リスト<list>からインデックス<index> ...の値を削除します。

set(list_value a;b;c;d;e)

list(REMOVE_AT list_value 1)
message("${list_value}") # a;c;d;e

list(REMOVE_AT list_value 1 3)
message("${list_value}") # a;d


list(REMOVE_DUPLICATES <list>)

リスト<list>から重複している値をすべて削除します。

set(list_value a;b;c;b;d;e;c;a)

list(REMOVE_DUPLICATES list_value)
message("${list_value}") # a;b;c;d;e


list(REVERSE <list>)

リスト<list>を逆順にします。

set(list_value a;b;c;d;e)

list(REVERSE list_value)
message("${list_value}") # e;d;c;b;a


list(SORT <list>)

リスト<list>を辞書順にソートします。

set(list_value aa;a;e;aaa;a;g;zz)

list(SORT list_value)
message("${list_value}") # a;a;aa;aaa;e;g;zz


リストの用途

リストには様々な用途がありますが、もっとも多用するのはソースファイルのリストになるでしょう。たとえば、以下ではディレクトリのソースファイル一覧をリストとして取得し、各ソースファイルの実行ファイルを作成する例です。

file(GLOB sources RELATIVE ${PROJECT_SOURCE_DIR} *.cpp) #[[

project-dir/
+-- a.cpp
+-- b.cpp
+-- c.cpp
]]

message("${sources}") # a.cpp;b.cpp;c.cpp

foreach(path IN LISTS sources)
get_filename_component(target ${path} NAME_WE)
add_executable(${target}_bin ${path})
endforeach()


おわりに

以上、リストでした。リストは普段、無意識に使っていますが、思いもよらない挙動をすることもあり、その仕様を知っておくことは重要です。

明日は、mrk_21 さんの『CMake: 条件分岐』です。