authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-09-24 00:12:25+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-09-26 18:21:21+01:00
logf8dd54d7d0e1f7ad71dcc7518659a9c30e09155d
treeee72857b7d5534459e815b42467e033811f4bf43
parentfaab901eb59a94735eec603ed42cb90b4477d8fb
signature Commit is signed but in an unrecognized format.

compiler: move darwin libSystem resolution to the frontend

Native libSystem detection happens via `std.zig.LibCInstallation`. In that type, the `crt_dir` field is now mandatory on Darwin (bringing Darwin into alignment with other OSes): it holds the directory containing `libSystem.dylib`/`libSystem.tbd`. (This is also the directory containing `crt1.o`, not that we need that.) In the compiler, a new field is added to `link.Input` to represent a tbd file. These are essentially text-based representations of a dylib's ABI, so the `tbd` field contains very similar information to the `dso` field. The handling for non-native libSystem is trivial compared to most cross libs, because we don't actually need to build anything (the linker can directly consume the tbd file we ship!), so the logic in `Compilation` just directly queues a single `.load_tbd` prelink task. Frameworks are not yet integrated with the frontend link input logic. The legacy Mach-O linker is now at least vaguely integrated with prelink: instead of building its own list of link inputs, it implements `loadInput` by just adding the `link.Input` to an `ArrayList` which it consumes in `flush`. This just helped to avoid duplicating code with the frontend.

11 files changed, 209 insertions(+), 271 deletions(-)

