
CMake 란, make의 빌드 관리 시스템을 만들기 위한 오픈소스 프로젝트이다. 즉, CMake를 통해서 프로젝트를 빌드하는 것이 아니라 CMake를 통해 빌드 파일을 생성하면 빌드 프로그램을 통해서 프로젝트를 빌드하는 것이다.
예를 들어 make를 사용한다면 CMake를 통해 Makefile을 생성할 것이고, Ninja를 사용한다면 CMake를 통해 .ninja 빌드 파일을 만들어 준다.
Makefile은 간단한 프로젝트를 관리하기 좋지만, 프로젝트 크기가 커질 경우, 아니면 해당 프로젝트를 여러 플랫폼에서 배포하기 위해서는 불편한 점이 많다. 이러한 문제를 해결하기 위해 나타난 것이 바로 CMake이다.
CMake는 Makefile 자동 생성 및 관리를 해준다. 지정한 운영체제에 맞는 Makefile을 생성해줘서 소스코드 빌드를 편리하게 할 수 있다. 또한 의존성 정보를 일일이 기술해주지 않아도 되므로 빌드 스크립트 관리가 효율적이다.
make가 무엇인 궁금하다면 아래의 링크를 통해 확인할 수 있다.
Make & Makefile
CMake는Makefile을 만들기 위한 툴이다. 즉,CMake는 빌드 프로그램이 아니라 빌드 파일을 생성하는 툴인셈이다.
CMake의 실행 및 빌드 명령어는 다음과 같은 형식이다.
$ cmake -S<source_dir> -B<build_dir> -DCMAKE_BUILD_TYPE=[Debug|Release]
$ cmake --build <build_dir> --config [Debug|Release]
CMake를 사용하는 모든 프로젝트에는 반드시 프로젝트 최상위 디렉토리에 CMakeLists.txt 파일이 있어야 한다. 해당 파일에는 CMake가 빌드 파일을 생성하는데 필요한 정보들이 들어 있다. 따라서 보통의 컴파일 과정은 다음과 같이 진행된다.

CMakeLists.txt파일을 cmake 명령으로 실행하면, Makefile이 생성된다. 생성된 Makefile을 make 명령으로 실행하면 실행파일이 만들어지는 구조이다.
cmake CMakeLists.txt
위의 명령을 실행하면 다음과 같은 파일들이 생성된다.

