aboutsummaryrefslogtreecommitdiff
path: root/src/Compilation.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2024-03-11 17:18:09 -0700
committerGitHub <noreply@github.com>2024-03-11 17:18:09 -0700
commit0c61466771ff205a955f3e5002d2a7f2449ccc78 (patch)
tree2a837dc71cb3077c538dd1bcd01b22ef233489de /src/Compilation.zig
parentf60c24c73cc5c5894fbfb7060a70bc683c4a4ba5 (diff)
parent3f92cbef89e13c90e2c9f7051dbf5edef76fa90b (diff)
downloadzig-0c61466771ff205a955f3e5002d2a7f2449ccc78.tar.gz
zig-0c61466771ff205a955f3e5002d2a7f2449ccc78.zip
Merge pull request #19174 from squeek502/lazy-resinator
Lazily compile the `zig rc` subcommand and use it during `zig build-exe`, etc
Diffstat (limited to 'src/Compilation.zig')
-rw-r--r--src/Compilation.zig634
1 files changed, 182 insertions, 452 deletions
diff --git a/src/Compilation.zig b/src/Compilation.zig
index 0fdfb6038f..97b7e448db 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -36,7 +36,6 @@ const Cache = std.Build.Cache;
const c_codegen = @import("codegen/c.zig");
const libtsan = @import("libtsan.zig");
const Zir = std.zig.Zir;
-const resinator = @import("resinator.zig");
const Builtin = @import("Builtin.zig");
const LlvmObject = @import("codegen/llvm.zig").Object;
@@ -174,7 +173,7 @@ local_cache_directory: Directory,
global_cache_directory: Directory,
libc_include_dir_list: []const []const u8,
libc_framework_dir_list: []const []const u8,
-rc_include_dir_list: []const []const u8,
+rc_includes: RcIncludes,
thread_pool: *ThreadPool,
/// Populated when we build the libc++ static library. A Job to build this is placed in the queue
@@ -1243,68 +1242,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
options.libc_installation,
);
- // The include directories used when preprocessing .rc files are separate from the
- // target. Which include directories are used is determined by `options.rc_includes`.
- //
- // Note: It should be okay that the include directories used when compiling .rc
- // files differ from the include directories used when compiling the main
- // binary, since the .res format is not dependent on anything ABI-related. The
- // only relevant differences would be things like `#define` constants being
- // different in the MinGW headers vs the MSVC headers, but any such
- // differences would likely be a MinGW bug.
- const rc_dirs: std.zig.LibCDirs = b: {
- // Set the includes to .none here when there are no rc files to compile
- var includes = if (options.rc_source_files.len > 0) options.rc_includes else .none;
- const target = options.root_mod.resolved_target.result;
- if (!options.root_mod.resolved_target.is_native_os or target.os.tag != .windows) {
- switch (includes) {
- // MSVC can't be found when the host isn't Windows, so short-circuit.
- .msvc => return error.WindowsSdkNotFound,
- // Skip straight to gnu since we won't be able to detect
- // MSVC on non-Windows hosts.
- .any => includes = .gnu,
- .none, .gnu => {},
- }
- }
- while (true) switch (includes) {
- .any, .msvc => break :b std.zig.LibCDirs.detect(
- arena,
- options.zig_lib_directory.path.?,
- .{
- .cpu = target.cpu,
- .os = target.os,
- .abi = .msvc,
- .ofmt = target.ofmt,
- },
- options.root_mod.resolved_target.is_native_abi,
- // The .rc preprocessor will need to know the libc include dirs even if we
- // are not linking libc, so force 'link_libc' to true
- true,
- options.libc_installation,
- ) catch |err| {
- if (includes == .any) {
- // fall back to mingw
- includes = .gnu;
- continue;
- }
- return err;
- },
- .gnu => break :b try std.zig.LibCDirs.detectFromBuilding(arena, options.zig_lib_directory.path.?, .{
- .cpu = target.cpu,
- .os = target.os,
- .abi = .gnu,
- .ofmt = target.ofmt,
- }),
- .none => break :b .{
- .libc_include_dir_list = &[0][]u8{},
- .libc_installation = null,
- .libc_framework_dir_list = &.{},
- .sysroot = null,
- .darwin_sdk_layout = null,
- },
- };
- };
-
const sysroot = options.sysroot orelse libc_dirs.sysroot;
const include_compiler_rt = options.want_compiler_rt orelse
@@ -1492,7 +1429,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
.self_exe_path = options.self_exe_path,
.libc_include_dir_list = libc_dirs.libc_include_dir_list,
.libc_framework_dir_list = libc_dirs.libc_framework_dir_list,
- .rc_include_dir_list = rc_dirs.libc_include_dir_list,
+ .rc_includes = options.rc_includes,
.thread_pool = options.thread_pool,
.clang_passthrough_mode = options.clang_passthrough_mode,
.clang_preprocessor_mode = options.clang_preprocessor_mode,
@@ -2506,7 +2443,7 @@ fn addNonIncrementalStuffToCacheManifest(
man.hash.add(comp.link_eh_frame_hdr);
man.hash.add(comp.skip_linker_dependencies);
man.hash.add(comp.include_compiler_rt);
- man.hash.addListOfBytes(comp.rc_include_dir_list);
+ man.hash.add(comp.rc_includes);
man.hash.addListOfBytes(comp.force_undefined_symbols.keys());
man.hash.addListOfBytes(comp.framework_dirs);
try link.hashAddSystemLibs(man, comp.system_libs);
@@ -4172,7 +4109,7 @@ pub fn obtainCObjectCacheManifest(
pub fn obtainWin32ResourceCacheManifest(comp: *const Compilation) Cache.Manifest {
var man = comp.cache_parent.obtain();
- man.hash.addListOfBytes(comp.rc_include_dir_list);
+ man.hash.add(comp.rc_includes);
return man;
}
@@ -4812,11 +4749,12 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
}
fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32_resource_prog_node: *std.Progress.Node) !void {
- if (!build_options.have_llvm) {
- return comp.failWin32Resource(win32_resource, "clang not available: compiler built without LLVM extensions", .{});
+ if (!std.process.can_spawn) {
+ return comp.failWin32Resource(win32_resource, "{s} does not support spawning a child process", .{@tagName(builtin.os.tag)});
}
+
const self_exe_path = comp.self_exe_path orelse
- return comp.failWin32Resource(win32_resource, "clang compilation disabled", .{});
+ return comp.failWin32Resource(win32_resource, "unable to find self exe path", .{});
const tracy_trace = trace(@src());
defer tracy_trace.end();
@@ -4856,6 +4794,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
if (win32_resource.src == .manifest) {
_ = try man.addFile(src_path, null);
+ const rc_basename = try std.fmt.allocPrint(arena, "{s}.rc", .{src_basename});
const res_basename = try std.fmt.allocPrint(arena, "{s}.res", .{src_basename});
const digest = if (try man.hit()) man.final() else blk: {
@@ -4867,17 +4806,12 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});
defer o_dir.close();
- var output_file = o_dir.createFile(res_basename, .{}) catch |err| {
- const output_file_path = try comp.local_cache_directory.join(arena, &.{ o_sub_path, res_basename });
- return comp.failWin32Resource(win32_resource, "failed to create output file '{s}': {s}", .{ output_file_path, @errorName(err) });
- };
- var output_file_closed = false;
- defer if (!output_file_closed) output_file.close();
-
- var diagnostics = resinator.errors.Diagnostics.init(arena);
- defer diagnostics.deinit();
-
- var output_buffered_stream = std.io.bufferedWriter(output_file.writer());
+ const in_rc_path = try comp.local_cache_directory.join(comp.gpa, &.{
+ o_sub_path, rc_basename,
+ });
+ const out_res_path = try comp.local_cache_directory.join(comp.gpa, &.{
+ o_sub_path, res_basename,
+ });
// In .rc files, a " within a quoted string is escaped as ""
const fmtRcEscape = struct {
@@ -4899,28 +4833,24 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
// 1 is CREATEPROCESS_MANIFEST_RESOURCE_ID which is the default ID used for RT_MANIFEST resources
// 24 is RT_MANIFEST
const input = try std.fmt.allocPrint(arena, "1 24 \"{s}\"", .{fmtRcEscape(src_path)});
+ try o_dir.writeFile(rc_basename, input);
+
+ var argv = std.ArrayList([]const u8).init(comp.gpa);
+ defer argv.deinit();
+
+ try argv.appendSlice(&.{
+ self_exe_path,
+ "rc",
+ "--zig-integration",
+ "/:no-preprocess",
+ "/x", // ignore INCLUDE environment variable
+ "/c65001", // UTF-8 codepage
+ "/:auto-includes",
+ "none",
+ });
+ try argv.appendSlice(&.{ "--", in_rc_path, out_res_path });
- resinator.compile.compile(arena, input, output_buffered_stream.writer(), .{
- .cwd = std.fs.cwd(),
- .diagnostics = &diagnostics,
- .ignore_include_env_var = true,
- .default_code_page = .utf8,
- }) catch |err| switch (err) {
- error.ParseError, error.CompileError => {
- // Delete the output file on error
- output_file.close();
- output_file_closed = true;
- // Failing to delete is not really a big deal, so swallow any errors
- o_dir.deleteFile(res_basename) catch {
- const output_file_path = try comp.local_cache_directory.join(arena, &.{ o_sub_path, res_basename });
- log.warn("failed to delete '{s}': {s}", .{ output_file_path, @errorName(err) });
- };
- return comp.failWin32ResourceCompile(win32_resource, input, &diagnostics, null);
- },
- else => |e| return e,
- };
-
- try output_buffered_stream.flush();
+ try spawnZigRc(comp, win32_resource, src_basename, arena, argv.items, &child_progress_node);
break :blk digest;
};
@@ -4951,9 +4881,6 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
const rc_basename_noext = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];
const digest = if (try man.hit()) man.final() else blk: {
- const rcpp_filename = try std.fmt.allocPrint(arena, "{s}.rcpp", .{rc_basename_noext});
-
- const out_rcpp_path = try comp.tmpFilePath(arena, rcpp_filename);
var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{});
defer zig_cache_tmp_dir.close();
@@ -4963,193 +4890,66 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
// so we need a temporary filename.
const out_res_path = try comp.tmpFilePath(arena, res_filename);
- var options = options: {
- var resinator_args = try std.ArrayListUnmanaged([]const u8).initCapacity(comp.gpa, rc_src.extra_flags.len + 4);
- defer resinator_args.deinit(comp.gpa);
-
- resinator_args.appendAssumeCapacity(""); // dummy 'process name' arg
- resinator_args.appendSliceAssumeCapacity(rc_src.extra_flags);
- resinator_args.appendSliceAssumeCapacity(&.{ "--", out_rcpp_path, out_res_path });
-
- var cli_diagnostics = resinator.cli.Diagnostics.init(comp.gpa);
- defer cli_diagnostics.deinit();
- const options = resinator.cli.parse(comp.gpa, resinator_args.items, &cli_diagnostics) catch |err| switch (err) {
- error.ParseError => {
- return comp.failWin32ResourceCli(win32_resource, &cli_diagnostics);
- },
- else => |e| return e,
- };
- break :options options;
- };
- defer options.deinit();
-
- // We never want to read the INCLUDE environment variable, so
- // unconditionally set `ignore_include_env_var` to true
- options.ignore_include_env_var = true;
-
- if (options.preprocess != .yes) {
- return comp.failWin32Resource(win32_resource, "the '{s}' option is not supported in this context", .{switch (options.preprocess) {
- .no => "/:no-preprocess",
- .only => "/p",
- .yes => unreachable,
- }});
- }
-
var argv = std.ArrayList([]const u8).init(comp.gpa);
defer argv.deinit();
- try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang" });
-
- try resinator.preprocess.appendClangArgs(arena, &argv, options, .{
- .clang_target = null, // handled by addCCArgs
- .system_include_paths = &.{}, // handled by addCCArgs
- .needs_gnu_workaround = comp.getTarget().isGnu(),
- .nostdinc = false, // handled by addCCArgs
+ const depfile_filename = try std.fmt.allocPrint(arena, "{s}.d.json", .{rc_basename_noext});
+ const out_dep_path = try comp.tmpFilePath(arena, depfile_filename);
+ try argv.appendSlice(&.{
+ self_exe_path,
+ "rc",
+ "--zig-integration",
+ "/:depfile",
+ out_dep_path,
+ "/:depfile-fmt",
+ "json",
+ "/x", // ignore INCLUDE environment variable
+ "/:auto-includes",
+ @tagName(comp.rc_includes),
});
-
- try argv.append(rc_src.src_path);
- try argv.appendSlice(&[_][]const u8{
- "-o",
- out_rcpp_path,
- });
-
- const out_dep_path = try std.fmt.allocPrint(arena, "{s}.d", .{out_rcpp_path});
- // Note: addCCArgs will implicitly add _DEBUG/NDEBUG depending on the optimization
- // mode. While these defines are not normally present when calling rc.exe directly,
+ // While these defines are not normally present when calling rc.exe directly,
// them being defined matches the behavior of how MSVC calls rc.exe which is the more
// relevant behavior in this case.
- try comp.addCCArgs(arena, &argv, .rc, out_dep_path, rc_src.owner);
-
- if (comp.verbose_cc) {
- dump_argv(argv.items);
+ switch (rc_src.owner.optimize_mode) {
+ .Debug => try argv.append("-D_DEBUG"),
+ .ReleaseSafe => {},
+ .ReleaseFast, .ReleaseSmall => try argv.append("-DNDEBUG"),
}
+ try argv.appendSlice(rc_src.extra_flags);
+ try argv.appendSlice(&.{ "--", rc_src.src_path, out_res_path });
- if (std.process.can_spawn) {
- var child = std.ChildProcess.init(argv.items, arena);
- child.stdin_behavior = .Ignore;
- child.stdout_behavior = .Ignore;
- child.stderr_behavior = .Pipe;
-
- try child.spawn();
-
- const stderr_reader = child.stderr.?.reader();
-
- const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024);
-
- const term = child.wait() catch |err| {
- return comp.failWin32Resource(win32_resource, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
- };
+ try spawnZigRc(comp, win32_resource, src_basename, arena, argv.items, &child_progress_node);
- switch (term) {
- .Exited => |code| {
- if (code != 0) {
- // TODO parse clang stderr and turn it into an error message
- // and then call failCObjWithOwnedErrorMsg
- log.err("clang preprocessor failed with stderr:\n{s}", .{stderr});
- return comp.failWin32Resource(win32_resource, "clang preprocessor exited with code {d}", .{code});
- }
- },
- else => {
- log.err("clang preprocessor terminated with stderr:\n{s}", .{stderr});
- return comp.failWin32Resource(win32_resource, "clang preprocessor terminated unexpectedly", .{});
- },
- }
- } else {
- const exit_code = try clangMain(arena, argv.items);
- if (exit_code != 0) {
- return comp.failWin32Resource(win32_resource, "clang preprocessor exited with code {d}", .{exit_code});
- }
- }
-
- const dep_basename = std.fs.path.basename(out_dep_path);
- // Add the files depended on to the cache system.
- try man.addDepFilePost(zig_cache_tmp_dir, dep_basename);
- switch (comp.cache_use) {
- .whole => |whole| if (whole.cache_manifest) |whole_cache_manifest| {
- whole.cache_manifest_mutex.lock();
- defer whole.cache_manifest_mutex.unlock();
- try whole_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename);
- },
- .incremental => {},
- }
- // Just to save disk space, we delete the file because it is never needed again.
- zig_cache_tmp_dir.deleteFile(dep_basename) catch |err| {
- log.warn("failed to delete '{s}': {s}", .{ out_dep_path, @errorName(err) });
- };
-
- const full_input = std.fs.cwd().readFileAlloc(arena, out_rcpp_path, std.math.maxInt(usize)) catch |err| switch (err) {
- error.OutOfMemory => return error.OutOfMemory,
- else => |e| {
- return comp.failWin32Resource(win32_resource, "failed to read preprocessed file '{s}': {s}", .{ out_rcpp_path, @errorName(e) });
- },
- };
-
- var mapping_results = try resinator.source_mapping.parseAndRemoveLineCommands(arena, full_input, full_input, .{ .initial_filename = rc_src.src_path });
- defer mapping_results.mappings.deinit(arena);
-
- const final_input = resinator.comments.removeComments(mapping_results.result, mapping_results.result, &mapping_results.mappings);
-
- var output_file = zig_cache_tmp_dir.createFile(out_res_path, .{}) catch |err| {
- return comp.failWin32Resource(win32_resource, "failed to create output file '{s}': {s}", .{ out_res_path, @errorName(err) });
- };
- var output_file_closed = false;
- defer if (!output_file_closed) output_file.close();
-
- var diagnostics = resinator.errors.Diagnostics.init(arena);
- defer diagnostics.deinit();
+ // Read depfile and update cache manifest
+ {
+ const dep_basename = std.fs.path.basename(out_dep_path);
+ const dep_file_contents = try zig_cache_tmp_dir.readFileAlloc(arena, dep_basename, 50 * 1024 * 1024);
+ defer arena.free(dep_file_contents);
- var dependencies_list = std.ArrayList([]const u8).init(comp.gpa);
- defer {
- for (dependencies_list.items) |item| {
- comp.gpa.free(item);
+ const value = try std.json.parseFromSliceLeaky(std.json.Value, arena, dep_file_contents, .{});
+ if (value != .array) {
+ return comp.failWin32Resource(win32_resource, "depfile from zig rc has unexpected format", .{});
}
- dependencies_list.deinit();
- }
- var output_buffered_stream = std.io.bufferedWriter(output_file.writer());
-
- resinator.compile.compile(arena, final_input, output_buffered_stream.writer(), .{
- .cwd = std.fs.cwd(),
- .diagnostics = &diagnostics,
- .source_mappings = &mapping_results.mappings,
- .dependencies_list = &dependencies_list,
- .system_include_paths = comp.rc_include_dir_list,
- .ignore_include_env_var = true,
- // options
- .extra_include_paths = options.extra_include_paths.items,
- .default_language_id = options.default_language_id,
- .default_code_page = options.default_code_page orelse .windows1252,
- .verbose = options.verbose,
- .null_terminate_string_table_strings = options.null_terminate_string_table_strings,
- .max_string_literal_codepoints = options.max_string_literal_codepoints,
- .silent_duplicate_control_ids = options.silent_duplicate_control_ids,
- .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 => {
- // Delete the output file on error
- output_file.close();
- output_file_closed = true;
- // Failing to delete is not really a big deal, so swallow any errors
- zig_cache_tmp_dir.deleteFile(out_res_path) catch {
- log.warn("failed to delete '{s}': {s}", .{ out_res_path, @errorName(err) });
- };
- return comp.failWin32ResourceCompile(win32_resource, final_input, &diagnostics, mapping_results.mappings);
- },
- else => |e| return e,
- };
-
- try output_buffered_stream.flush();
-
- for (dependencies_list.items) |dep_file_path| {
- try man.addFilePost(dep_file_path);
- switch (comp.cache_use) {
- .whole => |whole| if (whole.cache_manifest) |whole_cache_manifest| {
- whole.cache_manifest_mutex.lock();
- defer whole.cache_manifest_mutex.unlock();
- try whole_cache_manifest.addFilePost(dep_file_path);
- },
- .incremental => {},
+ for (value.array.items) |element| {
+ if (element != .string) {
+ return comp.failWin32Resource(win32_resource, "depfile from zig rc has unexpected format", .{});
+ }
+ const dep_file_path = element.string;
+ try man.addFilePost(dep_file_path);
+ switch (comp.cache_use) {
+ .whole => |whole| if (whole.cache_manifest) |whole_cache_manifest| {
+ whole.cache_manifest_mutex.lock();
+ defer whole.cache_manifest_mutex.unlock();
+ try whole_cache_manifest.addFilePost(dep_file_path);
+ },
+ .incremental => {},
+ }
}
+ // Just to save disk space, we delete the file because it is never needed again.
+ zig_cache_tmp_dir.deleteFile(dep_basename) catch |err| {
+ log.warn("failed to delete '{s}': {s}", .{ out_dep_path, @errorName(err) });
+ };
}
// Rename into place.
@@ -5159,8 +4959,6 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
defer o_dir.close();
const tmp_basename = std.fs.path.basename(out_res_path);
try std.fs.rename(zig_cache_tmp_dir, tmp_basename, o_dir, res_filename);
- const tmp_rcpp_basename = std.fs.path.basename(out_rcpp_path);
- try std.fs.rename(zig_cache_tmp_dir, tmp_rcpp_basename, o_dir, rcpp_filename);
break :blk digest;
};
@@ -5186,6 +4984,106 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
};
}
+fn spawnZigRc(
+ comp: *Compilation,
+ win32_resource: *Win32Resource,
+ src_basename: []const u8,
+ arena: Allocator,
+ argv: []const []const u8,
+ child_progress_node: *std.Progress.Node,
+) !void {
+ var node_name: std.ArrayListUnmanaged(u8) = .{};
+ defer node_name.deinit(arena);
+
+ var child = std.ChildProcess.init(argv, arena);
+ child.stdin_behavior = .Ignore;
+ child.stdout_behavior = .Pipe;
+ child.stderr_behavior = .Pipe;
+
+ child.spawn() catch |err| {
+ return comp.failWin32Resource(win32_resource, "unable to spawn {s} rc: {s}", .{ argv[0], @errorName(err) });
+ };
+
+ var poller = std.io.poll(comp.gpa, enum { stdout }, .{
+ .stdout = child.stdout.?,
+ });
+ defer poller.deinit();
+
+ const stdout = poller.fifo(.stdout);
+
+ poll: while (true) {
+ while (stdout.readableLength() < @sizeOf(std.zig.Server.Message.Header)) {
+ if (!(try poller.poll())) break :poll;
+ }
+ const header = stdout.reader().readStruct(std.zig.Server.Message.Header) catch unreachable;
+ while (stdout.readableLength() < header.bytes_len) {
+ if (!(try poller.poll())) break :poll;
+ }
+ const body = stdout.readableSliceOfLen(header.bytes_len);
+
+ switch (header.tag) {
+ // We expect exactly one ErrorBundle, and if any error_bundle header is
+ // sent then it's a fatal error.
+ .error_bundle => {
+ const EbHdr = std.zig.Server.Message.ErrorBundle;
+ const eb_hdr = @as(*align(1) const EbHdr, @ptrCast(body));
+ const extra_bytes =
+ body[@sizeOf(EbHdr)..][0 .. @sizeOf(u32) * eb_hdr.extra_len];
+ const string_bytes =
+ body[@sizeOf(EbHdr) + extra_bytes.len ..][0..eb_hdr.string_bytes_len];
+ const unaligned_extra = std.mem.bytesAsSlice(u32, extra_bytes);
+ const extra_array = try comp.gpa.alloc(u32, unaligned_extra.len);
+ @memcpy(extra_array, unaligned_extra);
+ const error_bundle = std.zig.ErrorBundle{
+ .string_bytes = try comp.gpa.dupe(u8, string_bytes),
+ .extra = extra_array,
+ };
+ return comp.failWin32ResourceWithOwnedBundle(win32_resource, error_bundle);
+ },
+ .progress => {
+ node_name.clearRetainingCapacity();
+ // <resinator> is a special string that indicates that the child
+ // process has reached resinator's main function
+ if (std.mem.eql(u8, body, "<resinator>")) {
+ child_progress_node.setName(src_basename);
+ }
+ // Ignore 0-length strings since if multiple zig rc commands
+ // are executed at the same time, only one will send progress strings
+ // while the other(s) will send empty strings.
+ else if (body.len > 0) {
+ try node_name.appendSlice(arena, "build 'zig rc'... ");
+ try node_name.appendSlice(arena, body);
+ child_progress_node.setName(node_name.items);
+ }
+ },
+ else => {}, // ignore other messages
+ }
+
+ stdout.discard(body.len);
+ }
+
+ // Just in case there's a failure that didn't send an ErrorBundle (e.g. an error return trace)
+ const stderr_reader = child.stderr.?.reader();
+ const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024);
+
+ const term = child.wait() catch |err| {
+ return comp.failWin32Resource(win32_resource, "unable to wait for {s} rc: {s}", .{ argv[0], @errorName(err) });
+ };
+
+ switch (term) {
+ .Exited => |code| {
+ if (code != 0) {
+ log.err("zig rc failed with stderr:\n{s}", .{stderr});
+ return comp.failWin32Resource(win32_resource, "zig rc exited with code {d}", .{code});
+ }
+ },
+ else => {
+ log.err("zig rc terminated with stderr:\n{s}", .{stderr});
+ return comp.failWin32Resource(win32_resource, "zig rc terminated unexpectedly", .{});
+ },
+ }
+}
+
pub fn tmpFilePath(comp: *Compilation, ally: Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 {
const s = std.fs.path.sep_str;
const rand_int = std.crypto.random.int(u64);
@@ -5352,16 +5250,9 @@ pub fn addCCArgs(
try argv.append("-isystem");
try argv.append(c_headers_dir);
- if (ext == .rc) {
- for (comp.rc_include_dir_list) |include_dir| {
- try argv.append("-isystem");
- try argv.append(include_dir);
- }
- } else {
- for (comp.libc_include_dir_list) |include_dir| {
- try argv.append("-isystem");
- try argv.append(include_dir);
- }
+ for (comp.libc_include_dir_list) |include_dir| {
+ try argv.append("-isystem");
+ try argv.append(include_dir);
}
if (target.cpu.model.llvm_name) |llvm_name| {
@@ -5726,167 +5617,6 @@ fn failWin32ResourceWithOwnedBundle(
return error.AnalysisFail;
}
-fn failWin32ResourceCli(
- comp: *Compilation,
- win32_resource: *Win32Resource,
- diagnostics: *resinator.cli.Diagnostics,
-) SemaError {
- @setCold(true);
-
- var bundle: ErrorBundle.Wip = undefined;
- try bundle.init(comp.gpa);
- errdefer bundle.deinit();
-
- try bundle.addRootErrorMessage(.{
- .msg = try bundle.addString("invalid command line option(s)"),
- .src_loc = try bundle.addSourceLocation(.{
- .src_path = try bundle.addString(switch (win32_resource.src) {
- .rc => |rc_src| rc_src.src_path,
- .manifest => |manifest_src| manifest_src,
- }),
- .line = 0,
- .column = 0,
- .span_start = 0,
- .span_main = 0,
- .span_end = 0,
- }),
- });
-
- var cur_err: ?ErrorBundle.ErrorMessage = null;
- var cur_notes: std.ArrayListUnmanaged(ErrorBundle.ErrorMessage) = .{};
- defer cur_notes.deinit(comp.gpa);
- for (diagnostics.errors.items) |err_details| {
- switch (err_details.type) {
- .err => {
- if (cur_err) |err| {
- try win32ResourceFlushErrorMessage(&bundle, err, cur_notes.items);
- }
- cur_err = .{
- .msg = try bundle.addString(err_details.msg.items),
- };
- cur_notes.clearRetainingCapacity();
- },
- .warning => cur_err = null,
- .note => {
- if (cur_err == null) continue;
- cur_err.?.notes_len += 1;
- try cur_notes.append(comp.gpa, .{
- .msg = try bundle.addString(err_details.msg.items),
- });
- },
- }
- }
- if (cur_err) |err| {
- try win32ResourceFlushErrorMessage(&bundle, err, cur_notes.items);
- }
-
- const finished_bundle = try bundle.toOwnedBundle("");
- return comp.failWin32ResourceWithOwnedBundle(win32_resource, finished_bundle);
-}
-
-fn failWin32ResourceCompile(
- comp: *Compilation,
- win32_resource: *Win32Resource,
- source: []const u8,
- diagnostics: *resinator.errors.Diagnostics,
- opt_mappings: ?resinator.source_mapping.SourceMappings,
-) SemaError {
- @setCold(true);
-
- var bundle: ErrorBundle.Wip = undefined;
- try bundle.init(comp.gpa);
- errdefer bundle.deinit();
-
- var msg_buf: std.ArrayListUnmanaged(u8) = .{};
- defer msg_buf.deinit(comp.gpa);
- var cur_err: ?ErrorBundle.ErrorMessage = null;
- var cur_notes: std.ArrayListUnmanaged(ErrorBundle.ErrorMessage) = .{};
- defer cur_notes.deinit(comp.gpa);
- for (diagnostics.errors.items) |err_details| {
- switch (err_details.type) {
- .hint => continue,
- // Clear the current error so that notes don't bleed into unassociated errors
- .warning => {
- cur_err = null;
- continue;
- },
- .note => if (cur_err == null) continue,
- .err => {},
- }
- const err_line, const err_filename = blk: {
- if (opt_mappings) |mappings| {
- const corresponding_span = mappings.get(err_details.token.line_number);
- const corresponding_file = mappings.files.get(corresponding_span.filename_offset);
- const err_line = corresponding_span.start_line;
- break :blk .{ err_line, corresponding_file };
- } else {
- break :blk .{ err_details.token.line_number, "<generated rc>" };
- }
- };
-
- const source_line_start = err_details.token.getLineStart(source);
- const column = err_details.token.calculateColumn(source, 1, source_line_start);
-
- msg_buf.clearRetainingCapacity();
- try err_details.render(msg_buf.writer(comp.gpa), source, diagnostics.strings.items);
-
- const src_loc = src_loc: {
- var src_loc: ErrorBundle.SourceLocation = .{
- .src_path = try bundle.addString(err_filename),
- .line = @intCast(err_line - 1), // 1-based -> 0-based
- .column = @intCast(column),
- .span_start = 0,
- .span_main = 0,
- .span_end = 0,
- };
- if (err_details.print_source_line) {
- const source_line = err_details.token.getLine(source, source_line_start);
- const visual_info = err_details.visualTokenInfo(source_line_start, source_line_start + source_line.len);
- src_loc.span_start = @intCast(visual_info.point_offset - visual_info.before_len);
- src_loc.span_main = @intCast(visual_info.point_offset);
- src_loc.span_end = @intCast(visual_info.point_offset + 1 + visual_info.after_len);
- src_loc.source_line = try bundle.addString(source_line);
- }
- break :src_loc try bundle.addSourceLocation(src_loc);
- };
-
- switch (err_details.type) {
- .err => {
- if (cur_err) |err| {
- try win32ResourceFlushErrorMessage(&bundle, err, cur_notes.items);
- }
- cur_err = .{
- .msg = try bundle.addString(msg_buf.items),
- .src_loc = src_loc,
- };
- cur_notes.clearRetainingCapacity();
- },
- .note => {
- cur_err.?.notes_len += 1;
- try cur_notes.append(comp.gpa, .{
- .msg = try bundle.addString(msg_buf.items),
- .src_loc = src_loc,
- });
- },
- .warning, .hint => unreachable,
- }
- }
- if (cur_err) |err| {
- try win32ResourceFlushErrorMessage(&bundle, err, cur_notes.items);
- }
-
- const finished_bundle = try bundle.toOwnedBundle("");
- return comp.failWin32ResourceWithOwnedBundle(win32_resource, finished_bundle);
-}
-
-fn win32ResourceFlushErrorMessage(wip: *ErrorBundle.Wip, msg: ErrorBundle.ErrorMessage, notes: []const ErrorBundle.ErrorMessage) !void {
- try wip.addRootErrorMessage(msg);
- const notes_start = try wip.reserveNotes(@intCast(notes.len));
- for (notes_start.., notes) |i, note| {
- wip.extra.items[i] = @intFromEnum(wip.addErrorMessageAssumeCapacity(note));
- }
-}
-
pub const FileExt = enum {
c,
cpp,