Skip to content
This repository was archived by the owner on Jun 23, 2025. It is now read-only.

Commit 6be43df

Browse files
authored
fix: cross-compilation using Cross (#21)
Modify the build script to fix GOCACHE and GOMODCACHE and let them point to a directory we can write to. Cross sets HOME to root (/), which is read-only for the user running the build. When building for aarch64, set CC to aarch64-linux-gnu-gcc so that Go uses the correct compiler to emit CGo code. Signed-off-by: Miroslav Bajtoš <[email protected]>
1 parent 5c81685 commit 6be43df

File tree

5 files changed

+99
-5
lines changed

5 files changed

+99
-5
lines changed

.github/workflows/ci.yaml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,46 @@ jobs:
131131
echo "PR title is too long (greater than 72 characters)"
132132
exit 1
133133
fi
134+
135+
cross-compile:
136+
name: Cross-compile for ${{ matrix.target }}
137+
runs-on: ubuntu-latest
138+
strategy:
139+
fail-fast: false
140+
matrix:
141+
include:
142+
- target: x86_64-unknown-linux-gnu
143+
test: true
144+
- target: aarch64-unknown-linux-gnu
145+
test: false
146+
steps:
147+
- name: Checkout
148+
uses: actions/checkout@v3
149+
150+
- name: Setup Rust
151+
uses: dtolnay/rust-toolchain@52e69531e6f69a396bc9d1226284493a5db969ff # v1
152+
with:
153+
toolchain: stable
154+
target: ${{ matrix.target }}
155+
156+
- name: Setup Cross
157+
run: |
158+
curl -L https://github.com/cross-rs/cross/releases/latest/download/cross-x86_64-unknown-linux-gnu.tar.gz -o /tmp/cross.tgz
159+
tar xzf /tmp/cross.tgz -C ~/.cargo/bin
160+
cross --version
161+
162+
- name: Cache Rust deps
163+
uses: Swatinem/rust-cache@988c164c3d0e93c4dbab36aaf5bbeb77425b2894 # v2.4.0
164+
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
165+
with:
166+
shared-key: cross-${{ matrix.target }}
167+
cache-on-failure: true
168+
169+
- name: Build
170+
run: cross build --all-targets --target ${{ matrix.target }}
171+
172+
- name: Test
173+
if: matrix.test == 'true'
174+
run: cross test --target ${{ matrix.target }}
175+
176+

Cross.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[target.x86_64-unknown-linux-gnu]
2+
dockerfile = "cross/Dockerfile"
3+
4+
[target.aarch64-unknown-linux-gnu]
5+
dockerfile = "cross/Dockerfile"
6+

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,21 @@ Rusty-Lassie's build script copies the DLL into the target directory next to the
8888
main executable. All you need is to include this DLL in your distribution
8989
archive.
9090

91+
## Cross-compilation
92+
93+
If you are building your project using
94+
[Cross](https://github.com/cross-rs/cross), you need to install Go in the Docker
95+
images used by Cross.
96+
97+
Check out our own [Cross.toml](./Cross.toml) and
98+
[cross/Dockerfile](./cross/Dockerfile) for inspiration.
99+
100+
Learn more in Cross and Go documentation:
101+
102+
- [Configuring cross via a Cross.toml file](https://github.com/cross-rs/cross#option-2-configuring-cross-via-a-crosstoml-file)
103+
- [Dockerfiles](https://github.com/cross-rs/cross#dockerfiles)
104+
- [Download and install Go](https://go.dev/doc/install)
105+
91106
## License
92107

93108
This library is dual-licensed under Apache 2.0 and MIT terms.

build.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ fn build_lassie() {
2323

2424
eprintln!("Building {out_file} for {arch} (GOARCH={goarch})");
2525

26-
let status = Command::new("go")
27-
.current_dir("go-lib")
26+
let mut cmd = Command::new("go");
27+
cmd.current_dir("go-lib")
2828
.args([
2929
"build",
3030
"-tags",
@@ -37,9 +37,30 @@ fn build_lassie() {
3737
.env("GOARCH", goarch)
3838
// We must explicitly enable CGO when cross-compiling
3939
// See e.g. https://stackoverflow.com/q/74976549/69868
40-
.env("CGO_ENABLED", "1")
41-
.status()
42-
.expect("Cannot execute `go`, make sure it's installed.\nLearn more at https://go.dev/doc/install");
40+
.env("CGO_ENABLED", "1");
41+
42+
if env::var("HOME") == Ok("/".to_string()) && env::var("CROSS_RUNNER").is_ok() {
43+
// When cross-compiling using `cross build`, HOME is set to `/` and go is trying to
44+
// create its cache dir in /.cache/go-build, which is not writable.
45+
// We fix the problem by explicitly setting the GOCACHE and GOMODCACHE env vars
46+
let target_dir = env::var("CARGO_TARGET_DIR")
47+
.expect("cannot obtain CARGO_TARGET_DIR from the environment");
48+
49+
cmd.env("GOCACHE", format!("{target_dir}/go/cache"))
50+
.env("GOMODCACHE", format!("{target_dir}/go/pkg-mod-cache"));
51+
52+
if arch == "aarch64" {
53+
// Overwrite Go CC config, unless it's already provided by the user
54+
// See https://github.com/golang/go/issues/28966
55+
if env::var("CC").is_err() {
56+
cmd.env("CC", "aarch64-linux-gnu-gcc");
57+
}
58+
}
59+
}
60+
61+
let status = cmd.status().expect(
62+
"Cannot execute `go`, make sure it's installed.\nLearn more at https://go.dev/doc/install",
63+
);
4364
assert!(status.success(), "`go build` failed");
4465

4566
println!("cargo:rustc-link-search=native={out_dir}");

cross/Dockerfile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
ARG CROSS_BASE_IMAGE
2+
FROM $CROSS_BASE_IMAGE
3+
4+
RUN rm -rf /usr/local/go
5+
RUN curl -L https://go.dev/dl/go1.20.5.linux-amd64.tar.gz | tar -xz -C /usr/local
6+
7+
ENV PATH /usr/local/go/bin:$PATH
8+
# Verify that `go` is in the path
9+
RUN go version

0 commit comments

Comments
 (0)