CMake
Definition : What is CMake
- this is a tool or language (not compiler) that create commands of compiler based on what OS is and what kind of Generator (build system) we use.
Terms
Term | Meaning |
---|---|
configure | CmakeList.txt를 읽으며, 프로젝트 설정들을 확인하여, build 에 필요한 재료들을 만드는 과정 및 행동 |
build | .. |
target | configure or build 대상들 |
linking | target들을 연결하는 과정. 빌드를 한다고하면, 각 target들로부터 개별적인 object 파일들을 만들며, 이 object 파일들을 연결해줘야한다. |
configurations | First off Debug/Release are called configurations |
.dll | 동적 라이브러리 : 라이브러리 인데, 런타임에 포함되는 라이브러리임 + .lib 사용될때 같이 사용됨 |
.lib | 정적 라이브러리 : 라이버리리 인데, 컴파일 때 포함되는 라이버리임 + 모든 코드가 다 들어있음 |
when to use dll / lib ?
빌드 방식 | 필요 파일 | 설명 |
---|---|---|
정적 라이브러리 | .lib | 실행 파일에 라이브러리 코드가 포함. .dll 파일 불필요. |
동적 라이브러리 | .lib + .dll 컴파일 시 | .lib, 실행 시 .dll 필요. 실행 파일 배포 시 .dll 포함. |
-
정적 라이브러리 (STATIC)
- 확장자:
.lib
(Windows),.a
(Linux/macOS) - 정의: 빌드 시점에 라이브러리 코드가 호출 대상 실행 파일에 그대로 포함되어 하나의 독립 실행 파일을 생성합니다.
- 확장자:
-
공유 라이브러리 (SHARED)
- 확장자:
.dll
(Windows),.so
(Linux),.dylib
(macOS) - 정의: 실행 시점에 동적으로 라이브러리를 로딩하여 심볼(함수, 데이터 등)을 연결합니다.
- 확장자:
-
장단점 및 사용 적합 시기
구분 | 정적 라이브러리 (STATIC) | 공유 라이브러리 (SHARED) |
---|---|---|
장점 | - 실행 파일 하나만 배포하면 됨 - 런타임 의존성 문제 감소 |
- 실행 파일 크기 작음 - 라이브러리만 교체해도 기능/보안 업데이트 반영됨 - 여러 프로세스가 메모리 공유 가능 |
단점 | - 실행 파일 크기 증가 - 라이브러리 수정 시 전체 재빌드 필요 |
- 런타임에 DLL/SO 위치 설정 필요 - 배포 시 .dll/.so 파일 포함 관리 필요 |
사용 적합 시기 | - 소규모 툴, 단일 배포 바이너리 선호 - 특정 버전 고정 필요할 때 |
- 플러그인 시스템, 자주 업데이트되는 기능 모듈 - 메모리 최적화가 중요한 대규모 애플리케이션 |
CMAKE_PREFIX_PATH
-
역할:
find_package()
가 검색할 설치 경로 목록을 지정하는 변수 -
형식:
# CMake 호출 시 옵션으로 설정 cmake -DCMAKE_PREFIX_PATH="/opt/myLib;/usr/local/myOtherLib" ../src
-
동작:
-
CMAKE_PREFIX_PATH
에 지정된 폴더를 먼저 뒤져<prefix>/lib
,<prefix>/share
등에서<Package>Config.cmake
찾기 - 전역 설치 경로(
/usr
,/usr/local
)를 뒤지기 전에 우선 탐색
-
-
사용 예:
cmake -DCMAKE_PREFIX_PATH="C:/MySdk;C:/AnotherLib" -B build
Install list of CMake dev env
Windows
- install several software
- Visual Studio 2022
- CMake
- Git
- Doxygen
- Python 3.8 or newer
- install wsl :
wsl --install
- install package on linux (ubuntu)
sudo apt-get update sudo apt-get upgrade # Mandatory sudo apt-get install gcc g++ gdb sudo apt-get install make cmake sudo apt-get install git sudo apt-get install doxygen sudo apt-get install python3 python3-pip # Optional sudo apt-get install lcov gcovr sudo apt-get install ccache sudo apt-get install cppcheck sudo apt-get install llvm clang-format clang-tidy sudo apt-get install curl zip unzip tar sudo apt-get install graphviz
- install several extentions of vscode
- C/C++ Extension Pack
- Coding Tools extension Pack
- WSL
- set global setting on VScode (User tab)
optional
Build after coding
```
0.) Create Source and CMakeFile
1.) mkdir build
2.) cd build
3.) cmake .. - Generting the Build Files / Configure the Project
4.) cmake --build .
5.) ./Executable
```
Methods
find_package( [version] [REQUIRED] [COMPONENTS ...])
- 목적: CMake 모듈 또는 패키지 설정 파일을 통해 자동으로 의존성 경로를 설정
-
인자:
-
<Package>
: 찾을 패키지 이름 -
version
: 최소/최대 버전 명시 -
REQUIRED
: 없으면 에러, 있으면 경고 후 계속 -
COMPONENTS
: 모듈별로 나눠 로드 가능 (예:usd
,usdGeom
)
-
-
결과:
<Package>_INCLUDE_DIRS
,<Package>_LIBRARIES
변수 또는<Package>::...
인터페이스 타겟 제공
include_directories(...) / target_include_directories( [SYSTEM] [AFTER|BEFORE] ...)
- 목적: 컴파일러 헤더 검색 경로 추가
-
차이:
- 전역:
include_directories()
는 이후 모든 타겟에 적용 - 타겟 한정:
target_include_directories()
는 특정 타겟에만 적용
- 전역:
- 사용 예:
target_include_directories(myexe PRIVATE
${SomeLib_INCLUDE_DIRS}
)
link_directories(...)
- 목적: 링커가 라이브러리(.lib/.a/.so) 파일을 찾을 수 있는 경로를 추가
-
주의:
- 가능하면 인터페이스 타겟 사용(
find_package()
방식) 권장 - 전역 설정이므로 의존성 충돌 우려
- 가능하면 인터페이스 타겟 사용(
target_link_libraries( [PRIVATE|PUBLIC|INTERFACE] ...)
- 목적: 특정 타겟에 라이브러리 링크를 지정
-
키워드:
-
PRIVATE
: 해당 타겟만 링크 -
PUBLIC
: 해당 타겟 + 이를 링크하는 하위 타겟 -
INTERFACE
: 링크 명세만 전파 (실체 없는 허브 타겟용)
-
-
사용 예:
target_link_libraries(myexe PRIVATE fnusd OpenUSD::usd )
add_library()
- 자신이 작성한 C++ 소스(
myCode.cpp
)와 헤더(myCode.h
)를 하나의 라이브러리로 만들고, 다른 타겟과 연동하는 방법입니다.
Create static library
# myCode.cpp, myCode.h가 있는 디렉토리에서
add_library(mycode_static STATIC
myCode.cpp
myCode.h # 헤더를 명시해도 되고, 헤더는 include 디렉토리에만 두어도 됨
)
target_include_directories(mycode_static PUBLIC
${CMAKE_CURRENT_SOURCE_DIR} # 헤더 파일 위치
)
- STATIC: 정적(.lib/.a) 라이브러리를 생성
-
PUBLIC
: 이 라이브러리를 링크하는 타겟에도 include 디렉토리를 전달
Create shared library
add_library(mycode_shared SHARED
myCode.cpp
)
target_include_directories(mycode_shared PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)
- SHARED: 공유(.dll/.so) 라이브러리를 생성
- 헤더는 별도로
target_include_directories()
로 설정
7.3 라이브러리 사용하기
# 라이브러리 생성 뒤, 실행 파일을 만들고 링크
add_executable(myApp main.cpp)
target_link_libraries(myApp PRIVATE
mycode_static # 또는 mycode_shared
)
-
myApp
타겟은mycode_*
라이브러리의 심볼과 헤더를 사용 가능
Tip: ## 7.4 정적 라이브러리(Static) vs 공유 라이브러리(Shared)
CMake에서 add_library()
로 생성할 때, STATIC
과 SHARED
두 가지 유형을 선택할 수 있습니다. 이하 정의와 적합한 사용 시기를 정리합니다.
[ Basic - (project / add_executable) ]
cmake_minimum_required(VERSION 3.22)
# projectName projectVersion projectLanguage (CXX stands for C++)
# v v v
project(CppProjectTemplate VERSION 1.0.0 LANGUAGES C CXX)
# User defined name
# v
add_executable(Executable main.cc)
[ Add variable - set ]
- set(변수명 변수값) or set(변수명 “변수값”) -> 선호에 따라서
set(LIBRARY_SOURCES
my_lib.cc)
set(LIBRARY_HEADERS
my_lib.h)
or
set(LIBRARY_SOURCES
"my_lib.cc")
set(LIBRARY_HEADERS
"my_lib.h")
[ Use external os environment vairable ]
- set(CMAKE변수명 $ENV{컴퓨터환경변수})
- bring os env variable in cmake. and then use it as a local variable
[ Add local library ]
- 자신이 작성한 C++ 소스(myCode.cpp)와 헤더(myCode.h)를 하나의 라이브러리로 만드는 방법으로,사용하게되면 target으로 지정하게 되는데, 다른 타겟과 연동하는 방법입니다.
set(EXECUTABLE_NAME Executable)
set(LIBRARY_NAME Library)
add_library(${LIBRARY_NAME} my_lib.cc) # library 파일들 리스트업
add_executable(${EXECUTABLE_NAME} main.cc) # execuatable 하게 만들 파일 targeting
target_link_libraries(${EXECUTABLE_NAME} ${LIBRARY_NAME}) # library하고 target파일을 연결관계 정의
[ Add local library 2 ]
- 폴더 구조를 만들고, library 를 위한 코드들이 다른 공간으로 분리되어있을 때,
- header 파일을 추가하고싶을때, 사용
# - root
# |-- app
# | |-- main.cc
# | |-- CMakeList.txt :
# add_executable(${EXECUTABLE_NAME} "main.cc")
# target_link_libraries(${EXECUTABLE_NAME} PUBLIC ${LIBRARY_NAME})
# |-- src
# |-- CMakeList.txt : add_subdirectory(my_lib)
# |-- my_lib
# |-- CMakeList.txt : add_library / target_include_directories 사용 ----------
# |-- CMakeList.txt |
# cmake_minimum_required(VERSION 3.22) |
# project(CppProjectTemplate VERSION 1.0.0 LANGUAGES C CXX) |
# set(EXECUTABLE_NAME Executable) |
# set(LIBRARY_NAME Library) |
# add_subdirectory(src) |
# add_subdirectory(app) |
# ---------------------------------------------------------
# |
set(LIBRARY_SOURCES
my_lib.cc)
set(LIBRARY_HEADERS
my_lib.h)
add_library(${LIBRARY_NAME} STATIC
${LIBRARY_SOURCES}
${LIBRARY_HEADERS})
# Include dir to header files
# This does not have to be set, to be able to compile the program
# However, for MSVC builds this is needed, to have the headers listed in VS.
target_include_directories(${LIBRARY_NAME} PUBLIC
"./")
[ How to set Debug / release ]
-
First off Debug/Release are called configurations in cmake (nitpick). If you are using a single configuration generator (Ninja/Unix-Makefiles) you must specify the CMAKE_BUILD_TYPE.
-
Like this:
# Configure the build
cmake -S . -B build/ -D CMAKE_BUILD_TYPE=Debug
# Actually build the binaries
cmake --build build/
# Configure a release build
cmake -S . -B build/ -D CMAKE_BUILD_TYPE=Release
# Build release binaries
cmake --build build/
For multi-configuration generators it's slightly different (Ninja Multi-Config, Visual Studio)
# Configure the build
cmake -S . -B build
# Build debug binaries
cmake --build build --config Debug
# Build release binaries
cmake --build build --config Release
- If you are wondering why this is necessary it’s because cmake isn’t a build system. It’s a meta-build system (IE a build system that build’s build systems). This is basically the result of handling build systems that support multiple-configurations in 1 build. If you’d like a deeper understanding I’d suggest reading a bit about cmake in Craig Scott’s book “Professional CMake: A Practical Guide
[ External library - Imath]
- Imath build 먼저
- CMakeList.txt 에 아래의 conditions 들 추가
- set Imath_DIR to ImathConfig.cmake directory.
- put include directory in target_include_directories() function
- put .lib file path in target_link_libraries() function to link in between source code and libraries.
... set(Imath_ROOT ...) set(Imath_LIB ${Imath_ROOT}/lib/Imath-3_1.lib) set(Imath_DIR ${Imath_ROOT}/lib/cmake/Imath) set(Imath_INCLUDE_DIR ${Imath_ROOT}/include/Imath) find_package(Katana PATHS "${KATANA_ROOT}/plugin_apis/cmake" REQUIRED) find_package(Imath REQUIRED) add_library( ${LIBRARY_NAME} MODULE code.cpp ) target_include_directories( ${LIBRARY_NAME} PUBLIC ${Imath_INCLUDE_DIR} ) target_link_libraries(${LIBRARY_NAME} PRIVATE Katana::FnGeolibPluginApis::Shared ${Imath_LIB} ) set_target_properties(${LIBRARY_NAME} PROPERTIES PREFIX "")
[ How to set up external libraries ]
- CMake 프로젝트에서 외부 라이브러리를 연동하는 방법은 크게 두 가지로 나뉩니다:
- 직접 지정(Manual Specification)
find_package()
사용- vcpkg 방식
Ways to set up based on form of library
라이브러리 형태 | 연동 방법 | 설명 |
---|---|---|
헤더 + 바이너리(.lib/.dll/.so) Katana FnUSD 등 |
직접 지정 | CMake 설정 파일(Config /Find 모듈)이 없으므로 include/link 경로를 수동 등록 |
설치(in-stall) 형태, CMake Config 제공OpenUSD, Qt, Boost 등 |
find_package() 사용 |
<Library>Config.cmake 또는 CMake 내장 Find<Library>.cmake 를 통해 자동 경로 설정 |
1. Manual Specification (Direct)
- When to use
- CMake용 설정 파일을 제공하지 않는 서드파티 바이너리
- 커스텀 빌드 환경, 내부 배포된 라이브러리 등
- 기본 흐름
-
include_directories()
또는target_include_directories()
로 헤더 경로 등록 -
link_directories()
로 라이브러리 검색 폴더 등록 -
target_link_libraries()
로 실제 라이브러리 링크
set(KATANA_ROOT "C:/Program Files/Katana6.5v4" CACHE PATH "Katana install root") add_executable(MyUsdTool main.cpp) # 1) 헤더 경로 target_include_directories(MyUsdTool PRIVATE "${KATANA_ROOT}/external/FnUSD/include" ) # 2) 라이브러리 검색 경로 (Windows의 경우) link_directories( "${KATANA_ROOT}/bin" ) # 3) 필요한 FnUSD 모듈 링크 target_link_libraries(MyUsdTool PRIVATE fnusd fnUSDEngine fnusdGeom fnusdImaging )
-
2. By using find_package()
- 동작 원리
-
Config 모드:
<Package>Config.cmake
를 찾아 설정 변수나 인터페이스 타겟을 가져옴 -
Module 모드: CMake 내장
Find<Package>.cmake
를 찾아*_INCLUDE_DIRS
,*_LIBRARIES
등을 설정
-
Config 모드:
-
사용 시기
- 공식 라이브러리(Boost, Qt, OpenCV 등)
- 설치 형태로 CMake 설정 파일을 제공하는 오픈소스/사내 패키지
-
예시
# Config 모드 (OpenUSD가 제공하는 경우) find_package(OpenUSD 23.05 REQUIRED COMPONENTS usd usdGeom) add_executable(myexe main.cpp) # 자동으로 설정된 인터페이스 타겟 사용 target_link_libraries(myexe PRIVATE OpenUSD::usd OpenUSD::usdGeom) # Module 모드 (CMake 내장 모듈 사용) find_package(ZLIB REQUIRED) include_directories(${ZLIB_INCLUDE_DIRS}) target_link_libraries(myexe PRIVATE ${ZLIB_LIBRARIES})
3. Using vcpkg
(1) vcpkg 설치
git clone https://github.com/microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh # Windows: .\bootstrap-vcpkg.bat
(2) 라이브러리 설치
vcpkg install [패키지명] # 예: vcpkg install fmt
vcpkg install [패키지명]:x64-windows # 플랫폼 지정
(3) CMake에서 사용하기
-
Toolchain 파일 지정
cmake -B build -S . \ -DCMAKE_TOOLCHAIN_FILE=/path/to/vcpkg/scripts/buildsystems/vcpkg.cmake
-
find_package() 또는 직접 링크
-
vcpkg가 CMake용 설정 파일을 제공하는 라이브러리라면
find_package()
사용 가능find_package(fmt CONFIG REQUIRED) target_link_libraries(myexe PRIVATE fmt::fmt)
-
그렇지 않은 경우, vcpkg toolchain이 자동으로 include/library 디렉토리를 CMake에 추가하므로
find_library(FOO_LIB foo) # 또는 직접 경로 사용 target_link_libraries(myexe PRIVATE ${FOO_LIB})
-
-
CMAKE_TOOLCHAIN_FILE
변수- 위
-DCMAKE_TOOLCHAIN_FILE
옵션을 통해 vcpkg가 설치된 라이브러리를 자동으로 검색 및 설정 -
CMAKE_PREFIX_PATH
대신 toolchain 파일을 사용하는 것이 권장됩니다.
- 위