aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2022-06-28 20:29:20 +0200
committerGitHub <noreply@github.com>2022-06-28 20:29:20 +0200
commit9e8298b864e076221ca9c487412209d8a08c43b2 (patch)
tree50eca29c2dd63c025823f818e882631c94cf8053 /src
parentca3c4ff2d0afcdc8fe86e7e7b41a967c88779729 (diff)
parent5834a608fc629319772b1623a31b62dd49ac6d63 (diff)
downloadzig-9e8298b864e076221ca9c487412209d8a08c43b2.tar.gz
zig-9e8298b864e076221ca9c487412209d8a08c43b2.zip
Merge pull request #11950 from ziglang/macho-weak-libs-frameworks
macho: fully implement `-weak-lx` and `-weak_framework x` flags
Diffstat (limited to 'src')
-rw-r--r--src/link.zig1
-rw-r--r--src/link/MachO.zig131
-rw-r--r--src/link/MachO/Dylib.zig26
-rw-r--r--src/link/MachO/bind.zig5
-rw-r--r--src/main.zig41
5 files changed, 150 insertions, 54 deletions
diff --git a/src/link.zig b/src/link.zig
index c3d1d216c0..da6e8c53ed 100644
--- a/src/link.zig
+++ b/src/link.zig
@@ -21,6 +21,7 @@ const TypedValue = @import("TypedValue.zig");
pub const SystemLib = struct {
needed: bool = false,
+ weak: bool = false,
};
pub const CacheMode = enum { incremental, whole };
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index d660d2ce7e..f5e1bf4b4d 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -52,6 +52,11 @@ pub const SearchStrategy = enum {
dylibs_first,
};
+const SystemLib = struct {
+ needed: bool = false,
+ weak: bool = false,
+};
+
base: File,
/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
@@ -768,7 +773,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
}
// Shared and static libraries passed via `-l` flag.
- var candidate_libs = std.StringArrayHashMap(Compilation.SystemLib).init(arena);
+ var candidate_libs = std.StringArrayHashMap(SystemLib).init(arena);
const system_lib_names = self.base.options.system_libs.keys();
for (system_lib_names) |system_lib_name| {
@@ -781,7 +786,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
}
const system_lib_info = self.base.options.system_libs.get(system_lib_name).?;
- try candidate_libs.put(system_lib_name, system_lib_info);
+ try candidate_libs.put(system_lib_name, .{
+ .needed = system_lib_info.needed,
+ .weak = system_lib_info.weak,
+ });
}
var lib_dirs = std.ArrayList([]const u8).init(arena);
@@ -793,7 +801,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
}
}
- var libs = std.StringArrayHashMap(Compilation.SystemLib).init(arena);
+ var libs = std.StringArrayHashMap(SystemLib).init(arena);
// Assume ld64 default -search_paths_first if no strategy specified.
const search_strategy = self.base.options.search_strategy orelse .paths_first;
@@ -890,7 +898,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
for (framework_dirs.items) |dir| {
for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
if (try resolveFramework(arena, dir, f_name, ext)) |full_path| {
- try libs.put(full_path, self.base.options.frameworks.get(f_name).?);
+ const info = self.base.options.frameworks.get(f_name).?;
+ try libs.put(full_path, .{
+ .needed = info.needed,
+ .weak = info.weak,
+ });
continue :outer;
}
}
@@ -1026,9 +1038,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
try argv.append("-lc");
for (self.base.options.system_libs.keys()) |l_name| {
- const needed = self.base.options.system_libs.get(l_name).?.needed;
- const arg = if (needed)
+ const info = self.base.options.system_libs.get(l_name).?;
+ const arg = if (info.needed)
try std.fmt.allocPrint(arena, "-needed-l{s}", .{l_name})
+ else if (info.weak)
+ try std.fmt.allocPrint(arena, "-weak-l{s}", .{l_name})
else
try std.fmt.allocPrint(arena, "-l{s}", .{l_name});
try argv.append(arg);
@@ -1039,9 +1053,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
}
for (self.base.options.frameworks.keys()) |framework| {
- const needed = self.base.options.frameworks.get(framework).?.needed;
- const arg = if (needed)
+ const info = self.base.options.frameworks.get(framework).?;
+ const arg = if (info.needed)
try std.fmt.allocPrint(arena, "-needed_framework {s}", .{framework})
+ else if (info.weak)
+ try std.fmt.allocPrint(arena, "-weak_framework {s}", .{framework})
else
try std.fmt.allocPrint(arena, "-framework {s}", .{framework});
try argv.append(arg);
@@ -1063,7 +1079,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
Compilation.dump_argv(argv.items);
}
- var dependent_libs = std.fifo.LinearFifo(Dylib.Id, .Dynamic).init(self.base.allocator);
+ var dependent_libs = std.fifo.LinearFifo(struct {
+ id: Dylib.Id,
+ parent: u16,
+ }, .Dynamic).init(self.base.allocator);
defer dependent_libs.deinit();
try self.parseInputFiles(positionals.items, self.base.options.sysroot, &dependent_libs);
try self.parseAndForceLoadStaticArchives(must_link_archives.keys());
@@ -1389,13 +1408,18 @@ const ParseDylibError = error{
const DylibCreateOpts = struct {
syslibroot: ?[]const u8,
- dependent_libs: *std.fifo.LinearFifo(Dylib.Id, .Dynamic),
id: ?Dylib.Id = null,
- is_dependent: bool = false,
- is_needed: bool = false,
+ dependent: bool = false,
+ needed: bool = false,
+ weak: bool = false,
};
-pub fn parseDylib(self: *MachO, path: []const u8, opts: DylibCreateOpts) ParseDylibError!bool {
+pub fn parseDylib(
+ self: *MachO,
+ path: []const u8,
+ dependent_libs: anytype,
+ opts: DylibCreateOpts,
+) ParseDylibError!bool {
const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
error.FileNotFound => return false,
else => |e| return e,
@@ -1405,12 +1429,19 @@ pub fn parseDylib(self: *MachO, path: []const u8, opts: DylibCreateOpts) ParseDy
const name = try self.base.allocator.dupe(u8, path);
errdefer self.base.allocator.free(name);
+ const dylib_id = @intCast(u16, self.dylibs.items.len);
var dylib = Dylib{
.name = name,
.file = file,
+ .weak = opts.weak,
};
- dylib.parse(self.base.allocator, self.base.options.target, opts.dependent_libs) catch |err| switch (err) {
+ dylib.parse(
+ self.base.allocator,
+ self.base.options.target,
+ dylib_id,
+ dependent_libs,
+ ) catch |err| switch (err) {
error.EndOfStream, error.NotDylib => {
try file.seekTo(0);
@@ -1420,7 +1451,13 @@ pub fn parseDylib(self: *MachO, path: []const u8, opts: DylibCreateOpts) ParseDy
};
defer lib_stub.deinit();
- try dylib.parseFromStub(self.base.allocator, self.base.options.target, lib_stub, opts.dependent_libs);
+ try dylib.parseFromStub(
+ self.base.allocator,
+ self.base.options.target,
+ lib_stub,
+ dylib_id,
+ dependent_libs,
+ );
},
else => |e| return e,
};
@@ -1438,13 +1475,12 @@ pub fn parseDylib(self: *MachO, path: []const u8, opts: DylibCreateOpts) ParseDy
}
}
- const dylib_id = @intCast(u16, self.dylibs.items.len);
try self.dylibs.append(self.base.allocator, dylib);
try self.dylibs_map.putNoClobber(self.base.allocator, dylib.id.?.name, dylib_id);
const should_link_dylib_even_if_unreachable = blk: {
- if (self.base.options.dead_strip_dylibs and !opts.is_needed) break :blk false;
- break :blk !(opts.is_dependent or self.referenced_dylibs.contains(dylib_id));
+ if (self.base.options.dead_strip_dylibs and !opts.needed) break :blk false;
+ break :blk !(opts.dependent or self.referenced_dylibs.contains(dylib_id));
};
if (should_link_dylib_even_if_unreachable) {
@@ -1467,9 +1503,8 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const
if (try self.parseObject(full_path)) continue;
if (try self.parseArchive(full_path, false)) continue;
- if (try self.parseDylib(full_path, .{
+ if (try self.parseDylib(full_path, dependent_libs, .{
.syslibroot = syslibroot,
- .dependent_libs = dependent_libs,
})) continue;
log.warn("unknown filetype for positional input file: '{s}'", .{file_name});
@@ -1494,17 +1529,17 @@ fn parseAndForceLoadStaticArchives(self: *MachO, files: []const []const u8) !voi
fn parseLibs(
self: *MachO,
lib_names: []const []const u8,
- lib_infos: []const Compilation.SystemLib,
+ lib_infos: []const SystemLib,
syslibroot: ?[]const u8,
dependent_libs: anytype,
) !void {
for (lib_names) |lib, i| {
const lib_info = lib_infos[i];
log.debug("parsing lib path '{s}'", .{lib});
- if (try self.parseDylib(lib, .{
+ if (try self.parseDylib(lib, dependent_libs, .{
.syslibroot = syslibroot,
- .dependent_libs = dependent_libs,
- .is_needed = lib_info.needed,
+ .needed = lib_info.needed,
+ .weak = lib_info.weak,
})) continue;
if (try self.parseArchive(lib, false)) continue;
@@ -1522,20 +1557,21 @@ fn parseDependentLibs(self: *MachO, syslibroot: ?[]const u8, dependent_libs: any
const arena = arena_alloc.allocator();
defer arena_alloc.deinit();
- while (dependent_libs.readItem()) |*id| {
- defer id.deinit(self.base.allocator);
+ while (dependent_libs.readItem()) |*dep_id| {
+ defer dep_id.id.deinit(self.base.allocator);
- if (self.dylibs_map.contains(id.name)) continue;
+ if (self.dylibs_map.contains(dep_id.id.name)) continue;
+ const weak = self.dylibs.items[dep_id.parent].weak;
const has_ext = blk: {
- const basename = fs.path.basename(id.name);
+ const basename = fs.path.basename(dep_id.id.name);
break :blk mem.lastIndexOfScalar(u8, basename, '.') != null;
};
- const extension = if (has_ext) fs.path.extension(id.name) else "";
+ const extension = if (has_ext) fs.path.extension(dep_id.id.name) else "";
const without_ext = if (has_ext) blk: {
- const index = mem.lastIndexOfScalar(u8, id.name, '.') orelse unreachable;
- break :blk id.name[0..index];
- } else id.name;
+ const index = mem.lastIndexOfScalar(u8, dep_id.id.name, '.') orelse unreachable;
+ break :blk dep_id.id.name[0..index];
+ } else dep_id.id.name;
for (&[_][]const u8{ extension, ".tbd" }) |ext| {
const with_ext = try std.fmt.allocPrint(arena, "{s}{s}", .{ without_ext, ext });
@@ -1543,15 +1579,15 @@ fn parseDependentLibs(self: *MachO, syslibroot: ?[]const u8, dependent_libs: any
log.debug("trying dependency at fully resolved path {s}", .{full_path});
- const did_parse_successfully = try self.parseDylib(full_path, .{
- .id = id.*,
+ const did_parse_successfully = try self.parseDylib(full_path, dependent_libs, .{
+ .id = dep_id.id,
.syslibroot = syslibroot,
- .is_dependent = true,
- .dependent_libs = dependent_libs,
+ .dependent = true,
+ .weak = weak,
});
if (did_parse_successfully) break;
} else {
- log.warn("unable to resolve dependency {s}", .{id.name});
+ log.warn("unable to resolve dependency {s}", .{dep_id.id.name});
}
}
}
@@ -3081,6 +3117,10 @@ fn resolveSymbolsInDylibs(self: *MachO) !void {
undef.n_type |= macho.N_EXT;
undef.n_desc = @intCast(u16, ordinal + 1) * macho.N_SYMBOL_RESOLVER;
+ if (dylib.weak) {
+ undef.n_desc |= macho.N_WEAK_REF;
+ }
+
if (self.unresolved.fetchSwapRemove(resolv.where_index)) |entry| outer_blk: {
switch (entry.value) {
.none => {},
@@ -3441,6 +3481,7 @@ fn addLoadDylibLC(self: *MachO, id: u16) !void {
const dylib_id = dylib.id orelse unreachable;
var dylib_cmd = try macho.createLoadDylibCommand(
self.base.allocator,
+ if (dylib.weak) .LOAD_WEAK_DYLIB else .LOAD_DYLIB,
dylib_id.name,
dylib_id.timestamp,
dylib_id.current_version,
@@ -4885,13 +4926,13 @@ fn populateMissingMetadata(self: *MachO) !void {
std.builtin.Version{ .major = 1, .minor = 0, .patch = 0 };
var dylib_cmd = try macho.createLoadDylibCommand(
self.base.allocator,
+ .ID_DYLIB,
install_name,
2,
current_version.major << 16 | current_version.minor << 8 | current_version.patch,
compat_version.major << 16 | compat_version.minor << 8 | compat_version.patch,
);
errdefer dylib_cmd.deinit(self.base.allocator);
- dylib_cmd.inner.cmd = .ID_DYLIB;
try self.load_commands.append(self.base.allocator, .{ .dylib = dylib_cmd });
self.load_commands_dirty = true;
}
@@ -5769,11 +5810,16 @@ fn writeDyldInfoData(self: *MachO) !void {
},
.undef => {
const bind_sym = self.undefs.items[resolv.where_index];
+ var flags: u4 = 0;
+ if (bind_sym.weakRef()) {
+ flags |= @truncate(u4, macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT);
+ }
try bind_pointers.append(.{
.offset = binding.offset + base_offset,
.segment_id = match.seg,
- .dylib_ordinal = @divExact(@bitCast(i16, bind_sym.n_desc), macho.N_SYMBOL_RESOLVER),
+ .dylib_ordinal = @divTrunc(@bitCast(i16, bind_sym.n_desc), macho.N_SYMBOL_RESOLVER),
.name = self.getString(bind_sym.n_strx),
+ .bind_flags = flags,
});
},
}
@@ -5791,11 +5837,16 @@ fn writeDyldInfoData(self: *MachO) !void {
},
.undef => {
const bind_sym = self.undefs.items[resolv.where_index];
+ var flags: u4 = 0;
+ if (bind_sym.weakRef()) {
+ flags |= @truncate(u4, macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT);
+ }
try lazy_bind_pointers.append(.{
.offset = binding.offset + base_offset,
.segment_id = match.seg,
- .dylib_ordinal = @divExact(@bitCast(i16, bind_sym.n_desc), macho.N_SYMBOL_RESOLVER),
+ .dylib_ordinal = @divTrunc(@bitCast(i16, bind_sym.n_desc), macho.N_SYMBOL_RESOLVER),
.name = self.getString(bind_sym.n_strx),
+ .bind_flags = flags,
});
},
}
diff --git a/src/link/MachO/Dylib.zig b/src/link/MachO/Dylib.zig
index 801f810f80..ba519aac0a 100644
--- a/src/link/MachO/Dylib.zig
+++ b/src/link/MachO/Dylib.zig
@@ -30,6 +30,7 @@ dysymtab_cmd_index: ?u16 = null,
id_cmd_index: ?u16 = null,
id: ?Id = null,
+weak: bool = false,
/// Parsed symbol table represented as hash map of symbols'
/// names. We can and should defer creating *Symbols until
@@ -141,7 +142,13 @@ pub fn deinit(self: *Dylib, allocator: Allocator) void {
}
}
-pub fn parse(self: *Dylib, allocator: Allocator, target: std.Target, dependent_libs: anytype) !void {
+pub fn parse(
+ self: *Dylib,
+ allocator: Allocator,
+ target: std.Target,
+ dylib_id: u16,
+ dependent_libs: anytype,
+) !void {
log.debug("parsing shared library '{s}'", .{self.name});
self.library_offset = try fat.getLibraryOffset(self.file.reader(), target);
@@ -163,12 +170,18 @@ pub fn parse(self: *Dylib, allocator: Allocator, target: std.Target, dependent_l
return error.MismatchedCpuArchitecture;
}
- try self.readLoadCommands(allocator, reader, dependent_libs);
+ try self.readLoadCommands(allocator, reader, dylib_id, dependent_libs);
try self.parseId(allocator);
try self.parseSymbols(allocator);
}
-fn readLoadCommands(self: *Dylib, allocator: Allocator, reader: anytype, dependent_libs: anytype) !void {
+fn readLoadCommands(
+ self: *Dylib,
+ allocator: Allocator,
+ reader: anytype,
+ dylib_id: u16,
+ dependent_libs: anytype,
+) !void {
const should_lookup_reexports = self.header.?.flags & macho.MH_NO_REEXPORTED_DYLIBS == 0;
try self.load_commands.ensureUnusedCapacity(allocator, self.header.?.ncmds);
@@ -190,7 +203,7 @@ fn readLoadCommands(self: *Dylib, allocator: Allocator, reader: anytype, depende
if (should_lookup_reexports) {
// Parse install_name to dependent dylib.
var id = try Id.fromLoadCommand(allocator, cmd.dylib);
- try dependent_libs.writeItem(id);
+ try dependent_libs.writeItem(.{ .id = id, .parent = dylib_id });
}
},
else => {
@@ -338,6 +351,7 @@ pub fn parseFromStub(
allocator: Allocator,
target: std.Target,
lib_stub: LibStub,
+ dylib_id: u16,
dependent_libs: anytype,
) !void {
if (lib_stub.inner.len == 0) return error.EmptyStubFile;
@@ -417,7 +431,7 @@ pub fn parseFromStub(
log.debug(" (found re-export '{s}')", .{lib});
var dep_id = try Id.default(allocator, lib);
- try dependent_libs.writeItem(dep_id);
+ try dependent_libs.writeItem(.{ .id = dep_id, .parent = dylib_id });
}
}
}
@@ -522,7 +536,7 @@ pub fn parseFromStub(
log.debug(" (found re-export '{s}')", .{lib});
var dep_id = try Id.default(allocator, lib);
- try dependent_libs.writeItem(dep_id);
+ try dependent_libs.writeItem(.{ .id = dep_id, .parent = dylib_id });
}
}
}
diff --git a/src/link/MachO/bind.zig b/src/link/MachO/bind.zig
index 14a5ba3e30..9e34581a23 100644
--- a/src/link/MachO/bind.zig
+++ b/src/link/MachO/bind.zig
@@ -7,6 +7,7 @@ pub const Pointer = struct {
segment_id: u16,
dylib_ordinal: ?i64 = null,
name: ?[]const u8 = null,
+ bind_flags: u4 = 0,
};
pub fn rebaseInfoSize(pointers: []const Pointer) !u64 {
@@ -73,7 +74,7 @@ pub fn writeBindInfo(pointers: []const Pointer, writer: anytype) !void {
}
try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @truncate(u4, macho.BIND_TYPE_POINTER));
- try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM); // TODO Sometimes we might want to add flags.
+ try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | pointer.bind_flags);
try writer.writeAll(pointer.name.?);
try writer.writeByte(0);
@@ -127,7 +128,7 @@ pub fn writeLazyBindInfo(pointers: []const Pointer, writer: anytype) !void {
try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @truncate(u4, @bitCast(u64, pointer.dylib_ordinal.?)));
}
- try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM); // TODO Sometimes we might want to add flags.
+ try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | pointer.bind_flags);
try writer.writeAll(pointer.name.?);
try writer.writeByte(0);
diff --git a/src/main.zig b/src/main.zig
index 749534416f..ae1b95a4aa 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -443,9 +443,12 @@ const usage_build_generic =
\\ --subsystem [subsystem] (Windows) /SUBSYSTEM:<subsystem> to the linker
\\ --stack [size] Override default stack size
\\ --image-base [addr] Set base address for executable image
+ \\ -weak-l[lib] (Darwin) link against system library and mark it and all referenced symbols as weak
+ \\ -weak_library [lib]
\\ -framework [name] (Darwin) link against framework
\\ -needed_framework [name] (Darwin) link against framework (even if unused)
\\ -needed_library [lib] (Darwin) link against system library (even if unused)
+ \\ -weak_framework [name] (Darwin) link against framework and mark it and all referenced symbols as weak
\\ -F[dir] (Darwin) add search path for frameworks
\\ -install_name=[value] (Darwin) add dylib's install name
\\ --entitlements [path] (Darwin) add path to entitlements file for embedding in code signature
@@ -916,7 +919,12 @@ fn buildOutputType(
const path = args_iter.next() orelse {
fatal("expected parameter after {s}", .{arg});
};
- try frameworks.put(gpa, path, .{ .needed = false });
+ try frameworks.put(gpa, path, .{});
+ } else if (mem.eql(u8, arg, "-weak_framework")) {
+ const path = args_iter.next() orelse {
+ fatal("expected parameter after {s}", .{arg});
+ };
+ try frameworks.put(gpa, path, .{ .weak = true });
} else if (mem.eql(u8, arg, "-needed_framework")) {
const path = args_iter.next() orelse {
fatal("expected parameter after {s}", .{arg});
@@ -962,7 +970,7 @@ fn buildOutputType(
};
// We don't know whether this library is part of libc or libc++ until
// we resolve the target, so we simply append to the list for now.
- try system_libs.put(next_arg, .{ .needed = false });
+ try system_libs.put(next_arg, .{});
} else if (mem.eql(u8, arg, "--needed-library") or
mem.eql(u8, arg, "-needed-l") or
mem.eql(u8, arg, "-needed_library"))
@@ -971,6 +979,11 @@ fn buildOutputType(
fatal("expected parameter after {s}", .{arg});
};
try system_libs.put(next_arg, .{ .needed = true });
+ } else if (mem.eql(u8, arg, "-weak_library") or mem.eql(u8, arg, "-weak-l")) {
+ const next_arg = args_iter.next() orelse {
+ fatal("expected parameter after {s}", .{arg});
+ };
+ try system_libs.put(next_arg, .{ .weak = true });
} else if (mem.eql(u8, arg, "-D") or
mem.eql(u8, arg, "-isystem") or
mem.eql(u8, arg, "-I") or
@@ -1300,9 +1313,11 @@ fn buildOutputType(
} else if (mem.startsWith(u8, arg, "-l")) {
// We don't know whether this library is part of libc or libc++ until
// we resolve the target, so we simply append to the list for now.
- try system_libs.put(arg["-l".len..], .{ .needed = false });
+ try system_libs.put(arg["-l".len..], .{});
} else if (mem.startsWith(u8, arg, "-needed-l")) {
try system_libs.put(arg["-needed-l".len..], .{ .needed = true });
+ } else if (mem.startsWith(u8, arg, "-weak-l")) {
+ try system_libs.put(arg["-weak-l".len..], .{ .weak = true });
} else if (mem.startsWith(u8, arg, "-D") or
mem.startsWith(u8, arg, "-I"))
{
@@ -1596,7 +1611,7 @@ fn buildOutputType(
try clang_argv.appendSlice(it.other_args);
},
.framework_dir => try framework_dirs.append(it.only_arg),
- .framework => try frameworks.put(gpa, it.only_arg, .{ .needed = false }),
+ .framework => try frameworks.put(gpa, it.only_arg, .{}),
.nostdlibinc => want_native_include_dirs = false,
.strip => strip = true,
.exec_model => {
@@ -1879,12 +1894,18 @@ fn buildOutputType(
) catch |err| {
fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
};
- } else if (mem.eql(u8, arg, "-framework") or mem.eql(u8, arg, "-weak_framework")) {
+ } else if (mem.eql(u8, arg, "-framework")) {
+ i += 1;
+ if (i >= linker_args.items.len) {
+ fatal("expected linker arg after '{s}'", .{arg});
+ }
+ try frameworks.put(gpa, linker_args.items[i], .{});
+ } else if (mem.eql(u8, arg, "-weak_framework")) {
i += 1;
if (i >= linker_args.items.len) {
fatal("expected linker arg after '{s}'", .{arg});
}
- try frameworks.put(gpa, linker_args.items[i], .{ .needed = false });
+ try frameworks.put(gpa, linker_args.items[i], .{ .weak = true });
} else if (mem.eql(u8, arg, "-needed_framework")) {
i += 1;
if (i >= linker_args.items.len) {
@@ -1897,6 +1918,14 @@ fn buildOutputType(
fatal("expected linker arg after '{s}'", .{arg});
}
try system_libs.put(linker_args.items[i], .{ .needed = true });
+ } else if (mem.startsWith(u8, arg, "-weak-l")) {
+ try system_libs.put(arg["-weak-l".len..], .{ .weak = true });
+ } else if (mem.eql(u8, arg, "-weak_library")) {
+ i += 1;
+ if (i >= linker_args.items.len) {
+ fatal("expected linker arg after '{s}'", .{arg});
+ }
+ try system_libs.put(linker_args.items[i], .{ .weak = true });
} else if (mem.eql(u8, arg, "-compatibility_version")) {
i += 1;
if (i >= linker_args.items.len) {