| author | |
| committer | |
| log | e3381ce10ee1ffec2ab7b82dd1b87a5aedaeef97 |
| tree | 7616c3532d4956bfb34b6c168274c68469fcc32e |
| parent | 48abf1a34e90acd42501f5296ba6a16c90f60fe9 |
| parent | 77d47494c7ccbe045b713900b32a85c859f78ed0 |
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/3690911 files changed, 239 insertions(+), 148 deletions(-)
src/Compilation.zig+3-2| ... | ... | @@ -2891,12 +2891,13 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 2891 | 2891 | } |
| 2892 | 2892 | } |
| 2893 | 2893 | |
| 2894 | for (comp.link_inputs) |input| if (input.path()) |path| { | |
| 2894 | for (comp.link_inputs) |input| { | |
| 2895 | const path = input.path(); | |
| 2895 | 2896 | try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{ |
| 2896 | 2897 | path.root_dir.path orelse ".", |
| 2897 | 2898 | path.sub_path, |
| 2898 | 2899 | })); |
| 2899 | }; | |
| 2900 | } | |
| 2900 | 2901 | |
| 2901 | 2902 | // For compiling Win32 resources, we rely on the cache hash system to avoid duplicating work. |
| 2902 | 2903 | // Add a Job for each Win32 resource file. |
src/link.zig+135-72| ... | ... | @@ -995,11 +995,7 @@ pub const File = struct { |
| 995 | 995 | .{}, |
| 996 | 996 | ) catch |err| { |
| 997 | 997 | const diags = &base.comp.link_diags; |
| 998 | return diags.fail("failed to copy '{f}' to '{f}': {t}", .{ | |
| 999 | std.fmt.alt(@as(Path, cached_pp_file_path), .formatEscapeChar), | |
| 1000 | std.fmt.alt(@as(Path, emit), .formatEscapeChar), | |
| 1001 | err, | |
| 1002 | }); | |
| 998 | return diags.fail("failed to copy {qf} to {qf}: {t}", .{ cached_pp_file_path, emit, err }); | |
| 1003 | 999 | }; |
| 1004 | 1000 | return; |
| 1005 | 1001 | } |
| ... | ... | @@ -1510,7 +1506,6 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { |
| 1510 | 1506 | .object => |obj| diags.addParseError(obj.path, "failed to parse object: {t}", .{e}), |
| 1511 | 1507 | .archive => |obj| diags.addParseError(obj.path, "failed to parse archive: {t}", .{e}), |
| 1512 | 1508 | .res => |res| diags.addParseError(res.path, "failed to parse Windows resource: {t}", .{e}), |
| 1513 | .dso_exact => diags.addError("failed to handle dso_exact: {t}", .{e}), | |
| 1514 | 1509 | }, |
| 1515 | 1510 | }; |
| 1516 | 1511 | prog_node.completeOne(); |
| ... | ... | @@ -1740,7 +1735,7 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void |
| 1740 | 1735 | if (comp.bin_file) |lf| { |
| 1741 | 1736 | lf.updateLineNumber(pt, line_update.inst, line_update.line) catch |err| switch (err) { |
| 1742 | 1737 | error.OutOfMemory => diags.setAllocFailure(), |
| 1743 | else => |e| log.err("update line number failed: {s}", .{@errorName(e)}), | |
| 1738 | else => |e| log.err("update line number failed: {t}", .{e}), | |
| 1744 | 1739 | }; |
| 1745 | 1740 | } |
| 1746 | 1741 | } |
| ... | ... | @@ -1753,7 +1748,7 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void |
| 1753 | 1748 | if (comp.bin_file) |lf| { |
| 1754 | 1749 | lf.lostTracking(pt, ti) catch |err| switch (err) { |
| 1755 | 1750 | error.OutOfMemory => diags.setAllocFailure(), |
| 1756 | else => |e| log.err("lost tracking failed: {s}", .{@errorName(e)}), | |
| 1751 | else => |e| log.err("lost tracking failed: {t}", .{e}), | |
| 1757 | 1752 | }; |
| 1758 | 1753 | } |
| 1759 | 1754 | } |
| ... | ... | @@ -1824,13 +1819,14 @@ pub const UnresolvedInput = union(enum) { |
| 1824 | 1819 | path_query: PathQuery, |
| 1825 | 1820 | /// Strings that come from GNU ld scripts. Is it a filename? Is it a path? |
| 1826 | 1821 | /// Who knows! Fuck around and find out. |
| 1827 | ambiguous_name: NameQuery, | |
| 1828 | /// Put exactly this string in the dynamic section, no rpath. | |
| 1829 | dso_exact: Input.DsoExact, | |
| 1822 | ambiguous_name: AmbiguousNameQuery, | |
| 1830 | 1823 | |
| 1831 | 1824 | pub const NameQuery = struct { |
| 1832 | 1825 | name: []const u8, |
| 1833 | 1826 | query: Query, |
| 1827 | // Corresponds to GNU ld `-l :path/to/filename`, meaning that `name` is a path relative to | |
| 1828 | // the library search path rather than just a library name. | |
| 1829 | name_done: bool, | |
| 1834 | 1830 | }; |
| 1835 | 1831 | |
| 1836 | 1832 | pub const PathQuery = struct { |
| ... | ... | @@ -1838,6 +1834,11 @@ pub const UnresolvedInput = union(enum) { |
| 1838 | 1834 | query: Query, |
| 1839 | 1835 | }; |
| 1840 | 1836 | |
| 1837 | pub const AmbiguousNameQuery = struct { | |
| 1838 | name: []const u8, | |
| 1839 | query: Query, | |
| 1840 | }; | |
| 1841 | ||
| 1841 | 1842 | pub const Query = struct { |
| 1842 | 1843 | needed: bool = false, |
| 1843 | 1844 | weak: bool = false, |
| ... | ... | @@ -1871,7 +1872,6 @@ pub const Input = union(enum) { |
| 1871 | 1872 | /// May not be a GNU ld script. Those are resolved when converting from |
| 1872 | 1873 | /// `UnresolvedInput` to `Input` values. |
| 1873 | 1874 | dso: Dso, |
| 1874 | dso_exact: DsoExact, | |
| 1875 | 1875 | |
| 1876 | 1876 | pub const Object = struct { |
| 1877 | 1877 | path: Path, |
| ... | ... | @@ -1891,29 +1891,22 @@ pub const Input = union(enum) { |
| 1891 | 1891 | needed: bool, |
| 1892 | 1892 | weak: bool, |
| 1893 | 1893 | reexport: bool, |
| 1894 | }; | |
| 1894 | fallback_soname: FallbackSoname, | |
| 1895 | 1895 | |
| 1896 | pub const DsoExact = struct { | |
| 1897 | /// Includes the ":" prefix. This is intended to be put into the DSO | |
| 1898 | /// section verbatim with no corresponding rpaths. | |
| 1899 | name: []const u8, | |
| 1896 | pub const FallbackSoname = enum { basename, full_path }; | |
| 1900 | 1897 | }; |
| 1901 | 1898 | |
| 1902 | /// Returns `null` in the case of `dso_exact`. | |
| 1903 | pub fn path(input: Input) ?Path { | |
| 1899 | pub fn path(input: Input) Path { | |
| 1904 | 1900 | return switch (input) { |
| 1905 | 1901 | .object, .archive => |obj| obj.path, |
| 1906 | 1902 | inline .res, .dso => |x| x.path, |
| 1907 | .dso_exact => null, | |
| 1908 | 1903 | }; |
| 1909 | 1904 | } |
| 1910 | 1905 | |
| 1911 | /// Returns `null` in the case of `dso_exact`. | |
| 1912 | pub fn pathAndFile(input: Input) ?struct { Path, Io.File } { | |
| 1906 | pub fn pathAndFile(input: Input) struct { Path, Io.File } { | |
| 1913 | 1907 | return switch (input) { |
| 1914 | 1908 | .object, .archive => |obj| .{ obj.path, obj.file }, |
| 1915 | 1909 | inline .res, .dso => |x| .{ x.path, x.file }, |
| 1916 | .dso_exact => null, | |
| 1917 | 1910 | }; |
| 1918 | 1911 | } |
| 1919 | 1912 | |
| ... | ... | @@ -1921,7 +1914,6 @@ pub const Input = union(enum) { |
| 1921 | 1914 | return switch (input) { |
| 1922 | 1915 | .object, .archive => |obj| obj.path.basename(), |
| 1923 | 1916 | inline .res, .dso => |x| x.path.basename(), |
| 1924 | .dso_exact => "dso_exact", | |
| 1925 | 1917 | }; |
| 1926 | 1918 | } |
| 1927 | 1919 | }; |
| ... | ... | @@ -1952,9 +1944,7 @@ pub fn hashInputs(man: *Cache.Manifest, link_inputs: []const Input) !void { |
| 1952 | 1944 | man.hash.add(dso.needed); |
| 1953 | 1945 | man.hash.add(dso.weak); |
| 1954 | 1946 | man.hash.add(dso.reexport); |
| 1955 | }, | |
| 1956 | .dso_exact => |dso_exact| { | |
| 1957 | man.hash.addBytes(dso_exact.name); | |
| 1947 | man.hash.add(dso.fallback_soname); | |
| 1958 | 1948 | }, |
| 1959 | 1949 | } |
| 1960 | 1950 | } |
| ... | ... | @@ -2005,7 +1995,7 @@ pub fn resolveInputs( |
| 2005 | 1995 | .name_query => |name_query| { |
| 2006 | 1996 | const query = name_query.query; |
| 2007 | 1997 | |
| 2008 | // Checked in the first pass above while looking for libc libraries. | |
| 1998 | // Checked in the first pass in `main.zig` while looking for libc libraries. | |
| 2009 | 1999 | assert(!fs.path.isAbsolute(name_query.name)); |
| 2010 | 2000 | |
| 2011 | 2001 | checked_paths.clearRetainingCapacity(); |
| ... | ... | @@ -2190,10 +2180,6 @@ pub fn resolveInputs( |
| 2190 | 2180 | } |
| 2191 | 2181 | continue; |
| 2192 | 2182 | }, |
| 2193 | .dso_exact => |dso_exact| { | |
| 2194 | try resolved_inputs.append(gpa, .{ .dso_exact = dso_exact }); | |
| 2195 | continue; | |
| 2196 | }, | |
| 2197 | 2183 | } |
| 2198 | 2184 | comptime unreachable; |
| 2199 | 2185 | } |
| ... | ... | @@ -2201,8 +2187,8 @@ pub fn resolveInputs( |
| 2201 | 2187 | if (failed_libs.items.len > 0) { |
| 2202 | 2188 | for (failed_libs.items) |f| { |
| 2203 | 2189 | const searched_paths = if (f.checked_paths.len == 0) " none" else f.checked_paths; |
| 2204 | std.log.err("unable to find {s} system library '{s}' using strategy '{s}'. searched paths:{s}", .{ | |
| 2205 | @tagName(f.preferred_mode), f.name, @tagName(f.strategy), searched_paths, | |
| 2190 | std.log.err("unable to find {t} system library {q} using strategy {t}. searched paths:{s}", .{ | |
| 2191 | f.preferred_mode, f.name, f.strategy, searched_paths, | |
| 2206 | 2192 | }); |
| 2207 | 2193 | } |
| 2208 | 2194 | std.process.exit(1); |
| ... | ... | @@ -2237,7 +2223,7 @@ fn resolveLibInput( |
| 2237 | 2223 | |
| 2238 | 2224 | const lib_name = name_query.name; |
| 2239 | 2225 | |
| 2240 | if (target.os.tag.isDarwin() and link_mode == .dynamic) tbd: { | |
| 2226 | if (target.os.tag.isDarwin() and link_mode == .dynamic and !name_query.name_done) tbd: { | |
| 2241 | 2227 | // Prefer .tbd over .dylib. |
| 2242 | 2228 | const test_path: Path = .{ |
| 2243 | 2229 | .root_dir = lib_directory, |
| ... | ... | @@ -2246,17 +2232,27 @@ fn resolveLibInput( |
| 2246 | 2232 | try checked_paths.print(gpa, "\n {f}", .{test_path}); |
| 2247 | 2233 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { |
| 2248 | 2234 | error.FileNotFound => break :tbd, |
| 2249 | else => |e| fatal("unable to search for tbd library '{f}': {s}", .{ test_path, @errorName(e) }), | |
| 2235 | else => |e| fatal("searching for tbd library {qf}: {t}", .{ test_path, e }), | |
| 2250 | 2236 | }; |
| 2251 | 2237 | errdefer file.close(io); |
| 2252 | return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, name_query.query); | |
| 2238 | return finishResolveLibInput( | |
| 2239 | io, | |
| 2240 | resolved_inputs, | |
| 2241 | archive_dedup, | |
| 2242 | test_path, | |
| 2243 | file, | |
| 2244 | link_mode, | |
| 2245 | name_query.query, | |
| 2246 | .basename, | |
| 2247 | ); | |
| 2253 | 2248 | } |
| 2254 | 2249 | |
| 2255 | 2250 | { |
| 2256 | 2251 | const test_path: Path = .{ |
| 2257 | 2252 | .root_dir = lib_directory, |
| 2258 | .sub_path = try std.fmt.allocPrint(arena, "{s}{s}{s}", .{ | |
| 2259 | target.libPrefix(), lib_name, | |
| 2253 | .sub_path = if (name_query.name_done) lib_name else try std.fmt.allocPrint(arena, "{s}{s}{s}", .{ | |
| 2254 | target.libPrefix(), | |
| 2255 | lib_name, | |
| 2260 | 2256 | switch (link_mode) { |
| 2261 | 2257 | .static => target.staticLibSuffix(), |
| 2262 | 2258 | .dynamic => target.dynamicLibSuffix(), |
| ... | ... | @@ -2267,7 +2263,7 @@ fn resolveLibInput( |
| 2267 | 2263 | switch (try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, .{ |
| 2268 | 2264 | .path = test_path, |
| 2269 | 2265 | .query = name_query.query, |
| 2270 | }, link_mode, color)) { | |
| 2266 | }, link_mode, color, .basename)) { | |
| 2271 | 2267 | .no_match => {}, |
| 2272 | 2268 | .ok => return .ok, |
| 2273 | 2269 | } |
| ... | ... | @@ -2275,7 +2271,7 @@ fn resolveLibInput( |
| 2275 | 2271 | |
| 2276 | 2272 | // In the case of Darwin, the main check will be .dylib, so here we |
| 2277 | 2273 | // additionally check for .so files. |
| 2278 | if (target.os.tag.isDarwin() and link_mode == .dynamic) so: { | |
| 2274 | if (target.os.tag.isDarwin() and link_mode == .dynamic and !name_query.name_done) so: { | |
| 2279 | 2275 | const test_path: Path = .{ |
| 2280 | 2276 | .root_dir = lib_directory, |
| 2281 | 2277 | .sub_path = try std.fmt.allocPrint(arena, "lib{s}.so", .{lib_name}), |
| ... | ... | @@ -2283,17 +2279,24 @@ fn resolveLibInput( |
| 2283 | 2279 | try checked_paths.print(gpa, "\n {f}", .{test_path}); |
| 2284 | 2280 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { |
| 2285 | 2281 | error.FileNotFound => break :so, |
| 2286 | else => |e| fatal("unable to search for so library '{f}': {s}", .{ | |
| 2287 | test_path, @errorName(e), | |
| 2288 | }), | |
| 2282 | else => |e| fatal("unable to search for so library {qf}: {t}", .{ test_path, e }), | |
| 2289 | 2283 | }; |
| 2290 | 2284 | errdefer file.close(io); |
| 2291 | return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, name_query.query); | |
| 2285 | return finishResolveLibInput( | |
| 2286 | io, | |
| 2287 | resolved_inputs, | |
| 2288 | archive_dedup, | |
| 2289 | test_path, | |
| 2290 | file, | |
| 2291 | link_mode, | |
| 2292 | name_query.query, | |
| 2293 | .basename, | |
| 2294 | ); | |
| 2292 | 2295 | } |
| 2293 | 2296 | |
| 2294 | 2297 | // In the case of MinGW, the main check will be .lib but we also need to |
| 2295 | 2298 | // look for `libfoo.a`. |
| 2296 | if (target.isMinGW() and link_mode == .static) mingw: { | |
| 2299 | if (target.isMinGW() and link_mode == .static and !name_query.name_done) mingw: { | |
| 2297 | 2300 | const test_path: Path = .{ |
| 2298 | 2301 | .root_dir = lib_directory, |
| 2299 | 2302 | .sub_path = try std.fmt.allocPrint(arena, "lib{s}.a", .{lib_name}), |
| ... | ... | @@ -2301,21 +2304,32 @@ fn resolveLibInput( |
| 2301 | 2304 | try checked_paths.print(gpa, "\n {f}", .{test_path}); |
| 2302 | 2305 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { |
| 2303 | 2306 | error.FileNotFound => break :mingw, |
| 2304 | else => |e| fatal("unable to search for static library '{f}': {s}", .{ test_path, @errorName(e) }), | |
| 2307 | else => |e| fatal("unable to search for static library {qf}: {t}", .{ test_path, e }), | |
| 2305 | 2308 | }; |
| 2306 | 2309 | errdefer file.close(io); |
| 2307 | return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, name_query.query); | |
| 2310 | return finishResolveLibInput( | |
| 2311 | io, | |
| 2312 | resolved_inputs, | |
| 2313 | archive_dedup, | |
| 2314 | test_path, | |
| 2315 | file, | |
| 2316 | link_mode, | |
| 2317 | name_query.query, | |
| 2318 | .basename, | |
| 2319 | ); | |
| 2308 | 2320 | } |
| 2309 | 2321 | |
| 2310 | 2322 | // In the case of OpenBSD, dynamic libraries are always versioned, without |
| 2311 | 2323 | // unversioned symlinks. OpenBSD patches LLD to select the highest-versioned |
| 2312 | 2324 | // shared library, and this code is intended to match that upstream behavior. |
| 2313 | if (target.isOpenBSDLibC() and link_mode == .dynamic) versioned: { | |
| 2325 | if (target.isOpenBSDLibC() and link_mode == .dynamic and !name_query.name_done) versioned: { | |
| 2314 | 2326 | const prefix = try std.fmt.allocPrint(arena, "lib{s}.so.", .{lib_name}); |
| 2315 | 2327 | |
| 2316 | 2328 | var dir = lib_directory.handle.openDir(io, ".", .{ .iterate = true }) catch |err| switch (err) { |
| 2317 | 2329 | error.NotDir, error.FileNotFound => break :versioned, |
| 2318 | else => |e| fatal("unable to search for shared library '{s}.*': {s}", .{ prefix, @errorName(e) }), | |
| 2330 | else => |e| fatal("unable to search for shared library \"{f}.*\": {t}", .{ | |
| 2331 | std.zig.fmtString(prefix), e, | |
| 2332 | }), | |
| 2319 | 2333 | }; |
| 2320 | 2334 | defer dir.close(io); |
| 2321 | 2335 | |
| ... | ... | @@ -2325,7 +2339,7 @@ fn resolveLibInput( |
| 2325 | 2339 | |
| 2326 | 2340 | var iter = dir.iterate(); |
| 2327 | 2341 | while (iter.next(io) catch |err| { |
| 2328 | fatal("unable to scan library directory '{s}'", .{@errorName(err)}); | |
| 2342 | fatal("scanning library directory: {t}", .{err}); | |
| 2329 | 2343 | }) |entry| { |
| 2330 | 2344 | if (entry.kind != .file) continue; |
| 2331 | 2345 | if (!std.mem.startsWith(u8, entry.name, prefix)) continue; |
| ... | ... | @@ -2354,7 +2368,7 @@ fn resolveLibInput( |
| 2354 | 2368 | switch (try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, .{ |
| 2355 | 2369 | .path = test_path, |
| 2356 | 2370 | .query = name_query.query, |
| 2357 | }, link_mode, color)) { | |
| 2371 | }, link_mode, color, .basename)) { | |
| 2358 | 2372 | .no_match => {}, |
| 2359 | 2373 | .ok => return .ok, |
| 2360 | 2374 | } |
| ... | ... | @@ -2395,6 +2409,7 @@ fn finishResolveLibInput( |
| 2395 | 2409 | file: Io.File, |
| 2396 | 2410 | link_mode: std.lang.LinkMode, |
| 2397 | 2411 | query: UnresolvedInput.Query, |
| 2412 | fallback_soname: Input.Dso.FallbackSoname, | |
| 2398 | 2413 | ) ResolveLibInputResult { |
| 2399 | 2414 | switch (link_mode) { |
| 2400 | 2415 | .static => { |
| ... | ... | @@ -2413,13 +2428,16 @@ fn finishResolveLibInput( |
| 2413 | 2428 | .hidden = query.hidden, |
| 2414 | 2429 | } }); |
| 2415 | 2430 | }, |
| 2416 | .dynamic => resolved_inputs.appendAssumeCapacity(.{ .dso = .{ | |
| 2417 | .path = path, | |
| 2418 | .file = file, | |
| 2419 | .needed = query.needed, | |
| 2420 | .weak = query.weak, | |
| 2421 | .reexport = query.reexport, | |
| 2422 | } }), | |
| 2431 | .dynamic => resolved_inputs.appendAssumeCapacity(.{ | |
| 2432 | .dso = .{ | |
| 2433 | .path = path, | |
| 2434 | .file = file, | |
| 2435 | .needed = query.needed, | |
| 2436 | .weak = query.weak, | |
| 2437 | .reexport = query.reexport, | |
| 2438 | .fallback_soname = fallback_soname, | |
| 2439 | }, | |
| 2440 | }), | |
| 2423 | 2441 | } |
| 2424 | 2442 | return .ok; |
| 2425 | 2443 | } |
| ... | ... | @@ -2441,11 +2459,37 @@ fn resolvePathInput( |
| 2441 | 2459 | color: std.zig.Color, |
| 2442 | 2460 | ) Allocator.Error!?ResolveLibInputResult { |
| 2443 | 2461 | switch (Compilation.classifyFileExt(pq.path.sub_path)) { |
| 2444 | .static_library => return try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, pq, .static, color), | |
| 2445 | .shared_library => return try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, pq, .dynamic, color), | |
| 2462 | .static_library => return try resolvePathInputLib( | |
| 2463 | gpa, | |
| 2464 | arena, | |
| 2465 | io, | |
| 2466 | unresolved_inputs, | |
| 2467 | resolved_inputs, | |
| 2468 | ld_script_bytes, | |
| 2469 | archive_dedup, | |
| 2470 | target, | |
| 2471 | pq, | |
| 2472 | .static, | |
| 2473 | color, | |
| 2474 | .full_path, | |
| 2475 | ), | |
| 2476 | .shared_library => return try resolvePathInputLib( | |
| 2477 | gpa, | |
| 2478 | arena, | |
| 2479 | io, | |
| 2480 | unresolved_inputs, | |
| 2481 | resolved_inputs, | |
| 2482 | ld_script_bytes, | |
| 2483 | archive_dedup, | |
| 2484 | target, | |
| 2485 | pq, | |
| 2486 | .dynamic, | |
| 2487 | color, | |
| 2488 | .full_path, | |
| 2489 | ), | |
| 2446 | 2490 | .object => { |
| 2447 | 2491 | var file = pq.path.root_dir.handle.openFile(io, pq.path.sub_path, .{}) catch |err| |
| 2448 | fatal("failed to open object {f}: {s}", .{ pq.path, @errorName(err) }); | |
| 2492 | fatal("failed to open object {f}: {t}", .{ pq.path, err }); | |
| 2449 | 2493 | errdefer file.close(io); |
| 2450 | 2494 | try resolved_inputs.append(gpa, .{ .object = .{ |
| 2451 | 2495 | .path = pq.path, |
| ... | ... | @@ -2457,7 +2501,7 @@ fn resolvePathInput( |
| 2457 | 2501 | }, |
| 2458 | 2502 | .res => { |
| 2459 | 2503 | var file = pq.path.root_dir.handle.openFile(io, pq.path.sub_path, .{}) catch |err| |
| 2460 | fatal("failed to open windows resource {f}: {s}", .{ pq.path, @errorName(err) }); | |
| 2504 | fatal("failed to open windows resource {f}: {t}", .{ pq.path, err }); | |
| 2461 | 2505 | errdefer file.close(io); |
| 2462 | 2506 | try resolved_inputs.append(gpa, .{ .res = .{ |
| 2463 | 2507 | .path = pq.path, |
| ... | ... | @@ -2485,6 +2529,7 @@ fn resolvePathInputLib( |
| 2485 | 2529 | pq: UnresolvedInput.PathQuery, |
| 2486 | 2530 | link_mode: std.lang.LinkMode, |
| 2487 | 2531 | color: std.zig.Color, |
| 2532 | fallback_soname: Input.Dso.FallbackSoname, | |
| 2488 | 2533 | ) Allocator.Error!ResolveLibInputResult { |
| 2489 | 2534 | try resolved_inputs.ensureUnusedCapacity(gpa, 1); |
| 2490 | 2535 | try archive_dedup.ensureUnusedCapacity(gpa, 1); |
| ... | ... | @@ -2498,21 +2543,30 @@ fn resolvePathInputLib( |
| 2498 | 2543 | }) { |
| 2499 | 2544 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { |
| 2500 | 2545 | error.FileNotFound => return .no_match, |
| 2501 | else => |e| fatal("unable to search for {t} library '{f}': {t}", .{ | |
| 2546 | else => |e| fatal("unable to search for {t} library {qf}: {t}", .{ | |
| 2502 | 2547 | link_mode, std.fmt.alt(test_path, .formatEscapeChar), e, |
| 2503 | 2548 | }), |
| 2504 | 2549 | }; |
| 2505 | 2550 | errdefer file.close(io); |
| 2506 | 2551 | try ld_script_bytes.resize(gpa, @max(std.elf.MAGIC.len, std.elf.ARMAG.len)); |
| 2507 | 2552 | const n = file.readPositionalAll(io, ld_script_bytes.items, 0) catch |err| |
| 2508 | fatal("failed to read '{f}': {t}", .{ std.fmt.alt(test_path, .formatEscapeChar), err }); | |
| 2553 | fatal("failed to read {qf}: {t}", .{ test_path, err }); | |
| 2509 | 2554 | const buf = ld_script_bytes.items[0..n]; |
| 2510 | 2555 | if (mem.startsWith(u8, buf, std.elf.MAGIC) or |
| 2511 | 2556 | mem.startsWith(u8, buf, std.elf.ARMAG) or |
| 2512 | 2557 | mem.startsWith(u8, buf, std.elf.ARMAG_THIN)) |
| 2513 | 2558 | { |
| 2514 | 2559 | // Appears to be an ELF or archive file. |
| 2515 | return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, pq.query); | |
| 2560 | return finishResolveLibInput( | |
| 2561 | io, | |
| 2562 | resolved_inputs, | |
| 2563 | archive_dedup, | |
| 2564 | test_path, | |
| 2565 | file, | |
| 2566 | link_mode, | |
| 2567 | pq.query, | |
| 2568 | fallback_soname, | |
| 2569 | ); | |
| 2516 | 2570 | } |
| 2517 | 2571 | const stat = file.stat(io) catch |err| |
| 2518 | 2572 | fatal("failed to stat {f}: {t}", .{ test_path, err }); |
| ... | ... | @@ -2563,6 +2617,7 @@ fn resolvePathInputLib( |
| 2563 | 2617 | unresolved_inputs.appendAssumeCapacity(.{ .name_query = .{ |
| 2564 | 2618 | .name = try arena.dupe(u8, arg.path["-l".len..]), |
| 2565 | 2619 | .query = query, |
| 2620 | .name_done = false, | |
| 2566 | 2621 | } }); |
| 2567 | 2622 | } else { |
| 2568 | 2623 | unresolved_inputs.appendAssumeCapacity(.{ .ambiguous_name = .{ |
| ... | ... | @@ -2577,12 +2632,19 @@ fn resolvePathInputLib( |
| 2577 | 2632 | |
| 2578 | 2633 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { |
| 2579 | 2634 | error.FileNotFound => return .no_match, |
| 2580 | else => |e| fatal("unable to search for {s} library {f}: {s}", .{ | |
| 2581 | @tagName(link_mode), test_path, @errorName(e), | |
| 2582 | }), | |
| 2635 | else => |e| fatal("unable to search for {t} library {f}: {t}", .{ link_mode, test_path, e }), | |
| 2583 | 2636 | }; |
| 2584 | 2637 | errdefer file.close(io); |
| 2585 | return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, pq.query); | |
| 2638 | return finishResolveLibInput( | |
| 2639 | io, | |
| 2640 | resolved_inputs, | |
| 2641 | archive_dedup, | |
| 2642 | test_path, | |
| 2643 | file, | |
| 2644 | link_mode, | |
| 2645 | pq.query, | |
| 2646 | fallback_soname, | |
| 2647 | ); | |
| 2586 | 2648 | } |
| 2587 | 2649 | |
| 2588 | 2650 | pub fn openObject(io: Io, path: Path, must_link: bool, hidden: bool) !Input.Object { |
| ... | ... | @@ -2605,6 +2667,7 @@ pub fn openDso(io: Io, path: Path, needed: bool, weak: bool, reexport: bool) !In |
| 2605 | 2667 | .needed = needed, |
| 2606 | 2668 | .weak = weak, |
| 2607 | 2669 | .reexport = reexport, |
| 2670 | .fallback_soname = .full_path, | |
| 2608 | 2671 | }; |
| 2609 | 2672 | } |
| 2610 | 2673 | |
| ... | ... | @@ -2636,7 +2699,7 @@ pub fn anyObjectInputs(inputs: []const Input) bool { |
| 2636 | 2699 | pub fn countObjectInputs(inputs: []const Input) usize { |
| 2637 | 2700 | var count: usize = 0; |
| 2638 | 2701 | for (inputs) |input| switch (input) { |
| 2639 | .dso, .dso_exact => continue, | |
| 2702 | .dso => continue, | |
| 2640 | 2703 | .res, .object, .archive => count += 1, |
| 2641 | 2704 | }; |
| 2642 | 2705 | return count; |
| ... | ... | @@ -2646,7 +2709,7 @@ pub fn countObjectInputs(inputs: []const Input) usize { |
| 2646 | 2709 | pub fn firstObjectInput(inputs: []const Input) ?Input.Object { |
| 2647 | 2710 | for (inputs) |input| switch (input) { |
| 2648 | 2711 | .object, .archive => |obj| return obj, |
| 2649 | .res, .dso, .dso_exact => continue, | |
| 2712 | .res, .dso => continue, | |
| 2650 | 2713 | }; |
| 2651 | 2714 | return null; |
| 2652 | 2715 | } |
src/link/Coff.zig+1-2| ... | ... | @@ -3905,7 +3905,7 @@ pub fn loadInput(coff: *Coff, input: link.Input) link.Error!void { |
| 3905 | 3905 | const comp = coff.base.comp; |
| 3906 | 3906 | const io = comp.io; |
| 3907 | 3907 | |
| 3908 | const path = input.path() orelse unreachable; | |
| 3908 | const path = input.path(); | |
| 3909 | 3909 | const gop = try coff.inputs.getOrPut(comp.gpa, path); |
| 3910 | 3910 | if (gop.found_existing) return; |
| 3911 | 3911 | errdefer _ = coff.inputs.swapRemove(path); |
| ... | ... | @@ -3935,7 +3935,6 @@ pub fn loadInput(coff: *Coff, input: link.Input) link.Error!void { |
| 3935 | 3935 | coff.loadDll(dso.path, &fr) catch |err| |
| 3936 | 3936 | return coff.failLoadInput(err, &fr, dso.path); |
| 3937 | 3937 | }, |
| 3938 | .dso_exact => unreachable, | |
| 3939 | 3938 | } |
| 3940 | 3939 | } |
| 3941 | 3940 |
src/link/Elf.zig+9-4| ... | ... | @@ -722,7 +722,6 @@ pub fn loadInput(self: *Elf, input: link.Input) !void { |
| 722 | 722 | const argv = &self.dump_argv_list; |
| 723 | 723 | switch (input) { |
| 724 | 724 | .res => unreachable, |
| 725 | .dso_exact => |dso_exact| try argv.appendSlice(gpa, &.{ "-l", dso_exact.name }), | |
| 726 | 725 | .object, .archive => |obj| try argv.append(gpa, try obj.path.toString(comp.arena)), |
| 727 | 726 | .dso => |dso| try argv.append(gpa, try dso.path.toString(comp.arena)), |
| 728 | 727 | } |
| ... | ... | @@ -730,14 +729,13 @@ pub fn loadInput(self: *Elf, input: link.Input) !void { |
| 730 | 729 | |
| 731 | 730 | switch (input) { |
| 732 | 731 | .res => unreachable, |
| 733 | .dso_exact => @panic("TODO"), | |
| 734 | 732 | .object => |obj| try parseObject(self, obj), |
| 735 | 733 | .archive => |obj| if (self.base.isStaticLib()) { |
| 736 | 734 | // Ignore static library inputs when generating a static library. |
| 737 | 735 | } else { |
| 738 | 736 | try parseArchive(gpa, io, diags, &self.file_handles, &self.files, target, debug_fmt_strip, default_sym_version, &self.objects, obj); |
| 739 | 737 | }, |
| 740 | .dso => |dso| try parseDso(gpa, io, diags, dso, &self.shared_objects, &self.files, target), | |
| 738 | .dso => |dso| try parseDso(gpa, comp.arena, io, diags, dso, &self.shared_objects, &self.files, target), | |
| 741 | 739 | } |
| 742 | 740 | } |
| 743 | 741 | |
| ... | ... | @@ -1108,6 +1106,7 @@ fn parseArchive( |
| 1108 | 1106 | |
| 1109 | 1107 | fn parseDso( |
| 1110 | 1108 | gpa: Allocator, |
| 1109 | arena: Allocator, | |
| 1111 | 1110 | io: Io, |
| 1112 | 1111 | diags: *Diags, |
| 1113 | 1112 | dso: link.Input.Dso, |
| ... | ... | @@ -1124,7 +1123,12 @@ fn parseDso( |
| 1124 | 1123 | var header = try SharedObject.parseHeader(gpa, io, diags, dso.path, handle, stat, target); |
| 1125 | 1124 | defer header.deinit(gpa); |
| 1126 | 1125 | |
| 1127 | const soname = header.soname() orelse dso.path.basename(); | |
| 1126 | const fallback_soname: []const u8 = switch (dso.fallback_soname) { | |
| 1127 | .full_path => try dso.path.toString(arena), | |
| 1128 | .basename => fs.path.basename(dso.path.sub_path), | |
| 1129 | }; | |
| 1130 | ||
| 1131 | const soname = header.soname() orelse fallback_soname; | |
| 1128 | 1132 | |
| 1129 | 1133 | const gop = try shared_objects.getOrPut(gpa, soname); |
| 1130 | 1134 | if (gop.found_existing) return; |
| ... | ... | @@ -1156,6 +1160,7 @@ fn parseDso( |
| 1156 | 1160 | .symbols_extra = .empty, |
| 1157 | 1161 | .symbols_resolver = .empty, |
| 1158 | 1162 | .output_symtab_ctx = .{}, |
| 1163 | .fallback_soname = fallback_soname, | |
| 1159 | 1164 | }, |
| 1160 | 1165 | }); |
| 1161 | 1166 | const so = fileLookup(files.*, index, null).?.shared_object; |
src/link/Elf/SharedObject.zig+3-1| ... | ... | @@ -31,6 +31,8 @@ alive: bool, |
| 31 | 31 | |
| 32 | 32 | output_symtab_ctx: Elf.SymtabCtx, |
| 33 | 33 | |
| 34 | fallback_soname: []const u8, | |
| 35 | ||
| 34 | 36 | pub fn deinit(so: *SharedObject, gpa: Allocator) void { |
| 35 | 37 | gpa.free(so.path.sub_path); |
| 36 | 38 | so.parsed.deinit(gpa); |
| ... | ... | @@ -427,7 +429,7 @@ pub fn asFile(self: *SharedObject) File { |
| 427 | 429 | } |
| 428 | 430 | |
| 429 | 431 | pub fn soname(self: *SharedObject) []const u8 { |
| 430 | return self.parsed.soname() orelse self.path.basename(); | |
| 432 | return self.parsed.soname() orelse self.fallback_soname; | |
| 431 | 433 | } |
| 432 | 434 | |
| 433 | 435 | pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void { |
src/link/Elf2.zig+15-22| ... | ... | @@ -6230,34 +6230,19 @@ fn loadInputInner(elf: *Elf, input: link.Input) (Error || error{BadMagic})!void |
| 6230 | 6230 | .dso => |dso| { |
| 6231 | 6231 | try elf.needed.ensureUnusedCapacity(elf.base.comp.gpa, 1); |
| 6232 | 6232 | var fr = dso.file.reader(io, &buf); |
| 6233 | elf.loadDso(dso.path, &fr) catch |err| switch (err) { | |
| 6233 | elf.loadDso(dso.path, dso.fallback_soname, &fr) catch |err| switch (err) { | |
| 6234 | 6234 | else => |e| return e, |
| 6235 | error.EndOfStream => return diags.failParse( | |
| 6236 | dso.path, | |
| 6237 | "unexpected eof", | |
| 6238 | .{}, | |
| 6239 | ), | |
| 6235 | error.EndOfStream => return diags.failParse(dso.path, "unexpected eof", .{}), | |
| 6240 | 6236 | error.AccessDenied, error.Unexpected, error.Unseekable => |e| return diags.fail( |
| 6241 | "failed to read \"{f}\": {t}", | |
| 6242 | .{ dso.path.fmtEscapeString(), e }, | |
| 6237 | "failed to read {qf}: {t}", | |
| 6238 | .{ dso.path, e }, | |
| 6243 | 6239 | ), |
| 6244 | 6240 | error.ReadFailed => switch (fr.err.?) { |
| 6245 | 6241 | error.Canceled => |e| return e, |
| 6246 | else => |e| return diags.fail( | |
| 6247 | "failed to read \"{f}\": {t}", | |
| 6248 | .{ dso.path.fmtEscapeString(), e }, | |
| 6249 | ), | |
| 6242 | else => |e| return diags.fail("failed to read {qf}: {t}", .{ dso.path, e }), | |
| 6250 | 6243 | }, |
| 6251 | 6244 | }; |
| 6252 | 6245 | }, |
| 6253 | .dso_exact => |dso_exact| { | |
| 6254 | log.debug("load dso_exact '{f}'", .{std.zig.fmtString(dso_exact.name)}); | |
| 6255 | if (elf.shndx.dynamic != .UNDEF) { | |
| 6256 | try elf.needed.put(elf.base.comp.gpa, try elf.string(.dynstr, dso_exact.name), {}); | |
| 6257 | } | |
| 6258 | // TODO: we need to get a resolved file path from the frontend, because we need to read | |
| 6259 | // the shared object to discover symbol types. | |
| 6260 | }, | |
| 6261 | 6246 | } |
| 6262 | 6247 | } |
| 6263 | 6248 | fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadParseInputError || error{BadMagic})!void { |
| ... | ... | @@ -6867,7 +6852,12 @@ fn populateArchiveMemberName(elf: *Elf, member_ar_hdr: *std.elf.ar_hdr, member_n |
| 6867 | 6852 | @memcpy(dest_slice[0 .. dest_slice.len - 2], member_name); |
| 6868 | 6853 | @memcpy(dest_slice[dest_slice.len - 2 ..], "/\n"); // yes, the terminator is weird |
| 6869 | 6854 | } |
| 6870 | fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadParseInputError || error{BadMagic})!void { | |
| 6855 | fn loadDso( | |
| 6856 | elf: *Elf, | |
| 6857 | path: std.Build.Cache.Path, | |
| 6858 | fallback_soname: link.Input.Dso.FallbackSoname, | |
| 6859 | fr: *Io.File.Reader, | |
| 6860 | ) (LoadParseInputError || error{BadMagic})!void { | |
| 6871 | 6861 | const comp = elf.base.comp; |
| 6872 | 6862 | const gpa = comp.gpa; |
| 6873 | 6863 | const diags = &comp.link_diags; |
| ... | ... | @@ -6963,7 +6953,10 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars |
| 6963 | 6953 | } |
| 6964 | 6954 | break std.mem.sliceTo(dynstr[@intCast(val)..], 0); |
| 6965 | 6955 | } |
| 6966 | } else std.fs.path.basename(path.sub_path); | |
| 6956 | } else switch (fallback_soname) { | |
| 6957 | .basename => std.fs.path.basename(path.sub_path), | |
| 6958 | .full_path => try path.toString(comp.arena), | |
| 6959 | }; | |
| 6967 | 6960 | try elf.needed.put(gpa, try elf.string(.dynstr, soname), {}); |
| 6968 | 6961 | |
| 6969 | 6962 | // Scan the symbol table and populate `elf.dso_globals`. |
src/link/Lld.zig+21-14| ... | ... | @@ -309,9 +309,9 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) link.Error!void { |
| 309 | 309 | |
| 310 | 310 | try object_files.ensureUnusedCapacity(arena, comp.link_inputs.len); |
| 311 | 311 | for (comp.link_inputs) |input| switch (input) { |
| 312 | .dso, .dso_exact, .archive => {}, // static archives should not contain shared libraries or other static archives | |
| 312 | .dso, .archive => {}, // static archives should not contain shared libraries or other static archives | |
| 313 | 313 | .res, .object => { |
| 314 | const path = try input.path().?.toStringZ(arena); | |
| 314 | const path = try input.path().toStringZ(arena); | |
| 315 | 315 | object_files.appendAssumeCapacity(path); |
| 316 | 316 | }, |
| 317 | 317 | }; |
| ... | ... | @@ -551,7 +551,6 @@ fn coffLink(lld: *Lld, arena: Allocator) !void { |
| 551 | 551 | |
| 552 | 552 | try argv.ensureUnusedCapacity(comp.link_inputs.len); |
| 553 | 553 | for (comp.link_inputs) |link_input| switch (link_input) { |
| 554 | .dso_exact => unreachable, // not applicable to PE/COFF | |
| 555 | 554 | inline .dso, .res => |x| { |
| 556 | 555 | argv.appendAssumeCapacity(try x.path.toString(arena)); |
| 557 | 556 | }, |
| ... | ... | @@ -1114,10 +1113,6 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { |
| 1114 | 1113 | } |
| 1115 | 1114 | try argv.append(try obj.path.toString(arena)); |
| 1116 | 1115 | }, |
| 1117 | .dso_exact => |dso_exact| { | |
| 1118 | assert(dso_exact.name[0] == ':'); | |
| 1119 | try argv.appendSlice(&.{ "-l", dso_exact.name }); | |
| 1120 | }, | |
| 1121 | 1116 | }; |
| 1122 | 1117 | |
| 1123 | 1118 | if (whole_archive) { |
| ... | ... | @@ -1159,9 +1154,16 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { |
| 1159 | 1154 | argv.appendAssumeCapacity("--as-needed"); |
| 1160 | 1155 | var as_needed = true; |
| 1161 | 1156 | |
| 1157 | // When we have a DSO input, in order to trick LLD into putting the basename in its | |
| 1158 | // `DT_NEEDED` entry while still allowing us to tell it the exact path to the shared | |
| 1159 | // object, we pass it on the CLI as "-l:/absolute/path/to/libfoo.so". This will treat | |
| 1160 | // the given path not actually as an absolute path, but as relative to the library | |
| 1161 | // search path, so the root directory must therefore be the only library search path. | |
| 1162 | try argv.append("-L/"); | |
| 1163 | ||
| 1162 | 1164 | for (base.comp.link_inputs) |link_input| switch (link_input) { |
| 1163 | 1165 | .res => unreachable, // Windows-only |
| 1164 | .object, .archive, .dso_exact => continue, | |
| 1166 | .object, .archive => continue, | |
| 1165 | 1167 | .dso => |dso| { |
| 1166 | 1168 | const lib_as_needed = !dso.needed; |
| 1167 | 1169 | switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) { |
| ... | ... | @@ -1176,11 +1178,17 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { |
| 1176 | 1178 | }, |
| 1177 | 1179 | } |
| 1178 | 1180 | |
| 1179 | // By this time, we depend on these libs being dynamically linked | |
| 1180 | // libraries and not static libraries (the check for that needs to be earlier), | |
| 1181 | // but they could be full paths to .so files, in which case we | |
| 1182 | // want to avoid prepending "-l". | |
| 1183 | argv.appendAssumeCapacity(try dso.path.toString(arena)); | |
| 1181 | // By this time, we depend on these libs being dynamically linked libraries and | |
| 1182 | // not static libraries (the check for that needs to be earlier), but they could | |
| 1183 | // be full file paths, in which case we don't want to use the "-l:" strategy. | |
| 1184 | switch (dso.fallback_soname) { | |
| 1185 | .basename => try argv.append(try arena.print("-l:{s}", .{try fs.path.resolve(arena, &.{ | |
| 1186 | comp.dirs.cwd, | |
| 1187 | dso.path.root_dir.path orelse ".", | |
| 1188 | dso.path.sub_path, | |
| 1189 | })})), | |
| 1190 | .full_path => try argv.append(try dso.path.toString(arena)), | |
| 1191 | } | |
| 1184 | 1192 | }, |
| 1185 | 1193 | }; |
| 1186 | 1194 | |
| ... | ... | @@ -1588,7 +1596,6 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void { |
| 1588 | 1596 | .dso => |dso| { |
| 1589 | 1597 | try argv.append(try dso.path.toString(arena)); |
| 1590 | 1598 | }, |
| 1591 | .dso_exact => unreachable, | |
| 1592 | 1599 | .res => unreachable, |
| 1593 | 1600 | }; |
| 1594 | 1601 | if (whole_archive) { |
src/link/MachO.zig+13-13| ... | ... | @@ -372,7 +372,6 @@ pub fn flush( |
| 372 | 372 | for (comp.link_inputs) |link_input| switch (link_input) { |
| 373 | 373 | .dso => continue, // handled below |
| 374 | 374 | .object, .archive => positionals.appendAssumeCapacity(link_input), |
| 375 | .dso_exact => @panic("TODO"), | |
| 376 | 375 | .res => unreachable, |
| 377 | 376 | }; |
| 378 | 377 | |
| ... | ... | @@ -406,7 +405,7 @@ pub fn flush( |
| 406 | 405 | |
| 407 | 406 | for (positionals.items) |link_input| { |
| 408 | 407 | self.classifyInputFile(link_input) catch |err| |
| 409 | diags.addParseError(link_input.path().?, "failed to read input file: {s}", .{@errorName(err)}); | |
| 408 | diags.addParseError(link_input.path(), "failed to read input file: {t}", .{err}); | |
| 410 | 409 | } |
| 411 | 410 | |
| 412 | 411 | var system_libs = std.array_list.Managed(SystemLib).init(gpa); |
| ... | ... | @@ -447,11 +446,11 @@ pub fn flush( |
| 447 | 446 | }; |
| 448 | 447 | |
| 449 | 448 | for (comp.link_inputs) |link_input| switch (link_input) { |
| 450 | .object, .archive, .dso_exact => continue, | |
| 449 | .object, .archive => continue, | |
| 451 | 450 | .res => unreachable, |
| 452 | 451 | .dso => { |
| 453 | 452 | self.classifyInputFile(link_input) catch |err| |
| 454 | diags.addParseError(link_input.path().?, "failed to parse input file: {s}", .{@errorName(err)}); | |
| 453 | diags.addParseError(link_input.path(), "failed to parse input file: {t}", .{err}); | |
| 455 | 454 | }, |
| 456 | 455 | }; |
| 457 | 456 | |
| ... | ... | @@ -655,8 +654,9 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { |
| 655 | 654 | for (comp.link_inputs) |link_input| switch (link_input) { |
| 656 | 655 | .object, .archive => |obj| try argv.append(try obj.path.toString(arena)), |
| 657 | 656 | .res => |res| try argv.append(try res.path.toString(arena)), |
| 658 | .dso => |dso| try argv.append(try dso.path.toString(arena)), | |
| 659 | .dso_exact => |dso_exact| try argv.appendSlice(&.{ "-l", dso_exact.name }), | |
| 657 | .dso => |dso| { | |
| 658 | try argv.append(try dso.path.toString(arena)); | |
| 659 | }, | |
| 660 | 660 | }; |
| 661 | 661 | |
| 662 | 662 | for (comp.c_objects.items) |c_object| { |
| ... | ... | @@ -748,7 +748,6 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { |
| 748 | 748 | if (obj.must_link) try argv.append("-force_load"); // TODO: verify this |
| 749 | 749 | try argv.append(try obj.path.toString(arena)); |
| 750 | 750 | }, |
| 751 | .dso_exact => |dso_exact| try argv.appendSlice(&.{ "-l", dso_exact.name }), | |
| 752 | 751 | }; |
| 753 | 752 | |
| 754 | 753 | for (comp.c_objects.items) |c_object| { |
| ... | ... | @@ -775,16 +774,18 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { |
| 775 | 774 | } |
| 776 | 775 | |
| 777 | 776 | for (comp.link_inputs) |link_input| switch (link_input) { |
| 778 | .object, .archive, .dso_exact => continue, // handled above | |
| 777 | .object, .archive => continue, // handled above | |
| 779 | 778 | .res => unreachable, // windows only |
| 780 | 779 | .dso => |dso| { |
| 780 | try argv.ensureUnusedCapacity(2); | |
| 781 | 781 | if (dso.needed) { |
| 782 | try argv.appendSlice(&.{ "-needed-l", try dso.path.toString(arena) }); | |
| 782 | argv.appendAssumeCapacity("-needed-l"); | |
| 783 | 783 | } else if (dso.weak) { |
| 784 | try argv.appendSlice(&.{ "-weak-l", try dso.path.toString(arena) }); | |
| 784 | argv.appendAssumeCapacity("-weak-l"); | |
| 785 | 785 | } else { |
| 786 | try argv.appendSlice(&.{ "-l", try dso.path.toString(arena) }); | |
| 786 | argv.appendAssumeCapacity("-l"); | |
| 787 | 787 | } |
| 788 | argv.appendAssumeCapacity(try dso.path.toString(arena)); | |
| 788 | 789 | }, |
| 789 | 790 | }; |
| 790 | 791 | |
| ... | ... | @@ -870,7 +871,7 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void { |
| 870 | 871 | const comp = self.base.comp; |
| 871 | 872 | const io = comp.io; |
| 872 | 873 | |
| 873 | const path, const file = input.pathAndFile().?; | |
| 874 | const path, const file = input.pathAndFile(); | |
| 874 | 875 | // TODO don't classify now, it's too late. The input file has already been classified |
| 875 | 876 | log.debug("classifying input file {f}", .{path}); |
| 876 | 877 | |
| ... | ... | @@ -4478,7 +4479,6 @@ const SystemLib = struct { |
| 4478 | 4479 | |
| 4479 | 4480 | fn fromLinkInput(link_input: link.Input) SystemLib { |
| 4480 | 4481 | return switch (link_input) { |
| 4481 | .dso_exact => unreachable, | |
| 4482 | 4482 | .res => unreachable, |
| 4483 | 4483 | .object, .archive => |obj| .{ |
| 4484 | 4484 | .path = obj.path, |
src/link/MachO/relocatable.zig+3-3| ... | ... | @@ -19,7 +19,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat |
| 19 | 19 | // Instead of invoking a full-blown `-r` mode on the input which sadly will strip all |
| 20 | 20 | // debug info segments/sections (this is apparently by design by Apple), we copy |
| 21 | 21 | // the *only* input file over. |
| 22 | const path = positionals.items[0].path().?; | |
| 22 | const path = positionals.items[0].path(); | |
| 23 | 23 | const in_file = path.root_dir.handle.openFile(io, path.sub_path, .{}) catch |err| |
| 24 | 24 | return diags.fail("failed to open {f}: {s}", .{ path, @errorName(err) }); |
| 25 | 25 | const stat = in_file.stat(io) catch |err| |
| ... | ... | @@ -31,7 +31,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat |
| 31 | 31 | |
| 32 | 32 | for (positionals.items) |link_input| { |
| 33 | 33 | macho_file.classifyInputFile(link_input) catch |err| |
| 34 | diags.addParseError(link_input.path().?, "failed to read input file: {s}", .{@errorName(err)}); | |
| 34 | diags.addParseError(link_input.path(), "failed to read input file: {t}", .{err}); | |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | 37 | if (diags.hasErrors()) return error.AlreadyReported; |
| ... | ... | @@ -102,7 +102,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 102 | 102 | |
| 103 | 103 | for (positionals.items) |link_input| { |
| 104 | 104 | macho_file.classifyInputFile(link_input) catch |err| |
| 105 | diags.addParseError(link_input.path().?, "failed to read input file: {s}", .{@errorName(err)}); | |
| 105 | diags.addParseError(link_input.path(), "failed to read input file: {t}", .{err}); | |
| 106 | 106 | } |
| 107 | 107 | |
| 108 | 108 | if (diags.hasErrors()) return error.AlreadyReported; |
src/link/Wasm.zig-2| ... | ... | @@ -3788,7 +3788,6 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void { |
| 3788 | 3788 | const argv = &wasm.dump_argv_list; |
| 3789 | 3789 | switch (input) { |
| 3790 | 3790 | .res => unreachable, |
| 3791 | .dso_exact => unreachable, | |
| 3792 | 3791 | .dso => unreachable, |
| 3793 | 3792 | .object, .archive => |obj| { |
| 3794 | 3793 | try argv.append(gpa, try obj.path.toString(comp.arena)); |
| ... | ... | @@ -3798,7 +3797,6 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void { |
| 3798 | 3797 | |
| 3799 | 3798 | switch (input) { |
| 3800 | 3799 | .res => unreachable, |
| 3801 | .dso_exact => unreachable, | |
| 3802 | 3800 | .dso => unreachable, |
| 3803 | 3801 | .object => |obj| try parseObject(wasm, obj), |
| 3804 | 3802 | .archive => |obj| try parseArchive(wasm, obj), |
src/main.zig+36-13| ... | ... | @@ -70,10 +70,6 @@ var stdin_buffer: [4096]u8 align(std.heap.page_size_min) = undefined; |
| 70 | 70 | /// This can be global since stdout is a singleton. |
| 71 | 71 | var stdout_buffer: [4096]u8 align(std.heap.page_size_min) = undefined; |
| 72 | 72 | |
| 73 | /// Shaming all the locations that inappropriately use an O(N) search algorithm. | |
| 74 | /// Please delete this and fix the compilation errors! | |
| 75 | pub const @"bad O(N)" = void; | |
| 76 | ||
| 77 | 73 | const normal_usage = |
| 78 | 74 | \\Usage: zig [command] [options] |
| 79 | 75 | \\ |
| ... | ... | @@ -807,7 +803,7 @@ const compile_usage = |
| 807 | 803 | \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features |
| 808 | 804 | \\ --debug-log [scope] Enable printing debug/info log messages for scope |
| 809 | 805 | \\ --debug-compile-errors Crash with helpful diagnostics at the first compile error |
| 810 | \\ --debug-link-snapshot Enable dumping of the linker's state in JSON format | |
| 806 | \\ --debug-link-snapshot Dump linker state and output file information for troubleshooting | |
| 811 | 807 | \\ --debug-rt[=mode] Build compiler runtime libraries with [mode] optimization |
| 812 | 808 | \\ (debug if [=mode] is omitted) |
| 813 | 809 | \\ --debug-incremental Enable incremental compilation debug features |
| ... | ... | @@ -1355,6 +1351,7 @@ fn buildOutputType( |
| 1355 | 1351 | .search_strategy = lib_search_strategy, |
| 1356 | 1352 | .allow_so_scripts = allow_so_scripts, |
| 1357 | 1353 | }, |
| 1354 | .name_done = false, | |
| 1358 | 1355 | } }); |
| 1359 | 1356 | } else if (mem.eql(u8, arg, "--needed-library") or |
| 1360 | 1357 | mem.eql(u8, arg, "-needed-l") or |
| ... | ... | @@ -1370,6 +1367,7 @@ fn buildOutputType( |
| 1370 | 1367 | .search_strategy = lib_search_strategy, |
| 1371 | 1368 | .allow_so_scripts = allow_so_scripts, |
| 1372 | 1369 | }, |
| 1370 | .name_done = false, | |
| 1373 | 1371 | } }); |
| 1374 | 1372 | } else if (mem.eql(u8, arg, "-weak_library") or mem.eql(u8, arg, "-weak-l")) { |
| 1375 | 1373 | try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ |
| ... | ... | @@ -1381,6 +1379,7 @@ fn buildOutputType( |
| 1381 | 1379 | .search_strategy = lib_search_strategy, |
| 1382 | 1380 | .allow_so_scripts = allow_so_scripts, |
| 1383 | 1381 | }, |
| 1382 | .name_done = false, | |
| 1384 | 1383 | } }); |
| 1385 | 1384 | } else if (mem.eql(u8, arg, "-D")) { |
| 1386 | 1385 | try cc_argv.appendSlice(arena, &.{ arg, args_iter.nextOrFatal() }); |
| ... | ... | @@ -1843,6 +1842,7 @@ fn buildOutputType( |
| 1843 | 1842 | .search_strategy = lib_search_strategy, |
| 1844 | 1843 | .allow_so_scripts = allow_so_scripts, |
| 1845 | 1844 | }, |
| 1845 | .name_done = false, | |
| 1846 | 1846 | } }); |
| 1847 | 1847 | } else if (mem.cutPrefix(u8, arg, "-needed-l")) |name| { |
| 1848 | 1848 | try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ |
| ... | ... | @@ -1854,6 +1854,7 @@ fn buildOutputType( |
| 1854 | 1854 | .search_strategy = lib_search_strategy, |
| 1855 | 1855 | .allow_so_scripts = allow_so_scripts, |
| 1856 | 1856 | }, |
| 1857 | .name_done = false, | |
| 1857 | 1858 | } }); |
| 1858 | 1859 | } else if (mem.cutPrefix(u8, arg, "-weak-l")) |name| { |
| 1859 | 1860 | try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ |
| ... | ... | @@ -1865,6 +1866,7 @@ fn buildOutputType( |
| 1865 | 1866 | .search_strategy = lib_search_strategy, |
| 1866 | 1867 | .allow_so_scripts = allow_so_scripts, |
| 1867 | 1868 | }, |
| 1869 | .name_done = false, | |
| 1868 | 1870 | } }); |
| 1869 | 1871 | } else if (mem.startsWith(u8, arg, "-D")) { |
| 1870 | 1872 | try cc_argv.append(arena, arg); |
| ... | ... | @@ -2083,12 +2085,24 @@ fn buildOutputType( |
| 2083 | 2085 | // We don't know whether this library is part of libc or libc++ until |
| 2084 | 2086 | // we resolve the target, so we simply append to the list for now. |
| 2085 | 2087 | if (mem.startsWith(u8, it.only_arg, ":")) { |
| 2086 | // -l :path/to/filename is used when callers need | |
| 2087 | // more control over what's in the resulting | |
| 2088 | // binary: no extra rpaths and DSO filename exactly | |
| 2089 | // as provided. CGo compilation depends on this. | |
| 2090 | try create_module.cli_link_inputs.append(arena, .{ .dso_exact = .{ | |
| 2091 | .name = it.only_arg, | |
| 2088 | // -l :path/to/filename indicates: | |
| 2089 | // * No extra rpaths. | |
| 2090 | // * NEEDED entry should be exactly the string | |
| 2091 | // after the colon. No file system paths prepended. | |
| 2092 | // * The DSO still must be found at compile/link | |
| 2093 | // time and its entries used to resolve symbols. | |
| 2094 | // CGo compilation depends on this. | |
| 2095 | try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ | |
| 2096 | .name = it.only_arg[1..], | |
| 2097 | .query = .{ | |
| 2098 | .must_link = must_link, | |
| 2099 | .needed = needed, | |
| 2100 | .weak = false, | |
| 2101 | .preferred_mode = lib_preferred_mode, | |
| 2102 | .search_strategy = lib_search_strategy, | |
| 2103 | .allow_so_scripts = allow_so_scripts, | |
| 2104 | }, | |
| 2105 | .name_done = true, | |
| 2092 | 2106 | } }); |
| 2093 | 2107 | } else { |
| 2094 | 2108 | const compiler_rt_classification = target_util.classifyCompilerRtLibName(it.only_arg); |
| ... | ... | @@ -2114,6 +2128,7 @@ fn buildOutputType( |
| 2114 | 2128 | .search_strategy = lib_search_strategy, |
| 2115 | 2129 | .allow_so_scripts = allow_so_scripts, |
| 2116 | 2130 | }, |
| 2131 | .name_done = false, | |
| 2117 | 2132 | } }); |
| 2118 | 2133 | } |
| 2119 | 2134 | } |
| ... | ... | @@ -2544,6 +2559,7 @@ fn buildOutputType( |
| 2544 | 2559 | .search_strategy = lib_search_strategy, |
| 2545 | 2560 | .allow_so_scripts = allow_so_scripts, |
| 2546 | 2561 | }, |
| 2562 | .name_done = false, | |
| 2547 | 2563 | } }), |
| 2548 | 2564 | .weak_framework => try create_module.frameworks.put(arena, it.only_arg, .{ .weak = true }), |
| 2549 | 2565 | .headerpad_max_install_names => headerpad_max_install_names = true, |
| ... | ... | @@ -2913,6 +2929,7 @@ fn buildOutputType( |
| 2913 | 2929 | .search_strategy = lib_search_strategy, |
| 2914 | 2930 | .allow_so_scripts = allow_so_scripts, |
| 2915 | 2931 | }, |
| 2932 | .name_done = false, | |
| 2916 | 2933 | } }); |
| 2917 | 2934 | } else if (mem.cutPrefix(u8, arg, "-weak-l")) |rest| { |
| 2918 | 2935 | try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ |
| ... | ... | @@ -2924,6 +2941,7 @@ fn buildOutputType( |
| 2924 | 2941 | .search_strategy = lib_search_strategy, |
| 2925 | 2942 | .allow_so_scripts = allow_so_scripts, |
| 2926 | 2943 | }, |
| 2944 | .name_done = false, | |
| 2927 | 2945 | } }); |
| 2928 | 2946 | } else if (mem.eql(u8, arg, "-weak_library")) { |
| 2929 | 2947 | try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ |
| ... | ... | @@ -2935,6 +2953,7 @@ fn buildOutputType( |
| 2935 | 2953 | .search_strategy = lib_search_strategy, |
| 2936 | 2954 | .allow_so_scripts = allow_so_scripts, |
| 2937 | 2955 | }, |
| 2956 | .name_done = false, | |
| 2938 | 2957 | } }); |
| 2939 | 2958 | } else if (mem.eql(u8, arg, "-compatibility_version")) { |
| 2940 | 2959 | const compat_version = linker_args_it.nextOrFatal(); |
| ... | ... | @@ -4175,6 +4194,10 @@ fn createModule( |
| 4175 | 4194 | fatal("cannot use absolute path as a system library: {s}", .{lib_name}); |
| 4176 | 4195 | } |
| 4177 | 4196 | |
| 4197 | if (!nq.name_done and std.mem.findScalar(u8, nq.name, '/') != null) { | |
| 4198 | fatal("cannot use path separator in system library name: {s}", .{lib_name}); | |
| 4199 | } | |
| 4200 | ||
| 4178 | 4201 | unresolved_link_inputs.appendAssumeCapacity(cli_link_input); |
| 4179 | 4202 | any_name_queries_remaining = true; |
| 4180 | 4203 | }, |
| ... | ... | @@ -4269,10 +4292,10 @@ fn createModule( |
| 4269 | 4292 | &create_module.link_inputs, |
| 4270 | 4293 | create_module.lib_directories.items, |
| 4271 | 4294 | color, |
| 4272 | ) catch |err| fatal("failed to resolve link inputs: {s}", .{@errorName(err)}); | |
| 4295 | ) catch |err| fatal("failed to resolve link inputs: {t}", .{err}); | |
| 4273 | 4296 | |
| 4274 | 4297 | if (!create_module.opts.any_dyn_libs) for (create_module.link_inputs.items) |item| switch (item) { |
| 4275 | .dso, .dso_exact => { | |
| 4298 | .dso => { | |
| 4276 | 4299 | create_module.opts.any_dyn_libs = true; |
| 4277 | 4300 | break; |
| 4278 | 4301 | }, |