
1편에서 CMakeLists.txt 기본 구조, 타겟 정의, 빌드 타입을 다뤘습니다. 2편에서는 프로젝트가 커졌을 때 쓰는 서브디렉토리 구조, 외부 라이브러리를 끌어오는 방법, 그리고 현장에서 자주 쓰는 패턴들을 정리합니다.
서브디렉토리 구조
프로젝트가 커지면 디렉토리를 나눠서 관리합니다. 각 디렉토리마다 CMakeLists.txt를 두고, 루트에서 add_subdirectory()로 불러오는 방식입니다.
디렉토리 구조 예시
MyProject/
├── CMakeLists.txt # 루트
├── src/
│ ├── CMakeLists.txt
│ ├── main.cpp
│ └── parser.cpp
├── lib/
│ ├── CMakeLists.txt
│ └── utils.cpp
└── tests/
├── CMakeLists.txt
└── test_parser.cpp
루트 CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(MyProject VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
option(BUILD_TESTS "테스트 빌드" ON)
add_subdirectory(lib)
add_subdirectory(src)
if(BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
lib/CMakeLists.txt
add_library(utils STATIC utils.cpp)
target_include_directories(utils PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)
src/CMakeLists.txt
add_executable(myapp main.cpp parser.cpp)
target_link_libraries(myapp PRIVATE utils)
lib에서 PUBLIC으로 include 경로를 열어뒀기 때문에, myapp이 utils에 링크하면 자동으로 include 경로도 따라옵니다.
find_package — 시스템 라이브러리 찾기
설치된 라이브러리를 CMake가 찾아서 연결합니다.
find_package(패키지명 버전 REQUIRED)
# OpenSSL
find_package(OpenSSL REQUIRED)
target_link_libraries(myapp PRIVATE OpenSSL::SSL OpenSSL::Crypto)
# Threads (pthread)
find_package(Threads REQUIRED)
target_link_libraries(myapp PRIVATE Threads::Threads)
# Boost
find_package(Boost 1.70 REQUIRED COMPONENTS filesystem system)
target_link_libraries(myapp PRIVATE Boost::filesystem Boost::system)
# zlib
find_package(ZLIB REQUIRED)
target_link_libraries(myapp PRIVATE ZLIB::ZLIB)
REQUIRED를 붙이면 못 찾을 때 에러로 멈춥니다. 선택적으로 쓰려면 빼고 if(패키지_FOUND)로 분기합니다.
find_package(OpenSSL)
if(OpenSSL_FOUND)
target_link_libraries(myapp PRIVATE OpenSSL::SSL)
target_compile_definitions(myapp PRIVATE HAS_OPENSSL)
endif()
pkg-config 방식
find_package 모듈이 없는 라이브러리는 pkg-config로 찾습니다.
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBFOO REQUIRED libfoo)
target_include_directories(myapp PRIVATE ${LIBFOO_INCLUDE_DIRS})
target_link_libraries(myapp PRIVATE ${LIBFOO_LIBRARIES})
FetchContent — 의존성 자동 다운로드
외부 라이브러리를 git에서 직접 받아서 빌드에 포함시킵니다. 별도 설치 없이 cmake configure 시점에 자동으로 받아옵니다.
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.14.0
)
FetchContent_MakeAvailable(googletest)
FetchContent_MakeAvailable()이 다운로드 + add_subdirectory를 한 번에 처리합니다.
자주 쓰는 라이브러리 예시
include(FetchContent)
# Google Test
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.14.0
)
# nlohmann/json
FetchContent_Declare(
nlohmann_json
GIT_REPOSITORY https://github.com/nlohmann/json.git
GIT_TAG v3.11.3
)
# spdlog
FetchContent_Declare(
spdlog
GIT_REPOSITORY https://github.com/gabime/spdlog.git
GIT_TAG v1.13.0
)
# fmt
FetchContent_Declare(
fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 10.2.1
)
FetchContent_MakeAvailable(googletest nlohmann_json spdlog fmt)
target_link_libraries(myapp PRIVATE
nlohmann_json::nlohmann_json
spdlog::spdlog
fmt::fmt
)
여러 개를 FetchContent_MakeAvailable()에 한 번에 넘길 수 있습니다.
다운로드 속도 개선
매번 git clone을 하면 느릴 수 있습니다. 아래 설정으로 zip 아카이브를 받으면 빠릅니다.
FetchContent_Declare(
nlohmann_json
URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz
URL_HASH SHA256=d6c65aca6b1ed68e7a182f4757257b107ae403032760ed6ef121c9d55e81757d
)
테스트 — CTest
CMake에 내장된 테스트 프레임워크입니다. Google Test와 같이 쓰는 패턴이 가장 많습니다.
# 루트 CMakeLists.txt
enable_testing()
# tests/CMakeLists.txt
add_executable(test_parser test_parser.cpp)
target_link_libraries(test_parser PRIVATE
GTest::gtest_main
mylib
)
include(GoogleTest)
gtest_discover_tests(test_parser)
# 빌드 후 테스트 실행
cd build
ctest
ctest --output-on-failure # 실패한 테스트 상세 출력
ctest -R test_parser # 특정 테스트만
ctest --parallel 4 # 병렬 실행
설치 규칙
install(TARGETS myapp
RUNTIME DESTINATION bin # 실행 파일
LIBRARY DESTINATION lib # 동적 라이브러리
ARCHIVE DESTINATION lib # 정적 라이브러리
)
install(DIRECTORY include/
DESTINATION include
)
install(FILES config.yaml
DESTINATION etc/myapp
)
cmake --install build --prefix /usr/local
생성된 파일에 변수 삽입 — configure_file
소스 파일이나 설정 파일에 CMake 변수를 주입할 때 씁니다.
configure_file(
${CMAKE_SOURCE_DIR}/src/version.h.in
${CMAKE_BINARY_DIR}/version.h
)
// version.h.in
#pragma once
#define APP_VERSION "@PROJECT_VERSION@"
#define APP_NAME "@PROJECT_NAME@"
빌드 후 version.h에 실제 값이 들어간 파일이 생성됩니다.
컴파일러 확인과 플랫폼 분기
# 컴파일러별 옵션
if(MSVC)
target_compile_options(myapp PRIVATE /W4 /WX)
else()
target_compile_options(myapp PRIVATE -Wall -Wextra -Werror)
endif()
# 플랫폼별 분기
if(WIN32)
target_compile_definitions(myapp PRIVATE PLATFORM_WINDOWS)
elseif(APPLE)
target_compile_definitions(myapp PRIVATE PLATFORM_MACOS)
elseif(UNIX)
target_compile_definitions(myapp PRIVATE PLATFORM_LINUX)
endif()
# 컴파일러 식별
message(STATUS "컴파일러: ${CMAKE_CXX_COMPILER_ID}") # GNU, Clang, MSVC
message(STATUS "컴파일러 버전: ${CMAKE_CXX_COMPILER_VERSION}")
실용 패턴 모음
compile_commands.json 생성
LSP(clangd)나 IDE에서 사용합니다. Neovim LSP 설정에서 clangd를 쓴다면 이 파일이 있어야 정확히 동작합니다.
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
또는 configure 시 옵션으로 줍니다.
cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
build/compile_commands.json이 생성됩니다. 루트에 심볼릭 링크를 만들어두면 clangd가 자동으로 찾습니다.
ln -s build/compile_commands.json compile_commands.json
디버그 / 릴리즈 공통 설정
# 빌드 타입에 따른 정의
target_compile_definitions(myapp PRIVATE
$<$<CONFIG:Debug>:DEBUG_MODE>
$<$<CONFIG:Release>:NDEBUG>
)
# 제너레이터 표현식으로 조건부 옵션
target_compile_options(myapp PRIVATE
$<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra>
$<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra -Wno-unused-parameter>
)
$<조건:값> 형태는 제너레이터 표현식이라고 부릅니다. configure 시점이 아니라 빌드 시점에 평가됩니다.
자주 쓰는 전체 CMakeLists.txt 템플릿
cmake_minimum_required(VERSION 3.20)
project(MyProject VERSION 1.0.0 LANGUAGES CXX)
# ── 기본 설정 ─────────────────────────────────
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug CACHE STRING "빌드 타입" FORCE)
endif()
# ── 옵션 ──────────────────────────────────────
option(BUILD_TESTS "테스트 빌드" ON)
# ── 외부 의존성 ───────────────────────────────
include(FetchContent)
FetchContent_Declare(
spdlog
GIT_REPOSITORY https://github.com/gabime/spdlog.git
GIT_TAG v1.13.0
)
FetchContent_MakeAvailable(spdlog)
# ── 타겟 ──────────────────────────────────────
add_executable(myapp
src/main.cpp
src/parser.cpp
)
target_include_directories(myapp PRIVATE
${CMAKE_SOURCE_DIR}/include
)
target_link_libraries(myapp PRIVATE
spdlog::spdlog
)
target_compile_options(myapp PRIVATE
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra>
)
# ── 테스트 ────────────────────────────────────
if(BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
정리 표
| 명령어 | 용도 |
|---|---|
add_subdirectory(경로) |
서브 CMakeLists.txt 포함 |
find_package(이름 REQUIRED) |
시스템 라이브러리 탐색 |
include(FetchContent) |
FetchContent 모듈 로드 |
FetchContent_Declare(이름 ...) |
외부 의존성 선언 |
FetchContent_MakeAvailable(이름) |
다운로드 + 빌드 포함 |
enable_testing() |
CTest 활성화 |
gtest_discover_tests(타겟) |
Google Test 자동 등록 |
install(TARGETS ...) |
설치 규칙 정의 |
configure_file(in out) |
변수 주입 파일 생성 |
CMAKE_EXPORT_COMPILE_COMMANDS |
clangd용 JSON 생성 |
접근 제어 요약
| 키워드 | 현재 타겟 | 링크하는 타겟 |
|---|---|---|
PRIVATE |
✓ | ✗ |
PUBLIC |
✓ | ✓ |
INTERFACE |
✗ | ✓ |
'블로그, 컴퓨터 > Cheatsheets' 카테고리의 다른 글
| GitHub Actions 정리 (2편) — 캐싱, Matrix, 재사용, 실전 패턴 (0) | 2026.05.31 |
|---|---|
| GitHub Actions 정리 (1편) — 개념, 워크플로우 구조, 트리거 (0) | 2026.05.31 |
| CMake 정리 (1편) — 개념, CMakeLists.txt, 기본 빌드 (0) | 2026.05.30 |
| tmux 정리 (2편) — 설정, 플러그인, 실용 커스터마이징 (0) | 2026.05.29 |
| tmux 정리 (1편) — 세션, 윈도우, 패널 (0) | 2026.05.29 |