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.