Rust: cross compilation with CI
Rust is one of my favorite languages. Go is another one, and I particularly like it for it's easiness on cross compilation. But Rust is a bit more complex, and I found it a bit hard to cross compile it. So I decided to write a guide on how to cross compile Rust projects with GitHub Actions and Goreleaser.
Why Goreleaser? Because it's a great tool for cross compilation, it's easy to use, has great features and I didn't find any other tool that was as good as it.
Prerequisites
- A GitHub account
- A GitHub repository
- A Rust project (a Hello World is enough)
Repository
Clone your repository. Then let's create a simple Rust project in case you have nothing:
Now add the rust toolchain version you want to use for your project. I recommend using the latest stable version (1.92.0 at the time of writing). Create a rust-toolchain file in the root of your repository:
This will help to keep the same version of Rust for all your CI runs and your local development.
GitHub Actions
We have to define all architectures, and the OS we want to build on. Then iterate over them to build the binaries. We'll store them as artifacts for later usage (with Goreleaser).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | |
GitHub Token
Now you have to configure a fine-grained token to allow Goreleaser to update the homebrew-myproject repository (if you are using it).
Your .goreleaser.yaml configures a Homebrew Tap in a separate repository (me/homebrew-myproject). The default secrets.GITHUB_TOKEN only has permission to modify the current repository. To update the separate homebrew-myproject repository automatically, you need a token with permissions across both repositories.
Generate a Fine-grained PAT
- Go to GitHub Settings > Developer settings > Personal access tokens > Fine-grained tokens.
- Name: myproject Release Token (or similar).
- Expiration: Set as desired.
- Resource owner: The owner of the repositories (me).
- Repository access: Select Only select repositories.
- Choose:
myprojectANDhomebrew-myproject. - Permissions (Repository permissions):
- Contents: Select Read and Write. (This allows pushing the Release to myproject and the Formula to homebrew-myproject)
- Click Generate token and copy the value.
Add Secret to GitHub Actions
- Navigate to your
myprojectrepository on GitHub. - Go to Settings > Secrets and variables > Actions.
- Click New repository secret.
- Name:
GH_TOKEN_GORELEASER(Must match exactly what is in your YAML). - Secret: Paste the token you copied.
- Click Add secret.
DockerHub Token
You also have to configure a token to allow Goreleaser to pull the Docker image from DockerHub and avoid rate limiting.
Generate a DockerHub Token
- Go to DockerHub Settings > Security > Personal Access Tokens.
- Name: myproject Release Token (or similar).
- Expiration: Set as desired.
- Permissions: Select Read and Write.
- Click Generate token and copy the value.
Add Secret to GitHub Actions
- Navigate to your
myprojectrepository on GitHub. - Go to Settings > Secrets and variables > Actions.
- Click New repository secret.
- Name:
DOCKERHUB_TOKEN_GORELEASER(Must match exactly what is in your YAML). - Secret: Paste the token you copied.
- Click Add secret.
Goreleaser
Now we have the cross compilation, let's add Goreleaser to our repository. In your repository, create a goreleaser.yml file at the root of your repository:
|
Here you'll be able to generate the releases for your project in those architectures:
- Linux (amd64, arm64)
- MacOS (amd64, arm64)
- Windows (amd64)
Now add a .goreleaser_hook.sh file at the root of your repository:
And finally:
Now, when you push a tag to your repository, Goreleaser will generate the releases for your project in those architectures.
If you want on concrete example, you can check my Vessel project.