CMake 에러 완벽 해결 가이드 | 빌드 실패·의존성·링커 에러 트러블슈팅

CMake 에러 완벽 해결 가이드 | 빌드 실패·의존성·링커 에러 트러블슈팅

이 글의 핵심

CMake 빌드 에러의 근본 원인을 이해하고 체계적으로 해결하는 완벽 가이드입니다. 실무에서 자주 마주치는 에러 패턴과 검증된 해결책을 제공합니다.

실무 경험 공유: 수십 개의 프로젝트에서 CMake 빌드 이슈를 해결하면서 축적한 노하우와 디버깅 기법을 공유합니다.

들어가며: “CMake가 왜 실패하죠?”

흔한 에러 시나리오

시나리오 1: 컴파일러를 찾지 못함

CMake Error: Could not find CMAKE_CXX_COMPILER

시나리오 2: 라이브러리 링킹 실패

undefined reference to `boost::system::error_category::~error_category()'

시나리오 3: 의존성 버전 충돌

CMake Error: Could NOT find OpenSSL (missing: OPENSSL_CRYPTO_LIBRARY)

시나리오 4: 크로스 플랫폼 빌드 실패
Windows에서는 빌드되는데 Linux에서 실패합니다.


목차

  1. CMake 에러 분류 체계
  2. 컴파일러 관련 에러
  3. 라이브러리 찾기 에러
  4. 링커 에러
  5. 의존성 관리 에러
  6. 크로스 플랫폼 에러
  7. 캐시 및 설정 에러
  8. 고급 디버깅 기법
  9. 예방 및 베스트 프랙티스

1. CMake 에러 분류 체계

에러 단계별 분류

flowchart TD
    A[CMake 실행] --> B{Configure 단계}
    B -->|실패| C[Configure Error]
    B -->|성공| D{Generate 단계}
    D -->|실패| E[Generate Error]
    D -->|성공| F{Build 단계}
    F -->|실패| G[Build Error]
    F -->|성공| H[성공]
    
    C --> C1[컴파일러 찾기 실패]
    C --> C2[find_package 실패]
    C --> C3[CMakeLists.txt 문법 에러]
    
    E --> E1[Generator 에러]
    E --> E2[Toolchain 에러]
    
    G --> G1[컴파일 에러]
    G --> G2[링커 에러]
    G --> G3[의존성 에러]

에러 심각도

심각도유형예시해결 난이도
FATAL_ERROR즉시 중단CMake Error높음
SEND_ERROR계속 진행 후 실패CMake Warning (dev)중간
WARNING경고만 표시Policy CMP0xxx낮음
STATUS정보 메시지-- Found OpenSSL-

2. 컴파일러 관련 에러

에러 1: 컴파일러를 찾을 수 없음

증상:

CMake Error: Could not find CMAKE_C_COMPILER
CMake Error: Could not find CMAKE_CXX_COMPILER

원인:

  1. 컴파일러가 설치되지 않음
  2. PATH 환경 변수에 없음
  3. CMake가 잘못된 경로 참조

해결책:

Linux/macOS

# GCC 설치 확인
which gcc g++

# 없으면 설치
# Ubuntu/Debian
sudo apt-get install build-essential

# macOS
xcode-select --install

# CMake에 명시적 지정
cmake -DCMAKE_C_COMPILER=/usr/bin/gcc \
      -DCMAKE_CXX_COMPILER=/usr/bin/g++ \
      ..

Windows

# Visual Studio 설치 확인
where cl.exe

# Visual Studio Developer Command Prompt에서 실행
# 또는 CMake에 명시적 지정
cmake -G "Visual Studio 17 2022" -A x64 ..

# MinGW 사용 시
cmake -G "MinGW Makefiles" \
      -DCMAKE_C_COMPILER=C:/mingw64/bin/gcc.exe \
      -DCMAKE_CXX_COMPILER=C:/mingw64/bin/g++.exe \
      ..

에러 2: 컴파일러 버전 불일치

증상:

CMake Error: The C++ compiler does not support C++17

해결책:

# CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(MyProject)

# C++ 표준 명시
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# 컴파일러 버전 확인
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "7.0")
        message(FATAL_ERROR "GCC 7.0 이상 필요 (현재: ${CMAKE_CXX_COMPILER_VERSION})")
    endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
    if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.14")
        message(FATAL_ERROR "MSVC 2017 15.7 이상 필요")
    endif()
endif()

에러 3: 크로스 컴파일 설정 오류

증상:

CMake Error: TRY_RUN() invoked in cross-compiling mode

해결책:

# toolchain.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)

# 크로스 컴파일 시 TRY_RUN 결과 미리 설정
set(HAVE_SOME_FEATURE 1 CACHE BOOL "Feature check result")

# 사용
cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake ..

3. 라이브러리 찾기 에러

에러 4: find_package 실패

증상:

CMake Error at CMakeLists.txt:10 (find_package):
  Could NOT find Boost (missing: Boost_INCLUDE_DIR)

원인:

  1. 라이브러리가 설치되지 않음
  2. CMake가 찾을 수 없는 경로에 설치됨
  3. 버전 불일치

해결책:

방법 1: 설치 경로 명시

# Boost 예시
cmake -DBoost_ROOT=/usr/local/boost_1_75_0 \
      -DBoost_INCLUDE_DIR=/usr/local/boost_1_75_0/include \
      -DBoost_LIBRARY_DIR=/usr/local/boost_1_75_0/lib \
      ..

방법 2: CMAKE_PREFIX_PATH 사용

cmake -DCMAKE_PREFIX_PATH="/usr/local;/opt/local" ..

방법 3: CMakeLists.txt 수정

# 디버그 정보 출력
set(Boost_DEBUG ON)

# 필수가 아닌 선택적으로 변경
find_package(Boost 1.70 COMPONENTS system filesystem)
if(NOT Boost_FOUND)
    message(WARNING "Boost not found, some features disabled")
    set(ENABLE_BOOST_FEATURES OFF)
else()
    message(STATUS "Boost version: ${Boost_VERSION}")
    message(STATUS "Boost include: ${Boost_INCLUDE_DIRS}")
    message(STATUS "Boost libraries: ${Boost_LIBRARIES}")
endif()

# 대체 방법: pkg-config 사용
find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
    pkg_check_modules(BOOST QUIET boost)
    if(BOOST_FOUND)
        include_directories(${BOOST_INCLUDE_DIRS})
        link_directories(${BOOST_LIBRARY_DIRS})
    endif()
endif()

에러 5: 라이브러리 버전 충돌

증상:

CMake Error: Could NOT find OpenSSL: Found unsuitable version "1.0.2", 
but required is at least "1.1.0"

해결책:

# 버전 범위 지정
find_package(OpenSSL 1.1.0 REQUIRED)

# 또는 여러 버전 시도
find_package(OpenSSL 3.0)
if(NOT OpenSSL_FOUND)
    find_package(OpenSSL 1.1 REQUIRED)
endif()

# 버전 정보 출력
message(STATUS "OpenSSL version: ${OPENSSL_VERSION}")
message(STATUS "OpenSSL include: ${OPENSSL_INCLUDE_DIR}")
message(STATUS "OpenSSL libraries: ${OPENSSL_LIBRARIES}")

에러 6: Config vs Module 모드 혼동

증상:

CMake Warning: Could not find a package configuration file provided by "MyLib"

이해:

  • Config 모드: MyLibConfig.cmake 파일 찾기 (라이브러리 제공)
  • Module 모드: FindMyLib.cmake 파일 찾기 (CMake 제공)

해결책:

# Config 모드 강제
find_package(MyLib CONFIG REQUIRED)

# Module 모드 강제
find_package(MyLib MODULE REQUIRED)

# 커스텀 Find 모듈 경로 추가
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")

# 수동으로 찾기
find_path(MYLIB_INCLUDE_DIR mylib.h
    PATHS /usr/local/include /opt/local/include
)
find_library(MYLIB_LIBRARY mylib
    PATHS /usr/local/lib /opt/local/lib
)

if(MYLIB_INCLUDE_DIR AND MYLIB_LIBRARY)
    set(MYLIB_FOUND TRUE)
    add_library(MyLib::MyLib UNKNOWN IMPORTED)
    set_target_properties(MyLib::MyLib PROPERTIES
        IMPORTED_LOCATION "${MYLIB_LIBRARY}"
        INTERFACE_INCLUDE_DIRECTORIES "${MYLIB_INCLUDE_DIR}"
    )
endif()

4. 링커 에러

에러 7: undefined reference

증상:

undefined reference to `boost::system::error_category::~error_category()'
undefined reference to `pthread_create'

원인:

  1. 라이브러리가 링크되지 않음
  2. 링크 순서 오류
  3. 정적/동적 라이브러리 혼용

해결책:

방법 1: 명시적 링크

# 라이브러리 링크
target_link_libraries(myapp PRIVATE
    Boost::system
    Boost::filesystem
    pthread
)

# 또는 직접 지정
target_link_libraries(myapp PRIVATE
    ${Boost_LIBRARIES}
    pthread
)

방법 2: 링크 순서 조정

# ❌ 잘못된 순서
target_link_libraries(myapp
    lib_a
    lib_b  # lib_b가 lib_a에 의존
)

# ✅ 올바른 순서 (의존성이 나중에)
target_link_libraries(myapp
    lib_b
    lib_a
)

방법 3: 전체 아카이브 링크

# 정적 라이브러리의 모든 심볼 포함
if(UNIX)
    target_link_libraries(myapp PRIVATE
        -Wl,--whole-archive
        mystaticlib
        -Wl,--no-whole-archive
    )
elseif(APPLE)
    target_link_libraries(myapp PRIVATE
        -Wl,-force_load
        mystaticlib
    )
elseif(MSVC)
    target_link_libraries(myapp PRIVATE
        /WHOLEARCHIVE:mystaticlib
    )
endif()

에러 8: 중복 심볼 (duplicate symbol)

증상:

duplicate symbol '_myFunction' in:
    obj1.o
    obj2.o

원인:

  1. 헤더에 함수 정의 (inline 없이)
  2. 같은 소스 파일이 여러 번 컴파일됨
  3. 라이브러리 중복 링크

해결책:

// ❌ 잘못된 헤더 (mylib.h)
void myFunction() {  // 여러 번 정의됨
    // ...
}

// ✅ 올바른 헤더
inline void myFunction() {  // inline 추가
    // ...
}

// 또는 선언만
void myFunction();  // 정의는 .cpp에
# 중복 링크 제거
target_link_libraries(myapp PRIVATE
    mylib
    # mylib  # 중복 제거
)

# 또는 INTERFACE로 전파
add_library(mylib INTERFACE)
target_link_libraries(mylib INTERFACE
    dependency
)

target_link_libraries(myapp PRIVATE
    mylib  # dependency는 자동 포함
)

에러 9: 라이브러리 찾을 수 없음 (runtime)

증상:

./myapp: error while loading shared libraries: libmylib.so.1: 
cannot open shared object file: No such file or directory

해결책:

Linux

# 방법 1: LD_LIBRARY_PATH 설정
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
./myapp

# 방법 2: ldconfig 업데이트
sudo echo "/usr/local/lib" > /etc/ld.so.conf.d/mylib.conf
sudo ldconfig

# 방법 3: RPATH 설정 (CMake)
# CMakeLists.txt
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

# 또는 $ORIGIN 사용 (실행 파일 기준)
set_target_properties(myapp PROPERTIES
    INSTALL_RPATH "$ORIGIN/../lib"
)

macOS

# DYLD_LIBRARY_PATH 설정
export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH

# 또는 install_name_tool 사용
install_name_tool -change \
    libmylib.dylib \
    @rpath/libmylib.dylib \
    myapp

Windows

# DLL을 실행 파일과 같은 디렉토리에 복사
add_custom_command(TARGET myapp POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        $<TARGET_FILE:mylib>
        $<TARGET_FILE_DIR:myapp>
)

5. 의존성 관리 에러

에러 10: FetchContent 실패

증상:

CMake Error: Failed to download https://github.com/user/repo/archive/v1.0.tar.gz

해결책:

include(FetchContent)

# 타임아웃 증가
set(FETCHCONTENT_QUIET OFF)

FetchContent_Declare(
    mylib
    GIT_REPOSITORY https://github.com/user/mylib.git
    GIT_TAG v1.0.0
    GIT_SHALLOW TRUE  # 히스토리 없이 빠르게
    TIMEOUT 60  # 타임아웃 60초
)

# 에러 처리
FetchContent_MakeAvailable(mylib)
if(NOT mylib_POPULATED)
    message(FATAL_ERROR "Failed to fetch mylib")
endif()

# 또는 수동으로
FetchContent_GetProperties(mylib)
if(NOT mylib_POPULATED)
    FetchContent_Populate(mylib)
    add_subdirectory(${mylib_SOURCE_DIR} ${mylib_BINARY_DIR})
endif()

에러 11: ExternalProject 빌드 실패

증상:

CMake Error: External project failed to build

해결책:

include(ExternalProject)

ExternalProject_Add(
    mylib_external
    URL https://example.com/mylib-1.0.tar.gz
    URL_HASH SHA256=abc123...
    
    # 빌드 설정
    CMAKE_ARGS
        -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
        -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/external
        -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
        -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
    
    # 로그 활성화
    LOG_DOWNLOAD ON
    LOG_CONFIGURE ON
    LOG_BUILD ON
    LOG_INSTALL ON
    
    # 병렬 빌드
    BUILD_COMMAND ${CMAKE_COMMAND} --build . --parallel
)

# 의존성 추가
add_dependencies(myapp mylib_external)

# 라이브러리 링크
target_link_libraries(myapp PRIVATE
    ${CMAKE_BINARY_DIR}/external/lib/libmylib.a
)
target_include_directories(myapp PRIVATE
    ${CMAKE_BINARY_DIR}/external/include
)

에러 12: vcpkg/Conan 통합 실패

증상:

CMake Error: Could not find vcpkg toolchain file

해결책:

vcpkg

# vcpkg 설치
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh  # Linux/macOS
# .\bootstrap-vcpkg.bat  # Windows

# 패키지 설치
./vcpkg install boost openssl

# CMake 통합
cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/vcpkg/scripts/buildsystems/vcpkg.cmake ..
# CMakeLists.txt
if(DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
    set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
        CACHE STRING "")
endif()

project(MyProject)

find_package(Boost REQUIRED)
find_package(OpenSSL REQUIRED)

Conan

# conanfile.txt
[requires]
boost/1.75.0
openssl/1.1.1k

[generators]
cmake_find_package

# 설치
conan install . --build=missing

# CMake
cmake -DCMAKE_PREFIX_PATH=$(pwd) ..

6. 크로스 플랫폼 에러

에러 13: 경로 구분자 문제

증상:

CMake Error: File not found: C:\path\to\file (Windows)
CMake Error: File not found: /path/to/file (Linux)

해결책:

# ❌ 하드코딩된 경로
set(MY_PATH "C:/Users/me/project")

# ✅ 플랫폼 독립적
set(MY_PATH "${CMAKE_SOURCE_DIR}/subdir")

# ✅ 경로 결합
file(TO_CMAKE_PATH "${MY_PATH}" MY_PATH)

# ✅ 네이티브 경로로 변환
file(TO_NATIVE_PATH "${MY_PATH}" MY_NATIVE_PATH)

# ✅ 파일 복사 (자동 경로 변환)
configure_file(
    "${CMAKE_SOURCE_DIR}/config.h.in"
    "${CMAKE_BINARY_DIR}/config.h"
)

에러 14: 플랫폼별 컴파일 옵션 충돌

증상:

cl.exe: error: unknown argument: '-Wall'
gcc: error: unrecognized command line option '/W4'

해결책:

# 플랫폼별 옵션
if(MSVC)
    target_compile_options(myapp PRIVATE
        /W4  # 경고 레벨 4
        /WX  # 경고를 에러로
        /permissive-  # 표준 준수
    )
else()
    target_compile_options(myapp PRIVATE
        -Wall
        -Wextra
        -Werror
        -pedantic
    )
endif()

# 또는 generator expression 사용
target_compile_options(myapp PRIVATE
    $<$<CXX_COMPILER_ID:MSVC>:/W4>
    $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall>
)

# 플랫폼별 정의
if(WIN32)
    target_compile_definitions(myapp PRIVATE
        _WIN32_WINNT=0x0601  # Windows 7
        NOMINMAX  # min/max 매크로 비활성화
    )
elseif(UNIX)
    target_compile_definitions(myapp PRIVATE
        _GNU_SOURCE
    )
endif()

에러 15: 라이브러리 확장자 차이

증상:

CMake Error: Cannot find libmylib.so (Linux)
CMake Error: Cannot find mylib.dll (Windows)

해결책:

# ❌ 확장자 하드코딩
find_library(MYLIB_LIBRARY mylib.so)

# ✅ 확장자 없이
find_library(MYLIB_LIBRARY mylib)

# ✅ 플랫폼별 처리
if(WIN32)
    set(LIB_SUFFIX ".dll")
elseif(APPLE)
    set(LIB_SUFFIX ".dylib")
else()
    set(LIB_SUFFIX ".so")
endif()

# ✅ CMake 변수 사용
set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "")
set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a" ".dll" ".lib")

7. 캐시 및 설정 에러

에러 16: 캐시된 설정으로 인한 문제

증상:

CMake Error: Variable was cached but is now different

해결책:

# 방법 1: 캐시 삭제
rm CMakeCache.txt
rm -rf CMakeFiles/

# 방법 2: 완전히 새로 빌드
rm -rf build/
mkdir build && cd build
cmake ..

# 방법 3: CMake GUI에서 캐시 삭제
cmake-gui .
# File -> Delete Cache
# 캐시 변수 강제 업데이트
set(MY_VAR "new_value" CACHE STRING "Description" FORCE)

# 캐시 변수 초기화
unset(MY_VAR CACHE)

# 조건부 캐시 설정
if(NOT DEFINED MY_VAR)
    set(MY_VAR "default" CACHE STRING "Description")
endif()

에러 17: Generator 불일치

증상:

CMake Error: Error: generator : Ninja
Does not match the generator used previously: Unix Makefiles

해결책:

# 빌드 디렉토리 삭제 후 재생성
rm -rf build/
mkdir build && cd build

# Generator 명시
cmake -G "Ninja" ..
# 또는
cmake -G "Unix Makefiles" ..
# 또는
cmake -G "Visual Studio 17 2022" ..

# 사용 가능한 Generator 목록
cmake --help

에러 18: Policy 경고

증상:

CMake Warning (dev): Policy CMP0054 is not set

해결책:

# 최소 버전 명시 (자동으로 policy 설정)
cmake_minimum_required(VERSION 3.15)

# 명시적 policy 설정
cmake_policy(SET CMP0054 NEW)

# 여러 policy 설정
if(POLICY CMP0054)
    cmake_policy(SET CMP0054 NEW)
endif()

# Policy 범위 설정
cmake_policy(PUSH)
cmake_policy(SET CMP0054 OLD)
# ... 코드 ...
cmake_policy(POP)

8. 고급 디버깅 기법

디버깅 옵션 활성화

# 상세 출력
cmake --debug-output ..

# 변수 추적
cmake --trace ..

# 특정 변수만 추적
cmake --trace-expand --trace-source=CMakeLists.txt ..

# 로그 레벨 설정
cmake --log-level=DEBUG ..

CMakeLists.txt 디버깅

# 변수 출력
message(STATUS "CMAKE_SOURCE_DIR: ${CMAKE_SOURCE_DIR}")
message(STATUS "CMAKE_BINARY_DIR: ${CMAKE_BINARY_DIR}")
message(STATUS "CMAKE_CXX_COMPILER: ${CMAKE_CXX_COMPILER}")

# 모든 변수 출력
get_cmake_property(_variableNames VARIABLES)
foreach(_variableName ${_variableNames})
    message(STATUS "${_variableName}=${${_variableName}}")
endforeach()

# 타겟 속성 출력
get_target_property(MYAPP_SOURCES myapp SOURCES)
message(STATUS "myapp sources: ${MYAPP_SOURCES}")

get_target_property(MYAPP_LINK_LIBS myapp LINK_LIBRARIES)
message(STATUS "myapp link libraries: ${MYAPP_LINK_LIBS}")

# 조건부 디버깅
option(CMAKE_DEBUG "Enable CMake debugging" OFF)
if(CMAKE_DEBUG)
    message(STATUS "=== Debug Info ===")
    message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
    message(STATUS "C++ flags: ${CMAKE_CXX_FLAGS}")
    message(STATUS "Link flags: ${CMAKE_EXE_LINKER_FLAGS}")
endif()

빌드 로그 분석

# 상세 빌드 로그
cmake --build . --verbose

# 또는 make 사용 시
make VERBOSE=1

# Ninja 사용 시
ninja -v

# 로그 파일로 저장
cmake --build . --verbose > build.log 2>&1

# 특정 타겟만 빌드
cmake --build . --target myapp --verbose

링커 명령 확인

# 링커 명령 출력
set(CMAKE_VERBOSE_MAKEFILE ON)

# 또는
set_target_properties(myapp PROPERTIES
    LINK_WHAT_YOU_USE TRUE
)

# 링커 맵 파일 생성
if(UNIX)
    target_link_options(myapp PRIVATE
        -Wl,-Map=myapp.map
    )
elseif(MSVC)
    target_link_options(myapp PRIVATE
        /MAP:myapp.map
    )
endif()

9. 예방 및 베스트 프랙티스

1) 견고한 CMakeLists.txt 작성

# 최소 버전 명시 (최신 버전 권장)
cmake_minimum_required(VERSION 3.15)

# 프로젝트 정보
project(MyProject
    VERSION 1.0.0
    DESCRIPTION "My awesome project"
    LANGUAGES CXX
)

# C++ 표준 설정
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# 빌드 타입 기본값
if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()

# 출력 디렉토리 통일
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

# 옵션 제공
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
option(BUILD_TESTS "Build tests" ON)
option(ENABLE_WARNINGS "Enable compiler warnings" ON)

# 의존성 찾기 (에러 처리 포함)
find_package(Boost 1.70 COMPONENTS system filesystem)
if(NOT Boost_FOUND)
    message(FATAL_ERROR "Boost not found. Install: sudo apt-get install libboost-all-dev")
endif()

# 타겟 정의
add_executable(myapp src/main.cpp)

# 타겟 속성 설정
target_include_directories(myapp PRIVATE
    ${CMAKE_SOURCE_DIR}/include
    ${Boost_INCLUDE_DIRS}
)

target_link_libraries(myapp PRIVATE
    Boost::system
    Boost::filesystem
)

# 컴파일 옵션
if(ENABLE_WARNINGS)
    if(MSVC)
        target_compile_options(myapp PRIVATE /W4)
    else()
        target_compile_options(myapp PRIVATE -Wall -Wextra)
    endif()
endif()

# 설치 규칙
install(TARGETS myapp
    RUNTIME DESTINATION bin
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
)

2) 의존성 관리 전략

# 방법 1: FetchContent (간단, 빠름)
include(FetchContent)
FetchContent_Declare(
    googletest
    GIT_REPOSITORY https://github.com/google/googletest.git
    GIT_TAG release-1.11.0
)
FetchContent_MakeAvailable(googletest)

# 방법 2: find_package + Fallback
find_package(fmt 8.0)
if(NOT fmt_FOUND)
    message(STATUS "fmt not found, fetching...")
    FetchContent_Declare(
        fmt
        GIT_REPOSITORY https://github.com/fmtlib/fmt.git
        GIT_TAG 8.1.1
    )
    FetchContent_MakeAvailable(fmt)
endif()

# 방법 3: 조건부 의존성
if(ENABLE_FEATURE_X)
    find_package(LibX REQUIRED)
    target_link_libraries(myapp PRIVATE LibX::LibX)
    target_compile_definitions(myapp PRIVATE FEATURE_X_ENABLED)
endif()

3) 에러 예방 체크리스트

# 1. 변수 존재 확인
if(NOT DEFINED MY_VAR)
    message(FATAL_ERROR "MY_VAR is not defined")
endif()

# 2. 파일 존재 확인
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/config.h.in")
    message(FATAL_ERROR "config.h.in not found")
endif()

# 3. 타겟 존재 확인
if(TARGET mylib)
    target_link_libraries(myapp PRIVATE mylib)
else()
    message(WARNING "mylib target not found")
endif()

# 4. 컴파일러 기능 확인
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-std=c++17 HAS_CXX17)
if(NOT HAS_CXX17)
    message(FATAL_ERROR "Compiler does not support C++17")
endif()

# 5. 헤더 파일 확인
include(CheckIncludeFileCXX)
check_include_file_cxx("filesystem" HAS_FILESYSTEM)
if(NOT HAS_FILESYSTEM)
    message(FATAL_ERROR "<filesystem> header not found")
endif()

# 6. 함수 존재 확인
include(CheckFunctionExists)
check_function_exists(pthread_create HAS_PTHREAD)
if(NOT HAS_PTHREAD)
    message(FATAL_ERROR "pthread_create not found")
endif()

4) 빌드 스크립트 자동화

#!/bin/bash
# build.sh

set -e  # 에러 시 중단

# 색상 정의
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'  # No Color

# 함수 정의
error() {
    echo -e "${RED}Error: $1${NC}" >&2
    exit 1
}

success() {
    echo -e "${GREEN}$1${NC}"
}

# 의존성 확인
command -v cmake >/dev/null 2>&1 || error "CMake not found"
command -v ninja >/dev/null 2>&1 || error "Ninja not found"

# 빌드 디렉토리 생성
BUILD_DIR="build"
rm -rf "$BUILD_DIR"
mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"

# CMake 설정
cmake -G Ninja \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
    .. || error "CMake configuration failed"

# 빌드
cmake --build . --parallel || error "Build failed"

# 테스트
if [ -f "bin/myapp_test" ]; then
    ./bin/myapp_test || error "Tests failed"
    success "All tests passed!"
fi

success "Build completed successfully!"

정리

핵심 요약

  1. 에러 분류

    • Configure 에러: 컴파일러, find_package 실패
    • Generate 에러: Generator, Toolchain 문제
    • Build 에러: 컴파일, 링커 에러
  2. 주요 에러 패턴

    • 컴파일러 찾기 실패 → PATH 확인, 명시적 지정
    • find_package 실패 → 설치 경로 지정, CMAKE_PREFIX_PATH
    • 링커 에러 → target_link_libraries, 순서 확인
    • 크로스 플랫폼 → 플랫폼별 분기, generator expression
  3. 디버깅 기법

    • --debug-output, --trace 옵션
    • message(STATUS) 활용
    • VERBOSE 빌드 로그
  4. 예방 전략

    • 명확한 에러 메시지
    • 의존성 버전 명시
    • 플랫폼 독립적 코드
    • 자동화된 빌드 스크립트

빠른 참조

# 캐시 삭제
rm CMakeCache.txt

# 상세 출력
cmake --debug-output ..

# 빌드 로그
cmake --build . --verbose

# Generator 변경
cmake -G "Ninja" ..

# 변수 지정
cmake -DCMAKE_PREFIX_PATH=/usr/local ..

# 컴파일러 지정
cmake -DCMAKE_CXX_COMPILER=g++-11 ..

체크리스트

  • CMake 최소 버전 명시
  • C++ 표준 설정
  • 의존성 버전 명시
  • 플랫폼별 분기 처리
  • 에러 메시지 명확히
  • 빌드 스크립트 자동화
  • 캐시 문제 시 삭제
  • VERBOSE 로그 확인

참고 자료

한 줄 요약: CMake 에러는 Configure/Generate/Build 단계로 분류되며, 컴파일러/라이브러리 경로 명시, 캐시 삭제, VERBOSE 로그 확인으로 대부분 해결 가능하고, 플랫폼 독립적 코드와 명확한 에러 메시지로 예방할 수 있습니다.

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3