Posted at
CMakeDay 8

CMake: 変数のスコープ

More than 3 years have passed since last update.


はじめに

みなさん、こんにちは。今回は、変数のスコープについて書いていきます。


スコープ

実は、CMakeの変数にはスコープが存在し、スコープには親子関係があります。 新しいスコープを作るとき、現在のスコープのすべての変数を、作成したスコープにコピーしてきます。つまり、スコープ内で作成した変数のほかに親スコープで生成した変数も存在するということです。ただし、コピーなので、親スコープ由来の変数を変更しても、親スコープには影響しません。また、スコープを抜けるとスコープ内の変数はすべて破棄されます。このスコープには以下の種類があります。


Directory Scope

ディレクトリごとにひとつ存在するスコープです。このスコープはadd_subdirectory()コマンドが呼び出されたときに作成されます。


CMakeLists.txt

set(value1 1)

message("value1: ${value1}") # value1: 1
message("value2: ${value2}") # value2:
add_subdirectory(subdir)
message("value1: ${value1}") # value1: 1
message("value2: ${value2}") # value2:


subdir/CMakeLists.txt

message("value1: ${value1}") # value1: 1

message("value2: ${value2}") # value2:
set(value1 2)
set(value2 2)
message("value1: ${value1}") # value1: 2
message("value2: ${value2}") # value2: 2


Function Scope

コマンドを呼び出すときに生成されるスコープです。つまり呼び出す文脈によって、引き継がれる変数が異なります。

function(func1)

message("value1: ${value1}")
message("value2: ${value2}")
set(value1 2)
set(value2 2)
message("value1: ${value1}")
message("value2: ${value2}")
endfunction()

function(func2)
set(value1 3)
set(value2 3)
func1()
endfunction()

set(value1 1)
message("value1: ${value1}") # value1: 1
message("value2: ${value2}") # value2:

func1() #[[
value1: 1
value2:
value1: 2
value2: 2
]]

message("value1: ${value1}") # value1: 1
message("value2: ${value2}") # value2:

func2() #[[
value1: 3
value2: 3
value1: 2
value2: 2
]]

message("value1: ${value1}") # value1: 1
message("value2: ${value2}") # value2:


Foreach Scope

このスコープはforeach()コマンドが評価された時に生成されるスコープで、ループを抜けたときに破棄されます。前述した2つのスコープとはだいぶ異なっていて、ループ変数以外は親スコープのままです。また、ループ変数と同名の変数が親スコープに存在していたときは、親スコープの変数はループを抜けるまで隠蔽されます。

set(value1 1)

set(value2 1)
message("value1: ${value1}") # value1: 1
message("value2: ${value2}") # value2: 1

foreach(value1 IN ITEMS a;b;c)
message("value1: ${value1}")
message("value2: ${value2}")
set(value1 "${value1}'")
set(value2 "${value2}'")
message("value1: ${value1}")
message("value2: ${value2}")
message("")
endforeach() #[[
value1: a
value2: 1
value1: a'
value2: 1'

value1: b
value2: 1'
value1: b'
value2: 1''

value1: c
value2: 1''
value1: c'
value2: 1'''
]]

message("value1: ${value1}") # 1
message("value2: ${value2}") # 1'''


親スコープの変数を操作

上記で、親スコープ由来の変数を操作しても親スコープには影響をあたえないと述べました。しかし、コマンドの戻り値を呼び出し元の変数に代入するときなど、親スコープの変数を操作したいときがあります。この場合は、set()コマンドのPARENT_SCOPEオプションを付与することで、これが可能となります。

function(func output_variable)

set(${output_variable} 1 PARENT_SCOPE)
endfunction()

message("result: ${result}") # result:
func(result)
message("result: ${result}") # result: 1


おわりに

以上、変数のスコープでした。add_subdirectory()コマンドやfunction()で定義したコマンドを多用している場合は、思わぬ変数を受け継ついでいる可能性があるので、十分に注意する必要があります。

明日は、mrk_21 さんの『CMake: コマンド定義』です。