aboutsummaryrefslogtreecommitdiff
path: root/src/main.zig
diff options
context:
space:
mode:
authorRyan Liptak <squeek502@hotmail.com>2024-03-02 00:50:53 -0800
committerRyan Liptak <squeek502@hotmail.com>2024-03-11 05:06:16 -0700
commit52de2802c457140f3d9923cf014b51bb8c16689f (patch)
treeed2accf0d3b85155e01ea7063792f28ec3d7184b /src/main.zig
parentd0c06ca7127110a8afeb0ef524a197049892db21 (diff)
downloadzig-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.zig277
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
\\