FreeBSD tier-2 cross-link under Zig 0.16: link staged libs by path, only when used - #1930
Merged
Merged
Conversation
…bs by path, only when used FreeBSD cross-linking a program that reaches the final link died with `ld.lld: cannot find entry symbol _start` + `error: libc not available`. Reported downstream as an OpenSSL-specific failure (aeo CLI's FreeBSD asset), but it was not crypto-specific: a program importing only std.io failed identically. Root cause: tools/ae_cross.c's FreeBSD/tier-2 wiring was written for Zig 0.16 (its own comments say so), but the crossbuild kit and CI pinned Zig 0.13, which does not resolve the base libc/CRT from --sysroot for a FreeBSD target. Bumping to 0.16 (separate commits in aether-crossbuild/deps.lock and the aeo release workflows) fixes the libc/_start error and exposes two tier-2 bugs 0.13 had masked, fixed here: - **Over-linking.** The CROSSBUILD_SYSROOT probe appended `-l<name>` for every archive STAGED in the sysroot, regardless of whether the program used it. A sysroot provisioned with openssl+pcre2+zlib plus the contrib veneers stages libpcre2-8.a / libaether_host_ruby.a / … even for a program that imports none of them. Zig 0.13 tolerated the dangling `-l`s; Zig 0.16 hard-errors (`unable to find dynamic system library 'pcre2-8'`). The probe now also gates on the program's resolved import closure — the raw `// aether-link:` header codegen emits — so a lib is linked only when it is BOTH staged AND requested. - **Mangled -L under --sysroot.** Tier-2 libs were linked as `-L$CROSSBUILD_SYSROOT/lib -lNAME`. Zig 0.16 resolves a bare `-L` beneath `--sysroot`, so an absolute `-L=/abs/sysroots/…` became `<base-sysroot>/abs/sysroots/…` and the libs were never found. They are now linked BY ABSOLUTE ARCHIVE PATH (`$CROSSBUILD_SYSROOT/lib/libNAME.a`), a plain input file immune to the sysroot L-path rewriting. openssl (ssl+crypto) and the sqlite veneer (veneer before backing lib) keep their multi-archive order. windows.yml's hardcoded zig fetch is bumped 0.13.0 -> 0.16.0 with the archive rename (0.16 is zig-<arch>-<os>-<ver>, was <os>-<arch>). aether's own scripts/get-zig.sh was already on 0.16. Verified on the real crossbuild kit (Zig 0.16, fully-staged FreeBSD15 sysroot): a std.cryptography program, a std.io-only program, and a std.regex program all cross-link to valid FreeBSD ELFs; the crypto link carries only libssl.a + libcrypto.a by absolute path (no -L, no unused python/ruby/pcre2). linux-musl and windows cross builds unaffected; `make test` 409/409. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
paul-hammant
force-pushed
the
fix/freebsd-cross-zig016-tier2-linking
branch
from
September 7, 2026 05:48
a83374c to
7a0c5e3
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.
Fixes FreeBSD cross-linking failing
ld.lld: cannot find entry symbol _start+error: libc not available— reported downstream (aeo'sasks/) as anOpenSSL-specific failure blocking the aeo CLI's FreeBSD asset.
What it actually was
Not crypto-specific. Reproduced on the real crossbuild kit: a program
importing only
std.iofails identically. The trigger is a Zig versionmismatch —
tools/ae_cross.c's FreeBSD/tier-2 wiring is written for Zig0.16 (its own comments say so: "Zig 0.16 supplies its CRT/libc", "resolves
target-root -L paths beneath --sysroot"), but the crossbuild kit and CI pinned
Zig 0.13, which does not resolve the base libc/CRT from
--sysrootfor aFreeBSD target →
libc not available.The Zig 0.13→0.16 bump (companion commits in aether-crossbuild
deps.lockand the aeo release workflows) fixes the reported error and exposes two
tier-2 linking bugs that 0.13 had masked — fixed in this PR:
1. Over-linking staged-but-unused libs
The CROSSBUILD_SYSROOT probe added
-l<name>for every archive staged in thesysroot, regardless of use. A sysroot with openssl+pcre2+zlib plus the contrib
veneers stages
libpcre2-8.a/libaether_host_ruby.a/ … even for a programimporting none of them. Zig 0.13 tolerated the dangling
-ls; Zig 0.16hard-errors (
unable to find dynamic system library 'pcre2-8'). The probe nowalso gates on the program's resolved import closure — the raw
// aether-link:header codegen emits — so a lib links only when staged AND requested.
2. Mangled
-Lunder--sysrootTier-2 libs used
-L$CROSSBUILD_SYSROOT/lib -lNAME. Zig 0.16 resolves a bare-Lbeneath--sysroot, so an absolute-L=/abs/sysroots/…became<base-sysroot>/abs/sysroots/…and the libs were never found. They are nowlinked by absolute archive path (
$CROSSBUILD_SYSROOT/lib/libNAME.a) — aplain input file, immune to the rewriting. openssl (ssl+crypto) and the sqlite
veneer keep their multi-archive link order.
windows.yml's hardcoded zig fetch is bumped to 0.16 with the archive rename(0.16 is
zig-<arch>-<os>-<ver>, was<os>-<arch>). aether's ownscripts/get-zig.shwas already on 0.16.Verification
On the real crossbuild kit (Zig 0.16, fully-staged FreeBSD15 sysroot):
std.cryptographyprogram → valid FreeBSD ELF; link carries onlylibssl.a+libcrypto.aby absolute path (no-L, no unusedpython/ruby/pcre2).
std.io-only andstd.regexprograms → valid FreeBSD ELFs.make test409/409.The FreeBSD-cross CI leg (
ci-freebsd-cross, already on 0.16 viascripts/get-zig.sh) exercises this path.Companion changes (separate repos)
aether-crossbuild:deps.lockzig 0.13.0 → 0.16.0 (+ get-zig.sh comment).aeo:release-aeo.yml/release-aeo-agent.ymlzig pin 0.13.0 → 0.16.0and the archive-name rename; once this lands, aeo bumps
AEO_FREEBSD_MIN_AEand drops
continue-on-erroron its FreeBSD jobs.🤖 Generated with Claude Code