How to cross compile Rust across operating systems and CPU architectures?

Viewed 48

I am learning Rust and writing some basic CLI tools as an exercise. I am storing my application source in Github, using Github actions to generate binaries and publish those binaries via Github releases.

The issue is; I am unsure how to cross compile my Rust application for various target architectures and operating systems.

(Apologise for the comparison) Previously when using Go, I could specify the target CPU architecture and target Operating System in the build command like:

env GOARCH=arm64 GOOS=darwin go build

When looking to see if there is an equivalent in Rust I am seeing instructions telling me to use virtualization and various other techniques to cross compile.

I suspect I might just be bad at researching, is there an equivalent simple way to cross compile Rust applications?

If not, why is that and could you point me to resources to help me learn how to do it?

1 Answers

cross makes this really easy, especially since it's supported by actions-rs/cargo.

I'm using something like

name: 'Release'

on:
  push:
    tags:
      - 'v*'

env:
  CARGO_INCREMENTAL: 0

jobs:
  build:
    name: Binary
    strategy:
      fail-fast: false
      matrix:
        job:
          - { target: x86_64-unknown-linux-musl, exe: amd64-linux, os: ubuntu-latest }
          - { target: aarch64-unknown-linux-musl, exe: aarch64-linux, os: ubuntu-latest }
          - { target: armv7-unknown-linux-musleabi, exe: armv7-linux, os: ubuntu-latest }
          - { target: wasm32-wasi, exe: wasi.wasm, os: ubuntu-latest }
          - { target: x86_64-apple-darwin, exe: macos, os: macos-latest }
          - { target: x86_64-pc-windows-msvc, exe: windows.exe, os: windows-2019 }
    runs-on: ${{ matrix.job.os }}
    steps:
      - uses: actions/checkout@v2
      - uses: actions-rs/toolchain@v1
        with:
          profile: minimal
          toolchain: 1.62.0
          override: true
          target: ${{ matrix.job.target }}
          components: rust-src # necessary for wasi, because there isn't a cross image for it
      - uses: actions-rs/cargo@v1
        with:
          use-cross: true
          args: --release --target=${{ matrix.job.target }} --locked
          command: build
      - name: Rename result
        run: |
          rm target/${{ matrix.job.target }}/release/patch-json.d
          cp target/${{ matrix.job.target }}/release/patch-json* patch-json-${{ matrix.job.exe }}
      - name: Archive production artifacts
        uses: actions/upload-artifact@v2
        with:
          name: arty
          path: patch-json-${{ matrix.job.exe }}

# Release artifacts in a separate step to make sure all are successfully produced and no partial release is created

on one of my projects.

I also specify

[profile.release]
lto = "fat"
strip = "debuginfo"

in my Cargo.toml to make the released files a bit nicer.

It is probably worth noting that Rust crates make it much easier to build and link in C/C++ libraries than Go, possibly invoking CMake or worse. Cross-compiling such crates can be a lot more difficult and how to do it exactly is up to the specific crate.

Related