스코프
- 일반적 프로그래밍 언어의 변수처럼 cmake의 변수도 스코프 영역에서만 유효하다.
- add_subdirectory, function은 새로운 스코프를 만든다
- include, macro 새로운 스코프를 만드는게 아니라 현재 스코프에서 동작한다.
cmake_minimum_required(VERSION 2.8)
project(foo NONE)
set(abc "123") # 123 출력
message("Top level scope (before): ${abc}")
add_subdirectory(boo) # 서브 디렉터리 추가
message("Top level scope (after): ${abc}") # 123 출력
# boo 디렉터리의 CMakeLists.txt
set(abc "456")
message("Directory 'boo' scope: ${abc}") # 456 출력
새 스코프 선언
- 새로운 스코프가 선언되면 변수는 부모 스코프의 변수로 초기화 된다.
- 현재 스코프에서 변수를 찾을 수 없다면 해당 변수는 빈 문자를 참조하게 된다.
cmake_minimum_required(VERSION 2.8)
project(foo NONE)
function(foo)
# set(abc "456")
# 부모 스코프의 123으로 초기화
# set(abc "456") 있을 경우 456
message("func : ${abc}")
endfunction()
set(abc "123")
message("main : ${abc}") # 123
foo()
message("main : ${abc}") # 123
- 스코프 생성 관계 main -> boo -> foo
cmake_minimum_required(VERSION 2.8)
project(foo NONE)
function(foo)
# 789, 456 출력
message("[foo]: { abc = '${abc}', xyz = '${xyz}' }")
unset(abc) # abc 변수 제거
# '', 456 출력
message("[foo]: { abc = '${abc}', xyz = '${xyz}' }")
endfunction()
function(boo)
# 123, 456 출력, 부모 스코프의 변수로 초기화 되어 있다
message("[boo]: { abc = '${abc}', xyz = '${xyz}' }")
set(abc "789")
# 789, 456 출력
message("[boo]: { abc = '${abc}', xyz = '${xyz}' }")
foo() # 2. foo 함수 호출
endfunction()
# abc 변수 선언
set(abc "123")
# xyz 변수 선언
set(xyz "456")
# 123, 456 출력
message("{ abc = '${abc}', xyz = '${xyz}' }")
boo() # 1. boo 함수 호출
새 스코프를 선언하지 않는 경우
- include 와 macro 는 새로운 스코프를 생성하지 않는다. 그래서 현재 스코프에서 set, unset 명령어를 사용할 경우 부모 스코프의 변수에 영향을 주는것과 같은 결과를 보인다.
- include, macro는 C/C++에서와 마찬가지로 코드 복사를 수행한다.
- 최상위 CMakeLists.txt
# Top level CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(foo NONE)
set(abc "123")
message("abc (before): ${abc}") # 123
include("./modify-abc.cmake") # 모듈 include, 모듈의 코드를 복사
message("abc (after): ${abc}") # 456, 모듈에서 변수를 바꿈
macro(modify_xyz) # 매크로
set(xyz "789")
endmacro()
set(xyz "336")
message("xyz (before): ${xyz}") # 336
modify_xyz() # 매크로 실행, 매크로의 코드를 복사
message("xyz (after): ${xyz}") # 789, 매크로에서 변수를 바꿈
# modify-abc.cmake, 모듈
set(abc "456")
부모 스코프
- PARENT_SCOPE를 사용하여 부모 스코프의 변수를 설정 할 수 있음
cmake_minimum_required(VERSION 2.8)
project(foo NONE)
set(abc "") # clear
function(scope_2)
message("Scope 2 (before): '${abc}'") # '', 현재 스코프값 출력
# 현재 스코프가 아닌 부모 스코프값 변경
# 바로 위의 parent scope에만 영향을 줌
set(abc "786" PARENT_SCOPE) # 현재 스코프가 아닌 부모 스코프값 변경
message("Scope 2 (after): '${abc}'") # '', 현재 스코프값 출력
endfunction()
function(scope_1)
message("Scope 1 (before): '${abc}'") # '', 현재 스코프값 출력
scope_2()
message("Scope 1 (after): '${abc}'") # '786', scope_2()에서 현재 스코프값 변경
endfunction()
message("Top level (before): '${abc}'") # '', 현재 스코프값 출력
scope_1()
message("Top level (after): '${abc}'") # '', 현재 스코프값 출력
캐시 변수의 스코프
- 일반 변수와 달리 캐시 변수는 스코프가 없다, 값 설정이 글로벌 하다
cmake_minimum_required(VERSION 2.8)
project(foo NONE)
add_subdirectory(boo)
# 일반변수 A가 없어서 캐시 변수 참조, 캐시 변수는 글로벌 해서 접근 가능
message("A: ${A}") # A: 123,
# boo 디렉터리의 CMakeLists.txt
set(A "123" CACHE STRING "cache value description") # 캐시 변수 설정
unset
- unset 명령을 사용하면 스코프 안에서의 변수값을 제거 가능하다.
- 캐시 제거하고 싶으면 unset(X CACHE) 사용.
- unset(X) 사용하면 현재 스코프의 일반 변수 제거, 캐시에 영향 없음
cmake_minimum_required(VERSION 2.8)
project(foo NONE)
set(X "123" CACHE STRING "X variable") # 캐시 변수 X 선언
set(X "456") # 일반 변수 X 선언
message("[0] X = ${X}") # [0] X = 456
unset(X) # 일반 변수 X 제거
message("[1] X = ${X}") # [1] X = 123, 일반 변수 X 없음으로 캐시 변수 X 참조
unset(X CACHE) # 캐시값 제거
message("[2] X = ${X}") # [2] X = , 참조 할게 없어서 제거됨
option(Y "Y option" ON) # 캐시 변수 Y 선언
set(Y OFF) # 일반 변수 Y 선언
message("[0] Y = ${Y}") # [0] Y = OFF, 일반 변수 Y
unset(Y) # 일반 변수 Y 제거
message("[1] Y = ${Y}") <-- [1] Y = ON # 일반 변수 제거되어 캐시 변수 Y 참조
unset(Y CACHE) # 캐시 변수 Y 제거
message("[2] Y = ${Y}") <-- [2] Y = # 모든 변수 제거됨
변수와 캐시 변수 이름이 같을 경우
- 일반 변수를 현재 스코프에서 찾지 못할 경우 같은 이름의 캐시 변수에서 가져옴
cmake_minimum_required(VERSION 2.8)
project(foo NONE)
set(a "789" CACHE STRING "") # 캐시 변수 선언
set(a "123") # 일반 변수 선언
message("Regular variable from current scope: ${a}") # 123
unset(a) # 일반 변수 a 제거, 캐시 변수 a 만 남게됨
message("Cache variable if regular not found: ${a}") # 789
- set(.. CACHE ..)는 같은 이름에 같은 스코프에 있는 변수를 제거한다.
cmake_minimum_required(VERSION 2.8)
project(foo NONE)
set(a "123")
set(a "789" CACHE STRING "") # 일반 변수 a 제거, a를 캐시 변수로 설정
message("take from cache: ${a}") # 789, 캐시 변수에서 789 가져옴
변수와 캐시 변수가 동시에 설정되는 경우 주의
- 캐시 변수값과 일반 변수의 이름이 같은 경우 혼란을 야기시킬 수 있다.
cmake_minimum_required(VERSION 2.8)
project(foo NONE)
function(set_abc_globally)
message("before cache modify ${abc}") # 123, 변수
# 첫번째 실행
# - 현재 스코프의 변수 abc 제거
# - abc를 캐시 변수로 선언
# 두번째 실행
# - 캐시 변수 이미 있음
# - 현재 스코프의 변수 제거하지 않음
set(abc "789" CACHE STRING "")
# 첫번째 실행 : 변수 abc 제거 됨으로 캐시 변수값 789 출력
# 두번째 실행 : 변수가 제거되지 않았으니 변수값 123 출력
message("after cache modify ${abc}")
endfunction()
set(abc "123")
set_abc_globally()
message("${abc}")
권고
- 일반 변수와 캐시 변수 이름을 중복하여 사용하는 것을 피해야 한다.
- 현재 스코프에서만 사용하고 짧게 사용하면 짧은 소문자 변수를 사용 (a, i, mylist, objects, etc.)
- 모든 스코프에서 사용하고 길게 사용하면 긴 대분자 변수 사용 (FOO_FEATURE, BOO_ENABLE_SOMETHING, etc.)
# bad
function(foo_something)
set(FOO_SOMETHING_A 1)
# ...
endfunction()
Using just a will be fine:
# good
function(foo_something)
set(a 1)
# ...
endfunction()
# Foo/CMakeLists.txt
# bad
message("Files:")
foreach(FOO_FILES_ITERATOR ${files})
message(" ${FOO_FILES_ITERATOR}")
endforeach()
# Foo/CMakeLists.txt
# good
message("Files:")
foreach(x ${files})
message(" ${x}")
endforeach()
# C++ 문법 철학과도 맞는다
// pretty bad idea
#define a
// good one
#define MYPROJECT_ENABLE_A
// does it make sense?
for (int array_iterator = 0; array_iterator < array.size(); ++array_iterator) {
// use 'array_iterator'
}
// good one
for (int i = 0; i < array.size(); ++i) {
// use 'i'
}