# CMake의 기본 개념 (Fundamentals of CMake)

#### CMake란 무엇인가?

CMake는 크로스 플랫폼 빌드 시스템을 생성하기 위한 도구이다. 소프트웨어 프로젝트의 컴파일, 링크 및 배포를 자동화하는 데 사용된다. CMake는 Makefile, Ninja 파일, Visual Studio 솔루션 파일 등을 생성하여, 다양한 환경에서 일관된 빌드 프로세스를 가능하게 한다. 이는 특히 대규모 프로젝트나 멀티플랫폼 환경에서 유용하다.

#### CMake의 구성 요소

CMake는 여러 구성 요소로 이루어져 있으며, 이들은 프로젝트의 빌드 프로세스를 정의하고 제어하는 역할을 한다.

* **CMakeLists.txt**: CMakeLists.txt 파일은 CMake 프로젝트의 핵심 구성 파일이다. 이 파일에는 프로젝트 설정, 소스 파일 목록, 타겟 정의, 빌드 옵션 등이 포함된다. 이 파일은 각 디렉토리에 존재할 수 있으며, 계층 구조를 통해 서브 프로젝트를 관리할 수 있다.
* **Commands (명령어)**: CMake는 다양한 명령어를 제공하며, 이를 통해 빌드 설정을 구체적으로 지정할 수 있다. 주요 명령어로는 `project()`, `add_executable()`, `add_library()`, `target_link_libraries()`, `find_package()` 등이 있다.
* **Variables (변수)**: CMake에서 변수는 설정을 저장하고 빌드 프로세스 전반에서 이를 참조하는 데 사용된다. 예를 들어, `CMAKE_CXX_COMPILER`는 사용할 C++ 컴파일러를 지정하는 변수이다. 변수는 `set()` 명령어를 통해 정의되며, 필요 시 `option()`을 사용해 사용자에게 값을 입력받을 수도 있다.
* **Targets (타겟)**: 타겟은 CMake에서 빌드할 엔티티를 의미한다. 예를 들어, 실행 파일, 라이브러리 등이 타겟이 될 수 있다. 타겟은 `add_executable()`이나 `add_library()` 명령어로 정의되며, 이후 `target_link_libraries()`, `target_include_directories()` 등을 통해 종속성 및 설정을 추가할 수 있다.

#### CMake의 작동 방식

CMake는 기본적으로 두 단계로 작동한다. 첫 번째 단계는 '생성' 단계이며, 두 번째 단계는 '빌드' 단계이다.

* **생성 단계 (Generation Stage)**: 이 단계에서는 CMake가 프로젝트의 `CMakeLists.txt` 파일을 읽고, 사용자가 지정한 빌드 시스템 파일(예: Makefile, Visual Studio 솔루션 파일)을 생성한다. `cmake` 명령어를 실행하면 이 단계가 시작된다. 이 단계에서 CMake는 설정된 변수 값, 타겟 및 종속성, 기타 설정을 종합하여 빌드 시스템을 설정한다.
* **빌드 단계 (Build Stage)**: 빌드 시스템이 생성된 후, 사용자는 해당 빌드 시스템의 명령어(예: `make`, `ninja`, `msbuild`)를 사용해 실제 컴파일을 수행한다. 이 단계에서는 CMake가 직접 관여하지 않으며, 빌드 시스템에 의해 관리된다.

#### CMake의 주요 명령어

CMake에는 프로젝트를 구성하고 관리하는 데 필수적인 여러 명령어가 있다.

