Skip to content

Commit 2ea561c

Browse files
fasterthanlimemistydemeo
authored andcommitted
feat: add cross-compilation support
1 parent e491b6a commit 2ea561c

File tree

96 files changed

+7151
-1348
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+7151
-1348
lines changed

.github/workflows/release.yml

+8
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ jobs:
111111
# - N "local" tasks that build each platform's binaries and platform-specific installers
112112
matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }}
113113
runs-on: ${{ matrix.runner }}
114+
container: ${{ matrix.container && matrix.container.image || null }}
114115
env:
115116
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
116117
BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json
@@ -121,6 +122,13 @@ jobs:
121122
- uses: actions/checkout@v4
122123
with:
123124
submodules: recursive
125+
- name: Install Rust non-interactively if not already installed
126+
if: ${{ matrix.container }}
127+
run: |
128+
if ! command -v cargo > /dev/null 2>&1; then
129+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
130+
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
131+
fi
124132
- name: Install dist
125133
run: ${{ matrix.install_dist.run }}
126134
# Get the dist-manifest

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ cargo-dist/wix
88
oranda-debug.log
99
/public
1010
cargo-dist/public
11+
12+
# Samply: <https://crates.io/crates/samply>
13+
/profile.json

Cargo.lock

+3-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ lazy_static = "1.5.0"
7070
current_platform = "0.2.0"
7171
color-backtrace = "0.6.1"
7272
backtrace = "0.3.74"
73+
target-lexicon = "0.12.16"
7374

7475
[workspace.metadata.release]
7576
shared-version = true

Justfile

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
2+
build-all-plaforms:
3+
#!/bin/bash -eux
4+
export AXOASSET_XZ_LEVEL=1
5+
cargo build
6+
./target/debug/dist init --yes
7+
./target/debug/dist build --artifacts all --target aarch64-apple-darwinx,x86_64-apple-darwin,x86_64-pc-windows-msvc,x86_64-unknown-linux-musl
8+
9+
patch-sh-installer:
10+
#!/usr/bin/env node
11+
const fs = require('fs');
12+
const installerUrl = process.env.INSTALLER_DOWNLOAD_URL || 'https://dl.bearcove.cloud/dump/dist-cross';
13+
const installerPath = './target/distrib/cargo-dist-installer.sh';
14+
15+
const content = fs.readFileSync(installerPath, 'utf8');
16+
const lines = content.split('\n');
17+
let modified = false;
18+
19+
const newLines = [];
20+
for (const line of lines) {
21+
if (line.includes('export INSTALLER_DOWNLOAD_URL')) {
22+
continue;
23+
}
24+
if (line.includes('set -u') && !modified) {
25+
modified = true;
26+
newLines.push(line);
27+
newLines.push(`export INSTALLER_DOWNLOAD_URL=${installerUrl} # patched by Justfile in dist repo, using dist_url_override feature`);
28+
continue;
29+
}
30+
newLines.push(line);
31+
}
32+
33+
fs.writeFileSync(installerPath, newLines.join('\n'));
34+
35+
if (modified) {
36+
console.log('\x1b[32m%s\x1b[0m', `${installerPath} patched successfully!`);
37+
console.log('\x1b[36m%s\x1b[0m', `🔗 Pointing to: ${installerUrl}`);
38+
} else {
39+
console.log('\x1b[31m%s\x1b[0m', '❌ Error: Could not find line with "set -u" in installer script');
40+
}
41+
42+
patch-ps1-installer:
43+
#!/usr/bin/env node
44+
const fs = require('fs');
45+
const installerUrl = process.env.INSTALLER_DOWNLOAD_URL || 'https://dl.bearcove.cloud/dump/dist-cross';
46+
const installerPath = './target/distrib/cargo-dist-installer.ps1';
47+
48+
const content = fs.readFileSync(installerPath, 'utf8');
49+
const lines = content.split('\n');
50+
let modified = false;
51+
52+
const newLines = [];
53+
for (const line of lines) {
54+
if (line.includes('$env:INSTALLER_DOWNLOAD_URL = ')) {
55+
continue;
56+
}
57+
if (line.includes('$app_name = ') && !modified) {
58+
modified = true;
59+
newLines.push(`$env:INSTALLER_DOWNLOAD_URL = "${installerUrl}" # patched by Justfile in dist repo, using dist_url_override feature`);
60+
newLines.push(line);
61+
continue;
62+
}
63+
newLines.push(line);
64+
}
65+
66+
fs.writeFileSync(installerPath, newLines.join('\n'));
67+
68+
if (modified) {
69+
console.log('\x1b[32m%s\x1b[0m', `${installerPath} patched successfully!`);
70+
console.log('\x1b[36m%s\x1b[0m', `🔗 Pointing to: ${installerUrl}`);
71+
} else {
72+
console.log('\x1b[31m%s\x1b[0m', '❌ Error: Could not find line with "cargo-dist = " in installer script');
73+
}
74+
75+
dump:
76+
#!/bin/bash -eux
77+
just build-all-plaforms
78+
just patch-sh-installer
79+
just patch-ps1-installer
80+
mc mirror --overwrite ./target/distrib ${DIST_TARGET:-bearcove/dump/dist-cross}

