detached 12ee364

purego: fix cgo fallback build for linux/mips (#462)

Package purego failed to compile under CGO_ENABLED=1 for the Linux
GOARCHs that lack a per-architecture struct file (mips, mipsle,
mips64, mips64le). func.go and syscall.go reference helpers
(addStruct, getStruct, shouldBundleStackArgs, collectStackArgs,
bundleStackArgs, syscall_syscallN) that are only defined for the
natively supported architectures, so the documented integer-only
cgo fallback was broken for these targets.

Add struct_other.go, providing those struct helpers as panicking
stubs for architectures that have no dedicated struct_<arch>.go,
and add the syscall_syscallN stub to syscall_cgo_linux.go.
struct_386.go was already a pure stub, so it is removed and 386
now shares struct_other.go. Structs and floats remain unsupported,
exactly as the README's "Cgo Fallback" section documents.

Add a CI step that cross-compiles linux/mips with CGO_ENABLED=1 to
guard against this regression.

Closes #460

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
commit
12ee364b5d17bb94d0f5e22976c5a3a6e7c74a8f
author
Hajime Hoshi · · 2026-06-16 03:35 UTC
committer
GitHub · · 2026-06-16 03:35 UTC
parent
d339eb0
signature
GPG UnverifiedB5690EEEBB952194 The key is unknown
4 files · +59 -52
M .github/workflows/test.yml +8 -0
@@ -83,6 +83,14 @@ jobs:
8383 env GOOS=linux GOARCH=ppc64le go build -v ./...
8484 env GOOS=linux GOARCH=riscv64 go build -v ./...
8585
86+ - name: go build (Linux mips, Cgo)
87+ # mips builds only via the Cgo fallback (CGO_ENABLED=1). See #460.
88+ if: runner.os == 'Linux'
89+ run: |
90+ sudo apt-get update
91+ sudo apt-get install -y gcc-mips-linux-gnu
92+ env GOOS=linux GOARCH=mips CGO_ENABLED=1 CC=mips-linux-gnu-gcc go build -v ./...
93+
8694 - name: go build (plugin)
8795 if: runner.os == 'Linux' || runner.os == 'macOS'
8896 run:
@@ -83,6 +83,14 @@ jobs:
83 env GOOS=linux GOARCH=ppc64le go build -v ./...83 env GOOS=linux GOARCH=ppc64le go build -v ./...
84 env GOOS=linux GOARCH=riscv64 go build -v ./...84 env GOOS=linux GOARCH=riscv64 go build -v ./...
85 85
86+ - name: go build (Linux mips, Cgo)
87+ # mips builds only via the Cgo fallback (CGO_ENABLED=1). See #460.
88+ if: runner.os == 'Linux'
89+ run: |
90+ sudo apt-get update
91+ sudo apt-get install -y gcc-mips-linux-gnu
92+ env GOOS=linux GOARCH=mips CGO_ENABLED=1 CC=mips-linux-gnu-gcc go build -v ./...
93+
86 - name: go build (plugin)94 - name: go build (plugin)
87 if: runner.os == 'Linux' || runner.os == 'macOS'95 if: runner.os == 'Linux' || runner.os == 'macOS'
88 run:96 run:
D struct_386.go +0 -52
@@ -1,52 +0,0 @@
1-// SPDX-License-Identifier: Apache-2.0
2-// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
3-
4-package purego
5-
6-import (
7- "reflect"
8- "unsafe"
9-)
10-
11-func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
12- panic("purego: struct arguments are not supported")
13-}
14-
15-func getStruct(outType reflect.Type, syscall syscallArgs) (v reflect.Value) {
16- panic("purego: struct returns are not supported")
17-}
18-
19-func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
20- panic("purego: placeRegisters not implemented on 386")
21-}
22-
23-// shouldBundleStackArgs always returns false on 386
24-// since C-style stack argument bundling is only needed on Darwin ARM64.
25-func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool {
26- return false
27-}
28-
29-// structFitsInRegisters is not used on 386.
30-func structFitsInRegisters(val reflect.Value, tempNumInts, tempNumFloats int) (bool, int, int) {
31- panic("purego: structFitsInRegisters should not be called on 386")
32-}
33-
34-// collectStackArgs is not used on 386.
35-func collectStackArgs(args []reflect.Value, startIdx int, numInts, numFloats int,
36- keepAlive []any, addInt, addFloat, addStack func(uintptr),
37- pNumInts, pNumFloats, pNumStack *int) ([]reflect.Value, []any) {
38- panic("purego: collectStackArgs should not be called on 386")
39-}
40-
41-// bundleStackArgs is not used on 386.
42-func bundleStackArgs(stackArgs []reflect.Value, addStack func(uintptr)) {
43- panic("purego: bundleStackArgs should not be called on 386")
44-}
45-
46-func getCallbackStruct(inType reflect.Type, frame unsafe.Pointer, floatsN *int, intsN *int, stackSlot *int, stackByteOffset *uintptr) reflect.Value {
47- panic("purego: struct callback arguments are not supported on 386")
48-}
49-
50-func setStruct(a *callbackArgs, ret reflect.Value) {
51- panic("purego: struct returns are not supported on 386")
52-}
@@ -1,52 +0,0 @@
1-// SPDX-License-Identifier: Apache-2.0
2-// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
3-
4-package purego
5-
6-import (
7- "reflect"
8- "unsafe"
9-)
10-
11-func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
12- panic("purego: struct arguments are not supported")
13-}
14-
15-func getStruct(outType reflect.Type, syscall syscallArgs) (v reflect.Value) {
16- panic("purego: struct returns are not supported")
17-}
18-
19-func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
20- panic("purego: placeRegisters not implemented on 386")
21-}
22-
23-// shouldBundleStackArgs always returns false on 386
24-// since C-style stack argument bundling is only needed on Darwin ARM64.
25-func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool {
26- return false
27-}
28-
29-// structFitsInRegisters is not used on 386.
30-func structFitsInRegisters(val reflect.Value, tempNumInts, tempNumFloats int) (bool, int, int) {
31- panic("purego: structFitsInRegisters should not be called on 386")
32-}
33-
34-// collectStackArgs is not used on 386.
35-func collectStackArgs(args []reflect.Value, startIdx int, numInts, numFloats int,
36- keepAlive []any, addInt, addFloat, addStack func(uintptr),
37- pNumInts, pNumFloats, pNumStack *int) ([]reflect.Value, []any) {
38- panic("purego: collectStackArgs should not be called on 386")
39-}
40-
41-// bundleStackArgs is not used on 386.
42-func bundleStackArgs(stackArgs []reflect.Value, addStack func(uintptr)) {
43- panic("purego: bundleStackArgs should not be called on 386")
44-}
45-
46-func getCallbackStruct(inType reflect.Type, frame unsafe.Pointer, floatsN *int, intsN *int, stackSlot *int, stackByteOffset *uintptr) reflect.Value {
47- panic("purego: struct callback arguments are not supported on 386")
48-}
49-
50-func setStruct(a *callbackArgs, ret reflect.Value) {
51- panic("purego: struct returns are not supported on 386")
52-}
A struct_other.go +47 -0
@@ -0,0 +1,47 @@
1+// SPDX-License-Identifier: Apache-2.0
2+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
3+
4+//go:build !(amd64 || arm || arm64 || loong64 || ppc64le || riscv64 || s390x)
5+
6+package purego
7+
8+import (
9+ "reflect"
10+ "unsafe"
11+)
12+
13+// This file provides the struct-handling helpers for architectures that do
14+// not support struct arguments or returns: 386, and any architecture reachable
15+// only through the integer-only cgo fallback. Every struct operation panics.
16+
17+func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
18+ panic("purego: struct arguments are not supported on this architecture")
19+}
20+
21+func getStruct(outType reflect.Type, syscall syscallArgs) reflect.Value {
22+ panic("purego: struct returns are not supported on this architecture")
23+}
24+
25+// shouldBundleStackArgs always returns false because C-style stack argument
26+// bundling is only needed on Darwin ARM64.
27+func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool {
28+ return false
29+}
30+
31+func collectStackArgs(args []reflect.Value, startIdx int, numInts, numFloats int,
32+ keepAlive []any, addInt, addFloat, addStack func(uintptr),
33+ pNumInts, pNumFloats, pNumStack *int) ([]reflect.Value, []any) {
34+ panic("purego: collectStackArgs should not be called on this architecture")
35+}
36+
37+func bundleStackArgs(stackArgs []reflect.Value, addStack func(uintptr)) {
38+ panic("purego: bundleStackArgs should not be called on this architecture")
39+}
40+
41+func getCallbackStruct(inType reflect.Type, frame unsafe.Pointer, floatsN *int, intsN *int, stackSlot *int, stackByteOffset *uintptr) reflect.Value {
42+ panic("purego: struct callback arguments are not supported on this architecture")
43+}
44+
45+func setStruct(a *callbackArgs, ret reflect.Value) {
46+ panic("purego: struct returns are not supported on this architecture")
47+}
@@ -0,0 +1,47 @@
1+// SPDX-License-Identifier: Apache-2.0
2+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
3+
4+//go:build !(amd64 || arm || arm64 || loong64 || ppc64le || riscv64 || s390x)
5+
6+package purego
7+
8+import (
9+ "reflect"
10+ "unsafe"
11+)
12+
13+// This file provides the struct-handling helpers for architectures that do
14+// not support struct arguments or returns: 386, and any architecture reachable
15+// only through the integer-only cgo fallback. Every struct operation panics.
16+
17+func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
18+ panic("purego: struct arguments are not supported on this architecture")
19+}
20+
21+func getStruct(outType reflect.Type, syscall syscallArgs) reflect.Value {
22+ panic("purego: struct returns are not supported on this architecture")
23+}
24+
25+// shouldBundleStackArgs always returns false because C-style stack argument
26+// bundling is only needed on Darwin ARM64.
27+func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool {
28+ return false
29+}
30+
31+func collectStackArgs(args []reflect.Value, startIdx int, numInts, numFloats int,
32+ keepAlive []any, addInt, addFloat, addStack func(uintptr),
33+ pNumInts, pNumFloats, pNumStack *int) ([]reflect.Value, []any) {
34+ panic("purego: collectStackArgs should not be called on this architecture")
35+}
36+
37+func bundleStackArgs(stackArgs []reflect.Value, addStack func(uintptr)) {
38+ panic("purego: bundleStackArgs should not be called on this architecture")
39+}
40+
41+func getCallbackStruct(inType reflect.Type, frame unsafe.Pointer, floatsN *int, intsN *int, stackSlot *int, stackByteOffset *uintptr) reflect.Value {
42+ panic("purego: struct callback arguments are not supported on this architecture")
43+}
44+
45+func setStruct(a *callbackArgs, ret reflect.Value) {
46+ panic("purego: struct returns are not supported on this architecture")
47+}
M syscall_cgo_linux.go +4 -0
@@ -14,3 +14,7 @@ var syscallXABI0 = uintptr(cgo.SyscallXABI0)
1414 func NewCallback(_ any) uintptr {
1515 panic("purego: NewCallback on Linux is only supported on 386/amd64/arm64/arm/loong64/ppc64le/riscv64/s390x")
1616 }
17+
18+func syscall_syscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) {
19+ panic("purego: syscall_syscallN is only supported on windows")
20+}
@@ -14,3 +14,7 @@ var syscallXABI0 = uintptr(cgo.SyscallXABI0)
14 func NewCallback(_ any) uintptr {14 func NewCallback(_ any) uintptr {
15 panic("purego: NewCallback on Linux is only supported on 386/amd64/arm64/arm/loong64/ppc64le/riscv64/s390x")15 panic("purego: NewCallback on Linux is only supported on 386/amd64/arm64/arm/loong64/ppc64le/riscv64/s390x")
16 }16 }
17+
18+func syscall_syscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) {
19+ panic("purego: syscall_syscallN is only supported on windows")
20+}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 102

↑↓ moveenter openesc close