크로스 컴파일(Cross-compiling)은 한 플랫폼(호스트)에서 다른 플랫폼(타겟)을 위한 코드를 컴파일하는 과정을 의미한다. CMake는 크로스 컴파일을 위한 유연한 도구로, 복잡한 프로젝트에서의 빌드 시스템을 관리하는 데 매우 유용하다. 이 문서에서는 CMake를 사용한 크로스 컴파일 방법을 단계별로 설명한다.

크로스 컴파일의 기본 개념

크로스 컴파일을 이해하기 위해 먼저 호스트(Host)와 타겟(Target)이라는 개념을 명확히 해야 한다. 호스트는 컴파일이 실행되는 시스템을 의미하고, 타겟은 생성된 바이너리가 실행될 시스템을 의미한다. 예를 들어, Linux x86_64 시스템에서 ARM 기반의 임베디드 장치에서 실행될 코드를 컴파일하는 경우, Linux x86_64가 호스트이고 ARM이 타겟이 된다.

CMake는 이러한 크로스 컴파일을 지원하기 위해 여러 설정 옵션과 도구 체인을 제공한다. CMake는 타겟 시스템에 맞는 컴파일러, 링커, 라이브러리 경로 등을 지정할 수 있는 기능을 갖추고 있다.

CMake 도구 체인 파일(Toolchain File)

크로스 컴파일에서 가장 중요한 파일 중 하나는 도구 체인 파일(Toolchain File)이다. 도구 체인 파일은 타겟 시스템에 필요한 컴파일러, 링커, 라이브러리 경로, 시스템 루트 등을 정의한다. 도구 체인 파일은 일반적으로 .cmake 확장자를 가지며, 다음과 같은 내용을 포함할 수 있다.

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER /usr/bin/arm-linux-gnueabi-gcc)
set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++)
set(CMAKE_SYSROOT /opt/arm-sysroot)

위의 예시에서 CMAKE_SYSTEM_NAME은 타겟 시스템의 운영 체제를, CMAKE_SYSTEM_PROCESSOR는 타겟 프로세서를 지정한다. CMAKE_C_COMPILERCMAKE_CXX_COMPILER는 각각 C와 C++ 컴파일러 경로를 지정하며, CMAKE_SYSROOT는 타겟 시스템의 루트 파일 시스템 경로를 지정한다.

CMakeLists.txt 파일에서의 설정

크로스 컴파일을 위한 CMake 설정은 프로젝트의 CMakeLists.txt 파일에서 다음과 같은 방식으로 이루어진다.

cmake_minimum_required(VERSION 3.10)
project(CrossCompileExample)

if(CMAKE_CROSSCOMPILING)
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv7-a")
endif()

add_executable(hello_world main.cpp)

위의 코드에서 CMAKE_CROSSCOMPILING 변수는 크로스 컴파일 시 자동으로 정의되며, 이를 이용해 특정 플래그나 설정을 추가할 수 있다.

크로스 컴파일 실행

크로스 컴파일을 실행하려면, CMake 명령어를 실행할 때 도구 체인 파일을 지정해야 한다. 예를 들어, 다음과 같이 명령어를 실행할 수 있다.

cmake -DCMAKE_TOOLCHAIN_FILE=path/to/your_toolchain_file.cmake -B build
cmake --build build

위 명령에서 -DCMAKE_TOOLCHAIN_FILE 옵션을 통해 도구 체인 파일을 지정하며, -B 옵션을 통해 빌드 디렉토리를 지정한다. 그 후 cmake --build 명령을 통해 실제 빌드 과정을 진행한다.

타겟 라이브러리 및 의존성 처리

크로스 컴파일에서 주의해야 할 점 중 하나는 타겟 라이브러리와 의존성 관리이다. 크로스 컴파일 환경에서는 타겟 시스템의 라이브러리와 호환되는 버전을 사용해야 한다. 이를 위해 CMAKE_FIND_ROOT_PATH 등을 설정하여 타겟 라이브러리 경로를 지정할 수 있다.

set(CMAKE_FIND_ROOT_PATH /path/to/target/libs)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

위의 설정은 라이브러리와 인클루드 파일을 지정된 경로에서만 검색하도록 한다.

크로스 컴파일 환경에서의 디버깅

크로스 컴파일된 바이너리를 디버깅하려면 타겟 시스템에 맞는 디버거를 사용해야 한다. 일반적으로 gdb를 사용하며, 타겟 시스템에서 원격 디버깅을 수행할 수 있다. 이를 위해 gdbserver를 사용하거나, QEMU와 같은 에뮬레이터를 활용할 수 있다.

타겟 시스템에서 다음과 같이 gdbserver를 실행한다.

gdbserver :1234 ./your_program

호스트 시스템에서는 다음과 같이 원격 디버깅을 연결한다.

gdb ./your_program
target remote <타겟 IP>:1234

빌드 시스템과 크로스 컴파일

크로스 컴파일 환경에서는 빌드 시스템을 관리하는 것이 중요하다. CMake는 ExternalProject_Add 모듈을 이용해 타겟에 맞는 외부 프로젝트를 관리할 수 있다. 이는 빌드 시스템의 복잡성을 줄이고, 타겟에 맞는 라이브러리와 도구를 효율적으로 사용할 수 있게 해준다.

include(ExternalProject)
ExternalProject_Add(
    external_project
    SOURCE_DIR /path/to/source
    CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=path/to/your_toolchain_file.cmake
)

이 모듈은 외부 프로젝트를 자동으로 다운로드하고, 지정된 도구 체인을 이용해 빌드하는 역할을 한다.


관련 자료: - https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html - https://cmake.org/cmake/help/latest/variable/CMAKE_CROSSCOMPILING.html - https://gcc.gnu.org/onlinedocs/gccint/Configure-Terms.html