Skip to content

Sema: Stop adding Windows implib link inputs for extern "..." syntax. #24146

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ pub fn build(b: *std.Build) !void {
.desc = "Run the behavior tests",
.optimize_modes = optimization_modes,
.include_paths = &.{},
.windows_libs = &.{},
.skip_single_threaded = skip_single_threaded,
.skip_non_native = skip_non_native,
.skip_freebsd = skip_freebsd,
Expand All @@ -461,6 +462,7 @@ pub fn build(b: *std.Build) !void {
.desc = "Run the @cImport tests",
.optimize_modes = optimization_modes,
.include_paths = &.{"test/c_import"},
.windows_libs = &.{},
.skip_single_threaded = true,
.skip_non_native = skip_non_native,
.skip_freebsd = skip_freebsd,
Expand All @@ -481,6 +483,7 @@ pub fn build(b: *std.Build) !void {
.desc = "Run the compiler_rt tests",
.optimize_modes = optimization_modes,
.include_paths = &.{},
.windows_libs = &.{},
.skip_single_threaded = true,
.skip_non_native = skip_non_native,
.skip_freebsd = skip_freebsd,
Expand All @@ -502,6 +505,7 @@ pub fn build(b: *std.Build) !void {
.desc = "Run the zigc tests",
.optimize_modes = optimization_modes,
.include_paths = &.{},
.windows_libs = &.{},
.skip_single_threaded = true,
.skip_non_native = skip_non_native,
.skip_freebsd = skip_freebsd,
Expand All @@ -523,6 +527,12 @@ pub fn build(b: *std.Build) !void {
.desc = "Run the standard library tests",
.optimize_modes = optimization_modes,
.include_paths = &.{},
.windows_libs = &.{
"advapi32",
"crypt32",
"iphlpapi",
"ws2_32",
},
.skip_single_threaded = skip_single_threaded,
.skip_non_native = skip_non_native,
.skip_freebsd = skip_freebsd,
Expand Down Expand Up @@ -720,6 +730,12 @@ fn addCompilerMod(b: *std.Build, options: AddCompilerModOptions) *std.Build.Modu
compiler_mod.addImport("aro", aro_mod);
compiler_mod.addImport("aro_translate_c", aro_translate_c_mod);

if (options.target.result.os.tag == .windows) {
compiler_mod.linkSystemLibrary("advapi32", .{});
compiler_mod.linkSystemLibrary("crypt32", .{});
compiler_mod.linkSystemLibrary("ws2_32", .{});
}

return compiler_mod;
}

Expand Down Expand Up @@ -1417,6 +1433,10 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath {
}),
});

if (b.graph.host.result.os.tag == .windows) {
doctest_exe.root_module.linkSystemLibrary("advapi32", .{});
}

var dir = b.build_root.handle.openDir("doc/langref", .{ .iterate = true }) catch |err| {
std.debug.panic("unable to open '{}doc/langref' directory: {s}", .{
b.build_root, @errorName(err),
Expand Down
4 changes: 2 additions & 2 deletions lib/std/start.zig
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ fn _start() callconv(.naked) noreturn {

fn WinStartup() callconv(.withStackAlign(.c, 1)) noreturn {
// Switch from the x87 fpu state set by windows to the state expected by the gnu abi.
if (builtin.abi == .gnu) asm volatile ("fninit");
if (builtin.cpu.arch.isX86() and builtin.abi == .gnu) asm volatile ("fninit");

if (!builtin.single_threaded and !builtin.link_libc) {
_ = @import("os/windows/tls.zig");
Expand All @@ -499,7 +499,7 @@ fn WinStartup() callconv(.withStackAlign(.c, 1)) noreturn {

fn wWinMainCRTStartup() callconv(.withStackAlign(.c, 1)) noreturn {
// Switch from the x87 fpu state set by windows to the state expected by the gnu abi.
if (builtin.abi == .gnu) asm volatile ("fninit");
if (builtin.cpu.arch.isX86() and builtin.abi == .gnu) asm volatile ("fninit");

if (!builtin.single_threaded and !builtin.link_libc) {
_ = @import("os/windows/tls.zig");
Expand Down
39 changes: 10 additions & 29 deletions src/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2070,12 +2070,8 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
.emit_docs = try options.emit_docs.resolve(arena, &options, .docs),
};

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), {});
comp.windows_libs = try std.StringArrayHashMapUnmanaged(void).init(gpa, options.windows_lib_names, &.{});
errdefer comp.windows_libs.deinit(gpa);

// Prevent some footguns by making the "any" fields of config reflect
// the default Module settings.
Expand Down Expand Up @@ -2306,6 +2302,13 @@ 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
Expand Down Expand Up @@ -2399,7 +2402,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(try gpa.dupe(u8, name), {});
for (mingw.always_link_libs) |name| comp.windows_libs.putAssumeCapacity(name, {});
} else {
return error.LibCUnavailable;
}
Expand Down Expand Up @@ -2497,7 +2500,6 @@ 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);

{
Expand Down Expand Up @@ -7595,27 +7597,6 @@ 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 {
Expand Down
13 changes: 0 additions & 13 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9409,14 +9409,6 @@ 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,
Expand Down Expand Up @@ -9466,11 +9458,6 @@ 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),
});
};
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/libs/mingw.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,7 @@ 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",
Expand All @@ -1031,8 +1032,6 @@ 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",
};
21 changes: 19 additions & 2 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ 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,
Expand Down Expand Up @@ -3631,7 +3632,6 @@ fn buildOutputType(
} else if (target.os.tag == .windows) {
try test_exec_args.appendSlice(arena, &.{
"--subsystem", "console",
"-lkernel32", "-lntdll",
});
}

Expand Down Expand Up @@ -3845,7 +3845,8 @@ fn createModule(
.only_compiler_rt => continue,
}

if (target.isMinGW()) {
// We currently prefer import libraries provided by MinGW-w64 even for MSVC.
if (target.os.tag == .windows) {
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),
Expand Down Expand Up @@ -5221,6 +5222,12 @@ 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.put(arena, "advapi32", {});
}

const comp = Compilation.create(gpa, arena, .{
.dirs = dirs,
.root_name = "build",
Expand All @@ -5242,6 +5249,7 @@ 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)});
};
Expand Down Expand Up @@ -5345,6 +5353,7 @@ 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,
Expand Down Expand Up @@ -5461,6 +5470,13 @@ 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,
Expand All @@ -5471,6 +5487,7 @@ 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)});
};
Expand Down
8 changes: 8 additions & 0 deletions test/standalone/simple/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ pub fn build(b: *std.Build) void {
});
if (case.link_libc) exe.root_module.link_libc = true;