lib/std/zig/LibCInstallation.zig+7-13
...@@ -96,6 +96,10 @@ pub fn parse(allocator: Allocator, io: Io, libc_file: []const u8, target: *const...@@ -96,6 +96,10 @@ pub fn parse(allocator: Allocator, io: Io, libc_file: []const u8, target: *const
96 log.err("sys_include_dir may not be empty", .{});96 log.err("sys_include_dir may not be empty", .{});
97 return error.ParseError;97 return error.ParseError;
98 }98 }
99 if (self.crt_dir == null) {
100 log.err("crt_dir may not be empty", .{});
101 return error.ParseError;
102 }
99103
100 const os_tag = target.os.tag;104 const os_tag = target.os.tag;
101105
...@@ -103,12 +107,6 @@ pub fn parse(allocator: Allocator, io: Io, libc_file: []const u8, target: *const...@@ -103,12 +107,6 @@ pub fn parse(allocator: Allocator, io: Io, libc_file: []const u8, target: *const
103 log.err("cc_dir may not be empty for {s}", .{@tagName(os_tag)});107 log.err("cc_dir may not be empty for {s}", .{@tagName(os_tag)});
104 return error.ParseError;108 return error.ParseError;
105 }109 }
106
107 if (self.crt_dir == null and !target.os.tag.isDarwin()) {
108 log.err("crt_dir may not be empty for {s}", .{@tagName(os_tag)});
109 return error.ParseError;
110 }
111
112 if (self.msvc_lib_dir == null and os_tag == .windows and (target.abi == .msvc or target.abi == .itanium)) {110 if (self.msvc_lib_dir == null and os_tag == .windows and (target.abi == .msvc or target.abi == .itanium)) {
113 log.err("msvc_lib_dir may not be empty for {s}-{s}", .{111 log.err("msvc_lib_dir may not be empty for {s}-{s}", .{
114 @tagName(os_tag),112 @tagName(os_tag),
...@@ -153,7 +151,6 @@ pub fn render(self: LibCInstallation, out: *std.Io.Writer) !void {...@@ -153,7 +151,6 @@ pub fn render(self: LibCInstallation, out: *std.Io.Writer) !void {
153 \\151 \\
154 \\# The directory that contains `crt1.o` or `crt2.o`.152 \\# The directory that contains `crt1.o` or `crt2.o`.
155 \\# On POSIX, can be found with `cc -print-file-name=crt1.o`.153 \\# On POSIX, can be found with `cc -print-file-name=crt1.o`.
156 \\# Not needed when targeting macOS.
157 \\crt_dir={s}154 \\crt_dir={s}
158 \\155 \\
159 \\# The directory that contains `vcruntime.lib`.156 \\# The directory that contains `vcruntime.lib`.
...@@ -193,12 +190,9 @@ pub fn findNative(gpa: Allocator, io: Io, args: FindNativeOptions) FindError!Lib...@@ -193,12 +190,9 @@ pub fn findNative(gpa: Allocator, io: Io, args: FindNativeOptions) FindError!Lib
193 return error.DarwinSdkNotFound;190 return error.DarwinSdkNotFound;
194 defer gpa.free(sdk);191 defer gpa.free(sdk);
195192
196 self.include_dir = try fs.path.join(gpa, &.{193 self.include_dir = try fs.path.join(gpa, &.{ sdk, "usr/include" });
197 sdk, "usr/include",194 self.sys_include_dir = try fs.path.join(gpa, &.{ sdk, "usr/include" });
198 });195 self.crt_dir = try fs.path.join(gpa, &.{ sdk, "usr/lib" });
199 self.sys_include_dir = try fs.path.join(gpa, &.{
200 sdk, "usr/include",
201 });
202 return self;196 return self;
203 } else if (is_windows) {197 } else if (is_windows) {
204 const sdk = std.zig.WindowsSdk.find(gpa, io, args.target.cpu.arch, args.environ_map) catch |err| switch (err) {198 const sdk = std.zig.WindowsSdk.find(gpa, io, args.target.cpu.arch, args.environ_map) catch |err| switch (err) {
src/Compilation.zig+7-5
...@@ -2429,11 +2429,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2429,11 +2429,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2429 // If linking against host libc installation, instead queue up jobs2429 // If linking against host libc installation, instead queue up jobs
2430 // for loading those files in the linker.2430 // for loading those files in the linker.
2431 if (comp.config.link_libc and is_exe_or_dyn_lib) {2431 if (comp.config.link_libc and is_exe_or_dyn_lib) {
2432 // If the "is darwin" check is moved below the libc_installation check below,2432 if (comp.libc_installation) |lci| {
2433 // error.LibCInstallationMissingCrtDir is returned from lci.resolveCrtPaths().
2434 if (target.isDarwinLibC()) {
2435 // TODO delete logic from MachO flush() and queue up tasks here instead.
2436 } else if (comp.libc_installation) |lci| {
2437 const basenames = LibCInstallation.CrtBasenames.get(.{2433 const basenames = LibCInstallation.CrtBasenames.get(.{
2438 .target = target,2434 .target = target,
2439 .link_libc = comp.config.link_libc,2435 .link_libc = comp.config.link_libc,
...@@ -2456,6 +2452,12 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2456,6 +2452,12 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2456 }2452 }
2457 // Loads the libraries provided by `target_util.libcFullLinkFlags(target)`.2453 // Loads the libraries provided by `target_util.libcFullLinkFlags(target)`.
2458 comp.oneshot_prelink_tasks.appendAssumeCapacity(.load_host_libc);2454 comp.oneshot_prelink_tasks.appendAssumeCapacity(.load_host_libc);
2455 } else if (target.isDarwinLibC()) {
2456 try comp.oneshot_prelink_tasks.append(gpa, .{ .load_tbd = .{
2457 .root_dir = comp.dirs.zig_lib,
2458 .sub_path = "libc" ++ fs.path.sep_str ++ "darwin" ++ fs.path.sep_str ++ "libSystem.tbd",
2459 } });
2460 // TODO delete logic from MachO flush() and queue up tasks here instead.
2459 } else if (target.isMuslLibC()) {2461 } else if (target.isMuslLibC()) {
2460 if (!std.zig.target.canBuildLibC(target)) return diag.fail(.cross_libc_unavailable);2462 if (!std.zig.target.canBuildLibC(target)) return diag.fail(.cross_libc_unavailable);
24612463
src/link.zig+122-43
...@@ -1236,15 +1236,15 @@ pub const File = struct {...@@ -1236,15 +1236,15 @@ pub const File = struct {
1236 }1236 }
12371237
1238 pub fn loadInput(base: *File, input: Input) anyerror!void {1238 pub fn loadInput(base: *File, input: Input) anyerror!void {
1239 if (base.tag == .lld) return;1239 if (base.tag != .lld) {
1240 assert(!base.post_prelink);1240 assert(!base.post_prelink);
12411241 }
1242 switch (base.tag) {1242 switch (base.tag) {
1243 inline .coff, .elf, .elf2, .macho2, .wasm, .spirv => |tag| {1243 inline else => |tag| {
1244 dev.check(tag.devFeature());1244 dev.check(tag.devFeature());
1245 return @as(*tag.Type(), @fieldParentPtr("base", base)).loadInput(input);1245 return @as(*tag.Type(), @fieldParentPtr("base", base)).loadInput(input);
1246 },1246 },
1247 else => {},1247 .c, .spork8, .plan9, .lld => {},
1248 }1248 }
1249 }1249 }
12501250
...@@ -1450,6 +1450,7 @@ pub const PrelinkTask = union(enum) {...@@ -1450,6 +1450,7 @@ pub const PrelinkTask = union(enum) {
1450 /// Tells the linker to load a shared library, possibly one that is a1450 /// Tells the linker to load a shared library, possibly one that is a
1451 /// GNU ld script.1451 /// GNU ld script.
1452 load_dso: Path,1452 load_dso: Path,
1453 load_tbd: Path,
1453};1454};
1454pub const ZcuTask = union(enum) {1455pub const ZcuTask = union(enum) {
1455 /// Sent once per update, as the very first `ZcuTask` in the update. Indicates that all per-file1456 /// Sent once per update, as the very first `ZcuTask` in the update. Indicates that all per-file
...@@ -1504,6 +1505,7 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {...@@ -1504,6 +1505,7 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
1504 error.AlreadyReported => return, // error reported via diags1505 error.AlreadyReported => return, // error reported via diags
1505 else => |e| switch (input) {1506 else => |e| switch (input) {
1506 .dso => |dso| diags.addParseError(dso.path, "failed to parse shared library: {t}", .{e}),1507 .dso => |dso| diags.addParseError(dso.path, "failed to parse shared library: {t}", .{e}),
1508 .tbd => |tbd| diags.addParseError(tbd.path, "failed to parse tbd: {t}", .{e}),
1507 .object => |obj| diags.addParseError(obj.path, "failed to parse object: {t}", .{e}),1509 .object => |obj| diags.addParseError(obj.path, "failed to parse object: {t}", .{e}),
1508 .archive => |obj| diags.addParseError(obj.path, "failed to parse archive: {t}", .{e}),1510 .archive => |obj| diags.addParseError(obj.path, "failed to parse archive: {t}", .{e}),
1509 .res => |res| diags.addParseError(res.path, "failed to parse Windows resource: {t}", .{e}),1511 .res => |res| diags.addParseError(res.path, "failed to parse Windows resource: {t}", .{e}),
...@@ -1525,34 +1527,72 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {...@@ -1525,34 +1527,72 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
1525 assert(mem.startsWith(u8, flag, "-l"));1527 assert(mem.startsWith(u8, flag, "-l"));
1526 const lib_name = flag["-l".len..];1528 const lib_name = flag["-l".len..];
1527 switch (comp.config.link_mode) {1529 switch (comp.config.link_mode) {
1528 .dynamic => {1530 .dynamic => loaded: {
1529 const dso_path = Path.initCwd(1531 if (target.os.tag.isDarwin()) {
1532 // Prefer .tbd over .dylib.
1533 const tbd_path: Path = .initCwd(std.fmt.allocPrint(
1534 comp.arena,
1535 "{s}" ++ sep ++ "{s}{s}.tbd",
1536 .{ crt_dir, target.libPrefix(), lib_name },
1537 ) catch return diags.setAllocFailure());
1538 if (tbd_path.root_dir.handle.openFile(io, tbd_path.sub_path, .{})) |file| {
1539 errdefer file.close(io);
1540 base.loadInput(.{ .tbd = .{
1541 .path = tbd_path,
1542 .file = file,
1543 .needed = false,
1544 .weak = false,
1545 .reexport = false,
1546 } }) catch |err| switch (err) {
1547 error.AlreadyReported => return,
1548 error.Canceled => io.recancel(),
1549 else => |e| diags.addParseError(tbd_path, "failed to parse tbd: {t}", .{e}),
1550 };
1551 break :loaded;
1552 } else |err| switch (err) {
1553 error.FileNotFound => {},
1554 error.Canceled => io.recancel(),
1555 else => |e| diags.addParseError(tbd_path, "failed to parse tbd: {t}", .{e}),
1556 }
1557 }
1558
1559 // Try dynamic library.
1560 const dso_path: Path = .initCwd(std.fmt.allocPrint(
1561 comp.arena,
1562 "{s}" ++ sep ++ "{s}{s}{s}",
1563 .{ crt_dir, target.libPrefix(), lib_name, target.dynamicLibSuffix() },
1564 ) catch return diags.setAllocFailure());
1565 if (base.openLoadDso(dso_path, .{
1566 .preferred_mode = .dynamic,
1567 .search_strategy = .paths_first,
1568 })) {
1569 break :loaded;
1570 } else |err| switch (err) {
1571 error.FileNotFound => {},
1572 error.AlreadyReported => return,
1573 error.Canceled => io.recancel(),
1574 else => |e| diags.addParseError(dso_path, "failed to parse shared library: {s}", .{@errorName(e)}),
1575 }
1576
1577 // Also try static.
1578 const archive_path = Path.initCwd(
1530 std.fmt.allocPrint(comp.arena, "{s}" ++ sep ++ "{s}{s}{s}", .{1579 std.fmt.allocPrint(comp.arena, "{s}" ++ sep ++ "{s}{s}{s}", .{
1531 crt_dir, target.libPrefix(), lib_name, target.dynamicLibSuffix(),1580 crt_dir, target.libPrefix(), lib_name, target.staticLibSuffix(),
1532 }) catch return diags.setAllocFailure(),1581 }) catch return diags.setAllocFailure(),
1533 );1582 );
1534 base.openLoadDso(dso_path, .{1583 if (base.openLoadArchiveQuery(archive_path, .{
1535 .preferred_mode = .dynamic,1584 .preferred_mode = .dynamic,
1536 .search_strategy = .paths_first,1585 .search_strategy = .paths_first,
1537 }) catch |err| switch (err) {1586 })) {
1538 error.FileNotFound => {1587 break :loaded;
1539 // Also try static.1588 } else |archive_err| switch (archive_err) {
1540 const archive_path = Path.initCwd(1589 error.FileNotFound => {},
1541 std.fmt.allocPrint(comp.arena, "{s}" ++ sep ++ "{s}{s}{s}", .{1590 error.AlreadyReported => return,
1542 crt_dir, target.libPrefix(), lib_name, target.staticLibSuffix(),1591 error.Canceled => io.recancel(),
1543 }) catch return diags.setAllocFailure(),1592 else => |e| diags.addParseError(archive_path, "failed to parse archive {f}: {s}", .{ archive_path, @errorName(e) }),
1544 );1593 }
1545 base.openLoadArchiveQuery(archive_path, .{1594
1546 .preferred_mode = .dynamic,1595 diags.addError("failed to find library '{s}'", .{lib_name});
1547 .search_strategy = .paths_first,
1548 }) catch |archive_err| switch (archive_err) {
1549 error.AlreadyReported => return, // error reported via diags
1550 else => |e| diags.addParseError(dso_path, "failed to parse archive {f}: {s}", .{ archive_path, @errorName(e) }),
1551 };
1552 },
1553 error.AlreadyReported => return, // error reported via diags
1554 else => |e| diags.addParseError(dso_path, "failed to parse shared library: {s}", .{@errorName(e)}),
1555 };
1556 },1596 },
1557 .static => {1597 .static => {
1558 const path = Path.initCwd(1598 const path = Path.initCwd(
...@@ -1647,6 +1687,28 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {...@@ -1647,6 +1687,28 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
1647 else => |e| diags.addParseError(path, "failed to parse shared library: {s}", .{@errorName(e)}),1687 else => |e| diags.addParseError(path, "failed to parse shared library: {s}", .{@errorName(e)}),
1648 };1688 };
1649 },1689 },
1690 .load_tbd => |path| {
1691 const prog_node = comp.link_prog_node.start("Parse Shared Library Stub", 0);
1692 defer prog_node.end();
1693 if (path.root_dir.handle.openFile(io, path.sub_path, .{})) |file| {
1694 errdefer file.close(io);
1695 base.loadInput(.{ .tbd = .{
1696 .path = path,
1697 .file = file,
1698 .needed = false,
1699 .weak = false,
1700 .reexport = false,
1701 } }) catch |err| switch (err) {
1702 error.AlreadyReported => return,
1703 error.Canceled => io.recancel(),
1704 else => |e| diags.addParseError(path, "failed to parse tbd: {t}", .{e}),
1705 };
1706 } else |err| switch (err) {
1707 error.FileNotFound => {},
1708 error.Canceled => io.recancel(),
1709 else => |e| diags.addParseError(path, "failed to parse tbd: {t}", .{e}),
1710 }
1711 },
1650 }1712 }
1651}1713}
1652pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void {1714pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void {
...@@ -1873,6 +1935,8 @@ pub const Input = union(enum) {...@@ -1873,6 +1935,8 @@ pub const Input = union(enum) {
1873 /// May not be a GNU ld script. Those are resolved when converting from1935 /// May not be a GNU ld script. Those are resolved when converting from
1874 /// `UnresolvedInput` to `Input` values.1936 /// `UnresolvedInput` to `Input` values.
1875 dso: Dso,1937 dso: Dso,
1938 /// Only possible when targeting Darwin.
1939 tbd: Tbd,
18761940
1877 pub const Object = struct {1941 pub const Object = struct {
1878 path: Path,1942 path: Path,
...@@ -1897,24 +1961,32 @@ pub const Input = union(enum) {...@@ -1897,24 +1961,32 @@ pub const Input = union(enum) {
1897 pub const FallbackSoname = enum { basename, full_path };1961 pub const FallbackSoname = enum { basename, full_path };
1898 };1962 };
18991963
1964 pub const Tbd = struct {
1965 path: Path,
1966 file: Io.File,
1967 needed: bool,
1968 weak: bool,
1969 reexport: bool,
1970 };
1971
1900 pub fn path(input: Input) Path {1972 pub fn path(input: Input) Path {
1901 return switch (input) {1973 return switch (input) {
1902 .object, .archive => |obj| obj.path,1974 .object, .archive => |obj| obj.path,
1903 inline .res, .dso => |x| x.path,1975 inline .res, .dso, .tbd => |x| x.path,
1904 };1976 };
1905 }1977 }
19061978
1907 pub fn pathAndFile(input: Input) struct { Path, Io.File } {1979 pub fn pathAndFile(input: Input) struct { Path, Io.File } {
1908 return switch (input) {1980 return switch (input) {
1909 .object, .archive => |obj| .{ obj.path, obj.file },1981 .object, .archive => |obj| .{ obj.path, obj.file },
1910 inline .res, .dso => |x| .{ x.path, x.file },1982 inline .res, .dso, .tbd => |x| .{ x.path, x.file },
1911 };1983 };
1912 }1984 }
19131985
1914 pub fn taskName(input: Input) []const u8 {1986 pub fn taskName(input: Input) []const u8 {
1915 return switch (input) {1987 return switch (input) {
1916 .object, .archive => |obj| obj.path.basename(),1988 .object, .archive => |obj| obj.path.basename(),
1917 inline .res, .dso => |x| x.path.basename(),1989 inline .res, .dso, .tbd => |x| x.path.basename(),
1918 };1990 };
1919 }1991 }
1920};1992};
...@@ -1947,6 +2019,15 @@ pub fn hashInputs(man: *Cache.Manifest, link_inputs: []const Input) !void {...@@ -1947,6 +2019,15 @@ pub fn hashInputs(man: *Cache.Manifest, link_inputs: []const Input) !void {
1947 man.hash.add(dso.reexport);2019 man.hash.add(dso.reexport);
1948 man.hash.add(dso.fallback_soname);2020 man.hash.add(dso.fallback_soname);
1949 },2021 },
2022 .tbd => |tbd| {
2023 _ = try man.addInputPath(tbd.path, .{
2024 .handle = .{ .file = tbd.file },
2025 .request_handle = true,
2026 });
2027 man.hash.add(tbd.needed);
2028 man.hash.add(tbd.weak);
2029 man.hash.add(tbd.reexport);
2030 },
1950 }2031 }
1951 }2032 }
1952}2033}
...@@ -2236,16 +2317,14 @@ fn resolveLibInput(...@@ -2236,16 +2317,14 @@ fn resolveLibInput(
2236 else => |e| fatal("searching for tbd library {qf}: {t}", .{ test_path, e }),2317 else => |e| fatal("searching for tbd library {qf}: {t}", .{ test_path, e }),
2237 };2318 };
2238 errdefer file.close(io);2319 errdefer file.close(io);
2239 return finishResolveLibInput(2320 resolved_inputs.appendAssumeCapacity(.{ .tbd = .{
2240 io,2321 .path = test_path,
2241 resolved_inputs,2322 .file = file,
2242 archive_dedup,2323 .needed = name_query.query.needed,
2243 test_path,2324 .weak = name_query.query.weak,
2244 file,2325 .reexport = name_query.query.reexport,
2245 link_mode,2326 } });
2246 name_query.query,2327 return .ok;
2247 .basename,
2248 );
2249 }2328 }
22502329
2251 {2330 {
...@@ -2700,7 +2779,7 @@ pub fn anyObjectInputs(inputs: []const Input) bool {...@@ -2700,7 +2779,7 @@ pub fn anyObjectInputs(inputs: []const Input) bool {
2700pub fn countObjectInputs(inputs: []const Input) usize {2779pub fn countObjectInputs(inputs: []const Input) usize {
2701 var count: usize = 0;2780 var count: usize = 0;
2702 for (inputs) |input| switch (input) {2781 for (inputs) |input| switch (input) {
2703 .dso => continue,2782 .dso, .tbd => continue,
2704 .res, .object, .archive => count += 1,2783 .res, .object, .archive => count += 1,
2705 };2784 };
2706 return count;2785 return count;
...@@ -2710,7 +2789,7 @@ pub fn countObjectInputs(inputs: []const Input) usize {...@@ -2710,7 +2789,7 @@ pub fn countObjectInputs(inputs: []const Input) usize {
2710pub fn firstObjectInput(inputs: []const Input) ?Input.Object {2789pub fn firstObjectInput(inputs: []const Input) ?Input.Object {
2711 for (inputs) |input| switch (input) {2790 for (inputs) |input| switch (input) {
2712 .object, .archive => |obj| return obj,2791 .object, .archive => |obj| return obj,
2713 .res, .dso => continue,2792 .res, .dso, .tbd => continue,
2714 };2793 };
2715 return null;2794 return null;
2716}2795}
src/link/Coff.zig+1
...@@ -3912,6 +3912,7 @@ pub fn loadInput(coff: *Coff, input: link.Input) link.Error!void {...@@ -3912,6 +3912,7 @@ pub fn loadInput(coff: *Coff, input: link.Input) link.Error!void {
3912 coff.loadDll(dso.path, &fr) catch |err|3912 coff.loadDll(dso.path, &fr) catch |err|
3913 return coff.failLoadInput(err, &fr, dso.path);3913 return coff.failLoadInput(err, &fr, dso.path);
3914 },3914 },
3915 .tbd => unreachable,
3915 }3916 }
3916}3917}
39173918
src/link/Elf.zig+2
...@@ -722,6 +722,7 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {...@@ -722,6 +722,7 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {
722 const argv = &self.dump_argv_list;722 const argv = &self.dump_argv_list;
723 switch (input) {723 switch (input) {
724 .res => unreachable,724 .res => unreachable,
725 .tbd => unreachable,
725 .object, .archive => |obj| try argv.append(gpa, try obj.path.toString(comp.arena)),726 .object, .archive => |obj| try argv.append(gpa, try obj.path.toString(comp.arena)),
726 .dso => |dso| try argv.append(gpa, try dso.path.toString(comp.arena)),727 .dso => |dso| try argv.append(gpa, try dso.path.toString(comp.arena)),
727 }728 }
...@@ -729,6 +730,7 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {...@@ -729,6 +730,7 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {
729730
730 switch (input) {731 switch (input) {
731 .res => unreachable,732 .res => unreachable,
733 .tbd => unreachable,
732 .object => |obj| try parseObject(self, obj),734 .object => |obj| try parseObject(self, obj),
733 .archive => |obj| if (self.base.isStaticLib()) {735 .archive => |obj| if (self.base.isStaticLib()) {
734 // Ignore static library inputs when generating a static library.736 // Ignore static library inputs when generating a static library.
src/link/Elf2.zig+2-1
...@@ -7148,7 +7148,6 @@ fn loadInputInner(elf: *Elf, input: link.Input) (Error || error{BadMagic})!void...@@ -7148,7 +7148,6 @@ fn loadInputInner(elf: *Elf, input: link.Input) (Error || error{BadMagic})!void
7148 },7148 },
7149 };7149 };
7150 },7150 },
7151 .res => unreachable,
7152 .dso => |dso| {7151 .dso => |dso| {
7153 try elf.needed.ensureUnusedCapacity(elf.base.comp.gpa, 1);7152 try elf.needed.ensureUnusedCapacity(elf.base.comp.gpa, 1);
7154 var fr = dso.file.reader(io, &buf);7153 var fr = dso.file.reader(io, &buf);
...@@ -7165,6 +7164,8 @@ fn loadInputInner(elf: *Elf, input: link.Input) (Error || error{BadMagic})!void...@@ -7165,6 +7164,8 @@ fn loadInputInner(elf: *Elf, input: link.Input) (Error || error{BadMagic})!void
7165 },7164 },
7166 };7165 };
7167 },7166 },
7167 .res => unreachable,
7168 .tbd => unreachable,
7168 }7169 }
7169}7170}
7170fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadParseInputError || error{BadMagic})!void {7171fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadParseInputError || error{BadMagic})!void {
src/link/Lld.zig+5-1
...@@ -309,7 +309,7 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) link.Error!void {...@@ -309,7 +309,7 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) link.Error!void {
309309
310 try object_files.ensureUnusedCapacity(arena, comp.link_inputs.len);310 try object_files.ensureUnusedCapacity(arena, comp.link_inputs.len);
311 for (comp.link_inputs) |input| switch (input) {311 for (comp.link_inputs) |input| switch (input) {
312 .dso, .archive => {}, // static archives should not contain shared libraries or other static archives312 .dso, .tbd, .archive => {}, // static archives should not contain shared libraries or other static archives
313 .res, .object => {313 .res, .object => {
314 const path = try input.path().toStringZ(arena);314 const path = try input.path().toStringZ(arena);
315 object_files.appendAssumeCapacity(path);315 object_files.appendAssumeCapacity(path);
...@@ -561,6 +561,7 @@ fn coffLink(lld: *Lld, arena: Allocator) !void {...@@ -561,6 +561,7 @@ fn coffLink(lld: *Lld, arena: Allocator) !void {
561 argv.appendAssumeCapacity(try obj.path.toString(arena));561 argv.appendAssumeCapacity(try obj.path.toString(arena));
562 }562 }
563 },563 },
564 .tbd => unreachable,
564 };565 };
565566
566 for (comp.c_objects.items) |c_object| {567 for (comp.c_objects.items) |c_object| {
...@@ -1102,6 +1103,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {...@@ -1102,6 +1103,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
11021103
1103 for (base.comp.link_inputs) |link_input| switch (link_input) {1104 for (base.comp.link_inputs) |link_input| switch (link_input) {
1104 .res => unreachable, // Windows-only1105 .res => unreachable, // Windows-only
1106 .tbd => unreachable, // Darwin-only
1105 .dso => continue,1107 .dso => continue,
1106 .object, .archive => |obj| {1108 .object, .archive => |obj| {
1107 if (obj.must_link and !whole_archive) {1109 if (obj.must_link and !whole_archive) {
...@@ -1163,6 +1165,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {...@@ -1163,6 +1165,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
11631165
1164 for (base.comp.link_inputs) |link_input| switch (link_input) {1166 for (base.comp.link_inputs) |link_input| switch (link_input) {
1165 .res => unreachable, // Windows-only1167 .res => unreachable, // Windows-only
1168 .tbd => unreachable, // Darwin-only
1166 .object, .archive => continue,1169 .object, .archive => continue,
1167 .dso => |dso| {1170 .dso => |dso| {
1168 const lib_as_needed = !dso.needed;1171 const lib_as_needed = !dso.needed;
...@@ -1596,6 +1599,7 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void {...@@ -1596,6 +1599,7 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void {
1596 .dso => |dso| {1599 .dso => |dso| {
1597 try argv.append(try dso.path.toString(arena));1600 try argv.append(try dso.path.toString(arena));
1598 },1601 },
1602 .tbd => unreachable,
1599 .res => unreachable,1603 .res => unreachable,
1600 };1604 };
1601 if (whole_archive) {1605 if (whole_archive) {
src/link/MachO.zig+31-161
...@@ -4,6 +4,8 @@ pub const Relocation = @import("MachO/Relocation.zig");...@@ -4,6 +4,8 @@ pub const Relocation = @import("MachO/Relocation.zig");
44
5base: link.File,5base: link.File,
66
7all_inputs: std.ArrayList(link.Input),
8
7rpath_list: []const []const u8,9rpath_list: []const []const u8,
810
9/// Debug symbols bundle (or dSym).11/// Debug symbols bundle (or dSym).
...@@ -190,6 +192,7 @@ pub fn createEmpty(...@@ -190,6 +192,7 @@ pub fn createEmpty(
190 .file = null,192 .file = null,
191 .build_id = options.build_id,193 .build_id = options.build_id,
192 },194 },
195 .all_inputs = .empty,
193 .rpath_list = options.rpath_list,196 .rpath_list = options.rpath_list,
194 .pagezero_size = options.pagezero_size,197 .pagezero_size = options.pagezero_size,
195 .headerpad_size = options.headerpad_size,198 .headerpad_size = options.headerpad_size,
...@@ -271,6 +274,8 @@ pub fn deinit(self: *MachO) void {...@@ -271,6 +274,8 @@ pub fn deinit(self: *MachO) void {
271 const gpa = comp.gpa;274 const gpa = comp.gpa;
272 const io = comp.io;275 const io = comp.io;
273276
277 self.all_inputs.deinit(gpa);
278
274 if (self.d_sym) |*d_sym| {279 if (self.d_sym) |*d_sym| {
275 d_sym.deinit();280 d_sym.deinit();
276 }281 }
...@@ -334,6 +339,11 @@ pub fn deinit(self: *MachO) void {...@@ -334,6 +339,11 @@ pub fn deinit(self: *MachO) void {
334 self.thunks.deinit(gpa);339 self.thunks.deinit(gpa);
335}340}
336341
342pub fn loadInput(self: *MachO, input: link.Input) link.Error!void {
343 const gpa = self.base.comp.gpa;
344 try self.all_inputs.append(gpa, input);
345}
346
337pub fn flush(347pub fn flush(
338 self: *MachO,348 self: *MachO,
339 arena: Allocator,349 arena: Allocator,
...@@ -343,6 +353,8 @@ pub fn flush(...@@ -343,6 +353,8 @@ pub fn flush(
343 const tracy = trace(@src());353 const tracy = trace(@src());
344 defer tracy.end();354 defer tracy.end();
345355
356 _ = arena;
357
346 const comp = self.base.comp;358 const comp = self.base.comp;
347 const gpa = comp.gpa;359 const gpa = comp.gpa;
348 const io = comp.io;360 const io = comp.io;
...@@ -351,148 +363,47 @@ pub fn flush(...@@ -351,148 +363,47 @@ pub fn flush(
351 const sub_prog_node = prog_node.start("MachO Flush", 0);363 const sub_prog_node = prog_node.start("MachO Flush", 0);
352 defer sub_prog_node.end();364 defer sub_prog_node.end();
353365
354 const zcu_obj_path: ?Path = p: {
355 const zcu = comp.zcu orelse break :p null;
356 const llvm_object = zcu.llvm_object orelse break :p null;
357 break :p try comp.resolveEmitPathFlush(arena, .temp, llvm_object.out_bin_basename);
358 };
359
360 // --verbose-link366 // --verbose-link
361 if (comp.verbose_link) try self.dumpArgv(comp);367 if (comp.verbose_link) try self.dumpArgv(comp);
362368
363 if (self.getZigObject()) |zo| try zo.flush(self, tid);369 if (self.getZigObject()) |zo| try zo.flush(self, tid);
364 if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, zcu_obj_path);370 if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp);
365 if (self.base.isObject()) return relocatable.flushObject(self, comp, zcu_obj_path);371 if (self.base.isObject()) return relocatable.flushObject(self, comp);
366
367 var positionals = std.array_list.Managed(link.Input).init(gpa);
368 defer positionals.deinit();
369
370 try positionals.ensureUnusedCapacity(comp.link_inputs.len);
371
372 for (comp.link_inputs) |link_input| switch (link_input) {
373 .dso => continue, // handled below
374 .object, .archive => positionals.appendAssumeCapacity(link_input),
375 .res => unreachable,
376 };
377
378 // This is a set of object files emitted by clang in a single `build-exe` invocation.
379 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
380 // in this set.
381 try positionals.ensureUnusedCapacity(comp.c_objects.items.len);
382 for (comp.c_objects.items) |c_object| {
383 positionals.appendAssumeCapacity(try link.openObjectInput(io, diags, c_object.status.success.object_path));
384 }
385
386 if (zcu_obj_path) |path| try positionals.append(try link.openObjectInput(io, diags, path));
387
388 if (comp.config.any_sanitize_thread) {
389 try positionals.append(try link.openObjectInput(io, diags, comp.tsan_lib.?.full_object_path));
390 }
391
392 if (comp.config.any_fuzz) {
393 try positionals.append(try link.openArchiveInput(io, diags, comp.fuzzer_lib.?.full_object_path, false, false));
394 }
395372
396 if (comp.ubsan_rt_lib) |crt_file| {373 for (self.all_inputs.items) |input| {
397 const path = crt_file.full_object_path;374 self.classifyInputFile(input) catch |err|
398 self.classifyInputFile(try link.openArchiveInput(io, diags, path, false, false)) catch |err|375 diags.addParseError(input.path(), "failed to read input file: {t}", .{err});
399 diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(err)});
400 } else if (comp.ubsan_rt_obj) |crt_file| {
401 const path = crt_file.full_object_path;
402 self.classifyInputFile(try link.openObjectInput(io, diags, path)) catch |err|
403 diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(err)});
404 }376 }
405377
406 for (positionals.items) |link_input| {
407 self.classifyInputFile(link_input) catch |err|
408 diags.addParseError(link_input.path(), "failed to read input file: {t}", .{err});
409 }
410
411 var system_libs = std.array_list.Managed(SystemLib).init(gpa);
412 defer system_libs.deinit();
413
414 // frameworks378 // frameworks
415 try system_libs.ensureUnusedCapacity(self.frameworks.len);379 for (self.frameworks) |framework| {
416 for (self.frameworks) |info| {380 switch (Compilation.classifyFileExt(framework.path.sub_path)) {
417 system_libs.appendAssumeCapacity(.{
418 .needed = info.needed,
419 .weak = info.weak,
420 .path = info.path,
421 });
422 }
423
424 // libc++ dep
425 if (comp.config.link_libcpp) {
426 try system_libs.ensureUnusedCapacity(2);
427 system_libs.appendAssumeCapacity(.{ .path = comp.libcxxabi_static_lib.?.full_object_path });
428 system_libs.appendAssumeCapacity(.{ .path = comp.libcxx_static_lib.?.full_object_path });
429 }
430
431 const is_exe_or_dyn_lib = comp.config.output_mode == .Exe or
432 (comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic);
433
434 if (comp.config.link_libc and is_exe_or_dyn_lib) {
435 if (comp.zigc_static_lib) |zigc| {
436 const path = zigc.full_object_path;
437 self.classifyInputFile(try link.openArchiveInput(io, diags, path, false, false)) catch |err|
438 diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(err)});
439 }
440 }
441
442 // libc/libSystem dep
443 self.resolveLibSystem(arena, comp, &system_libs) catch |err| switch (err) {
444 error.MissingLibSystem => {}, // already reported
445 else => |e| return diags.fail("failed to resolve libSystem: {s}", .{@errorName(e)}),
446 };
447
448 for (comp.link_inputs) |link_input| switch (link_input) {
449 .object, .archive => continue,
450 .res => unreachable,
451 .dso => {
452 self.classifyInputFile(link_input) catch |err|
453 diags.addParseError(link_input.path(), "failed to parse input file: {t}", .{err});
454 },
455 };
456
457 for (system_libs.items) |lib| {
458 switch (Compilation.classifyFileExt(lib.path.sub_path)) {
459 .shared_library => {381 .shared_library => {
460 const dso_input = try link.openDsoInput(io, diags, lib.path, lib.needed, lib.weak, lib.reexport);382 const dso_input = try link.openDsoInput(io, diags, framework.path, framework.needed, framework.weak, false);
461 self.classifyInputFile(dso_input) catch |err|383 self.classifyInputFile(dso_input) catch |err|
462 diags.addParseError(lib.path, "failed to parse input file: {s}", .{@errorName(err)});384 diags.addParseError(framework.path, "failed to parse input file: {s}", .{@errorName(err)});
463 },385 },
464 .static_library => {386 .static_library => {
465 const archive_input = try link.openArchiveInput(io, diags, lib.path, lib.must_link, lib.hidden);387 const archive_input = try link.openArchiveInput(io, diags, framework.path, false, false);
466 self.classifyInputFile(archive_input) catch |err|388 self.classifyInputFile(archive_input) catch |err|
467 diags.addParseError(lib.path, "failed to parse input file: {s}", .{@errorName(err)});389 diags.addParseError(framework.path, "failed to parse input file: {s}", .{@errorName(err)});
468 },390 },
469 else => {391 else => {
470 dso: {392 dso: {
471 const dso_input = link.openDsoInput(io, diags, lib.path, lib.needed, lib.weak, lib.reexport) catch break :dso;393 const dso_input = link.openDsoInput(io, diags, framework.path, framework.needed, framework.weak, false) catch break :dso;
472 self.classifyInputFile(dso_input) catch break :dso;394 self.classifyInputFile(dso_input) catch break :dso;
473 continue;395 continue;
474 }396 }
475 ar: {397 ar: {
476 const archive_input = link.openArchiveInput(io, diags, lib.path, lib.must_link, lib.hidden) catch break :ar;398 const archive_input = link.openArchiveInput(io, diags, framework.path, false, false) catch break :ar;
477 self.classifyInputFile(archive_input) catch break :ar;399 self.classifyInputFile(archive_input) catch break :ar;
478 continue;400 continue;
479 }401 }
480 diags.addParseError(lib.path, "unknown file extension", .{});402 diags.addParseError(framework.path, "unknown file extension", .{});
481 },403 },
482 }404 }
483 }405 }
484406
485 // Finally, link against compiler_rt.
486 if (comp.compiler_rt_lib) |crt_file| {
487 const path = crt_file.full_object_path;
488 self.classifyInputFile(try link.openArchiveInput(io, diags, path, false, false)) catch |err|
489 diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(err)});
490 } else if (comp.compiler_rt_obj) |crt_file| {
491 const path = crt_file.full_object_path;
492 self.classifyInputFile(try link.openObjectInput(io, diags, path)) catch |err|
493 diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(err)});
494 }
495
496 try self.parseInputFiles();407 try self.parseInputFiles();
497 self.parseDependentDylibs() catch |err| {408 self.parseDependentDylibs() catch |err| {
498 switch (err) {409 switch (err) {
...@@ -666,9 +577,8 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {...@@ -666,9 +577,8 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
666 for (comp.link_inputs) |link_input| switch (link_input) {577 for (comp.link_inputs) |link_input| switch (link_input) {
667 .object, .archive => |obj| try argv.append(try obj.path.toString(arena)),578 .object, .archive => |obj| try argv.append(try obj.path.toString(arena)),
668 .res => |res| try argv.append(try res.path.toString(arena)),579 .res => |res| try argv.append(try res.path.toString(arena)),
669 .dso => |dso| {580 .dso => |dso| try argv.append(try dso.path.toString(arena)),
670 try argv.append(try dso.path.toString(arena));581 .tbd => |tbd| try argv.append(try tbd.path.toString(arena)),
671 },
672 };582 };
673583
674 for (comp.c_objects.items) |c_object| {584 for (comp.c_objects.items) |c_object| {
...@@ -754,7 +664,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {...@@ -754,7 +664,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
754 }664 }
755665
756 for (comp.link_inputs) |link_input| switch (link_input) {666 for (comp.link_inputs) |link_input| switch (link_input) {
757 .dso => continue, // handled below667 .dso, .tbd => continue, // handled below
758 .res => unreachable, // windows only668 .res => unreachable, // windows only
759 .object, .archive => |obj| {669 .object, .archive => |obj| {
760 if (obj.must_link) try argv.append("-force_load"); // TODO: verify this670 if (obj.must_link) try argv.append("-force_load"); // TODO: verify this
...@@ -788,7 +698,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {...@@ -788,7 +698,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
788 for (comp.link_inputs) |link_input| switch (link_input) {698 for (comp.link_inputs) |link_input| switch (link_input) {
789 .object, .archive => continue, // handled above699 .object, .archive => continue, // handled above
790 .res => unreachable, // windows only700 .res => unreachable, // windows only
791 .dso => |dso| {701 inline .dso, .tbd => |dso| {
792 try argv.ensureUnusedCapacity(2);702 try argv.ensureUnusedCapacity(2);
793 if (dso.needed) {703 if (dso.needed) {
794 argv.appendAssumeCapacity("-needed-l");704 argv.appendAssumeCapacity("-needed-l");
...@@ -836,46 +746,6 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {...@@ -836,46 +746,6 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
836 try Compilation.dumpArgv(io, argv.items);746 try Compilation.dumpArgv(io, argv.items);
837}747}
838748
839/// TODO delete this, libsystem must be resolved when setting up the compilation pipeline
840pub fn resolveLibSystem(
841 self: *MachO,
842 arena: Allocator,
843 comp: *Compilation,
844 out_libs: anytype,
845) !void {
846 const io = comp.io;
847 const diags = &comp.link_diags;
848
849 var test_path = std.array_list.Managed(u8).init(arena);
850 var checked_paths = std.array_list.Managed([]const u8).init(arena);
851
852 success: {
853 if (self.sdk_layout) |sdk_layout| switch (sdk_layout) {
854 .sdk => {
855 const dir = try fs.path.join(arena, &.{ comp.sysroot.?, "usr", "lib" });
856 if (try accessLibPath(arena, io, &test_path, &checked_paths, dir, "System")) break :success;
857 },
858 .vendored => {
859 const dir = try comp.dirs.zig_lib.join(arena, &.{ "libc", "darwin" });
860 if (try accessLibPath(arena, io, &test_path, &checked_paths, dir, "System")) break :success;
861 },
862 };
863
864 for (self.lib_directories) |directory| {
865 if (try accessLibPath(arena, io, &test_path, &checked_paths, directory.path orelse ".", "System")) break :success;
866 }
867
868 diags.addMissingLibraryError(checked_paths.items, "unable to find libSystem system library", .{});
869 return error.MissingLibSystem;
870 }
871
872 const libsystem_path = Path.initCwd(try arena.dupe(u8, test_path.items));
873 try out_libs.append(.{
874 .needed = true,
875 .path = libsystem_path,
876 });
877}
878
879pub fn classifyInputFile(self: *MachO, input: link.Input) !void {749pub fn classifyInputFile(self: *MachO, input: link.Input) !void {
880 const tracy = trace(@src());750 const tracy = trace(@src());
881 defer tracy.end();751 defer tracy.end();
...@@ -4497,7 +4367,7 @@ const SystemLib = struct {...@@ -4497,7 +4367,7 @@ const SystemLib = struct {
4497 .must_link = obj.must_link,4367 .must_link = obj.must_link,
4498 .hidden = obj.hidden,4368 .hidden = obj.hidden,
4499 },4369 },
4500 .dso => |dso| .{4370 inline .dso, .tbd => |dso| .{
4501 .path = dso.path,4371 .path = dso.path,
4502 .needed = dso.needed,4372 .needed = dso.needed,
4503 .weak = dso.weak,4373 .weak = dso.weak,
src/link/MachO/relocatable.zig+29-46
...@@ -1,25 +1,25 @@...@@ -1,25 +1,25 @@
1pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Path) link.Error!void {1pub fn flushObject(macho_file: *MachO, comp: *Compilation) link.Error!void {
2 const gpa = comp.gpa;
3 const io = comp.io;2 const io = comp.io;
4 const diags = &comp.link_diags;3 const diags = &comp.link_diags;
54
6 // TODO: "positional arguments" is a CLI concept, not a linker concept. Delete this unnecessary array list.5 one_input: {
7 var positionals = std.array_list.Managed(link.Input).init(gpa);6 if (macho_file.getZigObject() != null) {
8 defer positionals.deinit();7 break :one_input;
9 try positionals.ensureUnusedCapacity(comp.link_inputs.len);8 }
10 positionals.appendSliceAssumeCapacity(comp.link_inputs);9 var only_input: ?link.Input = null;
1110 for (macho_file.all_inputs.items) |input| switch (input) {
12 for (comp.c_objects.items) |c_object| {11 .res => unreachable,
13 try positionals.append(try link.openObjectInput(io, diags, c_object.status.success.object_path));12 .dso, .tbd => {},
14 }13 .object, .archive => if (only_input == null) {
1514 only_input = input;
16 if (module_obj_path) |path| try positionals.append(try link.openObjectInput(io, diags, path));15 } else {
1716 break :one_input;
18 if (macho_file.getZigObject() == null and positionals.items.len == 1) {17 },
18 };
19 // Instead of invoking a full-blown `-r` mode on the input which sadly will strip all19 // Instead of invoking a full-blown `-r` mode on the input which sadly will strip all
20 // debug info segments/sections (this is apparently by design by Apple), we copy20 // debug info segments/sections (this is apparently by design by Apple), we copy
21 // the *only* input file over.21 // the *only* input file over.
22 const path = positionals.items[0].path();22 const path = (only_input orelse break :one_input).path();
23 const in_file = path.root_dir.handle.openFile(io, path.sub_path, .{}) catch |err|23 const in_file = path.root_dir.handle.openFile(io, path.sub_path, .{}) catch |err|
24 return diags.fail("failed to open {f}: {s}", .{ path, @errorName(err) });24 return diags.fail("failed to open {f}: {s}", .{ path, @errorName(err) });
25 const stat = in_file.stat(io) catch |err|25 const stat = in_file.stat(io) catch |err|
...@@ -29,10 +29,12 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat...@@ -29,10 +29,12 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
29 return;29 return;
30 }30 }
3131
32 for (positionals.items) |link_input| {32 for (macho_file.all_inputs.items) |input| switch (input) {
33 macho_file.classifyInputFile(link_input) catch |err|33 .res => unreachable,
34 diags.addParseError(link_input.path(), "failed to read input file: {t}", .{err});34 .dso, .tbd => {},
35 }35 .object, .archive => macho_file.classifyInputFile(input) catch |err|
36 diags.addParseError(input.path(), "failed to read input file: {t}", .{err}),
37 };
3638
37 if (diags.hasErrors()) return error.AlreadyReported;39 if (diags.hasErrors()) return error.AlreadyReported;
3840
...@@ -75,35 +77,16 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat...@@ -75,35 +77,16 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
75 try writeHeader(macho_file, ncmds, sizeofcmds);77 try writeHeader(macho_file, ncmds, sizeofcmds);
76}78}
7779
78pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Path) link.Error!void {80pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void {
79 const gpa = comp.gpa;81 const gpa = comp.gpa;
80 const io = comp.io;
81 const diags = &macho_file.base.comp.link_diags;82 const diags = &macho_file.base.comp.link_diags;
8283
83 var positionals = std.array_list.Managed(link.Input).init(gpa);84 for (macho_file.all_inputs.items) |input| switch (input) {
84 defer positionals.deinit();85 .res => unreachable,
8586 .dso, .tbd => {},
86 try positionals.ensureUnusedCapacity(comp.link_inputs.len);87 .object, .archive => macho_file.classifyInputFile(input) catch |err|
87 positionals.appendSliceAssumeCapacity(comp.link_inputs);88 diags.addParseError(input.path(), "failed to read input file: {t}", .{err}),
8889 };
89 for (comp.c_objects.items) |c_object| {
90 try positionals.append(try link.openObjectInput(io, diags, c_object.status.success.object_path));
91 }
92
93 if (module_obj_path) |path| try positionals.append(try link.openObjectInput(io, diags, path));
94
95 if (comp.compiler_rt_strat == .obj) {
96 try positionals.append(try link.openObjectInput(io, diags, comp.compiler_rt_obj.?.full_object_path));
97 }
98
99 if (comp.ubsan_rt_strat == .obj) {
100 try positionals.append(try link.openObjectInput(io, diags, comp.ubsan_rt_obj.?.full_object_path));
101 }
102
103 for (positionals.items) |link_input| {
104 macho_file.classifyInputFile(link_input) catch |err|
105 diags.addParseError(link_input.path(), "failed to read input file: {t}", .{err});
106 }
10790
108 if (diags.hasErrors()) return error.AlreadyReported;91 if (diags.hasErrors()) return error.AlreadyReported;
10992
src/link/Wasm.zig+2
...@@ -3789,6 +3789,7 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void {...@@ -3789,6 +3789,7 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void {
3789 switch (input) {3789 switch (input) {
3790 .res => unreachable,3790 .res => unreachable,
3791 .dso => unreachable,3791 .dso => unreachable,
3792 .tbd => unreachable,
3792 .object, .archive => |obj| {3793 .object, .archive => |obj| {
3793 try argv.append(gpa, try obj.path.toString(comp.arena));3794 try argv.append(gpa, try obj.path.toString(comp.arena));
3794 },3795 },
...@@ -3798,6 +3799,7 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void {...@@ -3798,6 +3799,7 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void {
3798 switch (input) {3799 switch (input) {
3799 .res => unreachable,3800 .res => unreachable,
3800 .dso => unreachable,3801 .dso => unreachable,
3802 .tbd => unreachable,
3801 .object => |obj| try parseObject(wasm, obj),3803 .object => |obj| try parseObject(wasm, obj),
3802 .archive => |obj| try parseArchive(wasm, obj),3804 .archive => |obj| try parseArchive(wasm, obj),
3803 }3805 }
src/target.zig+1-1
...@@ -510,7 +510,7 @@ pub fn libcFullLinkFlags(target: *const std.Target) []const []const u8 {...@@ -510,7 +510,7 @@ pub fn libcFullLinkFlags(target: *const std.Target) []const []const u8 {
510 },510 },
511 // On SerenityOS libc includes libm, libpthread, libdl, and libssp.511 // On SerenityOS libc includes libm, libpthread, libdl, and libssp.
512 .serenity => &.{"-lc"},512 .serenity => &.{"-lc"},
513 else => &.{},513 else => if (target.os.tag.isDarwin()) &.{"-lSystem"} else &.{},
514 };514 };
515 return result;515 return result;
516}516}