feat(build): add --compile-executable-path CLI flag (#25934)

## Summary

Adds a new CLI flag `--compile-executable-path` that allows specifying a
custom Bun executable path for cross-compilation instead of downloading
from the npm registry.

## Usage

```bash
bun build --compile --target=bun-linux-x64 \
  --compile-executable-path=/path/to/bun-linux-x64 app.ts
```

## Motivation

The `executablePath` option was already available in the JavaScript
`Bun.build()` API. This exposes the same functionality from the CLI.

## Changes

- Added `--compile-executable-path <STR>` CLI parameter in
`src/cli/Arguments.zig`
- Added `compile_executable_path` field to `BundlerOptions` in
`src/cli.zig`
- Wired the option through to `StandaloneModuleGraph.toExecutable()` in
`src/cli/build_command.zig`

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Dylan Conway
2026-01-09 16:21:40 -08:00
committed by GitHub
parent 1e0f51ddcc
commit 7704dca660
5 changed files with 14 additions and 4 deletions

View File

@@ -358,7 +358,7 @@ Bun represents [pointers](<https://en.wikipedia.org/wiki/Pointer_(computer_progr
**Why not `BigInt`?** `BigInt` is slower. JavaScript engines allocate a separate `BigInt` which means they can't fit into a regular JavaScript value. If you pass a `BigInt` to a function, it will be converted to a `number` **Why not `BigInt`?** `BigInt` is slower. JavaScript engines allocate a separate `BigInt` which means they can't fit into a regular JavaScript value. If you pass a `BigInt` to a function, it will be converted to a `number`
**Windows Note**: The Windows API type HANDLE does not represent a virtual address, and using `ptr` for it will *not* work as expected. Use `u64` to safely represent HANDLE values. **Windows Note**: The Windows API type HANDLE does not represent a virtual address, and using `ptr` for it will _not_ work as expected. Use `u64` to safely represent HANDLE values.
</Accordion> </Accordion>

View File

@@ -464,6 +464,7 @@ pub const Command = struct {
compile_autoload_bunfig: bool = true, compile_autoload_bunfig: bool = true,
compile_autoload_tsconfig: bool = false, compile_autoload_tsconfig: bool = false,
compile_autoload_package_json: bool = false, compile_autoload_package_json: bool = false,
compile_executable_path: ?[]const u8 = null,
windows: options.WindowsOptions = .{}, windows: options.WindowsOptions = .{},
}; };

View File

@@ -158,6 +158,7 @@ pub const build_only_params = [_]ParamType{
clap.parseParam("--no-compile-autoload-tsconfig Disable autoloading of tsconfig.json at runtime in standalone executable") catch unreachable, clap.parseParam("--no-compile-autoload-tsconfig Disable autoloading of tsconfig.json at runtime in standalone executable") catch unreachable,
clap.parseParam("--compile-autoload-package-json Enable autoloading of package.json at runtime in standalone executable (default: false)") catch unreachable, clap.parseParam("--compile-autoload-package-json Enable autoloading of package.json at runtime in standalone executable (default: false)") catch unreachable,
clap.parseParam("--no-compile-autoload-package-json Disable autoloading of package.json at runtime in standalone executable") catch unreachable, clap.parseParam("--no-compile-autoload-package-json Disable autoloading of package.json at runtime in standalone executable") catch unreachable,
clap.parseParam("--compile-executable-path <STR> Path to a Bun executable to use for cross-compilation instead of downloading") catch unreachable,
clap.parseParam("--bytecode Use a bytecode cache") catch unreachable, clap.parseParam("--bytecode Use a bytecode cache") catch unreachable,
clap.parseParam("--watch Automatically restart the process on file change") catch unreachable, clap.parseParam("--watch Automatically restart the process on file change") catch unreachable,
clap.parseParam("--no-clear-screen Disable clearing the terminal screen on reload when --watch is enabled") catch unreachable, clap.parseParam("--no-clear-screen Disable clearing the terminal screen on reload when --watch is enabled") catch unreachable,
@@ -1106,6 +1107,14 @@ pub fn parse(allocator: std.mem.Allocator, ctx: Command.Context, comptime cmd: C
} }
} }
if (args.option("--compile-executable-path")) |path| {
if (!ctx.bundler_options.compile) {
Output.errGeneric("--compile-executable-path requires --compile", .{});
Global.crash();
}
ctx.bundler_options.compile_executable_path = path;
}
if (args.flag("--windows-hide-console")) { if (args.flag("--windows-hide-console")) {
// --windows-hide-console technically doesnt depend on WinAPI, but since since --windows-icon // --windows-hide-console technically doesnt depend on WinAPI, but since since --windows-icon
// does, all of these customization options have been gated to windows-only // does, all of these customization options have been gated to windows-only

View File

@@ -468,7 +468,7 @@ pub const BuildCommand = struct {
this_transpiler.options.output_format, this_transpiler.options.output_format,
ctx.bundler_options.windows, ctx.bundler_options.windows,
ctx.bundler_options.compile_exec_argv orelse "", ctx.bundler_options.compile_exec_argv orelse "",
null, ctx.bundler_options.compile_executable_path,
.{ .{
.disable_default_env_files = !ctx.bundler_options.compile_autoload_dotenv, .disable_default_env_files = !ctx.bundler_options.compile_autoload_dotenv,
.disable_autoload_bunfig = !ctx.bundler_options.compile_autoload_bunfig, .disable_autoload_bunfig = !ctx.bundler_options.compile_autoload_bunfig,

View File

@@ -77,8 +77,8 @@ pub const MachoFile = struct {
found_bun = true; found_bun = true;
original_fileoff = sect.offset; original_fileoff = sect.offset;
original_vmaddr = sect.addr; original_vmaddr = sect.addr;
original_data_end = original_fileoff + blob_alignment; original_data_end = command.fileoff + command.filesize;
original_segsize = sect.size; original_segsize = command.filesize;
self.segment = command; self.segment = command;
self.section = sect.*; self.section = sect.*;