From 4f921814c0a6555a61d9e0a92fcc6f30bc20e994 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Tue, 16 Jun 2026 01:43:20 -0400 Subject: [PATCH] main: handle more cli args for `zig test -ofmt=c` --- lib/zig.h | 26 +++++--- src/Compilation.zig | 109 ++++++++++++++++++--------------- src/codegen/c.zig | 5 +- src/link.zig | 4 +- src/link/Lld.zig | 40 ++++++------ src/link/MachO.zig | 14 ++--- src/link/MachO/relocatable.zig | 8 +-- src/main.zig | 98 ++++++++++++++++++++--------- 8 files changed, 184 insertions(+), 120 deletions(-) diff --git a/lib/zig.h b/lib/zig.h index 4f8b2da1d7de0ddcbd6d7df8c1b85d563349d7c1..34b56286a508b2707f4498f49612d9d625ee7c86 100644 --- a/lib/zig.h +++ b/lib/zig.h @@ -4557,9 +4557,12 @@ static inline void zig_msvc_atomic_store_i128(zig_i128 volatile* obj, zig_i128 a #include #endif +static inline void* zig_e_zig_windows_teb(void) zig_mangled(zig_e_zig_windows_teb, "zig_windows_teb"); +static inline void* zig_e_zig_windows_peb(void) zig_mangled(zig_e_zig_windows_peb, "zig_windows_peb"); + #if defined(zig_thumb) -static inline void* zig_windows_teb(void) { +static inline void* zig_e_zig_windows_teb(void) { void* teb = 0; #if defined(zig_msvc) teb = (void*)_MoveFromCoprocessor(15, 0, 13, 0, 2); @@ -4571,7 +4574,7 @@ static inline void* zig_windows_teb(void) { #elif defined(zig_aarch64) -static inline void* zig_windows_teb(void) { +static inline void* zig_e_zig_windows_teb(void) { void* teb = 0; #if defined(zig_msvc) teb = (void*)__readx18qword(0x0); @@ -4583,7 +4586,7 @@ static inline void* zig_windows_teb(void) { #elif defined(zig_x86_32) -static inline void* zig_windows_teb(void) { +static inline void* zig_e_zig_windows_teb(void) { void* teb = 0; #if defined(zig_msvc) teb = (void*)__readfsdword(0x18); @@ -4593,7 +4596,7 @@ static inline void* zig_windows_teb(void) { return teb; } -static inline void* zig_windows_peb(void) { +static inline void* zig_e_zig_windows_peb(void) { void* peb = 0; #if defined(zig_msvc) peb = (void*)__readfsdword(0x30); @@ -4605,7 +4608,7 @@ static inline void* zig_windows_peb(void) { #elif defined(zig_x86_64) -static inline void* zig_windows_teb(void) { +static inline void* zig_e_zig_windows_teb(void) { void* teb = 0; #if defined(zig_msvc) teb = (void*)__readgsqword(0x30); @@ -4615,7 +4618,7 @@ static inline void* zig_windows_teb(void) { return teb; } -static inline void* zig_windows_peb(void) { +static inline void* zig_e_zig_windows_peb(void) { void* peb = 0; #if defined(zig_msvc) peb = (void*)__readgsqword(0x60); @@ -4629,7 +4632,9 @@ static inline void* zig_windows_peb(void) { #if defined(zig_loongarch) -static inline void zig_loongarch_cpucfg(uint32_t word, uint32_t* result) { +static inline void zig_e_zig_loongarch_cpucfg(uint32_t word, uint32_t* result) zig_mangled(zig_e_zig_loongarch_cpucfg, "zig_loongarch_cpucfg"); + +static inline void zig_e_zig_loongarch_cpucfg(uint32_t word, uint32_t* result) { #if defined(zig_gnuc_asm) __asm__("cpucfg %[result], %[word]" : [result] "=r" (result) : [word] "r" (word)); #else @@ -4639,7 +4644,10 @@ static inline void zig_loongarch_cpucfg(uint32_t word, uint32_t* result) { #elif defined(zig_x86) && !defined(zig_x86_16) -static inline void zig_x86_cpuid(uint32_t leaf_id, uint32_t subid, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) { +static inline void zig_e_zig_x86_cpuid(uint32_t leaf_id, uint32_t subid, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) zig_mangled(zig_e_zig_x86_cpuid, "zig_x86_cpuid"); +static inline uint32_t zig_e_zig_x86_get_xcr0(void) zig_mangled(zig_e_zig_x86_get_xcr0, "zig_x86_get_xcr0"); + +static inline void zig_e_zig_x86_cpuid(uint32_t leaf_id, uint32_t subid, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) { #if defined(zig_msvc) int cpu_info[4]; __cpuidex(cpu_info, leaf_id, subid); @@ -4657,7 +4665,7 @@ static inline void zig_x86_cpuid(uint32_t leaf_id, uint32_t subid, uint32_t* eax #endif } -static inline uint32_t zig_x86_get_xcr0(void) { +static inline uint32_t zig_e_zig_x86_get_xcr0(void) { #if defined(zig_msvc) return (uint32_t)_xgetbv(0); #elif defined(zig_gnuc_asm) diff --git a/src/Compilation.zig b/src/Compilation.zig index c5d78866f8a97c69727b496abee4b035e5c14935..684889f2d021ea78587078d62468c85e1e4a971d 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -103,16 +103,12 @@ native_system_include_paths: []const []const u8, /// Corresponds to `-u ` for ELF/MachO and `/include:` for COFF/PE. force_undefined_symbols: std.array_hash_map.String(void), -c_object_table: std.array_hash_map.Auto(*CObject, void) = .empty, -win32_resource_table: if (dev.env.supports(.win32_resource)) std.array_hash_map.Auto(*Win32Resource, void) else struct { - pub fn keys(_: @This()) [0]void { - return .{}; - } - pub fn count(_: @This()) u0 { - return 0; - } +c_objects: std.ArrayList(*CObject) = .empty, +win32_resources: if (dev.env.supports(.win32_resource)) std.ArrayList(*Win32Resource) else struct { + items: [0]*struct {}, + pub const empty: @This() = .{ .items = .{} }; pub fn deinit(_: @This(), _: Allocator) void {} -} = .{}, +} = .empty, link_diags: link.Diags, link_queue: link.Queue = .empty, @@ -915,21 +911,6 @@ pub const CrtFile = struct { } }; -/// Supported languages for "zig clang -x ". -/// Loosely based on llvm-project/clang/include/clang/Driver/Types.def -pub const LangToExt = std.StaticStringMap(FileExt).initComptime(.{ - .{ "c", .c }, - .{ "c-header", .h }, - .{ "c++", .cpp }, - .{ "c++-header", .hpp }, - .{ "objective-c", .m }, - .{ "objective-c-header", .hm }, - .{ "objective-c++", .mm }, - .{ "objective-c++-header", .hmm }, - .{ "assembler", .assembly }, - .{ "assembler-with-cpp", .assembly_with_cpp }, -}); - /// For passing to a C compiler. pub const CSourceFile = struct { /// Many C compiler flags are determined by settings contained in the owning Module. @@ -2486,8 +2467,10 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, }; errdefer comp.destroy(); + if (target.ofmt == .c) return comp; + // Add a `CObject` for each `c_source_files`. - try comp.c_object_table.ensureTotalCapacity(gpa, options.c_source_files.len); + try comp.c_objects.ensureTotalCapacity(gpa, options.c_source_files.len); for (options.c_source_files) |c_source_file| { const c_object = try gpa.create(CObject); errdefer gpa.destroy(c_object); @@ -2496,7 +2479,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, .status = .{ .new = {} }, .src = c_source_file, }; - comp.c_object_table.putAssumeCapacityNoClobber(c_object, {}); + comp.c_objects.appendAssumeCapacity(c_object); } // Add a `Win32Resource` for each `rc_source_files` and one for `manifest_file`. @@ -2504,7 +2487,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, options.rc_source_files.len + @intFromBool(options.manifest_file != null); if (win32_resource_count > 0) { dev.check(.win32_resource); - try comp.win32_resource_table.ensureTotalCapacity(gpa, win32_resource_count); + try comp.win32_resources.ensureTotalCapacity(gpa, win32_resource_count); for (options.rc_source_files) |rc_source_file| { const win32_resource = try gpa.create(Win32Resource); errdefer gpa.destroy(win32_resource); @@ -2513,7 +2496,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, .status = .{ .new = {} }, .src = .{ .rc = rc_source_file }, }; - comp.win32_resource_table.putAssumeCapacityNoClobber(win32_resource, {}); + comp.win32_resources.appendAssumeCapacity(win32_resource); } if (options.manifest_file) |manifest_path| { @@ -2524,11 +2507,11 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, .status = .{ .new = {} }, .src = .{ .manifest = manifest_path }, }; - comp.win32_resource_table.putAssumeCapacityNoClobber(win32_resource, {}); + comp.win32_resources.appendAssumeCapacity(win32_resource); } } - if (comp.emit_bin != null and target.ofmt != .c) { + if (comp.emit_bin != null) { if (!comp.skip_linker_dependencies) { // If we need to build libc for the target, add work items for it. // We go through the work queue so that building can be done in parallel. @@ -2749,20 +2732,20 @@ pub fn destroy(comp: *Compilation) void { openbsd_file.deinit(gpa, io); } - for (comp.c_object_table.keys()) |key| { - key.destroy(gpa, io); + for (comp.c_objects.items) |c_object| { + c_object.destroy(gpa, io); } - comp.c_object_table.deinit(gpa); + comp.c_objects.deinit(gpa); for (comp.failed_c_objects.values()) |bundle| { bundle.destroy(gpa); } comp.failed_c_objects.deinit(gpa); - for (comp.win32_resource_table.keys()) |key| { - key.destroy(gpa, io); + for (comp.win32_resources.items) |win32_resource| { + win32_resource.destroy(gpa, io); } - comp.win32_resource_table.deinit(gpa); + comp.win32_resources.deinit(gpa); for (comp.failed_win32_resources.values()) |*value| { value.deinit(gpa); @@ -3016,8 +2999,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE // changes. For now, to avoid crashing the linker in this case, don't kick off C object // updates if we've done prelink already. https://codeberg.org/ziglang/zig/issues/32081 } else { - try comp.c_object_work_queue.ensureUnusedCapacity(gpa, comp.c_object_table.count()); - for (comp.c_object_table.keys()) |c_object| { + try comp.c_object_work_queue.ensureUnusedCapacity(gpa, comp.c_objects.items.len); + for (comp.c_objects.items) |c_object| { comp.c_object_work_queue.pushBackAssumeCapacity(c_object); try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{c_object.src.src_path})); } @@ -3032,8 +3015,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE // For compiling Win32 resources, we rely on the cache hash system to avoid duplicating work. // Add a Job for each Win32 resource file. - try comp.win32_resource_work_queue.ensureUnusedCapacity(gpa, comp.win32_resource_table.count()); - for (comp.win32_resource_table.keys()) |win32_resource| { + try comp.win32_resource_work_queue.ensureUnusedCapacity(gpa, comp.win32_resources.items.len); + for (comp.win32_resources.items) |win32_resource| { comp.win32_resource_work_queue.pushBackAssumeCapacity(win32_resource); switch (win32_resource.src) { .rc => |f| { @@ -3140,9 +3123,9 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE return; } - if (comp.zcu == null and comp.config.output_mode == .Obj and comp.c_object_table.count() == 1) { + if (comp.zcu == null and comp.config.output_mode == .Obj and comp.c_objects.items.len == 1) { // This is `zig build-obj foo.c`. We can emit asm and LLVM IR/bitcode. - const c_obj_path = comp.c_object_table.keys()[0].status.success.object_path; + const c_obj_path = comp.c_objects.items[0].status.success.object_path; if (comp.emit_asm) |path| try comp.emitFromCObject(arena, c_obj_path, ".s", path); if (comp.emit_llvm_ir) |path| try comp.emitFromCObject(arena, c_obj_path, ".ll", path); if (comp.emit_llvm_bc) |path| try comp.emitFromCObject(arena, c_obj_path, ".bc", path); @@ -3482,14 +3465,14 @@ fn addNonIncrementalStuffToCacheManifest( try link.hashInputs(man, comp.link_inputs); - for (comp.c_object_table.keys()) |key| { - _ = try man.addFile(key.src.src_path, null); - man.hash.addOptional(key.src.ext); - man.hash.addListOfBytes(key.src.extra_flags); + for (comp.c_objects.items) |c_object| { + _ = try man.addFile(c_object.src.src_path, null); + man.hash.addOptional(c_object.src.ext); + man.hash.addListOfBytes(c_object.src.extra_flags); } - for (comp.win32_resource_table.keys()) |key| { - switch (key.src) { + for (comp.win32_resources.items) |win32_resource| { + switch (win32_resource.src) { .rc => |rc_src| { _ = try man.addFile(rc_src.src_path, null); man.hash.addListOfBytes(rc_src.extra_flags); @@ -5592,9 +5575,10 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr c_source_basename[0 .. c_source_basename.len - fs.path.extension(c_source_basename).len]; const target = comp.getTarget(); + assert(target.ofmt != .c); const o_ext = target.ofmt.fileExt(target.cpu.arch); const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: { - var argv = std.array_list.Managed([]const u8).init(gpa); + var argv: std.array_list.Managed([]const u8) = .init(gpa); defer argv.deinit(); // In case we are doing passthrough mode, we need to detect -S and -emit-llvm. @@ -7057,6 +7041,33 @@ pub const FileExt = enum { .unknown => "", }; } + + /// The value accepted by "zig clang -x " and passed to "clang -x ". + pub fn toLang(ext: FileExt) ?[]const u8 { + return switch (ext) { + else => null, + .c => "c", + .h => "c-header", + .cpp => "c++", + .hpp => "c++-header", + .m => "objective-c", + .hm => "objective-c-header", + .mm => "objective-c++", + .hmm => "objective-c++-header", + .assembly => "assembler", + .assembly_with_cpp => "assembler-with-cpp", + }; + } + + /// Supported languages for "zig clang -x ". + /// Loosely based on llvm-project/clang/include/clang/Driver/Types.def + pub const from_lang = std.StaticStringMap(FileExt).initComptime(init: { + var init: []const struct { []const u8, FileExt } = &.{}; + for (std.enums.values(FileExt)) |file_ext| if (file_ext.toLang()) |lang| { + init = init ++ .{.{ lang, file_ext }}; + }; + break :init init; + }); }; pub fn hasObjectExt(filename: []const u8) bool { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 54b86f833191a93e6f059ccece94dbb951fa67c6..4a84fafc619dc1d9e772680f29052eef81dc9ddd 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -328,6 +328,9 @@ fn isReservedIdent(ident: []const u8) bool { return true; } + // zig.h + if (mem.startsWith(u8, ident, "zig_")) return true; + return reserved_idents.has(ident); } @@ -3755,7 +3758,7 @@ fn airCmpLteErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { try f.writeCValue(w, local, .other); try w.writeAll(" = "); try f.writeCValue(w, operand, .other); - try w.print(" < sizeof({f}) / sizeof(*{0f});", .{fmtIdentSolo("zig_errorName")}); + try w.writeAll(" < sizeof(zig_errorName) / sizeof(*zig_errorName);"); try f.newline(); return local; } diff --git a/src/link.zig b/src/link.zig index 2b1fd8735bc5125d95f5e2135233a1a61ddd73d9..844eef3c407f3aecbc27b764a822808c5d1433e3 100644 --- a/src/link.zig +++ b/src/link.zig @@ -933,8 +933,8 @@ pub const File = struct { // Until then, we do `lld -r -o output.o input.o` even though the output is the same // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file // to the final location. See also the corresponding TODO in Coff linking. - assert(comp.c_object_table.count() == 1); - const the_key = comp.c_object_table.keys()[0]; + assert(comp.c_objects.items.len == 1); + const the_key = comp.c_objects.items[0]; const cached_pp_file_path = the_key.status.success.object_path; Io.Dir.copyFile( cached_pp_file_path.root_dir.handle, diff --git a/src/link/Lld.zig b/src/link/Lld.zig index de9beee22a2d2259d2ba594e30a8637978b7a977..d84e3c1fe2a68042dd90ead613f9e9f17c80e740 100644 --- a/src/link/Lld.zig +++ b/src/link/Lld.zig @@ -313,14 +313,14 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) !void { object_files.appendAssumeCapacity(try input.path().?.toStringZ(arena)); } - try object_files.ensureUnusedCapacity(arena, comp.c_object_table.count() + - comp.win32_resource_table.count() + 2); + try object_files.ensureUnusedCapacity(arena, comp.c_objects.items.len + + comp.win32_resources.items.len + 2); - for (comp.c_object_table.keys()) |key| { - object_files.appendAssumeCapacity(try key.status.success.object_path.toStringZ(arena)); + for (comp.c_objects.items) |c_object| { + object_files.appendAssumeCapacity(try c_object.status.success.object_path.toStringZ(arena)); } - for (comp.win32_resource_table.keys()) |key| { - object_files.appendAssumeCapacity(try arena.dupeSentinel(u8, key.status.success.res_path, 0)); + for (comp.win32_resources.items) |win32_resource| { + object_files.appendAssumeCapacity(try arena.dupeSentinel(u8, win32_resource.status.success.res_path, 0)); } if (zcu_obj_path) |p| object_files.appendAssumeCapacity(try p.toStringZ(arena)); if (compiler_rt_path) |p| object_files.appendAssumeCapacity(try p.toStringZ(arena)); @@ -395,8 +395,8 @@ fn coffLink(lld: *Lld, arena: Allocator) !void { const the_object_path = blk: { if (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path; - if (comp.c_object_table.count() != 0) - break :blk comp.c_object_table.keys()[0].status.success.object_path; + if (comp.c_objects.items.len != 0) + break :blk comp.c_objects.items[0].status.success.object_path; if (zcu_obj_path) |p| break :blk p; @@ -546,12 +546,12 @@ fn coffLink(lld: *Lld, arena: Allocator) !void { }, }; - for (comp.c_object_table.keys()) |key| { - try argv.append(try key.status.success.object_path.toString(arena)); + for (comp.c_objects.items) |c_object| { + try argv.append(try c_object.status.success.object_path.toString(arena)); } - for (comp.win32_resource_table.keys()) |key| { - try argv.append(key.status.success.res_path); + for (comp.win32_resources.items) |win32_resource| { + try argv.append(win32_resource.status.success.res_path); } if (zcu_obj_path) |p| { @@ -805,8 +805,8 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { const the_object_path = blk: { if (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path; - if (comp.c_object_table.count() != 0) - break :blk comp.c_object_table.keys()[0].status.success.object_path; + if (comp.c_objects.items.len != 0) + break :blk comp.c_objects.items[0].status.success.object_path; if (zcu_obj_path) |p| break :blk p; @@ -1099,8 +1099,8 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { whole_archive = false; } - for (comp.c_object_table.keys()) |key| { - try argv.append(try key.status.success.object_path.toString(arena)); + for (comp.c_objects.items) |c_object| { + try argv.append(try c_object.status.success.object_path.toString(arena)); } if (zcu_obj_path) |p| { @@ -1381,8 +1381,8 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void { const the_object_path = blk: { if (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path; - if (comp.c_object_table.count() != 0) - break :blk comp.c_object_table.keys()[0].status.success.object_path; + if (comp.c_objects.items.len != 0) + break :blk comp.c_objects.items[0].status.success.object_path; if (zcu_obj_path) |p| break :blk p; @@ -1566,8 +1566,8 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void { whole_archive = false; } - for (comp.c_object_table.keys()) |key| { - try argv.append(try key.status.success.object_path.toString(arena)); + for (comp.c_objects.items) |c_object| { + try argv.append(try c_object.status.success.object_path.toString(arena)); } if (zcu_obj_path) |p| { try argv.append(try p.toString(arena)); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 8b045bf354aca5f5df2955307a1b67cc75f1a2fa..125db2983f2fa8a550b218d2d4be6d41153c1c8b 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -377,9 +377,9 @@ pub fn flush( // This is a set of object files emitted by clang in a single `build-exe` invocation. // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up // in this set. - try positionals.ensureUnusedCapacity(comp.c_object_table.keys().len); - for (comp.c_object_table.keys()) |key| { - positionals.appendAssumeCapacity(try link.openObjectInput(io, diags, key.status.success.object_path)); + try positionals.ensureUnusedCapacity(comp.c_objects.items.len); + for (comp.c_objects.items) |c_object| { + positionals.appendAssumeCapacity(try link.openObjectInput(io, diags, c_object.status.success.object_path)); } if (zcu_obj_path) |path| try positionals.append(try link.openObjectInput(io, diags, path)); @@ -657,8 +657,8 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { .dso_exact => |dso_exact| try argv.appendSlice(&.{ "-l", dso_exact.name }), }; - for (comp.c_object_table.keys()) |key| { - try argv.append(try key.status.success.object_path.toString(arena)); + for (comp.c_objects.items) |c_object| { + try argv.append(try c_object.status.success.object_path.toString(arena)); } if (zcu_obj_path) |p| { @@ -749,8 +749,8 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { .dso_exact => |dso_exact| try argv.appendSlice(&.{ "-l", dso_exact.name }), }; - for (comp.c_object_table.keys()) |key| { - try argv.append(try key.status.success.object_path.toString(arena)); + for (comp.c_objects.items) |c_object| { + try argv.append(try c_object.status.success.object_path.toString(arena)); } if (zcu_obj_path) |p| { diff --git a/src/link/MachO/relocatable.zig b/src/link/MachO/relocatable.zig index be36cfc045b7bb4abe4ff8fde43b62b7299511e6..b864ee66ca42394529dd6c58556e5cb10801e413 100644 --- a/src/link/MachO/relocatable.zig +++ b/src/link/MachO/relocatable.zig @@ -9,8 +9,8 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat try positionals.ensureUnusedCapacity(comp.link_inputs.len); positionals.appendSliceAssumeCapacity(comp.link_inputs); - for (comp.c_object_table.keys()) |key| { - try positionals.append(try link.openObjectInput(io, diags, key.status.success.object_path)); + for (comp.c_objects.items) |c_object| { + try positionals.append(try link.openObjectInput(io, diags, c_object.status.success.object_path)); } if (module_obj_path) |path| try positionals.append(try link.openObjectInput(io, diags, path)); @@ -86,8 +86,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? try positionals.ensureUnusedCapacity(comp.link_inputs.len); positionals.appendSliceAssumeCapacity(comp.link_inputs); - for (comp.c_object_table.keys()) |key| { - try positionals.append(try link.openObjectInput(io, diags, key.status.success.object_path)); + for (comp.c_objects.items) |c_object| { + try positionals.append(try link.openObjectInput(io, diags, c_object.status.success.object_path)); } if (module_obj_path) |path| try positionals.append(try link.openObjectInput(io, diags, path)); diff --git a/src/main.zig b/src/main.zig index 44001796ff06962aae4168d2ae7ed7d241e84c42..6e47c30a30bb0e15d5f742c151a444a426ff91cd 100644 --- a/src/main.zig +++ b/src/main.zig @@ -887,6 +887,7 @@ const CliModule = struct { inherited: Package.Module.CreateOptions.Inherited, target_arch_os_abi: ?[]const u8, target_mcpu: ?[]const u8, + dynamic_linker: ?[]const u8, deps: []const Dep, resolved: ?*Package.Module, @@ -943,6 +944,7 @@ fn buildOutputType( var emit_implib_arg_provided = false; var target_arch_os_abi: ?[]const u8 = null; var target_mcpu: ?[]const u8 = null; + var dynamic_linker: ?[]const u8 = null; var emit_h: Emit = .no; var soname: SOName = undefined; var want_compiler_rt: ?bool = null; @@ -1059,7 +1061,6 @@ fn buildOutputType( // Populated just before the call to `createModule`. .dirs = undefined, .object_format = null, - .dynamic_linker = null, .modules = .empty, .opts = .{ .is_test = switch (arg_mode) { @@ -1179,6 +1180,7 @@ fn buildOutputType( &cc_argv, &target_arch_os_abi, &target_mcpu, + &dynamic_linker, &deps, &c_source_files_owner_index, &rc_source_files_owner_index, @@ -1397,9 +1399,9 @@ fn buildOutputType( } else if (mem.cutPrefix(u8, arg, "-O")) |rest| { mod_opts.optimize_mode = parseOptimizeMode(rest); } else if (mem.eql(u8, arg, "--dynamic-linker")) { - create_module.dynamic_linker = args_iter.nextOrFatal(); + dynamic_linker = args_iter.nextOrFatal(); } else if (mem.eql(u8, arg, "--no-dynamic-linker")) { - create_module.dynamic_linker = ""; + dynamic_linker = ""; } else if (mem.eql(u8, arg, "--sysroot")) { const next_arg = args_iter.nextOrFatal(); create_module.sysroot = next_arg; @@ -1846,7 +1848,7 @@ fn buildOutputType( const lang = if (rest.len == 0) args_iter.nextOrFatal() else rest; if (mem.eql(u8, lang, "none")) { file_ext = null; - } else if (Compilation.LangToExt.get(lang)) |got_ext| { + } else if (Compilation.FileExt.from_lang.get(lang)) |got_ext| { file_ext = got_ext; } else { fatal("language not recognized: {s}", .{lang}); @@ -1983,7 +1985,7 @@ fn buildOutputType( const lang = mem.sliceTo(it.only_arg, 0); if (mem.eql(u8, lang, "none")) { file_ext = null; - } else if (Compilation.LangToExt.get(lang)) |got_ext| { + } else if (Compilation.FileExt.from_lang.get(lang)) |got_ext| { file_ext = got_ext; } else { fatal("language not recognized: {q}", .{lang}); @@ -2610,12 +2612,11 @@ fn buildOutputType( mem.eql(u8, arg, "--dynamic-linker") or mem.eql(u8, arg, "-dynamic-linker")) { - create_module.dynamic_linker = linker_args_it.nextOrFatal(); - } else if (mem.eql(u8, arg, "-I") or - mem.eql(u8, arg, "--no-dynamic-linker") or + dynamic_linker = linker_args_it.nextOrFatal(); + } else if (mem.eql(u8, arg, "--no-dynamic-linker") or mem.eql(u8, arg, "-no-dynamic-linker")) { - create_module.dynamic_linker = ""; + dynamic_linker = ""; } else if (mem.eql(u8, arg, "-E") or mem.eql(u8, arg, "--export-dynamic") or mem.eql(u8, arg, "-export-dynamic")) @@ -3184,6 +3185,7 @@ fn buildOutputType( .inherited = mod_opts, .target_arch_os_abi = target_arch_os_abi, .target_mcpu = target_mcpu, + .dynamic_linker = dynamic_linker, .deps = try deps.toOwnedSlice(arena), .resolved = null, .c_source_files_start = c_source_files_owner_index, @@ -3842,10 +3844,59 @@ fn buildOutputType( if (test_exec_args.items.len == 0 and target.ofmt == .c and emit_bin_resolved != .no) { // Default to using `zig run` to execute the produced .c code from `zig test`. try test_exec_args.appendSlice(arena, &.{ self_exe_path, "run" }); - if (dirs.zig_lib.path) |p| { - try test_exec_args.appendSlice(arena, &.{ "-I", p }); + // Skip passing `-ofmt`, we want the default for the target, not `.c` anymore. + + var prev_has_cflags = false; + var prev_has_rcflags = false; + if (dirs.zig_lib.path) |zig_lib_path| { + try test_exec_args.appendSlice(arena, &.{ "-cflags", "-I", zig_lib_path, "--" }); + prev_has_cflags = true; + } + try test_exec_args.append(arena, null); + for (create_module.modules.keys(), create_module.modules.values()) |mod_name, mod| { + for (create_module.c_source_files.items[mod.c_source_files_start..mod.c_source_files_end]) |c_source_file| { + const cflags_len = c_source_file.extra_flags.len + c_source_file.cache_exempt_flags.len; + if (prev_has_cflags or cflags_len > 0) { + try test_exec_args.ensureUnusedCapacity(arena, 1 + cflags_len + 1); + test_exec_args.appendAssumeCapacity("-cflags"); + for (c_source_file.extra_flags) |extra_flag| test_exec_args.appendAssumeCapacity(extra_flag); + for (c_source_file.cache_exempt_flags) |cache_exempt_flag| test_exec_args.appendAssumeCapacity(cache_exempt_flag); + test_exec_args.appendAssumeCapacity("--"); + } + prev_has_cflags = cflags_len > 0; + if (c_source_file.ext) |ext| try test_exec_args.appendSlice(arena, &.{ "-x", ext.toLang() }); + try test_exec_args.append(arena, c_source_file.src_path); + if (c_source_file.ext) |_| try test_exec_args.appendSlice(arena, &.{ "-x", "none" }); + } + for (create_module.rc_source_files.items[mod.rc_source_files_start..mod.rc_source_files_end]) |rc_source_file| { + const rcflags_len = rc_source_file.extra_flags.len; + if (prev_has_rcflags or rcflags_len > 0) { + try test_exec_args.ensureUnusedCapacity(arena, 1 + rcflags_len + 1); + test_exec_args.appendAssumeCapacity("-rcflags"); + for (rc_source_file.extra_flags) |extra_flag| test_exec_args.appendAssumeCapacity(extra_flag); + test_exec_args.appendAssumeCapacity("--"); + } + prev_has_rcflags = rcflags_len > 0; + try test_exec_args.append(arena, rc_source_file.src_path); + } + if (mod.target_arch_os_abi) |triple| try test_exec_args.appendSlice(arena, &.{ "-target", triple }); + if (mod.target_mcpu) |mcpu| try test_exec_args.appendSlice(arena, &.{ "-mcpu", mcpu }); + if (mod.dynamic_linker) |dl| if (dl.len > 0) + try test_exec_args.appendSlice(arena, &.{ "--dynamic-linker", dl }) + else + try test_exec_args.append(arena, "--no-dynamic-linker"); + try test_exec_args.ensureUnusedCapacity(arena, mod.cc_argv.len); + for (mod.cc_argv) |cc_arg| test_exec_args.appendAssumeCapacity(cc_arg); + for (mod.deps) |dep| try test_exec_args.appendSlice(arena, &.{ + "--dep", + if (std.mem.eql(u8, dep.key, dep.value)) dep.value else try std.fmt.allocPrint(arena, "{s}={s}", .{ dep.key, dep.value }), + }); + try test_exec_args.append(arena, try std.fmt.allocPrint(arena, "-M{s}", .{mod_name})); } + try test_exec_args.ensureUnusedCapacity(arena, comp.global_cc_argv.len); + for (comp.global_cc_argv) |global_cc_arg| test_exec_args.appendAssumeCapacity(global_cc_arg); + if (create_module.resolved_options.link_libcpp) try test_exec_args.append(arena, "-lc++"); if (create_module.resolved_options.link_libc) { try test_exec_args.append(arena, "-lc"); } else if (target.os.tag == .windows) { @@ -3855,21 +3906,10 @@ fn buildOutputType( }); } - const first_cli_mod = create_module.modules.values()[0]; - if (first_cli_mod.target_arch_os_abi) |triple| { - try test_exec_args.appendSlice(arena, &.{ "-target", triple }); - } - if (first_cli_mod.target_mcpu) |mcpu| { - try test_exec_args.append(arena, try std.fmt.allocPrint(arena, "-mcpu={s}", .{mcpu})); - } - if (create_module.dynamic_linker) |dl| { - if (dl.len > 0) { - try test_exec_args.appendSlice(arena, &.{ "--dynamic-linker", dl }); - } else { - try test_exec_args.append(arena, "--no-dynamic-linker"); - } - } - try test_exec_args.append(arena, null); // placeholder for the path of the emitted C source file + try test_exec_args.ensureUnusedCapacity(arena, 2 * log_scopes.items.len + @intFromBool(verbose_link) + @intFromBool(verbose_cc)); + for (log_scopes.items) |log_scope| test_exec_args.appendSliceAssumeCapacity(&.{ "--debug-log", log_scope }); + if (verbose_link) test_exec_args.appendAssumeCapacity("--verbose-link"); + if (verbose_cc) test_exec_args.appendAssumeCapacity("--verbose-cc"); } try runOrTest( @@ -3898,7 +3938,6 @@ const CreateModule = struct { dirs: Compilation.Directories, modules: std.array_hash_map.String(CliModule), opts: Compilation.Config.Options, - dynamic_linker: ?[]const u8, object_format: ?[]const u8, /// undefined until createModule() for the root module is called. resolved_options: Compilation.Config, @@ -3960,7 +3999,7 @@ fn createModule( var target_parse_options: std.Target.Query.ParseOptions = .{ .arch_os_abi = cli_mod.target_arch_os_abi orelse "native", .cpu_features = cli_mod.target_mcpu, - .dynamic_linker = create_module.dynamic_linker, + .dynamic_linker = cli_mod.dynamic_linker, .object_format = create_module.object_format, }; @@ -7844,6 +7883,7 @@ fn handleModArg( cc_argv: *std.ArrayList([]const u8), target_arch_os_abi: *?[]const u8, target_mcpu: *?[]const u8, + dynamic_linker: *?[]const u8, deps: *std.ArrayList(CliModule.Dep), c_source_files_owner_index: *usize, rc_source_files_owner_index: *usize, @@ -7892,6 +7932,7 @@ fn handleModArg( .inherited = mod_opts.*, .target_arch_os_abi = target_arch_os_abi.*, .target_mcpu = target_mcpu.*, + .dynamic_linker = dynamic_linker.*, .deps = try deps.toOwnedSlice(arena), .resolved = null, .c_source_files_start = c_source_files_owner_index.*, @@ -7903,6 +7944,7 @@ fn handleModArg( mod_opts.* = .{}; target_arch_os_abi.* = null; target_mcpu.* = null; + dynamic_linker.* = null; c_source_files_owner_index.* = create_module.c_source_files.items.len; rc_source_files_owner_index.* = create_module.rc_source_files.items.len; } -- 2.54.0