본문 바로가기
HW SW 개발

💻🔧CMake Toolchain 파일로 ARM32 라즈베리파이 크로스 빌드 자동화 (Host: Ubuntu x86_64 → Target: Pi OS 32-bit/armhf)

by 아이텍 2025. 12. 14.
반응형

이번 글에서는 CMake Toolchain 파일을 사용해, 매번 arm-linux-gnueabihf-gcc ... --sysroot=... 같은 커맨드를 손으로 치지 않고도 ARM32 라즈베리파이용 빌드를 자동화하는 표준 흐름을 정리합니다.

전제:

  • Host: Ubuntu x86_64
  • Target: Raspberry Pi OS 32-bit (armhf, armv7l)
  • 빌드 산출물: Pi에서 실행되는 ARM32 ELF

1) Host에 크로스 컴파일러 설치

 
sudo apt update
sudo apt install -y gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf cmake ninja-build rsync

2) sysroot 준비 (라즈베리파이의 /lib, /usr를 Host로 동기화)

CMake 크로스 빌드가 실무에서 안정적으로 돌려면 sysroot가 사실상 필수입니다.

 
export RPI_HOST=raspberrypi.local # 또는 Pi의 IP
export RPI_USER=pi
mkdir -p $HOME/rpi-sysroot
rsync -avz --delete ${RPI_USER}@${RPI_HOST}:/lib $HOME/rpi-sysroot/
rsync -avz --delete ${RPI_USER}@${RPI_HOST}:/usr $HOME/rpi-sysroot/

--delete는 Host의 sysroot를 Pi와 동일하게 유지하는 데 유용합니다. (원치 않으면 제거)


3) Toolchain 파일 작성: cmake/toolchains/rpi-arm32.cmake

프로젝트 루트에 아래 경로로 생성한다고 가정합니다.

 
<project>/
CMakeLists.txt
cmake/toolchains/rpi-arm32.cmake
src/...

 

cmake/toolchains/rpi-arm32.cmake 내용:

 
# Target 플랫폼 정의
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
 
# 크로스 컴파일러 지정 (armhf)
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
 
# sysroot 경로 (환경/PC에 맞게 수정)
set(RPI_SYSROOT "$ENV{HOME}/rpi-sysroot")
set(CMAKE_SYSROOT "${RPI_SYSROOT}")
 
# CMake가 라이브러리/헤더를 찾을 때, sysroot 우선 탐색하도록 설정
set(CMAKE_FIND_ROOT_PATH "${CMAKE_SYSROOT}")
 
# 프로그램(호스트에서 실행되는 도구)은 Host에서 찾고,
# 라이브러리/헤더/패키지는 Target(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)
 
# try_compile 시 실행 파일을 타깃에서 실행할 수 없으므로,
# 테스트 빌드는 정적 라이브러리 형태로 수행하게 해서 실패를 줄임.
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
 
# (선택) 하드플로트 ABI 명시가 필요할 때만 사용 (대부분 툴체인이 알아서 처리)
# add_compile_options(-mfloat-abi=hard -mfpu=vfp)
 
 

핵심 포인트는:

  • CMAKE_SYSROOT + CMAKE_FIND_ROOT_PATH_MODE_* 조합으로 헤더/라이브러리 탐색이 Host로 새지 않게 하는 것
  • CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY로 크로스 환경에서의 CMake 검사 실패를 줄이는 것

4) 최소 예시 CMakeLists.txt

 
cmake_minimum_required(VERSION 3.16)
project(hello_rpi_arm32 C)
 
add_executable(hello src/hello.c)

 

 

 

src/hello.c:

#include <stdio.h>
int main(void) {
     puts("Hello from CMake cross-compile (ARM32)!");
     return 0;
}
 

5) 빌드 자동화 (Ninja 권장)

프로젝트 루트에서:

 
cmake -S . -B build-rpi-arm32 -G Ninja \
      -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/rpi-arm32.cmake \ 
      -DCMAKE_BUILD_TYPE=Release
 
cmake --build build-rpi-arm32

 

결과 확인:

file build-rpi-arm32/hello

6) Pi로 배포 및 실행

 
scp build-rpi-arm32/hello pi@raspberrypi.local:/home/pi/
ssh pi@raspberrypi.local 'chmod +x ~/hello && ~/hello'
 

7) (실전) pkg-config가 필요한 프로젝트라면

find_package()나 pkg_check_modules()를 쓰는 프로젝트는, Host의 pkg-config가 Host 라이브러리를 가리키지 않게 sysroot 기반으로 유도해야 합니다.

 

빌드 전에 아래를 설정하는 방식이 가장 단순합니다:

 
export PKG_CONFIG_SYSROOT_DIR=$HOME/rpi-sysroot
export PKG_CONFIG_LIBDIR=$HOME/rpi-sysroot/usr/lib/arm-linux-gnueabihf/pkgconfig:$HOME/rpi-sysroot/usr/lib/pkgconfig:$HOME/rpi-sysroot/usr/share/pkgconfig

 

경로는 Pi 배포판/모델에 따라 약간 달라질 수 있습니다. (arm-linux-gnueabihf 디렉터리 유무 확인)


8) 자주 막히는 지점 (체크리스트)

  • 링크가 Host 라이브러리로 잡히는 문제
    → Toolchain에서 CMAKE_FIND_ROOT_PATH_MODE_LIBRARY/INCLUDE/PACKAGE ONLY 설정이 핵심입니다.
  • CMake configure 단계에서 try_run/try_compile 실패
    → CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY를 toolchain에 넣고, 필요하면 특정 기능 테스트를 옵션으로 끄거나 캐시 변수를 지정합니다.
  • “Exec format error”
    → Pi가 32-bit(armhf)인데 aarch64로 빌드한 경우가 많습니다. 반드시 arm-linux-gnueabihf-* 툴체인 사용 및 Pi에서 dpkg --print-architecture가 armhf인지 확인하세요.
반응형