Rust - Raspberry Pi(ARMv7)용 크로스 컴파일 하기

숲사람·2022년 8월 24일
0

Rust

목록 보기
15/15

Rust로 작성한 프로그램이 여러 환경에서 실행되도록 지원하기 위해서는 각각의 OS와 Architecture에 맞게 cross-compile이 필요하다. 여기서 확인해 볼 소스코드를 작성하고 컴파일 할 환경(Host)과, 생성한 실행파일이 실행될 Target 환경은 아래와 같다.

MachineOSArchitecture
HostMacBook Air (2015)MacOS(v10.14) / Darwin Kernel(v17.6)x86_64 (64bit)
TargetRaspberry PI 4Raspbian(v10) / Linux Kernel(5.4.79)ARMv7 (32bit)

(참고로 ARM은 v8 부터 64bit을 지원)

1. rustup에 빌드 target 추가.

rustup--target 옵션으로 크로스-컴파일 시에 사용할 툴체인을 명시한다.

 $ rustup target add armv7-unknown-linux-musleabihf

사용 가능한 target은 여기서 확인해볼 수 있다. armv7-unknown-linux-musleabihf 는 현재 rustc 에서 티어2 target이다. 참고로 mac에서는 gnu-eabi가 아니라 musl-eabi 를 사용해야한다. armv7-unknown-linux-gnueabihf 는 빌드가 안됨.

여기까지만 하고 컴파일을 해보면 아래와 같은 linking에러가 발생한다. 이 target용 크로스 컴파일에서 필요한 linker를 지정하지 않았기 때문이다. 해결방법은 아래 3번에서 살펴본다. (왜 알아서 안되는지는 의문?)

$ cargo build --target armv7-unknown-linux-musleabihf
   Compiling hello v0.1.0 (/Users/jihuun/project/rust/projects/hello)
error: linking with `cc` failed: exit status: 1
...

MUSL은 Linux시스템을 위한 새로운 libc(Standard C library) C 라이브러리다(muscle과 동일한 발음). glibc 보다 더 효율적이고. POSIX표준을 따른다. https://musl.libc.org

2. 내 Mac PC에 ARM cross-compile toolchain설치

보통 툴체인에는 크로스 컴파일용 컴파일러, binutils, C 라이브러리, 디버거등이 포함되어있다. 먼저 내 Host PC에 ARM용 크로스 컴파일 도구가 없기때문에, brew를 통해 arm-linux-gnueabihf-binutils 을 설치한다.

brew install arm-linux-gnueabihf-binutils 

설치 이후 아래의 ARM용 크로스-컴파일 도구들이 설치된것을 확인할 수 있다. 여기서 우리가 사용할것은 링커(ld)이기 때문에 arm-linux-gnueabihf-ld이다. (궁금증: 요걸로 M1 맥용으로도 컴파일 할수 있는지 궁금?)

 $ arm-linux-gnueabihf-
arm-linux-gnueabihf-addr2line  arm-linux-gnueabihf-c++filt    arm-linux-gnueabihf-gprof      arm-linux-gnueabihf-ld.gold    arm-linux-gnueabihf-objdump    arm-linux-gnueabihf-size
arm-linux-gnueabihf-ar         arm-linux-gnueabihf-dwp        arm-linux-gnueabihf-ld         arm-linux-gnueabihf-nm         arm-linux-gnueabihf-ranlib     arm-linux-gnueabihf-strings
arm-linux-gnueabihf-as         arm-linux-gnueabihf-elfedit    arm-linux-gnueabihf-ld.bfd     arm-linux-gnueabihf-objcopy    arm-linux-gnueabihf-readelf    arm-linux-gnueabihf-strip

ARM EABI란? 소스코드를 ARM 아키텍처에서 동작하도록 컴파일할 수 있다는 의미. ABI(Aplication Binary Interface)는 일종의 CPU와 명령어간의 규약이다. 여기서 EABI의 E는 임베디드환경을 의미한다. hf는 플로팅포인터 연산이다. arm-linux-gnueabihf- 는 위의 규약을 따르도록 구현된 크로스 컴파일용 소프트웨어 모음이다.

3. ~/.cargo/config 파일에 target 추가.

앞서 확인했던 컴파일 에러 error: linking with cc failed: exit status: 1는 이 수정으로 해결할 수 있다. Home 디렉토리의 .cargo/config 파일에 아래 내용을 추가한다.

[target.armv7-unknown-linux-musleabihf]
linker = "arm-linux-gnueabihf-ld"

이제 armv7-unknown-linux-musleabihf 으로 크로스 컴파일 해보면.

 $ cargo build --target armv7-unknown-linux-musleabihf

컴파일에 성공하면 아래와 같이 target이 추가된다. cross compile한 target arch 명으로 경로가 생성되고 거기에 executable 파일이 생성된다.

$ ls target/
CACHEDIR.TAG                    armv7-unknown-linux-musleabihf/ debug/

참고로 컴파일한 소스코드는 아래와 같다.

fn main() {
    println!("Hello, Executable written by Rust on Raspberry PI!");
}

4. 라즈베리파이에 파일 보내고, 실행하기!

jihuun@MacBook $ scp -P 10001 target/armv7-unknown-linux-musleabihf/debug/hello jihuun@111.222.333.444:~

라즈베리파이에 ssh로 접속한뒤 전송한 ELF 실행파일을 실행하면 아래와 같이 정상적으로 실행된다! 신기하다!

jihuun@raspberrypi:~ $ ./hello 
Hello, Executable written by Rust on Raspberry PI!

추가 정보

해당 파일에 대한 추가 정보

jihuun@raspberrypi:~ $ ldd hello 
        not a dynamic executable
        
jihuun@raspberrypi:~ $ readelf -h hello 
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x11d91
  Start of program headers:          52 (bytes into file)
  Start of section headers:          4068704 (bytes into file)
  Flags:                             0x5000400, Version5 EABI, hard-float ABI
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         6
  Size of section headers:           40 (bytes)
  Number of section headers:         32
  Section header string table index: 31

Host PC에서 rustup show를 하면 현재 설치된 target Toolchain을 확인할 수 있다.

$ rustup show
Default host: x86_64-apple-darwin
rustup home:  /Users/jihuun/.rustup

installed targets for active toolchain
--------------------------------------

armv7-unknown-linux-gnueabihf
armv7-unknown-linux-musleabihf
x86_64-apple-darwin

active toolchain
----------------

stable-x86_64-apple-darwin (default)
rustc 1.63.0 (4b91a6ea7 2022-08-08)

참고

profile
기록 & 정리 아카이브 용도 (보다 완성된 글은 http://soopsaram.com/documentudy)

0개의 댓글