본문 바로가기
기타/CMake

변수와 캐시 엔트리

by 이재만박사 2016. 6. 17.

CMakeLists 파일은 어느 프로그래밍 언어와 같이 변수를 사용한다

변수는 이후의 사용을 위해 값을 저장하는데 사용되고 ON 또는 OFF 또는 (/usr/include /home/foo/include /usr/local/include) 와 같은 리스트를 나타낼 수 있는 단일 변수가 될 수 있다

많은 유용한 변수들은 CMake에 의해 자동적으로 정의된다

 

CMake에서 변수는 ${VARIABLE} 표기를 사용하여 참조하고, 그것들은 set 명령어의 실행 순서로 정의된다

다음 예제를 생각해보자

 

# FOO is undefined

 

set (FOO 1)

# FOO is now set to 1

 

set (FOO 0)

# FOO is now set to 0

 

이것은 직관적일수 있지만, 다음 예제를 생각해보자

 

set (FOO 1)

 

if (${FOO} LESS 2)

set (FOO 2)

else (${FOO} LESS 2)

set (FOO 3)

endif (${FOO} LESS 2)

 

명백히 if 구문은 true 이고, 이것은 if 구문의 몸체가 실행될 것이라는 것을 의미한다

그것은 변수 FOO를 2로 설정할 것이고 그래서 else 구문이 맞딱드릴 때 FOO 는  2의 값을 가질 것이다

정상적으로 CMake에서 FOO의 새로운 값이 사용되지만, else 구문은 if 구문이 실행될 때 변수의 값에 항상 언급되고 규칙에 거의 드문 예외이다

그래서 이 경우에 else 절의 몸체는 실행되지 않을 것이다

변수의 영역을 더 잘 이해하기 위해 이 예제를 생각해보자

 

set (foo 1)

 

#process the dir1 subdirectoryu

add_subdirectory (dir1)

 

# include and process the commands in file1.make

include (file1.cmake)

 

set (bar 2)

#process the dir2 subdirectory

add_subdirectory (dir2)

 

#include and process the commands in file2.cmake

include (file2.cmake)

 

이 예제에서 변수 foo는 시작에서 정의되기 때문에 그것은 dir1과 dir2 둘 다 진행되는 동안 정의될 것이다

대조적으로 bar는 오직 dir2가 진행될 때만 정의될 것이다

마찬가지로 foo는 file1.cmake와 file2.cmake 둘 다 진행될 때 정의될 것이다

반면에 bar는 오직 file2.cmake 가 진행될 때 오직 정의될 것이다

 

CMake에서 변수는 대부분의 언어와 거의 다르지 않은 영역을 갖는다

당신이 변수를 설정할 때 서브 디렉토리의 CMakeLists 파일, 호출되는 어떤 함수 또는 매크로, INCLUDE 명령어를 사용하여 포함되는 어떤 파일들 뿐만 아니라, 현재 CMakelists 파일이나 함수에 보여질 수 있다

새로운 서브 디렉토리가 진행될 때 새로운 변수 영역은 호출 영역에서 모든 변수의 현재 값을 가지고 생성되고 초기화된다

자식 영역에서 생성된, 또는 존재하는 변수로 만들어진 변화로 생성되는 어떤 새로운 변수들은 부모의 영역을 침범하지 않을 것이다

다음 예제를 생각해보자

 

function (foo)

message (${test})    # test is 1 here

set (test 2)

message (${test})    # test is 2 here, but only in this scope

endfunction()

 

set (test 1)

foo()

message (${test})     # test will still be 1 here\

 

어떤 경우에 당신은 그것의 부모의 영역에서 변수를 설정하기 위해 함수 또는 서브 디렉토리를 원할 수도 있다

이것은 CMake가 함수로부터 변수를 리턴하기 위한 한가지 방법이고, 그것은 set 명령어를 가지고 PARENT_SCOPE 옵션을 사용하여 수행될 수 있다

우리는 함수 foo 가 다음과 같이 부모의 영역에서 테스트의 값을 변화하기 위해 이전의 예제를 변경할 수 있다

 

