CMake 익히기 : 기초문법 (1)
작성 배경
원래는 공식 웹 페이지에 있는 튜토리얼로 학습을 생각이었는데, 비교적 불친절한 설명과 실습하기에는 부족한 부분이 많았다. 따라서 기존 대형 오픈소스 프로젝트인 OpenCV나 VTK의 CMake 스크립트를 참고하면서 공식 서적인 "Matering CMake-Platform Build System"을 참고하여 조금씩 연습을 하려고 마음을 먹었다.
"Matering CMake-Platform Build System"서적의 경우 대부분이 레퍼런스이고, 단계적인 설명은 약250페이지 정도 된다.
CMake
이 글은 CMake를 익히기 위한 내용이기 때문에 CMake의 빌드 메카니즘에 대해서는 과감히 스킵을 한다.
다만, CMake로 빌드를 하기 위해서는 몇 가지 알아야할 사항이 있다. CMake 자체는 CUI 인터페이스이다. 보니 진입장벽이 존재하고 또한 프로젝트의 규모가 커질 수 록 옵션을 어떻게 잡아야하는지가 막막해진다. 이 때문에 보조 도구가 2가지가 있다. 그리고 공식적으로 대규모의 오픈소스 프로젝트를 빌드할 경우에는 CUI보다는 GUI환경에서 빌드할 것을 권장하고 있다.
CMake-GUI
기존의 CMake의 기능을 윈도우와 같은 GUI로 사용할 수 있는 툴이다. 리눅스 뿐만 아니라 윈도우, OS X 등에서도 사용이 가능하다. 혹시나 빌드시스템에 대해서 잘 모르지만, C/C++로 만들어진 오픈 소스 프로젝트를 윈도우에서 빌드를 해야할 경우 한번쯤은 사용하게 된다.
CCMake
CMake-GUI의 경우 OS가 GUI환경을 제공해야 사용이 가능하다는 단점이 있다. 즉, Windows나 Linux의 X-Window와 같은 환경이 먼저 있어야 한다. 하지만, CCMake는 기존의 CUI 환경에서 CMake-GUI와 비슷하게 옵션을 선택할 수 있도록 해준다. 인터페이스는 Vi(혹은 Vim)과 유사한 단축키를 사용한다.
CMake 기초 문법
정상적으로 CMakeLists.txt가 작동되기 위해서는 서드에 cmake_minimum_required()이 선언되어 있어야 한다. 만약 안하게 될 경우 에러 메시지를 볼 수 있다.
Agruments 구분
CMake는 CMakeLists.txt에 작성된 스크립트대로 작동이 된다(처음 파일이름 작성시 대소문자 주의). CMake는 대부분 변수와 명령어로 구성되어 있고, 명령어는 command( arg ...) 형태로 구성되어 있다.
대부분 명령어의 첫 arg는 대부분 특수한 의미가 있다. set()의 경우 첫 arg는 최종적으로 정의되는 변수가 된다.
명령어의 arguments를 인식하는 것은 다음 예시와 같다.
# set의 예시
# set([변수] [arguements 값])
# set arguments를 2개로 인식
set(VAL "")
set(VAL "a;b;c")
set(VAL "a b c")
set(VAL a;b;c)
# set arguments를 4개로 인식
set(VAL "a" "b" "c")
set(VAL a b c)
과거에 작성된 문서를 보면, CMake의 명령어들이 대문자로 되어 있지만, vs code의 확장 도구를 통해 CMakeLists.txt를 작성해보면, 명령어는 소문자로 되어 있다. 또한, 변수는 대부분 대문자로 사용하는 관습이 있다(그 이유는 항상 합리적이 이유다).
스코프(Scope) 구분
C/C++언어에서는 중괄호를 활용해서 함수나 조건문 등의 영역인 스코프를 정의 한다. CMake에서는 이러한 중괄호가 없고 해당되는 command를 호출해서 스코프를 구분한다.
# function의 경우
function(foo)
message("Hello foo")
endfunction()
# function foo 호출
foo()
message()의 경우 C의 puts()처럼 입력받은 string을 한줄 출력을 한다. 이러한 명령어는 디버그할때 매우 유용하다. function()은 endfunction()으로 스코프 영역을 정의 해주고, function의 첫 arg는 function의 이름이 된다.
변수
변수는 set()을 통해서 정의가 되고 ${}를 통해서 값을 호출한다. 또한 변수에 여러개의 값을 정의하면, 배열(혹은 리스트) 형태로 정의가 된다.
이렇게 정의된 배열은 foreach()로 순차적으로 호출할 수 있다.
연습예제
이제, 이 페이지에서 배운 내용을 복습해보자.
cmake_minimum_required(VERSION 2.6)
# function foo 정의
function(foo)
message(${test})
set(test 2 PARENT_SCOPE)
message(${test})
endfunction()
set(test 1)
# function foo 호출
foo()
# 값확인
message(${test})
# list item_to_buy
set(item_to_buy apple orange pear beer)
# foreach item_to_buy
foreach(item ${item_to_buy})
message("Do not forget to buy one ${item}")
endforeach()
간단하기 때문에 CMakeLists.txt가 있는 폴더에서 다음과 같은 명령어로 빌드한다.
cmake -H. -Bbuild
위의 -B 옵션을 사용할 경우 자동으로 build 폴더를 생성하여 해당 폴더에 빌드를 한다. 빌드 과정에 다음 메시지가 출력되는 것을 확인할 수 있다.
예제에서 특이한 점을 보면, 메시지 결과를 보면, function foo()가 종료되어야 test값이 달라지는 것을 확인 할 수 있다. 이렇게 간단하게 기초 문법을 확인 해봤다.
참고
Matering CMake A Cross-Platform Build System 서적(영문)