목적 파일(obj)들이 만들어진다.cmake 명령은 소스파일을 추가하지 않는 이상 최초로 한번만 실행하면 된다. 만약, 소스파일이 수정되었을 경우에는 make 명령으로 빌드만 하면 된다.
cmake 명령 실행make 명령으로 빌드만 다시 실행참고로
CMake로 반드시Makefile을 만들 필요는 없다. 원하는 빌드 프로그램을 선택하여 만들 수 있다.
ConfigurationCMakeLists.txt 파일 해석GenerationProject 파일 생성다음의 명령어는 각 플랫폼에서 주로 사용되는 IDE에 맞는 파일을 생성하는 것을 보여준다.
windows
# Generate for VS
cmake -S . -B ./build -G "Visual Studio 17 2022 Win64"
unix/linux
# Generate for Ninja
cmake -S . -B ./build -G Ninja
MacOS
# Generate for XCode
cmake -S . -B ./build -G XCode
거듭 강조하자면, CMake의 목적은 파일을 생성하는데 있으며, 프로그램 빌드를 하지는 않는다.
다만 아래와 같이 명령어에서 -G 옵션으로 지정한 빌드 시스템을 호출하도록 명령할 수는 있다.
# 지정된 툴을 사용해 빌드 진행
cmake --build ./build
# 병렬 빌드
cmake --build ./build --parallel
# 빌드에 성공하면 설치까지 진행
cmake --build ./build --target install
# Debug로 빌드
cmake --build ./build --config Debug
툴체인 파일은 CMake가 지원하는 다양한 기능들을 사용해 빌드를 수행할 수 있도록 미리 지정된 파일을 의미한다.
대표적으로 Android NDK에서는 여러 아키텍처로의 크로스 컴파일에 필요한 설정들이 작성된 android.toolchanin.cmake 파일이 함께 제공되며, CMake를 사용한 빌드를 수행시에 Gradle에 의해서 자동으로 지정된다.
iPhone을 대상으로 하는 경우에는 iOS-CMake를 사용해 XCode 프로젝트를 생성하기도 한다.
그리고 vcpkg와 같이 라이브러리 탐색에 특화된 툴체인 파일을 사용하는 경우도 있다.
# vcpkg에서 제공하는 cmake 툴체인의 경로 제공
cmake -S . -B ./build -G "Visual Studio 17 2022 Win64" -DCMAKE_TOOLCHAIN_FILE="<vcpkg 경로>/scripts/buildsystems/vcpkg.cmake"
최상위 CMakeLists.txt 파일에는 반드시 아래 두 개의 내용이 들어가야 한다.
# CMake 프로그램의 최소 버전
cmake_minimum_required(VERSION 3.30)
# 프로젝트 정보
project(
my-project
VERSION 1.0
DESCRIPTION "나의 cmake프로젝트"
LANGUAGES CXX
)
cmake_minimum_required(VERSION 3.30)
CMakeLists.txt 최상단에는 해당 프로젝트에서 사용할 CMake의 최소 버전을 명시해준다. 그 이유는 CMake의 버전에 따라 그 차이가 상당히 크다. 옛 버전(특히 2.x 대의 버전)의 CMake를 사용할 경우 지원하지 않는 기능이 많이 있다. 그래서 cmake의 version을 명시하는 것이다.
project(
my-project
VERSION 1.0
DESCRIPTION "나의 cmake프로젝트"
LANGUAGES CXX
)
그 다음으로 프로젝트의 정보를 간단히 명시할 수 있다. 프로젝트의 이름을 필수로 들어가야하고 나머지는 옵션이다.
참고로 LANGUAGES 부분의 경우, C프로젝트이면 C를 명시하고 C++프로젝트면 CXX를 명시하면 된다. 만일 아무것도 명시하지 않을 경우 디폴트로 C와 CXX가 설정된다. 그 외에도 CUDA, CSharp, Swift 등등이 가능하다. 자세한 내용은 여기를 참고하자.
타겟(target)에만 헤더 디렉토리를 적용타겟(target)에만 영향을 미치므로 더 명시적이고 권장되는 방식이다.target_include_directories(my_target PUBLIC ${CMAKE_SOURCE_DIR}/include)my_target 타겟에만 해당 디렉토리가 포함된다.target_include_directories는 접근 제어(PRIVATE, PUBLIC, INTERFACE) 옵션을 제공하여 헤더 디렉토리의 가시성을 제어할 수 있다.PRIVATEPUBLICINTERFACEPRIVATEPRIVATE로 지정된 컴파일 옵션은 해당 타겟에만 적용되고, 이 타겟을 의존하는 다른 타겟에는 전파되지 않는다.PUBLIC다른 타겟에도 적용. 즉, PUBLIC으로 지정된 옵션은 해당 타겟뿐만 아니라, 이 타겟을 의존하는 다른 타겟에도 동일하게 적용된다.INTERFACEINTERFACE로 지정된 옵션은 해당 타겟 자체에는 적용되지 않고, 오직 이 타겟을 의존하는 타겟에만 적용된다.링킹(Linking)의 형태를 명시하지 않는다면, 여기서 생성되는 라이브러리는 프로젝트 생성 시, BUILD_SHARED_LIBS 변수에 따라서 결정된다.CMakeLists.txt 파일이 존재해야 한다)make all 명령어를 실행할 때, 해당 디렉토리의 target을 제외 함CMakeLists.txt파일을 호출하고 빌드 시스템에 통합할 때 사용add_subdirectory는 디렉토리마다 독립적인 CMakeLists.txt 파일을 정의하고, 이를 상위 프로젝트에서 통합할 때 사용make install 실행 시, 동작 지정링크할 때 사용Makefile로 작성했던 것을 CMakeLists.txt 파일로 다시 작성해보자. 파일 구조는 다음과 같다.

