-
Notifications
You must be signed in to change notification settings - Fork 293
fix(build): compile x64 binaries against Bun's baseline runtime #797
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "hunkdiff": patch | ||
| --- | ||
|
|
||
| Build the x64 binaries for CPUs without AVX2, so Hunk no longer dies with an illegal instruction on pre-Haswell machines and conservative VM CPU models. |
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| import { describe, expect, test } from "bun:test"; | ||
| import { compileTargetForHost } from "./build-bin"; | ||
|
|
||
| describe("compileTargetForHost", () => { | ||
| test("compiles every x64 platform against Bun's baseline runtime", () => { | ||
| // Bun's default x64 runtime needs AVX2/BMI2; these targets only need x86-64-v2. | ||
| expect(compileTargetForHost("darwin", "x64")).toBe("bun-darwin-x64-baseline"); | ||
| expect(compileTargetForHost("win32", "x64")).toBe("bun-windows-x64-baseline"); | ||
| expect(compileTargetForHost("linux", "x64", () => false)).toBe("bun-linux-x64-baseline"); | ||
| }); | ||
|
|
||
| test("keeps the host libc when compiling on a musl x64 host", () => { | ||
| expect(compileTargetForHost("linux", "x64", () => true)).toBe("bun-linux-x64-musl-baseline"); | ||
| }); | ||
|
|
||
| test("leaves arm64 hosts on Bun's own default runtime", () => { | ||
| expect(compileTargetForHost("darwin", "arm64")).toBeNull(); | ||
| expect(compileTargetForHost("linux", "arm64")).toBeNull(); | ||
| expect(compileTargetForHost("win32", "arm64")).toBeNull(); | ||
| }); | ||
|
|
||
| test("returns no target for platforms Hunk does not publish binaries for", () => { | ||
| expect(compileTargetForHost("freebsd", "x64")).toBeNull(); | ||
| }); | ||
| }); | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,43 +1,87 @@ | ||
| #!/usr/bin/env bun | ||
|
|
||
| import { mkdirSync, rmSync } from "node:fs"; | ||
| import { existsSync, mkdirSync, rmSync } from "node:fs"; | ||
| import path from "node:path"; | ||
|
|
||
| const repoRoot = path.resolve(import.meta.dir, ".."); | ||
| const distDir = path.join(repoRoot, "dist"); | ||
| const binaryName = process.platform === "win32" ? "hunk.exe" : "hunk"; | ||
| const outfile = path.join(distDir, binaryName); | ||
| const legacyOutfile = path.join(distDir, process.platform === "win32" ? "otdiff.exe" : "otdiff"); | ||
|
|
||
| mkdirSync(distDir, { recursive: true }); | ||
| rmSync(legacyOutfile, { force: true }); | ||
|
|
||
| const proc = Bun.spawnSync( | ||
| [ | ||
| "bun", | ||
| "build", | ||
| "--compile", | ||
| "--no-compile-autoload-bunfig", | ||
| path.join(repoRoot, "src", "main.tsx"), | ||
| path.join(repoRoot, "src", "highlightWorkerEntry.ts"), | ||
| "--outfile", | ||
| outfile, | ||
| ], | ||
| { | ||
| cwd: repoRoot, | ||
| stdin: "inherit", | ||
| stdout: "inherit", | ||
| stderr: "inherit", | ||
| env: { | ||
| ...process.env, | ||
| BUN_TMPDIR: path.join(repoRoot, ".bun-tmp"), | ||
| BUN_INSTALL: path.join(repoRoot, ".bun-install"), | ||
| }, | ||
| }, | ||
| ); | ||
| /** | ||
| * Resolves the Bun compile target for one host, or null to keep Bun's own host default. | ||
| * | ||
| * x64 hosts compile against Bun's baseline runtime. Bun's default x64 runtime is built for | ||
| * Haswell (AVX2/BMI2, 2013+) and dies with SIGILL before any Hunk code runs on older CPUs and | ||
| * on VMs that expose a conservative CPU model, so the shipped binary would be unusable there. | ||
| * The baseline runtime only asks for x86-64-v2 (SSE4.2/POPCNT). arm64 has no such split and | ||
| * keeps whatever runtime the host Bun already carries. | ||
| */ | ||
| export function compileTargetForHost( | ||
| platform: NodeJS.Platform, | ||
| arch: string, | ||
| isMuslHost = () => existsSync("/lib/ld-musl-x86_64.so.1"), | ||
| ) { | ||
| if (arch !== "x64") { | ||
| return null; | ||
| } | ||
|
|
||
| if (platform === "darwin") { | ||
| return "bun-darwin-x64-baseline"; | ||
| } | ||
|
|
||
| if (platform === "win32") { | ||
| return "bun-windows-x64-baseline"; | ||
| } | ||
|
|
||
| if (proc.exitCode !== 0) { | ||
| throw new Error(`bun build --compile failed with exit ${proc.exitCode}`); | ||
| if (platform === "linux") { | ||
| // The musl and glibc runtimes are not interchangeable, so keep the host's libc. | ||
| return isMuslHost() ? "bun-linux-x64-musl-baseline" : "bun-linux-x64-baseline"; | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
|
|
||
| console.log(`Built ${outfile}`); | ||
| if (import.meta.main) { | ||
| const repoRoot = path.resolve(import.meta.dir, ".."); | ||
| const distDir = path.join(repoRoot, "dist"); | ||
| const binaryName = process.platform === "win32" ? "hunk.exe" : "hunk"; | ||
| const outfile = path.join(distDir, binaryName); | ||
| const legacyOutfile = path.join(distDir, process.platform === "win32" ? "otdiff.exe" : "otdiff"); | ||
|
|
||
| mkdirSync(distDir, { recursive: true }); | ||
| rmSync(legacyOutfile, { force: true }); | ||
|
|
||
| const target = compileTargetForHost(process.platform, process.arch); | ||
|
|
||
| const proc = Bun.spawnSync( | ||
| [ | ||
| "bun", | ||
| "build", | ||
| "--compile", | ||
| "--no-compile-autoload-bunfig", | ||
| ...(target ? [`--target=${target}`] : []), | ||
| path.join(repoRoot, "src", "main.tsx"), | ||
| path.join(repoRoot, "src", "highlightWorkerEntry.ts"), | ||
| "--outfile", | ||
| outfile, | ||
| ], | ||
| { | ||
| cwd: repoRoot, | ||
| stdin: "inherit", | ||
| stdout: "inherit", | ||
| stderr: "inherit", | ||
| env: { | ||
| ...process.env, | ||
| BUN_TMPDIR: path.join(repoRoot, ".bun-tmp"), | ||
| BUN_INSTALL: path.join(repoRoot, ".bun-install"), | ||
| }, | ||
| }, | ||
| ); | ||
|
|
||
| if (proc.exitCode !== 0) { | ||
| // Bun fetches a non-host target runtime instead of reusing the installed one, so the first | ||
| // build on a machine needs network access; after that it comes from the repo-local cache. | ||
| const offlineHint = target | ||
| ? ` Building for ${target} downloads that runtime once into .bun-install; rerun with network access if the download failed.` | ||
| : ""; | ||
| throw new Error(`bun build --compile failed with exit ${proc.exitCode}.${offlineHint}`); | ||
| } | ||
|
|
||
| console.log(`Built ${outfile}${target ? ` for ${target}` : ""}`); | ||
| } |
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.