book/src/ci/customizing.md

+134-4
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@
44

55
dist's generated CI configuration can be extended in several ways: it can be configured to install extra packages before the build begins, and it's possible to add extra jobs to run at specific lifecycle moments.
66

7-
87
## Install extra packages
98

109
> since 0.4.0
1110
1211
Sometimes, you may need extra packages from the system package manager to be installed before in the builder before dist begins building your software. dist can do this for you by adding the `dependencies` setting to your dist config. When set, the packages you request will be fetched and installed in the step before `build`. Additionally, on macOS, the `cargo build` process will be wrapped in `brew bundle exec` to ensure that your dependencies can be found no matter where Homebrew placed them.
1312

14-
By default, we run Apple silicon (aarch64) builds for macOS on the `macos-13` runner, which is Intel-based. If your build process needs to link against C libraries from Homebrew using the `dependencies` feature, you will need to switch to an Apple silicon-native runner to ensure that you have access to Apple silicon-native dependencies from Homebrew. You can do this using the [custom runners][custom-runners] feature. Currently, `macos-14` is the oldest (and only) GitHub-provided runner for Apple silicon.
13+
By default, we run Apple silicon (aarch64) builds for macOS on the `macos-13` runner, which is Intel-based. If your build process needs to link against C libraries from Homebrew using the `dependencies` feature, you will need to switch to an Apple silicon-native runner to ensure that you have access to Apple silicon-native dependencies from Homebrew. You can do this using the [custom runners][custom-runners] feature. Currently, `macos-14` is the oldest GitHub-provided runner for Apple silicon.
1514

1615
Sometimes, you may want to make sure your users also have these dependencies available when they install your software. If you use a package manager-based installer, dist has the ability to specify these dependencies. By default, dist will examine your program to try to detect which dependencies it thinks will be necessary. At the moment, [Homebrew][homebrew] is the only supported package manager installer. You can also specify these dependencies manually.
1716

