authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-08-05 22:32:35+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-08-06 06:15:13+02:00
log7ee6dab39fac7aa12fa9fd952bb2bdc28d5eabe8
treeb97957e62077e78f6bf49836babcdb84b4ff772f
parent9a158c1dae531f2a4e5667569bed38c27cbd4d57

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.

10 files changed, 46 insertions(+), 78 deletions(-)

build.zig-20
......@@ -452,7 +452,6 @@ pub fn build(b: *std.Build) !void {
452452 .desc = "Run the behavior tests",
453453 .optimize_modes = optimization_modes,
454454 .include_paths = &.{},
455 .windows_libs = &.{},
456455 .skip_single_threaded = skip_single_threaded,
457456 .skip_non_native = skip_non_native,
458457 .skip_freebsd = skip_freebsd,
......@@ -475,7 +474,6 @@ pub fn build(b: *std.Build) !void {
475474 .desc = "Run the @cImport tests",
476475 .optimize_modes = optimization_modes,
477476 .include_paths = &.{"test/c_import"},
478 .windows_libs = &.{},
479477 .skip_single_threaded = true,
480478 .skip_non_native = skip_non_native,
481479 .skip_freebsd = skip_freebsd,
......@@ -496,7 +494,6 @@ pub fn build(b: *std.Build) !void {
496494 .desc = "Run the compiler_rt tests",
497495 .optimize_modes = optimization_modes,
498496 .include_paths = &.{},
499 .windows_libs = &.{},
500497 .skip_single_threaded = true,
501498 .skip_non_native = skip_non_native,
502499 .skip_freebsd = skip_freebsd,
......@@ -518,7 +515,6 @@ pub fn build(b: *std.Build) !void {
518515 .desc = "Run the zigc tests",
519516 .optimize_modes = optimization_modes,
520517 .include_paths = &.{},
521 .windows_libs = &.{},
522518 .skip_single_threaded = true,
523519 .skip_non_native = skip_non_native,
524520 .skip_freebsd = skip_freebsd,
......@@ -540,12 +536,6 @@ pub fn build(b: *std.Build) !void {
540536 .desc = "Run the standard library tests",
541537 .optimize_modes = optimization_modes,
542538 .include_paths = &.{},
543 .windows_libs = &.{
544 "advapi32",
545 "crypt32",
546 "iphlpapi",
547 "ws2_32",
548 },
549539 .skip_single_threaded = skip_single_threaded,
550540 .skip_non_native = skip_non_native,
551541 .skip_freebsd = skip_freebsd,
......@@ -743,12 +733,6 @@ fn addCompilerMod(b: *std.Build, options: AddCompilerModOptions) *std.Build.Modu
743733 compiler_mod.addImport("aro", aro_mod);
744734 compiler_mod.addImport("aro_translate_c", aro_translate_c_mod);
745735
746 if (options.target.result.os.tag == .windows) {
747 compiler_mod.linkSystemLibrary("advapi32", .{});
748 compiler_mod.linkSystemLibrary("crypt32", .{});
749 compiler_mod.linkSystemLibrary("ws2_32", .{});
750 }
751
752736 return compiler_mod;
753737}
754738
......@@ -1446,10 +1430,6 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath {
14461430 }),
14471431 });
14481432
1449 if (b.graph.host.result.os.tag == .windows) {
1450 doctest_exe.root_module.linkSystemLibrary("advapi32", .{});
1451 }
1452
14531433 var dir = b.build_root.handle.openDir("doc/langref", .{ .iterate = true }) catch |err| {
14541434 std.debug.panic("unable to open '{f}doc/langref' directory: {s}", .{
14551435 b.build_root, @errorName(err),
src/Compilation.zig+29-10
......@@ -2185,8 +2185,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
21852185 .emit_docs = try options.emit_docs.resolve(arena, &options, .docs),
21862186 };
21872187
2188 comp.windows_libs = try std.StringArrayHashMapUnmanaged(void).init(gpa, options.windows_lib_names, &.{});
2189 errdefer comp.windows_libs.deinit(gpa);
2188 errdefer {
2189 for (comp.windows_libs.keys()) |windows_lib| gpa.free(windows_lib);
2190 comp.windows_libs.deinit(gpa);
2191 }
2192 try comp.windows_libs.ensureUnusedCapacity(gpa, options.windows_lib_names.len);
2193 for (options.windows_lib_names) |windows_lib| comp.windows_libs.putAssumeCapacity(try gpa.dupe(u8, windows_lib), {});
21902194
21912195 // Prevent some footguns by making the "any" fields of config reflect
21922196 // the default Module settings.
......@@ -2417,13 +2421,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
24172421
24182422 if (comp.emit_bin != null and target.ofmt != .c) {
24192423 if (!comp.skip_linker_dependencies) {
2420 // These DLLs are always loaded into every Windows process.
2421 if (target.os.tag == .windows and is_exe_or_dyn_lib) {
2422 try comp.windows_libs.ensureUnusedCapacity(gpa, 2);
2423 comp.windows_libs.putAssumeCapacity("kernel32", {});
2424 comp.windows_libs.putAssumeCapacity("ntdll", {});
2425 }
2426
24272424 // If we need to build libc for the target, add work items for it.
24282425 // We go through the work queue so that building can be done in parallel.
24292426 // If linking against host libc installation, instead queue up jobs
......@@ -2512,7 +2509,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
25122509
25132510 // When linking mingw-w64 there are some import libs we always need.
25142511 try comp.windows_libs.ensureUnusedCapacity(gpa, mingw.always_link_libs.len);
2515 for (mingw.always_link_libs) |name| comp.windows_libs.putAssumeCapacity(name, {});
2512 for (mingw.always_link_libs) |name| comp.windows_libs.putAssumeCapacity(try gpa.dupe(u8, name), {});
25162513 } else {
25172514 return error.LibCUnavailable;
25182515 }
......@@ -2610,6 +2607,7 @@ pub fn destroy(comp: *Compilation) void {
26102607 comp.c_object_work_queue.deinit();
26112608 comp.win32_resource_work_queue.deinit();
26122609
2610 for (comp.windows_libs.keys()) |windows_lib| gpa.free(windows_lib);
26132611 comp.windows_libs.deinit(gpa);
26142612
26152613 {
......@@ -7795,6 +7793,27 @@ fn getCrtPathsInner(
77957793 };
77967794}
77977795
7796pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {
7797 // Avoid deadlocking on building import libs such as kernel32.lib
7798 // This can happen when the user uses `build-exe foo.obj -lkernel32` and
7799 // then when we create a sub-Compilation for zig libc, it also tries to
7800 // build kernel32.lib.
7801 if (comp.skip_linker_dependencies) return;
7802 const target = &comp.root_mod.resolved_target.result;
7803 if (target.os.tag != .windows or target.ofmt == .c) return;
7804
7805 // This happens when an `extern "foo"` function is referenced.
7806 // If we haven't seen this library yet and we're targeting Windows, we need
7807 // to queue up a work item to produce the DLL import library for this.
7808 const gop = try comp.windows_libs.getOrPut(comp.gpa, lib_name);
7809 if (gop.found_existing) return;
7810 {
7811 errdefer _ = comp.windows_libs.pop();
7812 gop.key_ptr.* = try comp.gpa.dupe(u8, lib_name);
7813 }
7814 try comp.queueJob(.{ .windows_import_lib = gop.index });
7815}
7816
77987817/// This decides the optimization mode for all zig-provided libraries, including
77997818/// compiler-rt, libcxx, libc, libunwind, etc.
78007819pub fn compilerRtOptMode(comp: Compilation) std.builtin.OptimizeMode {
src/Sema.zig+13
......@@ -8906,6 +8906,14 @@ fn resolveGenericBody(
89068906 return sema.resolveConstDefinedValue(block, src, result, reason);
89078907}
89088908
8909/// Given a library name, examines if the library name should end up in
8910/// `link.File.Options.windows_libs` table (for example, libc is always
8911/// specified via dedicated flag `link_libc` instead),
8912/// and puts it there if it doesn't exist.
8913/// It also dupes the library name which can then be saved as part of the
8914/// respective `Decl` (either `ExternFn` or `Var`).
8915/// The liveness of the duped library name is tied to liveness of `Zcu`.
8916/// To deallocate, call `deinit` on the respective `Decl` (`ExternFn` or `Var`).
89098917pub fn handleExternLibName(
89108918 sema: *Sema,
89118919 block: *Block,
......@@ -8955,6 +8963,11 @@ pub fn handleExternLibName(
89558963 .{ lib_name, lib_name },
89568964 );
89578965 }
8966 comp.addLinkLib(lib_name) catch |err| {
8967 return sema.fail(block, src_loc, "unable to add link lib '{s}': {s}", .{
8968 lib_name, @errorName(err),
8969 });
8970 };
89588971 }
89598972}
89608973
src/libs/mingw.zig+2-1
......@@ -1012,7 +1012,6 @@ const mingw32_winpthreads_src = [_][]const u8{
10121012 "winpthreads" ++ path.sep_str ++ "thread.c",
10131013};
10141014
1015// Note: kernel32 and ntdll are always linked even without targeting MinGW-w64.
10161015pub const always_link_libs = [_][]const u8{
10171016 "api-ms-win-crt-conio-l1-1-0",
10181017 "api-ms-win-crt-convert-l1-1-0",
......@@ -1030,6 +1029,8 @@ pub const always_link_libs = [_][]const u8{
10301029 "api-ms-win-crt-time-l1-1-0",
10311030 "api-ms-win-crt-utility-l1-1-0",
10321031 "advapi32",
1032 "kernel32",
1033 "ntdll",
10331034 "shell32",
10341035 "user32",
10351036};
src/main.zig+2-22
......@@ -312,7 +312,6 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
312312 return jitCmd(gpa, arena, cmd_args, .{
313313 .cmd_name = "resinator",
314314 .root_src_path = "resinator/main.zig",
315 .windows_libs = &.{"advapi32"},
316315 .depend_on_aro = true,
317316 .prepend_zig_lib_dir_path = true,
318317 .server = use_server,
......@@ -337,7 +336,6 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
337336 return jitCmd(gpa, arena, cmd_args, .{
338337 .cmd_name = "std",
339338 .root_src_path = "std-docs.zig",
340 .windows_libs = &.{"ws2_32"},
341339 .prepend_zig_lib_dir_path = true,
342340 .prepend_zig_exe_path = true,
343341 .prepend_global_cache_path = true,
......@@ -3659,6 +3657,7 @@ fn buildOutputType(
36593657 } else if (target.os.tag == .windows) {
36603658 try test_exec_args.appendSlice(arena, &.{
36613659 "--subsystem", "console",
3660 "-lkernel32", "-lntdll",
36623661 });
36633662 }
36643663
......@@ -3862,8 +3861,7 @@ fn createModule(
38623861 .only_compiler_rt => continue,
38633862 }
38643863
3865 // We currently prefer import libraries provided by MinGW-w64 even for MSVC.
3866 if (target.os.tag == .windows) {
3864 if (target.isMinGW()) {
38673865 const exists = mingw.libExists(arena, target, create_module.dirs.zig_lib, lib_name) catch |err| {
38683866 fatal("failed to check zig installation for DLL import libs: {s}", .{
38693867 @errorName(err),
......@@ -5375,14 +5373,6 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
53755373
53765374 try root_mod.deps.put(arena, "@build", build_mod);
53775375
5378 var windows_libs: std.StringArrayHashMapUnmanaged(void) = .empty;
5379
5380 if (resolved_target.result.os.tag == .windows) {
5381 try windows_libs.ensureUnusedCapacity(arena, 2);
5382 windows_libs.putAssumeCapacity("advapi32", {});
5383 windows_libs.putAssumeCapacity("ws2_32", {}); // for `--listen` (web interface)
5384 }
5385
53865376 const comp = Compilation.create(gpa, arena, .{
53875377 .libc_installation = libc_installation,
53885378 .dirs = dirs,
......@@ -5405,7 +5395,6 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
54055395 .cache_mode = .whole,
54065396 .reference_trace = reference_trace,
54075397 .debug_compile_errors = debug_compile_errors,
5408 .windows_lib_names = windows_libs.keys(),
54095398 }) catch |err| {
54105399 fatal("unable to create compilation: {s}", .{@errorName(err)});
54115400 };
......@@ -5509,7 +5498,6 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
55095498const JitCmdOptions = struct {
55105499 cmd_name: []const u8,
55115500 root_src_path: []const u8,
5512 windows_libs: []const []const u8 = &.{},
55135501 prepend_zig_lib_dir_path: bool = false,
55145502 prepend_global_cache_path: bool = false,
55155503 prepend_zig_exe_path: bool = false,
......@@ -5626,13 +5614,6 @@ fn jitCmd(
56265614 try root_mod.deps.put(arena, "aro", aro_mod);
56275615 }
56285616
5629 var windows_libs: std.StringArrayHashMapUnmanaged(void) = .empty;
5630
5631 if (resolved_target.result.os.tag == .windows) {
5632 try windows_libs.ensureUnusedCapacity(arena, options.windows_libs.len);
5633 for (options.windows_libs) |lib| windows_libs.putAssumeCapacity(lib, {});
5634 }
5635
56365617 const comp = Compilation.create(gpa, arena, .{
56375618 .dirs = dirs,
56385619 .root_name = options.cmd_name,
......@@ -5643,7 +5624,6 @@ fn jitCmd(
56435624 .self_exe_path = self_exe_path,
56445625 .thread_pool = &thread_pool,
56455626 .cache_mode = .whole,
5646 .windows_lib_names = windows_libs.keys(),
56475627 }) catch |err| {
56485628 fatal("unable to create compilation: {s}", .{@errorName(err)});
56495629 };
test/standalone/simple/build.zig-8
......@@ -50,10 +50,6 @@ pub fn build(b: *std.Build) void {
5050 });
5151 if (case.link_libc) exe.root_module.link_libc = true;
5252
53 if (resolved_target.result.os.tag == .windows) {
54 exe.root_module.linkSystemLibrary("advapi32", .{});
55 }
56
5753 _ = exe.getEmittedBin();
5854
5955 step.dependOn(&exe.step);
......@@ -70,10 +66,6 @@ pub fn build(b: *std.Build) void {
7066 });
7167 if (case.link_libc) exe.root_module.link_libc = true;
7268
73 if (resolved_target.result.os.tag == .windows) {
74 exe.root_module.linkSystemLibrary("advapi32", .{});
75 }
76
7769 const run = b.addRunArtifact(exe);
7870 step.dependOn(&run.step);
7971 }
test/standalone/windows_argv/build.zig-2
......@@ -47,8 +47,6 @@ pub fn build(b: *std.Build) !void {
4747 }),
4848 });
4949
50 fuzz.root_module.linkSystemLibrary("advapi32", .{});
51
5250 const fuzz_max_iterations = b.option(u64, "iterations", "The max fuzz iterations (default: 100)") orelse 100;
5351 const fuzz_iterations_arg = std.fmt.allocPrint(b.allocator, "{}", .{fuzz_max_iterations}) catch @panic("oom");
5452
test/standalone/windows_bat_args/build.zig-4
......@@ -28,8 +28,6 @@ pub fn build(b: *std.Build) !void {
2828 }),
2929 });
3030
31 test_exe.root_module.linkSystemLibrary("advapi32", .{});
32
3331 const run = b.addRunArtifact(test_exe);
3432 run.addArtifactArg(echo_args);
3533 run.expectExitCode(0);
......@@ -46,8 +44,6 @@ pub fn build(b: *std.Build) !void {
4644 }),
4745 });
4846
49 fuzz.root_module.linkSystemLibrary("advapi32", .{});
50
5147 const fuzz_max_iterations = b.option(u64, "iterations", "The max fuzz iterations (default: 100)") orelse 100;
5248 const fuzz_iterations_arg = std.fmt.allocPrint(b.allocator, "{}", .{fuzz_max_iterations}) catch @panic("oom");
5349
test/standalone/windows_spawn/build.zig-2
......@@ -28,8 +28,6 @@ pub fn build(b: *std.Build) void {
2828 }),
2929 });
3030
31 main.root_module.linkSystemLibrary("advapi32", .{});
32
3331 const run = b.addRunArtifact(main);
3432 run.addArtifactArg(hello);
3533 run.expectExitCode(0);
test/tests.zig-9
......@@ -2238,7 +2238,6 @@ const ModuleTestOptions = struct {
22382238 desc: []const u8,
22392239 optimize_modes: []const OptimizeMode,
22402240 include_paths: []const []const u8,
2241 windows_libs: []const []const u8,
22422241 skip_single_threaded: bool,
22432242 skip_non_native: bool,
22442243 skip_freebsd: bool,
......@@ -2373,10 +2372,6 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
23732372
23742373 for (options.include_paths) |include_path| these_tests.root_module.addIncludePath(b.path(include_path));
23752374
2376 if (target.os.tag == .windows) {
2377 for (options.windows_libs) |lib| these_tests.root_module.linkSystemLibrary(lib, .{});
2378 }
2379
23802375 const qualified_name = b.fmt("{s}-{s}-{s}-{s}{s}{s}{s}{s}{s}{s}", .{
23812376 options.name,
23822377 triple_txt,
......@@ -2672,10 +2667,6 @@ pub fn addIncrementalTests(b: *std.Build, test_step: *Step) !void {
26722667 }),
26732668 });
26742669
2675 if (b.graph.host.result.os.tag == .windows) {
2676 incr_check.root_module.linkSystemLibrary("advapi32", .{});
2677 }
2678
26792670 var dir = try b.build_root.handle.openDir("test/incremental", .{ .iterate = true });
26802671 defer dir.close();
26812672