It’s easy enough to add extra targets using the cargo command when building your Rust project. However, the Rust cross compile process gets a little tricker when linking is done for platforms different to the host platform.
I wanted to setup a GitHub Actions workflow that would build binaries for different platforms from the same actions runner.
While it might be possible to use GitHub Actions Matrix to run a build across multiple operating systems and install Rust / rustup / cargo on each, performing the build in each place, I opted for a different strategy.
Using a base Rust musl build container, on top of Debian Buster, I’ve added osxcross and the required build tools. This supports building and linking macOS binaries from the Linux container.
Rust Cross Compile GitHub Action
I’ve built a Docker image for GitHub Actions to use. It is based on the popular rustup image. Currently I’ve built a musl-1.0.53 variant. My version copies in and sets up osxcross. This bakes all the heavy lifting into the image so that GitHub actions can quickly build targets for linux and macOS (x86).
You can find the action on the Rust Cross Compile GitHub Action here.
Usage example
Set up a .cargo/config file to designate the target to linker mapping. For example macOS x86:
[target.x86_64-apple-darwin] linker = "x86_64-apple-darwin14-clang" ar = "x86_64-apple-darwin14-ar"
Add a GitHub Actions workflow:
name: Rust static build macOS and Linux
on:
push:
branches:
- main
jobs:
build:
name: build for all platforms
runs-on: ubuntu-latest
env:
CARGO_TERM_COLOR: always
BINARY_NAME: rust-test1
steps:
- uses: actions/checkout@v2
- name: Build-musl macOS x86
uses: Shogan/rust-musl-action@v1.0.2
with:
args: cargo build --target x86_64-apple-darwin --release
- name: Build-musl Linux x86
uses: Shogan/rust-musl-action@v1.0.2
with:
args: cargo build --target x86_64-unknown-linux-musl --release
Release binaries can now easily be built from a single ubuntu linux GitHub actions runner. For example, get the Cargo.toml version and create a release with the built binaries by adding a couple of extra steps:
steps:
- uses: actions/checkout@v2
- name: Set build version
id: version
shell: bash
run: |
VERSION="$(cat Cargo.toml | grep 'version =' -m 1 | sed 's@version =@@' | xargs)"
echo "RELEASE_VERSION=$VERSION" >> $GITHUB_ENV
echo "::notice::publish build version $VERSION"
- name: Upload macOS x86 binary to release
uses: Spikatrix/upload-release-action@b713c4b73f0a8ddda515820c124efc6538685492
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: target/x86_64-apple-darwin/release/${{ env.BINARY_NAME }}
asset_name: ${{ env.BINARY_NAME }}-macos-x86
target_commit: ${{ github.sha }}
tag: v${{ env.RELEASE_VERSION }}
release_name: v${{ env.RELEASE_VERSION }}
prerelease: false
overwrite: true
body: ${{ env.BINARY_NAME }} release
There are many ways to achieve an automated CI process that can do Rust cross compile and linking. It was an interesting investigation into custom Docker containers for GitHub actions and the Rust tool chain setting up this GitHub Action package.
Feel free to contribute or improve the GitHub Action by sending a pull request on GitHub.