authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2025-06-28 19:43:16-07:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2025-06-28 19:52:18-07:00
log09f4e2d9d138d313b93ab10cbac1fee2a8f4e9f0
treed7196125040c837e81959d4af2b7c375e74ec148
parent761783f54d1f5ecfaaefc466693f8912ed2e83f5

resinator: Fix include directory detection when cross-compiling from certain host archs

Previously, resinator would use the host arch as the target arch when looking for windows-gnu include directories. However, Zig only thinks it can provide a libc for targets specified in the `std.zig.target.available_libcs` array, which only includes a few for windows-gnu. Therefore, when cross-compiling from a host architecture that doesn't have a windows-gnu target in the available_libcs list, resinator would fail to detect the MinGW include directories. Now, the custom option `/:target` is passed to `zig rc` which is intended for the COFF object file target, but can be re-used for the include directory target as well. For the include directory target, resinator will convert the MachineType to the relevant arch, or fail if there is no equivalent arch/no support for detecting the includes for the MachineType (currently 64-bit Itanium and EBC). Fixes the `windows_resources` standalone test failing when the host is, for example, `riscv64-linux`.

2 files changed, 67 insertions(+), 19 deletions(-)

lib/compiler/resinator/main.zig+63-19
......@@ -104,20 +104,11 @@ pub fn main() !void {
104104 }
105105 const maybe_dependencies_list: ?*std.ArrayList([]const u8) = if (options.depfile_path != null) &dependencies_list else null;
106106
107 const include_paths = getIncludePaths(arena, options.auto_includes, zig_lib_dir) catch |err| switch (err) {
108 error.OutOfMemory => |e| return e,
109 else => |e| {
110 switch (e) {
111 error.MsvcIncludesNotFound => {
112 try error_handler.emitMessage(allocator, .err, "MSVC include paths could not be automatically detected", .{});
113 },
114 error.MingwIncludesNotFound => {
115 try error_handler.emitMessage(allocator, .err, "MinGW include paths could not be automatically detected", .{});
116 },
117 }
118 try error_handler.emitMessage(allocator, .note, "to disable auto includes, use the option /:auto-includes none", .{});
119 std.process.exit(1);
120 },
107 var include_paths = LazyIncludePaths{
108 .arena = arena,
109 .auto_includes_option = options.auto_includes,
110 .zig_lib_dir = zig_lib_dir,
111 .target_machine_type = options.coff_options.target,
121112 };
122113
123114 const full_input = full_input: {
......@@ -138,7 +129,8 @@ pub fn main() !void {
138129 defer argv.deinit();
139130
140131 try argv.append("arocc"); // dummy command name
141 try preprocess.appendAroArgs(aro_arena, &argv, options, include_paths);
132 const resolved_include_paths = try include_paths.get(&error_handler);
133 try preprocess.appendAroArgs(aro_arena, &argv, options, resolved_include_paths);
142134 try argv.append(switch (options.input_source) {
143135 .stdio => "-",
144136 .filename => |filename| filename,
......@@ -264,7 +256,7 @@ pub fn main() !void {
264256 .dependencies_list = maybe_dependencies_list,
265257 .ignore_include_env_var = options.ignore_include_env_var,
266258 .extra_include_paths = options.extra_include_paths.items,
267 .system_include_paths = include_paths,
259 .system_include_paths = try include_paths.get(&error_handler),
268260 .default_language_id = options.default_language_id,
269261 .default_code_page = default_code_page,
270262 .disjoint_code_page = has_disjoint_code_page,
......@@ -498,21 +490,71 @@ const IoStream = struct {
498490 };
499491};
500492
501fn getIncludePaths(arena: std.mem.Allocator, auto_includes_option: cli.Options.AutoIncludes, zig_lib_dir: []const u8) ![]const []const u8 {
493const LazyIncludePaths = struct {
494 arena: std.mem.Allocator,
495 auto_includes_option: cli.Options.AutoIncludes,
496 zig_lib_dir: []const u8,
497 target_machine_type: std.coff.MachineType,
498 resolved_include_paths: ?[]const []const u8 = null,
499
500 pub fn get(self: *LazyIncludePaths, error_handler: *ErrorHandler) ![]const []const u8 {
501 if (self.resolved_include_paths) |include_paths|
502 return include_paths;
503
504 return getIncludePaths(self.arena, self.auto_includes_option, self.zig_lib_dir, self.target_machine_type) catch |err| switch (err) {
505 error.OutOfMemory => |e| return e,
506 else => |e| {
507 switch (e) {
508 error.UnsupportedAutoIncludesMachineType => {
509 try error_handler.emitMessage(self.arena, .err, "automatic include path detection is not supported for target '{s}'", .{@tagName(self.target_machine_type)});
510 },
511 error.MsvcIncludesNotFound => {
512 try error_handler.emitMessage(self.arena, .err, "MSVC include paths could not be automatically detected", .{});
513 },
514 error.MingwIncludesNotFound => {
515 try error_handler.emitMessage(self.arena, .err, "MinGW include paths could not be automatically detected", .{});
516 },
517 }
518 try error_handler.emitMessage(self.arena, .note, "to disable auto includes, use the option /:auto-includes none", .{});
519 std.process.exit(1);
520 },
521 };
522 }
523};
524
525fn getIncludePaths(arena: std.mem.Allocator, auto_includes_option: cli.Options.AutoIncludes, zig_lib_dir: []const u8, target_machine_type: std.coff.MachineType) ![]const []const u8 {
526 if (auto_includes_option == .none) return &[_][]const u8{};
527
528 const includes_arch: std.Target.Cpu.Arch = switch (target_machine_type) {
529 .X64 => .x86_64,
530 .I386 => .x86,
531 .ARMNT => .thumb,
532 .ARM64 => .aarch64,
533 .ARM64EC => .aarch64,
534 .ARM64X => .aarch64,
535 .IA64, .EBC => {
536 return error.UnsupportedAutoIncludesMachineType;
537 },
538 // The above cases are exhaustive of all the `MachineType`s supported (see supported_targets in cvtres.zig)
539 // This is enforced by the argument parser in cli.zig.
540 else => unreachable,
541 };
542
502543 var includes = auto_includes_option;
503544 if (builtin.target.os.tag != .windows) {
504545 switch (includes) {
546 .none => unreachable,
505547 // MSVC can't be found when the host isn't Windows, so short-circuit.
506548 .msvc => return error.MsvcIncludesNotFound,
507549 // Skip straight to gnu since we won't be able to detect MSVC on non-Windows hosts.
508550 .any => includes = .gnu,
509 .none, .gnu => {},
551 .gnu => {},
510552 }
511553 }
512554
513555 while (true) {
514556 switch (includes) {
515 .none => return &[_][]const u8{},
557 .none => unreachable,
516558 .any, .msvc => {
517559 // MSVC is only detectable on Windows targets. This unreachable is to signify
518560 // that .any and .msvc should be dealt with on non-Windows targets before this point,
......@@ -521,6 +563,7 @@ fn getIncludePaths(arena: std.mem.Allocator, auto_includes_option: cli.Options.A
521563
522564 const target_query: std.Target.Query = .{
523565 .os_tag = .windows,
566 .cpu_arch = includes_arch,
524567 .abi = .msvc,
525568 };
526569 const target = std.zig.resolveTargetQueryOrFatal(target_query);
......@@ -546,6 +589,7 @@ fn getIncludePaths(arena: std.mem.Allocator, auto_includes_option: cli.Options.A
546589 .gnu => {
547590 const target_query: std.Target.Query = .{
548591 .os_tag = .windows,
592 .cpu_arch = includes_arch,
549593 .abi = .gnu,
550594 };
551595 const target = std.zig.resolveTargetQueryOrFatal(target_query);
src/Compilation.zig+4
......@@ -6058,6 +6058,8 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
60586058 self_exe_path,
60596059 "rc",
60606060 "--zig-integration",
6061 "/:target",
6062 @tagName(comp.getTarget().cpu.arch),
60616063 "/:no-preprocess",
60626064 "/x", // ignore INCLUDE environment variable
60636065 "/c65001", // UTF-8 codepage
......@@ -6115,6 +6117,8 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
61156117 self_exe_path,
61166118 "rc",
61176119 "--zig-integration",
6120 "/:target",
6121 @tagName(comp.getTarget().cpu.arch),
61186122 "/:depfile",
61196123 out_dep_path,
61206124 "/:depfile-fmt",