| author | |
| committer | |
| log | c1ce1a2da70b1f3667df16212ace4c227aeaced1 |
| tree | fd60fdcaf2b3ccab262529165e940fb1b2a4df17 |
| parent | c1456afca0aaf0e9e2cdb29865766d8e017b7f06 |
| signature | Commit is signed but in an unrecognized format. |
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 | } | ||
| 99 | 103 | ||
| 100 | const os_tag = target.os.tag; | 104 | const os_tag = target.os.tag; |
| 101 | 105 | ||
| ... | @@ -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); |
| 195 | 192 | ||
| 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 jobs | 2429 | // 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); |
| 2461 | 2463 |
src/link.zig+122-43| ... | @@ -1236,15 +1236,15 @@ pub const File = struct { | ... | @@ -1236,15 +1236,15 @@ pub const File = struct { |
| 1236 | } | 1236 | } |
| 1237 | 1237 | ||
| 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); |
| 1241 | 1241 | } | |
| 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 | } |
| 1250 | 1250 | ||
| ... | @@ -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 a | 1450 | /// 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 | }; |
| 1454 | pub const ZcuTask = union(enum) { | 1455 | pub const ZcuTask = union(enum) { |
| 1455 | /// Sent once per update, as the very first `ZcuTask` in the update. Indicates that all per-file | 1456 | /// 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 diags | 1505 | 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 | } |
| 1652 | pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void { | 1714 | pub 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 from | 1935 | /// 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, | ||
| 1876 | 1940 | ||
| 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 | }; |
| 1899 | 1963 | ||
| 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 | } |
| 1906 | 1978 | ||
| 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 | } |
| 1913 | 1985 | ||
| 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 | } |
| 2250 | 2329 | ||
| 2251 | { | 2330 | { |
| ... | @@ -2700,7 +2779,7 @@ pub fn anyObjectInputs(inputs: []const Input) bool { | ... | @@ -2700,7 +2779,7 @@ pub fn anyObjectInputs(inputs: []const Input) bool { |
| 2700 | pub fn countObjectInputs(inputs: []const Input) usize { | 2779 | pub 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 { |
| 2710 | pub fn firstObjectInput(inputs: []const Input) ?Input.Object { | 2789 | pub 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 | } |
| 3917 | 3918 |
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 { |
| 729 | 730 | ||
| 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| ... | @@ -7146,7 +7146,6 @@ fn loadInputInner(elf: *Elf, input: link.Input) (Error || error{BadMagic})!void | ... | @@ -7146,7 +7146,6 @@ fn loadInputInner(elf: *Elf, input: link.Input) (Error || error{BadMagic})!void |
| 7146 | }, | 7146 | }, |
| 7147 | }; | 7147 | }; |
| 7148 | }, | 7148 | }, |
| 7149 | .res => unreachable, | ||
| 7150 | .dso => |dso| { | 7149 | .dso => |dso| { |
| 7151 | try elf.needed.ensureUnusedCapacity(elf.base.comp.gpa, 1); | 7150 | try elf.needed.ensureUnusedCapacity(elf.base.comp.gpa, 1); |
| 7152 | var fr = dso.file.reader(io, &buf); | 7151 | var fr = dso.file.reader(io, &buf); |
| ... | @@ -7163,6 +7162,8 @@ fn loadInputInner(elf: *Elf, input: link.Input) (Error || error{BadMagic})!void | ... | @@ -7163,6 +7162,8 @@ fn loadInputInner(elf: *Elf, input: link.Input) (Error || error{BadMagic})!void |
| 7163 | }, | 7162 | }, |
| 7164 | }; | 7163 | }; |
| 7165 | }, | 7164 | }, |
| 7165 | .res => unreachable, | ||
| 7166 | .tbd => unreachable, | ||
| 7166 | } | 7167 | } |
| 7167 | } | 7168 | } |
| 7168 | fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadParseInputError || error{BadMagic})!void { | 7169 | fn 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 { |
| 309 | 309 | ||
| 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 archives | 312 | .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 | }; |
| 565 | 566 | ||
| 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 { |
| 1102 | 1103 | ||
| 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-only | 1105 | .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 { |
| 1163 | 1165 | ||
| 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-only | 1167 | .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"); |
| 4 | 4 | ||
| 5 | base: link.File, | 5 | base: link.File, |
| 6 | 6 | ||
| 7 | all_inputs: std.ArrayList(link.Input), | ||
| 8 | |||
| 7 | rpath_list: []const []const u8, | 9 | rpath_list: []const []const u8, |
| 8 | 10 | ||
| 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; |
| 273 | 276 | ||
| 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 | } |
| 336 | 341 | ||
| 342 | pub 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 | |||
| 337 | pub fn flush( | 347 | pub 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(); |
| 345 | 355 | ||
| 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(); |
| 353 | 365 | ||
| 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-link | 366 | // --verbose-link |
| 361 | if (comp.verbose_link) try self.dumpArgv(comp); | 367 | if (comp.verbose_link) try self.dumpArgv(comp); |
| 362 | 368 | ||
| 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 | } | ||
| 395 | 372 | ||
| 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 | } |
| 405 | 377 | ||
| 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 | // frameworks | 378 | // 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 | } |
| 484 | 406 | ||
| 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 | }; |
| 673 | 583 | ||
| 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 | } |
| 755 | 665 | ||
| 756 | for (comp.link_inputs) |link_input| switch (link_input) { | 666 | for (comp.link_inputs) |link_input| switch (link_input) { |
| 757 | .dso => continue, // handled below | 667 | .dso, .tbd => continue, // handled below |
| 758 | .res => unreachable, // windows only | 668 | .res => unreachable, // windows only |
| 759 | .object, .archive => |obj| { | 669 | .object, .archive => |obj| { |
| 760 | if (obj.must_link) try argv.append("-force_load"); // TODO: verify this | 670 | 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 above | 699 | .object, .archive => continue, // handled above |
| 790 | .res => unreachable, // windows only | 700 | .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 | } |
| 838 | 748 | ||
| 839 | /// TODO delete this, libsystem must be resolved when setting up the compilation pipeline | ||
| 840 | pub 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 | |||
| 879 | pub fn classifyInputFile(self: *MachO, input: link.Input) !void { | 749 | pub 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 @@ |
| 1 | pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Path) link.Error!void { | 1 | pub 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; |
| 5 | 4 | ||
| 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; |
| 11 | 10 | 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) { |
| 15 | 14 | only_input = input; | |
| 16 | if (module_obj_path) |path| try positionals.append(try link.openObjectInput(io, diags, path)); | 15 | } else { |
| 17 | 16 | 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 all | 19 | // 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 copy | 20 | // 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 | } |
| 31 | 31 | ||
| 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 | }; | ||
| 36 | 38 | ||
| 37 | if (diags.hasErrors()) return error.AlreadyReported; | 39 | if (diags.hasErrors()) return error.AlreadyReported; |
| 38 | 40 | ||
| ... | @@ -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 | } |
| 77 | 79 | ||
| 78 | pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Path) link.Error!void { | 80 | pub 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; |
| 82 | 83 | ||
| 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, |
| 85 | 86 | .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}), |
| 88 | 89 | }; | |
| 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 | } | ||
| 107 | 90 | ||
| 108 | if (diags.hasErrors()) return error.AlreadyReported; | 91 | if (diags.hasErrors()) return error.AlreadyReported; |
| 109 | 92 |
src/link/Wasm.zig+2| ... | @@ -3783,6 +3783,7 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void { | ... | @@ -3783,6 +3783,7 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void { |
| 3783 | switch (input) { | 3783 | switch (input) { |
| 3784 | .res => unreachable, | 3784 | .res => unreachable, |
| 3785 | .dso => unreachable, | 3785 | .dso => unreachable, |
| 3786 | .tbd => unreachable, | ||
| 3786 | .object, .archive => |obj| { | 3787 | .object, .archive => |obj| { |
| 3787 | try argv.append(gpa, try obj.path.toString(comp.arena)); | 3788 | try argv.append(gpa, try obj.path.toString(comp.arena)); |
| 3788 | }, | 3789 | }, |
| ... | @@ -3792,6 +3793,7 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void { | ... | @@ -3792,6 +3793,7 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void { |
| 3792 | switch (input) { | 3793 | switch (input) { |
| 3793 | .res => unreachable, | 3794 | .res => unreachable, |
| 3794 | .dso => unreachable, | 3795 | .dso => unreachable, |
| 3796 | .tbd => unreachable, | ||
| 3795 | .object => |obj| try parseObject(wasm, obj), | 3797 | .object => |obj| try parseObject(wasm, obj), |
| 3796 | .archive => |obj| try parseArchive(wasm, obj), | 3798 | .archive => |obj| try parseArchive(wasm, obj), |
| 3797 | } | 3799 | } |
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 | } |