@@ -96,18 +95,149 @@ By default, dist uses the following runners:
9695
It's possible to configure alternate runners for these jobs, or runners for targets not natively supported by GitHub actions. To do this, use the [`github-custom-runners`][config-github-custom-runners] configuration setting in your dist config. Here's an example which adds support for Linux (aarch64) using runners from [Buildjet](https://buildjet.com/for-github-actions):
9796

9897
```toml
99-
[workspace.metadata.dist.github-custom-runners]
98+
# in `dist-workspace.toml`
99+
100+
[dist.github-custom-runners]
100101
aarch64-unknown-linux-gnu = "buildjet-8vcpu-ubuntu-2204-arm"
101102
aarch64-unknown-linux-musl = "buildjet-8vcpu-ubuntu-2204-arm"
102103
```
103104

104105
In addition to adding support for new targets, some users may find it useful to use this feature to fine-tune their builds for supported targets. For example, some projects may wish to build on a newer Ubuntu runner or alternate Linux distros, or may wish to opt into building for Apple Silicon from a native runner by using the `macos-14` runner. Here's an example which uses `macos-14` for native Apple Silicon builds:
105106

106107
```toml
107-
[workspace.metadata.dist.github-custom-runners]
108+
# in `dist-workspace.toml`
109+
110+
[dist.github-custom-runners]
108111
aarch64-apple-darwin = "macos-14"
109112
```
110113

114+
## Cross-compilation
115+
116+
> since 0.26.0
117+
118+
dist will transparently use either of:
119+
120+
* [cargo-zigbuild](https://github.com/rust-cross/cargo-zigbuild)
121+
* [cargo-xwin](https://github.com/rust-cross/cargo-xwin)
122+
123+
To try and build for the target you specified, from the host you specified.
124+
125+
dist hardcodes knowledge of which cargo wrappers are better suited for which cross: `cargo-zigbuild`
126+
handles `x86_64-unknown-linux-gnu` to `aarch64-unknown-linux-gnu` handsomely, for example.
127+
128+
So if you ask for `aarch64-unknown-linux-gnu` artifacts, because at the time of this writing
129+
there are no free `aarch64` GitHub runners, dist will assume you meant this:
130+
131+
```toml
132+
[dist.github-custom-runners]
133+
aarch64-unknown-linux-gnu = "ubuntu-20.04"
134+
```
135+
136+
Which really means this:
137+
138+
```toml
139+
[dist.github-custom-runners.aarch64-unknown-linux-gnu]
140+
runner = "ubuntu-20.04"
141+
host = "x86_64-unknown-linux-gnu"
142+
```
143+
144+
...since dist knows which platform GitHub's own [runner
145+
images](https://github.com/actions/runner-images) are.
146+
147+
So you really only need to specify the `host` if you use [third-party GitHub Actions
148+
runners](https://github.com/neysofu/awesome-github-actions-runners?tab=readme-ov-file#list-of-providers) (Namespace, Buildjet, etc.)
149+
150+
If you don't specify the host, dist will just assume it's the same platform as
151+
the target, which is why this works:
152+
153+
```toml
154+
[dist.github-custom-runners]
155+
aarch64-unknown-linux-gnu = "buildjet-8vcpu-ubuntu-2204-arm"
156+
```
157+
158+
Building `aarch64-pc-windows-msvc` binaries from a `x86_64-pc-windows-msvc` runner (like
159+
`windows-2019`) is surprisingly hard. But building both binaries from an `x86_64-unknown-linux-gnu`
160+
runner is surprisingly easy via `cargo-xwin`
161+
162+
This will work, eventually:
163+
164+
```toml
165+
# in `dist-workspace.toml`
166+
167+
[dist]
168+
targets = ["x86_64-pc-windows-msvc", "aarch64-pc-windows-msvc"]
169+
170+
[dist.github-custom-runners.x86_64-pc-windows-msvc]
171+
runner = "ubuntu-20.04"
172+
173+
[dist.github-custom-runners.aarch64-pc-windows-msvc]
174+
runner = "ubuntu-20.04"
175+
```
176+
177+
...because dist can install `cargo-xwin` via `pip`. However, it will take
178+
forever. It's probably best to use a docker image that already has
179+
`cargo-xwin` installed, and other dependencies you probably want:
180+
181+
```toml
182+
# in `dist-workspace.toml`
183+
184+
[dist]
185+
targets = ["x86_64-pc-windows-msvc", "aarch64-pc-windows-msvc"]
186+
187+
[dist.github-custom-runners.x86_64-pc-windows-msvc]
188+
container = "messense/cargo-xwin"
189+
190+
[dist.github-custom-runners.aarch64-pc-windows-msvc]
191+
container = "messense/cargo-xwin"
192+
```
193+
194+
Which is short for:
195+
196+
```toml
197+
# cut: the rest of the config file
198+
199+
[dist.github-custom-runners.x86_64-pc-windows-msvc]
200+
container = { image = "messense/cargo-xwin", host = "x86_64-unknown-linux-gnu" }
201+
202+
# etc.
203+
```
204+
205+
...but unfortunately, GitHub Actions's "run workflows in container" feature doesn't
206+
support emulation yet. We'd have to set up qemu, run docker manually, etc. — which
207+
dist doesn't do as of now. So the `host` just defaults to `x86_64-unknown-linux-gnu`
208+
right now, because that's all the GitHub runners support anywyay.
209+
210+
So, because we're only specifying one feature, it's probably easier to just write this:
211+
212+
```toml
213+
[dist]
214+
targets = ["x86_64-pc-windows-msvc", "aarch64-pc-windows-msvc"]
215+
216+
[dist.github-custom-runners]
217+
x86_64-pc-windows-msvc.container = "messense/cargo-xwin"
218+
aarch64-pc-windows-msvc.container = "messense/cargo-xwin"
219+
220+
# (yes, that /is/ valid TOML)
221+
```
222+
223+
Note that you can use containers for non-cross reasons: maybe you want your binaries to be
224+
compatible with really old versions of glibc, older than Ubuntu 20.04: in this case, you
225+
can do something like:
226+
227+
```toml
228+
[dist.github-custom-runners.x86_64-unknown-linux-gnu]
229+
container = { image = "quay.io/pypa/manylinux_2_28_x86_64", host = "x86_64-unknown-linux-musl" }
230+
231+
[dist.github-custom-runners.aarch64-unknown-linux-gnu]
232+
container = { image = "quay.io/pypa/manylinux_2_28_x86_64", host = "x86_64-unknown-linux-musl" }
233+
```
234+
235+
Note that here, the host triple for those container images is overriden to be `x86_64-unknown-linux-musl`, because dist itself (which must run in the container) might be using a too-recent version of glibc.
236+
237+
Because of dist's cross-compilation support, if you have both `cargo-zigbuild` and `cargo-xwin`
238+
installed on a macOS machine, you can build pretty much every target dist supports, by running
239+
`dist build --artifacts all` — in fact, this is used to develop dist itself!
240+
111241
### Build and upload artifacts on every pull request
112242

113243
> since 0.3.0

cargo-dist-schema/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ schemars.workspace = true
2626
semver.workspace = true
2727
serde.workspace = true
2828
serde_json.workspace = true
29-
29+
target-lexicon.workspace = true
3030

3131
[dev-dependencies]
3232
insta.workspace = true

0 commit comments

Comments
 (0)