From 20bd722464699bd11a05fe8e250f9f8086853cf2 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 28 Jun 2022 09:13:45 +0200 Subject: [PATCH] build: handle weakly imported libs and frameworks --- lib/std/build.zig | 72 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index ab4472d01e..96abc51fac 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1483,7 +1483,7 @@ pub const LibExeObjStep = struct { lib_paths: ArrayList([]const u8), rpaths: ArrayList([]const u8), framework_dirs: ArrayList([]const u8), - frameworks: StringHashMap(bool), + frameworks: StringHashMap(FrameworkLinkInfo), verbose_link: bool, verbose_cc: bool, emit_analysis: EmitOption = .default, @@ -1643,6 +1643,7 @@ pub const LibExeObjStep = struct { pub const SystemLib = struct { name: []const u8, needed: bool, + weak: bool, use_pkg_config: enum { /// Don't use pkg-config, just pass -lfoo where foo is name. no, @@ -1655,6 +1656,11 @@ pub const LibExeObjStep = struct { }, }; + const FrameworkLinkInfo = struct { + needed: bool = false, + weak: bool = false, + }; + pub const IncludeDir = union(enum) { raw_path: []const u8, raw_path_system: []const u8, @@ -1744,7 +1750,7 @@ pub const LibExeObjStep = struct { .kind = kind, .root_src = root_src, .name = name, - .frameworks = StringHashMap(bool).init(builder.allocator), + .frameworks = StringHashMap(FrameworkLinkInfo).init(builder.allocator), .step = Step.init(base_id, name, builder.allocator, make), .version = ver, .out_filename = undefined, @@ -1893,11 +1899,19 @@ pub const LibExeObjStep = struct { } pub fn linkFramework(self: *LibExeObjStep, framework_name: []const u8) void { - self.frameworks.put(self.builder.dupe(framework_name), false) catch unreachable; + self.frameworks.put(self.builder.dupe(framework_name), .{}) catch unreachable; } pub fn linkFrameworkNeeded(self: *LibExeObjStep, framework_name: []const u8) void { - self.frameworks.put(self.builder.dupe(framework_name), true) catch unreachable; + self.frameworks.put(self.builder.dupe(framework_name), .{ + .needed = true, + }) catch unreachable; + } + + pub fn linkFrameworkWeak(self: *LibExeObjStep, framework_name: []const u8) void { + self.frameworks.put(self.builder.dupe(framework_name), .{ + .weak = true, + }) catch unreachable; } /// Returns whether the library, executable, or object depends on a particular system library. @@ -1939,6 +1953,7 @@ pub const LibExeObjStep = struct { .system_lib = .{ .name = "c", .needed = false, + .weak = false, .use_pkg_config = .no, }, }) catch unreachable; @@ -1952,6 +1967,7 @@ pub const LibExeObjStep = struct { .system_lib = .{ .name = "c++", .needed = false, + .weak = false, .use_pkg_config = .no, }, }) catch unreachable; @@ -1977,6 +1993,7 @@ pub const LibExeObjStep = struct { .system_lib = .{ .name = self.builder.dupe(name), .needed = false, + .weak = false, .use_pkg_config = .no, }, }) catch unreachable; @@ -1989,6 +2006,20 @@ pub const LibExeObjStep = struct { .system_lib = .{ .name = self.builder.dupe(name), .needed = true, + .weak = false, + .use_pkg_config = .no, + }, + }) catch unreachable; + } + + /// Darwin-only. This one has no integration with anything, it just puts -weak-lname on the + /// command line. Prefer to use `linkSystemLibraryWeak` instead. + pub fn linkSystemLibraryWeakName(self: *LibExeObjStep, name: []const u8) void { + self.link_objects.append(.{ + .system_lib = .{ + .name = self.builder.dupe(name), + .needed = false, + .weak = true, .use_pkg_config = .no, }, }) catch unreachable; @@ -2001,6 +2032,7 @@ pub const LibExeObjStep = struct { .system_lib = .{ .name = self.builder.dupe(lib_name), .needed = false, + .weak = false, .use_pkg_config = .force, }, }) catch unreachable; @@ -2013,6 +2045,7 @@ pub const LibExeObjStep = struct { .system_lib = .{ .name = self.builder.dupe(lib_name), .needed = true, + .weak = false, .use_pkg_config = .force, }, }) catch unreachable; @@ -2115,14 +2148,21 @@ pub const LibExeObjStep = struct { } pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void { - self.linkSystemLibraryInner(name, false); + self.linkSystemLibraryInner(name, .{}); } pub fn linkSystemLibraryNeeded(self: *LibExeObjStep, name: []const u8) void { - self.linkSystemLibraryInner(name, true); + self.linkSystemLibraryInner(name, .{ .needed = true }); } - fn linkSystemLibraryInner(self: *LibExeObjStep, name: []const u8, needed: bool) void { + pub fn linkSystemLibraryWeak(self: *LibExeObjStep, name: []const u8) void { + self.linkSystemLibraryInner(name, .{ .weak = true }); + } + + fn linkSystemLibraryInner(self: *LibExeObjStep, name: []const u8, opts: struct { + needed: bool = false, + weak: bool = false, + }) void { if (isLibCLibrary(name)) { self.linkLibC(); return; @@ -2135,7 +2175,8 @@ pub const LibExeObjStep = struct { self.link_objects.append(.{ .system_lib = .{ .name = self.builder.dupe(name), - .needed = needed, + .needed = opts.needed, + .weak = opts.weak, .use_pkg_config = .yes, }, }) catch unreachable; @@ -2513,7 +2554,14 @@ pub const LibExeObjStep = struct { }, .system_lib => |system_lib| { - const prefix: []const u8 = if (system_lib.needed) "-needed-l" else "-l"; + const prefix: []const u8 = prefix: { + if (system_lib.needed) break :prefix "-needed-l"; + if (system_lib.weak) { + if (self.target.isDarwin()) break :prefix "-weak-l"; + warn("Weak library import used for a non-darwin target, this will be converted to normally library import `-lname`\n", .{}); + } + break :prefix "-l"; + }; switch (system_lib.use_pkg_config) { .no => try zig_args.append(builder.fmt("{s}{s}", .{ prefix, system_lib.name })), .yes, .force => { @@ -3018,9 +3066,11 @@ pub const LibExeObjStep = struct { var it = self.frameworks.iterator(); while (it.next()) |entry| { const name = entry.key_ptr.*; - const needed = entry.value_ptr.*; - if (needed) { + const info = entry.value_ptr.*; + if (info.needed) { zig_args.append("-needed_framework") catch unreachable; + } else if (info.weak) { + zig_args.append("-weak_framework") catch unreachable; } else { zig_args.append("-framework") catch unreachable; }