[CMake] 프로젝트 템플릿

CMake 를 처음 사용하시는 분들이 좀 더 빠르게 프로젝트를 구성하고 시작하는데 도움을 주기 위해서 템플릿을 만들어 보았다.

Github 주소: CMake C++ Project Template

활용하는 방법에 대해서는 Readme.md 파일에 간단하게 써두었으니 따라서 하면 된다. 여기서는 템플릿을 이용해서 응용을 원하는 분들을 위해 각각의 기능들에 대해 자세하게 설명하고자 한다. (Tag: v1.0 을 기준으로 설명한다.)

템플릿에는 크게 3가지 기능이 구현되어 있다. 나눈 기준은 주관적인 판단이므로 진지하게 볼 필요는 없다.

  • Build 스크립트 생성하고 라이브러리 build 하기 (예를 들어 Makefiles 후 make)
  • Build 된 라이브러리를 컴퓨터에 설치하고 다른 CMake 프로젝트에서 사용 가능하게 만들기
  • Doxygen 을 이용하여 API 문서 작성하기

위에 기능들은 자신이 작성한 라이브러리를 다른 사람들이 이용할 수 있게 하기 위한 가장 기본적인 기능들이다. CMake 를 이용하면 쉽고 빠르게 위와 같은 작업을 수행 할 수 있다.

CMake 에 대해서는 다른 글에서 자세하게 다루고 있으니 참고 바란다. 여기서는 템플릿 프로젝트가 실제로 어떻게 구성되어있고 CMakeLists 를 작성했는지를 설명한다.

이론적인 내용이 많으므로 ‘나는 그냥 쓸줄 만 알면되’ 하시는 분들은 안보셔도 됩니다.

프로젝트 구성

템플릿 프로젝트는 아래와 같이 구성되어 있다.

cmake-project-template
├── CMakeLists.txt
├── LICENSE
├── README.md
├── cmake
│   ├── BuildDoc.cmake
│   ├── FindSomeProject.cmake
│   └── bundang-config.cmake.in
├── doxygen
│   └── Doxyfile.in
├── example
│   ├── CMakeLists.txt
│   └── simple
│       ├── CMakeLists.txt
│       └── main.cpp
├── include
│   ├── CMakeLists.txt
│   └── bundang
│       └── core.hpp
└── src
    ├── CMakeLists.txt
    └── core.cpp

./cmake/

CMake 관련 모듈들이 구현되어 있는 폴더이다. 특히 CMake 로 구성되어 있지 않은 third party 라이브러리를 찾고 CMake 프로젝트에서 사용할 수 있게 만들어준다.

  • BuildDoc.cmake: Doxygen 을 이용하여 API 문서를 만들어주는 함수가 구현되어 있다.
  • FindSomeProject.cmake: SomeProject 라는 라이브러리를 find_package 함수를 이용해서 찾기 위해 필요한 모듈이다. find_package(SomeProject) 라고 호출하면 find_package 는 ${CMAKE_MODULE_PATH} 에서 FindSomeProject.cmake 를 검색해서 수행하게 된다. (참고: find_package 어떤 규칙으로 어떤 파일을 찾는지 확인해보자.)
  • bundang-config.cmake.in: 현재 이 프로젝트 (budang 라이브러리) 를 다른 CMake 프로젝트에서 사용할 수 있게 만들어주는 파일이다. 나중에 configure_file 함수를 이용해서 bundang-config.cmake.in 에 있는 특수 문자열들을 치환해서 실제 사용할 ‘~.cmake’ 파일을 생성한다. 즉, 설치 위치나 프로젝트 이름 등 가변적으로 변할 수 있는 것들을 위한 템플릿 파일이라고 보면 된다.
find_package 에 대해서 간단하게 소개해 두었다.

./include/

include 폴더 안에는 헤더 파일이 있다. 제 경우에는 나중에 install 할 때 편의를 위해 include 폴더 안에 바로 헤더 파일을 넣지 않고 라이브러리 이름을 가진 폴더 하나를 더 생성하고 그 안에 헤더를 넣는다. 그 이유는 헤더 파일의 이름이 다른 라이브러리의 이름과 동일하거나 헷갈릴 가능성이 있기 때문이다.

./src/

src 폴더 안에는 소스 파일을 넣는다. include 폴더와 src 폴더를 따로 두는 이유는 보기에 좋은 이유와 abstraction 의 기능을 하는 헤더 파일을 실제 구현을 담고 있는 소스 파일과 나눔으로서 그 기능을 분리하는 느낌도 있다. 꼭, 이렇게 구성 해야 하는 이유는 없지만 다른 사람들이 보기 편하게 만드는 것도 유지 보수나 재사용성 측면에서 중요한 부분이라 생각한다. (참고: Separate “include” and “src” folders for application-level code?)