CMakeLists.txt 파일의 내용은 다음과 같다.
# 최소 cmake 버전 설정
cmake_minimum_required(VERSION 3.30.3)
# 프로젝트 이름 및 버전 설정
project(my-project VERSION 1.0.0 LANGUAGES CXX)
# C++17 표준을 사용
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 소스 파일 목록 설정
set(
SOURCES
src/Base.cpp
src/A_Module.cpp
src/B_Module.cpp
src/main.cpp
)
# 실행 파일 생성
add_executable(
${PROJECT_NAME}
${SOURCES}
)
# compile 옵션
target_compile_options(${PROJECT_NAME} PUBLIC -Wall -Werror -O2)
# include 디렉토리 추가 (헤더 파일 경로)
target_include_directories(${PROJECT_NAME} BEFORE include)
위의 경우 실행 파일을 빌드할 때 컴파일 옵션으로 -Wall (모든 경고 표시)과 -Werror (경고는 컴파일 오류로 간주)를 준다는 의미이다.

위의 그림에서 보다시피 아주 간단하게 작성한 CMakeLists.txt 파일로 실행파일을 만들어냈다. 기존의 Makefile과는 비교할 수 없을 정도로 간단해졌다. 😄
다음은 실행 파일을 만들어냈던 명령어이다.
$ mkdir build
$ cd build
$ cmake -S .. -B .
$ make -j$(nproc)
Makefile을 만들어 냈던 cmake -S .. -B . 명령을 살펴보자.
-S소스 디렉토리(Source Directory)를 지정하는 옵션이다. 여기서 ..로 현재 디렉토리의 상위 디렉토리를 소스 디렉토리로 지정하고 있다.cmake가 CMakeLists.txt 파일을 찾기 위해 상위 디렉토리를 소스 디렉토리로 사용한다.-B빌드 디렉토리(Build Directory)를 지정하는 옵션이다. 여기서 .으로 현재 디렉토리를 빌드 디렉토리로 설정하고 있다.-D특정 변수 설정을 할 수 있도록 해준다. 이 옵션은 -D<변수>=<값> 형식으로 사용되며, 프로젝트의 빌드 과정에서 변수 값을 정의하거나 특정 옵션을 활성화/비활성화하는 데 유용하다.
cmake -S .. -B .명령은, 상위 디렉토리에 있는CMakeLists.txt를 찾아 현재 디렉토리에 빌드 파일을 생성하라는 의미이다.
target_compile_options 명령을 통해 실행 파일을 빌드할 때 컴파일 옵션을 줄 수 있었다. 그렇다면 CMake에서 말하는 타겟(target)이란 무엇을 말하는 것일까?
쉽게 말해서 타겟이란 프로그램을 구성하는 요소들 이라고 보면 된다. 예를 들어 위에서 처럼 실행 파일이 될 수도 있고, 라이브러리 파일이 될 수도 있다.
CMake의 모든 명령어들은 이 타겟들을 기준을 돌아간다. 그리고 각 타겟에는 속성(Property)을 정의할 수 있는데, 위와 같이 컴파일 옵션을 주는 것도 실행 파일이라는 타겟에 컴파일 옵션 속성을 설정하는 것이라고 볼 수 있다.
그 외에도, 어떠한 라이브러리를 링크할 것인지, include 하는 파일은 어디서 보는지 등등의 여러가지 속성들을 정의해줄 수 있다.
모든 CMake 명령은 그냥 타겟을 정의하고 (add_executable 과 같이), 해당 타겟들의 속성을 지정하는 명령들(target_compile_options 처럼)로 이루어진 것이라 보면 된다.
CMake에서는 컴파일 시에 헤더 파일들을 찾을 경로의 위치를 지정할 수 있다. 보통 컴파일러는 #include <>의 형태로 include되는 헤더 파일들은 시스템 경로에서 찾고, #include ""의 형태로 include된 헤더 파일의 경우는 따로 지정하지 않는 이상 현재 코드의 위치를 기준으로 찾는다.
하지만 경우에 따라서 (특히 라이브러리를 만들 시) 헤더 파일들을 다른 곳에 위치시키는 경우가 있는데, 컴파일러가 해당 파일들을 찾기 위해서는 컴파일 시에 따로 경로를 지정해줘야 한다. 따라서 CMakeLists.txt에 include 디렉토리를 헤더 파일 경로 탐색 시 확인해라 라고 알려줘야 한다.
target_include_directories(MyTarget PUBLIC ${CMAKE_SOURCE_DIR}/include)
사용 방법은 아래와 같다.
target_include_directories(<실행 파일 이름> PUBLIC <경로 1> <경로 2> ...)
위의 경우 ${CMAKE_SOURCE_DIR}/include 를 헤더 파일 탐색 경로에 추가하고 있다. 한 가지 중요한 점은 CMake에서 디렉토리의 경로를 지정할 때, 왠만하면 절대 경로를 쓰지 않는 것이 중요하다. 그 이유는 CMake의 가장 큰 장점이 여러 플랫폼에서 사용할 수 있는 것인데, 절대 경로로 설정하면 다른 시스템에서 사용할 수 없기 때문이다.
${CMAKE_SOURCE_DIR}은 CMake에서 기본으로 제공하는 변수로, 최상위 CMakeLists.txt, 즉 cmake .. 할 때 읽어들이는 CMakeLists.txt의 경로를 의미한다. 다시 말해 프로젝트의 경로라고 볼 수 있다. 따라서 ${CMAKE_SOURCE_DIR}/include 는 현재 프로젝트 경로 안에 include 디렉토리라고 보면 된다.
프로젝트 내에서 여러 라이브러리를 빌드한다면, 그리고 서로 의존성이 있다면 이를 제어하는 것도 가능하다. 이 과정은 보통 해당 sub-project들을 모두 확인할 수 있는 CMakeLists.txt 파일에서 수행하게 된다.
의존성은 add_dependencies 함수를 사용해 명시하게 된다. 이름에서 알 수 있듯이 다수를 지정할 수 있다.
만약 target이 module1과 module2가 필요하다면 다음과 같이 구성할 수 있다.
add_dependencies(target module1 module2)
라이브러리들의 수가 많아지거나 경우에 따라 달라지면 별명(alias)을 붙여서 상위의 CMakeLists.txt에서 조금 더 편하게 사용할 수 있도록 구성할 수 있다.
# sub-project CMakeLists.txt
add_library(my_custom_logger_lib ...)
add_library(module::logger ALIAS my_custom_logger_lib)
디버그 모드와 릴리즈 모드에서 라이브러리 이름이 바뀌는 경우, 이는 굉장히 유용한 기능이 된다.
# higher-project CMakeLists.txt
add_subdirectory(some_exe)
add_subdirectory(custom_logger)
add_dependencies(some_exe module::logger)
빌드 순서를 제어하기 위해서 add_dependencies를 사용했다면, 프로그램 생성 시, 링킹에 필요한 정보들이 공유되도록 하기 위해서는 target_link_libraries를 사용하게 된다.
add_library(my_custom_logger_lib ...)
target_link_libraries(my_custom_logger_lib
PUBLIC
spdlog fmt
PRIVATE
utf8proc
)
특히 target_link_libraries 함수는 target의 의존성을 전파시키는 역할도 수행한다. 위와 같은 경우, PRIVATE과 PUBLIC을 사용해 이를 제어하고 있다. C++ class의 멤버 접근 한정자(Access Qualifier)와 유사하게 생각할 수 있다.
위와 같이 작성하면 다른 프로젝트에서 my_custom_logger_lib를 link하는 경우, spdlog와 fmt에 있는 헤더파일을 include하기 위한 경로와 빌드 결과 생성되는 라이브러리에 접근할 수 있게 된다.
하지만 PRIVATE으로 선언된 utf8proc는 이와 같은 정보를 차단한다.
add_executable(some_test_program ...)
target_link_libraries(some_test_program
PUBLIC
# spdlog와 fmt이 적혀있지 않지만 자동으로 추가된다.
my_custom_logger_lib
)
PUBLIC으로 설정한다.PRIVATE에 배치하는 것이 적합하다.반드시 빌드 파일 용의 디렉토리를 만든 다음에 해당 디렉토리에서 CMake를 실행하자.
CMake는 실행시, 여러 가지 파일들(캐시 용도)을 생성하는데 이 때문에 프로젝트 디렉토리가 엉망이 될 수 있다. 특히 이미 존재하는 파일을 덮어 씌울 수 있는 위험이 있다.
규모가 큰 프로젝트를 진행할 때, 하나의 파일이 아닌 여러개의 라이브러리들로 쪼개서 진행한다.
그 이유는? 하나의 파일에서 진행할 경우, 수정이 생기면 커다란 전체 소스코드를 다시 컴파일해야 하는데 이러면 컴파일 시간이 너무 오래 걸려 개발 속도가 느려지기 때문이다.
따라서 라이브러리로 쪼개서 수정된 부분만 다시 컴파일 하는 구조로 프로젝트를 진행한다.
즉, 다음과 같은 구조로 진행된다.

