aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlex Rønne Petersen <alex@alexrp.com>2025-08-05 22:32:35 +0200
committerAlex Rønne Petersen <alex@alexrp.com>2025-08-06 06:15:13 +0200
commit7ee6dab39fac7aa12fa9fd952bb2bdc28d5eabe8 (patch)
treeb97957e62077e78f6bf49836babcdb84b4ff772f /src
parent9a158c1dae531f2a4e5667569bed38c27cbd4d57 (diff)
downloadzig-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.zig39
-rw-r--r--src/Sema.zig13
-rw-r--r--src/libs/mingw.zig3
-rw-r--r--src/main.zig24
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)});
};