if (resolved_target.result.os.tag == .windows) {
exe.root_module.linkSystemLibrary("advapi32", .{});
}

_ = exe.getEmittedBin();

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

if (resolved_target.result.os.tag == .windows) {
exe.root_module.linkSystemLibrary("advapi32", .{});
}

const run = b.addRunArtifact(exe);
step.dependOn(&run.step);
}
Expand Down
2 changes: 2 additions & 0 deletions test/standalone/windows_argv/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ pub fn build(b: *std.Build) !void {
}),
});

fuzz.root_module.linkSystemLibrary("advapi32", .{});

const fuzz_max_iterations = b.option(u64, "iterations", "The max fuzz iterations (default: 100)") orelse 100;
const fuzz_iterations_arg = std.fmt.allocPrint(b.allocator, "{}", .{fuzz_max_iterations}) catch @panic("oom");

Expand Down
4 changes: 4 additions & 0 deletions test/standalone/windows_bat_args/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub fn build(b: *std.Build) !void {
}),
});

test_exe.root_module.linkSystemLibrary("advapi32", .{});

const run = b.addRunArtifact(test_exe);
run.addArtifactArg(echo_args);
run.expectExitCode(0);
Expand All @@ -44,6 +46,8 @@ pub fn build(b: *std.Build) !void {
}),
});

fuzz.root_module.linkSystemLibrary("advapi32", .{});

const fuzz_max_iterations = b.option(u64, "iterations", "The max fuzz iterations (default: 100)") orelse 100;
const fuzz_iterations_arg = std.fmt.allocPrint(b.allocator, "{}", .{fuzz_max_iterations}) catch @panic("oom");

Expand Down
2 changes: 2 additions & 0 deletions test/standalone/windows_spawn/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub fn build(b: *std.Build) void {
}),
});

main.root_module.linkSystemLibrary("advapi32", .{});

const run = b.addRunArtifact(main);
run.addArtifactArg(hello);
run.expectExitCode(0);
Expand Down
Loading