Repository navigation
fix(builder/go): register the generated C header after compiling - #7113
Conversation
Header discovery ran before the compiler, and it returns nil when the file is absent. GoReleaser refuses a non-empty dist, so the header never existed at that point and was never registered: every c-archive and c-shared build shipped a library without its header. Discovery now runs after the build, in the loop that registers the binaries, and the header gets the same mod timestamp as its library so archives containing both stay reproducible. Closes #6897 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
Deploying goreleaser with
|
| Latest commit: |
a85cd79
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://26e7d0f7.goreleaser.pages.dev |
| Branch Preview URL: | https://fix-go-c-headers.goreleaser.pages.dev |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7113 +/- ##
==========================================
+ Coverage 91.47% 91.52% +0.04%
==========================================
Files 191 191
Lines 15877 15874 -3
==========================================
+ Hits 14524 14529 +5
+ Misses 1353 1345 -8 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
Address the PR patch-coverage failure with a real C archive build. Assert that a header-specific timestamp error is returned, no artifacts are registered, and the library timestamp was set successfully. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
Fix the Windows CI assertion to match the native artifact path used before registration. Keep the header-specific error and artifact assertions intact. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
caarlos0
left a comment
There was a problem hiding this comment.
No findings. I could not find a correctness, scope, compatibility or determinism problem in this change.
What I verified
- The premise holds.
getHeaderArtifactForLibrarydoes anos.Stat, and GoReleaser refuses a non-emptydist, so the pre-Execcall always returnednil. The regression came from c3bfb5a (#6254), which added the existence check but left the call before compilation. Before that commit the header was registered unconditionally, so this restores behaviour rather than adding it. - The move is complete. The type guard is unchanged, so
NoMainCheckand wasmc-shared(artifactTypereturnsBinary) behave exactly as before.strings.TrimSuffix(a.Path, options.Ext)matches how the Go toolchain derives the header name (hdrTarget := target[:len(target)-len(filepath.Ext(target))] + ".h"), andextForonly ever returns single-dot extensions, so the two formulas agree. - No multi-library collision.
go build -buildmode=c-archive -o out ./...fails with-buildmode=c-archive requires exactly one main package(reproduced locally), solen(allbinaries) == 1whenever the branch fires. Artifact insertion order is therefore identical to before:[header, library]. - No template leakage.
Template.WithExtraFieldscallscopying(), which allocates a freshFieldsmap, sotpl.WithArtifact(ha)cannot leak.ArtifactExt ".h"into a later use oftpl. - The
ChTimescall on the header is justified, not scope creep.pkg/archive/tarandpkg/archive/zipfall back to the file's own mtime unlessarchives.files[].info.mtimeis set, so without it the header would carry wall-clock time into an otherwise reproducible archive. - The tests earn their place. They fail against
main("[]" should have 1 item(s), but has 0), and deleting only the headerChTimescall makes the mtime assertion fail with a wall-clock time, so that assertion really covers the reproducibility claim. - Portability is proven, not assumed. These are the first tests here that need a C toolchain, so I checked the real matrix instead of reasoning about it:
test (ubuntu-latest)andtest (windows-latest)both pass at a85cd79.CGO_ENABLED=1is set explicitly inbuild.Env, so an ambientCGO_ENABLED=0cannot break them, and the failure test needs no compiler at all. Cost is about +13s on the Windows job.
Worth a changelog line
For c-archive and c-shared users, archive contents and checksums change relative to v2.13.x, because the .h comes back into archives and nFPM packages. One knock-on: a single archives entry that mixes native c-shared (gets a header) with wasm c-shared (no header) will now trip ErrArchiveDifferentBinaryCount, since checkArtifacts compares per-platform counts. That was also the pre-#6254 behaviour, so it is a restoration and not a new break, but it will look like a break to anyone upgrading from v2.13.x.
Disclosure
This review was produced by GitHub Copilot CLI, a bot, and includes independent maintainer-perspective and adversarial passes. It is posted as a comment rather than an approval only because GitHub does not allow approving your own pull request. No local build, lint or fmt was run, per instruction; CI covers them and is green.
Closes #6897
Problem
getHeaderArtifactForLibraryreturnsnilwhen the header file is absent, and it was called beforebase.Exec:The issue describes this as affecting clean builds. It is worse than that: GoReleaser refuses to run against a non-empty
dist(dist is not empty, remove it before running goreleaser), so the header can never exist when discovery runs. Everyc-archiveandc-sharedbuild was affected.Verified on
mainwithbuildmode: c-shared—dist/lib_darwin_arm64_v8.0/cexport.hexists on disk,artifacts.jsonlists only the library, andtar tzfshows the archive containscexport.dylibalone. Headers feedarchives,nfpms,makeselfandreportsizes, so a shipped C library was unusable by any consumer.Introduced by
c3bfb5a5b(#6254), which correctly stopped registering nonexistent headers but placed the check before compilation.Fix
Header discovery moves into the loop that registers the binaries, after the build. The header also gets
base.ChTimes, so amod_timestampbuild stays reproducible — without it the header would carry a wall-clock mtime into the archive while the library was pinned.Tests
TestBuildCgoLibraryRegistersGeneratedHeader— realc-archiveandc-sharedbuilds, asserting the header artifact and its mod timestamp.TestBuildCgoLibraryFailureDoesNotRegisterStaleHeader— keepsc3bfb5a5b's guarantee: a failed build must not register a leftover header.TestBuildCgoLibraryHeaderTimestampFailure- a real C archive build verifies that a header-specific timestamp error is returned, no artifacts are registered, and the library timestamp is set. This covers the new error path without changing the coverage threshold.