From 789cb73c301db23dd9d08b00bf8dae2b8893f7dd Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 28 May 2026 13:29:01 +0300 Subject: [PATCH 1/2] fix: add FreeBSD ARM64 build support (closes #52) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add freebsd to build tags in 4 files that were missing it: - internal/arch/arm64/call_arm64.go (root cause of #52) - internal/syscall/syscall_arm64.go - internal/syscall/syscall_arm64.s - ffi/callback_arm64.s (hidden bug: Go side had freebsd, asm did not) FreeBSD ARM64 uses identical AAPCS64 calling convention as Linux ARM64. No code changes needed — purely build tag additions. CI cross-compilation check now validates all 8 platforms. Platform count: 7 → 8 targets. --- .github/workflows/ci.yml | 22 ++++++++++++---------- CHANGELOG.md | 10 ++++++++++ README.md | 5 +++-- ROADMAP.md | 2 +- docs/ARCHITECTURE.md | 1 + ffi/callback_arm64.s | 2 +- internal/arch/arm64/call_arm64.go | 6 +++--- internal/syscall/syscall_arm64.go | 4 ++-- internal/syscall/syscall_arm64.s | 2 +- 9 files changed, 34 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ab3f38..8a1022f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -124,21 +124,23 @@ jobs: done # FreeBSD requires -gcflags="-std" for fakecgo's //go:cgo_export_dynamic - echo "Building freebsd/amd64 (with -gcflags for fakecgo)..." - if GOOS=freebsd GOARCH=amd64 go build \ - -gcflags="github.com/go-webgpu/goffi/internal/fakecgo=-std" \ - ./... 2>&1; then - echo " ✅ freebsd/amd64" - else - echo " ❌ freebsd/amd64 FAILED" - FAILED=1 - fi + for fbsd_arch in amd64 arm64; do + echo "Building freebsd/${fbsd_arch} (with -gcflags for fakecgo)..." + if GOOS=freebsd GOARCH=${fbsd_arch} go build \ + -gcflags="github.com/go-webgpu/goffi/internal/fakecgo=-std" \ + ./... 2>&1; then + echo " ✅ freebsd/${fbsd_arch}" + else + echo " ❌ freebsd/${fbsd_arch} FAILED" + FAILED=1 + fi + done if [ $FAILED -eq 1 ]; then echo "❌ Cross-compilation check FAILED" exit 1 fi - echo "✅ All 7 platforms compile successfully" + echo "✅ All 8 platforms compile successfully" # Unit tests - Platform-specific (Linux + Windows + macOS AMD64) # Tested under both CGO_ENABLED=0 (fakecgo path) and CGO_ENABLED=1 (real diff --git a/CHANGELOG.md b/CHANGELOG.md index e136a63..9fcca77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.5.3] - 2026-05-28 + +### Fixed +- **FreeBSD ARM64 build failure** — added `freebsd` to build tags in `internal/arch/arm64/call_arm64.go`, `internal/syscall/syscall_arm64.go`, `internal/syscall/syscall_arm64.s`, and `ffi/callback_arm64.s`. FreeBSD ARM64 uses identical AAPCS64 calling convention as Linux ARM64 — no code changes needed, only build tag additions. Requires same `-gcflags="github.com/go-webgpu/goffi/internal/fakecgo=-std"` workaround as FreeBSD AMD64. Closes [#52](https://github.com/go-webgpu/goffi/issues/52) +- **FreeBSD ARM64 callback trampoline** — `ffi/callback_arm64.s` was missing `freebsd` in build tags while `ffi/callback_arm64.go` (Go side) already included it, causing `NewCallback()` to silently return invalid addresses on FreeBSD ARM64 + +### Changed +- Platform count: 7 → 8 targets (added FreeBSD ARM64) +- CI cross-compilation check now validates all 8 platforms including `freebsd/arm64` + ## [0.5.2] - 2026-05-25 ### Added diff --git a/README.md b/README.md index ee87f41..54fa4c1 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ ffi.CallFunction(cif, sym, unsafe.Pointer(&result), args) |---|---------|---------| | **Zero CGO** | Pure Go | No C compiler needed. `go get` and build. | | **Fast** | 88–114 ns/op | Pre-computed CIF, zero per-call allocations | -| **Cross-platform** | 7 targets | Windows, Linux, macOS, FreeBSD × AMD64 + ARM64 | +| **Cross-platform** | 8 targets | Windows, Linux, macOS, FreeBSD × AMD64 + ARM64 | | **Callbacks** | C→Go safe | `crosscall2` integration, struct args, works from any C thread | | **Type-safe** | Runtime validation | 5 typed error types with `errors.As()` support | | **Struct pass/return** | Full ABI | Args: INTEGER/SSE classification. Returns: ≤8B (RAX/XMM0), 9–16B (4 modes: RAX/XMM × RAX/XMM), >16B (sret) | @@ -273,7 +273,7 @@ if err != nil { | Context support | Timeouts/cancellation | No | No | | C-thread callbacks | crosscall2 | crosscall2 | Full | | String/bool/slice args | Raw pointers only | Auto-marshaling | Full | -| Platform breadth | 7 targets | 8 GOARCH / 20+ OS×ARCH | All | +| Platform breadth | 8 targets | 8 GOARCH / 20+ OS×ARCH | All | | AMD64 overhead | 88–114 ns | Not published | ~140 ns (Go 1.26 claims ~30% reduction) | **Choose goffi** for GPU/real-time workloads: struct passing, zero per-call overhead, callback float returns, typed errors. @@ -326,6 +326,7 @@ if err != nil { | macOS | amd64 | System V | v0.1.1 | Tested | | macOS | arm64 | AAPCS64 | v0.3.7 | Tested (M3 Pro) | | FreeBSD | amd64 | System V | v0.5.0 | Cross-compile verified | +| FreeBSD | arm64 | AAPCS64 | v0.5.3 | Cross-compile verified | --- diff --git a/ROADMAP.md b/ROADMAP.md index 7f6c3cb..2797391 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -128,7 +128,7 @@ v1.0.0 LTS → Long-term support release (2027 Q1) **v0.5.0** = Platform coverage ✅ RELEASED (2026-03-29) - **Windows ARM64** support (Snapdragon X Elite, tested by @SideFx) - **FreeBSD amd64** support (cross-compile verified) -- 7 platform targets (Linux/Windows/macOS/FreeBSD × amd64 + ARM64) +- 7 platform targets (Linux/Windows/macOS/FreeBSD × amd64 + Linux/macOS/Windows ARM64) **v0.5.1** = Struct ABI + CGO_ENABLED=1 ✅ RELEASED (2026-05-13) - **CGO_ENABLED=1 support** (PR #37 by @jiyeyuran) — dual-mode build, race detector compatible diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 6e586dd..b2abfe9 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -402,6 +402,7 @@ go run github.com/go-webgpu/goffi/cmd/variadic-test | **macOS** | AMD64 | System V | Production | | **macOS** | ARM64 | AAPCS64 | Production (tested on M3 Pro) | | **FreeBSD** | AMD64 | System V | Cross-compile verified | +| **FreeBSD** | ARM64 | AAPCS64 | Cross-compile verified | | **Linux** | ARM64 | AAPCS64 | Production | --- diff --git a/ffi/callback_arm64.s b/ffi/callback_arm64.s index c74ae80..81740d9 100644 --- a/ffi/callback_arm64.s +++ b/ffi/callback_arm64.s @@ -1,4 +1,4 @@ -//go:build (linux || darwin) && arm64 +//go:build (linux || darwin || freebsd) && arm64 #include "textflag.h" #include "go_asm.h" diff --git a/internal/arch/arm64/call_arm64.go b/internal/arch/arm64/call_arm64.go index 9bf0da6..11c4277 100644 --- a/internal/arch/arm64/call_arm64.go +++ b/internal/arch/arm64/call_arm64.go @@ -1,7 +1,7 @@ -//go:build arm64 && (linux || darwin || windows) +//go:build arm64 && (linux || darwin || windows || freebsd) -// AAPCS64 ABI implementation (Linux, macOS, Windows on ARM64) -// Windows ARM64 uses the same calling convention as Unix ARM64 for non-variadic functions. +// AAPCS64 ABI implementation (Linux, macOS, Windows, FreeBSD on ARM64) +// All ARM64 platforms use the same AAPCS64 calling convention for non-variadic functions. // See: https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions package arm64 diff --git a/internal/syscall/syscall_arm64.go b/internal/syscall/syscall_arm64.go index fe3c636..4aa88ca 100644 --- a/internal/syscall/syscall_arm64.go +++ b/internal/syscall/syscall_arm64.go @@ -1,6 +1,6 @@ -//go:build (linux || darwin || windows) && arm64 +//go:build (linux || darwin || windows || freebsd) && arm64 -// AAPCS64 ABI syscall implementation (Linux, macOS, Windows on ARM64) +// AAPCS64 ABI syscall implementation (Linux, macOS, Windows, FreeBSD on ARM64) // ARM64 Procedure Call Standard - identical across all platforms. package syscall diff --git a/internal/syscall/syscall_arm64.s b/internal/syscall/syscall_arm64.s index a12a700..35e526d 100644 --- a/internal/syscall/syscall_arm64.s +++ b/internal/syscall/syscall_arm64.s @@ -1,4 +1,4 @@ -//go:build (linux || darwin || windows) && arm64 +//go:build (linux || darwin || windows || freebsd) && arm64 #include "textflag.h" #include "abi_arm64.h" From 1a8cc3d952e6208418e2b29c27dd27b7c6e42a83 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 28 May 2026 13:33:36 +0300 Subject: [PATCH 2/2] docs: document go vet false positives in dl_windows.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add explicit comments explaining that go vet warnings on lines 52 and 84 are false positives — Windows DLL handles and function pointers are OS values, not Go heap pointers. --- ffi/dl_windows.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ffi/dl_windows.go b/ffi/dl_windows.go index a4528b8..9ac990a 100644 --- a/ffi/dl_windows.go +++ b/ffi/dl_windows.go @@ -49,8 +49,8 @@ func LoadLibrary(name string) (unsafe.Pointer, error) { } } - // Safe: handle is immediately converted from uintptr to unsafe.Pointer - // without intermediate storage, keeping it reachable by GC. + // go vet: "possible misuse of unsafe.Pointer" — false positive. + // Windows DLL handles are opaque OS values, not Go heap pointers. return unsafe.Pointer(handle), nil } @@ -81,8 +81,8 @@ func GetSymbol(handle unsafe.Pointer, name string) (unsafe.Pointer, error) { } } - // Safe: proc is immediately converted from uintptr to unsafe.Pointer - // without intermediate storage, keeping it reachable by GC. + // go vet: "possible misuse of unsafe.Pointer" — false positive. + // GetProcAddress returns a function pointer, not a Go heap pointer. return unsafe.Pointer(proc), nil }