* **project()**: `project()` 명령어는 CMake 프로젝트의 이름과 언어를 정의한다. 예를 들어, `project(MyProject CXX)`는 MyProject라는 이름의 C++ 프로젝트를 정의한다.
* **add\_executable()**: `add_executable()` 명령어는 실행 파일 타겟을 정의한다. 예를 들어, `add_executable(MyApp main.cpp)`는 MyApp이라는 이름의 실행 파일을 생성하며, 이를 위해 main.cpp 파일을 컴파일한다.
* **add\_library()**: `add_library()` 명령어는 정적 또는 동적 라이브러리 타겟을 정의한다. 예를 들어, `add_library(MyLib STATIC lib.cpp)`는 MyLib라는 이름의 정적 라이브러리를 생성하며, 이를 위해 lib.cpp 파일을 컴파일한다.
* **target\_link\_libraries()**: `target_link_libraries()` 명령어는 타겟에 대해 링크할 라이브러리를 지정한다. 예를 들어, `target_link_libraries(MyApp MyLib)`는 MyApp 실행 파일에 MyLib 라이브러리를 링크한다.
* **find\_package()**: `find_package()` 명령어는 외부 패키지를 검색하고, 이를 프로젝트에 포함시킨다. 예를 들어, `find_package(Boost REQUIRED)`는 Boost 라이브러리를 검색하고, 이를 프로젝트에 포함한다.

#### CMake의 변수와 설정

CMake에서는 다양한 변수와 설정을 통해 빌드 프로세스를 제어할 수 있다. 이러한 변수들은 전역적으로 사용되거나 특정 타겟에만 적용될 수 있다.

* **CMAKE\_CXX\_COMPILER**: C++ 컴파일러를 지정하는 변수이다. 예를 들어, `set(CMAKE_CXX_COMPILER /usr/bin/g++)`는 G++ 컴파일러를 사용하도록 설정한다.
* **CMAKE\_BUILD\_TYPE**: 빌드 타입을 지정하는 변수로, `Debug`, `Release`, `MinSizeRel`, `RelWithDebInfo`와 같은 값이 올 수 있다. 예를 들어, `set(CMAKE_BUILD_TYPE Release)`는 릴리즈 빌드를 수행하도록 설정한다.
* **CMAKE\_CXX\_FLAGS**: C++ 컴파일러에 전달할 추가 플래그를 지정하는 변수이다. 예를 들어, `set(CMAKE_CXX_FLAGS "-Wall -O2")`는 모든 경고를 출력하고 최적화 수준 2를 사용하도록 설정한다.

#### CMake의 고급 기능

CMake는 대규모 프로젝트나 복잡한 빌드 요구사항을 지원하기 위해 다양한 고급 기능을 제공한다.

* **ExternalProject**: `ExternalProject` 모듈은 외부 프로젝트를 빌드하고 이를 포함할 수 있도록 한다. 이는 예를 들어, 서드파티 라이브러리를 소스 코드부터 빌드하여 포함해야 할 때 유용하다.
* **CTest**: CTest는 CMake와 통합된 테스트 도구이다. 이를 통해 자동화된 테스트를 설정하고 실행할 수 있다. `enable_testing()`과 `add_test()` 명령어를 통해 테스트를 정의할 수 있다.
* **CPack**: CPack은 CMake 프로젝트의 패키징을 자동화하는 도구이다. 이를 통해 다양한 포맷(RPM, DEB, ZIP 등)으로 패키지를 생성할 수 있다.

#### CMake의 확장성과 모듈화

CMake는 모듈화된 구조를 가지고 있으며, 이는 사용자가 정의한 기능을 추가하거나 CMake의 기본 기능을 확장하는 데 유용하다.

* **Custom Modules**: 사용자는 CMake 모듈을 정의하여, 프로젝트 내에서 반복적으로 사용되는 설정이나 명령어를 관리할 수 있다. 이는 `CMakeLists.txt` 파일을 간소화하고 유지보수를 용이하게 한다.
* **Function 및 Macro**: `function()`과 `macro()` 명령어는 사용자 정의 함수와 매크로를 생성할 수 있도록 한다. 이는 복잡한 설정을 단순화하고, 코드 재사용성을 높인다.

***

관련 자료:

* CMake 공식 문서: <https://cmake.org/cmake/help/latest/>
* Modern CMake 소개: <https://cliutils.gitlab.io/modern-cmake/>
* Professional CMake: A Practical Guide by Craig Scott