function (foo)

message (${test})    # test is 1 here

set (test 2 PARENT_SCOPE)

message (${test})    # test still 1 in this scope

endfunction()

 

set (test 1)

foo()

message (${test})     # test will now be 2 here

 

변수는 또한 값의 리스트로 나타낼 수 있다

이 경우에 변수가 확장될 때 그것은 여러 개의 변수로 확장될 것이다

다음 예제를 생각해보자

 

# set a list of items

set (items_to_buy apple orange pear beer)

 

# loop over the items

foreach (item ${items_to_buy})

message ("Don't forget to buy one ${item}")

endforeach()

 

어떤 경우에 당신은 CMake 사용자 인터페이스로부터 변수를 설정하기 위해 사용자가 당신의 프로젝트를 빌드하는 것을 허락하기를 원할 수도 있다

그 경우에 변수는 캐시 엔트리가 되어야 한다

CMake가 실행될 때마다 그것은 바이너리 파일이 쓰여지는 디렉토리에서 캐시 파일을 생산한다

이 캐시 파일의 값은 CMake 사용자 인터페이스에 의해 보여진다

이 캐시의 몇 가지 목적이 있다

첫 번째는 만약 그것들이 CMake를 다시 실행해야 한다면 그것들이 그 정보를 다시 입력할 필요가 없게 하기 위해 사용자의 선택을 저장하는 것이다

예를 들면, option 명령어는 Boolean 변수를 생성하고 캐시에 저장한다

 

option (USE_JPEG "Do you want to use the jpeg library")

 

위의 줄은 USE_JPEG이라 불리는 변수를 생성하고 그것을 캐시로 넣을 것이다

사용자가 사용자 인터페이스로와 그것의 값으부터 변수를 설정할 수 있는 방법은 사용자가 나중에 CMake를 다시 실행해야 하는 경우에 남아있을 것이다

캐시에 변수를 생성하기 위해 option, find_file과 같은 명령어를 사용할 수 있거나 CACHE 옵션을 가진 표준 set 명령어를 사용할 수 있다

 

set (USE_JPEG ON CACHE BOOL "include jpeg support?")

 

당신이 캐시 옵션을 사용할 때 당신은 변수의 타입과 문서 문자열을 제공해야 한다

변수의 타입은 어떻게 그 변수가 설정되고 보여지는지 제어하기 위해 GUI에 의해 사용된다

변수 타입은 BOOL, PATH, FILEPATH, 그리고 STRING을 포함한다

문서 문자열은 온라인 도움을 제공하기 위해 GUI에 의해 사용된다

 

캐시의 다른 목적은 결정하기에 비용이 많이 드는 키 변수를 저장하는 것이다

이 변수들은 사용자에 의해 보여지거나 조정될 수 있는 것이 아닐 수도 있다

전형적으로 이 변수들은 CMAKE_WORDS_BEGENDIAN 과 같은 시스템 종속적인 변수들인데, 이것은 그들의 값을 결정하기 위해 프로그램을 컴파일하고 실행하기 위해 CMake를 필요로 한다

일단 이 값이 결정되면, 그것들은 CMake가 실행되는 매번 그것들을 다시 계산해야만 하는 것을 피하기 위해 캐시에 저장한다

일반적으로 CMake는 이 변수들이 결코 변하지 않는 속성(당신이 속한 기계의 바이트 순서와 같은)을 제한하기로 시도한다

만약 당신이 운영체제를 바꿈으로써, 또는 다른 컴파일러에 교환함으로써 상당히 당신의 컴퓨터를 변경한다면, 당신은 캐시 파일 (그리고 아마도 당신의 바이너리 트리의 객체 파일들, 라이브러리들, 그리고 실행 파일들 모두)을 삭제하는 것을 필요로 한다

 

캐시 안에 있는 변수는 또한 만약 그것들이 고급인지 아닌지를 가리키는 속성을 갖는다

디폴트로 CMake GUI (ccmake 또는 cmake-gui와 같은)가 실행될 때 고급 캐시 엔트리는 보이지 않는다

