mirror of
https://github.com/oven-sh/bun
synced 2026-02-12 11:59:00 +00:00
wip
This commit is contained in:
@@ -380,7 +380,9 @@ pub const StandaloneModuleGraph = struct {
|
||||
var entry_point_id: ?usize = null;
|
||||
var string_builder = bun.StringBuilder{};
|
||||
var module_count: usize = 0;
|
||||
for (output_files) |output_file| {
|
||||
std.debug.print("[DEBUG] toBytes - processing {d} output files\n", .{output_files.len});
|
||||
for (output_files, 0..) |output_file, i| {
|
||||
std.debug.print("[DEBUG] toBytes - file {d}: dest_path={s}, output_kind={}, side={?}, value={}\n", .{ i, output_file.dest_path, output_file.output_kind, output_file.side, output_file.value });
|
||||
string_builder.countZ(output_file.dest_path);
|
||||
string_builder.countZ(prefix);
|
||||
if (output_file.value == .buffer) {
|
||||
@@ -395,10 +397,15 @@ pub const StandaloneModuleGraph = struct {
|
||||
string_builder.cap += (output_file.value.buffer.bytes.len + 255) / 256 * 256 + 256;
|
||||
} else {
|
||||
if (entry_point_id == null) {
|
||||
if (output_file.side == null or output_file.side.? == .server) {
|
||||
std.debug.print("[DEBUG] toBytes - checking entry-point: side={?}, output_kind={}\n", .{ output_file.side, output_file.output_kind });
|
||||
// For standalone executables, accept client-side entry points as well as server-side
|
||||
if (output_file.side == null or output_file.side.? == .server or output_file.side.? == .client) {
|
||||
if (output_file.output_kind == .@"entry-point") {
|
||||
std.debug.print("[DEBUG] toBytes - setting entry_point_id = {d}\n", .{module_count});
|
||||
entry_point_id = module_count;
|
||||
}
|
||||
} else {
|
||||
std.debug.print("[DEBUG] toBytes - skipping entry-point due to side: {?}\n", .{output_file.side});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,7 +415,11 @@ pub const StandaloneModuleGraph = struct {
|
||||
}
|
||||
}
|
||||
|
||||
if (module_count == 0 or entry_point_id == null) return &[_]u8{};
|
||||
std.debug.print("[DEBUG] toBytes - module_count: {d}, entry_point_id: {?}\n", .{ module_count, entry_point_id });
|
||||
if (module_count == 0 or entry_point_id == null) {
|
||||
std.debug.print("[DEBUG] toBytes - returning empty array because module_count={d} or entry_point_id={?}\n", .{ module_count, entry_point_id });
|
||||
return &[_]u8{};
|
||||
}
|
||||
|
||||
string_builder.cap += @sizeOf(CompiledModuleGraphFile) * output_files.len;
|
||||
string_builder.cap += trailer.len;
|
||||
@@ -853,7 +864,9 @@ pub const StandaloneModuleGraph = struct {
|
||||
windows_hide_console: bool,
|
||||
windows_icon: ?[]const u8,
|
||||
) anyerror!void {
|
||||
std.debug.print("[DEBUG] StandaloneModuleGraph.toExecutable entry - outfile: {s}\n", .{outfile});
|
||||
const bytes = try toBytes(allocator, module_prefix, output_files, output_format);
|
||||
std.debug.print("[DEBUG] toBytes returned {d} bytes\n", .{bytes.len});
|
||||
if (bytes.len == 0) return;
|
||||
|
||||
const fd = try inject(
|
||||
@@ -866,6 +879,7 @@ pub const StandaloneModuleGraph = struct {
|
||||
target,
|
||||
);
|
||||
bun.debugAssert(fd.kind == .system);
|
||||
std.debug.print("[DEBUG] After inject, about to check Environment.isWindows: {}\n", .{Environment.isWindows});
|
||||
|
||||
if (Environment.isWindows) {
|
||||
var outfile_buf: bun.OSPathBuffer = undefined;
|
||||
@@ -902,14 +916,27 @@ pub const StandaloneModuleGraph = struct {
|
||||
|
||||
var buf: bun.PathBuffer = undefined;
|
||||
const temp_location = bun.getFdPath(fd, &buf) catch |err| return err;
|
||||
|
||||
const dest_basename = std.fs.path.basename(outfile);
|
||||
std.debug.print("[DEBUG] toExecutable - temp_location: {s}\n", .{temp_location});
|
||||
std.debug.print("[DEBUG] toExecutable - outfile: {s}\n", .{outfile});
|
||||
std.debug.print("[DEBUG] toExecutable - dest_basename: {s}\n", .{dest_basename});
|
||||
|
||||
// Check the size of the temporary file before moving
|
||||
if (std.fs.cwd().statFile(temp_location)) |temp_stat| {
|
||||
std.debug.print("[DEBUG] toExecutable - temp file size: {d} bytes\n", .{temp_stat.size});
|
||||
} else |err| {
|
||||
std.debug.print("[DEBUG] toExecutable - failed to stat temp file: {}\n", .{err});
|
||||
}
|
||||
|
||||
bun.sys.moveFileZWithHandle(
|
||||
fd,
|
||||
bun.FD.cwd(),
|
||||
bun.sliceTo(&(try std.posix.toPosixPath(temp_location)), 0),
|
||||
.fromStdDir(root_dir),
|
||||
bun.sliceTo(&(try std.posix.toPosixPath(std.fs.path.basename(outfile))), 0),
|
||||
bun.sliceTo(&(try std.posix.toPosixPath(dest_basename)), 0),
|
||||
) catch |err| {
|
||||
std.debug.print("[DEBUG] toExecutable - moveFileZWithHandle failed: {}\n", .{err});
|
||||
if (err == error.IsDir or err == error.EISDIR) {
|
||||
Output.prettyErrorln("<r><red>error<r><d>:<r> {} is a directory. Please choose a different --outfile or delete the directory", .{bun.fmt.quote(outfile)});
|
||||
} else {
|
||||
|
||||
@@ -2292,60 +2292,124 @@ pub const BundleV2 = struct {
|
||||
|
||||
const output_files_list = try this.linker.generateChunksInParallel(chunks, false);
|
||||
|
||||
// ADD COMPILE LOGIC HERE
|
||||
// Handle compile: true option
|
||||
if (this.transpiler.options.compile) {
|
||||
defer {
|
||||
for (output_files_list.items) |*file| {
|
||||
file.deinit();
|
||||
}
|
||||
output_files_list.deinit();
|
||||
}
|
||||
|
||||
const outfile = if (this.transpiler.options.output_dir.len > 0)
|
||||
// This logic might need adjustment based on how --outfile is handled.
|
||||
// For now, assume the first entry point name.
|
||||
this.transpiler.options.entry_points[0]
|
||||
else
|
||||
"a.out";
|
||||
|
||||
// The JS task holds the compile target.
|
||||
const compile_target_from_js = this.completion.?.compile_target;
|
||||
std.debug.print("[DEBUG] Entering compile mode\n", .{});
|
||||
// Extract the compile target from the completion task
|
||||
const compile_target_from_js = if (this.completion) |completion| completion.compile_target else null;
|
||||
var default_compile_target: CompileTarget = .{};
|
||||
const target = compile_target_from_js orelse &default_compile_target;
|
||||
|
||||
// Determine output file name - use proper basename logic
|
||||
const entry_point = this.transpiler.options.entry_points[0];
|
||||
const basename = std.fs.path.basename(entry_point);
|
||||
const name_without_ext = if (std.mem.lastIndexOfScalar(u8, basename, '.')) |dot_index|
|
||||
basename[0..dot_index]
|
||||
else
|
||||
basename;
|
||||
|
||||
// Create output path in the specified output directory
|
||||
var outfile_buf: bun.PathBuffer = undefined;
|
||||
const outfile = if (this.transpiler.options.output_dir.len > 0) blk: {
|
||||
break :blk std.fmt.bufPrint(&outfile_buf, "{s}{c}{s}", .{
|
||||
this.transpiler.options.output_dir,
|
||||
std.fs.path.sep,
|
||||
name_without_ext,
|
||||
}) catch "a.out";
|
||||
} else name_without_ext;
|
||||
|
||||
std.debug.print("[DEBUG] Output file path: {s}\n", .{outfile});
|
||||
|
||||
// For compile mode, we need to load saved files into buffers for embedding
|
||||
var output_files_for_executable = std.ArrayList(options.OutputFile).init(this.graph.allocator);
|
||||
defer output_files_for_executable.deinit();
|
||||
|
||||
for (output_files_list.items) |*output_file| {
|
||||
if (output_file.value == .saved) {
|
||||
// Read the saved file content into a buffer
|
||||
// Check if dest_path is absolute or relative to output_dir
|
||||
const file_path = if (std.fs.path.isAbsolute(output_file.dest_path))
|
||||
output_file.dest_path
|
||||
else if (this.transpiler.options.output_dir.len > 0) blk: {
|
||||
var path_buf: bun.PathBuffer = undefined;
|
||||
break :blk std.fmt.bufPrint(&path_buf, "{s}{c}{s}", .{
|
||||
this.transpiler.options.output_dir,
|
||||
std.fs.path.sep,
|
||||
output_file.dest_path,
|
||||
}) catch output_file.dest_path;
|
||||
} else output_file.dest_path;
|
||||
|
||||
std.debug.print("[DEBUG] Attempting to read file: {s}\n", .{file_path});
|
||||
const file_content = std.fs.cwd().readFileAlloc(this.graph.allocator, file_path, 16 * 1024 * 1024) catch |err| {
|
||||
std.debug.print("[DEBUG] Failed to read saved file {s}: {}\n", .{ file_path, err });
|
||||
continue;
|
||||
};
|
||||
|
||||
// Create a new output file with buffer content
|
||||
var new_output_file = output_file.*;
|
||||
new_output_file.value = .{ .buffer = .{ .allocator = this.graph.allocator, .bytes = file_content } };
|
||||
try output_files_for_executable.append(new_output_file);
|
||||
std.debug.print("[DEBUG] Loaded saved file into buffer: {s} ({d} bytes)\n", .{ file_path, file_content.len });
|
||||
} else {
|
||||
try output_files_for_executable.append(output_file.*);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate standalone executable from bundled output
|
||||
std.debug.print("[DEBUG] Calling toExecutable with {} output files\n", .{output_files_for_executable.items.len});
|
||||
|
||||
// For toExecutable to work correctly, we need to pass the directory and filename separately
|
||||
var output_dir_owned: ?std.fs.Dir = null;
|
||||
const output_dir = if (std.fs.path.dirname(outfile)) |dirname| blk: {
|
||||
const dir = std.fs.cwd().openDir(dirname, .{}) catch |err| {
|
||||
std.debug.print("[DEBUG] Failed to open output directory {s}: {}\n", .{ dirname, err });
|
||||
return err;
|
||||
};
|
||||
output_dir_owned = dir;
|
||||
break :blk dir;
|
||||
} else std.fs.cwd();
|
||||
defer if (output_dir_owned) |*dir| dir.close();
|
||||
|
||||
const output_filename = std.fs.path.basename(outfile);
|
||||
std.debug.print("[DEBUG] Output directory: {s}, filename: {s}\n", .{
|
||||
if (std.fs.path.dirname(outfile)) |dir| dir else ".",
|
||||
output_filename
|
||||
});
|
||||
|
||||
bun.StandaloneModuleGraph.toExecutable(
|
||||
target,
|
||||
this.graph.allocator,
|
||||
output_files_list.items,
|
||||
std.fs.cwd(), // Assumes CWD, might need to use rootdir
|
||||
output_files_for_executable.items,
|
||||
output_dir,
|
||||
"", // module_prefix
|
||||
outfile,
|
||||
output_filename,
|
||||
this.transpiler.env,
|
||||
this.transpiler.options.output_format,
|
||||
false, // windows_hide_console, TODO: expose this option
|
||||
null, // windows_icon, TODO: expose this option
|
||||
) catch |err| {
|
||||
// Handle the new errors from StandaloneModuleGraph
|
||||
std.debug.print("[DEBUG] toExecutable failed with error: {}\n", .{err});
|
||||
this.transpiler.log.addError(null, .{}, @errorName(err)) catch {};
|
||||
// Propagate the error to fail the Bun.build() promise
|
||||
return err;
|
||||
};
|
||||
std.debug.print("[DEBUG] toExecutable completed successfully\n", .{});
|
||||
|
||||
// Debug: Check if the executable was actually created
|
||||
if (std.fs.cwd().access(outfile, .{})) {
|
||||
std.debug.print("[DEBUG] Executable file created successfully at: {s}\n", .{outfile});
|
||||
} else |err| {
|
||||
std.debug.print("[DEBUG] Executable file NOT found after toExecutable: {} at path: {s}\n", .{ err, outfile });
|
||||
}
|
||||
|
||||
// Return a BuildArtifact representing the executable
|
||||
var executable_output = std.ArrayList(options.OutputFile).init(this.graph.allocator);
|
||||
try executable_output.append(options.OutputFile{
|
||||
.loader = .file,
|
||||
.src_path = Fs.Path.init(this.transpiler.options.entry_points[0]),
|
||||
.dest_path = outfile,
|
||||
.value = .{ .saved = .{} },
|
||||
.size = 0, // Will be set correctly by the file system
|
||||
.output_kind = .@"entry-point",
|
||||
.side = null,
|
||||
.entry_point_index = 0,
|
||||
});
|
||||
return executable_output;
|
||||
// Clean up the intermediate output files since we've created an executable
|
||||
for (output_files_list.items) |*file| {
|
||||
file.deinit();
|
||||
}
|
||||
output_files_list.deinit();
|
||||
|
||||
// Return empty output list for compile mode (executable was written to disk)
|
||||
return std.ArrayList(options.OutputFile).init(this.graph.allocator);
|
||||
}
|
||||
// END ADDED BLOCK
|
||||
|
||||
return output_files_list;
|
||||
}
|
||||
|
||||
30
src/sys.zig
30
src/sys.zig
@@ -4942,6 +4942,7 @@ pub fn moveFileZWithHandle(from_handle: bun.FileDescriptor, from_dir: bun.FileDe
|
||||
if (err.getErrno() == .XDEV) {
|
||||
try copyFileZSlowWithHandle(from_handle, to_dir, destination).unwrap();
|
||||
_ = unlinkat(from_dir, filename);
|
||||
return;
|
||||
}
|
||||
|
||||
return bun.errnoToZigErr(err.errno);
|
||||
@@ -5008,9 +5009,34 @@ pub fn copyFileZSlowWithHandle(in_handle: bun.FileDescriptor, to_dir: bun.FileDe
|
||||
_ = std.os.linux.fallocate(out_handle.cast(), 0, 0, @intCast(stat_.size));
|
||||
}
|
||||
|
||||
// Seek to the beginning of the input file
|
||||
switch (lseek(in_handle, 0, std.posix.SEEK.SET)) {
|
||||
.result => |pos| {
|
||||
std.debug.print("[DEBUG] copyFileZSlowWithHandle - seeked to position: {d}\n", .{pos});
|
||||
},
|
||||
.err => |err| {
|
||||
std.debug.print("[DEBUG] copyFileZSlowWithHandle - failed to seek input file: {}\n", .{err});
|
||||
},
|
||||
}
|
||||
|
||||
std.debug.print("[DEBUG] copyFileZSlowWithHandle - copying from fd {d} to fd {d}, source size: {d}\n", .{ in_handle.cast(), out_handle.cast(), stat_.size });
|
||||
switch (bun.copyFile(in_handle, out_handle)) {
|
||||
.err => |e| return .{ .err = e },
|
||||
.result => {},
|
||||
.err => |e| {
|
||||
std.debug.print("[DEBUG] copyFileZSlowWithHandle - copyFile failed: {}\n", .{e});
|
||||
return .{ .err = e };
|
||||
},
|
||||
.result => {
|
||||
std.debug.print("[DEBUG] copyFileZSlowWithHandle - copyFile succeeded\n", .{});
|
||||
// Check the size of the output file after copying
|
||||
switch (fstat(out_handle)) {
|
||||
.result => |out_stat| {
|
||||
std.debug.print("[DEBUG] copyFileZSlowWithHandle - output file size after copy: {d}\n", .{out_stat.size});
|
||||
},
|
||||
.err => |err| {
|
||||
std.debug.print("[DEBUG] copyFileZSlowWithHandle - failed to stat output file: {}\n", .{err});
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
if (comptime Environment.isPosix) {
|
||||
|
||||
Reference in New Issue
Block a user