diff --git a/src/Compilation.zig b/src/Compilation.zig index f966f1e17f..0c8b3c5248 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -5618,6 +5618,11 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void { // to queue up a work item to produce the DLL import library for this. const gop = try comp.bin_file.options.system_libs.getOrPut(comp.gpa, lib_name); if (!gop.found_existing and comp.getTarget().os.tag == .windows) { + gop.value_ptr.* = .{ + .needed = true, + .weak = false, + .path = undefined, + }; try comp.work_queue.writeItem(.{ .windows_import_lib = comp.bin_file.options.system_libs.count() - 1, }); diff --git a/src/main.zig b/src/main.zig index 83e1e2bc38..797a33a20b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -28,6 +28,7 @@ const target_util = @import("target.zig"); const crash_report = @import("crash_report.zig"); const Module = @import("Module.zig"); const AstGen = @import("AstGen.zig"); +const mingw = @import("mingw.zig"); const Server = std.zig.Server; pub const std_options = struct { @@ -477,6 +478,8 @@ const usage_build_generic = \\ -needed-l[lib], Link against system library (even if unused) \\ --needed-library [lib] \\ -L[d], --library-directory [d] Add a directory to the library search path + \\ -search_paths_first Search each library search path for dynamic libs then static libs + \\ -search_dylibs_first Search for dynamic libs in each library search path, then static libs. \\ -T[script], --script [script] Use a custom linker script \\ --version-script [path] Provide a version .map file \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so) @@ -537,8 +540,6 @@ const usage_build_generic = \\ -install_name=[value] (Darwin) add dylib's install name \\ --entitlements [path] (Darwin) add path to entitlements file for embedding in code signature \\ -pagezero_size [value] (Darwin) size of the __PAGEZERO segment in hexadecimal notation - \\ -search_paths_first (Darwin) search each dir in library search paths for `libx.dylib` then `libx.a` - \\ -search_dylibs_first (Darwin) search `libx.dylib` in each dir in library search paths, then `libx.a` \\ -headerpad [value] (Darwin) set minimum space for future expansion of the load commands in hexadecimal notation \\ -headerpad_max_install_names (Darwin) set enough space as if all paths were MAXPATHLEN \\ -dead_strip (Darwin) remove functions and data that are unreachable by the entry point or exported symbols @@ -2567,6 +2568,34 @@ fn buildOutputType( } lib_dir_args = undefined; // From here we use lib_dirs instead. + const self_exe_path: ?[]const u8 = if (!process.can_spawn) + null + else + introspect.findZigExePath(arena) catch |err| { + fatal("unable to find zig self exe path: {s}", .{@errorName(err)}); + }; + + var zig_lib_directory: Compilation.Directory = d: { + if (override_lib_dir) |unresolved_lib_dir| { + const lib_dir = try introspect.resolvePath(arena, unresolved_lib_dir); + break :d .{ + .path = lib_dir, + .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| { + fatal("unable to open zig lib directory '{s}': {s}", .{ lib_dir, @errorName(err) }); + }, + }; + } else if (builtin.os.tag == .wasi) { + break :d getWasiPreopen("/lib"); + } else if (self_exe_path) |p| { + break :d introspect.findZigLibDirFromSelfExe(arena, p) catch |err| { + fatal("unable to find zig installation directory: {s}", .{@errorName(err)}); + }; + } else { + unreachable; + } + }; + defer zig_lib_directory.handle.close(); + // Now that we have target info, we can find out if any of the system libraries // are part of libc or libc++. We remove them from the list and communicate their // existence via flags instead. @@ -2612,6 +2641,25 @@ fn buildOutputType( }, } + if (target_info.target.os.tag == .windows) { + const exists = mingw.libExists(arena, target_info.target, zig_lib_directory, lib_name) catch |err| { + fatal("failed to check zig installation for DLL import libs: {s}", .{ + @errorName(err), + }); + }; + if (exists) { + try resolved_system_libs.append(arena, .{ + .name = lib_name, + .lib = .{ + .needed = true, + .weak = false, + .path = undefined, + }, + }); + continue; + } + } + if (fs.path.isAbsolute(lib_name)) { fatal("cannot use absolute path as a system library: {s}", .{lib_name}); } @@ -2758,9 +2806,13 @@ fn buildOutputType( if (failed_libs.items.len > 0) { for (failed_libs.items) |f| { + const searched_paths = if (f.checked_paths.len == 0) " none" else f.checked_paths; std.log.err("unable to find {s} system library '{s}' using strategy '{s}'. searched paths:{s}", .{ - @tagName(f.preferred_mode), f.name, @tagName(f.strategy), f.checked_paths, + @tagName(f.preferred_mode), f.name, @tagName(f.strategy), searched_paths, }); + if (f.preferred_mode == .Dynamic and f.strategy == .no_fallback) { + std.log.info("to link statically, pass the library as a positional argument", .{}); + } } process.exit(1); } @@ -3079,35 +3131,6 @@ fn buildOutputType( } } - const self_exe_path: ?[]const u8 = if (!process.can_spawn) - null - else - introspect.findZigExePath(arena) catch |err| { - fatal("unable to find zig self exe path: {s}", .{@errorName(err)}); - }; - - var zig_lib_directory: Compilation.Directory = d: { - if (override_lib_dir) |unresolved_lib_dir| { - const lib_dir = try introspect.resolvePath(arena, unresolved_lib_dir); - break :d .{ - .path = lib_dir, - .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| { - fatal("unable to open zig lib directory '{s}': {s}", .{ lib_dir, @errorName(err) }); - }, - }; - } else if (builtin.os.tag == .wasi) { - break :d getWasiPreopen("/lib"); - } else if (self_exe_path) |p| { - break :d introspect.findZigLibDirFromSelfExe(arena, p) catch |err| { - fatal("unable to find zig installation directory: {s}", .{@errorName(err)}); - }; - } else { - unreachable; - } - }; - - defer zig_lib_directory.handle.close(); - var thread_pool: ThreadPool = undefined; try thread_pool.init(.{ .allocator = gpa }); defer thread_pool.deinit(); diff --git a/src/mingw.zig b/src/mingw.zig index 39059f804a..f4d5ae23e2 100644 --- a/src/mingw.zig +++ b/src/mingw.zig @@ -283,7 +283,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - const def_file_path = findDef(comp, arena, lib_name) catch |err| switch (err) { + const def_file_path = findDef(arena, comp.getTarget(), comp.zig_lib_directory, lib_name) catch |err| switch (err) { error.FileNotFound => { log.debug("no {s}.def file available to make a DLL import {s}.lib", .{ lib_name, lib_name }); // In this case we will end up putting foo.lib onto the linker line and letting the linker @@ -431,10 +431,28 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { }); } -/// This function body is verbose but all it does is test 3 different paths and see if a .def file exists. -fn findDef(comp: *Compilation, allocator: Allocator, lib_name: []const u8) ![]u8 { - const target = comp.getTarget(); +pub fn libExists( + allocator: Allocator, + target: std.Target, + zig_lib_directory: Cache.Directory, + lib_name: []const u8, +) !bool { + const s = findDef(allocator, target, zig_lib_directory, lib_name) catch |err| switch (err) { + error.FileNotFound => return false, + else => |e| return e, + }; + defer allocator.free(s); + return true; +} +/// This function body is verbose but all it does is test 3 different paths and +/// see if a .def file exists. +fn findDef( + allocator: Allocator, + target: std.Target, + zig_lib_directory: Cache.Directory, + lib_name: []const u8, +) ![]u8 { const lib_path = switch (target.cpu.arch) { .x86 => "lib32", .x86_64 => "lib64", @@ -451,7 +469,7 @@ fn findDef(comp: *Compilation, allocator: Allocator, lib_name: []const u8) ![]u8 { // Try the archtecture-specific path first. const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "{s}" ++ s ++ "{s}.def"; - if (comp.zig_lib_directory.path) |p| { + if (zig_lib_directory.path) |p| { try override_path.writer().print("{s}" ++ s ++ fmt_path, .{ p, lib_path, lib_name }); } else { try override_path.writer().print(fmt_path, .{ lib_path, lib_name }); @@ -468,7 +486,7 @@ fn findDef(comp: *Compilation, allocator: Allocator, lib_name: []const u8) ![]u8 // Try the generic version. override_path.shrinkRetainingCapacity(0); const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def"; - if (comp.zig_lib_directory.path) |p| { + if (zig_lib_directory.path) |p| { try override_path.writer().print("{s}" ++ s ++ fmt_path, .{ p, lib_name }); } else { try override_path.writer().print(fmt_path, .{lib_name}); @@ -485,7 +503,7 @@ fn findDef(comp: *Compilation, allocator: Allocator, lib_name: []const u8) ![]u8 // Try the generic version and preprocess it. override_path.shrinkRetainingCapacity(0); const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def.in"; - if (comp.zig_lib_directory.path) |p| { + if (zig_lib_directory.path) |p| { try override_path.writer().print("{s}" ++ s ++ fmt_path, .{ p, lib_name }); } else { try override_path.writer().print(fmt_path, .{lib_name});