./example/

다른 사람들이 쉽게 라이브러리를 이용할 수 있게 예제들을 넣어 놓는다. cmake 의 BUILD_EXAMPLE 옵션을 ON/OFF 하여 빌드를 할 수도 안할 수도 있다.

./CMakeLists.txt

최상위 CMakeLists 는 중요하므로 같이 살펴보고 넘어가자 v1.0 태그 기준으로 최상위 CMakeLists.txt 는 아래처럼 구현되어 있다.

cmake_minimum_required(VERSION 3.5)
project(bundang C CXX)

set(CMAKE_CXX_STANDARD 14)

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH};${PROJECT_SOURCE_DIR}/cmake)

set(BUILD_EXAMPLE ON CACHE BOOL "Build examples")
set(BUILD_DOC ON CACHE BOOL "Build documentation")

find_package(SomePackage QUIET)
if(SomePackage_FOUND)
else()
  message(STATUS "[SomePackage] Cannot find a package.")
endif()

include_directories(include)
add_subdirectory(src)
if(BUILD_EXAMPLE)
  add_subdirectory(example)
endif()
if(BUILD_DOC)
  include(BuildDoc)

  BuildDoxygen(${CMAKE_CURRENT_SOURCE_DIR}/doxygen/Doxyfile.in
    DEST_DIR              ${CMAKE_BINARY_DIR}
    INPUT_ROOT_DIR        ${CMAKE_HOME_DIRECTORY}
    EXCLUDE_PATTERNS_DIR  ${CMAKE_BINARY_DIR}
  )
endif()

configure_file(${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}-config.cmake.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake @ONLY)
install(FILES ${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake DESTINATION lib/bundang)
  • 6: find_package 또는 include 함수에서 ./cmake/ 폴더 안에 있는 모듈들을 이용하기 위해서는 CMAKE_MODULE_PATH 에 cmake 폴더 주소를 넣어줘야 한다. set 함수를 이용해서 추가 할 수 있다.
  • 8-9: 예제를 빌드할 건지 말건지, API 문서를 생성할건지 말건지 등 사용자의 니즈에 맞춰서 cmake 를 수행할 수 있다. set 함수와 CACHE 옵션을 이용하면 사용자가 외부에서 cmake 의 변수를 조작할 수 있다. 예를 들어 BUILD_EXAMPLE 은 ON 으로, BUILD_DOC은 OFF로 하고 싶으면 ‘cmake -D BUILD_EXAMPLE=ON -D BUILD_DOC=OFF ..’와 같이 수행하면 된다. (참고: 변수와 캐시)
  • 11-15: find_package(SomePackage) 를 수행하면 ./cmake/FindSomePackage.cmake 가 실행되고 만약에 해당 라이브러리를 찾으면 SomePackage_FOUND 가 TRUE 가 된다. 만약에 찾지 못하는경우 14번째 줄로가서 에러 메세지를 출력한다.
  • 19-21: 만약에 cmake 옵션으로 BUILD_EXAMPLE 이 ON 또는 TRUE 세팅된 경우 20번째 줄이 수행된다. (아무 세팅도 하지 않는 경우 default 가 ON 이므로 결과는 똑같다.) 20번째 줄은 example 디렉토리에 있는 CMakeLists.txt 를 실행시키라는 의미를 담고 있다.
  • 22-30: BUILD_DOC 이 ON 또는 TRUE 인 경우 API 문서를 만드는 함수를 실행한다. 정확하게 말하면 cmake 하는 도중에 만드는것이 아니고 add_custom_target 을 통해서 make doc 과 같이 사용자 정의 빌드 규칙을 만들어서 문서를 생성하게 된다. 현재 이 템플릿의 경우 make doc 을 하면 API 문서를 생성한다.
  • 32: 위에서 설명한것처럼 bundang-config.cmake.in 을 이용해서 bundang-config.cmake 을 만들어낸다. 자세한건 configure_file 을 참고하자.
  • 33: bundang-config.cmake 는 외부 CMake 프로젝트에서 현재 이 프로젝트에서 생성된 bundang 라이브러리를 사용하기 위해 필요한 파일이다. CMake 에는 이와 같은 config 파일에 경로를 정하는 규칙을 정해두었다. 규칙을 따르지 않는 경우 직접 경로를 설정해야하는 불편함이 있으므로 따르는 것이 좋다. 33번째 줄은 사용자가 make install 을 수행할때 bundang-config.cmake 파일을 적절한 위치에 복사 붙여넣기 하는 과정을 설정하고 있다.

./doxygen/

API 문서를 만들기 위한 Doxygen 설정 파일이 들어있다.