# CMake를 이용한 크로스 컴파일

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

#### 크로스 컴파일의 기본 개념

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

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

#### CMake 도구 체인 파일(Toolchain File)

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

```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_COMPILER`와 `CMAKE_CXX_COMPILER`는 각각 C와 C++ 컴파일러 경로를 지정하며, `CMAKE_SYSROOT`는 타겟 시스템의 루트 파일 시스템 경로를 지정한다.

#### CMakeLists.txt 파일에서의 설정

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

```cmake
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 명령어를 실행할 때 도구 체인 파일을 지정해야 한다. 예를 들어, 다음과 같이 명령어를 실행할 수 있다.

```bash
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` 등을 설정하여 타겟 라이브러리 경로를 지정할 수 있다.

```cmake
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를 실행한다.

```bash
gdbserver :1234 ./your_program
```

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

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

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

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

```cmake
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>
