mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
Fixes ENG-21287
Build times, from `bun run build && echo '//' >> src/main.zig && time
bun run build`
|Platform|0.14.1|0.15.2|Speedup|
|-|-|-|-|
|macos debug asan|126.90s|106.27s|1.19x|
|macos debug noasan|60.62s|50.85s|1.19x|
|linux debug asan|292.77s|241.45s|1.21x|
|linux debug noasan|146.58s|130.94s|1.12x|
|linux debug use_llvm=false|n/a|78.27s|1.87x|
|windows debug asan|177.13s|142.55s|1.24x|
Runtime performance:
- next build memory usage may have gone up by 5%. Otherwise seems the
same. Some code with writers may have gotten slower, especially one
instance of a counting writer and a few instances of unbuffered writers
that now have vtable overhead.
- File size reduced by 800kb (from 100.2mb to 99.4mb)
Improvements:
- `@export` hack is no longer needed for watch
- native x86_64 backend for linux builds faster. to use it, set use_llvm
false and no_link_obj false. also set `ASAN_OPTIONS=detect_leaks=0`
otherwise it will spam the output with tens of thousands of lines of
debug info errors. may need to use the zig lldb fork for debugging.
- zig test-obj, which we will be able to use for zig unit tests
Still an issue:
- false 'dependency loop' errors remain in watch mode
- watch mode crashes observed
Follow-up:
- [ ] search `comptime Writer: type` and `comptime W: type` and remove
- [ ] remove format_mode in our zig fork
- [ ] remove deprecated.zig autoFormatLabelFallback
- [ ] remove deprecated.zig autoFormatLabel
- [ ] remove deprecated.BufferedWriter and BufferedReader
- [ ] remove override_no_export_cpp_apis as it is no longer needed
- [ ] css Parser(W) -> Parser, and remove all the comptime writer: type
params
- [ ] remove deprecated writer fully
Files that add lines:
```
649 src/deprecated.zig
167 scripts/pack-codegen-for-zig-team.ts
54 scripts/cleartrace-impl.js
46 scripts/cleartrace.ts
43 src/windows.zig
18 src/fs.zig
17 src/bun.js/ConsoleObject.zig
16 src/output.zig
12 src/bun.js/test/debug.zig
12 src/bun.js/node/node_fs.zig
8 src/env_loader.zig
7 src/css/printer.zig
7 src/cli/init_command.zig
7 src/bun.js/node.zig
6 src/string/escapeRegExp.zig
6 src/install/PnpmMatcher.zig
5 src/bun.js/webcore/Blob.zig
4 src/crash_handler.zig
4 src/bun.zig
3 src/install/lockfile/bun.lock.zig
3 src/cli/update_interactive_command.zig
3 src/cli/pack_command.zig
3 build.zig
2 src/Progress.zig
2 src/install/lockfile/lockfile_json_stringify_for_debugging.zig
2 src/css/small_list.zig
2 src/bun.js/webcore/prompt.zig
1 test/internal/ban-words.test.ts
1 test/internal/ban-limits.json
1 src/watcher/WatcherTrace.zig
1 src/transpiler.zig
1 src/shell/builtin/cp.zig
1 src/js_printer.zig
1 src/io/PipeReader.zig
1 src/install/bin.zig
1 src/css/selectors/selector.zig
1 src/cli/run_command.zig
1 src/bun.js/RuntimeTranspilerStore.zig
1 src/bun.js/bindings/JSRef.zig
1 src/bake/DevServer.zig
```
Files that remove lines:
```
-1 src/test/recover.zig
-1 src/sql/postgres/SocketMonitor.zig
-1 src/sql/mysql/MySQLRequestQueue.zig
-1 src/sourcemap/CodeCoverage.zig
-1 src/css/values/color_js.zig
-1 src/compile_target.zig
-1 src/bundler/linker_context/convertStmtsForChunk.zig
-1 src/bundler/bundle_v2.zig
-1 src/bun.js/webcore/blob/read_file.zig
-1 src/ast/base.zig
-2 src/sql/postgres/protocol/ArrayList.zig
-2 src/shell/builtin/mkdir.zig
-2 src/install/PackageManager/patchPackage.zig
-2 src/install/PackageManager/PackageManagerDirectories.zig
-2 src/fmt.zig
-2 src/css/declaration.zig
-2 src/css/css_parser.zig
-2 src/collections/baby_list.zig
-2 src/bun.js/bindings/ZigStackFrame.zig
-2 src/ast/E.zig
-3 src/StandaloneModuleGraph.zig
-3 src/deps/picohttp.zig
-3 src/deps/libuv.zig
-3 src/btjs.zig
-4 src/threading/Futex.zig
-4 src/shell/builtin/touch.zig
-4 src/meta.zig
-4 src/install/lockfile.zig
-4 src/css/selectors/parser.zig
-5 src/shell/interpreter.zig
-5 src/css/error.zig
-5 src/bun.js/web_worker.zig
-5 src/bun.js.zig
-6 src/cli/test_command.zig
-6 src/bun.js/VirtualMachine.zig
-6 src/bun.js/uuid.zig
-6 src/bun.js/bindings/JSValue.zig
-9 src/bun.js/test/pretty_format.zig
-9 src/bun.js/api/BunObject.zig
-14 src/install/install_binding.zig
-14 src/fd.zig
-14 src/bun.js/node/path.zig
-14 scripts/pack-codegen-for-zig-team.sh
-17 src/bun.js/test/diff_format.zig
```
`git diff --numstat origin/main...HEAD | awk '{ print ($1-$2)"\t"$3 }' |
sort -rn`
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
Co-authored-by: Meghan Denny <meghan@bun.com>
Co-authored-by: tayor.fish <contact@taylor.fish>
515 lines
18 KiB
Zig
515 lines
18 KiB
Zig
/// Used for `bun build --compile`
|
|
///
|
|
/// This downloads and extracts the bun binary for the target platform
|
|
/// It uses npm to download the bun binary from the npm registry
|
|
/// It stores the downloaded binary into the bun install cache.
|
|
///
|
|
const CompileTarget = @This();
|
|
|
|
os: Environment.OperatingSystem = Environment.os,
|
|
arch: Environment.Architecture = Environment.arch,
|
|
baseline: bool = !Environment.enableSIMD,
|
|
version: bun.Semver.Version = .{
|
|
.major = @truncate(Environment.version.major),
|
|
.minor = @truncate(Environment.version.minor),
|
|
.patch = @truncate(Environment.version.patch),
|
|
},
|
|
libc: Libc = if (!Environment.isMusl) .default else .musl,
|
|
|
|
const Libc = enum {
|
|
/// The default libc for the target
|
|
/// "glibc" for linux, unspecified for other OSes
|
|
default,
|
|
/// musl libc
|
|
musl,
|
|
|
|
/// npm package name, `@oven-sh/bun-{os}-{arch}`
|
|
pub fn npmName(this: Libc) []const u8 {
|
|
return switch (this) {
|
|
.default => "",
|
|
.musl => "-musl",
|
|
};
|
|
}
|
|
|
|
pub fn format(self: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void {
|
|
if (self == .musl) {
|
|
try writer.writeAll("-musl");
|
|
}
|
|
}
|
|
};
|
|
|
|
const BaselineFormatter = struct {
|
|
baseline: bool = false,
|
|
pub fn format(self: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void {
|
|
if (self.baseline) {
|
|
try writer.writeAll("-baseline");
|
|
}
|
|
}
|
|
};
|
|
|
|
pub const DownloadError = error{
|
|
TargetNotFound,
|
|
NetworkError,
|
|
InvalidResponse,
|
|
ExtractionFailed,
|
|
InvalidTarget,
|
|
OutOfMemory,
|
|
NoSpaceLeft,
|
|
};
|
|
|
|
pub fn eql(this: *const CompileTarget, other: *const CompileTarget) bool {
|
|
return this.os == other.os and this.arch == other.arch and this.baseline == other.baseline and this.version.eql(other.version) and this.libc == other.libc;
|
|
}
|
|
|
|
pub fn isDefault(this: *const CompileTarget) bool {
|
|
return this.eql(&.{});
|
|
}
|
|
|
|
pub fn toNPMRegistryURL(this: *const CompileTarget, buf: []u8) ![]const u8 {
|
|
if (bun.env_var.BUN_COMPILE_TARGET_TARBALL_URL.get()) |url| {
|
|
if (strings.hasPrefixComptime(url, "http://") or strings.hasPrefixComptime(url, "https://"))
|
|
return url;
|
|
}
|
|
|
|
return try this.toNPMRegistryURLWithURL(buf, "https://registry.npmjs.org");
|
|
}
|
|
|
|
pub fn toNPMRegistryURLWithURL(this: *const CompileTarget, buf: []u8, registry_url: []const u8) ![]const u8 {
|
|
// Validate the target is supported before building URL
|
|
if (!this.isSupported()) {
|
|
return error.UnsupportedTarget;
|
|
}
|
|
|
|
return switch (this.os) {
|
|
inline else => |os| switch (this.arch) {
|
|
inline else => |arch| switch (this.libc) {
|
|
inline else => |libc| switch (this.baseline) {
|
|
// https://registry.npmjs.org/@oven/bun-linux-x64/-/bun-linux-x64-0.1.6.tgz
|
|
inline else => |is_baseline| std.fmt.bufPrint(buf, comptime "{s}/@oven/bun-" ++
|
|
os.npmName() ++ "-" ++ arch.npmName() ++
|
|
libc.npmName() ++
|
|
(if (is_baseline) "-baseline" else "") ++
|
|
"/-/bun-" ++
|
|
os.npmName() ++ "-" ++ arch.npmName() ++
|
|
libc.npmName() ++
|
|
(if (is_baseline) "-baseline" else "") ++
|
|
"-" ++
|
|
"{d}.{d}.{d}.tgz", .{
|
|
registry_url,
|
|
this.version.major,
|
|
this.version.minor,
|
|
this.version.patch,
|
|
}) catch |err| {
|
|
// Catch buffer overflow or other formatting errors
|
|
if (err == error.NoSpaceLeft) {
|
|
return error.BufferTooSmall;
|
|
}
|
|
return err;
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
pub fn format(this: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void {
|
|
try writer.print(
|
|
// bun-darwin-x64-baseline-v1.0.0
|
|
// This doesn't match up 100% with npm, but that's okay.
|
|
"bun-{s}-{s}{f}{f}-v{d}.{d}.{d}",
|
|
.{
|
|
this.os.npmName(),
|
|
this.arch.npmName(),
|
|
this.libc,
|
|
BaselineFormatter{ .baseline = this.baseline },
|
|
this.version.major,
|
|
this.version.minor,
|
|
this.version.patch,
|
|
},
|
|
);
|
|
}
|
|
|
|
pub fn exePath(this: *const CompileTarget, buf: *bun.PathBuffer, version_str: [:0]const u8, env: *bun.DotEnv.Loader, needs_download: *bool) [:0]const u8 {
|
|
if (this.isDefault()) brk: {
|
|
const self_exe_path = bun.selfExePath() catch break :brk;
|
|
@memcpy(buf, self_exe_path);
|
|
buf[self_exe_path.len] = 0;
|
|
needs_download.* = false;
|
|
return buf[0..self_exe_path.len :0];
|
|
}
|
|
|
|
if (bun.FD.cwd().existsAt(version_str)) {
|
|
needs_download.* = false;
|
|
return version_str;
|
|
}
|
|
|
|
const dest = bun.path.joinAbsStringBufZ(
|
|
bun.fs.FileSystem.instance.top_level_dir,
|
|
buf,
|
|
&.{
|
|
bun.install.PackageManager.fetchCacheDirectoryPath(env, null).path,
|
|
version_str,
|
|
},
|
|
.auto,
|
|
);
|
|
|
|
if (bun.FD.cwd().existsAt(dest)) {
|
|
needs_download.* = false;
|
|
}
|
|
|
|
return dest;
|
|
}
|
|
|
|
pub fn downloadToPath(this: *const CompileTarget, env: *bun.DotEnv.Loader, allocator: std.mem.Allocator, dest_z: [:0]const u8) !void {
|
|
HTTP.HTTPThread.init(&.{});
|
|
var refresher = bun.Progress{};
|
|
|
|
{
|
|
refresher.refresh();
|
|
|
|
// TODO: This is way too much code necessary to send a single HTTP request...
|
|
var async_http = try allocator.create(HTTP.AsyncHTTP);
|
|
var compressed_archive_bytes = try allocator.create(MutableString);
|
|
compressed_archive_bytes.* = try MutableString.init(allocator, 24 * 1024 * 1024);
|
|
var url_buffer: [2048]u8 = undefined;
|
|
const url_str = this.toNPMRegistryURL(&url_buffer) catch |err| {
|
|
// Return error without printing - let caller decide how to handle
|
|
return err;
|
|
};
|
|
const url_str_copy = try bun.default_allocator.dupe(u8, url_str);
|
|
const url = bun.URL.parse(url_str_copy);
|
|
{
|
|
var progress = refresher.start("Downloading", 0);
|
|
defer progress.end();
|
|
const http_proxy: ?bun.URL = env.getHttpProxyFor(url);
|
|
|
|
async_http.* = HTTP.AsyncHTTP.initSync(
|
|
allocator,
|
|
.GET,
|
|
url,
|
|
.{},
|
|
"",
|
|
compressed_archive_bytes,
|
|
"",
|
|
http_proxy,
|
|
null,
|
|
HTTP.FetchRedirect.follow,
|
|
);
|
|
async_http.client.progress_node = progress;
|
|
async_http.client.flags.reject_unauthorized = env.getTLSRejectUnauthorized();
|
|
|
|
const response = try async_http.sendSync();
|
|
|
|
switch (response.status_code) {
|
|
404 => {
|
|
// Return error without printing - let caller handle the messaging
|
|
return error.TargetNotFound;
|
|
},
|
|
403, 429, 499...599 => {
|
|
// Return error without printing - let caller handle the messaging
|
|
return error.NetworkError;
|
|
},
|
|
200 => {},
|
|
else => return error.NetworkError,
|
|
}
|
|
}
|
|
|
|
var tarball_bytes = std.ArrayListUnmanaged(u8){};
|
|
{
|
|
refresher.refresh();
|
|
defer compressed_archive_bytes.list.deinit(allocator);
|
|
|
|
if (compressed_archive_bytes.list.items.len == 0) {
|
|
// Return error without printing - let caller handle the messaging
|
|
return error.InvalidResponse;
|
|
}
|
|
|
|
{
|
|
var node = refresher.start("Decompressing", 0);
|
|
defer node.end();
|
|
var gunzip = bun.zlib.ZlibReaderArrayList.init(compressed_archive_bytes.list.items, &tarball_bytes, allocator) catch {
|
|
node.end();
|
|
// Return error without printing - let caller handle the messaging
|
|
return error.InvalidResponse;
|
|
};
|
|
gunzip.readAll(true) catch {
|
|
node.end();
|
|
// Return error without printing - let caller handle the messaging
|
|
return error.InvalidResponse;
|
|
};
|
|
gunzip.deinit();
|
|
}
|
|
refresher.refresh();
|
|
|
|
{
|
|
var node = refresher.start("Extracting", 0);
|
|
defer node.end();
|
|
|
|
const libarchive = bun.libarchive;
|
|
var tmpname_buf: [1024]u8 = undefined;
|
|
const tempdir_name = try bun.fs.FileSystem.tmpname("tmp", &tmpname_buf, bun.fastRandom());
|
|
var tmpdir = try std.fs.cwd().makeOpenPath(tempdir_name, .{});
|
|
defer tmpdir.close();
|
|
defer std.fs.cwd().deleteTree(tempdir_name) catch {};
|
|
_ = libarchive.Archiver.extractToDir(
|
|
tarball_bytes.items,
|
|
tmpdir,
|
|
null,
|
|
void,
|
|
{},
|
|
.{
|
|
// "package/bin"
|
|
.depth_to_skip = 2,
|
|
},
|
|
) catch {
|
|
node.end();
|
|
// Return error without printing - let caller handle the messaging
|
|
return error.ExtractionFailed;
|
|
};
|
|
|
|
var did_retry = false;
|
|
while (true) {
|
|
bun.sys.moveFileZ(.fromStdDir(tmpdir), if (this.os == .windows) "bun.exe" else "bun", bun.invalid_fd, dest_z) catch {
|
|
if (!did_retry) {
|
|
did_retry = true;
|
|
const dirname = bun.path.dirname(dest_z, .loose);
|
|
if (dirname.len > 0) {
|
|
std.fs.cwd().makePath(dirname) catch {};
|
|
continue;
|
|
}
|
|
|
|
// fallthrough, failed for another reason
|
|
}
|
|
node.end();
|
|
// Return error without printing - let caller handle the messaging
|
|
return error.ExtractionFailed;
|
|
};
|
|
break;
|
|
}
|
|
}
|
|
refresher.refresh();
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn isSupported(this: *const CompileTarget) bool {
|
|
return switch (this.os) {
|
|
.windows => this.arch == .x64,
|
|
|
|
.mac => true,
|
|
.linux => true,
|
|
|
|
.wasm => false,
|
|
};
|
|
}
|
|
|
|
pub const ParseError = error{
|
|
UnsupportedTarget,
|
|
InvalidTarget,
|
|
};
|
|
|
|
pub fn tryFrom(input_: []const u8) ParseError!CompileTarget {
|
|
var this = CompileTarget{};
|
|
const input = bun.strings.trim(input_, " \t\r");
|
|
if (input.len == 0) {
|
|
return this;
|
|
}
|
|
|
|
var found_os = false;
|
|
var found_arch = false;
|
|
var found_baseline = false;
|
|
var found_version = false;
|
|
var found_libc = false;
|
|
|
|
// Parse each of the supported values.
|
|
// The user shouldn't have to care about the order of the values. As long as it starts with "bun-".
|
|
// Nobody wants to remember whether its "bun-linux-x64" or "bun-x64-linux".
|
|
var splitter = bun.strings.split(input, "-");
|
|
while (input.len > 0) {
|
|
const token = splitter.next() orelse break;
|
|
if (token.len == 0) continue;
|
|
|
|
if (Environment.Architecture.names.get(token)) |arch| {
|
|
this.arch = arch;
|
|
found_arch = true;
|
|
continue;
|
|
} else if (Environment.OperatingSystem.names.get(token)) |os| {
|
|
this.os = os;
|
|
found_os = true;
|
|
continue;
|
|
} else if (strings.eqlComptime(token, "modern")) {
|
|
this.baseline = false;
|
|
found_baseline = true;
|
|
continue;
|
|
} else if (strings.eqlComptime(token, "baseline")) {
|
|
this.baseline = true;
|
|
found_baseline = true;
|
|
continue;
|
|
} else if (strings.hasPrefixComptime(token, "v1.") or strings.hasPrefixComptime(token, "v0.")) {
|
|
const version = bun.Semver.Version.parse(bun.Semver.SlicedString.init(token[1..], token[1..]));
|
|
if (version.valid) {
|
|
if (version.version.major == null or version.version.minor == null or version.version.patch == null) {
|
|
return error.InvalidTarget;
|
|
}
|
|
|
|
this.version = .{
|
|
.major = version.version.major.?,
|
|
.minor = version.version.minor.?,
|
|
.patch = version.version.patch.?,
|
|
};
|
|
found_version = true;
|
|
continue;
|
|
}
|
|
} else if (strings.eqlComptime(token, "musl")) {
|
|
this.libc = .musl;
|
|
found_libc = true;
|
|
continue;
|
|
} else {
|
|
return error.UnsupportedTarget;
|
|
}
|
|
}
|
|
|
|
if (!found_libc and this.libc == .musl and this.os != .linux) {
|
|
// "bun-windows-x64" should not implicitly be "bun-windows-x64-musl"
|
|
this.libc = .default;
|
|
}
|
|
|
|
if (found_os and !found_arch) {
|
|
// default to x64 if no arch is specified but OS is specified
|
|
// On macOS arm64, it's kind of surprising to choose Linux arm64 or Windows arm64
|
|
this.arch = .x64;
|
|
found_arch = true;
|
|
}
|
|
|
|
// there is no baseline arm64.
|
|
if (this.baseline and this.arch == .arm64) {
|
|
this.baseline = false;
|
|
}
|
|
|
|
if (this.libc == .musl and this.os != .linux) {
|
|
return error.InvalidTarget;
|
|
}
|
|
|
|
if (this.arch == .wasm or this.os == .wasm) {
|
|
return error.InvalidTarget;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
pub fn from(input_: []const u8) CompileTarget {
|
|
return tryFrom(input_) catch |err| {
|
|
switch (err) {
|
|
ParseError.UnsupportedTarget => {
|
|
const input = bun.strings.trim(input_, " \t\r");
|
|
var splitter = bun.strings.split(input, "-");
|
|
var unsupported_token: ?[]const u8 = null;
|
|
while (splitter.next()) |token| {
|
|
if (token.len == 0) continue;
|
|
if (Environment.Architecture.names.get(token) == null and
|
|
Environment.OperatingSystem.names.get(token) == null and
|
|
!strings.eqlComptime(token, "modern") and
|
|
!strings.eqlComptime(token, "baseline") and
|
|
!strings.eqlComptime(token, "musl") and
|
|
!(strings.hasPrefixComptime(token, "v1.") or strings.hasPrefixComptime(token, "v0.")))
|
|
{
|
|
unsupported_token = token;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (unsupported_token) |token| {
|
|
Output.errGeneric(
|
|
\\Unsupported target {f} in "bun{s}"
|
|
\\To see the supported targets:
|
|
\\ https://bun.com/docs/bundler/executables
|
|
, .{
|
|
bun.fmt.quote(token),
|
|
input_,
|
|
});
|
|
} else {
|
|
Output.errGeneric("Unsupported target: {s}", .{input_});
|
|
}
|
|
Global.exit(1);
|
|
},
|
|
ParseError.InvalidTarget => {
|
|
const input = bun.strings.trim(input_, " \t\r");
|
|
if (strings.containsComptime(input, "musl") and !strings.containsComptime(input, "linux")) {
|
|
Output.errGeneric("invalid target, musl libc only exists on linux", .{});
|
|
} else if (strings.containsComptime(input, "wasm")) {
|
|
Output.errGeneric("invalid target, WebAssembly is not supported. Sorry!", .{});
|
|
} else if (strings.containsComptime(input, "v")) {
|
|
Output.errGeneric("Please pass a complete version number to --target. For example, --target=bun-v" ++ Environment.version_string, .{});
|
|
} else {
|
|
Output.errGeneric("Invalid target: {s}", .{input_});
|
|
}
|
|
Global.exit(1);
|
|
},
|
|
}
|
|
};
|
|
}
|
|
|
|
// Exists for consistentcy with values.
|
|
pub fn defineKeys(_: *const CompileTarget) []const []const u8 {
|
|
return &.{
|
|
"process.platform",
|
|
"process.arch",
|
|
"process.versions.bun",
|
|
};
|
|
}
|
|
|
|
pub fn defineValues(this: *const CompileTarget) []const []const u8 {
|
|
// Use inline else to avoid extra allocations.
|
|
switch (this.os) {
|
|
inline else => |os| switch (this.arch) {
|
|
inline .arm64, .x64 => |arch| return struct {
|
|
pub const values = &.{
|
|
"\"" ++ os.nameString() ++ "\"",
|
|
|
|
switch (arch) {
|
|
.x64 => "\"x64\"",
|
|
.arm64 => "\"arm64\"",
|
|
else => @compileError("TODO"),
|
|
},
|
|
|
|
"\"" ++ Global.package_json_version ++ "\"",
|
|
};
|
|
}.values,
|
|
else => @panic("TODO"),
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn fromJS(global: *jsc.JSGlobalObject, value: jsc.JSValue) bun.JSError!CompileTarget {
|
|
const slice = try value.toSlice(global, bun.default_allocator);
|
|
defer slice.deinit();
|
|
if (!strings.hasPrefixComptime(slice.slice(), "bun-")) {
|
|
return global.throwInvalidArguments("Expected compile target to start with 'bun-', got {s}", .{slice.slice()});
|
|
}
|
|
|
|
return fromSlice(global, slice.slice());
|
|
}
|
|
|
|
pub fn fromSlice(global: *jsc.JSGlobalObject, slice_with_bun_prefix: []const u8) bun.JSError!CompileTarget {
|
|
const slice = slice_with_bun_prefix["bun-".len..];
|
|
const target_parsed = tryFrom(slice) catch {
|
|
return global.throwInvalidArguments("Unknown compile target: {s}", .{slice_with_bun_prefix});
|
|
};
|
|
if (!target_parsed.isSupported()) {
|
|
return global.throwInvalidArguments("Unsupported compile target: {s}", .{slice_with_bun_prefix});
|
|
}
|
|
|
|
return target_parsed;
|
|
}
|
|
|
|
const std = @import("std");
|
|
|
|
const bun = @import("bun");
|
|
const Environment = bun.Environment;
|
|
const Global = bun.Global;
|
|
const HTTP = bun.http;
|
|
const MutableString = bun.MutableString;
|
|
const Output = bun.Output;
|
|
const jsc = bun.jsc;
|
|
const strings = bun.strings;
|