Conversation
Both Android arm64 jobs now fail in "Set up Android SDK", before any goffi
code runs:
Warning: Failed to find package 'tools'
Error: The process '/usr/local/lib/android/sdk/cmdline-tools/16.0/bin/sdkmanager' failed with exit code 1
android-actions/setup-android@v3 defaults its `packages` input to
`tools platform-tools` and runs `sdkmanager <pkg>` for each entry. Google's
SDK repository index (repository2-3.xml) no longer contains a `tools`
package, while `platform-tools` and `cmdline-tools` are still listed, so
the `tools` call exits 1. The same breakage is tracked upstream in
android-actions/setup-android#537. The last green run of these jobs on main
was for c8f74c6 on 2026-09-10; the workflow has not changed since, and the
failure is identical on a docs-only PR.
Nothing in this workflow or in scripts/check-android-arm64.sh uses the
`tools` package. Pass `packages: platform-tools`, which keeps everything
the step installed before except the package that no longer exists. The
action still accepts licenses, exports ANDROID_HOME and puts sdkmanager on
PATH, which the following NDK step relies on.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
A default goffi binary cannot start on Alpine: PT_INTERP names the glibc
loader, which musl systems do not have, and the cgo_import_dynamic
directives name libdl.so.2, libc.so.6 and libpthread.so.0, none of which
musl ships. Its whole POSIX surface lives in one arch-named object,
libc.musl-<arch>.so.1. Both facts are baked into the ELF at link time, so
the libc flavor is a build-time choice.
The goffi_musl tag selects musl flavors of the three directive groups
(internal/dl, internal/syscall, internal/fakecgo) and bakes the musl
loader path into PT_INTERP via //go:cgo_dynamic_linker. That directive is
restricted to cgo-generated code, so musl builds pass
-gcflags=github.com/go-webgpu/goffi/internal/dl=-std. Forgetting the flag
is a compile error naming the directive, not a binary that dies at
startup with a confusing ENOENT.
The glibc libdl imports move out of dl_linux.go into dl_linux_glibc.go so
the RTLD_* constants stay shared by both flavors.
One symbol is dropped from the musl set: pthread_get_stacksize_np is a
Darwin-only API that glibc's lazy PLT tolerates but musl's immediate
binding would reject at load time. Its trampoline is only reachable from
the Darwin thread-entry path, so the linker drops it on Linux. The
fakecgo musl files are generated by gen.go from the same symbol tables as
the glibc ones.
goffi_static wins over goffi_musl; the tag is inert off Linux.
Verification:
- TestMuslDirectiveParity pins glibc/musl symbol-set parity (including
the one intentional exclusion), per-arch SONAMEs and the interpreter.
- TestMuslLinkArtifacts builds linux/{amd64,arm64} probes and checks
PT_INTERP and DT_NEEDED with debug/elf.
- cmd/musl-probe runs against a real musl libc: dlopen/dlsym, float and
integer calls, errno capture, qsort with a Go callback, and a
64-goroutine hammer that makes the runtime create OS threads through
fakecgo's pthread imports. scripts/check-musl.sh runs it inside Alpine
and is wired into CI.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
unxed
force-pushed
the
feature/goffi-musl
branch
from
September 25, 2026 16:31
34042b8 to
1e5844a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Step 3 of the split agreed in #76, built on the
goffi_staticfrom #78.A default goffi binary does not start on Alpine. Its
PT_INTERPnames the glibc loader, and itsDT_NEEDEDentries namelibdl.so.2,libc.so.6andlibpthread.so.0. musl has neither: it ships one loader,/lib/ld-musl-<arch>.so.1, and one libc,libc.musl-<arch>.so.1. Both are fixed at link time, so the libc flavor has to be chosen at build time.CGO_ENABLED=0 go build -tags goffi_musl \ -gcflags=github.com/go-webgpu/goffi/internal/dl=-std ./...What changes (linux/amd64 and linux/arm64 only):
internal/dl,internal/syscallandinternal/fakecgoget musl flavors of theircgo_import_dynamicdirectives. The glibc libdl imports move fromdl_linux.gotodl_linux_glibc.go, so theRTLD_*constants stay shared.internal/dlsets the musl loader with//go:cgo_dynamic_linker. The compiler accepts that directive only in cgo-generated code, which is why the build needs the-gcflagsline. If you leave the flag out, the compile fails and names the directive.pthread_get_stacksize_npis left out of the musl set. It is a Darwin-only API. glibc binds lazily and never calls it, but musl binds every import at load time and would refuse to start the binary. The linker already drops its trampoline on Linux.gen.gogenerates the fakecgo musl files from the same symbol tables as the glibc ones.goffi_statictakes precedence.goffi_muslhas no effect off Linux. FFI is fully available undergoffi_musl.Tests:
TestMuslDirectiveParitychecks that the glibc and musl symbol sets match, apart from the one intended exclusion. It also checks the per-arch SONAMEs and the interpreter.TestMuslLinkArtifactsbuilds linux/amd64 and linux/arm64 probes and readsPT_INTERPandDT_NEEDEDwithdebug/elf.cmd/musl-proberuns in an Alpine container (scripts/check-musl.sh, newmusl-buildCI job on Go 1.25 and 1.26). It covers dlopen/dlsym, integer and float calls, errno, aqsortcallback, and a goroutine hammer that makes the runtime start OS threads through fakecgo's pthread imports.Docs:
docs/MUSL.md, the README linking-modes table and CHANGELOG.The Android arm64 jobs fail in "Set up Android SDK" before any goffi code runs. That failure is unrelated to this PR and is fixed by #85.
🤖 Generated with Claude Code