diff options
| author | Alex Rønne Petersen <alex@alexrp.com> | 2025-08-05 22:32:35 +0200 |
|---|---|---|
| committer | Alex Rønne Petersen <alex@alexrp.com> | 2025-08-06 06:15:13 +0200 |
| commit | 7ee6dab39fac7aa12fa9fd952bb2bdc28d5eabe8 (patch) | |
| tree | b97957e62077e78f6bf49836babcdb84b4ff772f /src | |
| parent | 9a158c1dae531f2a4e5667569bed38c27cbd4d57 (diff) | |
| download | zig-7ee6dab39fac7aa12fa9fd952bb2bdc28d5eabe8.tar.gz zig-7ee6dab39fac7aa12fa9fd952bb2bdc28d5eabe8.zip | |
Revert "Sema: Stop adding Windows implib link inputs for `extern "..."` syntax."
This reverts commit b461d07a5464aec86c533434dab0b58edfffb331.
After some discussion in the team, we've decided that this is too disruptive,
especially because the linker errors are less than helpful. That's a fixable
problem, so we might reconsider this in the future, but revert it for now.
Diffstat (limited to 'src')
| -rw-r--r-- | src/Compilation.zig | 39 | ||||
| -rw-r--r-- | src/Sema.zig | 13 | ||||
| -rw-r--r-- | src/libs/mingw.zig | 3 | ||||
| -rw-r--r-- | src/main.zig | 24 |
4 files changed, 46 insertions, 33 deletions
diff --git a/src/Compilation.zig b/src/Compilation.zig index 4024e0a49e..ae3ab118b7 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2185,8 +2185,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil .emit_docs = try options.emit_docs.resolve(arena, &options, .docs), }; - comp.windows_libs = try std.StringArrayHashMapUnmanaged(void).init(gpa, options.windows_lib_names, &.{}); - errdefer comp.windows_libs.deinit(gpa); + errdefer { + for (comp.windows_libs.keys()) |windows_lib| gpa.free(windows_lib); + comp.windows_libs.deinit(gpa); + } + try comp.windows_libs.ensureUnusedCapacity(gpa, options.windows_lib_names.len); + for (options.windows_lib_names) |windows_lib| comp.windows_libs.putAssumeCapacity(try gpa.dupe(u8, windows_lib), {}); // Prevent some footguns by making the "any" fields of config reflect // the default Module settings. @@ -2417,13 +2421,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil if (comp.emit_bin != null and target.ofmt != .c) { if (!comp.skip_linker_dependencies) { - // These DLLs are always loaded into every Windows process. - if (target.os.tag == .windows and is_exe_or_dyn_lib) { - try comp.windows_libs.ensureUnusedCapacity(gpa, 2); - comp.windows_libs.putAssumeCapacity("kernel32", {}); - comp.windows_libs.putAssumeCapacity("ntdll", {}); - } - // 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. // If linking against host libc installation, instead queue up jobs @@ -2512,7 +2509,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil // When linking mingw-w64 there are some import libs we always need. try comp.windows_libs.ensureUnusedCapacity(gpa, mingw.always_link_libs.len); - for (mingw.always_link_libs) |name| comp.windows_libs.putAssumeCapacity(name, {}); + for (mingw.always_link_libs) |name| comp.windows_libs.putAssumeCapacity(try gpa.dupe(u8, name), {}); } else { return error.LibCUnavailable; } @@ -2610,6 +2607,7 @@ pub fn destroy(comp: *Compilation) void { comp.c_object_work_queue.deinit(); comp.win32_resource_work_queue.deinit(); + for (comp.windows_libs.keys()) |windows_lib| gpa.free(windows_lib); comp.windows_libs.deinit(gpa); { @@ -7795,6 +7793,27 @@ fn getCrtPathsInner( }; } +pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void { + // Avoid deadlocking on building import libs such as kernel32.lib + // This can happen when the user uses `build-exe foo.obj -lkernel32` and + // then when we create a sub-Compilation for zig libc, it also tries to + // build kernel32.lib. + if (comp.skip_linker_dependencies) return; + const target = &comp.root_mod.resolved_target.result; + if (target.os.tag != .windows or target.ofmt == .c) return; + + // This happens when an `extern "foo"` function is referenced. + // If we haven't seen this library yet and we're targeting Windows, we need + // to queue up a work item to produce the DLL import library for this. + const gop = try comp.windows_libs.getOrPut(comp.gpa, lib_name); + if (gop.found_existing) return; + { + errdefer _ = comp.windows_libs.pop(); + gop.key_ptr.* = try comp.gpa.dupe(u8, lib_name); + } + try comp.queueJob(.{ .windows_import_lib = gop.index }); +} + /// This decides the optimization mode for all zig-provided libraries, including /// compiler-rt, libcxx, libc, libunwind, etc. pub fn compilerRtOptMode(comp: Compilation) std.builtin.OptimizeMode { diff --git a/src/Sema.zig b/src/Sema.zig index 5816990eb2..41e1444420 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -8906,6 +8906,14 @@ fn resolveGenericBody( return sema.resolveConstDefinedValue(block, src, result, reason); } +/// Given a library name, examines if the library name should end up in +/// `link.File.Options.windows_libs` table (for example, libc is always +/// specified via dedicated flag `link_libc` instead), +/// and puts it there if it doesn't exist. +/// It also dupes the library name which can then be saved as part of the +/// respective `Decl` (either `ExternFn` or `Var`). +/// The liveness of the duped library name is tied to liveness of `Zcu`. +/// To deallocate, call `deinit` on the respective `Decl` (`ExternFn` or `Var`). pub fn handleExternLibName( sema: *Sema, block: *Block, @@ -8955,6 +8963,11 @@ pub fn handleExternLibName( .{ lib_name, lib_name }, ); } + comp.addLinkLib(lib_name) catch |err| { + return sema.fail(block, src_loc, "unable to add link lib '{s}': {s}", .{ + lib_name, @errorName(err), + }); + }; } } diff --git a/src/libs/mingw.zig b/src/libs/mingw.zig index 1c2927eba0..5603a15a57 100644 --- a/src/libs/mingw.zig +++ b/src/libs/mingw.zig @@ -1012,7 +1012,6 @@ const mingw32_winpthreads_src = [_][]const u8{ "winpthreads" ++ path.sep_str ++ "thread.c", }; -// Note: kernel32 and ntdll are always linked even without targeting MinGW-w64. pub const always_link_libs = [_][]const u8{ "api-ms-win-crt-conio-l1-1-0", "api-ms-win-crt-convert-l1-1-0", @@ -1030,6 +1029,8 @@ pub const always_link_libs = [_][]const u8{ "api-ms-win-crt-time-l1-1-0", "api-ms-win-crt-utility-l1-1-0", "advapi32", + "kernel32", + "ntdll", "shell32", "user32", }; diff --git a/src/main.zig b/src/main.zig index 0efa54ac1e..5bc6c2e923 100644 --- a/src/main.zig +++ b/src/main.zig @@ -312,7 +312,6 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { return jitCmd(gpa, arena, cmd_args, .{ .cmd_name = "resinator", .root_src_path = "resinator/main.zig", - .windows_libs = &.{"advapi32"}, .depend_on_aro = true, .prepend_zig_lib_dir_path = true, .server = use_server, @@ -337,7 +336,6 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { return jitCmd(gpa, arena, cmd_args, .{ .cmd_name = "std", .root_src_path = "std-docs.zig", - .windows_libs = &.{"ws2_32"}, .prepend_zig_lib_dir_path = true, .prepend_zig_exe_path = true, .prepend_global_cache_path = true, @@ -3659,6 +3657,7 @@ fn buildOutputType( } else if (target.os.tag == .windows) { try test_exec_args.appendSlice(arena, &.{ "--subsystem", "console", + "-lkernel32", "-lntdll", }); } @@ -3862,8 +3861,7 @@ fn createModule( .only_compiler_rt => continue, } - // We currently prefer import libraries provided by MinGW-w64 even for MSVC. - if (target.os.tag == .windows) { + if (target.isMinGW()) { const exists = mingw.libExists(arena, target, create_module.dirs.zig_lib, lib_name) catch |err| { fatal("failed to check zig installation for DLL import libs: {s}", .{ @errorName(err), @@ -5375,14 +5373,6 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { try root_mod.deps.put(arena, "@build", build_mod); - var windows_libs: std.StringArrayHashMapUnmanaged(void) = .empty; - - if (resolved_target.result.os.tag == .windows) { - try windows_libs.ensureUnusedCapacity(arena, 2); - windows_libs.putAssumeCapacity("advapi32", {}); - windows_libs.putAssumeCapacity("ws2_32", {}); // for `--listen` (web interface) - } - const comp = Compilation.create(gpa, arena, .{ .libc_installation = libc_installation, .dirs = dirs, @@ -5405,7 +5395,6 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { .cache_mode = .whole, .reference_trace = reference_trace, .debug_compile_errors = debug_compile_errors, - .windows_lib_names = windows_libs.keys(), }) catch |err| { fatal("unable to create compilation: {s}", .{@errorName(err)}); }; @@ -5509,7 +5498,6 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { const JitCmdOptions = struct { cmd_name: []const u8, root_src_path: []const u8, - windows_libs: []const []const u8 = &.{}, prepend_zig_lib_dir_path: bool = false, prepend_global_cache_path: bool = false, prepend_zig_exe_path: bool = false, @@ -5626,13 +5614,6 @@ fn jitCmd( try root_mod.deps.put(arena, "aro", aro_mod); } - var windows_libs: std.StringArrayHashMapUnmanaged(void) = .empty; - - if (resolved_target.result.os.tag == .windows) { - try windows_libs.ensureUnusedCapacity(arena, options.windows_libs.len); - for (options.windows_libs) |lib| windows_libs.putAssumeCapacity(lib, {}); - } - const comp = Compilation.create(gpa, arena, .{ .dirs = dirs, .root_name = options.cmd_name, @@ -5643,7 +5624,6 @@ fn jitCmd( .self_exe_path = self_exe_path, .thread_pool = &thread_pool, .cache_mode = .whole, - .windows_lib_names = windows_libs.keys(), }) catch |err| { fatal("unable to create compilation: {s}", .{@errorName(err)}); }; |
