ci: single arm64 debian-13 build host; ThinLTO everywhere; baseline-only x64; rust+link merge; sysroots; WebKit a36c188; rust 2026-07-20#34782
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughChangesThis PR consolidates x64 baseline handling, updates CI release gating and artifact aliases, adds Linux glibc and macOS SDK bootstrap support, pins Rust nightly toolchains, removes AVX2-based platform selection, and applies Rust fixed-size chunk and expression-based refactors. Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Comment |
f72bd40 to
710f3fb
Compare
710f3fb to
84ca491
Compare
|
Added unit tests in Note on the fail-before gate: the |
10907c1 to
d4d4c5e
Compare
There was a problem hiding this comment.
Additional findings (outside current diff — PR may have been updated during review):
-
🟡
.buildkite/ci.mjs:1626-1633— The comment says "enforce only on main or [lto] PRs", but the code issizeRecordOnly = isMainBranch() || !options.forceLto— on main,recordOnlyis true so--no-failis passed and the size threshold is not enforced (it only records the baseline, matching pre-PR behavior and your own verification table). Enforcement happens only on[lto]PRs; consider rewording to something like "enforce only on [lto] PRs; main records the baseline; non-LTO PRs annotate only."Extended reasoning...
What the comment says vs. what the code does
The newly-added comment at
.buildkite/ci.mjs:1626-1628reads:Binary-size tracking. Non-LTO PR binaries are larger than the LTO main canary they compare against, so enforce only on main or [lto] PRs; other PRs still annotate.
The code immediately below it is:
const sizeRecordOnly = isMainBranch() || !options.forceLto; steps.push(getBinarySizeStep(strippedPlatforms, options, { recordOnly: sizeRecordOnly }));
getBinarySizeStep()translatesrecordOnly: trueinto the--no-failflag, which makesscripts/binary-size.tsannotate without failing the build. So "enforce" ↔recordOnly === false, and "annotate only" ↔recordOnly === true.Step-by-step proof
Scenario isMainBranch()options.forceLtosizeRecordOnly--no-failpassed?Enforced? main true(irrelevant — short-circuit) trueyes no PR without [lto]falsefalsetrueyes no PR with [lto]falsetrue(truthy string)falseno yes So enforcement happens only on
[lto]PRs. Main is record-only — it never enforces the threshold.The code is intentional; the comment is wrong
Three independent sources confirm main is meant to be record-only:
- Pre-PR behavior: the old line was
recordOnly: isMainBranch()— main was already record-only before this PR touched it. getBinarySizeStep()'s own docstring (unchanged in this PR): "Runs on PR builds (comparison) and main (record-only, to produce the baseline artifact)."- The PR description's verification table: the
mainrow showsbinary-size --no-failcount = 1, i.e. main gets--no-fail.
So the logic is deliberate and correct; only the comment's phrase "enforce only on main or [lto] PRs" contradicts it.
Impact
No runtime effect — this is purely a documentation inaccuracy. But per REVIEW.md, comments must "carry only durable non-obvious content" and be accurate. A future reader of this comment would reasonably conclude that main hard-fails on binary-size regressions, when in fact main only records the baseline artifact and never fails on size. That could lead to confusion when debugging why a size regression on main didn't block the canary, or when someone later revisits this gating.
Suggested fix
Reword the comment to match the code, e.g.:
// Binary-size tracking. Non-LTO PR binaries are larger than the LTO main // canary they compare against, so enforce only on [lto] PRs; main records // the baseline; non-LTO PRs annotate only.
- Pre-PR behavior: the old line was
|
Good catch on the binary-size comment wording: |
d4d4c5e to
00ea037
Compare
There was a problem hiding this comment.
Additional findings (outside current diff — PR may have been updated during review):
-
🔴
.buildkite/scripts/upload-release.sh:340-349—alias_baseline_artifact()copies the zip verbatim (cp "$artifact" "$alias"), so the inner directory is stillbun-linux-x64-baseline/. On AVX2-capable machinesinstall.shcomputestarget=linux-x64(no-baselinesuffix), downloads the aliasedbun-linux-x64.zip, and thenmv "$bin_dir/bun-linux-x64/bun" ...fails with "Failed to move extracted bun to destination" — same forinstall.ps1(line 191/200 → "Download is corrupt or intercepted Antivirus?") andbun upgradefrom every already-installed haswell x64 build (EXE_SUBPATHusesVersion::FOLDER_NAMEwithEnvironment::BASELINE = false). The alias needs to repack: unzip → rename the inner directory to the aliased stem → re-zip.Extended reasoning...
What the bug is
upload-release.shnow aliases each*-baseline*.zipto its historical non-baseline name so "existing download URLs keep resolving" (per the code comment and the PR description). But the alias is created with a barerun_command cp "$artifact" "$alias", which renames only the zip file — the top-level directory inside the zip is unchanged.The zip layout is
${bunTriplet}.zip → ${bunTriplet}/bun[.exe]wherebunTriplet = bun-${os}-${arch}[-musl][-baseline](scripts/build/ci.ts:330–339,computeBunTriplet()/makeZip()). Sobun-linux-x64-baseline.zipcontainsbun-linux-x64-baseline/bun, and after thecpthe aliasedbun-linux-x64.zipalso containsbun-linux-x64-baseline/bun.Every consumer of these zips relies on the invariant that the inner directory name matches the zip filename stem — that convention is exactly what the alias exists to preserve.
Code paths that break
src/runtime/cli/install.sh(thecurl -fsSL https://bun.sh/install | bashpath):- Line 83:
Linux x86_64→target=linux-x64 - Line 117: appends
-baselineonly whengrep avx2 /proc/cpuinfois empty — on the vast majority of modern x64 machines AVX2 is present, sotargetstayslinux-x64(orlinux-x64-muslon Alpine) - Line 132: downloads
.../bun-linux-x64.zip→ gets the alias - Line 152:
unzip -oqd "$bin_dir" "$exe.zip"→ creates$bin_dir/bun-linux-x64-baseline/ - Line 155:
mv "$bin_dir/bun-linux-x64/bun" "$exe"→ No such file or directory →error 'Failed to move extracted bun to destination'
src/runtime/cli/install.ps1:- Line 143:
$Target = "bun-windows-$BunArch"(no-baselineunless$IsBaseline, which is CPU-feature-gated) - Line 148: downloads
.../bun-windows-x64.zip→ gets the alias - Line 191:
Test-Path "${BunBin}\bun-windows-x64\bun.exe"→ false (actual path is${BunBin}\bun-windows-x64-baseline\bun.exe) - Line 192: throws
"Download is corrupt or intercepted Antivirus?"
src/runtime/cli/upgrade_command.rs(bun upgrade):EXE_SUBPATH = Version::FOLDER_NAME + "/bun"(line 503–508), whereFOLDER_NAMEincludes-baselineonly ifEnvironment::BASELINEis true (line 116–123)- Every x64 binary already installed on user machines was built as haswell (non-baseline), so
Environment::BASELINE = falsein those binaries → they downloadbun-linux-x64.zip/bun-windows-x64.zip(the alias) and look forbun-linux-x64/buninside → extraction fails
Why nothing prevents it
The PR description says "the install scripts keep resolving." The URLs resolve — GitHub/S3 serve the aliased asset — but resolving the URL is only half the contract. The install scripts, install.ps1, and
bun upgradeall hard-code the inner-directory-matches-zip-stem convention, andcpdoesn't rewrite zip contents.Impact
On the first canary shipped from
mainafter this merges:curl -fsSL https://bun.sh/install | bashfails for essentially every Linux x64 glibc and musl user with a post-2013 CPU.irm bun.sh/install.ps1 | iexfails for essentially every Windows x64 user with an AVX2-capable CPU.bun upgradefails for every existing x64 install.
Users on non-AVX2 CPUs (who get
target=…-baselineand download the real-baseline.zip) are unaffected, as are aarch64 users.Step-by-step proof
- CI builds
bun-linux-x64-baseline.zipcontainingbun-linux-x64-baseline/bun(ci.tsmakeZip(cfg, bunTriplet, [...])stages files underresolve(buildDir, bunTriplet)). upload-release.shrunsalias_baseline_artifact "bun-linux-x64-baseline.zip"→ echoesbun-linux-x64.zip.run_command cp "bun-linux-x64-baseline.zip" "bun-linux-x64.zip"— byte-identical copy, inner dir stillbun-linux-x64-baseline/.- Both are uploaded to S3 + the GitHub release.
- A user on an AVX2-capable Ubuntu box runs
curl -fsSL https://bun.sh/install | bash. target=linux-x64(line 83);/proc/cpuinfocontainsavx2so line 117 does not append-baseline.bun_uri=.../releases/latest/download/bun-linux-x64.zip— downloads the alias.unzip -oqd "$HOME/.bun/bin" bun.zip→ creates$HOME/.bun/bin/bun-linux-x64-baseline/bun.mv "$HOME/.bun/bin/bun-linux-x64/bun" "$HOME/.bun/bin/bun"→mv: cannot stat …: No such file or directory.- Script exits with
error: Failed to move extracted bun to destination.
Fix
Repack the alias so the inner directory matches the aliased stem, e.g.:
local alias="$(alias_baseline_artifact "$artifact")" if [ -n "$alias" ]; then local src_dir="${artifact%.zip}" local dst_dir="${alias%.zip}" rm -rf "$src_dir" "$dst_dir" run_command unzip -q "$artifact" run_command mv "$src_dir" "$dst_dir" run_command zip -qr "$alias" "$dst_dir" rm -rf "$dst_dir" upload_one "$alias" fi
(
unzip/zipare already available on the release agent —install_aws_linuxinstallsunzip, and Amazon Linux 2023 shipszip; add acommand -v zip || package_manager_install zipguard if desired.) - Line 83:
00ea037 to
a903927
Compare
a903927 to
0b859d1
Compare
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/runtime/cli/install.ps1 (1)
133-135: 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy liftAdd one hermetic regression suite for baseline-free artifact resolution. The installer and upgrader now share unsuffixed x64 artifact naming, but the supplied tests only exercise build configuration.
src/runtime/cli/install.ps1#L133-L135: test plain Windows x64 archive selection for current and legacy requested versions.src/runtime/cli/install.sh#L108-L110: test Unix x64 resolution through fixture-backed redirect behavior, without public-network access.src/runtime/cli/upgrade_command.rs#L116-L124: test normal and profile ZIP/folder names selected by upgrade metadata parsing.As per coding guidelines, every behavioral change must include an automated regression test in the same change.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/runtime/cli/install.ps1` around lines 133 - 135, Add a hermetic regression suite covering baseline-free artifact resolution: in src/runtime/cli/install.ps1 lines 133-135, test plain Windows x64 archive selection for both current and legacy requested versions; in src/runtime/cli/install.sh lines 108-110, test Unix x64 resolution using fixture-backed redirects without network access; and in src/runtime/cli/upgrade_command.rs lines 116-124, test normal and profile ZIP/folder names produced by upgrade metadata parsing. Use the existing test conventions and keep all cases automated within this change.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.buildkite/ci.mjs:
- Around line 158-162: Condense the Windows LTO rationale comment in
.buildkite/ci.mjs lines 158-162 to three lines or fewer while retaining the key
constraint and reference to ltoDefault. Also condense the baseline-alias
compatibility rationale comment in .buildkite/scripts/upload-release.sh lines
317-320 to three lines or fewer, preserving its essential meaning.
In @.buildkite/scripts/upload-release.sh:
- Around line 340-346: Update the archive repacking flow around src_zip and
dst_zip to derive absolute workspace paths for all rm, unzip, mv, and zip file
operations, while passing relative paths to zip as needed to preserve archive
entry names. Ensure cleanup and repacking remain anchored to the intended
workspace regardless of the caller’s current directory.
In `@scripts/bootstrap.sh`:
- Around line 1408-1474: Require checksum verification in
install_linux_glibc_sysroot before any tar extraction by populating
linux_sysroot_sha256_x86_64 and linux_sysroot_sha256_aarch64 with the matching
published digests and removing the empty-checksum fallback. Ensure each
architecture uses download_and_verify_file and aborts rather than extracting
when its checksum is missing or invalid.
In `@scripts/build/config.ts`:
- Around line 564-583: Update detectLinuxGlibcSysroot so the aarch64 candidates
cannot include the generic /opt/linux-sysroot-glibc path used for x86_64; retain
only the arm64-specific path for aarch64 and preserve the existing x86_64
candidate behavior. Keep the environment override and undefined result
unchanged.
In `@src/js_parser/parse/parse_typescript.rs`:
- Around line 637-638: Update the comment in the TypeScript parsing code to
remove the temporary reference to duplicated slice8 implementations and retain
only the durable invariant that to_utf8_e_string guarantees is_utf16 == false,
explaining why accessing .data directly is safe.
In `@src/js_printer/lib.rs`:
- Around line 7926-7932: Compress the comment immediately above module_scope
into no more than three lines, preserving both points: Scope is not Copy, and
compute_reserved_names_for_scope only traverses members/generated/children, so
referencing the in-place tree.module_scope preserves the required lifetime.
In `@test/internal/macos-cross-config.test.ts`:
- Line 76: Remove the redundant “explicit override still wins” comment from the
regression test, leaving the adjacent assertion unchanged; retain only an issue
URL comment if one is required by the project guidelines.
---
Outside diff comments:
In `@src/runtime/cli/install.ps1`:
- Around line 133-135: Add a hermetic regression suite covering baseline-free
artifact resolution: in src/runtime/cli/install.ps1 lines 133-135, test plain
Windows x64 archive selection for both current and legacy requested versions; in
src/runtime/cli/install.sh lines 108-110, test Unix x64 resolution using
fixture-backed redirects without network access; and in
src/runtime/cli/upgrade_command.rs lines 116-124, test normal and profile
ZIP/folder names produced by upgrade metadata parsing. Use the existing test
conventions and keep all cases automated within this change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 2ec5289a-54b3-44cf-a26a-9793a1f92fd9
📒 Files selected for processing (48)
.buildkite/ci.mjs.buildkite/scripts/upload-release.sh.github/workflows/clippy.yml.github/workflows/format.yml.github/workflows/miri.ymlrust-toolchain.tomlscripts/bootstrap.shscripts/build/buildOptionsRs.tsscripts/build/ci.tsscripts/build/config.tsscripts/build/deps/webkit.tsscripts/build/flags.tsscripts/build/rust.tsscripts/build/source.tsscripts/build/tools.tssrc/ast/char_freq.rssrc/boringssl/lib.rssrc/bun_alloc/lib.rssrc/bun_bin/lib.rssrc/bun_core/Global.rssrc/bun_core/build.rssrc/bun_core/env.rssrc/bun_core/lib.rssrc/collections/bit_set.rssrc/collections/multi_array_list.rssrc/crash_handler/lib.rssrc/css/values/color.rssrc/http_jsc/websocket_client/WebSocketUpgradeClient.rssrc/install/PackageManager/CommandLineArguments.rssrc/install/resolvers/folder_resolver.rssrc/js_parser/parse/parse_typescript.rssrc/js_printer/lib.rssrc/jsc/bindings/ANSIHelpers.hsrc/jsc/bindings/c-bindings.cppsrc/jsc/bindings/xxhash3.cppsrc/options_types/compile_target.rssrc/react_compiler/ssa/enter_ssa.rssrc/router/lib.rssrc/runtime/cli/install.ps1src/runtime/cli/install.shsrc/runtime/cli/upgrade_command.rssrc/runtime/image/codecs.rssrc/runtime/node/path.rssrc/runtime/socket/udp_socket.rssrc/runtime/valkey_jsc/valkey.rssrc/runtime/webcore/encoding.rssrc/sql_jsc/mysql/MySQLValue.rstest/internal/macos-cross-config.test.ts
💤 Files with no reviewable changes (2)
- scripts/build/buildOptionsRs.ts
- src/jsc/bindings/c-bindings.cpp
0b859d1 to
40bcd4d
Compare
9045f7b to
2039218
Compare
2039218 to
ec0ca0f
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/bootstrap.sh`:
- Around line 1604-1640: Harden install_macos_sdk by eliminating execution of an
implicitly mutable xmac.mjs ref: default BUN_BOOTSTRAP_REPO_REF to the pinned
commit or tag associated with this bootstrap.sh, and add checksum verification
for the downloaded xmac_mjs before invoking it via bun. Reuse the existing
trusted-reference or sha256 validation patterns in the script, and abort before
execution when validation fails.
In `@src/jsc/bindings/ANSIHelpers.h`:
- Around line 50-53: Condense the comments at ANSIHelpers.h lines 50-53 and
77-82, and xxhash3.cpp lines 4-8, to no more than three lines each while
preserving their explanations of Highway runtime dispatch, the long-scan fast
path, and file-level dispatch rationale.
In `@src/runtime/cli/install.sh`:
- Around line 108-112: Restore the Darwin x64 branch in the target-selection
case handling so pinned Haswell releases on non-AVX2 macOS hosts probe AVX2 and
fall back to the baseline artifact. Keep the current behavior for newer releases
unchanged, and condense the associated comment to no more than three lines so it
accurately describes the preserved fallback.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 1a52bebf-9a65-4677-967c-66b842860c72
📒 Files selected for processing (50)
.buildkite/ci.mjs.buildkite/scripts/upload-release.sh.github/workflows/clippy.yml.github/workflows/format.yml.github/workflows/miri.ymlpackages/bun-release/src/platform.tsrust-toolchain.tomlscripts/bootstrap.shscripts/build/buildOptionsRs.tsscripts/build/ci.tsscripts/build/config.tsscripts/build/deps/webkit.tsscripts/build/flags.tsscripts/build/rust.tsscripts/build/source.tsscripts/build/tools.tssrc/ast/char_freq.rssrc/boringssl/lib.rssrc/bun_alloc/lib.rssrc/bun_bin/lib.rssrc/bun_core/Global.rssrc/bun_core/build.rssrc/bun_core/env.rssrc/bun_core/lib.rssrc/bun_core/string/immutable/unicode.rssrc/collections/bit_set.rssrc/collections/multi_array_list.rssrc/crash_handler/lib.rssrc/css/values/color.rssrc/http_jsc/websocket_client/WebSocketUpgradeClient.rssrc/install/PackageManager/CommandLineArguments.rssrc/install/resolvers/folder_resolver.rssrc/js_parser/parse/parse_typescript.rssrc/js_printer/lib.rssrc/jsc/bindings/ANSIHelpers.hsrc/jsc/bindings/c-bindings.cppsrc/jsc/bindings/xxhash3.cppsrc/options_types/compile_target.rssrc/react_compiler/ssa/enter_ssa.rssrc/router/lib.rssrc/runtime/cli/install.ps1src/runtime/cli/install.shsrc/runtime/cli/upgrade_command.rssrc/runtime/image/codecs.rssrc/runtime/node/path.rssrc/runtime/socket/udp_socket.rssrc/runtime/valkey_jsc/valkey.rssrc/runtime/webcore/encoding.rssrc/sql_jsc/mysql/MySQLValue.rstest/internal/source-lints/windows-cross-config.test.ts
💤 Files with no reviewable changes (3)
- scripts/build/buildOptionsRs.ts
- src/jsc/bindings/c-bindings.cpp
- src/bun_core/env.rs
ec0ca0f to
890c0cd
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.buildkite/ci.mjs:
- Around line 1592-1613: Remove the unused forceTests destructuring and simplify
the test-step condition in the relevant pipeline setup to rely only on
skipTests, since getPipelineOptions does not populate forceTests. Preserve the
existing behavior of running tests when tests are not skipped and omitting them
when skipTests is enabled.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 2fbfdef8-8008-438e-bfaf-99bb9668f498
📒 Files selected for processing (51)
.buildkite/ci.mjs.buildkite/scripts/upload-release.sh.github/workflows/clippy.yml.github/workflows/format.yml.github/workflows/miri.ymlpackages/bun-release/src/platform.tsrust-toolchain.tomlscripts/bootstrap.shscripts/build/buildOptionsRs.tsscripts/build/ci.tsscripts/build/config.tsscripts/build/deps/webkit.tsscripts/build/flags.tsscripts/build/rust.tsscripts/build/source.tsscripts/build/tools.tssrc/ast/char_freq.rssrc/boringssl/lib.rssrc/bun_alloc/lib.rssrc/bun_bin/lib.rssrc/bun_core/Global.rssrc/bun_core/build.rssrc/bun_core/env.rssrc/bun_core/lib.rssrc/bun_core/string/immutable/unicode.rssrc/collections/bit_set.rssrc/collections/multi_array_list.rssrc/crash_handler/lib.rssrc/css/values/color.rssrc/http_jsc/websocket_client/WebSocketUpgradeClient.rssrc/install/PackageManager/CommandLineArguments.rssrc/install/resolvers/folder_resolver.rssrc/js_parser/parse/parse_typescript.rssrc/js_printer/lib.rssrc/jsc/bindings/ANSIHelpers.hsrc/jsc/bindings/c-bindings.cppsrc/jsc/bindings/xxhash3.cppsrc/options_types/compile_target.rssrc/react_compiler/ssa/enter_ssa.rssrc/router/lib.rssrc/runtime/cli/install.ps1src/runtime/cli/install.shsrc/runtime/cli/upgrade_command.rssrc/runtime/image/codecs.rssrc/runtime/node/path.rssrc/runtime/socket/udp_socket.rssrc/runtime/valkey_jsc/valkey.rssrc/runtime/webcore/encoding.rssrc/sql_jsc/mysql/MySQLValue.rstest/internal/source-lints/webkit-prebuilt-url.test.tstest/internal/source-lints/windows-cross-config.test.ts
💤 Files with no reviewable changes (3)
- src/jsc/bindings/c-bindings.cpp
- src/bun_core/env.rs
- scripts/build/buildOptionsRs.ts
890c0cd to
bcae883
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.buildkite/ci.mjs:
- Around line 1592-1621: Add automated pipeline-generation regression tests
covering the relevantTestPlatforms filtering for main without ASAN, release test
dependency wiring through testStepKeys, and getBinarySizeStep behavior for main
versus non-LTO and LTO builds. Keep the assertions focused on generated steps
and dependencies, and place the coverage alongside the existing
.buildkite/ci.mjs pipeline-generation tests.
- Line 1643: Filter ASAN platforms out of the buildPlatforms list before passing
it to getReleaseStep in the steps.push release-step construction, while
preserving all other platform dependencies and existing release options.
In `@packages/bun-release/src/platform.ts`:
- Around line 133-136: Add automated postinstall platform-selection coverage for
supportedPlatforms, using the x64 Linux-musl scenario to assert that the plain
package is selected, the compatibility alias is excluded, and the Linux-musl
match remains included. Place the regression test alongside the existing
platform-selection tests and preserve the current filtering behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: edb90c0a-02db-498d-9986-c2a654e275ac
📒 Files selected for processing (52)
.buildkite/ci.mjs.buildkite/scripts/upload-release.sh.github/workflows/clippy.yml.github/workflows/format.yml.github/workflows/miri.ymlpackages/bun-release/src/platform.tsrust-toolchain.tomlscripts/bootstrap.shscripts/build/buildOptionsRs.tsscripts/build/ci.tsscripts/build/config.tsscripts/build/deps/brotli.tsscripts/build/deps/webkit.tsscripts/build/flags.tsscripts/build/rust.tsscripts/build/source.tsscripts/build/tools.tssrc/ast/char_freq.rssrc/boringssl/lib.rssrc/bun_alloc/lib.rssrc/bun_bin/lib.rssrc/bun_core/Global.rssrc/bun_core/build.rssrc/bun_core/env.rssrc/bun_core/lib.rssrc/bun_core/string/immutable/unicode.rssrc/collections/bit_set.rssrc/collections/multi_array_list.rssrc/crash_handler/lib.rssrc/css/values/color.rssrc/http_jsc/websocket_client/WebSocketUpgradeClient.rssrc/install/PackageManager/CommandLineArguments.rssrc/install/resolvers/folder_resolver.rssrc/js_parser/parse/parse_typescript.rssrc/js_printer/lib.rssrc/jsc/bindings/ANSIHelpers.hsrc/jsc/bindings/c-bindings.cppsrc/jsc/bindings/xxhash3.cppsrc/options_types/compile_target.rssrc/react_compiler/ssa/enter_ssa.rssrc/router/lib.rssrc/runtime/cli/install.ps1src/runtime/cli/install.shsrc/runtime/cli/upgrade_command.rssrc/runtime/image/codecs.rssrc/runtime/node/path.rssrc/runtime/socket/udp_socket.rssrc/runtime/valkey_jsc/valkey.rssrc/runtime/webcore/encoding.rssrc/sql_jsc/mysql/MySQLValue.rstest/internal/source-lints/webkit-prebuilt-url.test.tstest/internal/source-lints/windows-cross-config.test.ts
💤 Files with no reviewable changes (4)
- scripts/build/deps/brotli.ts
- scripts/build/buildOptionsRs.ts
- src/jsc/bindings/c-bindings.cpp
- src/bun_core/env.rs
The Rust side is #[host_fn(export = ...)] which emits extern "sysv64" on win-x64, but NodeTLS.cpp declared them as plain extern "C" (Win64 ABI). Without LTO this worked by accident: the sysv_abi wrapper getDefaultCiphers receives args in RDI/RSI, clang moves them to RCX/RDX for the (misdeclared as Win64) call, and Rust reads RDI/RSI which still hold the original values. ThinLTO reorders the registers and the coincidence breaks, so every ESM import of node:tls (which enumerates exports and hits the DEFAULT_CIPHERS getter) crashes with STATUS_BREAKPOINT. Scan of the other 31 #[host_fn(export = ...)] symbols found no other plain-extern-"C" declarations. Also: - allowlist-x64-windows: widen rsaz_1024_gather5_avx2 ceiling to cover the PDB range bleed into _aesni_ctr32_ghash_6x (both OPENSSL_ia32cap_P-gated) - rust.ts: collapse the stale ELF-full-LTO bullet above CARGO_PROFILE_RELEASE_LTO into the ThinLTO one-liner
CI runs tests under bun-profile, which under ThinLTO carries ~2x the DWARF of the full-LTO build (333 MB vs 175 MB zip; ~700 MB uncompressed on linux-x64). bun build --compile copies, reads, and rewrites the whole executable to /tmp, which on debian/ubuntu is disk-backed gp3 (tmp.mount is masked), so the I/O alone exceeds the old 10s budget. alpine passes because /tmp is tmpfs there. [skip size check]
rust-lld is built without LLVM_ENABLE_ZLIB, so the crosslang-LTO swap to rust-lld (rustc's LLVM 22 is ahead of the CI clang 21 after the nightly bump) drops -Wl,--compress-debug-sections=zlib and bun-profile came out 895 MB instead of the ~380 MB it is with compressed DWARF. The test lanes run against bun-profile, and `bun build --compile` copies the running executable, so every --compile in the suite was writing ~900 MB. That is what took type-export.test.ts (dozens of compiles) past the file timeout and pushed napi.test.ts's --compile case (10 s cap, its compile step alone hit 5.5 s) into `code 1` on all four linux lanes. Compress after the link with llvm-objcopy instead — the same `&& tool $out` postlink pattern the darwin-cross fixup already uses, and the same llvm-objcopy the musl CRT shim already relies on. Measured on the build-76603 artifact: 895 MB -> 383 MB, --compile 2.4 s -> 1.1 s locally. No-Verification-Needed: build-script-only change; the LTO+rust-lld link path is not reachable from a local debug drive
- Pass --lto-whole-program-visibility to lld on ELF (was Darwin-only via -mllvm). The WebKit -lto prebuilts carry !vcall_visibility metadata, so this lets whole-program devirtualization fire on JSC/WTF's exported classes, not just our -fvisibility=hidden ones. - -Zshare-generics=y for the Rust build: reuse an upstream crate's monomorphization instead of re-instantiating it per crate. Cross-language ThinLTO still imports+inlines small callees, so this only dedups the large bodies (parse_selector x3, printer/lexer x2, ...).
… alias filter; doc - leaksan.supp: HTTPClient::clone_metadata (daemon http thread holds the last response at exit) and napi_internal_enqueue_finalizer (global_exit GC sweep enqueues finalizer tasks the already-exiting loop never drains). Both pre-existing; -Zshare-generics=y routes Box/Vec allocs through the shared alloc-crate instantiation so the old stack no longer matches whatever suppression covered them. - upload-npm.ts: drop alias platforms from the root package optionalDependencies so npm on x64 does not download both @oven/bun-*-x64 and the byte-identical -baseline alias. Aliases are still published for back-compat. - scripts/build/CLAUDE.md: add rust-and-link to the split-CI-modes enumeration. [skip size check]
…entry [skip size check] Routing Box/Vec allocs through the shared alloc-crate instantiation moves their frames enough that LSAN loses some at-exit allocations it previously found reachable (bun-info, bun-audit, issue 30205). ASAN builds do not benefit from the binary-size savings anyway, so keep share-generics for release and skip it under ASAN rather than suppressing clone_metadata (which would also hide a real header-cloning leak if one ever lands). The napi_internal_enqueue_finalizer suppression stays: it is unambiguously at-exit (global_exit GC sweep enqueues finalizer tasks into a loop that is already exiting) and already matched.
-fno-threadsafe-statics (unix) / /Zc:threadSafeInit- /Zc:tlsGuards- (windows) for C++ TUs. WTF's convention is that multi-thread-reachable statics are main-thread-first-touched or std::once-guarded, so the compiler-emitted guard around every function-local static is dead weight.
… check] This reverts commit 0b3359f. globalFlags reaches bun's own bindings and every vendored dep, not just WebKit (which is prebuilt and already has this flag upstream). At least src/jsc/bindings/image_coregraphics_shim.cpp:146 explicitly relies on C++11 magic-static guards for WorkPool thread safety, and test-http2-reset-flood.js started hitting an ExceptionScope::assertNoException() SIGABRT on asan with this flag. Binary sizes were byte-identical between 76721 and 76728, so the guard removal was zero measured benefit anyway.
…kip size check] RSS reports ~280 MB on alpine-aarch64 under ThinLTO + -Zshare-generics for the same 400-iteration require+delete workload that measures under 64 MB on every other lane. Intermittent (passed on retry in build 76728, red on 76690/76721/76756). Already todo'd on macOS CI for the same RSS-accounting sensitivity; extending the condition rather than masking a potential regression with a threshold bump. Worth a closer look once the rest of the pipeline is green.
| * release workflow naming in oven-sh/WebKit's CI. There is no -baseline | ||
| * variant: every x64 WebKit is built at the nehalem floor. | ||
| */ | ||
| function prebuiltSuffix(cfg: Config): string { | ||
| let s = ""; | ||
| if (cfg.linux && cfg.abi === "musl") s += "-musl"; | ||
| if (cfg.linux && cfg.abi === "android") s += "-android"; |
There was a problem hiding this comment.
🟡 nit: This PR removed the -baseline branch from prebuiltSuffix() here and moved every build lane onto one arm64 host, but the sibling consumer scripts/prefetch-deps.ts (invoked by prefetch_build_deps() in bootstrap.sh at image-bake time) wasn't updated for either change: (1) prefetch-deps.ts:21/:45 still list baseline as a URL-affecting dimension and :56 still iterates for (const baseline of baseCfg.x64 ? [false, true] : [false]) — with the -baseline suffix gone the two iterations produce identical URLs (harmlessly deduped at :80). Same class as the baseline sweep this PR already did in brotli.ts/rust.ts/buildOptionsRs.ts/env.rs; per REVIEW.md "Delete dead code in the same PR that makes it dead", drop the loop and reword the comments. (2) prefetch-deps.ts:50's base has no os/arch (host-detected) and only varies asan/lto/baseline/abi, so the single debian-13 arm64 build host's baked cache only holds bun-webkit-linux-arm64* — the linux-x64 gnu/musl/asan lanes (which pre-PR had their own x64 images with matching prefetch) now cache-miss and re-download WebKit in every build-cpp job. Not a correctness bug (download fallback works; the file's own doc says partial hits are tolerated), but same class as the is_ci_build_host() gate this PR added at bootstrap.sh:1155-1163 for sysroots — either enumerate os/arch on the build host, or gate prefetch_build_deps() on is_ci_build_host() too (test images never build, so their WebKit prefetch is dead weight in the baked image).
Extended reasoning...
What's stale / regressed
scripts/prefetch-deps.ts runs at CI-image bake time (via prefetch_build_deps() in scripts/bootstrap.sh:2139, called unconditionally at :2248 gated only on $ci=1) to warm a read-only download cache for WebKit and other dep tarballs. Two of this PR's changes leave it out of sync:
(1) Dead baseline dimension. This PR removed if (cfg.baseline && cfg.x64) s += "-baseline" from prebuiltSuffix() in scripts/build/deps/webkit.ts ("There is no -baseline variant: every x64 WebKit is built at the nehalem floor"). But scripts/prefetch-deps.ts still treats baseline as URL-affecting:
- :20-21 — comment: "Enumerates variants on the dimensions that affect download URLs (asan, lto, baseline, musl)"
- :45 — comment: "WebKit prebuilt URL varies by (musl, baseline, debug|lto, asan)"
- :56 —
for (const baseline of baseCfg.x64 ? [false, true] : [false])
With the -baseline suffix gone, cfg.baseline no longer affects any URL prebuiltSuffix() produces, so on an x64 host the two loop iterations produce identical URLs — harmlessly deduped by items.has(item.url) at :80.
(2) Prefetch coverage after the single-host move. prefetch-deps.ts:50 has const base: PartialConfig = { buildType: "Release", ci: true, webkit: "prebuilt" } with no os/arch, so resolveConfig detects the host. The variants loop at :54-58 varies only asan/lto/baseline/abi — never os or arch. Pre-PR each build platform had its own image (amazonlinux-x64, amazonlinux-aarch64, alpine-x64, alpine-aarch64) and each prefetched its own target's WebKit. Post-PR one debian-13 arm64 image (buildHostPlatform in ci.mjs) serves all 13 build lanes, but its baked prefetch only contains bun-webkit-linux-arm64{,-musl}{,-lto,-debug,-asan}.tar.gz.
Step-by-step proof
Take the linux-x64 build lane on a [build images] run of this PR:
- Image bake.
bootstrap.shruns on the debian-13 aarch64 build-host VM. At :2248 it callsprefetch_build_deps()(gated only on$ci=1at :2139-2145, not onis_ci_build_host()). - prefetch-deps.ts resolves the host.
baseat :50 has noos/arch, soresolveConfig(base, toolchain)returns{os: "linux", arch: "aarch64", abi: "gnu", ...}.baseCfg.x64is false, so the :56 loop iterates[false]only (part (1) is arm64-moot on the actual build host, but the dead code and stale comments remain). - Variants enumerate arm64 only. The loop varies
asan × lto × abion the fixed host arch.prebuiltSuffix()produces suffixes like ``,-musl, `-lto`, `-musl-lto`, `-asan`, etc.; `prebuiltUrl()` (webkit.ts) prepends `bun-webkit-linux-arm64`. The baked `by-url/` cache holds only linux-arm64 tarballs. - linux-x64 build-cpp runs.
getBuildArgs()passes--os=linux --arch=x64 --abi=gnu;webkit.source(cfg)computesbun-webkit-linux-amd64-lto.tar.gz.downloadWithRetrycomputesprefetchPathForUrl(url, BUN_BUILD_PREFETCH_DIR)→ key = sha256 of the amd64 URL → not inby-url/→ cache miss → downloads ~200 MB from GitHub. - Pre-PR contrast. The same lane ran on an amazonlinux-x64 image whose bake-time
prefetch-deps.tshadbaseCfg.x64 === trueand cachedbun-webkit-linux-amd64*— cache hit.
The genuinely new misses are the linux-x64 gnu/musl/asan lanes (~3 lanes). darwin/windows/freebsd/android were already cache-misses pre-PR (also cross-compiled from a linux host that only prefetched linux WebKit), so "defeats prefetch for most lanes" describes the post-PR state accurately but the regression is narrower.
Why this is in-scope for this PR
Per REVIEW.md "Fix the whole class in the same PR (same-class sites are ONE concern, not scope creep)" and "Delete dead code in the same PR that makes it dead":
- Part (1) is exactly the same class as the
baselinesweep this PR already did inscripts/build/deps/brotli.ts(removed the!cfg.baseline-fno-ltoblock),scripts/build/rust.ts(removed thebaseline ? "nehalem" : "haswell"ternary),buildOptionsRs.ts,env.rs,crash_handler/lib.rs,upgrade_command.rs— one more sibling of the same edit. - Part (2) is exactly the same class as the
is_ci_build_host()gate this PR added at bootstrap.sh:1155-1163 for the same single-host reason ("Cross-compile sysroots + runtimes are only needed on the single build host … test images never cross-compile, so skip the ~3GB of NDK/SDK/sysroot downloads there").prefetch_build_deps()at :2248 is the sibling that wasn't gated: test-only images (ubuntu, debian-x64, alpine, windows) still bake ~several hundred MB of WebKit tarballs they never read.
Why nit (not a regression that blocks)
Nothing breaks. Part (1) is dead code + stale comments, harmlessly deduped. Part (2) is CI-cost only: the file's own doc at :14-15 explicitly says "the baked cache just becomes a partial hit until the next image refresh", and downloadWithRetry in download.ts falls through cleanly on a cache miss. Every build lane still produces correct artifacts.
Fix
- Part (1): delete the
baselineloop at :56 (unwrap to a single iteration), dropbaselinefrom the comments at :20-21 and :45. - Part (2): either (a) on the build host, enumerate
arch(and optionallyos) in the variants loop — e.g.for (const arch of ["x64", "aarch64"])— so the arm64 image also cachesbun-webkit-linux-amd64*; or (b) gateprefetch_build_deps()at bootstrap.sh:2248 onis_ci_build_host()(matching the sysroot gate at :1155-1163) so test images stop baking dead-weight WebKit; ideally both.
There was a problem hiding this comment.
Valid on both counts. Part (1) is a trivial dead-loop cleanup; part (2) is CI-cost (cache miss falls through to download, no correctness impact). Will batch into the next push if one is needed; not pushing for a non-blocking optimization while 2c1bffe is nearly green.
- scripts/bootstrap.{sh,ps1}: Version 41->42 / 23->24 (main caught up to
41/22 via #34782).
- scripts/bootstrap.sh: alpine_sysroot_version 3.23 -> 3.24.
- scripts/build/deps/webkit.ts: pin to autobuild-preview-pr-296-6144f510
(oven-sh/WebKit#296 rebased onto main c9296e353e).
- src/jsc/bindings/highway_{json,sourcemap}.cpp: disable scalable
HWY_SVE/HWY_SVE2. clang >= 22 stops marking them HWY_BROKEN in
detect_targets.h, so foreach_target compiles for them, but BitsFromMask
only exists for the fixed-size SVE_256/SVE2_128 variants.
|
Heads up: this pushed ASAN |
|
The debian-13 x64-asan lane surfaced a latent 200ms guard-timer flake in |
…#35132) Fixes `test/js/third_party/socket.io/socket.io-connection-state-recovery.test.ts` going red on the debian-13 x64-asan lane. ## Failure ``` error: timeout at <anonymous> (test/js/third_party/socket.io/socket.io-connection-state-recovery.test.ts:46:26) ✗ connection state recovery > should restore session and missed packets [219.96ms] ``` Seen on builds [77055](https://buildkite.com/bun/bun/builds/77055) (219.84ms) and [77789](https://buildkite.com/bun/bun/builds/77789) (219.96ms), both debian-13 x64-asan. ## Cause Each test in this file carries a `setTimeout(() => fail(...), 200)` guard that was added when the suite was ported from upstream socket.io in fe74c94. The [upstream test](https://github.com/socketio/socket.io/blob/main/packages/socket.io/test/connection-state-recovery.ts) has no such timers. These tests drive the Engine.IO long-polling transport by hand via supertest: the first test performs 8 sequential HTTP round trips. On release that is ~50ms; on release+ASAN it is ~220ms. #34782 moved the x64-asan build lane from amazonlinux-2023 to debian-13 on Jul 21, and the failures started immediately after, with the work landing just past the 200ms guard every time. The guard is not a behavioral assertion. It races real work against a wall clock and turns a slow-but-correct run into a failure. The test runner already applies its own per-test timeout (90s, tripled under ASAN in CI). ## Fix Drop the guard timers and align with the upstream structure: plain `async` tests that await the protocol events, with `io.close()` in a `finally` block so the server is always released. Every assertion is preserved; the same code paths are exercised. ## Verification ``` # before, bun bd (debug+asan), 5 runs: 0 pass / 7 fail every time # after, bun bd (debug+asan), 5 runs: 7 pass / 0 fail (×5) # release bun, 3 runs: 7 pass / 0 fail (×3) ``` <!-- robobun:evidence:begin --> --- **[stamp-90s]** gate passed · iteration 0 · 1 files touched <details><summary>passes on PR (with fix)</summary> ```console Test-only change. Debug/ASAN (expected pass): $ bun bd test 'test/js/third_party/socket.io/socket.io-connection-state-recovery.test.ts' $ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test test/js/third_party/socket.io/socket.io-connection-state-recovery.test.ts bun test v1.4.0 (70a1c05) test/js/third_party/socket.io/socket.io-connection-state-recovery.test.ts: (pass) connection state recovery > should restore session and missed packets [2559.28ms] (pass) connection state recovery > should restore rooms and data attributes [1087.52ms] (pass) connection state recovery > should not run middlewares upon recovery by default [1125.18ms] (pass) connection state recovery > should run middlewares even upon recovery [1000.73ms] (pass) connection state recovery > should fail to restore an unknown session [421.80ms] (pass) connection state recovery > should be disabled by default [434.45ms] (pass) connection state recovery > should not call adapter#persistSession or adapter#restoreSession if disabled [405.80ms] 7 pass 0 fail 43 expect() calls Ran 7 tests across 1 file. [14.50s] Exit: 0 ``` </details> <details><summary>diff hotspot</summary> ``` .../socket.io-connection-state-recovery.test.ts | 318 +++++++++------------ 1 file changed, 134 insertions(+), 184 deletions(-) ``` </details> **gate history** · 1 passed · 0 rejected · iteration 0 <details><summary>evidence per changed file</summary> ``` file reads edits tests …y/socket.io/socket.io-connection-state-recovery.test.ts 2 3 0 ``` </details> **self-review** · no surviving concerns 25 concerns were raised and did not survive verification. **root cause** · written by the author bot The test wrapped its async work in a hardcoded 200ms setTimeout guard that was not a behavioral assertion, and on slow ASAN builds the real protocol steps outran that window, so the guard fired and failed the test even though the code under test behaved correctly. The fix removes the wall-clock guards entirely and converts each test to a plain async function that awaits the protocol steps directly, with server cleanup moved into a try/finally block. Hangs are now bounded by the test runner's per-test timeout rather than an arbitrary 200ms race, and all original assertions are preserved. <!-- robobun:evidence:end -->
One image bake covering a set of coupled CI/build changes. Commit subject carries
[build images]so the v40 images bake on this PR.What
Single arm64 debian-12 build host
Every build lane (all 13 targets: linux x64/aarch64 gnu/musl/android/asan, darwin x64/aarch64, freebsd x64/aarch64, windows x64/aarch64) now runs on one
linux-aarch64-12-debianhost image and cross-compiles to its target via--target+--sysroot.buildHostPlatformin.buildkite/ci.mjsis the single source of truth;getCppAgent()/getLinkBunAgent()always pickc8g.4xlarge/r8g.2xlarge.getBuildArgs()always emits--os/--arch/--abisoresolveConfig()never infers target from the host.scripts/build/config.tsgains a Linux cross-arch/cross-abi block: when targetarchorabidiffers from the host's,crossTargetis set to<arch>-unknown-linux-<gnu|musl>andsysrootto the matching/opt/linux-sysroot-{glibc,musl}{,-arm64}.scripts/build/flags.tsadds the matching--target/--sysrootlinkerFlags entry.scripts/build/shims.tspoints the musl CRT-print-file-nameprobe at the sysroot when cross-compiling.bootstrap.sh v40
install_linux_glibc_sysroot(): extracts glibc 2.17 headers/libs + devtoolset libstdc++ fromquay.io/pypa/manylinux2014_<arch>:latestviaskopeo copy dir:+ manifest-ordered layer unpack into/opt/linux-sysroot-glibc{,-arm64}. Best-effort during bake (prints a warning, does not abort); the build throws a clearBuildErrorif missing when cross-compiling.install_linux_musl_sysroot(): extracts<triple>/+lib/gcc/frommusl.cc/<arch>-linux-musl-cross.tgzinto/opt/linux-sysroot-musl{,-arm64}.install_macos_sdk(): fetchesscripts/build/xmac.mjsatBUN_BOOTSTRAP_REPO_REFand splats the pinned SDK into/opt/macos-sdk, so the per-job Apple CDN fetch in configure goes away.install_cross_compiler_rt(): best-effortdpkg --add-architecture amd64+libclang-rt-<v>-dev:amd64on arm64 debian so x64 asan cross can link. If apt.llvm.org lacks the amd64 packages on arm64 repos, the asan lane is the one candidate for an x64-host exception.install_rust(): adds{x86_64,aarch64}-unknown-linux-{gnu,musl}rustup targets.clean_system():apt-get clean/dnf clean all/apkcache purge,rm -rf /tmp/*, andfstrim -avbefore snapshot to shrink the EBS snapshot.install_osxcrosspath and--osxcrossflag removed;lsb-releaseandqemu-useradded to apt installs.rust-and-link merged step
getBuildRustStep()andgetLinkBunStep()collapse into onegetBuildBunStep()(key*-build-bun,timeout_in_minutes: 60) that runsci-rust-and-link:ninja bun-rust, pollbuildkite-agent step get outcome --step <target>-build-cpp(60m deadline), download the cpp archive, link, package. build-cpp runs in parallel with nodepends_onbetween them.test/release/verify-baseline/binary-sizedepends_onstay on*-build-bun.PR builds skip LTO
getBuildArgs()passes--lto=offon non-main branches.[lto]in the commit subject opts back in.binary-sizeis annotate-only on non-LTO PRs.mainkeeps LTO.Tests on
main, canary gated on greenThe
!isMainBranch()guard around test steps is dropped (asan stays PR-only).getReleaseStep()depends_onevery*-test-bunkey.Test shards in their own groups
Test groups are keyed on
getPlatformKey/getPlatformLabel(distro + release) instead ofgetTargetKey/getTargetLabel, so they no longer merge into the build groups by label. Build groups depend only on thebuildHostPlatformimage; test groups depend on their own native image.verify-baseline stays arch-matched
getVerifyBaselineHost()picks a per-target-arch native host (debian-13 / windows-2019) so the pinned qemu/SDE binaries keep working.scripts/verify-baseline.tsaccepts--archinstead of inferring fromprocess.arch.x64 is baseline-only
scripts/build/config.tsdefaultsbaseline = trueon x64,scripts/build/flags.tsdrops-march=haswell. Non-baseline x64 lanes removed fromci.mjs.upload-release.shgainsalias_baseline_artifact()+rezip_as()which rezips each x64 artifact under its old non-baseline name so existing download URLs keep resolving.ENABLE_SIMDandBASELINEenv constants removed fromsrc/bun_core/env.rs;bun_warn_avx_missingremoved fromc-bindings.cppandlib.rs.Rust nightly-2026-07-20
Folds #34452.
#[allow(suspicious_runtime_symbol_definitions)]on thesafe fnlibc extern blocks insrc/bun_core/Global.rsandsrc/sys/lib.rsfor the new lint.scripts/packer/build-image.pkr.hcl
New Packer template with
docker+amazon-ebssources both runningscripts/bootstrap.sh, so localdocker runand CI AMIs share one provisioner. Not yet wired intomachine.mjs.Verification
Generated
.buildkite/ci.ymlunder[build images]/[publish images]/[build linux images]/ plain-PR: all YAML-valid, 0 danglingdepends_on, 0 duplicate keys. Bake set is 9 images (1 build host + 8 test-platform).sh -n/bash -nonbootstrap.shandupload-release.sh.bunx tsc --noEmit -p scripts/build/tsconfig.jsonintroduces no new errors.cargo check --workspace --target {x86_64,aarch64}-unknown-linux-{gnu,musl}and{aarch64-apple-darwin, x86_64-unknown-freebsd, aarch64-pc-windows-msvc}all pass.bun bdbuilds;bun bd teston the four config/flags/shims-touching internal tests passes.The actual cross-link of x64/musl binaries from an arm64 host is not exercisable locally (needs the baked sysroots); the
[build images]run on this PR is the first end-to-end exercise.no test proof · iteration 32 · Platform-specific test(s) that do not run on this machine. Deferring to CI, which covers all platforms: test/cli/run/require-cache.test.ts test/internal/macos-cross-config.test.ts test/internal/source-lints/windows-cross-config.test.ts test/js/bun/perf/linker-order.test.ts test/napi/napi.test.ts