aarch64 크로스 컴파일 CMake, toolchain 파일은 어떻게 쓰나
aarch64 등 타깃 보드용으로 크로스 컴파일할 때는 CMAKE_TOOLCHAIN_FILE로 타깃 시스템 정보와 컴파일러를 지정하고, CMAKE_SYSROOT로 타깃 루트 파일 시스템을 잡은 뒤, CMAKE_FIND_ROOT_PATH_MODE_* 변수로 find_package() 등이 호스트 라이브러리를 잘못 집어오는 문제를 막습니다.
이 글은 CMake 공식 문서(cmake-toolchains 매뉴얼 및 관련 변수 문서)를 기준으로 정리한 일반 설명이며, 실제 툴체인·SDK 경로는 사용 중인 크로스 컴파일러 배포판에 맞게 바꿔야 합니다.
toolchain 파일에 무엇을 넣나?
한 줄 답: CMAKE_SYSTEM_NAME으로 크로스 컴파일 모드를 켜고, CMAKE_SYSTEM_PROCESSOR와 CMAKE_C_COMPILER/CMAKE_CXX_COMPILER로 타깃 아키텍처와 컴파일러를 지정합니다.
CMake는 기본적으로 지금 빌드가 실행되는 호스트 머신을 대상으로 빌드시스템을 구성합니다. 크로스 컴파일이 필요하면 CMAKE_TOOLCHAIN_FILE 캐시 변수로 별도의 .cmake 파일을 가리켜 설정 단계 초반에 이 값들을 미리 채워 넣어야 합니다.
CMAKE_SYSTEM_NAME에 타깃 운영체제 이름(예: Linux)을 넣으면, 이 값이 호스트 시스템 이름과 다르다는 것만으로 CMake는 크로스 컴파일 모드로 동작합니다. 여기에 CMAKE_SYSTEM_PROCESSOR로 타깃 아키텍처(aarch64)를 지정하고, CMAKE_C_COMPILER·CMAKE_CXX_COMPILER에 각각 aarch64-linux-gnu-gcc, aarch64-linux-gnu-g++ 같은 크로스 컴파일러 경로를 넣습니다.
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)
이 4줄만으로 CMake는 “지금 만들 결과물은 호스트가 아니라 aarch64 타깃용”이라는 사실을 인식하고, 이후 컴파일러 탐색이나 라이브러리 탐색 로직을 크로스 컴파일 방식으로 바꿉니다.
sysroot는 어떻게 맞추나?
한 줄 답: CMAKE_SYSROOT에 타깃 루트 파일 시스템 경로를 지정하면, CMake가 컴파일러·링커에 --sysroot=<path> 플래그를 자동으로 넘깁니다.
크로스 컴파일러 자체는 호스트 머신에서 실행되지만, 헤더와 라이브러리는 타깃 환경 것을 써야 합니다. CMAKE_SYSROOT는 이 타깃 루트 파일 시스템의 위치를 CMake에게 알려주는 변수입니다.
set(CMAKE_SYSROOT /opt/aarch64-sysroot)
이 값을 설정하면 CMake는 컴파일러와 링커를 호출할 때 --sysroot=/opt/aarch64-sysroot를 자동으로 붙여줍니다. 그 결과 컴파일러는 기본 경로인 호스트의 /usr/include, /usr/lib 대신 지정한 sysroot 안의 include·lib를 먼저 찾게 됩니다.
sysroot는 실제로 타깃 보드에서 복사해 오거나, 사용 중인 크로스 컴파일 SDK가 함께 제공하는 루트 파일 시스템 디렉터리를 그대로 가리키면 됩니다. 경로가 잘못되면 헤더를 못 찾는 오류로 바로 드러나므로 확인이 비교적 쉽습니다.
find_package가 호스트 라이브러리를 집을 때 어떻게 막나?
한 줄 답: CMAKE_FIND_ROOT_PATH_MODE_PROGRAM은 NEVER로, LIBRARY·INCLUDE·PACKAGE는 ONLY로 설정해 검색 범위를 완전히 분리합니다.
크로스 컴파일에서 가장 흔히 겪는 문제는 find_package()나 find_library()가 sysroot가 아니라 호스트 시스템(예: x86_64) 경로에서 라이브러리를 찾아버리는 현상입니다. 이 문제는 CMAKE_FIND_ROOT_PATH_MODE_* 변수 네 가지로 검색 대상을 명확히 나눠서 막습니다.
실행 파일과 라이브러리는 검색 범위가 달라야 합니다
빌드 중에 실행해야 하는 코드 생성기 같은 프로그램은 호스트에서 돌아가야 하므로, CMAKE_FIND_ROOT_PATH_MODE_PROGRAM은 NEVER로 두어 호스트 경로에서만 찾도록 합니다. 반대로 링크에 쓸 라이브러리·헤더·패키지 설정은 타깃 sysroot 안에만 있어야 하므로, 나머지 세 변수는 ONLY로 지정해 sysroot 바깥은 아예 보지 않게 만듭니다.
set(CMAKE_FIND_ROOT_PATH /opt/aarch64-sysroot)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
이렇게 설정해 두면 find_package(), find_library(), find_path() 같은 명령이 CMAKE_FIND_ROOT_PATH로 지정한 sysroot 안에서만 라이브러리·헤더·패키지 설정 파일을 찾고, 호스트 시스템의 /usr/lib나 /usr/include는 건너뜁니다.
변수권장 값이유
CMAKE_FIND_ROOT_PATH_MODE_PROGRAM``NEVER빌드 중 실행할 프로그램은 호스트에서 실행되어야 합니다.
CMAKE_FIND_ROOT_PATH_MODE_LIBRARY``ONLY링크용 라이브러리는 타깃 sysroot에만 있어야 합니다.
CMAKE_FIND_ROOT_PATH_MODE_INCLUDE``ONLY헤더도 타깃 sysroot 기준으로만 찾아야 합니다.
CMAKE_FIND_ROOT_PATH_MODE_PACKAGE``ONLY패키지 설정 파일도 호스트 경로를 침범하지 않아야 합니다.
이 네 변수를 빼먹으면, 빌드는 되지만 실제로는 호스트용 라이브러리가 링크되어 타깃 보드에서 실행할 때만 문제가 드러나는 경우가 있습니다. 크로스 컴파일 toolchain 파일에서는 처음부터 이 설정을 넣어 두는 것이 안전합니다.
FAQ
toolchain 파일은 어디에 두고 어떻게 지정합니까?
파일 자체는 프로젝트 안이든 밖이든 원하는 위치에 .cmake 파일로 두면 되고, 설정 단계에서 cmake -S <source> -B <build> -DCMAKE_TOOLCHAIN_FILE=/path/to/aarch64-toolchain.cmake처럼 캐시 변수로 지정합니다.
sysroot 없이 그냥 컴파일러 경로만 지정해도 됩니까?
동작할 수는 있지만 권장하지 않습니다. sysroot를 지정하지 않으면 컴파일러가 헤더나 라이브러리를 찾을 때 기본 검색 경로(호스트 경로)에 의존하게 되어, 위 CMAKE_FIND_ROOT_PATH_MODE_* 설정과 별개로 헤더·라이브러리 버전이 뒤섞일 위험이 남습니다.
CMAKE_FIND_ROOT_PATH_MODE_PROGRAM만 NEVER로 두는 이유는 무엇입니까?
빌드 중간에 실행되는 코드 생성기 같은 프로그램은 타깃 아키텍처(aarch64) 바이너리가 아니라 호스트에서 바로 실행 가능한 바이너리여야 하기 때문입니다. 이 값을 ONLY로 두면 오히려 호스트에서 실행 불가능한 타깃용 실행 파일을 찾다가 빌드가 깨질 수 있습니다.
정리하며
aarch64 크로스 컴파일 toolchain 파일은 결국 세 가지 역할로 요약됩니다. CMAKE_SYSTEM_NAME·CMAKE_SYSTEM_PROCESSOR·컴파일러 경로로 크로스 컴파일 모드를 켜고, CMAKE_SYSROOT로 타깃 루트 파일 시스템을 잡고, CMAKE_FIND_ROOT_PATH_MODE_* 네 변수로 프로그램 탐색과 라이브러리·헤더·패키지 탐색의 범위를 분리하는 것입니다. 이 세 부분만 정확히 채워 두면 호스트 라이브러리가 실수로 링크되는 문제를 대부분 예방할 수 있습니다.
출처
한 줄 답: 본문의 변수와 동작 방식은 CMake 공식 문서(cmake-toolchains 매뉴얼과 관련 변수 문서)를 기준으로 확인했습니다.
- cmake-toolchains(7) 매뉴얼 — Cross Compiling —
CMAKE_SYSTEM_NAME,CMAKE_SYSTEM_PROCESSOR, 크로스 컴파일 모드 진입 조건을 확인했습니다. - CMAKE_SYSROOT 변수 문서 — sysroot 지정 시
--sysroot플래그가 자동으로 전달되는 동작을 확인했습니다. - CMAKE_FIND_ROOT_PATH_MODE_PROGRAM 변수 문서 —
PROGRAM/LIBRARY/INCLUDE/PACKAGE각 모드의 기본값과ONLY/NEVER의미를 확인했습니다.