diff --git a/src/libc_installation.zig b/src/libc_installation.zig index c011abbfcc..62174930f8 100644 --- a/src/libc_installation.zig +++ b/src/libc_installation.zig @@ -41,6 +41,7 @@ pub const LibCInstallation = struct { pub fn parse( allocator: *Allocator, libc_file: []const u8, + target: std.zig.CrossTarget, ) !LibCInstallation { var self: LibCInstallation = .{}; @@ -96,26 +97,31 @@ pub const LibCInstallation = struct { log.err("sys_include_dir may not be empty\n", .{}); return error.ParseError; } - if (self.crt_dir == null and !is_darwin) { - log.err("crt_dir may not be empty for {s}\n", .{@tagName(Target.current.os.tag)}); + + const os_tag = target.getOsTag(); + if (self.crt_dir == null and !target.isDarwin()) { + log.err("crt_dir may not be empty for {s}\n", .{@tagName(os_tag)}); return error.ParseError; } - if (self.msvc_lib_dir == null and is_windows) { + + const abi = target.getAbi(); + if (self.msvc_lib_dir == null and target.isWindows() and abi == .msvc) { log.err("msvc_lib_dir may not be empty for {s}-{s}\n", .{ - @tagName(Target.current.os.tag), - @tagName(Target.current.abi), + @tagName(os_tag), + @tagName(abi), }); return error.ParseError; } - if (self.kernel32_lib_dir == null and is_windows) { + if (self.kernel32_lib_dir == null and target.isWindows() and abi == .msvc) { log.err("kernel32_lib_dir may not be empty for {s}-{s}\n", .{ - @tagName(Target.current.os.tag), - @tagName(Target.current.abi), + @tagName(os_tag), + @tagName(abi), }); return error.ParseError; } - if (self.gcc_dir == null and is_haiku) { - log.err("gcc_dir may not be empty for {s}\n", .{@tagName(Target.current.os.tag)}); + + if (self.gcc_dir == null and os_tag == .haiku) { + log.err("gcc_dir may not be empty for {s}\n", .{@tagName(os_tag)}); return error.ParseError; } diff --git a/src/main.zig b/src/main.zig index 8b5fbba90d..6a76c9507f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1593,39 +1593,11 @@ fn buildOutputType( } }; - var diags: std.zig.CrossTarget.ParseOptions.Diagnostics = .{}; - const cross_target = std.zig.CrossTarget.parse(.{ + const cross_target = try parseCrossTargetOrReportFatalError(arena, .{ .arch_os_abi = target_arch_os_abi, .cpu_features = target_mcpu, .dynamic_linker = target_dynamic_linker, - .diagnostics = &diags, - }) catch |err| switch (err) { - error.UnknownCpuModel => { - help: { - var help_text = std.ArrayList(u8).init(arena); - for (diags.arch.?.allCpuModels()) |cpu| { - help_text.writer().print(" {s}\n", .{cpu.name}) catch break :help; - } - std.log.info("Available CPUs for architecture '{s}':\n{s}", .{ - @tagName(diags.arch.?), help_text.items, - }); - } - fatal("Unknown CPU: '{s}'", .{diags.cpu_name.?}); - }, - error.UnknownCpuFeature => { - help: { - var help_text = std.ArrayList(u8).init(arena); - for (diags.arch.?.allFeaturesList()) |feature| { - help_text.writer().print(" {s}: {s}\n", .{ feature.name, feature.description }) catch break :help; - } - std.log.info("Available CPU features for architecture '{s}':\n{s}", .{ - @tagName(diags.arch.?), help_text.items, - }); - } - fatal("Unknown CPU feature: '{s}'", .{diags.unknown_feature_name}); - }, - else => |e| return e, - }; + }); const target_info = try detectNativeTargetInfo(gpa, cross_target); @@ -1972,7 +1944,7 @@ fn buildOutputType( defer if (libc_installation) |*l| l.deinit(gpa); if (libc_paths_file) |paths_file| { - libc_installation = LibCInstallation.parse(gpa, paths_file) catch |err| { + libc_installation = LibCInstallation.parse(gpa, paths_file, cross_target) catch |err| { fatal("unable to parse libc paths file at path {s}: {s}", .{ paths_file, @errorName(err) }); }; } @@ -2289,6 +2261,43 @@ fn buildOutputType( return cleanExit(); } +fn parseCrossTargetOrReportFatalError(allocator: *Allocator, opts: std.zig.CrossTarget.ParseOptions) !std.zig.CrossTarget { + var opts_with_diags = opts; + var diags: std.zig.CrossTarget.ParseOptions.Diagnostics = .{}; + if (opts_with_diags.diagnostics == null) { + opts_with_diags.diagnostics = &diags; + } + return std.zig.CrossTarget.parse(opts_with_diags) catch |err| switch (err) { + error.UnknownCpuModel => { + help: { + var help_text = std.ArrayList(u8).init(allocator); + defer help_text.deinit(); + for (diags.arch.?.allCpuModels()) |cpu| { + help_text.writer().print(" {s}\n", .{cpu.name}) catch break :help; + } + std.log.info("Available CPUs for architecture '{s}':\n{s}", .{ + @tagName(diags.arch.?), help_text.items, + }); + } + fatal("Unknown CPU: '{s}'", .{diags.cpu_name.?}); + }, + error.UnknownCpuFeature => { + help: { + var help_text = std.ArrayList(u8).init(allocator); + defer help_text.deinit(); + for (diags.arch.?.allFeaturesList()) |feature| { + help_text.writer().print(" {s}: {s}\n", .{ feature.name, feature.description }) catch break :help; + } + std.log.info("Available CPU features for architecture '{s}':\n{s}", .{ + @tagName(diags.arch.?), help_text.items, + }); + } + fatal("Unknown CPU feature: '{s}'", .{diags.unknown_feature_name}); + }, + else => |e| return e, + }; +} + fn runOrTest( comp: *Compilation, gpa: *Allocator, @@ -2630,10 +2639,15 @@ pub const usage_libc = \\ \\ Parse a libc installation text file and validate it. \\ + \\Options: + \\ -h, --help Print this help and exit + \\ -target [name] -- see the targets command + \\ ; pub fn cmdLibC(gpa: *Allocator, args: []const []const u8) !void { var input_file: ?[]const u8 = null; + var target_arch_os_abi: []const u8 = "native"; { var i: usize = 0; while (i < args.len) : (i += 1) { @@ -2643,6 +2657,10 @@ pub fn cmdLibC(gpa: *Allocator, args: []const []const u8) !void { const stdout = io.getStdOut().writer(); try stdout.writeAll(usage_libc); return cleanExit(); + } else if (mem.eql(u8, arg, "-target")) { + if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); + i += 1; + target_arch_os_abi = args[i]; } else { fatal("unrecognized parameter: '{s}'", .{arg}); } @@ -2653,12 +2671,21 @@ pub fn cmdLibC(gpa: *Allocator, args: []const []const u8) !void { } } } + + const cross_target = try parseCrossTargetOrReportFatalError(gpa, .{ + .arch_os_abi = target_arch_os_abi, + }); + if (input_file) |libc_file| { - var libc = LibCInstallation.parse(gpa, libc_file) catch |err| { + var libc = LibCInstallation.parse(gpa, libc_file, cross_target) catch |err| { fatal("unable to parse libc file at path {s}: {s}", .{ libc_file, @errorName(err) }); }; defer libc.deinit(gpa); } else { + if (!cross_target.isNative()) { + fatal("unable to detect libc for non-native target", .{}); + } + var libc = LibCInstallation.findNative(.{ .allocator = gpa, .verbose = true,