라이브러리들로 쪼개서 프로젝트를 관리하게되면, 바뀐 부분만 컴파일하고 링킹하면 되므로 컴파일 시간이 비약적으로 빨라지며 개발 속도 또한 빨라지게된다. 그리고 테스트하기도 용이하다.
이러한 구조로 된 큰 프로젝트인 경우, make로만 관리하면 힘들 것이다. 이때 힘을 발휘하는 것이 바로 cmake이다.
테스트를 위한 라이브러리를 작성해 보자. 파일&디렉토리 구조는 다음과 같다.

다음은 Calculate 라이브러리의 파일 내용이다.
// Caculator.h
#ifndef __CALCULATOR_H__
#define __CALCULATOR_H__
double Add(double, double);
void PrintResult(double);
#endif // __CALCULATOR_H__
// Caculator.cpp
#include "Calculator.h"
#include <iostream>
using std::cout;
using std::endl;
double Add(double a, double b)
{
return a + b;
}
void PrintResult(double result)
{
cout << endl;
cout << "외부 라이브러리 함수" << endl;
cout << "The result is: " << result << endl;
}
// main.cpp
#include "Base.h"
#include "A_Module.h"
#include "B_Module.h"
#include "Calculator.h"
#include <iostream>
int main(){
Base* a = new A_Module(1, 2);
Base* b = new B_Module(3, 4);
a->ShowValues();
b->ShowValues();
delete a;
delete b;
PrintResult(Add(1.1, 2.2));
return 0;
}
나머지 파일들의 내용은 여기(click me)에 가면 볼 수 있다.
라이브러리 생성은 보통 다음과 같은 CMakeLists.txt 파일의 내용은 갖는다.
# 정적 라이브러리 생성
add_library(MyLib STATIC mylib.cpp)
# 해당 라이브러리 컴파일 시 사용할 헤더파일 포함
target_include_directories(MyLib PUBLIC ${CMAKE_SOURCE_DIR}/include)
# 해당 라이브러리를 컴파일 할 옵션
target_compile_options(MyLib PRIVATE -Wall -Werror)
add_library 명령을 통해서 만들어낼 라이브러리 파일을 추가한다. add_library의 사용법은 다음과 같다.
add_library(<라이브러리 이름> [STATIC | SHARED | MODULE] <소스 1> <소스 2> ...)
중간에 어떠한 형태의 라이브러리를 만들지 설정할 수 있는데 STATIC 으로 명시하면 정적 라이브러리를, SHARED 로 설정하면 동적으로 링크되는 동적 라이브러리를, MODULE 로 설정하면 동적으로 링크되지는 않지만 dlopen 과 같은 함수로 런타임시에 불러올 수 있는 라이브러리를 생성한다.
STATICSHAREDMODULEdlopen과 같은 함수로 런타임시, 불러올 수 있는 라이브러리 생성정적 라이브러리는 프로그램 실행 파일 생성시, 라이브러리 코드가 전부 들어가는 것이고, 동적 라이브러리는 프로그램 실행 파일 생성시, 라이브러리 코드가 포함되는 것이 아닌 메모리에 라이브러리가 따로 올라가는데 이를 참조하는 형태이다.
보통 정적으로 링크하면 실행 파일의 크기가 커지는 대신 동적 라이브러리를 사용할 때 보다 더 빠르다.
# 해당 라이브러리 컴파일 시 사용할 헤더파일 경로
target_include_directories(MyLib PUBLIC ${CMAKE_SOURCE_DIR}/include)
# 해당 라이브러리를 컴파일 할 옵션
target_compile_options(MyLib PRIVATE -Wall -Werror)
위에서 눈여겨 봐야할 부분은 PUBLIC과 PRIVATE의 차이이다.
기본적으로 CMake에서 만약 A Library가 B Library를 사용한다면 A는 B의 컴파일 옵션들과 헤더 파일 탐색 디렉토리 목록을 물려받게 된다. 정확히 말하면 PUBLIC으로 설정된 것은 물려 받고, PRIVATE으로 설정된 것은 물려받지 않는다.
target_include_directories(MyLib PUBLIC ${CMAKE_SOURCE_DIR}/include)
따라서 위의 문장 의미는 다음과 같다.
MyLib를 컴파일 할 때, 헤더 파일 검색 경로에 ${CMAKE_SOURCE_DIR}/include를 추가해라.MyLib를 참조는 타겟의 헤더 파일 검색 경로에 ${CMAKE_SOURCE_DIR}/include를 추가해라.그래서 예를 들어, target이 MyLib를 사용한다면, target을 컴파일 할 때 헤더 파일 검색 경로에 ${CMAKE_SOURCE_DIR}/include가 자동으로 추가된다.
target_compile_options(MyLib PRIVATE -Wall -Werror)
반면, 라이브러리를 컴파일 하는 옵션은 PRIVATE으로 설정되어 있다. 그 이유는 MyLib를 빌드할 때에는 -Wall과 -Werror 옵션을 사용하고 싶지만, MyLib를 사용하는 target들에게까지 이 옵션을 강제하고 싶지 않기 때문이다.
일단, 생성한 라이브러리 컴파일이 잘되는지 확인해 볼 필요가 있다.

