Skip to content

fix: build release binaries with CGO_ENABLED=0 - #97

Open
dhryoo wants to merge 1 commit into
onecli:mainfrom
dhryoo:fix/cgo-disabled-static-builds
Open

fix: build release binaries with CGO_ENABLED=0#97
dhryoo wants to merge 1 commit into
onecli:mainfrom
dhryoo:fix/cgo-disabled-static-builds

Conversation

@dhryoo

@dhryoo dhryoo commented Jul 26, 2026

Copy link
Copy Markdown

Problem

The published linux binaries are dynamically linked against the release runner's glibc, so they refuse to start on distros with an older one:

$ onecli version
onecli: /lib64/libc.so.6: version `GLIBC_2.34' not found (required by onecli)
onecli: /lib64/libc.so.6: version `GLIBC_2.32' not found (required by onecli)

$ objdump -T onecli | grep -o 'GLIBC_[0-9.]*' | sort -uV | tail -2
GLIBC_2.32
GLIBC_2.34

This affects every still-supported distro on glibc < 2.32:

Distro glibc
RHEL / Rocky / AlmaLinux 8 2.28
Debian 10 (buster) 2.28
Ubuntu 20.04 LTS 2.31

There is no fallback — the binary cannot execute at all, so onecli is simply unusable on these systems. I hit this installing NanoClaw on Rocky Linux 8.10, where its setup step fails at onecli_not_on_path_after_install because the freshly-downloaded binary won't run.

Cause

.goreleaser.yaml doesn't pin CGO_ENABLED. goreleaser cross-compiles darwin and windows, so those artifacts are already built without cgo — only the native linux build picks up the runner's libc and ends up dynamically linked.

Fix

One env entry on the build. This makes the existing cross-compile behaviour explicit and applies it to linux too.

Why this is safe

The source imports no cgo:

  • no import "C", no #cgo directives, no cgo build tags anywhere in *.go
  • every dependency is pure Go — kong, x/term, x/sys, yaml
  • internal/auth reaches the OS keychain through a Keychain interface that NewStore explicitly accepts as nil, not through a cgo binding

Verification

All six release targets build clean with CGO_ENABLED=0:

linux/amd64    ✅   darwin/amd64   ✅   windows/amd64  ✅
linux/arm64    ✅   darwin/arm64   ✅   windows/arm64  ✅

The resulting linux binary is static and runs on glibc 2.28:

$ file onecli
ELF 64-bit LSB executable, x86-64, statically linked, stripped

$ ./onecli version
{"version": "2.2.5", "server_version": "...", "server_status": "ok"}

goreleaser check passes.

Trade-off worth naming

With cgo off, Go uses its pure-Go resolver and os/user implementation instead of the libc ones. For a CLI whose job is HTTPS calls to the OneCLI API this is not a behaviour change in practice, and it's already what the darwin and windows artifacts do today — so this only makes linux consistent with them.

🤖 Generated with Claude Code

The published linux binaries are dynamically linked against the release
runner's glibc, so they fail to start on distros with an older one:

    $ onecli version
    onecli: /lib64/libc.so.6: version `GLIBC_2.34' not found (required by onecli)
    onecli: /lib64/libc.so.6: version `GLIBC_2.32' not found (required by onecli)

    $ objdump -T onecli | grep -o 'GLIBC_[0-9.]*' | sort -uV | tail -2
    GLIBC_2.32
    GLIBC_2.34

This affects every still-supported distro on glibc < 2.32 — RHEL/Rocky/
AlmaLinux 8 (2.28), Debian 10 (2.28), Ubuntu 20.04 (2.31).

goreleaser cross-compiles darwin and windows, so those artifacts are
already built without cgo; only the native linux build picks up the
runner's libc. Setting CGO_ENABLED=0 makes that explicit and uniform.

The source imports no cgo — no `import "C"`, no `#cgo` directives, no
cgo build tags — and every dependency is pure Go (kong, x/term, x/sys,
yaml). internal/auth reaches the OS keychain through an interface that
callers may leave nil, not through a cgo binding.

Verified all six release targets build clean with CGO_ENABLED=0
(linux, darwin, windows x amd64, arm64) and that the resulting linux
binary is statically linked and runs on glibc 2.28:

    $ file onecli
    ELF 64-bit LSB executable, x86-64, statically linked, stripped
    $ ./onecli version
    {"version": "2.2.5", "server_status": "ok"}

`goreleaser check` passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant