Rust

Rust - Mac에서 Linux용 binary cross compile

2021.04.08


Cross Compile?

Mac에서 컴파일한 바이너리 프로그램이 Ubuntu 시스템에서 제대로 작동한는 것을 기대하는 건, 영어를 배우고 나서 중국어를 말하게 하는 거랑 똑같다.

Rust에서는 서로 다른 운영체제에서 작성한 코드를 컴파일해서 바이너리 실행파일을 만들 때, 어떤 운영체제를 타겟으로 하는지 명시하여 타겟 운영체제에서 실행될 수 있도록 할 수 있다.

OSX 운영체제에서 Ubuntu에서 작동할 수 있도록 cross compile 하는 방법에 대해 작성하였다.

 

방법

기존 crago 프로젝트에서 cargo build 를 실행하면, 현재 운영체제에 맞도록 컴파일 한다.

file {{executable 프로그램 이름}} 을 실행하면 해당 파일의 타입이 binance_trader: Mach-O 64-bit executable x86_64 임을 확인할 수 있다. Ubuntu 체계에서 이 파일을 실행해보면

-bash: ./{{executable 프로그램 이름}}: cannot execute binary file: Exec format error

위와 같은 메시지를 보게 된다.

즉, 운영체제가 다르기 때문에 이해할 수 있는 파일 형식이 아닌 것이다.

 

다행히도 누군가가 cross compile tool chain을 만들어 놓았고, 만들어 놓은 것을 설치하여 사용하기만 하면 된다.

brew tap SergioBenitez/osxct
brew install FiloSottile/musl-cross/musl-cross
rustup target add x86_64-unknown-linux-musl

위의 명령어를 하나씩 실행 한다. 그 후,

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

installed targets for active toolchain


x86_64-apple-darwin
x86_64-unknown-linux-gnu
x86_64-unknown-linux-musl # 여기!!

active toolchain


stable-x86_64-apple-darwin (default)
rustc 1.51.0 (2fd73fabe 2021-03-23)

rustup show 를 했을 때, x86_64-unknown-linux-musl 이 추가되어있으면 성공이다.

musl linker를 사용하여 Statically linking 하기 위해서 프로젝트 루트 경로에 .cargo/config 파일을 생성하고, 아래 내용을 작성한다.

[target.x86_64-unknown-linux-musl]
linker = "x86_64-linux-musl-gcc"

그 후, 빌드해본다.

  • Bash shell
TARGET_CC=x86_64-linux-musl-gcc \
RUSTFLAGS="-C linker=x86_64-linux-musl-gcc" \
cargo build --target=x86_64-unknown-linux-musl
  • Fish shell
env TARGET_CC=x86_64-linux-musl-gcc \
RUSTFLAGS="-C linker=x86_64-linux-musl-gcc" \
cargo build --target=x86_64-unknown-linux-musl
  • release build는 --release 를 추가하면 된다.

 

오류 발생시

  • 테스트 해본 프로젝트에서 아래와 같은 오류가 발생했었다.
  Could not find directory of OpenSSL installation, and this `-sys` crate cannot
  proceed without this knowledge. If OpenSSL is installed and this crate had
  trouble finding it,  you can set the `OPENSSL_DIR` environment variable for the
  compilation process.

  Make sure you also have the development packages of openssl installed.
  For example, `libssl-dev` on Ubuntu or `openssl-devel` on Fedora.

  If you're in a situation where you think the directory *should* be found
  automatically, please open a bug at https://github.com/sfackler/rust-openssl
  and include information about your system as well as this message.

  $HOST = x86_64-apple-darwin
  $TARGET = x86_64-unknown-linux-musl
  openssl-sys = 0.9.60

해당 프로젝트는 reqwest crate를 사용했고,

이를 해결하기 위해서는 openssl crate를 cargo.toml[dependencies] 부분에 추가해주면 해결 된다.

openssl = { version="0.10.33", features =["vendored"]}

 

  • release build 를 통해 생성된 파일의 타입을 확인해보니 다음과 같다.
$ file target/x86_64-unknown-linux-musl/release/{{executable 파일 이름}}
target/x86_64-unknown-linux-musl/release/{{executable 파일 이름}}: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, with debug_info, not stripped

 

해당 파일을 ubuntu 서버에서 실행해보면, 이전과는 달리 별다른 오류 없이 잘 실행되는 것을 볼 수 있다.

참고 자료