diff --git a/lib/compiler/resinator/compile.zig b/lib/compiler/resinator/compile.zig index fbb3797fde..df1bbbcddf 100644 --- a/lib/compiler/resinator/compile.zig +++ b/lib/compiler/resinator/compile.zig @@ -1,6 +1,12 @@ -const std = @import("std"); const builtin = @import("builtin"); +const native_endian = builtin.cpu.arch.endian(); + +const std = @import("std"); +const Io = std.Io; const Allocator = std.mem.Allocator; +const WORD = std.os.windows.WORD; +const DWORD = std.os.windows.DWORD; + const Node = @import("ast.zig").Node; const lex = @import("lex.zig"); const Parser = @import("parse.zig").Parser; @@ -17,8 +23,6 @@ const res = @import("res.zig"); const ico = @import("ico.zig"); const ani = @import("ani.zig"); const bmp = @import("bmp.zig"); -const WORD = std.os.windows.WORD; -const DWORD = std.os.windows.DWORD; const utils = @import("utils.zig"); const NameOrOrdinal = res.NameOrOrdinal; const SupportedCodePage = @import("code_pages.zig").SupportedCodePage; @@ -28,7 +32,6 @@ const windows1252 = @import("windows1252.zig"); const lang = @import("lang.zig"); const code_pages = @import("code_pages.zig"); const errors = @import("errors.zig"); -const native_endian = builtin.cpu.arch.endian(); pub const CompileOptions = struct { cwd: std.fs.Dir, @@ -77,7 +80,7 @@ pub const Dependencies = struct { } }; -pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer, options: CompileOptions) !void { +pub fn compile(allocator: Allocator, io: Io, source: []const u8, writer: *std.Io.Writer, options: CompileOptions) !void { var lexer = lex.Lexer.init(source, .{ .default_code_page = options.default_code_page, .source_mappings = options.source_mappings, @@ -166,10 +169,11 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer, defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - var compiler = Compiler{ + var compiler: Compiler = .{ .source = source, .arena = arena, .allocator = allocator, + .io = io, .cwd = options.cwd, .diagnostics = options.diagnostics, .dependencies = options.dependencies, @@ -191,6 +195,7 @@ pub const Compiler = struct { source: []const u8, arena: Allocator, allocator: Allocator, + io: Io, cwd: std.fs.Dir, state: State = .{}, diagnostics: *Diagnostics, @@ -409,7 +414,7 @@ pub const Compiler = struct { } } - var first_error: ?std.fs.File.OpenError = null; + var first_error: ?(std.fs.File.OpenError || std.fs.File.StatError) = null; for (self.search_dirs) |search_dir| { if (utils.openFileNotDir(search_dir.dir, path, .{})) |file| { errdefer file.close(); @@ -496,6 +501,8 @@ pub const Compiler = struct { } pub fn writeResourceExternal(self: *Compiler, node: *Node.ResourceExternal, writer: *std.Io.Writer) !void { + const io = self.io; + // Init header with data size zero for now, will need to fill it in later var header = try self.resourceHeader(node.id, node.type, .{}); defer header.deinit(self.allocator); @@ -582,7 +589,7 @@ pub const Compiler = struct { }; defer file_handle.close(); var file_buffer: [2048]u8 = undefined; - var file_reader = file_handle.reader(&file_buffer); + var file_reader = file_handle.reader(io, &file_buffer); if (maybe_predefined_type) |predefined_type| { switch (predefined_type) { diff --git a/lib/compiler/resinator/cvtres.zig b/lib/compiler/resinator/cvtres.zig index 50d2c6e96a..26b6620af2 100644 --- a/lib/compiler/resinator/cvtres.zig +++ b/lib/compiler/resinator/cvtres.zig @@ -1,5 +1,7 @@ const std = @import("std"); +const Io = std.Io; const Allocator = std.mem.Allocator; + const res = @import("res.zig"); const NameOrOrdinal = res.NameOrOrdinal; const MemoryFlags = res.MemoryFlags; @@ -169,8 +171,7 @@ pub fn parseNameOrOrdinal(allocator: Allocator, reader: *std.Io.Reader) !NameOrO pub const CoffOptions = struct { target: std.coff.IMAGE.FILE.MACHINE = .AMD64, - /// If true, zeroes will be written to all timestamp fields - reproducible: bool = true, + timestamp: i64 = 0, /// If true, the MEM_WRITE flag will not be set in the .rsrc section header read_only: bool = false, /// If non-null, a symbol with this name and storage class EXTERNAL will be added to the symbol table. @@ -188,7 +189,13 @@ pub const Diagnostics = union { overflow_resource: usize, }; -pub fn writeCoff(allocator: Allocator, writer: *std.Io.Writer, resources: []const Resource, options: CoffOptions, diagnostics: ?*Diagnostics) !void { +pub fn writeCoff( + allocator: Allocator, + writer: *std.Io.Writer, + resources: []const Resource, + options: CoffOptions, + diagnostics: ?*Diagnostics, +) !void { var resource_tree = ResourceTree.init(allocator, options); defer resource_tree.deinit(); @@ -215,7 +222,7 @@ pub fn writeCoff(allocator: Allocator, writer: *std.Io.Writer, resources: []cons const pointer_to_rsrc02_data = pointer_to_relocations + relocations_len; const pointer_to_symbol_table = pointer_to_rsrc02_data + lengths.rsrc02; - const timestamp: i64 = if (options.reproducible) 0 else std.time.timestamp(); + const timestamp: i64 = options.timestamp; const size_of_optional_header = 0; const machine_type: std.coff.IMAGE.FILE.MACHINE = options.target; const flags = std.coff.Header.Flags{ diff --git a/lib/compiler/resinator/errors.zig b/lib/compiler/resinator/errors.zig index 1d9cbf4c5b..aad74a3ca3 100644 --- a/lib/compiler/resinator/errors.zig +++ b/lib/compiler/resinator/errors.zig @@ -1,5 +1,11 @@ +const builtin = @import("builtin"); +const native_endian = builtin.cpu.arch.endian(); + const std = @import("std"); +const Io = std.Io; const assert = std.debug.assert; +const Allocator = std.mem.Allocator; + const Token = @import("lex.zig").Token; const SourceMappings = @import("source_mapping.zig").SourceMappings; const utils = @import("utils.zig"); @@ -11,19 +17,19 @@ const parse = @import("parse.zig"); const lang = @import("lang.zig"); const code_pages = @import("code_pages.zig"); const SupportedCodePage = code_pages.SupportedCodePage; -const builtin = @import("builtin"); -const native_endian = builtin.cpu.arch.endian(); pub const Diagnostics = struct { errors: std.ArrayList(ErrorDetails) = .empty, /// Append-only, cannot handle removing strings. /// Expects to own all strings within the list. strings: std.ArrayList([]const u8) = .empty, - allocator: std.mem.Allocator, + allocator: Allocator, + io: Io, - pub fn init(allocator: std.mem.Allocator) Diagnostics { + pub fn init(allocator: Allocator, io: Io) Diagnostics { return .{ .allocator = allocator, + .io = io, }; } @@ -62,10 +68,11 @@ pub const Diagnostics = struct { } pub fn renderToStdErr(self: *Diagnostics, cwd: std.fs.Dir, source: []const u8, tty_config: std.Io.tty.Config, source_mappings: ?SourceMappings) void { + const io = self.io; const stderr = std.debug.lockStderrWriter(&.{}); defer std.debug.unlockStderrWriter(); for (self.errors.items) |err_details| { - renderErrorMessage(stderr, tty_config, cwd, err_details, source, self.strings.items, source_mappings) catch return; + renderErrorMessage(io, stderr, tty_config, cwd, err_details, source, self.strings.items, source_mappings) catch return; } } @@ -167,9 +174,9 @@ pub const ErrorDetails = struct { filename_string_index: FilenameStringIndex, pub const FilenameStringIndex = std.meta.Int(.unsigned, 32 - @bitSizeOf(FileOpenErrorEnum)); - pub const FileOpenErrorEnum = std.meta.FieldEnum(std.fs.File.OpenError); + pub const FileOpenErrorEnum = std.meta.FieldEnum(std.fs.File.OpenError || std.fs.File.StatError); - pub fn enumFromError(err: std.fs.File.OpenError) FileOpenErrorEnum { + pub fn enumFromError(err: (std.fs.File.OpenError || std.fs.File.StatError)) FileOpenErrorEnum { return switch (err) { inline else => |e| @field(ErrorDetails.FileOpenError.FileOpenErrorEnum, @errorName(e)), }; @@ -894,7 +901,16 @@ fn cellCount(code_page: SupportedCodePage, source: []const u8, start_index: usiz const truncated_str = "<...truncated...>"; -pub fn renderErrorMessage(writer: *std.Io.Writer, tty_config: std.Io.tty.Config, cwd: std.fs.Dir, err_details: ErrorDetails, source: []const u8, strings: []const []const u8, source_mappings: ?SourceMappings) !void { +pub fn renderErrorMessage( + io: Io, + writer: *std.Io.Writer, + tty_config: std.Io.tty.Config, + cwd: std.fs.Dir, + err_details: ErrorDetails, + source: []const u8, + strings: []const []const u8, + source_mappings: ?SourceMappings, +) !void { if (err_details.type == .hint) return; const source_line_start = err_details.token.getLineStartForErrorDisplay(source); @@ -989,6 +1005,7 @@ pub fn renderErrorMessage(writer: *std.Io.Writer, tty_config: std.Io.tty.Config, var initial_lines_err: ?anyerror = null; var file_reader_buf: [max_source_line_bytes * 2]u8 = undefined; var corresponding_lines: ?CorrespondingLines = CorrespondingLines.init( + io, cwd, err_details, source_line_for_display.line, @@ -1084,6 +1101,7 @@ const CorrespondingLines = struct { code_page: SupportedCodePage, pub fn init( + io: Io, cwd: std.fs.Dir, err_details: ErrorDetails, line_for_comparison: []const u8, @@ -1108,7 +1126,7 @@ const CorrespondingLines = struct { .code_page = err_details.code_page, .file_reader = undefined, }; - corresponding_lines.file_reader = corresponding_lines.file.reader(file_reader_buf); + corresponding_lines.file_reader = corresponding_lines.file.reader(io, file_reader_buf); errdefer corresponding_lines.deinit(); try corresponding_lines.writeLineFromStreamVerbatim( diff --git a/lib/compiler/resinator/main.zig b/lib/compiler/resinator/main.zig index ce8532ae9f..108b914377 100644 --- a/lib/compiler/resinator/main.zig +++ b/lib/compiler/resinator/main.zig @@ -1,5 +1,9 @@ -const std = @import("std"); const builtin = @import("builtin"); + +const std = @import("std"); +const Io = std.Io; +const Allocator = std.mem.Allocator; + const removeComments = @import("comments.zig").removeComments; const parseAndRemoveLineCommands = @import("source_mapping.zig").parseAndRemoveLineCommands; const compile = @import("compile.zig").compile; @@ -16,19 +20,18 @@ const aro = @import("aro"); const compiler_util = @import("../util.zig"); pub fn main() !void { - var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init; - defer std.debug.assert(gpa.deinit() == .ok); - const allocator = gpa.allocator(); + var debug_allocator: std.heap.DebugAllocator(.{}) = .init; + defer std.debug.assert(debug_allocator.deinit() == .ok); + const gpa = debug_allocator.allocator(); - var arena_state = std.heap.ArenaAllocator.init(allocator); + var arena_state = std.heap.ArenaAllocator.init(gpa); defer arena_state.deinit(); const arena = arena_state.allocator(); const stderr = std.fs.File.stderr(); const stderr_config = std.Io.tty.detectConfig(stderr); - const args = try std.process.argsAlloc(allocator); - defer std.process.argsFree(allocator, args); + const args = try std.process.argsAlloc(arena); if (args.len < 2) { try renderErrorMessage(std.debug.lockStderrWriter(&.{}), stderr_config, .err, "expected zig lib dir as first argument", .{}); @@ -59,11 +62,11 @@ pub fn main() !void { }; var options = options: { - var cli_diagnostics = cli.Diagnostics.init(allocator); + var cli_diagnostics = cli.Diagnostics.init(gpa); defer cli_diagnostics.deinit(); - var options = cli.parse(allocator, cli_args, &cli_diagnostics) catch |err| switch (err) { + var options = cli.parse(gpa, cli_args, &cli_diagnostics) catch |err| switch (err) { error.ParseError => { - try error_handler.emitCliDiagnostics(allocator, cli_args, &cli_diagnostics); + try error_handler.emitCliDiagnostics(gpa, cli_args, &cli_diagnostics); std.process.exit(1); }, else => |e| return e, @@ -84,6 +87,10 @@ pub fn main() !void { }; defer options.deinit(); + var threaded: std.Io.Threaded = .init(gpa); + defer threaded.deinit(); + const io = threaded.io(); + if (options.print_help_and_exit) { try cli.writeUsage(stdout, "zig rc"); try stdout.flush(); @@ -99,12 +106,13 @@ pub fn main() !void { try stdout.flush(); } - var dependencies = Dependencies.init(allocator); + var dependencies = Dependencies.init(gpa); defer dependencies.deinit(); const maybe_dependencies: ?*Dependencies = if (options.depfile_path != null) &dependencies else null; var include_paths = LazyIncludePaths{ .arena = arena, + .io = io, .auto_includes_option = options.auto_includes, .zig_lib_dir = zig_lib_dir, .target_machine_type = options.coff_options.target, @@ -112,12 +120,12 @@ pub fn main() !void { const full_input = full_input: { if (options.input_format == .rc and options.preprocess != .no) { - var preprocessed_buf: std.Io.Writer.Allocating = .init(allocator); + var preprocessed_buf: std.Io.Writer.Allocating = .init(gpa); errdefer preprocessed_buf.deinit(); // We're going to throw away everything except the final preprocessed output anyway, // so we can use a scoped arena for everything else. - var aro_arena_state = std.heap.ArenaAllocator.init(allocator); + var aro_arena_state = std.heap.ArenaAllocator.init(gpa); defer aro_arena_state.deinit(); const aro_arena = aro_arena_state.allocator(); @@ -129,12 +137,12 @@ pub fn main() !void { .color = stderr_config, } } }, true => .{ .output = .{ .to_list = .{ - .arena = .init(allocator), + .arena = .init(gpa), } } }, }; defer diagnostics.deinit(); - var comp = aro.Compilation.init(aro_arena, aro_arena, &diagnostics, std.fs.cwd()); + var comp = aro.Compilation.init(aro_arena, aro_arena, io, &diagnostics, std.fs.cwd()); defer comp.deinit(); var argv: std.ArrayList([]const u8) = .empty; @@ -159,20 +167,20 @@ pub fn main() !void { preprocess.preprocess(&comp, &preprocessed_buf.writer, argv.items, maybe_dependencies) catch |err| switch (err) { error.GeneratedSourceError => { - try error_handler.emitAroDiagnostics(allocator, "failed during preprocessor setup (this is always a bug)", &comp); + try error_handler.emitAroDiagnostics(gpa, "failed during preprocessor setup (this is always a bug)", &comp); std.process.exit(1); }, // ArgError can occur if e.g. the .rc file is not found error.ArgError, error.PreprocessError => { - try error_handler.emitAroDiagnostics(allocator, "failed during preprocessing", &comp); + try error_handler.emitAroDiagnostics(gpa, "failed during preprocessing", &comp); std.process.exit(1); }, error.FileTooBig => { - try error_handler.emitMessage(allocator, .err, "failed during preprocessing: maximum file size exceeded", .{}); + try error_handler.emitMessage(gpa, .err, "failed during preprocessing: maximum file size exceeded", .{}); std.process.exit(1); }, error.WriteFailed => { - try error_handler.emitMessage(allocator, .err, "failed during preprocessing: error writing the preprocessed output", .{}); + try error_handler.emitMessage(gpa, .err, "failed during preprocessing: error writing the preprocessed output", .{}); std.process.exit(1); }, error.OutOfMemory => |e| return e, @@ -182,22 +190,22 @@ pub fn main() !void { } else { switch (options.input_source) { .stdio => |file| { - var file_reader = file.reader(&.{}); - break :full_input file_reader.interface.allocRemaining(allocator, .unlimited) catch |err| { - try error_handler.emitMessage(allocator, .err, "unable to read input from stdin: {s}", .{@errorName(err)}); + var file_reader = file.reader(io, &.{}); + break :full_input file_reader.interface.allocRemaining(gpa, .unlimited) catch |err| { + try error_handler.emitMessage(gpa, .err, "unable to read input from stdin: {s}", .{@errorName(err)}); std.process.exit(1); }; }, .filename => |input_filename| { - break :full_input std.fs.cwd().readFileAlloc(input_filename, allocator, .unlimited) catch |err| { - try error_handler.emitMessage(allocator, .err, "unable to read input file path '{s}': {s}", .{ input_filename, @errorName(err) }); + break :full_input std.fs.cwd().readFileAlloc(input_filename, gpa, .unlimited) catch |err| { + try error_handler.emitMessage(gpa, .err, "unable to read input file path '{s}': {s}", .{ input_filename, @errorName(err) }); std.process.exit(1); }; }, } } }; - defer allocator.free(full_input); + defer gpa.free(full_input); if (options.preprocess == .only) { switch (options.output_source) { @@ -221,55 +229,55 @@ pub fn main() !void { } else if (options.input_format == .res) IoStream.fromIoSource(options.input_source, .input) catch |err| { - try error_handler.emitMessage(allocator, .err, "unable to read res file path '{s}': {s}", .{ options.input_source.filename, @errorName(err) }); + try error_handler.emitMessage(gpa, .err, "unable to read res file path '{s}': {s}", .{ options.input_source.filename, @errorName(err) }); std.process.exit(1); } else IoStream.fromIoSource(options.output_source, .output) catch |err| { - try error_handler.emitMessage(allocator, .err, "unable to create output file '{s}': {s}", .{ options.output_source.filename, @errorName(err) }); + try error_handler.emitMessage(gpa, .err, "unable to create output file '{s}': {s}", .{ options.output_source.filename, @errorName(err) }); std.process.exit(1); }; - defer res_stream.deinit(allocator); + defer res_stream.deinit(gpa); const res_data = res_data: { if (options.input_format != .res) { // Note: We still want to run this when no-preprocess is set because: // 1. We want to print accurate line numbers after removing multiline comments // 2. We want to be able to handle an already-preprocessed input with #line commands in it - var mapping_results = parseAndRemoveLineCommands(allocator, full_input, full_input, .{ .initial_filename = options.input_source.filename }) catch |err| switch (err) { + var mapping_results = parseAndRemoveLineCommands(gpa, full_input, full_input, .{ .initial_filename = options.input_source.filename }) catch |err| switch (err) { error.InvalidLineCommand => { // TODO: Maybe output the invalid line command - try error_handler.emitMessage(allocator, .err, "invalid line command in the preprocessed source", .{}); + try error_handler.emitMessage(gpa, .err, "invalid line command in the preprocessed source", .{}); if (options.preprocess == .no) { - try error_handler.emitMessage(allocator, .note, "line commands must be of the format: #line \"\"", .{}); + try error_handler.emitMessage(gpa, .note, "line commands must be of the format: #line \"\"", .{}); } else { - try error_handler.emitMessage(allocator, .note, "this is likely to be a bug, please report it", .{}); + try error_handler.emitMessage(gpa, .note, "this is likely to be a bug, please report it", .{}); } std.process.exit(1); }, error.LineNumberOverflow => { // TODO: Better error message - try error_handler.emitMessage(allocator, .err, "line number count exceeded maximum of {}", .{std.math.maxInt(usize)}); + try error_handler.emitMessage(gpa, .err, "line number count exceeded maximum of {}", .{std.math.maxInt(usize)}); std.process.exit(1); }, error.OutOfMemory => |e| return e, }; - defer mapping_results.mappings.deinit(allocator); + defer mapping_results.mappings.deinit(gpa); const default_code_page = options.default_code_page orelse .windows1252; const has_disjoint_code_page = hasDisjointCodePage(mapping_results.result, &mapping_results.mappings, default_code_page); const final_input = try removeComments(mapping_results.result, mapping_results.result, &mapping_results.mappings); - var diagnostics = Diagnostics.init(allocator); + var diagnostics = Diagnostics.init(gpa, io); defer diagnostics.deinit(); var output_buffer: [4096]u8 = undefined; - var res_stream_writer = res_stream.source.writer(allocator, &output_buffer); + var res_stream_writer = res_stream.source.writer(gpa, &output_buffer); defer res_stream_writer.deinit(&res_stream.source); const output_buffered_stream = res_stream_writer.interface(); - compile(allocator, final_input, output_buffered_stream, .{ + compile(gpa, io, final_input, output_buffered_stream, .{ .cwd = std.fs.cwd(), .diagnostics = &diagnostics, .source_mappings = &mapping_results.mappings, @@ -287,7 +295,7 @@ pub fn main() !void { .warn_instead_of_error_on_invalid_code_page = options.warn_instead_of_error_on_invalid_code_page, }) catch |err| switch (err) { error.ParseError, error.CompileError => { - try error_handler.emitDiagnostics(allocator, std.fs.cwd(), final_input, &diagnostics, mapping_results.mappings); + try error_handler.emitDiagnostics(gpa, std.fs.cwd(), final_input, &diagnostics, mapping_results.mappings); // Delete the output file on error res_stream.cleanupAfterError(); std.process.exit(1); @@ -305,7 +313,7 @@ pub fn main() !void { // write the depfile if (options.depfile_path) |depfile_path| { var depfile = std.fs.cwd().createFile(depfile_path, .{}) catch |err| { - try error_handler.emitMessage(allocator, .err, "unable to create depfile '{s}': {s}", .{ depfile_path, @errorName(err) }); + try error_handler.emitMessage(gpa, .err, "unable to create depfile '{s}': {s}", .{ depfile_path, @errorName(err) }); std.process.exit(1); }; defer depfile.close(); @@ -332,41 +340,41 @@ pub fn main() !void { if (options.output_format != .coff) return; - break :res_data res_stream.source.readAll(allocator) catch |err| { - try error_handler.emitMessage(allocator, .err, "unable to read res from '{s}': {s}", .{ res_stream.name, @errorName(err) }); + break :res_data res_stream.source.readAll(gpa, io) catch |err| { + try error_handler.emitMessage(gpa, .err, "unable to read res from '{s}': {s}", .{ res_stream.name, @errorName(err) }); std.process.exit(1); }; }; // No need to keep the res_data around after parsing the resources from it - defer res_data.deinit(allocator); + defer res_data.deinit(gpa); std.debug.assert(options.output_format == .coff); // TODO: Maybe use a buffered file reader instead of reading file into memory -> fbs var res_reader: std.Io.Reader = .fixed(res_data.bytes); - break :resources cvtres.parseRes(allocator, &res_reader, .{ .max_size = res_data.bytes.len }) catch |err| { + break :resources cvtres.parseRes(gpa, &res_reader, .{ .max_size = res_data.bytes.len }) catch |err| { // TODO: Better errors - try error_handler.emitMessage(allocator, .err, "unable to parse res from '{s}': {s}", .{ res_stream.name, @errorName(err) }); + try error_handler.emitMessage(gpa, .err, "unable to parse res from '{s}': {s}", .{ res_stream.name, @errorName(err) }); std.process.exit(1); }; }; defer resources.deinit(); var coff_stream = IoStream.fromIoSource(options.output_source, .output) catch |err| { - try error_handler.emitMessage(allocator, .err, "unable to create output file '{s}': {s}", .{ options.output_source.filename, @errorName(err) }); + try error_handler.emitMessage(gpa, .err, "unable to create output file '{s}': {s}", .{ options.output_source.filename, @errorName(err) }); std.process.exit(1); }; - defer coff_stream.deinit(allocator); + defer coff_stream.deinit(gpa); var coff_output_buffer: [4096]u8 = undefined; - var coff_output_buffered_stream = coff_stream.source.writer(allocator, &coff_output_buffer); + var coff_output_buffered_stream = coff_stream.source.writer(gpa, &coff_output_buffer); var cvtres_diagnostics: cvtres.Diagnostics = .{ .none = {} }; - cvtres.writeCoff(allocator, coff_output_buffered_stream.interface(), resources.list.items, options.coff_options, &cvtres_diagnostics) catch |err| { + cvtres.writeCoff(gpa, coff_output_buffered_stream.interface(), resources.list.items, options.coff_options, &cvtres_diagnostics) catch |err| { switch (err) { error.DuplicateResource => { const duplicate_resource = resources.list.items[cvtres_diagnostics.duplicate_resource]; - try error_handler.emitMessage(allocator, .err, "duplicate resource [id: {f}, type: {f}, language: {f}]", .{ + try error_handler.emitMessage(gpa, .err, "duplicate resource [id: {f}, type: {f}, language: {f}]", .{ duplicate_resource.name_value, fmtResourceType(duplicate_resource.type_value), duplicate_resource.language, @@ -374,8 +382,8 @@ pub fn main() !void { }, error.ResourceDataTooLong => { const overflow_resource = resources.list.items[cvtres_diagnostics.duplicate_resource]; - try error_handler.emitMessage(allocator, .err, "resource has a data length that is too large to be written into a coff section", .{}); - try error_handler.emitMessage(allocator, .note, "the resource with the invalid size is [id: {f}, type: {f}, language: {f}]", .{ + try error_handler.emitMessage(gpa, .err, "resource has a data length that is too large to be written into a coff section", .{}); + try error_handler.emitMessage(gpa, .note, "the resource with the invalid size is [id: {f}, type: {f}, language: {f}]", .{ overflow_resource.name_value, fmtResourceType(overflow_resource.type_value), overflow_resource.language, @@ -383,15 +391,15 @@ pub fn main() !void { }, error.TotalResourceDataTooLong => { const overflow_resource = resources.list.items[cvtres_diagnostics.duplicate_resource]; - try error_handler.emitMessage(allocator, .err, "total resource data exceeds the maximum of the coff 'size of raw data' field", .{}); - try error_handler.emitMessage(allocator, .note, "size overflow occurred when attempting to write this resource: [id: {f}, type: {f}, language: {f}]", .{ + try error_handler.emitMessage(gpa, .err, "total resource data exceeds the maximum of the coff 'size of raw data' field", .{}); + try error_handler.emitMessage(gpa, .note, "size overflow occurred when attempting to write this resource: [id: {f}, type: {f}, language: {f}]", .{ overflow_resource.name_value, fmtResourceType(overflow_resource.type_value), overflow_resource.language, }); }, else => { - try error_handler.emitMessage(allocator, .err, "unable to write coff output file '{s}': {s}", .{ coff_stream.name, @errorName(err) }); + try error_handler.emitMessage(gpa, .err, "unable to write coff output file '{s}': {s}", .{ coff_stream.name, @errorName(err) }); }, } // Delete the output file on error @@ -423,7 +431,7 @@ const IoStream = struct { }; } - pub fn deinit(self: *IoStream, allocator: std.mem.Allocator) void { + pub fn deinit(self: *IoStream, allocator: Allocator) void { self.source.deinit(allocator); } @@ -458,7 +466,7 @@ const IoStream = struct { } } - pub fn deinit(self: *Source, allocator: std.mem.Allocator) void { + pub fn deinit(self: *Source, allocator: Allocator) void { switch (self.*) { .file => |file| file.close(), .stdio => {}, @@ -471,18 +479,18 @@ const IoStream = struct { bytes: []const u8, needs_free: bool, - pub fn deinit(self: Data, allocator: std.mem.Allocator) void { + pub fn deinit(self: Data, allocator: Allocator) void { if (self.needs_free) { allocator.free(self.bytes); } } }; - pub fn readAll(self: Source, allocator: std.mem.Allocator) !Data { + pub fn readAll(self: Source, allocator: Allocator, io: Io) !Data { return switch (self) { inline .file, .stdio => |file| .{ .bytes = b: { - var file_reader = file.reader(&.{}); + var file_reader = file.reader(io, &.{}); break :b try file_reader.interface.allocRemaining(allocator, .unlimited); }, .needs_free = true, @@ -496,7 +504,7 @@ const IoStream = struct { file: std.fs.File.Writer, allocating: std.Io.Writer.Allocating, - pub const Error = std.mem.Allocator.Error || std.fs.File.WriteError; + pub const Error = Allocator.Error || std.fs.File.WriteError; pub fn interface(this: *@This()) *std.Io.Writer { return switch (this.*) { @@ -514,7 +522,7 @@ const IoStream = struct { } }; - pub fn writer(source: *Source, allocator: std.mem.Allocator, buffer: []u8) Writer { + pub fn writer(source: *Source, allocator: Allocator, buffer: []u8) Writer { return switch (source.*) { .file, .stdio => |file| .{ .file = file.writer(buffer) }, .memory => |*list| .{ .allocating = .fromArrayList(allocator, list) }, @@ -525,17 +533,20 @@ const IoStream = struct { }; const LazyIncludePaths = struct { - arena: std.mem.Allocator, + arena: Allocator, + io: Io, auto_includes_option: cli.Options.AutoIncludes, zig_lib_dir: []const u8, target_machine_type: std.coff.IMAGE.FILE.MACHINE, resolved_include_paths: ?[]const []const u8 = null, pub fn get(self: *LazyIncludePaths, error_handler: *ErrorHandler) ![]const []const u8 { + const io = self.io; + if (self.resolved_include_paths) |include_paths| return include_paths; - return getIncludePaths(self.arena, self.auto_includes_option, self.zig_lib_dir, self.target_machine_type) catch |err| switch (err) { + return getIncludePaths(self.arena, io, self.auto_includes_option, self.zig_lib_dir, self.target_machine_type) catch |err| switch (err) { error.OutOfMemory => |e| return e, else => |e| { switch (e) { @@ -556,7 +567,13 @@ const LazyIncludePaths = struct { } }; -fn getIncludePaths(arena: std.mem.Allocator, auto_includes_option: cli.Options.AutoIncludes, zig_lib_dir: []const u8, target_machine_type: std.coff.IMAGE.FILE.MACHINE) ![]const []const u8 { +fn getIncludePaths( + arena: Allocator, + io: Io, + auto_includes_option: cli.Options.AutoIncludes, + zig_lib_dir: []const u8, + target_machine_type: std.coff.IMAGE.FILE.MACHINE, +) ![]const []const u8 { if (auto_includes_option == .none) return &[_][]const u8{}; const includes_arch: std.Target.Cpu.Arch = switch (target_machine_type) { @@ -626,7 +643,7 @@ fn getIncludePaths(arena: std.mem.Allocator, auto_includes_option: cli.Options.A .cpu_arch = includes_arch, .abi = .gnu, }; - const target = std.zig.resolveTargetQueryOrFatal(target_query); + const target = std.zig.resolveTargetQueryOrFatal(io, target_query); const is_native_abi = target_query.isNativeAbi(); const detected_libc = std.zig.LibCDirs.detect(arena, zig_lib_dir, &target, is_native_abi, true, null) catch |err| switch (err) { error.OutOfMemory => |e| return e, @@ -647,7 +664,7 @@ const ErrorHandler = union(enum) { pub fn emitCliDiagnostics( self: *ErrorHandler, - allocator: std.mem.Allocator, + allocator: Allocator, args: []const []const u8, diagnostics: *cli.Diagnostics, ) !void { @@ -666,7 +683,7 @@ const ErrorHandler = union(enum) { pub fn emitAroDiagnostics( self: *ErrorHandler, - allocator: std.mem.Allocator, + allocator: Allocator, fail_msg: []const u8, comp: *aro.Compilation, ) !void { @@ -692,7 +709,7 @@ const ErrorHandler = union(enum) { pub fn emitDiagnostics( self: *ErrorHandler, - allocator: std.mem.Allocator, + allocator: Allocator, cwd: std.fs.Dir, source: []const u8, diagnostics: *Diagnostics, @@ -713,7 +730,7 @@ const ErrorHandler = union(enum) { pub fn emitMessage( self: *ErrorHandler, - allocator: std.mem.Allocator, + allocator: Allocator, msg_type: @import("utils.zig").ErrorMessageType, comptime format: []const u8, args: anytype, @@ -738,7 +755,7 @@ const ErrorHandler = union(enum) { }; fn cliDiagnosticsToErrorBundle( - gpa: std.mem.Allocator, + gpa: Allocator, diagnostics: *cli.Diagnostics, ) !ErrorBundle { @branchHint(.cold); @@ -783,7 +800,7 @@ fn cliDiagnosticsToErrorBundle( } fn diagnosticsToErrorBundle( - gpa: std.mem.Allocator, + gpa: Allocator, source: []const u8, diagnostics: *Diagnostics, mappings: SourceMappings, @@ -870,7 +887,7 @@ fn diagnosticsToErrorBundle( return try bundle.toOwnedBundle(""); } -fn errorStringToErrorBundle(allocator: std.mem.Allocator, comptime format: []const u8, args: anytype) !ErrorBundle { +fn errorStringToErrorBundle(allocator: Allocator, comptime format: []const u8, args: anytype) !ErrorBundle { @branchHint(.cold); var bundle: ErrorBundle.Wip = undefined; try bundle.init(allocator); diff --git a/lib/compiler/resinator/utils.zig b/lib/compiler/resinator/utils.zig index b535ab9c71..021b8cf4de 100644 --- a/lib/compiler/resinator/utils.zig +++ b/lib/compiler/resinator/utils.zig @@ -26,7 +26,11 @@ pub const UncheckedSliceWriter = struct { /// Cross-platform 'std.fs.Dir.openFile' wrapper that will always return IsDir if /// a directory is attempted to be opened. /// TODO: Remove once https://github.com/ziglang/zig/issues/5732 is addressed. -pub fn openFileNotDir(cwd: std.fs.Dir, path: []const u8, flags: std.fs.File.OpenFlags) std.fs.File.OpenError!std.fs.File { +pub fn openFileNotDir( + cwd: std.fs.Dir, + path: []const u8, + flags: std.fs.File.OpenFlags, +) (std.fs.File.OpenError || std.fs.File.StatError)!std.fs.File { const file = try cwd.openFile(path, flags); errdefer file.close(); // https://github.com/ziglang/zig/issues/5732