이것은 그것들이 변경하는 것을 고려해야만 하는 캐시 엔트리에 사용자가 초점을 맞출 수 있게 하기 위해서다

고급 캐시 엔트리는 사용자가 변경할 수 있는 다른 옵션이지만, 전형적으로 그렇지 않을 것이다

큰 소프트웨어 프로젝트가 50 또는 그 이상의 옵션을 갖는 것은 평범하지 않은 것이고 고급 속성은 소프트웨어 프로젝트가 그것들을 대다수의 사용자들을 위한 핵심 옵션으로 그리고 고급 사용자들을 위한 고급 옵션으로 나누도록 하게 한다

프로젝트에 종속하면 어떤 비고급 캐시 엔트리도 존재하지 않을 수도 있다

캐시 엔트리를 고급으로 만들기 위해 mark_as_advanced 명령어가 고급을 만들기 위해 (캐시 엔트리라 알려진) 변수의 이름을 가지고 사용된다

 

어떤 경우에 당신은 미리 정의된 옵션의 제한적인 집합에 캐시 엔트리를 제한하기를 원할 수도 있다

당신은 이것을 캐시 엔트리로 STRINGS 속성으로 설정함으로써 이것을 할 수 있다

다음 CMakeLists 코드는 보통과 같이 CRYPTOBACKEND 라는 이름의 속성을 설정하고, 그리고 나서 STRINGS 속성을 세 개의 옵션의 집합에 그것을 설정함으로써 이 예제를 보여준다

 

set (CRYPTOBACKEND "OpenSSL" CACHE STRING

"Select a cryptography backend")

set_property (CACHE CRYPTOBACKEND PROPERTY STRINGS)

"OpenSSL" "LibTomCrypt" "LibDES")

 

cmake-gui가 실행되고 사용자가 CRYPTOBACKEND 캐시 엔트리를 설정할 때, 그것은 그들이 원하는 옵션이 어떤 것인지 선택하기 위해 아래로 내려가는 콤보 박스로 나타내질 것이다

 

몇 개의 마지막 점은 변수와 캐시를 가진 그것들의 상호작용을 고려하면서 만들어져야 한다

만약 변수가 캐시에 있으면, 그것은 CACHE 옵션 없이 set 명령어를 사용하여 CMakeLists 파일에 여전히 덮어 쓰여질 것이다

오직 만약 변수가 CMakeLists 파일 진행을 시작하기 전에 현재의 cmMakefile 객체에서 발견되지 않는다면 캐시 값은 점검된다

set 명령어는 캐시에서 값을 변화시키는 것 없이 현재의 CMakeLists 파일을 진행하기 위한 변수를 설정해야 한다

 

# assume that FOO is set to ON in the cache

 

set (FOO OFF)

# sets foo to OFF for processing this CMakeLists file

# and subdirectories; the value in the cache stays ON

 

일단 변수가 캐시 안에 있으면, 그것의 "캐시" 값은 CMakeLists 파일로부터 평범하게 변경될 수 없다

이 뒤의 이유는 일단 CMake가 변수를 그것의 초기가밧을 가지고 캐시로 넣고, 그리고 나서 사용자 는 GUI로부터 그 값을 변경할 수 있을 것이다

만약 CMake의 다음 호출이 그것들의 변화를 set 값 뒤에 덮어 쓴다면, 사용자는 CMake가 결코 덮어 쓰지 않을 변화를 만들지 않을 것이다

그래서 set (FOO ON CACHE BOOL "doc") 명령어는 전형적으로 캐시가 그 안에 변수를 가지지 않을 때 어떤 것을 할 것이다

일단 변수가 캐시 안에 있으면 그 명령어는 영향을 줄 수 없다

당신이 정말로 캐시된 변수의 값을 변경하기를 원하는 드문 경우에 당신은 CACHE 옵션에 set 명령어를 조합하여 FORCE 옵션을 사용할 수 있다

FORCE 옵션은 set 명령어를 오버라이딩 하게 야기할 것이고, 변수의 캐시 값을 변경할 것이다

 

 

 

 

 

 

 

 

 

 

 

 

 

 

댓글