모던 CMake를 활용하여 효율적인 C++ 프로젝트 빌드 시스템을 구축하는 방법을 계속해서 알아보겠습니다. 이번 글에서는 외부 프로젝트와의 통합 및 CMake의 ExternalProject 모듈을 활용하여 서드 파티 라이브러리나 의존성을 관리하는 방법에 대해 다루겠습니다. 이를 통해 프로젝트의 확장성과 유지보수성을 높일 수 있습니다.
외부 프로젝트 통합의 필요성
현대 소프트웨어 개발에서는 다양한 오픈 소스 라이브러리와 서드 파티 코드를 활용하는 것이 일반적입니다. 이러한 외부 의존성을 효율적으로 관리하고 빌드 시스템에 통합하는 것은 프로젝트의 성공에 중요한 요소입니다.
- 일관된 빌드 환경 유지: 모든 개발자와 CI/CD 시스템에서 동일한 버전의 라이브러리를 사용하도록 보장합니다.
- 의존성 관리의 편의성: 라이브러리의 설치 및 설정 과정을 자동화하여 개발 생산성을 향상시킵니다.
- 프로젝트의 이동성 증가: 새로운 환경에서도 쉽게 빌드할 수 있도록 지원합니다.
CMake의 ExternalProject 모듈
CMake는 외부 프로젝트를 빌드하고 관리하기 위한 ExternalProject 모듈을 제공합니다. 이를 활용하면 외부 라이브러리를 자동으로 다운로드, 빌드, 설치하여 프로젝트에 통합할 수 있습니다.
ExternalProject_Add 함수
ExternalProject_Add 함수를 사용하여 외부 프로젝트를 추가할 수 있습니다.
include(ExternalProject)
ExternalProject_Add(
프로젝트_이름
URL 라이브러리_소스_주소
PREFIX 라이브러리_빌드_디렉토리
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR> 추가_옵션
)
- 프로젝트_이름: 외부 프로젝트의 이름입니다.
- URL: 소스 코드를 다운로드할 위치입니다. Git 리포지토리, 압축 파일 등 다양한 소스가 가능합니다.
- PREFIX: 빌드 및 설치 디렉토리를 지정합니다.
- CMAKE_ARGS: 외부 프로젝트의 CMake 설정에 전달할 인자들입니다.
예제: GoogleTest 통합
GoogleTest를 ExternalProject를 통해 통합해보겠습니다.
최상위 CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(MyProject VERSION 1.0.0)
include(ExternalProject)
# GoogleTest 외부 프로젝트 추가
ExternalProject_Add(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.11.0
PREFIX ${CMAKE_BINARY_DIR}/googletest
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/googletest/install
)
# GoogleTest의 설치 경로 설정
set(GTEST_ROOT ${CMAKE_BINARY_DIR}/googletest/install)
# 의존성 설정
add_dependencies(MyApp googletest)
# MyApp 타겟 설정
add_executable(MyApp src/main.cpp)
# GoogleTest 라이브러리 링크
target_include_directories(MyApp PRIVATE ${GTEST_ROOT}/include)
target_link_libraries(MyApp PRIVATE ${GTEST_ROOT}/lib/libgtest.a)
설명
- ExternalProject_Add를 사용하여 GoogleTest를 다운로드하고 빌드합니다.
- GIT_REPOSITORY와 GIT_TAG를 지정하여 특정 버전의 코드를 가져옵니다.
- CMAKE_INSTALL_PREFIX를 설정하여 설치 경로를 지정합니다.
- add_dependencies를 통해 MyApp이 googletest에 의존하도록 합니다.
- 빌드 시 자동으로 GoogleTest를 빌드하고, MyApp에 링크합니다.
FetchContent 모듈의 활용
CMake 3.11부터 제공되는 FetchContent 모듈은 ExternalProject의 단순화된 버전으로, 외부 프로젝트를 보다 쉽게 가져올 수 있습니다.
FetchContent 사용법
include(FetchContent)
FetchContent_Declare(
프로젝트_이름
GIT_REPOSITORY 라이브러리_소스_주소
GIT_TAG 라이브러리_버전
)
FetchContent_MakeAvailable(프로젝트_이름)
- FetchContent_Declare로 외부 프로젝트를 선언합니다.
- FetchContent_MakeAvailable로 프로젝트를 다운로드하고 빌드합니다.
예제: SPDLOG 통합
고성능 로깅 라이브러리인 SPDLOG를 FetchContent를 통해 통합해보겠습니다.
CMakeLists.txt 업데이트
cmake_minimum_required(VERSION 3.15)
project(MyProject VERSION 1.0.0)
include(FetchContent)
# SPDLOG 가져오기
FetchContent_Declare(
spdlog
GIT_REPOSITORY https://github.com/gabime/spdlog.git
GIT_TAG v1.9.2
)
FetchContent_MakeAvailable(spdlog)
# MyApp 타겟 설정
add_executable(MyApp src/main.cpp)
# SPDLOG 링크
target_link_libraries(MyApp PRIVATE spdlog::spdlog)
설명
- FetchContent_Declare를 통해 SPDLOG를 가져옵니다.
- FetchContent_MakeAvailable로 SPDLOG를 프로젝트에 포함시킵니다.
- spdlog::spdlog 인터페이스 라이브러리를 통해 MyApp에 링크합니다.
CPM.cmake를 통한 패키지 관리
CPM.cmake는 CMake를 위한 패키지 관리자 역할을 하는 스크립트로, 외부 라이브러리를 쉽게 가져오고 캐싱하여 빌드 시간을 단축합니다.
CPM.cmake 설정
먼저 CPM.cmake를 프로젝트에 포함시킵니다.
include(cmake/CPM.cmake)
예제: Eigen 통합
선형대수 라이브러리인 Eigen을 CPM.cmake를 통해 통합해보겠습니다.
CMakeLists.txt 업데이트
cmake_minimum_required(VERSION 3.15)
project(MyProject VERSION 1.0.0)
include(cmake/CPM.cmake)
# Eigen 가져오기
CPMAddPackage(
NAME eigen
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
GIT_TAG 3.4.0
)
# MyApp 타겟 설정
add_executable(MyApp src/main.cpp)
# Eigen 링크
target_link_libraries(MyApp PRIVATE Eigen3::Eigen)
설명
- CPMAddPackage를 사용하여 Eigen을 가져옵니다.
- Eigen3::Eigen 타겟을 통해 MyApp에 링크합니다.
외부 프로젝트의 빌드 옵션 설정
외부 프로젝트를 가져올 때 특정 빌드 옵션을 설정해야 할 경우가 있습니다.
예제: 외부 프로젝트 빌드 옵션 설정
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.11.0
)
# 빌드 옵션 설정
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
- 외부 프로젝트의 CMake 옵션을 설정하기 위해 변수를 지정합니다.
- CACHE BOOL "" FORCE를 사용하여 값을 강제로 설정합니다.
외부 프로젝트의 의존성 관리
외부 프로젝트 간의 의존성을 관리하여 빌드 순서를 제어할 수 있습니다.
예제: 의존성 설정
ExternalProject_Add(
libA
GIT_REPOSITORY https://github.com/example/libA.git
GIT_TAG v1.0.0
PREFIX ${CMAKE_BINARY_DIR}/libA
)
ExternalProject_Add(
libB
GIT_REPOSITORY https://github.com/example/libB.git
GIT_TAG v2.0.0
PREFIX ${CMAKE_BINARY_DIR}/libB
DEPENDS libA
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/libB/install
-DlibA_DIR=${CMAKE_BINARY_DIR}/libA/install/lib/cmake/libA
)
- DEPENDS를 사용하여 libB가 libA에 의존하도록 설정합니다.
- CMAKE_ARGS를 통해 libA의 경로를 libB에 전달합니다.
서드 파티 라이브러리의 버전 관리
외부 라이브러리의 버전을 명시적으로 관리하여 호환성을 유지합니다.
Git 서브모듈 사용
- 외부 라이브러리를 Git 서브모듈로 포함하여 특정 커밋이나 태그를 고정합니다.
- git submodule add https://github.com/example/libC.git libs/libC
패키지 버전 고정
- FetchContent나 CPM.cmake를 사용할 때 GIT_TAG를 통해 버전을 고정합니다.
- 버전 업그레이드 시 테스트를 통해 호환성을 검증합니다.
외부 프로젝트의 설치 및 패키징
외부 라이브러리를 프로젝트의 설치 및 패키징 과정에 포함시킬 수 있습니다.
설치 설정
install(TARGETS MyApp
RUNTIME DESTINATION bin)
install(DIRECTORY ${GTEST_ROOT}/lib/
DESTINATION lib)
install(DIRECTORY ${GTEST_ROOT}/include/
DESTINATION include)
- 외부 라이브러리의 바이너리와 헤더를 설치 경로에 복사합니다.
CPack과의 통합
- 이전 글에서 다룬 CPack을 사용하여 외부 라이브러리를 포함한 패키지를 생성합니다.
- 설치 경로에 복사된 외부 라이브러리 파일들이 패키지에 포함됩니다.
주의사항과 베스트 프랙티스
- 라이선스 확인: 외부 라이브러리의 라이선스를 확인하고 프로젝트와의 호환성을 검토합니다.
- 빌드 시간 관리: 외부 라이브러리의 빌드 시간이 길어질 수 있으므로, 필요에 따라 바이너리를 캐싱하거나 프리빌트 라이브러리를 사용합니다.
- 의존성 충돌 방지: 동일한 라이브러리의 다른 버전이 중복으로 포함되지 않도록 주의합니다.
- 네트워크 의존성 최소화: 빌드 과정에서 네트워크에 의존하지 않도록 소스 코드를 미리 다운로드하거나 캐싱합니다.
결론
이번 글에서는 CMake를 사용하여 외부 프로젝트와 라이브러리를 통합하고 활용하는 방법에 대해 알아보았습니다. ExternalProject, FetchContent, CPM.cmake 등의 도구를 활용하여 외부 의존성을 효율적으로 관리하고, 프로젝트의 확장성과 유지보수성을 높일 수 있습니다.
'개발 이야기 > CMake' 카테고리의 다른 글
[모던 CMake] CUDA 프로젝트 구성과 빌드 (0) | 2024.12.10 |
---|---|
[모던 CMake] Python 바인딩 프로젝트 구성과 설정 (0) | 2024.12.09 |
[모던 CMake] 대규모 프로젝트에서의 베스트 프랙티스 (0) | 2024.12.07 |
[모던 CMake] 코드 분석 도구와 포매터 통합 (2) | 2024.12.06 |
[모던 CMake] 프로젝트 설정 및 옵션 관리 (0) | 2024.12.05 |