Skip to content

release: build every artifact with cgo disabled - #30

Merged
CamiloSierraH merged 1 commit into
mainfrom
david/release-static-builds
Sep 23, 2026
Merged

CamiloSierraH merged 1 commit into
mainfrom
david/release-static-builds

Conversation

@davidhogeg-ch

Copy link
Copy Markdown
Contributor

Why

The clickhouse-diagnostic-linux-amd64 asset we publish is dynamically linked and carries GLIBC_2.32 and GLIBC_2.34 version requirements. On a RHEL-8-era host it exits before any of our code runs:

./clickhouse-diagnostic: /lib64/libc.so.6: version `GLIBC_2.34' not found (required by ./clickhouse-diagnostic)
./clickhouse-diagnostic: /lib64/libc.so.6: version `GLIBC_2.32' not found (required by ./clickhouse-diagnostic)

This came off a live self-managed case where the customer was asked to run the collector, could not start it, and went to their sysadmin team to have glibc upgraded — for a tool that needs no C library at all. Measured on the downloaded tarballs of both v0.4.5 and v0.5.0, so it is not new and upgrading does not clear it.

The cause

The release loop ran a plain go build for six targets. Go disables cgo on its own when cross-compiling, so five came out static. linux/amd64 is the same platform as the release runner, so it is not a cross-compile, cgo stayed on, and that one binary picked up a dynamic link to the runner's glibc. Nothing in the tool asks for cgo — the linux/arm64 build of the same source has always been static with zero glibc references.

What changed

Makefile — CGO_ENABLED=0 on the release go build, plus a comment recording why. Two lines of behaviour; the rest is the comment.

The build and install targets are deliberately untouched: those produce a local dev binary, not a shipped artifact, and a dev build linking the local libc is harmless.

Verification

Matched arms, same source tree, same amd64 container (golang:1.23.9, ldd (Debian GLIBC 2.36-9+deb12u10) 2.36), only the flag differing:

build file glibc version refs
GOOS=linux GOARCH=amd64 go build dynamically linked GLIBC_2.2.5 2.3.2 2.32 2.34
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build statically linked none

The first arm reproduces the published artifact's requirement, including the exact two versions the customer's loader rejected.

Then make release on this branch, in an amd64 container so the native target is the one that used to break:

linux-amd64      ELF 64-bit LSB executable, x86-64, statically linked | GLIBC refs: 0
linux-arm64      ELF 64-bit LSB executable, ARM aarch64, statically linked | GLIBC refs: 0
darwin-amd64     Mach-O 64-bit executable x86_64
darwin-arm64     Mach-O 64-bit executable arm64
windows-amd64    PE32+ executable (console) x86-64, for MS Windows
windows-arm64    PE32+ executable (console) Aarch64, for MS Windows

All six archives are produced, the linux-amd64 archive holds the same 229 entries as the official v0.5.0 one, and the packaged binary starts under ldd (GNU libc) 2.28 on a native amd64 Rocky Linux 8 container. go test ./... passes (all packages ok).

Note on the stopgap

v0.5.0-static-amd64 is a pre-release holding a hand-built static amd64 archive, cut for that customer before this fix existed. It can be deleted once the next tagged release carries the change: gh release delete v0.5.0-static-amd64 --cleanup-tag.

🤖 Generated with Claude Code

The published clickhouse-diagnostic-linux-amd64 binary is dynamically linked
and carries GLIBC_2.32 and GLIBC_2.34 version requirements, so on a RHEL-8-era
host it exits before running any of our code:

  ./clickhouse-diagnostic: /lib64/libc.so.6: version `GLIBC_2.34' not found

The release loop ran a plain `go build` for six targets. Go turns cgo off by
itself when cross-compiling, so five came out static; linux/amd64 matches the
release runner, is therefore not a cross-compile, kept cgo on and picked up a
dynamic link to the runner's glibc. Setting CGO_ENABLED=0 makes the choice
explicit and independent of whichever host cuts the release.

Matched arms, same source tree and same amd64 container (glibc 2.36), only the
flag differing:

  without CGO_ENABLED=0  dynamically linked  GLIBC_2.2.5 2.3.2 2.32 2.34
  with CGO_ENABLED=0     statically linked   no GLIBC references

After the change `make release` produces all six archives; both Linux binaries
are statically linked with zero glibc references, darwin stays Mach-O and
windows stays PE32+, and the linux-amd64 archive holds the same 229 entries as
v0.5.0. The packaged binary starts on a glibc 2.28 userland. `go test ./...`
passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Release paths remain inconsistently configured and are not covered by PR checks.

Review effort: Lite
Findings: None

What changed in this PR

This PR disables cgo for release builds to produce statically linked Linux artifacts without newer glibc requirements.

Changes:

  • Sets CGO_ENABLED=0 for release builds.
  • Documents the glibc compatibility rationale.
File Summary
Makefile Release builds disable cgo; documented single-target commands and PR coverage still need alignment.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@CamiloSierraH CamiloSierraH left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@CamiloSierraH
CamiloSierraH merged commit 869f209 into main Sep 23, 2026
3 checks passed
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.

3 participants