Posted at
CMakeDay 7

CMake: ループ

More than 3 years have passed since last update.


はじめに

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


ループの種類

CMakeのループには、foreach()while()の2種類存在し、以下に示すようにそれぞれ用途が異なっています。


foreach()

foreach()は、リストもしくは範囲のイテレーションを行うためのもので、次のような構文になっています。


foreach(loop_var arg1 arg2 ...)

COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
endforeach(loop_var)

foreach — CMake 3.0.2 Documentation


foreach()は、以下の4つの機能を提供します。


foreach(loop_var IN LISTS [variable_name ...])

引数variable_name ...の各値をリストの変数名と解釈して、変数の値でイテレーションします。

set(list1 a;b)

set(list2 c;d)

# loop_var: a
# loop_var: b
foreach(loop_var IN LISTS list1)
message("loop_var: ${loop_var}")
endforeach()

# loop_var: a
# loop_var: b
# loop_var: c
# loop_var: d
foreach(loop_var IN LISTS list1 list2)
message("loop_var: ${loop_var}")
endforeach()


foreach(loop_var IN ITEMS [value ...])

引数value ...の各値をリストと解釈して、イテレーションします。また、IN ITEMSを省略したものも同様の動作を行うようです。

# loop_var: a

# loop_var: b
foreach(loop_var IN ITEMS a b)
message("loop_var: ${loop_var}")
endforeach()

# loop_var: a
# loop_var: b
# loop_var: c
# loop_var: d
foreach(loop_var IN ITEMS a b c;d)
message("loop_var: ${loop_var}")
endforeach()

# loop_var: a
# loop_var: b
# loop_var: c
# loop_var: d
foreach(loop_var a b c;d)
message("loop_var: ${loop_var}")
endforeach()


foreach(loop_var RANGE total)

0..totalの範囲の各値をイテレーションします。

# loop_var: 0

# loop_var: 1
# loop_var: 2
foreach(loop_var RANGE 2)
message("loop_var: ${loop_var}")
endforeach()


foreach(loop_var RANGE start stop [step])

start..stopの範囲の値をイテレーションします。このとき値の増分をstepで指定できます。これには負の値も指定できます。

# loop_var: 1

# loop_var: 2
# loop_var: 3
foreach(loop_var RANGE 1 3)
message("loop_var: ${loop_var}")
endforeach()

# loop_var: 1
# loop_var: 3
# loop_var: 5
foreach(loop_var RANGE 1 6 2)
message("loop_var: ${loop_var}")
endforeach()

# loop_var: 9
# loop_var: 8
# loop_var: 7
foreach(loop_var RANGE 9 7 -1)
message("loop_var: ${loop_var}")
endforeach()


while()

while()コマンドは指定された条件式を満たすまでの繰り返しを行うもので、次のような構文になっています。


while(condition)

COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
endwhile(condition)

while — CMake 3.0.2 Documentation


while()コマンドの条件式には、if()コマンドと同じものが利用できます。

set(filename "")

# 変数filenameの値が指定のパターンにマッチするまで繰り返す
while(NOT filename MATCHES "[0-9][A-Z]")
string(RANDOM filename)
endwhile()


break()による中断

これらのループでは、break()コマンドを用いて途中で中断することができます。

# loop_var: a

# loop_var: b
foreach(loop_var a;b;c;d)
if(loop_var STREQUAL "c")
break()
endif()
message("loop_var: ${loop_var}")
endforeach()

while(true)
string(RANDOM filename)
if(filename MATCHES "[0-9][A-Z]")
break()
endif()
endwhile()


おわりに

以上、ループでした。実際には、file(GLOB)コマンドで取得したソースファイルのイテレーションなどforeach()を利用することがほとんどだと思います。しかし、条件を満たすまで試行し続ける、などwhile()コマンドを使用したほうが便利な場合もあります。この場合、if()コマンド同様に条件式の仕様に気を付ける必要があります。

明日は、mrk_21 さんの『CMake: 変数のスコープ』です。