C依存のあるプロジェクトのビルドが難しい
Rustはビルトインでクロスコンパイルをサポートしている。以下のようにすることでクロスコンパイル可能となっている。
rustup target add aarch64-unknown-linux-musl cargo build --target aarch64-unknown-linux-musl
しかし、これではビルドできない場合がある。依存するcrateのビルド時、C言語への依存があった場合はC言語のビルドに必要なツールチェイン(コンパイラとリンカ)を揃える必要がある。
warning: cc: error: unrecognized command-line option `-arch` error: failed to run custom build command for `wasmtime-fiber` Caused by: ... running "cc" ...
zig cc を利用する
従来は clang
や llvm-ar
を追加でインストールする必要があったが、最近話題になっているzigを使うことでこれを回避することができる。
Zig Makes Rust Cross-compilation Just Work · Um, actually...
具体的には、次のようなwrapperを用意し、
#!/bin/sh /path-to-zig/zig cc -target aarch64-linux $@
以下のようにリンカ/ビルド時に利用する。
[target.aarch64-unknown-linux-musl] linker = "/path-to-wrapper/zcc"
CC="/path-to-wrapper/zcc" cargo build --target aarch64-unknown-linux-musl
cargo-zigbuild
これをcargo subcommandとして簡単に利用できるようになった cargo-zigbuild を紹介する。
GitHub - messense/cargo-zigbuild: Compile Cargo project with zig as linker
使い方としてはこんな感じ。かなり簡単でとても嬉しい。
rustup target add aarch64-unknown-linux-musl cargo zigbuild --release --target aarch64-unknown-linux-musl
インストールも簡単で、pipが入っていれば pip install cargo-zigbuild
を打つだけでzigも一緒にインストールしてくれる。
マルチアーキテクチャ対応のイメージ作成に利用する
前回、Rust + GitHub Actionsでマルチアーキテクチャ対応のイメージをなるべく早く作るという記事を書いた。この時まさにマルチアーキテクチャ対応のイメージビルドで困っていて、イメージビルド時に clang
と llvm
をインストールしていたんだけど、cargo-zigbuildを利用することでこの箇所が簡単にできる。
FROM --platform=$BUILDPLATFORM rust:1.63 as builder # clang や llvm が必要なくなった! cargo-zigbuild をインストールする RUN apt update -y && apt install python3-pip -y && pip3 install cargo-zigbuild RUN cargo new --bin app WORKDIR /app COPY ./Cargo.lock ./Cargo.lock COPY ./Cargo.toml ./Cargo.toml # リンカの指定も必要なくなった! # ENV CC_aarch64_unknown_linux_musl=clang # ENV AR_aarch64_unknown_linux_musl=llvm-ar # ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_RUSTFLAGS="-Clink-self-contained=yes -Clinker=rust-lld" # # ENV CC_x86_64_unknown_linux_musl=clang # ENV AR_x86_64_unknown_linux_musl=llvm-ar # ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_RUSTFLAGS="-Clink-self-contained=yes -Clinker=rust-lld" ARG TARGETPLATFORM RUN case "$TARGETPLATFORM" in \ "linux/arm64") echo aarch64-unknown-linux-musl > /rust_target.txt ;; \ "linux/amd64") echo x86_64-unknown-linux-musl > /rust_target.txt ;; \ *) exit 1 ;; \ esac RUN rustup target add $(cat /rust_target.txt) RUN --mount=type=cache,target=/usr/local/cargo/registry \ --mount=type=cache,target=/app/target \ cargo zigbuild --release --target $(cat /rust_target.txt) RUN rm src/*.rs COPY ./src ./src RUN touch ./src/main.rs RUN --mount=type=cache,target=/usr/local/cargo/registry \ --mount=type=cache,target=/app/target \ # cargo install が使えないので、代わりに手動でコピーする cargo zigbuild --release --target $(cat /rust_target.txt) && \ cp target/$(cat /rust_target.txt)/release/minecraft-command-bot /usr/local/bin/app FROM alpine COPY --from=builder /usr/local/bin/app . CMD ["./app"]
かなり嬉しい。