diff options
| author | Ryan Liptak <squeek502@hotmail.com> | 2024-03-02 00:50:53 -0800 |
|---|---|---|
| committer | Ryan Liptak <squeek502@hotmail.com> | 2024-03-11 05:06:16 -0700 |
| commit | 52de2802c457140f3d9923cf014b51bb8c16689f (patch) | |
| tree | ed2accf0d3b85155e01ea7063792f28ec3d7184b /src/main.zig | |
| parent | d0c06ca7127110a8afeb0ef524a197049892db21 (diff) | |
| download | zig-52de2802c457140f3d9923cf014b51bb8c16689f.tar.gz zig-52de2802c457140f3d9923cf014b51bb8c16689f.zip | |
Lazily compile the `zig rc` subcommand and use it during `zig build-exe`
This moves .rc/.manifest compilation out of the main Zig binary, contributing towards #19063
Also:
- Make resinator use Aro as its preprocessor instead of clang
- Sync resinator with upstream
Diffstat (limited to 'src/main.zig')
| -rw-r--r-- | src/main.zig | 277 |
1 files changed, 6 insertions, 271 deletions
diff --git a/src/main.zig b/src/main.zig index 5a187c65e9..a11bf4b808 100644 --- a/src/main.zig +++ b/src/main.zig @@ -291,7 +291,12 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { } else if (mem.eql(u8, cmd, "translate-c")) { return buildOutputType(gpa, arena, args, .translate_c); } else if (mem.eql(u8, cmd, "rc")) { - return cmdRc(gpa, arena, args[1..]); + return jitCmd(gpa, arena, cmd_args, .{ + .cmd_name = "resinator", + .root_src_path = "resinator/main.zig", + .depend_on_aro = true, + .prepend_zig_lib_dir_path = true, + }); } else if (mem.eql(u8, cmd, "fmt")) { return jitCmd(gpa, arena, cmd_args, .{ .cmd_name = "fmt", @@ -4625,276 +4630,6 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati } } -fn cmdRc(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { - const resinator = @import("resinator.zig"); - - const stderr = std.io.getStdErr(); - const stderr_config = std.io.tty.detectConfig(stderr); - - var options = options: { - var cli_diagnostics = resinator.cli.Diagnostics.init(gpa); - defer cli_diagnostics.deinit(); - var options = resinator.cli.parse(gpa, args, &cli_diagnostics) catch |err| switch (err) { - error.ParseError => { - cli_diagnostics.renderToStdErr(args, stderr_config); - process.exit(1); - }, - else => |e| return e, - }; - try options.maybeAppendRC(std.fs.cwd()); - - // print any warnings/notes - cli_diagnostics.renderToStdErr(args, stderr_config); - // If there was something printed, then add an extra newline separator - // so that there is a clear separation between the cli diagnostics and whatever - // gets printed after - if (cli_diagnostics.errors.items.len > 0) { - std.debug.print("\n", .{}); - } - break :options options; - }; - defer options.deinit(); - - if (options.print_help_and_exit) { - try resinator.cli.writeUsage(stderr.writer(), "zig rc"); - return; - } - - const stdout_writer = std.io.getStdOut().writer(); - if (options.verbose) { - try options.dumpVerbose(stdout_writer); - try stdout_writer.writeByte('\n'); - } - - const full_input = full_input: { - if (options.preprocess != .no) { - if (!build_options.have_llvm) { - fatal("clang not available: compiler built without LLVM extensions", .{}); - } - - var argv = std.ArrayList([]const u8).init(gpa); - defer argv.deinit(); - - const self_exe_path = try introspect.findZigExePath(arena); - var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| { - try resinator.utils.renderErrorMessage(stderr.writer(), stderr_config, .err, "unable to find zig installation directory: {s}", .{@errorName(err)}); - process.exit(1); - }; - defer zig_lib_directory.handle.close(); - - const include_args = detectRcIncludeDirs(arena, zig_lib_directory.path.?, options.auto_includes) catch |err| { - try resinator.utils.renderErrorMessage(stderr.writer(), stderr_config, .err, "unable to detect system include directories: {s}", .{@errorName(err)}); - process.exit(1); - }; - - try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang" }); - - const clang_target = clang_target: { - if (include_args.target_abi) |abi| { - break :clang_target try std.fmt.allocPrint(arena, "x86_64-unknown-windows-{s}", .{abi}); - } - break :clang_target "x86_64-unknown-windows"; - }; - try resinator.preprocess.appendClangArgs(arena, &argv, options, .{ - .clang_target = clang_target, - .system_include_paths = include_args.include_paths, - .needs_gnu_workaround = if (include_args.target_abi) |abi| std.mem.eql(u8, abi, "gnu") else false, - .nostdinc = true, - }); - - try argv.append(options.input_filename); - - if (options.verbose) { - try stdout_writer.writeAll("Preprocessor: zig clang\n"); - for (argv.items[0 .. argv.items.len - 1]) |arg| { - try stdout_writer.print("{s} ", .{arg}); - } - try stdout_writer.print("{s}\n\n", .{argv.items[argv.items.len - 1]}); - } - - if (process.can_spawn) { - const result = std.ChildProcess.run(.{ - .allocator = gpa, - .argv = argv.items, - .max_output_bytes = std.math.maxInt(u32), - }) catch |err| { - try resinator.utils.renderErrorMessage(stderr.writer(), stderr_config, .err, "unable to spawn preprocessor child process: {s}", .{@errorName(err)}); - process.exit(1); - }; - errdefer gpa.free(result.stdout); - defer gpa.free(result.stderr); - - switch (result.term) { - .Exited => |code| { - if (code != 0) { - try resinator.utils.renderErrorMessage(stderr.writer(), stderr_config, .err, "the preprocessor failed with exit code {}:", .{code}); - try stderr.writeAll(result.stderr); - try stderr.writeAll("\n"); - process.exit(1); - } - }, - .Signal, .Stopped, .Unknown => { - try resinator.utils.renderErrorMessage(stderr.writer(), stderr_config, .err, "the preprocessor terminated unexpectedly ({s}):", .{@tagName(result.term)}); - try stderr.writeAll(result.stderr); - try stderr.writeAll("\n"); - process.exit(1); - }, - } - - break :full_input result.stdout; - } else { - // need to use an intermediate file - const rand_int = std.crypto.random.int(u64); - const preprocessed_path = try std.fmt.allocPrint(gpa, "resinator{x}.rcpp", .{rand_int}); - defer gpa.free(preprocessed_path); - defer std.fs.cwd().deleteFile(preprocessed_path) catch {}; - - try argv.appendSlice(&.{ "-o", preprocessed_path }); - const exit_code = try clangMain(arena, argv.items); - if (exit_code != 0) { - try resinator.utils.renderErrorMessage(stderr.writer(), stderr_config, .err, "the preprocessor failed with exit code {}:", .{exit_code}); - process.exit(1); - } - break :full_input std.fs.cwd().readFileAlloc(gpa, preprocessed_path, std.math.maxInt(usize)) catch |err| { - try resinator.utils.renderErrorMessage(stderr.writer(), stderr_config, .err, "unable to read preprocessed file path '{s}': {s}", .{ preprocessed_path, @errorName(err) }); - process.exit(1); - }; - } - } else { - break :full_input std.fs.cwd().readFileAlloc(gpa, options.input_filename, std.math.maxInt(usize)) catch |err| { - try resinator.utils.renderErrorMessage(stderr.writer(), stderr_config, .err, "unable to read input file path '{s}': {s}", .{ options.input_filename, @errorName(err) }); - process.exit(1); - }; - } - }; - defer gpa.free(full_input); - - if (options.preprocess == .only) { - std.fs.cwd().writeFile(options.output_filename, full_input) catch |err| { - try resinator.utils.renderErrorMessage(stderr.writer(), stderr_config, .err, "unable to write output file '{s}': {s}", .{ options.output_filename, @errorName(err) }); - process.exit(1); - }; - return cleanExit(); - } - - var mapping_results = try resinator.source_mapping.parseAndRemoveLineCommands(gpa, full_input, full_input, .{ .initial_filename = options.input_filename }); - defer mapping_results.mappings.deinit(gpa); - - const final_input = resinator.comments.removeComments(mapping_results.result, mapping_results.result, &mapping_results.mappings); - - var output_file = std.fs.cwd().createFile(options.output_filename, .{}) catch |err| { - try resinator.utils.renderErrorMessage(stderr.writer(), stderr_config, .err, "unable to create output file '{s}': {s}", .{ options.output_filename, @errorName(err) }); - process.exit(1); - }; - var output_file_closed = false; - defer if (!output_file_closed) output_file.close(); - - var diagnostics = resinator.errors.Diagnostics.init(gpa); - defer diagnostics.deinit(); - - var output_buffered_stream = std.io.bufferedWriter(output_file.writer()); - - resinator.compile.compile(gpa, final_input, output_buffered_stream.writer(), .{ - .cwd = std.fs.cwd(), - .diagnostics = &diagnostics, - .source_mappings = &mapping_results.mappings, - .dependencies_list = null, - .ignore_include_env_var = options.ignore_include_env_var, - .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 => { - diagnostics.renderToStdErr(std.fs.cwd(), final_input, stderr_config, mapping_results.mappings); - // 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 - std.fs.cwd().deleteFile(options.output_filename) catch {}; - process.exit(1); - }, - else => |e| return e, - }; - - try output_buffered_stream.flush(); - - // print any warnings/notes - diagnostics.renderToStdErr(std.fs.cwd(), final_input, stderr_config, mapping_results.mappings); - - return cleanExit(); -} - -const RcIncludeArgs = struct { - include_paths: []const []const u8 = &.{}, - target_abi: ?[]const u8 = null, -}; - -fn detectRcIncludeDirs(arena: Allocator, zig_lib_dir: []const u8, auto_includes: @import("resinator.zig").cli.Options.AutoIncludes) !RcIncludeArgs { - if (auto_includes == .none) return .{}; - var cur_includes = auto_includes; - if (builtin.target.os.tag != .windows) { - switch (cur_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 => cur_includes = .gnu, - .gnu => {}, - .none => unreachable, - } - } - while (true) { - switch (cur_includes) { - .any, .msvc => { - const target_query: std.Target.Query = .{ - .os_tag = .windows, - .abi = .msvc, - }; - const target = std.zig.resolveTargetQueryOrFatal(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| { - if (cur_includes == .any) { - // fall back to mingw - cur_includes = .gnu; - continue; - } - return err; - }; - if (detected_libc.libc_include_dir_list.len == 0) { - if (cur_includes == .any) { - // fall back to mingw - cur_includes = .gnu; - continue; - } - return error.WindowsSdkNotFound; - } - return .{ - .include_paths = detected_libc.libc_include_dir_list, - .target_abi = "msvc", - }; - }, - .gnu => { - const target_query: std.Target.Query = .{ - .os_tag = .windows, - .abi = .gnu, - }; - const target = std.zig.resolveTargetQueryOrFatal(target_query); - const is_native_abi = target_query.isNativeAbi(); - const detected_libc = try std.zig.LibCDirs.detect(arena, zig_lib_dir, target, is_native_abi, true, null); - return .{ - .include_paths = detected_libc.libc_include_dir_list, - .target_abi = "gnu", - }; - }, - .none => unreachable, - } - } -} - const usage_init = \\Usage: zig init \\ |
