Releasing Rust Binaries with GitHub Actions - Part 2
Justin Patriquin
Posted on November 21, 2022
In this part I'm going to go over how I ended up releasing binaries for MacOS and Windows MSVC.
Cross Compilation
Ideally, we could use the cross compilation to build all of the binaries on the same runner type in GitHub Actions. This allows you to build binaries on one platform (e.g. Linux x86_64) that can then run on other platforms. Being able to do this would make our GitHub Action easier to write and maintain. But, there was issue I ran into that prevented cross compilation with Nitrogen from being able to build for different platforms.
The AWS Rust library we were using as a dependency depended on a cryptography library called ring. This library leverages C and assembly code to implement its cryptographic primitives. Unfortunately, cross compiling when C is involved can add complexity to the build process. While it might've been possible to overcome these issues I decided that it wasn't worth digging into more.
Implementation
Fortunately, the GitHub Action implementation I ended up going with wasn't that complicated. I just had to use separate runners. One for MacOS Arm and one for Windows MSVC. Here are the steps I had to do for each release type.
Build the binary
For Windows it was as simple as running a release build:
$ cargo build --release
The MacOS Arm build is just slightly more complex because the GitHub Actions runner isn't running on Arm architecture so we have to add the separate toolchain and target.
$ rustup toolchain install stable-aarch64-apple-darwin
$ rustup target add aarch64-apple-darwin
$ cargo build --release --target aarch64-apple-darwin
Compress the binary
We use tar
to compress the binaries:
$ tar --directory=target/release -cf archive.tar.gz nitrogen.exe
The MacOS tar
command differs slightly because of the cross compilation required to build for Arm.
$ tar --directory=target/aarch64-apple-darwin/release -cf archive.tar.gz nitrogen
Upload the artifact
Since the release is already created we need to query the release ID and then upload the archived binary to the release using the GitHub API.
The Windows and MacOS version of these differs slightly because Windows has to run in the PowerShell where MacOS would be using bash. You can select the bash shell in the Windows runner but I had an issue with this where it couldn't find the gh
command line tool.
Windows:
$ $id = gh api -H "Accept: application/vnd.github+json" /repos/capeprivacy/nitrogen/releases/tags/${{ github.ref_name }} --jq .id
Note: cURL command is edited here for brevity see here for the full command
$ curl -X POST --data-binary "@archive.tar.gz" "https://uploads.github.com/repos/capeprivacy/nitrogen/releases/$id/assets?name=nitrogen_${{ github.ref_name }}_x86_64-pc-windows-msvc.tar.gz"
MacOS:
$ id=$(gh api -H "Accept: application/vnd.github+json" /repos/capeprivacy/nitrogen/releases/tags/${{ github.ref_name }} --jq .id)
Note: cURL command is edited here for brevity see here for the full command
$ curl -X POST --data-binary @"archive.tar.gz" "https://uploads.github.com/repos/capeprivacy/nitrogen/releases/$id/assets?name=nitrogen_${{ github.ref_name }}_aarch64-apple-darwin.tar.gz"
Check out the full implementation here.
This was an interesting problem to work on and I learned a lot. Let me know if you have any questions!
Thanks for reading! If Nitrogen sounds cool to you check it out and give it a star here, check out the quick installation guide here and come see what's going on on Discord.
Posted on November 21, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.