Rust로 작성한 프로그램이 여러 환경에서 실행되도록 지원하기 위해서는 각각의 OS와 Architecture에 맞게 cross-compile이 필요하다. 여기서 확인해 볼 소스코드를 작성하고 컴파일 할 환경(Host)과, 생성한 실행파일이 실행될 Target 환경은 아래와 같다.
Machine | OS | Architecture | |
---|---|---|---|
Host | MacBook Air (2015) | MacOS(v10.14) / Darwin Kernel(v17.6) | x86_64 (64bit) |
Target | Raspberry PI 4 | Raspbian(v10) / Linux Kernel(5.4.79) | ARMv7 (32bit) |
(참고로 ARM은 v8 부터 64bit을 지원)
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
보통 툴체인에는 크로스 컴파일용 컴파일러, 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-
는 위의 규약을 따르도록 구현된 크로스 컴파일용 소프트웨어 모음이다.
~/.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!");
}
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)