Skip to content

Commit b461d07

Browse files
committed
Sema: Stop adding Windows implib link inputs for extern "..." syntax.
Closes #23971.
1 parent 044ccf4 commit b461d07

File tree

10 files changed

+75
-46
lines changed

10 files changed

+75
-46
lines changed

build.zig

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ pub fn build(b: *std.Build) !void {
450450
.desc = "Run the behavior tests",
451451
.optimize_modes = optimization_modes,
452452
.include_paths = &.{},
453+
.windows_libs = &.{},
453454
.skip_single_threaded = skip_single_threaded,
454455
.skip_non_native = skip_non_native,
455456
.skip_freebsd = skip_freebsd,
@@ -472,6 +473,7 @@ pub fn build(b: *std.Build) !void {
472473
.desc = "Run the @cImport tests",
473474
.optimize_modes = optimization_modes,
474475
.include_paths = &.{"test/c_import"},
476+
.windows_libs = &.{},
475477
.skip_single_threaded = true,
476478
.skip_non_native = skip_non_native,
477479
.skip_freebsd = skip_freebsd,
@@ -492,6 +494,7 @@ pub fn build(b: *std.Build) !void {
492494
.desc = "Run the compiler_rt tests",
493495
.optimize_modes = optimization_modes,
494496
.include_paths = &.{},
497+
.windows_libs = &.{},
495498
.skip_single_threaded = true,
496499
.skip_non_native = skip_non_native,
497500
.skip_freebsd = skip_freebsd,
@@ -513,6 +516,7 @@ pub fn build(b: *std.Build) !void {
513516
.desc = "Run the zigc tests",
514517
.optimize_modes = optimization_modes,
515518
.include_paths = &.{},
519+
.windows_libs = &.{},
516520
.skip_single_threaded = true,
517521
.skip_non_native = skip_non_native,
518522
.skip_freebsd = skip_freebsd,
@@ -534,6 +538,12 @@ pub fn build(b: *std.Build) !void {
534538
.desc = "Run the standard library tests",
535539
.optimize_modes = optimization_modes,
536540
.include_paths = &.{},
541+
.windows_libs = &.{
542+
"advapi32",
543+
"crypt32",
544+
"iphlpapi",
545+
"ws2_32",
546+
},
537547
.skip_single_threaded = skip_single_threaded,
538548
.skip_non_native = skip_non_native,
539549
.skip_freebsd = skip_freebsd,
@@ -731,6 +741,12 @@ fn addCompilerMod(b: *std.Build, options: AddCompilerModOptions) *std.Build.Modu
731741
compiler_mod.addImport("aro", aro_mod);
732742
compiler_mod.addImport("aro_translate_c", aro_translate_c_mod);
733743

744+
if (options.target.result.os.tag == .windows) {
745+
compiler_mod.linkSystemLibrary("advapi32", .{});
746+
compiler_mod.linkSystemLibrary("crypt32", .{});
747+
compiler_mod.linkSystemLibrary("ws2_32", .{});
748+
}
749+
734750
return compiler_mod;
735751
}
736752

@@ -1428,6 +1444,10 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath {
14281444
}),
14291445
});
14301446

1447+
if (b.graph.host.result.os.tag == .windows) {
1448+
doctest_exe.root_module.linkSystemLibrary("advapi32", .{});
1449+
}
1450+
14311451
var dir = b.build_root.handle.openDir("doc/langref", .{ .iterate = true }) catch |err| {
14321452
std.debug.panic("unable to open '{}doc/langref' directory: {s}", .{
14331453
b.build_root, @errorName(err),

src/Compilation.zig

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2070,12 +2070,8 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
20702070
.emit_docs = try options.emit_docs.resolve(arena, &options, .docs),
20712071
};
20722072

2073-
errdefer {
2074-
for (comp.windows_libs.keys()) |windows_lib| gpa.free(windows_lib);
2075-
comp.windows_libs.deinit(gpa);
2076-
}
2077-
try comp.windows_libs.ensureUnusedCapacity(gpa, options.windows_lib_names.len);
2078-
for (options.windows_lib_names) |windows_lib| comp.windows_libs.putAssumeCapacity(try gpa.dupe(u8, windows_lib), {});
2073+
comp.windows_libs = try std.StringArrayHashMapUnmanaged(void).init(gpa, options.windows_lib_names, &.{});
2074+
errdefer comp.windows_libs.deinit(gpa);
20792075

20802076
// Prevent some footguns by making the "any" fields of config reflect
20812077
// the default Module settings.
@@ -2306,6 +2302,13 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
23062302

23072303
if (comp.emit_bin != null and target.ofmt != .c) {
23082304
if (!comp.skip_linker_dependencies) {
2305+
// These DLLs are always loaded into every Windows process.
2306+
if (target.os.tag == .windows and is_exe_or_dyn_lib) {
2307+
try comp.windows_libs.ensureUnusedCapacity(gpa, 2);
2308+
comp.windows_libs.putAssumeCapacity("kernel32", {});
2309+
comp.windows_libs.putAssumeCapacity("ntdll", {});
2310+
}
2311+
23092312
// If we need to build libc for the target, add work items for it.
23102313
// We go through the work queue so that building can be done in parallel.
23112314
// If linking against host libc installation, instead queue up jobs
@@ -2399,7 +2402,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
23992402

24002403
// When linking mingw-w64 there are some import libs we always need.
24012404
try comp.windows_libs.ensureUnusedCapacity(gpa, mingw.always_link_libs.len);
2402-
for (mingw.always_link_libs) |name| comp.windows_libs.putAssumeCapacity(try gpa.dupe(u8, name), {});
2405+
for (mingw.always_link_libs) |name| comp.windows_libs.putAssumeCapacity(name, {});
24032406
} else {
24042407
return error.LibCUnavailable;
24052408
}
@@ -2497,7 +2500,6 @@ pub fn destroy(comp: *Compilation) void {
24972500
comp.c_object_work_queue.deinit();
24982501
comp.win32_resource_work_queue.deinit();
24992502

2500-
for (comp.windows_libs.keys()) |windows_lib| gpa.free(windows_lib);
25012503
comp.windows_libs.deinit(gpa);
25022504

25032505
{
@@ -7599,27 +7601,6 @@ fn getCrtPathsInner(
75997601
};
76007602
}
76017603

7602-
pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {
7603-
// Avoid deadlocking on building import libs such as kernel32.lib
7604-
// This can happen when the user uses `build-exe foo.obj -lkernel32` and
7605-
// then when we create a sub-Compilation for zig libc, it also tries to
7606-
// build kernel32.lib.
7607-
if (comp.skip_linker_dependencies) return;
7608-
const target = &comp.root_mod.resolved_target.result;
7609-
if (target.os.tag != .windows or target.ofmt == .c) return;
7610-
7611-
// This happens when an `extern "foo"` function is referenced.
7612-
// If we haven't seen this library yet and we're targeting Windows, we need
7613-
// to queue up a work item to produce the DLL import library for this.
7614-
const gop = try comp.windows_libs.getOrPut(comp.gpa, lib_name);
7615-
if (gop.found_existing) return;
7616-
{
7617-
errdefer _ = comp.windows_libs.pop();
7618-
gop.key_ptr.* = try comp.gpa.dupe(u8, lib_name);
7619-
}
7620-
try comp.queueJob(.{ .windows_import_lib = gop.index });
7621-
}
7622-
76237604
/// This decides the optimization mode for all zig-provided libraries, including
76247605
/// compiler-rt, libcxx, libc, libunwind, etc.
76257606
pub fn compilerRtOptMode(comp: Compilation) std.builtin.OptimizeMode {

src/Sema.zig

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9418,14 +9418,6 @@ fn resolveGenericBody(
94189418
return sema.resolveConstDefinedValue(block, src, result, reason);
94199419
}
94209420

9421-
/// Given a library name, examines if the library name should end up in
9422-
/// `link.File.Options.windows_libs` table (for example, libc is always
9423-
/// specified via dedicated flag `link_libc` instead),
9424-
/// and puts it there if it doesn't exist.
9425-
/// It also dupes the library name which can then be saved as part of the
9426-
/// respective `Decl` (either `ExternFn` or `Var`).
9427-
/// The liveness of the duped library name is tied to liveness of `Zcu`.
9428-
/// To deallocate, call `deinit` on the respective `Decl` (`ExternFn` or `Var`).
94299421
pub fn handleExternLibName(
94309422
sema: *Sema,
94319423
block: *Block,
@@ -9475,11 +9467,6 @@ pub fn handleExternLibName(
94759467
.{ lib_name, lib_name },
94769468
);
94779469
}
9478-
comp.addLinkLib(lib_name) catch |err| {
9479-
return sema.fail(block, src_loc, "unable to add link lib '{s}': {s}", .{
9480-
lib_name, @errorName(err),
9481-
});
9482-
};
94839470
}
94849471
}
94859472

src/libs/mingw.zig

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,7 @@ 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.
10151016
pub const always_link_libs = [_][]const u8{
10161017
"api-ms-win-crt-conio-l1-1-0",
10171018
"api-ms-win-crt-convert-l1-1-0",
@@ -1029,8 +1030,6 @@ pub const always_link_libs = [_][]const u8{
10291030
"api-ms-win-crt-time-l1-1-0",
10301031
"api-ms-win-crt-utility-l1-1-0",
10311032
"advapi32",
1032-
"kernel32",
1033-
"ntdll",
10341033
"shell32",
10351034
"user32",
10361035
};

src/main.zig

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
306306
return jitCmd(gpa, arena, cmd_args, .{
307307
.cmd_name = "resinator",
308308
.root_src_path = "resinator/main.zig",
309+
.windows_libs = &.{"advapi32"},
309310
.depend_on_aro = true,
310311
.prepend_zig_lib_dir_path = true,
311312
.server = use_server,
@@ -3631,7 +3632,6 @@ fn buildOutputType(
36313632
} else if (target.os.tag == .windows) {
36323633
try test_exec_args.appendSlice(arena, &.{
36333634
"--subsystem", "console",
3634-
"-lkernel32", "-lntdll",
36353635
});
36363636
}
36373637

@@ -3845,7 +3845,8 @@ fn createModule(
38453845
.only_compiler_rt => continue,
38463846
}
38473847

3848-
if (target.isMinGW()) {
3848+
// We currently prefer import libraries provided by MinGW-w64 even for MSVC.
3849+
if (target.os.tag == .windows) {
38493850
const exists = mingw.libExists(arena, target, create_module.dirs.zig_lib, lib_name) catch |err| {
38503851
fatal("failed to check zig installation for DLL import libs: {s}", .{
38513852
@errorName(err),
@@ -5221,6 +5222,12 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
52215222

52225223
try root_mod.deps.put(arena, "@build", build_mod);
52235224

5225+
var windows_libs: std.StringArrayHashMapUnmanaged(void) = .empty;
5226+
5227+
if (resolved_target.result.os.tag == .windows) {
5228+
try windows_libs.put(arena, "advapi32", {});
5229+
}
5230+
52245231
const comp = Compilation.create(gpa, arena, .{
52255232
.dirs = dirs,
52265233
.root_name = "build",
@@ -5242,6 +5249,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
52425249
.cache_mode = .whole,
52435250
.reference_trace = reference_trace,
52445251
.debug_compile_errors = debug_compile_errors,
5252+
.windows_lib_names = windows_libs.keys(),
52455253
}) catch |err| {
52465254
fatal("unable to create compilation: {s}", .{@errorName(err)});
52475255
};
@@ -5345,6 +5353,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
53455353
const JitCmdOptions = struct {
53465354
cmd_name: []const u8,
53475355
root_src_path: []const u8,
5356+
windows_libs: []const []const u8 = &.{},
53485357
prepend_zig_lib_dir_path: bool = false,
53495358
prepend_global_cache_path: bool = false,
53505359
prepend_zig_exe_path: bool = false,
@@ -5461,6 +5470,13 @@ fn jitCmd(
54615470
try root_mod.deps.put(arena, "aro", aro_mod);
54625471
}
54635472

5473+
var windows_libs: std.StringArrayHashMapUnmanaged(void) = .empty;
5474+
5475+
if (resolved_target.result.os.tag == .windows) {
5476+
try windows_libs.ensureUnusedCapacity(arena, options.windows_libs.len);
5477+
for (options.windows_libs) |lib| windows_libs.putAssumeCapacity(lib, {});
5478+
}
5479+
54645480
const comp = Compilation.create(gpa, arena, .{
54655481
.dirs = dirs,
54665482
.root_name = options.cmd_name,
@@ -5471,6 +5487,7 @@ fn jitCmd(
54715487
.self_exe_path = self_exe_path,
54725488
.thread_pool = &thread_pool,
54735489
.cache_mode = .whole,
5490+
.windows_lib_names = windows_libs.keys(),
54745491
}) catch |err| {
54755492
fatal("unable to create compilation: {s}", .{@errorName(err)});
54765493
};

test/standalone/simple/build.zig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ 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+
5357
_ = exe.getEmittedBin();
5458

5559
step.dependOn(&exe.step);
@@ -66,6 +70,10 @@ pub fn build(b: *std.Build) void {
6670
});
6771
if (case.link_libc) exe.root_module.link_libc = true;
6872

73+
if (resolved_target.result.os.tag == .windows) {
74+
exe.root_module.linkSystemLibrary("advapi32", .{});
75+
}
76+
6977
const run = b.addRunArtifact(exe);
7078
step.dependOn(&run.step);
7179
}

test/standalone/windows_argv/build.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ pub fn build(b: *std.Build) !void {
4747
}),
4848
});
4949

50+
fuzz.root_module.linkSystemLibrary("advapi32", .{});
51+
5052
const fuzz_max_iterations = b.option(u64, "iterations", "The max fuzz iterations (default: 100)") orelse 100;
5153
const fuzz_iterations_arg = std.fmt.allocPrint(b.allocator, "{}", .{fuzz_max_iterations}) catch @panic("oom");
5254

test/standalone/windows_bat_args/build.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ pub fn build(b: *std.Build) !void {
2828
}),
2929
});
3030

31+
test_exe.root_module.linkSystemLibrary("advapi32", .{});
32+
3133
const run = b.addRunArtifact(test_exe);
3234
run.addArtifactArg(echo_args);
3335
run.expectExitCode(0);
@@ -44,6 +46,8 @@ pub fn build(b: *std.Build) !void {
4446
}),
4547
});
4648

49+
fuzz.root_module.linkSystemLibrary("advapi32", .{});
50+
4751
const fuzz_max_iterations = b.option(u64, "iterations", "The max fuzz iterations (default: 100)") orelse 100;
4852
const fuzz_iterations_arg = std.fmt.allocPrint(b.allocator, "{}", .{fuzz_max_iterations}) catch @panic("oom");
4953

test/standalone/windows_spawn/build.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ pub fn build(b: *std.Build) void {
2828
}),
2929
});
3030

