CMake - 스코프

mohadang·2022년 8월 13일
0

CMake

목록 보기
18/24
post-thumbnail

스코프

  • 일반적 프로그래밍 언어의 변수처럼 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'
}
profile
mohadang

0개의 댓글