Skip to content

Commit a5592ea

Browse files
authored
Merge pull request #214 from crazy-max/zig
xx-go: zig support
2 parents f074957 + 9fb3908 commit a5592ea

File tree

4 files changed

+258
-15
lines changed

4 files changed

+258
-15
lines changed

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,28 @@ RUN go build -o hello hello.go && \
342342
xx-verify hello
343343
```
344344

345+
`xx-go` can also drive [Zig](https://ziglang.org/) as the underlying C
346+
toolchain for CGo builds. This can be useful when you want a single
347+
cross-compiling toolchain that works across multiple platforms, or when you
348+
already rely on Zig in your build pipeline.
349+
350+
Zig support is **opt-in** and is enabled by setting the `XX_GO_PREFER_C_COMPILER`
351+
environment variable to `zig`. When this variable is set and the `zig` binary
352+
is available in `PATH`, `xx-go` will configure CGo to use Zig as the C compiler
353+
for the current target.
354+
355+
```dockerfile
356+
FROM --platform=$BUILDPLATFORM golang:alpine
357+
RUN apk add zig
358+
# ...
359+
ARG TARGETPLATFORM
360+
RUN xx-apk add musl-dev
361+
ENV CGO_ENABLED=1
362+
ENV XX_GO_PREFER_C_COMPILER=zig
363+
RUN xx-go build -o hello ./hello.go && \
364+
xx-verify hello
365+
```
366+
345367
## Rust
346368

347369
Building Rust can be achieved with the `xx-cargo` wrapper that automatically

src/test-go.bats

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,96 @@ testHelloCGO() {
511511
assert_output --partial "PKG_CONFIG=$(xx-info triple)-pkg-config"
512512
}
513513

514+
testHelloCGOZig() {
515+
if ! supportZig; then
516+
skip "Zig not supported"
517+
fi
518+
export CGO_ENABLED=1
519+
export XX_GO_PREFER_C_COMPILER=zig
520+
add zig
521+
run xx-go build -x -o /tmp/a.out ./fixtures/hello_cgo.go
522+
assert_success
523+
run xx-verify /tmp/a.out
524+
assert_success
525+
if ! xx-info is-cross; then
526+
run /tmp/a.out
527+
assert_success
528+
assert_output "hello cgo"
529+
fi
530+
}
531+
532+
@test "native-hellocgo-zig" {
533+
unset TARGETARCH
534+
testHelloCGOZig
535+
}
536+
537+
@test "amd64-hellocgo-zig" {
538+
export TARGETARCH=amd64
539+
testHelloCGOZig
540+
}
541+
542+
@test "arm64-hellocgo-zig" {
543+
export TARGETARCH=arm64
544+
testHelloCGOZig
545+
}
546+
547+
@test "arm-hellocgo-zig" {
548+
export TARGETARCH=arm
549+
testHelloCGOZig
550+
}
551+
552+
@test "ppc64le-hellocgo-zig" {
553+
export TARGETARCH=ppc64le
554+
testHelloCGOZig
555+
}
556+
557+
@test "riscv64-hellocgo-zig" {
558+
if ! supportRiscVCGo; then
559+
skip "RISC-V CGO not supported"
560+
fi
561+
export TARGETARCH=riscv64
562+
testHelloCGOZig
563+
}
564+
565+
@test "loong64-hellocgo-zig" {
566+
if ! supportLoong64CGo; then
567+
skip "LOONGARCH64 not supported"
568+
fi
569+
if [ -f /etc/alpine-release ]; then
570+
# FIXME: loong64-hellocgo issue on alpine < 3.21
571+
# ld.lld: error: unknown emulation: elf64loongarch
572+
# ld.lld: error: /loongarch64-alpine-linux-musl/usr/lib/gcc/loongarch64-alpine-linux-musl/14.2.0/crtbeginS.o:(.text+0x0): unknown relocation (102) against symbol
573+
# error: unknown target triple 'loongarch64-alpine-linux-musl', please use -triple or -arch
574+
alpineRelease=$(cat /etc/alpine-release)
575+
if ! grep PRETTY_NAME /etc/os-release | cut -d '=' -f 2 | tr -d '"' | grep -q "edge$" || [ "$(semver compare "$alpineRelease" "3.21.0")" -lt 0 ]; then
576+
skip
577+
fi
578+
fi
579+
export TARGETARCH=loong64
580+
testHelloCGOZig
581+
}
582+
583+
@test "386-hellocgo-zig" {
584+
export TARGETARCH=386
585+
testHelloCGOZig
586+
}
587+
588+
@test "arm64-cgoenv-zig" {
589+
if ! supportZig; then
590+
skip "Zig not supported"
591+
fi
592+
export TARGETARCH=arm64
593+
export XX_GO_PREFER_C_COMPILER=zig
594+
export CGO_ENABLED=1
595+
596+
add zig
597+
# single/double quotes changed in between go versions
598+
run sh -c "xx-go env | sed 's/[\"'\'']//g'"
599+
assert_success
600+
assert_output --partial "CC=zig cc -target"
601+
assert_output --partial "CXX=zig c++ -target"
602+
}
603+
514604
@test "wrap-unwrap" {
515605
target="arm64"
516606
if [ "$(xx-info arch)" = "arm64" ]; then target="amd64"; fi
@@ -535,3 +625,10 @@ testHelloCGO() {
535625
assert_success
536626
assert_output "$nativeArch"
537627
}
628+
629+
@test "clean-packages" {
630+
if ! supportZig; then
631+
skip "Zig not supported"
632+
fi
633+
del zig
634+
}

src/test_helper.bash

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,7 @@ supportLoong64CGo() {
142142
supportRC() {
143143
command -v llvm-rc >/dev/null 2>&1
144144
}
145+
146+
supportZig() {
147+
[ -f /etc/alpine-release ] && versionGTE "$(xx-info os-version | cut -d'.' -f1-2)" "3.20"
148+
}

src/xx-go

Lines changed: 135 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ for l in $(xx-info env); do
66
export "${l?}"
77
done
88

9+
: "${XX_GO_PREFER_C_COMPILER=clang}"
10+
: "${XX_ZIG_TRIPLE=unknown-unknown-none}"
11+
912
export GOOS="${TARGETOS}"
1013
export GOARCH="${TARGETARCH}"
1114

@@ -24,6 +27,28 @@ case "$TARGETARCH" in
2427
;;
2528
esac
2629
fi
30+
if [ "$XX_LIBC" = "musl" ]; then
31+
XX_ZIG_TRIPLE="x86_64-linux-musl"
32+
else
33+
XX_ZIG_TRIPLE="x86_64-linux-gnu"
34+
fi
35+
if [ "$TARGETOS" = "darwin" ]; then
36+
XX_ZIG_TRIPLE="x86_64-macos-none"
37+
elif [ "$TARGETOS" = "windows" ]; then
38+
XX_ZIG_TRIPLE="x86_64-windows-gnu"
39+
fi
40+
;;
41+
"arm64")
42+
if [ "$XX_LIBC" = "musl" ]; then
43+
XX_ZIG_TRIPLE="aarch64-linux-musl"
44+
else
45+
XX_ZIG_TRIPLE="aarch64-linux-gnu"
46+
fi
47+
if [ "$TARGETOS" = "darwin" ]; then
48+
XX_ZIG_TRIPLE="aarch64-macos-none"
49+
elif [ "$TARGETOS" = "windows" ]; then
50+
XX_ZIG_TRIPLE="aarch64-windows-gnu"
51+
fi
2752
;;
2853
"arm")
2954
if [ -z "$GOARM" ]; then
@@ -39,6 +64,94 @@ case "$TARGETARCH" in
3964
;;
4065
esac
4166
fi
67+
if [ "$XX_LIBC" = "musl" ]; then
68+
XX_ZIG_TRIPLE="arm-linux-musleabihf"
69+
else
70+
XX_ZIG_TRIPLE="arm-linux-gnueabihf"
71+
fi
72+
if [ "$TARGETVARIANT" = "v6" ]; then
73+
if [ "$XX_LIBC" = "musl" ]; then
74+
XX_ZIG_TRIPLE="arm-linux-musleabi"
75+
else
76+
XX_ZIG_TRIPLE="arm-linux-gnueabi"
77+
fi
78+
fi
79+
if [ "$TARGETVARIANT" = "v5" ]; then
80+
if [ "$XX_LIBC" = "musl" ]; then
81+
XX_ZIG_TRIPLE="arm-linux-musleabi"
82+
else
83+
XX_ZIG_TRIPLE="arm-linux-gnueabi"
84+
fi
85+
fi
86+
if [ "$TARGETOS" = "windows" ]; then
87+
XX_ZIG_TRIPLE="arm-windows-gnu"
88+
fi
89+
;;
90+
"riscv64")
91+
if [ "$XX_LIBC" = "musl" ]; then
92+
XX_ZIG_TRIPLE="riscv64-linux-musl"
93+
else
94+
XX_ZIG_TRIPLE="riscv64-linux-gnu"
95+
fi
96+
;;
97+
"ppc64le")
98+
if [ "$XX_LIBC" = "musl" ]; then
99+
XX_ZIG_TRIPLE="powerpc64le-linux-musl"
100+
else
101+
XX_ZIG_TRIPLE="powerpc64le-linux-gnu"
102+
fi
103+
;;
104+
"s390x")
105+
if [ "$XX_LIBC" = "musl" ]; then
106+
XX_ZIG_TRIPLE="s390x-linux-musl"
107+
else
108+
XX_ZIG_TRIPLE="s390x-linux-gnu"
109+
fi
110+
;;
111+
"loong64")
112+
if [ "$XX_LIBC" = "musl" ]; then
113+
XX_ZIG_TRIPLE="loongarch64-linux-musl"
114+
else
115+
XX_ZIG_TRIPLE="loongarch64-linux-gnu"
116+
fi
117+
;;
118+
"386")
119+
if [ "$XX_LIBC" = "musl" ]; then
120+
XX_ZIG_TRIPLE="x86-linux-musl"
121+
else
122+
XX_ZIG_TRIPLE="x86-linux-gnu"
123+
fi
124+
if [ "$TARGETOS" = "windows" ]; then
125+
XX_ZIG_TRIPLE="x86-windows-gnu"
126+
fi
127+
;;
128+
"mips")
129+
if [ "$XX_LIBC" = "musl" ]; then
130+
XX_ZIG_TRIPLE="mips-linux-musl"
131+
else
132+
XX_ZIG_TRIPLE="mips-linux-gnueabi"
133+
fi
134+
;;
135+
"mipsle")
136+
if [ "$XX_LIBC" = "musl" ]; then
137+
XX_ZIG_TRIPLE="mipsel-linux-musl"
138+
else
139+
XX_ZIG_TRIPLE="mipsel-linux-gnueabi"
140+
fi
141+
;;
142+
"mips64")
143+
if [ "$XX_LIBC" = "musl" ]; then
144+
XX_ZIG_TRIPLE="mips64-linux-musl"
145+
else
146+
XX_ZIG_TRIPLE="mips64-linux-gnuabi64"
147+
fi
148+
;;
149+
"mips64le")
150+
if [ "$XX_LIBC" = "musl" ]; then
151+
XX_ZIG_TRIPLE="mips64el-linux-musl"
152+
else
153+
XX_ZIG_TRIPLE="mips64el-linux-gnuabi64"
154+
fi
42155
;;
43156
esac
44157

@@ -76,26 +189,33 @@ if command -v "$XX_TRIPLE-g++" >/dev/null 2>/dev/null; then
76189
cxx_set=1
77190
fi
78191

79-
if command -v clang >/dev/null 2>/dev/null; then
80-
triple=$(xx-clang --print-target-triple || true)
81-
if [ -n "$triple" ]; then
82-
export CC="$triple-clang"
83-
export CXX="$triple-clang++"
192+
if [ "$XX_GO_PREFER_C_COMPILER" = "clang" ]; then
193+
if command -v clang >/dev/null 2>/dev/null; then
194+
triple=$(xx-clang --print-target-triple || true)
195+
if [ -n "$triple" ]; then
196+
export CC="$triple-clang"
197+
export CXX="$triple-clang++"
198+
c_set=1
199+
cxx_set=1
200+
fi
201+
fi
202+
if command -v "$XX_TRIPLE-ar" >/dev/null 2>/dev/null; then
203+
export AR="$XX_TRIPLE-ar"
204+
ar_set=1
205+
fi
206+
if command -v "$XX_TRIPLE-pkg-config" >/dev/null 2>/dev/null; then
207+
export PKG_CONFIG="$XX_TRIPLE-pkg-config"
208+
pkgconfig_set=1
209+
fi
210+
elif [ "$XX_GO_PREFER_C_COMPILER" = "zig" ]; then
211+
if command -v "zig" >/dev/null 2>/dev/null; then
212+
export CC="zig cc -target $XX_ZIG_TRIPLE"
84213
c_set=1
214+
export CXX="zig c++ -target $XX_ZIG_TRIPLE"
85215
cxx_set=1
86216
fi
87217
fi
88218

89-
if command -v "$XX_TRIPLE-ar" >/dev/null 2>/dev/null; then
90-
export AR="$XX_TRIPLE-ar"
91-
ar_set=1
92-
fi
93-
94-
if command -v "$XX_TRIPLE-pkg-config" >/dev/null 2>/dev/null; then
95-
export PKG_CONFIG="$XX_TRIPLE-pkg-config"
96-
pkgconfig_set=1
97-
fi
98-
99219
if [ -z "$GOBIN" ] && [ -n "$GOPATH" ] && [ -n "$GOARCH" ] && [ -n "$GOOS" ]; then
100220
export PATH="${GOPATH}/bin/${GOOS}_${GOARCH}:${PATH}"
101221
fi

0 commit comments

Comments
 (0)