31+
main.root_module.linkSystemLibrary("advapi32", .{});
32+
3133
const run = b.addRunArtifact(main);
3234
run.addArtifactArg(hello);
3335
run.expectExitCode(0);

test/tests.zig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2308,6 +2308,7 @@ const ModuleTestOptions = struct {
23082308
desc: []const u8,
23092309
optimize_modes: []const OptimizeMode,
23102310
include_paths: []const []const u8,
2311+
windows_libs: []const []const u8,
23112312
skip_single_threaded: bool,
23122313
skip_non_native: bool,
23132314
skip_freebsd: bool,
@@ -2437,6 +2438,10 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
24372438

24382439
for (options.include_paths) |include_path| these_tests.addIncludePath(b.path(include_path));
24392440

2441+
if (target.os.tag == .windows) {
2442+
for (options.windows_libs) |lib| these_tests.linkSystemLibrary(lib);
2443+
}
2444+
24402445
const qualified_name = b.fmt("{s}-{s}-{s}-{s}{s}{s}{s}{s}{s}{s}", .{
24412446
options.name,
24422447
triple_txt,
@@ -2732,6 +2737,10 @@ pub fn addIncrementalTests(b: *std.Build, test_step: *Step) !void {
27322737
}),
27332738
});
27342739

2740+
if (b.graph.host.result.os.tag == .windows) {
2741+
incr_check.root_module.linkSystemLibrary("advapi32", .{});
2742+
}
2743+
27352744
var dir = try b.build_root.handle.openDir("test/incremental", .{ .iterate = true });
27362745
defer dir.close();
27372746

0 commit comments

Comments
 (0)