위의 그림에서 보다시피 libCalculator.a라는 라이브러리가 만들어진 것을 볼 수 있다.
이제 최상위 CMakeLists.txt파일에 통합해보자.
# 최소 cmake 버전 설정
cmake_minimum_required(VERSION 3.30.3)
# 프로젝트 이름 및 버전 설정
project(my-project VERSION 1.0.0 LANGUAGES CXX)
# C++17 표준을 사용
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# lib 디렉토리 추가 (라이브러리 빌드)
# lib 디렉토리내의 CMakeLists.txt 파일을 참조하여 Caculator 라이브러리 빌드
add_subdirectory(lib/Calculate)
# compile 옵션
add_compile_options(-std=c++17 -Wall -Wextra -Werror -O2)
# 소스 파일 목록 설정
set(
SOURCES
src/Base.cpp
src/A_Module.cpp
src/B_Module.cpp
src/main.cpp
)
# 실행 파일 생성
add_executable(
${PROJECT_NAME}
${SOURCES}
)
# include 디렉토리 추가 (헤더 파일 경로)
target_include_directories(${PROJECT_NAME} BEFORE include)
# 라이브러리 링크
target_link_libraries(
${PROJECT_NAME}
Calculator
)
add_subdirectory 명령을 통해서 CMake가 추가로 확인해야 할 디렉토리의 경로를 지정해준다. 그러면 CMake 실행 시에, 해당 디렉토리로 들어가서 그 안에 있는 CMakeLists.txt도 실행할 것이다.
target_link_libraries(${PROJECT_NAME} Calculator)
그리고 위와 같이 target을 빌드할 때, Calculator 라이브러리를 링크시켜 준다. 참고로 실행 파일은 PUBLIC 혹은 PRIVATE의 여부는 크게 중요하지 않다. 왜냐하면 실행 파일은 다른 target이 참조할 수 없기 때문이다.
그래서 위와 같이 간단하게 작성해도 상관없다.
최상위 CMakeList.txt 파일의 실행 명령은 다음과 같다.
$ mkdir build && cd build
$ cmake -S .. -B .
$ make

위의 그림처럼 Linking CXX static library libCaculator.a 라는 문구가 나오며 잘 실행된 것을 볼 수 있다.
실제로 build 디렉토리를 확인해보면, libCalculator.a 파일이 생긴 것을 볼 수 있다. 참고로 CMake는 라이브러리를 만들게 되면, 앞에 lib를 붙인 라이브러리 파일을 생성한다.
이처럼 cmake를 이용하면 외부 라이브러리도 쉽게 적용하여 컴파일하고 링킹하여 실행 파일을 생성할 수 있다. 😃
❗주의 사항
오래된 버전의
CMake에서는 앞에target_이 빠진include_directories,link_directories와 같은 명령들이 사용되었는데 이는 최신의CMake에서는 사용이 권장되지 않는 명령들이다.현재의
CMake패러다임은타겟들을 기준으로 돌아가기 때문에 꼭 `target_` 형태의 명령을 사용하는 것이 좋다.*
CMake에서 따로 설정하지 않았다면 기본으로 Make가 선택되지만 경우에 따라선 다른 빌드 프로그램을 선택해야 한다.
예를 들어, 많이 사용하는 Ninja를 사용하고 싶을 수도 있고 아니면 Visual Studio를 사용할 경우 Visual Studio용 빌드 파일을 생성해야 한다.
이 경우 아래와 같이 CMake 명령을 사용하면 된다.
$ cmake -S.. -B. -DCMAKE_GENERATOR=Nonja
CMAKE_GENERATOR 인자로 원하는 빌드 시스템을 전달하면 된다. 빌드 시스템의 전체 목록은 여기에서 볼 수 있다.
CMake에서 지원하는 대표적인 빌드 시스템은 다음과 같다.
Unix Makefiles <default>NinjaVisual Studio등등을 사용할 수 있다.
참고로 한 가지 중요한 점은 이미 빌드 시스템을 설정하였다면 바꿀 수 없다는 것이다. 새로운 디렉토리를 만들어서
CMake명령을 다시 실행하거나, 기존 디렉토리 안의 파일들을 모두 삭제해야 한다.
STATIC, SHARED, MODULE, PRIVATE, PUBLIC, INTERFACE 등등은 대문자인 점에 주의하자.
CMake 파일은 대소문자를 신경써서 사용해야만 한다. CMake 함수들(project, add_executable 등)은 소문자를 사용해도 괜찮다. 하지만 일부 예약된 단어(sub-command)들은 대문자만을 사용해야 한다.
가독성을 고려하여 일관성있게 작성하는 것이 좋다. CMake 기반 프로젝트에서는 개발자들이 서로의 CMakeLists.txt 파일을 주의 깊게 살펴보는 경우가 많다. 보고 배울만한 CMake 사례들을 모아두고 따라서 만들어보는 것이 좋을것이다.
CMake는 상당히 방대하다. 이를 테면 여타 다른 언어들처럼 변수를 정의할 수 있고, if, else, for 문 모두 사용 가능하다.
그래서 이곳 (공식 사이트)을 통해 학습을 진행하면 좋을 것이다.