| 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,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 | try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{ | 2896 | try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{ |
| 2896 | path.root_dir.path orelse ".", | 2897 | path.root_dir.path orelse ".", |
| 2897 | path.sub_path, | 2898 | path.sub_path, |
| 2898 | })); | 2899 | })); |
| 2899 | }; | 2900 | } |
| 2900 | 2901 | ||
| 2901 | // For compiling Win32 resources, we rely on the cache hash system to avoid duplicating work. | 2902 | // For compiling Win32 resources, we rely on the cache hash system to avoid duplicating work. |
| 2902 | // Add a Job for each Win32 resource file. | 2903 | // Add a Job for each Win32 resource file. |
src/link.zig+135-72| ... | @@ -995,11 +995,7 @@ pub const File = struct { | ... | @@ -995,11 +995,7 @@ pub const File = struct { |
| 995 | .{}, | 995 | .{}, |
| 996 | ) catch |err| { | 996 | ) catch |err| { |
| 997 | const diags = &base.comp.link_diags; | 997 | const diags = &base.comp.link_diags; |
| 998 | return diags.fail("failed to copy '{f}' to '{f}': {t}", .{ | 998 | return diags.fail("failed to copy {qf} to {qf}: {t}", .{ cached_pp_file_path, emit, err }); |
| 999 | std.fmt.alt(@as(Path, cached_pp_file_path), .formatEscapeChar), | ||
| 1000 | std.fmt.alt(@as(Path, emit), .formatEscapeChar), | ||
| 1001 | err, | ||
| 1002 | }); | ||
| 1003 | }; | 999 | }; |
| 1004 | return; | 1000 | return; |
| 1005 | } | 1001 | } |
| ... | @@ -1510,7 +1506,6 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { | ... | @@ -1510,7 +1506,6 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { |
| 1510 | .object => |obj| diags.addParseError(obj.path, "failed to parse object: {t}", .{e}), | 1506 | .object => |obj| diags.addParseError(obj.path, "failed to parse object: {t}", .{e}), |
| 1511 | .archive => |obj| diags.addParseError(obj.path, "failed to parse archive: {t}", .{e}), | 1507 | .archive => |obj| diags.addParseError(obj.path, "failed to parse archive: {t}", .{e}), |
| 1512 | .res => |res| diags.addParseError(res.path, "failed to parse Windows resource: {t}", .{e}), | 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 | prog_node.completeOne(); | 1511 | prog_node.completeOne(); |
| ... | @@ -1740,7 +1735,7 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void | ... | @@ -1740,7 +1735,7 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void |
| 1740 | if (comp.bin_file) |lf| { | 1735 | if (comp.bin_file) |lf| { |
| 1741 | lf.updateLineNumber(pt, line_update.inst, line_update.line) catch |err| switch (err) { | 1736 | lf.updateLineNumber(pt, line_update.inst, line_update.line) catch |err| switch (err) { |
| 1742 | error.OutOfMemory => diags.setAllocFailure(), | 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,7 +1748,7 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void |
| 1753 | if (comp.bin_file) |lf| { | 1748 | if (comp.bin_file) |lf| { |
| 1754 | lf.lostTracking(pt, ti) catch |err| switch (err) { | 1749 | lf.lostTracking(pt, ti) catch |err| switch (err) { |
| 1755 | error.OutOfMemory => diags.setAllocFailure(), | 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,13 +1819,14 @@ pub const UnresolvedInput = union(enum) { |
| 1824 | path_query: PathQuery, | 1819 | path_query: PathQuery, |
| 1825 | /// Strings that come from GNU ld scripts. Is it a filename? Is it a path? | 1820 | /// Strings that come from GNU ld scripts. Is it a filename? Is it a path? |
| 1826 | /// Who knows! Fuck around and find out. | 1821 | /// Who knows! Fuck around and find out. |
| 1827 | ambiguous_name: NameQuery, | 1822 | ambiguous_name: AmbiguousNameQuery, |
| 1828 | /// Put exactly this string in the dynamic section, no rpath. | ||
| 1829 | dso_exact: Input.DsoExact, | ||
| 1830 | 1823 | ||
| 1831 | pub const NameQuery = struct { | 1824 | pub const NameQuery = struct { |
| 1832 | name: []const u8, | 1825 | name: []const u8, |
| 1833 | query: Query, | 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 | pub const PathQuery = struct { | 1832 | pub const PathQuery = struct { |
| ... | @@ -1838,6 +1834,11 @@ pub const UnresolvedInput = union(enum) { | ... | @@ -1838,6 +1834,11 @@ pub const UnresolvedInput = union(enum) { |
| 1838 | query: Query, | 1834 | query: Query, |
| 1839 | }; | 1835 | }; |
| 1840 | 1836 | ||
| 1837 | pub const AmbiguousNameQuery = struct { | ||
| 1838 | name: []const u8, | ||
| 1839 | query: Query, | ||
| 1840 | }; | ||
| 1841 | |||
| 1841 | pub const Query = struct { | 1842 | pub const Query = struct { |
| 1842 | needed: bool = false, | 1843 | needed: bool = false, |
| 1843 | weak: bool = false, | 1844 | weak: bool = false, |
| ... | @@ -1871,7 +1872,6 @@ pub const Input = union(enum) { | ... | @@ -1871,7 +1872,6 @@ pub const Input = union(enum) { |
| 1871 | /// May not be a GNU ld script. Those are resolved when converting from | 1872 | /// May not be a GNU ld script. Those are resolved when converting from |
| 1872 | /// `UnresolvedInput` to `Input` values. | 1873 | /// `UnresolvedInput` to `Input` values. |
| 1873 | dso: Dso, | 1874 | dso: Dso, |
| 1874 | dso_exact: DsoExact, | ||
| 1875 | 1875 | ||
| 1876 | pub const Object = struct { | 1876 | pub const Object = struct { |
| 1877 | path: Path, | 1877 | path: Path, |
| ... | @@ -1891,29 +1891,22 @@ pub const Input = union(enum) { | ... | @@ -1891,29 +1891,22 @@ pub const Input = union(enum) { |
| 1891 | needed: bool, | 1891 | needed: bool, |
| 1892 | weak: bool, | 1892 | weak: bool, |
| 1893 | reexport: bool, | 1893 | reexport: bool, |
| 1894 | }; | 1894 | fallback_soname: FallbackSoname, |
| 1895 | 1895 | ||
| 1896 | pub const DsoExact = struct { | 1896 | pub const FallbackSoname = enum { basename, full_path }; |
| 1897 | /// Includes the ":" prefix. This is intended to be put into the DSO | ||
| 1898 | /// section verbatim with no corresponding rpaths. | ||
| 1899 | name: []const u8, | ||
| 1900 | }; | 1897 | }; |
| 1901 | 1898 | ||
| 1902 | /// Returns `null` in the case of `dso_exact`. | 1899 | pub fn path(input: Input) Path { |
| 1903 | pub fn path(input: Input) ?Path { | ||
| 1904 | return switch (input) { | 1900 | return switch (input) { |
| 1905 | .object, .archive => |obj| obj.path, | 1901 | .object, .archive => |obj| obj.path, |
| 1906 | inline .res, .dso => |x| x.path, | 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`. | 1906 | pub fn pathAndFile(input: Input) struct { Path, Io.File } { |
| 1912 | pub fn pathAndFile(input: Input) ?struct { Path, Io.File } { | ||
| 1913 | return switch (input) { | 1907 | return switch (input) { |
| 1914 | .object, .archive => |obj| .{ obj.path, obj.file }, | 1908 | .object, .archive => |obj| .{ obj.path, obj.file }, |
| 1915 | inline .res, .dso => |x| .{ x.path, x.file }, | 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,7 +1914,6 @@ pub const Input = union(enum) { |
| 1921 | return switch (input) { | 1914 | return switch (input) { |
| 1922 | .object, .archive => |obj| obj.path.basename(), | 1915 | .object, .archive => |obj| obj.path.basename(), |
| 1923 | inline .res, .dso => |x| x.path.basename(), | 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,9 +1944,7 @@ pub fn hashInputs(man: *Cache.Manifest, link_inputs: []const Input) !void { |
| 1952 | man.hash.add(dso.needed); | 1944 | man.hash.add(dso.needed); |
| 1953 | man.hash.add(dso.weak); | 1945 | man.hash.add(dso.weak); |
| 1954 | man.hash.add(dso.reexport); | 1946 | man.hash.add(dso.reexport); |
| 1955 | }, | 1947 | man.hash.add(dso.fallback_soname); |
| 1956 | .dso_exact => |dso_exact| { | ||
| 1957 | man.hash.addBytes(dso_exact.name); | ||
| 1958 | }, | 1948 | }, |
| 1959 | } | 1949 | } |
| 1960 | } | 1950 | } |
| ... | @@ -2005,7 +1995,7 @@ pub fn resolveInputs( | ... | @@ -2005,7 +1995,7 @@ pub fn resolveInputs( |
| 2005 | .name_query => |name_query| { | 1995 | .name_query => |name_query| { |
| 2006 | const query = name_query.query; | 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 | assert(!fs.path.isAbsolute(name_query.name)); | 1999 | assert(!fs.path.isAbsolute(name_query.name)); |
| 2010 | 2000 | ||
| 2011 | checked_paths.clearRetainingCapacity(); | 2001 | checked_paths.clearRetainingCapacity(); |
| ... | @@ -2190,10 +2180,6 @@ pub fn resolveInputs( | ... | @@ -2190,10 +2180,6 @@ pub fn resolveInputs( |
| 2190 | } | 2180 | } |
| 2191 | continue; | 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 | comptime unreachable; | 2184 | comptime unreachable; |
| 2199 | } | 2185 | } |
| ... | @@ -2201,8 +2187,8 @@ pub fn resolveInputs( | ... | @@ -2201,8 +2187,8 @@ pub fn resolveInputs( |
| 2201 | if (failed_libs.items.len > 0) { | 2187 | if (failed_libs.items.len > 0) { |
| 2202 | for (failed_libs.items) |f| { | 2188 | for (failed_libs.items) |f| { |
| 2203 | const searched_paths = if (f.checked_paths.len == 0) " none" else f.checked_paths; | 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}", .{ | 2190 | std.log.err("unable to find {t} system library {q} using strategy {t}. searched paths:{s}", .{ |
| 2205 | @tagName(f.preferred_mode), f.name, @tagName(f.strategy), searched_paths, | 2191 | f.preferred_mode, f.name, f.strategy, searched_paths, |
| 2206 | }); | 2192 | }); |
| 2207 | } | 2193 | } |
| 2208 | std.process.exit(1); | 2194 | std.process.exit(1); |
| ... | @@ -2237,7 +2223,7 @@ fn resolveLibInput( | ... | @@ -2237,7 +2223,7 @@ fn resolveLibInput( |
| 2237 | 2223 | ||
| 2238 | const lib_name = name_query.name; | 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 | // Prefer .tbd over .dylib. | 2227 | // Prefer .tbd over .dylib. |
| 2242 | const test_path: Path = .{ | 2228 | const test_path: Path = .{ |
| 2243 | .root_dir = lib_directory, | 2229 | .root_dir = lib_directory, |
| ... | @@ -2246,17 +2232,27 @@ fn resolveLibInput( | ... | @@ -2246,17 +2232,27 @@ fn resolveLibInput( |
| 2246 | try checked_paths.print(gpa, "\n {f}", .{test_path}); | 2232 | try checked_paths.print(gpa, "\n {f}", .{test_path}); |
| 2247 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { | 2233 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { |
| 2248 | error.FileNotFound => break :tbd, | 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 | errdefer file.close(io); | 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 | const test_path: Path = .{ | 2251 | const test_path: Path = .{ |
| 2257 | .root_dir = lib_directory, | 2252 | .root_dir = lib_directory, |
| 2258 | .sub_path = try std.fmt.allocPrint(arena, "{s}{s}{s}", .{ | 2253 | .sub_path = if (name_query.name_done) lib_name else try std.fmt.allocPrint(arena, "{s}{s}{s}", .{ |
| 2259 | target.libPrefix(), lib_name, | 2254 | target.libPrefix(), |
| 2255 | lib_name, | ||
| 2260 | switch (link_mode) { | 2256 | switch (link_mode) { |
| 2261 | .static => target.staticLibSuffix(), | 2257 | .static => target.staticLibSuffix(), |
| 2262 | .dynamic => target.dynamicLibSuffix(), | 2258 | .dynamic => target.dynamicLibSuffix(), |
| ... | @@ -2267,7 +2263,7 @@ fn resolveLibInput( | ... | @@ -2267,7 +2263,7 @@ fn resolveLibInput( |
| 2267 | switch (try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, .{ | 2263 | switch (try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, .{ |
| 2268 | .path = test_path, | 2264 | .path = test_path, |
| 2269 | .query = name_query.query, | 2265 | .query = name_query.query, |
| 2270 | }, link_mode, color)) { | 2266 | }, link_mode, color, .basename)) { |
| 2271 | .no_match => {}, | 2267 | .no_match => {}, |
| 2272 | .ok => return .ok, | 2268 | .ok => return .ok, |
| 2273 | } | 2269 | } |
| ... | @@ -2275,7 +2271,7 @@ fn resolveLibInput( | ... | @@ -2275,7 +2271,7 @@ fn resolveLibInput( |
| 2275 | 2271 | ||
| 2276 | // In the case of Darwin, the main check will be .dylib, so here we | 2272 | // In the case of Darwin, the main check will be .dylib, so here we |
| 2277 | // additionally check for .so files. | 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 | const test_path: Path = .{ | 2275 | const test_path: Path = .{ |
| 2280 | .root_dir = lib_directory, | 2276 | .root_dir = lib_directory, |
| 2281 | .sub_path = try std.fmt.allocPrint(arena, "lib{s}.so", .{lib_name}), | 2277 | .sub_path = try std.fmt.allocPrint(arena, "lib{s}.so", .{lib_name}), |
| ... | @@ -2283,17 +2279,24 @@ fn resolveLibInput( | ... | @@ -2283,17 +2279,24 @@ fn resolveLibInput( |
| 2283 | try checked_paths.print(gpa, "\n {f}", .{test_path}); | 2279 | try checked_paths.print(gpa, "\n {f}", .{test_path}); |
| 2284 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { | 2280 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { |
| 2285 | error.FileNotFound => break :so, | 2281 | error.FileNotFound => break :so, |
| 2286 | else => |e| fatal("unable to search for so library '{f}': {s}", .{ | 2282 | else => |e| fatal("unable to search for so library {qf}: {t}", .{ test_path, e }), |
| 2287 | test_path, @errorName(e), | ||
| 2288 | }), | ||
| 2289 | }; | 2283 | }; |
| 2290 | errdefer file.close(io); | 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 | // In the case of MinGW, the main check will be .lib but we also need to | 2297 | // In the case of MinGW, the main check will be .lib but we also need to |
| 2295 | // look for `libfoo.a`. | 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 | const test_path: Path = .{ | 2300 | const test_path: Path = .{ |
| 2298 | .root_dir = lib_directory, | 2301 | .root_dir = lib_directory, |
| 2299 | .sub_path = try std.fmt.allocPrint(arena, "lib{s}.a", .{lib_name}), | 2302 | .sub_path = try std.fmt.allocPrint(arena, "lib{s}.a", .{lib_name}), |
| ... | @@ -2301,21 +2304,32 @@ fn resolveLibInput( | ... | @@ -2301,21 +2304,32 @@ fn resolveLibInput( |
| 2301 | try checked_paths.print(gpa, "\n {f}", .{test_path}); | 2304 | try checked_paths.print(gpa, "\n {f}", .{test_path}); |
| 2302 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { | 2305 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { |
| 2303 | error.FileNotFound => break :mingw, | 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 | errdefer file.close(io); | 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 | // In the case of OpenBSD, dynamic libraries are always versioned, without | 2322 | // In the case of OpenBSD, dynamic libraries are always versioned, without |
| 2311 | // unversioned symlinks. OpenBSD patches LLD to select the highest-versioned | 2323 | // unversioned symlinks. OpenBSD patches LLD to select the highest-versioned |
| 2312 | // shared library, and this code is intended to match that upstream behavior. | 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 | const prefix = try std.fmt.allocPrint(arena, "lib{s}.so.", .{lib_name}); | 2326 | const prefix = try std.fmt.allocPrint(arena, "lib{s}.so.", .{lib_name}); |
| 2315 | 2327 | ||
| 2316 | var dir = lib_directory.handle.openDir(io, ".", .{ .iterate = true }) catch |err| switch (err) { | 2328 | var dir = lib_directory.handle.openDir(io, ".", .{ .iterate = true }) catch |err| switch (err) { |
| 2317 | error.NotDir, error.FileNotFound => break :versioned, | 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 | defer dir.close(io); | 2334 | defer dir.close(io); |
| 2321 | 2335 | ||
| ... | @@ -2325,7 +2339,7 @@ fn resolveLibInput( | ... | @@ -2325,7 +2339,7 @@ fn resolveLibInput( |
| 2325 | 2339 | ||
| 2326 | var iter = dir.iterate(); | 2340 | var iter = dir.iterate(); |
| 2327 | while (iter.next(io) catch |err| { | 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 | }) |entry| { | 2343 | }) |entry| { |
| 2330 | if (entry.kind != .file) continue; | 2344 | if (entry.kind != .file) continue; |
| 2331 | if (!std.mem.startsWith(u8, entry.name, prefix)) continue; | 2345 | if (!std.mem.startsWith(u8, entry.name, prefix)) continue; |
| ... | @@ -2354,7 +2368,7 @@ fn resolveLibInput( | ... | @@ -2354,7 +2368,7 @@ fn resolveLibInput( |
| 2354 | switch (try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, .{ | 2368 | switch (try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, .{ |
| 2355 | .path = test_path, | 2369 | .path = test_path, |
| 2356 | .query = name_query.query, | 2370 | .query = name_query.query, |
| 2357 | }, link_mode, color)) { | 2371 | }, link_mode, color, .basename)) { |
| 2358 | .no_match => {}, | 2372 | .no_match => {}, |
| 2359 | .ok => return .ok, | 2373 | .ok => return .ok, |
| 2360 | } | 2374 | } |
| ... | @@ -2395,6 +2409,7 @@ fn finishResolveLibInput( | ... | @@ -2395,6 +2409,7 @@ fn finishResolveLibInput( |
| 2395 | file: Io.File, | 2409 | file: Io.File, |
| 2396 | link_mode: std.lang.LinkMode, | 2410 | link_mode: std.lang.LinkMode, |
| 2397 | query: UnresolvedInput.Query, | 2411 | query: UnresolvedInput.Query, |
| 2412 | fallback_soname: Input.Dso.FallbackSoname, | ||
| 2398 | ) ResolveLibInputResult { | 2413 | ) ResolveLibInputResult { |
| 2399 | switch (link_mode) { | 2414 | switch (link_mode) { |
| 2400 | .static => { | 2415 | .static => { |
| ... | @@ -2413,13 +2428,16 @@ fn finishResolveLibInput( | ... | @@ -2413,13 +2428,16 @@ fn finishResolveLibInput( |
| 2413 | .hidden = query.hidden, | 2428 | .hidden = query.hidden, |
| 2414 | } }); | 2429 | } }); |
| 2415 | }, | 2430 | }, |
| 2416 | .dynamic => resolved_inputs.appendAssumeCapacity(.{ .dso = .{ | 2431 | .dynamic => resolved_inputs.appendAssumeCapacity(.{ |
| 2417 | .path = path, | 2432 | .dso = .{ |
| 2418 | .file = file, | 2433 | .path = path, |
| 2419 | .needed = query.needed, | 2434 | .file = file, |
| 2420 | .weak = query.weak, | 2435 | .needed = query.needed, |
| 2421 | .reexport = query.reexport, | 2436 | .weak = query.weak, |
| 2422 | } }), | 2437 | .reexport = query.reexport, |
| 2438 | .fallback_soname = fallback_soname, | ||
| 2439 | }, | ||
| 2440 | }), | ||
| 2423 | } | 2441 | } |
| 2424 | return .ok; | 2442 | return .ok; |
| 2425 | } | 2443 | } |
| ... | @@ -2441,11 +2459,37 @@ fn resolvePathInput( | ... | @@ -2441,11 +2459,37 @@ fn resolvePathInput( |
| 2441 | color: std.zig.Color, | 2459 | color: std.zig.Color, |
| 2442 | ) Allocator.Error!?ResolveLibInputResult { | 2460 | ) Allocator.Error!?ResolveLibInputResult { |
| 2443 | switch (Compilation.classifyFileExt(pq.path.sub_path)) { | 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), | 2462 | .static_library => return try resolvePathInputLib( |
| 2445 | .shared_library => return try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, pq, .dynamic, color), | 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 | .object => { | 2490 | .object => { |
| 2447 | var file = pq.path.root_dir.handle.openFile(io, pq.path.sub_path, .{}) catch |err| | 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 | errdefer file.close(io); | 2493 | errdefer file.close(io); |
| 2450 | try resolved_inputs.append(gpa, .{ .object = .{ | 2494 | try resolved_inputs.append(gpa, .{ .object = .{ |
| 2451 | .path = pq.path, | 2495 | .path = pq.path, |
| ... | @@ -2457,7 +2501,7 @@ fn resolvePathInput( | ... | @@ -2457,7 +2501,7 @@ fn resolvePathInput( |
| 2457 | }, | 2501 | }, |
| 2458 | .res => { | 2502 | .res => { |
| 2459 | var file = pq.path.root_dir.handle.openFile(io, pq.path.sub_path, .{}) catch |err| | 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 | errdefer file.close(io); | 2505 | errdefer file.close(io); |
| 2462 | try resolved_inputs.append(gpa, .{ .res = .{ | 2506 | try resolved_inputs.append(gpa, .{ .res = .{ |
| 2463 | .path = pq.path, | 2507 | .path = pq.path, |
| ... | @@ -2485,6 +2529,7 @@ fn resolvePathInputLib( | ... | @@ -2485,6 +2529,7 @@ fn resolvePathInputLib( |
| 2485 | pq: UnresolvedInput.PathQuery, | 2529 | pq: UnresolvedInput.PathQuery, |
| 2486 | link_mode: std.lang.LinkMode, | 2530 | link_mode: std.lang.LinkMode, |
| 2487 | color: std.zig.Color, | 2531 | color: std.zig.Color, |
| 2532 | fallback_soname: Input.Dso.FallbackSoname, | ||
| 2488 | ) Allocator.Error!ResolveLibInputResult { | 2533 | ) Allocator.Error!ResolveLibInputResult { |
| 2489 | try resolved_inputs.ensureUnusedCapacity(gpa, 1); | 2534 | try resolved_inputs.ensureUnusedCapacity(gpa, 1); |
| 2490 | try archive_dedup.ensureUnusedCapacity(gpa, 1); | 2535 | try archive_dedup.ensureUnusedCapacity(gpa, 1); |
| ... | @@ -2498,21 +2543,30 @@ fn resolvePathInputLib( | ... | @@ -2498,21 +2543,30 @@ fn resolvePathInputLib( |
| 2498 | }) { | 2543 | }) { |
| 2499 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { | 2544 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { |
| 2500 | error.FileNotFound => return .no_match, | 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 | link_mode, std.fmt.alt(test_path, .formatEscapeChar), e, | 2547 | link_mode, std.fmt.alt(test_path, .formatEscapeChar), e, |
| 2503 | }), | 2548 | }), |
| 2504 | }; | 2549 | }; |
| 2505 | errdefer file.close(io); | 2550 | errdefer file.close(io); |
| 2506 | try ld_script_bytes.resize(gpa, @max(std.elf.MAGIC.len, std.elf.ARMAG.len)); | 2551 | try ld_script_bytes.resize(gpa, @max(std.elf.MAGIC.len, std.elf.ARMAG.len)); |
| 2507 | const n = file.readPositionalAll(io, ld_script_bytes.items, 0) catch |err| | 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 | const buf = ld_script_bytes.items[0..n]; | 2554 | const buf = ld_script_bytes.items[0..n]; |
| 2510 | if (mem.startsWith(u8, buf, std.elf.MAGIC) or | 2555 | if (mem.startsWith(u8, buf, std.elf.MAGIC) or |
| 2511 | mem.startsWith(u8, buf, std.elf.ARMAG) or | 2556 | mem.startsWith(u8, buf, std.elf.ARMAG) or |
| 2512 | mem.startsWith(u8, buf, std.elf.ARMAG_THIN)) | 2557 | mem.startsWith(u8, buf, std.elf.ARMAG_THIN)) |
| 2513 | { | 2558 | { |
| 2514 | // Appears to be an ELF or archive file. | 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 | const stat = file.stat(io) catch |err| | 2571 | const stat = file.stat(io) catch |err| |
| 2518 | fatal("failed to stat {f}: {t}", .{ test_path, err }); | 2572 | fatal("failed to stat {f}: {t}", .{ test_path, err }); |
| ... | @@ -2563,6 +2617,7 @@ fn resolvePathInputLib( | ... | @@ -2563,6 +2617,7 @@ fn resolvePathInputLib( |
| 2563 | unresolved_inputs.appendAssumeCapacity(.{ .name_query = .{ | 2617 | unresolved_inputs.appendAssumeCapacity(.{ .name_query = .{ |
| 2564 | .name = try arena.dupe(u8, arg.path["-l".len..]), | 2618 | .name = try arena.dupe(u8, arg.path["-l".len..]), |
| 2565 | .query = query, | 2619 | .query = query, |
| 2620 | .name_done = false, | ||
| 2566 | } }); | 2621 | } }); |
| 2567 | } else { | 2622 | } else { |
| 2568 | unresolved_inputs.appendAssumeCapacity(.{ .ambiguous_name = .{ | 2623 | unresolved_inputs.appendAssumeCapacity(.{ .ambiguous_name = .{ |
| ... | @@ -2577,12 +2632,19 @@ fn resolvePathInputLib( | ... | @@ -2577,12 +2632,19 @@ fn resolvePathInputLib( |
| 2577 | 2632 | ||
| 2578 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { | 2633 | var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { |
| 2579 | error.FileNotFound => return .no_match, | 2634 | error.FileNotFound => return .no_match, |
| 2580 | else => |e| fatal("unable to search for {s} library {f}: {s}", .{ | 2635 | else => |e| fatal("unable to search for {t} library {f}: {t}", .{ link_mode, test_path, e }), |
| 2581 | @tagName(link_mode), test_path, @errorName(e), | ||
| 2582 | }), | ||
| 2583 | }; | 2636 | }; |
| 2584 | errdefer file.close(io); | 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 | pub fn openObject(io: Io, path: Path, must_link: bool, hidden: bool) !Input.Object { | 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,6 +2667,7 @@ pub fn openDso(io: Io, path: Path, needed: bool, weak: bool, reexport: bool) !In |
| 2605 | .needed = needed, | 2667 | .needed = needed, |
| 2606 | .weak = weak, | 2668 | .weak = weak, |
| 2607 | .reexport = reexport, | 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,7 +2699,7 @@ pub fn anyObjectInputs(inputs: []const Input) bool { |
| 2636 | pub fn countObjectInputs(inputs: []const Input) usize { | 2699 | pub fn countObjectInputs(inputs: []const Input) usize { |
| 2637 | var count: usize = 0; | 2700 | var count: usize = 0; |
| 2638 | for (inputs) |input| switch (input) { | 2701 | for (inputs) |input| switch (input) { |
| 2639 | .dso, .dso_exact => continue, | 2702 | .dso => continue, |
| 2640 | .res, .object, .archive => count += 1, | 2703 | .res, .object, .archive => count += 1, |
| 2641 | }; | 2704 | }; |
| 2642 | return count; | 2705 | return count; |
| ... | @@ -2646,7 +2709,7 @@ pub fn countObjectInputs(inputs: []const Input) usize { | ... | @@ -2646,7 +2709,7 @@ pub fn countObjectInputs(inputs: []const Input) usize { |
| 2646 | pub fn firstObjectInput(inputs: []const Input) ?Input.Object { | 2709 | pub fn firstObjectInput(inputs: []const Input) ?Input.Object { |
| 2647 | for (inputs) |input| switch (input) { | 2710 | for (inputs) |input| switch (input) { |
| 2648 | .object, .archive => |obj| return obj, | 2711 | .object, .archive => |obj| return obj, |
| 2649 | .res, .dso, .dso_exact => continue, | 2712 | .res, .dso => continue, |
| 2650 | }; | 2713 | }; |
| 2651 | return null; | 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,7 +3905,7 @@ pub fn loadInput(coff: *Coff, input: link.Input) link.Error!void { |
| 3905 | const comp = coff.base.comp; | 3905 | const comp = coff.base.comp; |
| 3906 | const io = comp.io; | 3906 | const io = comp.io; |
| 3907 | 3907 | ||
| 3908 | const path = input.path() orelse unreachable; | 3908 | const path = input.path(); |
| 3909 | const gop = try coff.inputs.getOrPut(comp.gpa, path); | 3909 | const gop = try coff.inputs.getOrPut(comp.gpa, path); |
| 3910 | if (gop.found_existing) return; | 3910 | if (gop.found_existing) return; |
| 3911 | errdefer _ = coff.inputs.swapRemove(path); | 3911 | errdefer _ = coff.inputs.swapRemove(path); |
| ... | @@ -3935,7 +3935,6 @@ pub fn loadInput(coff: *Coff, input: link.Input) link.Error!void { | ... | @@ -3935,7 +3935,6 @@ pub fn loadInput(coff: *Coff, input: link.Input) link.Error!void { |
| 3935 | coff.loadDll(dso.path, &fr) catch |err| | 3935 | coff.loadDll(dso.path, &fr) catch |err| |
| 3936 | return coff.failLoadInput(err, &fr, dso.path); | 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,7 +722,6 @@ 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 | .dso_exact => |dso_exact| try argv.appendSlice(gpa, &.{ "-l", dso_exact.name }), | ||
| 726 | .object, .archive => |obj| try argv.append(gpa, try obj.path.toString(comp.arena)), | 725 | .object, .archive => |obj| try argv.append(gpa, try obj.path.toString(comp.arena)), |
| 727 | .dso => |dso| try argv.append(gpa, try dso.path.toString(comp.arena)), | 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,14 +729,13 @@ pub fn loadInput(self: *Elf, input: link.Input) !void { |
| 730 | 729 | ||
| 731 | switch (input) { | 730 | switch (input) { |
| 732 | .res => unreachable, | 731 | .res => unreachable, |
| 733 | .dso_exact => @panic("TODO"), | ||
| 734 | .object => |obj| try parseObject(self, obj), | 732 | .object => |obj| try parseObject(self, obj), |
| 735 | .archive => |obj| if (self.base.isStaticLib()) { | 733 | .archive => |obj| if (self.base.isStaticLib()) { |
| 736 | // Ignore static library inputs when generating a static library. | 734 | // Ignore static library inputs when generating a static library. |
| 737 | } else { | 735 | } else { |
| 738 | try parseArchive(gpa, io, diags, &self.file_handles, &self.files, target, debug_fmt_strip, default_sym_version, &self.objects, obj); | 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,6 +1106,7 @@ fn parseArchive( |
| 1108 | 1106 | ||
| 1109 | fn parseDso( | 1107 | fn parseDso( |
| 1110 | gpa: Allocator, | 1108 | gpa: Allocator, |
| 1109 | arena: Allocator, | ||
| 1111 | io: Io, | 1110 | io: Io, |
| 1112 | diags: *Diags, | 1111 | diags: *Diags, |
| 1113 | dso: link.Input.Dso, | 1112 | dso: link.Input.Dso, |
| ... | @@ -1124,7 +1123,12 @@ fn parseDso( | ... | @@ -1124,7 +1123,12 @@ fn parseDso( |
| 1124 | var header = try SharedObject.parseHeader(gpa, io, diags, dso.path, handle, stat, target); | 1123 | var header = try SharedObject.parseHeader(gpa, io, diags, dso.path, handle, stat, target); |
| 1125 | defer header.deinit(gpa); | 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 | const gop = try shared_objects.getOrPut(gpa, soname); | 1133 | const gop = try shared_objects.getOrPut(gpa, soname); |
| 1130 | if (gop.found_existing) return; | 1134 | if (gop.found_existing) return; |
| ... | @@ -1156,6 +1160,7 @@ fn parseDso( | ... | @@ -1156,6 +1160,7 @@ fn parseDso( |
| 1156 | .symbols_extra = .empty, | 1160 | .symbols_extra = .empty, |
| 1157 | .symbols_resolver = .empty, | 1161 | .symbols_resolver = .empty, |
| 1158 | .output_symtab_ctx = .{}, | 1162 | .output_symtab_ctx = .{}, |
| 1163 | .fallback_soname = fallback_soname, | ||
| 1159 | }, | 1164 | }, |
| 1160 | }); | 1165 | }); |
| 1161 | const so = fileLookup(files.*, index, null).?.shared_object; | 1166 | const so = fileLookup(files.*, index, null).?.shared_object; |
src/link/Elf/SharedObject.zig+3-1| ... | @@ -31,6 +31,8 @@ alive: bool, | ... | @@ -31,6 +31,8 @@ alive: bool, |
| 31 | 31 | ||
| 32 | output_symtab_ctx: Elf.SymtabCtx, | 32 | output_symtab_ctx: Elf.SymtabCtx, |
| 33 | 33 | ||
| 34 | fallback_soname: []const u8, | ||
| 35 | |||
| 34 | pub fn deinit(so: *SharedObject, gpa: Allocator) void { | 36 | pub fn deinit(so: *SharedObject, gpa: Allocator) void { |
| 35 | gpa.free(so.path.sub_path); | 37 | gpa.free(so.path.sub_path); |
| 36 | so.parsed.deinit(gpa); | 38 | so.parsed.deinit(gpa); |
| ... | @@ -427,7 +429,7 @@ pub fn asFile(self: *SharedObject) File { | ... | @@ -427,7 +429,7 @@ pub fn asFile(self: *SharedObject) File { |
| 427 | } | 429 | } |
| 428 | 430 | ||
| 429 | pub fn soname(self: *SharedObject) []const u8 { | 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 | pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void { | 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,34 +6230,19 @@ fn loadInputInner(elf: *Elf, input: link.Input) (Error || error{BadMagic})!void |
| 6230 | .dso => |dso| { | 6230 | .dso => |dso| { |
| 6231 | try elf.needed.ensureUnusedCapacity(elf.base.comp.gpa, 1); | 6231 | try elf.needed.ensureUnusedCapacity(elf.base.comp.gpa, 1); |
| 6232 | var fr = dso.file.reader(io, &buf); | 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 | else => |e| return e, | 6234 | else => |e| return e, |
| 6235 | error.EndOfStream => return diags.failParse( | 6235 | error.EndOfStream => return diags.failParse(dso.path, "unexpected eof", .{}), |
| 6236 | dso.path, | ||
| 6237 | "unexpected eof", | ||
| 6238 | .{}, | ||
| 6239 | ), | ||
| 6240 | error.AccessDenied, error.Unexpected, error.Unseekable => |e| return diags.fail( | 6236 | error.AccessDenied, error.Unexpected, error.Unseekable => |e| return diags.fail( |
| 6241 | "failed to read \"{f}\": {t}", | 6237 | "failed to read {qf}: {t}", |
| 6242 | .{ dso.path.fmtEscapeString(), e }, | 6238 | .{ dso.path, e }, |
| 6243 | ), | 6239 | ), |
| 6244 | error.ReadFailed => switch (fr.err.?) { | 6240 | error.ReadFailed => switch (fr.err.?) { |
| 6245 | error.Canceled => |e| return e, | 6241 | error.Canceled => |e| return e, |
| 6246 | else => |e| return diags.fail( | 6242 | else => |e| return diags.fail("failed to read {qf}: {t}", .{ dso.path, e }), |
| 6247 | "failed to read \"{f}\": {t}", | ||
| 6248 | .{ dso.path.fmtEscapeString(), e }, | ||
| 6249 | ), | ||
| 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 | fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadParseInputError || error{BadMagic})!void { | 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,7 +6852,12 @@ fn populateArchiveMemberName(elf: *Elf, member_ar_hdr: *std.elf.ar_hdr, member_n |
| 6867 | @memcpy(dest_slice[0 .. dest_slice.len - 2], member_name); | 6852 | @memcpy(dest_slice[0 .. dest_slice.len - 2], member_name); |
| 6868 | @memcpy(dest_slice[dest_slice.len - 2 ..], "/\n"); // yes, the terminator is weird | 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 | const comp = elf.base.comp; | 6861 | const comp = elf.base.comp; |
| 6872 | const gpa = comp.gpa; | 6862 | const gpa = comp.gpa; |
| 6873 | const diags = &comp.link_diags; | 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,7 +6953,10 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars |
| 6963 | } | 6953 | } |
| 6964 | break std.mem.sliceTo(dynstr[@intCast(val)..], 0); | 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 | try elf.needed.put(gpa, try elf.string(.dynstr, soname), {}); | 6960 | try elf.needed.put(gpa, try elf.string(.dynstr, soname), {}); |
| 6968 | 6961 | ||
| 6969 | // Scan the symbol table and populate `elf.dso_globals`. | 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,9 +309,9 @@ 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, .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 | .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); |
| 316 | }, | 316 | }, |
| 317 | }; | 317 | }; |
| ... | @@ -551,7 +551,6 @@ fn coffLink(lld: *Lld, arena: Allocator) !void { | ... | @@ -551,7 +551,6 @@ fn coffLink(lld: *Lld, arena: Allocator) !void { |
| 551 | 551 | ||
| 552 | try argv.ensureUnusedCapacity(comp.link_inputs.len); | 552 | try argv.ensureUnusedCapacity(comp.link_inputs.len); |
| 553 | for (comp.link_inputs) |link_input| switch (link_input) { | 553 | for (comp.link_inputs) |link_input| switch (link_input) { |
| 554 | .dso_exact => unreachable, // not applicable to PE/COFF | ||
| 555 | inline .dso, .res => |x| { | 554 | inline .dso, .res => |x| { |
| 556 | argv.appendAssumeCapacity(try x.path.toString(arena)); | 555 | argv.appendAssumeCapacity(try x.path.toString(arena)); |
| 557 | }, | 556 | }, |
| ... | @@ -1114,10 +1113,6 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { | ... | @@ -1114,10 +1113,6 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { |
| 1114 | } | 1113 | } |
| 1115 | try argv.append(try obj.path.toString(arena)); | 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 | if (whole_archive) { | 1118 | if (whole_archive) { |
| ... | @@ -1159,9 +1154,16 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { | ... | @@ -1159,9 +1154,16 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { |
| 1159 | argv.appendAssumeCapacity("--as-needed"); | 1154 | argv.appendAssumeCapacity("--as-needed"); |
| 1160 | var as_needed = true; | 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 | for (base.comp.link_inputs) |link_input| switch (link_input) { | 1164 | for (base.comp.link_inputs) |link_input| switch (link_input) { |
| 1163 | .res => unreachable, // Windows-only | 1165 | .res => unreachable, // Windows-only |
| 1164 | .object, .archive, .dso_exact => continue, | 1166 | .object, .archive => continue, |
| 1165 | .dso => |dso| { | 1167 | .dso => |dso| { |
| 1166 | const lib_as_needed = !dso.needed; | 1168 | const lib_as_needed = !dso.needed; |
| 1167 | switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) { | 1169 | switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) { |
| ... | @@ -1176,11 +1178,17 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { | ... | @@ -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 | 1181 | // By this time, we depend on these libs being dynamically linked libraries and |
| 1180 | // libraries and not static libraries (the check for that needs to be earlier), | 1182 | // not static libraries (the check for that needs to be earlier), but they could |
| 1181 | // but they could be full paths to .so files, in which case we | 1183 | // be full file paths, in which case we don't want to use the "-l:" strategy. |
| 1182 | // want to avoid prepending "-l". | 1184 | switch (dso.fallback_soname) { |
| 1183 | argv.appendAssumeCapacity(try dso.path.toString(arena)); | 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,7 +1596,6 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void { |
| 1588 | .dso => |dso| { | 1596 | .dso => |dso| { |
| 1589 | try argv.append(try dso.path.toString(arena)); | 1597 | try argv.append(try dso.path.toString(arena)); |
| 1590 | }, | 1598 | }, |
| 1591 | .dso_exact => unreachable, | ||
| 1592 | .res => unreachable, | 1599 | .res => unreachable, |
| 1593 | }; | 1600 | }; |
| 1594 | if (whole_archive) { | 1601 | if (whole_archive) { |
src/link/MachO.zig+13-13| ... | @@ -372,7 +372,6 @@ pub fn flush( | ... | @@ -372,7 +372,6 @@ pub fn flush( |
| 372 | for (comp.link_inputs) |link_input| switch (link_input) { | 372 | for (comp.link_inputs) |link_input| switch (link_input) { |
| 373 | .dso => continue, // handled below | 373 | .dso => continue, // handled below |
| 374 | .object, .archive => positionals.appendAssumeCapacity(link_input), | 374 | .object, .archive => positionals.appendAssumeCapacity(link_input), |
| 375 | .dso_exact => @panic("TODO"), | ||
| 376 | .res => unreachable, | 375 | .res => unreachable, |
| 377 | }; | 376 | }; |
| 378 | 377 | ||
| ... | @@ -406,7 +405,7 @@ pub fn flush( | ... | @@ -406,7 +405,7 @@ pub fn flush( |
| 406 | 405 | ||
| 407 | for (positionals.items) |link_input| { | 406 | for (positionals.items) |link_input| { |
| 408 | self.classifyInputFile(link_input) catch |err| | 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 | var system_libs = std.array_list.Managed(SystemLib).init(gpa); | 411 | var system_libs = std.array_list.Managed(SystemLib).init(gpa); |
| ... | @@ -447,11 +446,11 @@ pub fn flush( | ... | @@ -447,11 +446,11 @@ pub fn flush( |
| 447 | }; | 446 | }; |
| 448 | 447 | ||
| 449 | for (comp.link_inputs) |link_input| switch (link_input) { | 448 | for (comp.link_inputs) |link_input| switch (link_input) { |
| 450 | .object, .archive, .dso_exact => continue, | 449 | .object, .archive => continue, |
| 451 | .res => unreachable, | 450 | .res => unreachable, |
| 452 | .dso => { | 451 | .dso => { |
| 453 | self.classifyInputFile(link_input) catch |err| | 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,8 +654,9 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { |
| 655 | for (comp.link_inputs) |link_input| switch (link_input) { | 654 | for (comp.link_inputs) |link_input| switch (link_input) { |
| 656 | .object, .archive => |obj| try argv.append(try obj.path.toString(arena)), | 655 | .object, .archive => |obj| try argv.append(try obj.path.toString(arena)), |
| 657 | .res => |res| try argv.append(try res.path.toString(arena)), | 656 | .res => |res| try argv.append(try res.path.toString(arena)), |
| 658 | .dso => |dso| try argv.append(try dso.path.toString(arena)), | 657 | .dso => |dso| { |
| 659 | .dso_exact => |dso_exact| try argv.appendSlice(&.{ "-l", dso_exact.name }), | 658 | try argv.append(try dso.path.toString(arena)); |
| 659 | }, | ||
| 660 | }; | 660 | }; |
| 661 | 661 | ||
| 662 | for (comp.c_objects.items) |c_object| { | 662 | for (comp.c_objects.items) |c_object| { |
| ... | @@ -748,7 +748,6 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { | ... | @@ -748,7 +748,6 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { |
| 748 | if (obj.must_link) try argv.append("-force_load"); // TODO: verify this | 748 | if (obj.must_link) try argv.append("-force_load"); // TODO: verify this |
| 749 | try argv.append(try obj.path.toString(arena)); | 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 | for (comp.c_objects.items) |c_object| { | 753 | for (comp.c_objects.items) |c_object| { |
| ... | @@ -775,16 +774,18 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { | ... | @@ -775,16 +774,18 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { |
| 775 | } | 774 | } |
| 776 | 775 | ||
| 777 | for (comp.link_inputs) |link_input| switch (link_input) { | 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 | .res => unreachable, // windows only | 778 | .res => unreachable, // windows only |
| 780 | .dso => |dso| { | 779 | .dso => |dso| { |
| 780 | try argv.ensureUnusedCapacity(2); | ||
| 781 | if (dso.needed) { | 781 | if (dso.needed) { |
| 782 | try argv.appendSlice(&.{ "-needed-l", try dso.path.toString(arena) }); | 782 | argv.appendAssumeCapacity("-needed-l"); |
| 783 | } else if (dso.weak) { | 783 | } else if (dso.weak) { |
| 784 | try argv.appendSlice(&.{ "-weak-l", try dso.path.toString(arena) }); | 784 | argv.appendAssumeCapacity("-weak-l"); |
| 785 | } else { | 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,7 +871,7 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void { |
| 870 | const comp = self.base.comp; | 871 | const comp = self.base.comp; |
| 871 | const io = comp.io; | 872 | const io = comp.io; |
| 872 | 873 | ||
| 873 | const path, const file = input.pathAndFile().?; | 874 | const path, const file = input.pathAndFile(); |
| 874 | // TODO don't classify now, it's too late. The input file has already been classified | 875 | // TODO don't classify now, it's too late. The input file has already been classified |
| 875 | log.debug("classifying input file {f}", .{path}); | 876 | log.debug("classifying input file {f}", .{path}); |
| 876 | 877 | ||
| ... | @@ -4478,7 +4479,6 @@ const SystemLib = struct { | ... | @@ -4478,7 +4479,6 @@ const SystemLib = struct { |
| 4478 | 4479 | ||
| 4479 | fn fromLinkInput(link_input: link.Input) SystemLib { | 4480 | fn fromLinkInput(link_input: link.Input) SystemLib { |
| 4480 | return switch (link_input) { | 4481 | return switch (link_input) { |
| 4481 | .dso_exact => unreachable, | ||
| 4482 | .res => unreachable, | 4482 | .res => unreachable, |
| 4483 | .object, .archive => |obj| .{ | 4483 | .object, .archive => |obj| .{ |
| 4484 | .path = obj.path, | 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,7 +19,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat |
| 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 = positionals.items[0].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| |
| ... | @@ -31,7 +31,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat | ... | @@ -31,7 +31,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat |
| 31 | 31 | ||
| 32 | for (positionals.items) |link_input| { | 32 | for (positionals.items) |link_input| { |
| 33 | macho_file.classifyInputFile(link_input) catch |err| | 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 | if (diags.hasErrors()) return error.AlreadyReported; | 37 | if (diags.hasErrors()) return error.AlreadyReported; |
| ... | @@ -102,7 +102,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? | ... | @@ -102,7 +102,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 102 | 102 | ||
| 103 | for (positionals.items) |link_input| { | 103 | for (positionals.items) |link_input| { |
| 104 | macho_file.classifyInputFile(link_input) catch |err| | 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 | if (diags.hasErrors()) return error.AlreadyReported; | 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,7 +3788,6 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void { |
| 3788 | const argv = &wasm.dump_argv_list; | 3788 | const argv = &wasm.dump_argv_list; |
| 3789 | switch (input) { | 3789 | switch (input) { |
| 3790 | .res => unreachable, | 3790 | .res => unreachable, |
| 3791 | .dso_exact => unreachable, | ||
| 3792 | .dso => unreachable, | 3791 | .dso => unreachable, |
| 3793 | .object, .archive => |obj| { | 3792 | .object, .archive => |obj| { |
| 3794 | try argv.append(gpa, try obj.path.toString(comp.arena)); | 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,7 +3797,6 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void { |
| 3798 | 3797 | ||
| 3799 | switch (input) { | 3798 | switch (input) { |
| 3800 | .res => unreachable, | 3799 | .res => unreachable, |
| 3801 | .dso_exact => unreachable, | ||
| 3802 | .dso => unreachable, | 3800 | .dso => unreachable, |
| 3803 | .object => |obj| try parseObject(wasm, obj), | 3801 | .object => |obj| try parseObject(wasm, obj), |
| 3804 | .archive => |obj| try parseArchive(wasm, obj), | 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,10 +70,6 @@ var stdin_buffer: [4096]u8 align(std.heap.page_size_min) = undefined; |
| 70 | /// This can be global since stdout is a singleton. | 70 | /// This can be global since stdout is a singleton. |
| 71 | var stdout_buffer: [4096]u8 align(std.heap.page_size_min) = undefined; | 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 | const normal_usage = | 73 | const normal_usage = |
| 78 | \\Usage: zig [command] [options] | 74 | \\Usage: zig [command] [options] |
| 79 | \\ | 75 | \\ |
| ... | @@ -807,7 +803,7 @@ const compile_usage = | ... | @@ -807,7 +803,7 @@ const compile_usage = |
| 807 | \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features | 803 | \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features |
| 808 | \\ --debug-log [scope] Enable printing debug/info log messages for scope | 804 | \\ --debug-log [scope] Enable printing debug/info log messages for scope |
| 809 | \\ --debug-compile-errors Crash with helpful diagnostics at the first compile error | 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 | \\ --debug-rt[=mode] Build compiler runtime libraries with [mode] optimization | 807 | \\ --debug-rt[=mode] Build compiler runtime libraries with [mode] optimization |
| 812 | \\ (debug if [=mode] is omitted) | 808 | \\ (debug if [=mode] is omitted) |
| 813 | \\ --debug-incremental Enable incremental compilation debug features | 809 | \\ --debug-incremental Enable incremental compilation debug features |
| ... | @@ -1355,6 +1351,7 @@ fn buildOutputType( | ... | @@ -1355,6 +1351,7 @@ fn buildOutputType( |
| 1355 | .search_strategy = lib_search_strategy, | 1351 | .search_strategy = lib_search_strategy, |
| 1356 | .allow_so_scripts = allow_so_scripts, | 1352 | .allow_so_scripts = allow_so_scripts, |
| 1357 | }, | 1353 | }, |
| 1354 | .name_done = false, | ||
| 1358 | } }); | 1355 | } }); |
| 1359 | } else if (mem.eql(u8, arg, "--needed-library") or | 1356 | } else if (mem.eql(u8, arg, "--needed-library") or |
| 1360 | mem.eql(u8, arg, "-needed-l") or | 1357 | mem.eql(u8, arg, "-needed-l") or |
| ... | @@ -1370,6 +1367,7 @@ fn buildOutputType( | ... | @@ -1370,6 +1367,7 @@ fn buildOutputType( |
| 1370 | .search_strategy = lib_search_strategy, | 1367 | .search_strategy = lib_search_strategy, |
| 1371 | .allow_so_scripts = allow_so_scripts, | 1368 | .allow_so_scripts = allow_so_scripts, |
| 1372 | }, | 1369 | }, |
| 1370 | .name_done = false, | ||
| 1373 | } }); | 1371 | } }); |
| 1374 | } else if (mem.eql(u8, arg, "-weak_library") or mem.eql(u8, arg, "-weak-l")) { | 1372 | } else if (mem.eql(u8, arg, "-weak_library") or mem.eql(u8, arg, "-weak-l")) { |
| 1375 | try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ | 1373 | try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ |
| ... | @@ -1381,6 +1379,7 @@ fn buildOutputType( | ... | @@ -1381,6 +1379,7 @@ fn buildOutputType( |
| 1381 | .search_strategy = lib_search_strategy, | 1379 | .search_strategy = lib_search_strategy, |
| 1382 | .allow_so_scripts = allow_so_scripts, | 1380 | .allow_so_scripts = allow_so_scripts, |
| 1383 | }, | 1381 | }, |
| 1382 | .name_done = false, | ||
| 1384 | } }); | 1383 | } }); |
| 1385 | } else if (mem.eql(u8, arg, "-D")) { | 1384 | } else if (mem.eql(u8, arg, "-D")) { |
| 1386 | try cc_argv.appendSlice(arena, &.{ arg, args_iter.nextOrFatal() }); | 1385 | try cc_argv.appendSlice(arena, &.{ arg, args_iter.nextOrFatal() }); |
| ... | @@ -1843,6 +1842,7 @@ fn buildOutputType( | ... | @@ -1843,6 +1842,7 @@ fn buildOutputType( |
| 1843 | .search_strategy = lib_search_strategy, | 1842 | .search_strategy = lib_search_strategy, |
| 1844 | .allow_so_scripts = allow_so_scripts, | 1843 | .allow_so_scripts = allow_so_scripts, |
| 1845 | }, | 1844 | }, |
| 1845 | .name_done = false, | ||
| 1846 | } }); | 1846 | } }); |
| 1847 | } else if (mem.cutPrefix(u8, arg, "-needed-l")) |name| { | 1847 | } else if (mem.cutPrefix(u8, arg, "-needed-l")) |name| { |
| 1848 | try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ | 1848 | try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ |
| ... | @@ -1854,6 +1854,7 @@ fn buildOutputType( | ... | @@ -1854,6 +1854,7 @@ fn buildOutputType( |
| 1854 | .search_strategy = lib_search_strategy, | 1854 | .search_strategy = lib_search_strategy, |
| 1855 | .allow_so_scripts = allow_so_scripts, | 1855 | .allow_so_scripts = allow_so_scripts, |
| 1856 | }, | 1856 | }, |
| 1857 | .name_done = false, | ||
| 1857 | } }); | 1858 | } }); |
| 1858 | } else if (mem.cutPrefix(u8, arg, "-weak-l")) |name| { | 1859 | } else if (mem.cutPrefix(u8, arg, "-weak-l")) |name| { |
| 1859 | try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ | 1860 | try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ |
| ... | @@ -1865,6 +1866,7 @@ fn buildOutputType( | ... | @@ -1865,6 +1866,7 @@ fn buildOutputType( |
| 1865 | .search_strategy = lib_search_strategy, | 1866 | .search_strategy = lib_search_strategy, |
| 1866 | .allow_so_scripts = allow_so_scripts, | 1867 | .allow_so_scripts = allow_so_scripts, |
| 1867 | }, | 1868 | }, |
| 1869 | .name_done = false, | ||
| 1868 | } }); | 1870 | } }); |
| 1869 | } else if (mem.startsWith(u8, arg, "-D")) { | 1871 | } else if (mem.startsWith(u8, arg, "-D")) { |
| 1870 | try cc_argv.append(arena, arg); | 1872 | try cc_argv.append(arena, arg); |
| ... | @@ -2083,12 +2085,24 @@ fn buildOutputType( | ... | @@ -2083,12 +2085,24 @@ fn buildOutputType( |
| 2083 | // We don't know whether this library is part of libc or libc++ until | 2085 | // We don't know whether this library is part of libc or libc++ until |
| 2084 | // we resolve the target, so we simply append to the list for now. | 2086 | // we resolve the target, so we simply append to the list for now. |
| 2085 | if (mem.startsWith(u8, it.only_arg, ":")) { | 2087 | if (mem.startsWith(u8, it.only_arg, ":")) { |
| 2086 | // -l :path/to/filename is used when callers need | 2088 | // -l :path/to/filename indicates: |
| 2087 | // more control over what's in the resulting | 2089 | // * No extra rpaths. |
| 2088 | // binary: no extra rpaths and DSO filename exactly | 2090 | // * NEEDED entry should be exactly the string |
| 2089 | // as provided. CGo compilation depends on this. | 2091 | // after the colon. No file system paths prepended. |
| 2090 | try create_module.cli_link_inputs.append(arena, .{ .dso_exact = .{ | 2092 | // * The DSO still must be found at compile/link |
| 2091 | .name = it.only_arg, | 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 | } else { | 2107 | } else { |
| 2094 | const compiler_rt_classification = target_util.classifyCompilerRtLibName(it.only_arg); | 2108 | const compiler_rt_classification = target_util.classifyCompilerRtLibName(it.only_arg); |
| ... | @@ -2114,6 +2128,7 @@ fn buildOutputType( | ... | @@ -2114,6 +2128,7 @@ fn buildOutputType( |
| 2114 | .search_strategy = lib_search_strategy, | 2128 | .search_strategy = lib_search_strategy, |
| 2115 | .allow_so_scripts = allow_so_scripts, | 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,6 +2559,7 @@ fn buildOutputType( |
| 2544 | .search_strategy = lib_search_strategy, | 2559 | .search_strategy = lib_search_strategy, |
| 2545 | .allow_so_scripts = allow_so_scripts, | 2560 | .allow_so_scripts = allow_so_scripts, |
| 2546 | }, | 2561 | }, |
| 2562 | .name_done = false, | ||
| 2547 | } }), | 2563 | } }), |
| 2548 | .weak_framework => try create_module.frameworks.put(arena, it.only_arg, .{ .weak = true }), | 2564 | .weak_framework => try create_module.frameworks.put(arena, it.only_arg, .{ .weak = true }), |
| 2549 | .headerpad_max_install_names => headerpad_max_install_names = true, | 2565 | .headerpad_max_install_names => headerpad_max_install_names = true, |
| ... | @@ -2913,6 +2929,7 @@ fn buildOutputType( | ... | @@ -2913,6 +2929,7 @@ fn buildOutputType( |
| 2913 | .search_strategy = lib_search_strategy, | 2929 | .search_strategy = lib_search_strategy, |
| 2914 | .allow_so_scripts = allow_so_scripts, | 2930 | .allow_so_scripts = allow_so_scripts, |
| 2915 | }, | 2931 | }, |
| 2932 | .name_done = false, | ||
| 2916 | } }); | 2933 | } }); |
| 2917 | } else if (mem.cutPrefix(u8, arg, "-weak-l")) |rest| { | 2934 | } else if (mem.cutPrefix(u8, arg, "-weak-l")) |rest| { |
| 2918 | try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ | 2935 | try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ |
| ... | @@ -2924,6 +2941,7 @@ fn buildOutputType( | ... | @@ -2924,6 +2941,7 @@ fn buildOutputType( |
| 2924 | .search_strategy = lib_search_strategy, | 2941 | .search_strategy = lib_search_strategy, |
| 2925 | .allow_so_scripts = allow_so_scripts, | 2942 | .allow_so_scripts = allow_so_scripts, |
| 2926 | }, | 2943 | }, |
| 2944 | .name_done = false, | ||
| 2927 | } }); | 2945 | } }); |
| 2928 | } else if (mem.eql(u8, arg, "-weak_library")) { | 2946 | } else if (mem.eql(u8, arg, "-weak_library")) { |
| 2929 | try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ | 2947 | try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ |
| ... | @@ -2935,6 +2953,7 @@ fn buildOutputType( | ... | @@ -2935,6 +2953,7 @@ fn buildOutputType( |
| 2935 | .search_strategy = lib_search_strategy, | 2953 | .search_strategy = lib_search_strategy, |
| 2936 | .allow_so_scripts = allow_so_scripts, | 2954 | .allow_so_scripts = allow_so_scripts, |
| 2937 | }, | 2955 | }, |
| 2956 | .name_done = false, | ||
| 2938 | } }); | 2957 | } }); |
| 2939 | } else if (mem.eql(u8, arg, "-compatibility_version")) { | 2958 | } else if (mem.eql(u8, arg, "-compatibility_version")) { |
| 2940 | const compat_version = linker_args_it.nextOrFatal(); | 2959 | const compat_version = linker_args_it.nextOrFatal(); |
| ... | @@ -4175,6 +4194,10 @@ fn createModule( | ... | @@ -4175,6 +4194,10 @@ fn createModule( |
| 4175 | fatal("cannot use absolute path as a system library: {s}", .{lib_name}); | 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 | unresolved_link_inputs.appendAssumeCapacity(cli_link_input); | 4201 | unresolved_link_inputs.appendAssumeCapacity(cli_link_input); |
| 4179 | any_name_queries_remaining = true; | 4202 | any_name_queries_remaining = true; |
| 4180 | }, | 4203 | }, |
| ... | @@ -4269,10 +4292,10 @@ fn createModule( | ... | @@ -4269,10 +4292,10 @@ fn createModule( |
| 4269 | &create_module.link_inputs, | 4292 | &create_module.link_inputs, |
| 4270 | create_module.lib_directories.items, | 4293 | create_module.lib_directories.items, |
| 4271 | color, | 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 | if (!create_module.opts.any_dyn_libs) for (create_module.link_inputs.items) |item| switch (item) { | 4297 | if (!create_module.opts.any_dyn_libs) for (create_module.link_inputs.items) |item| switch (item) { |
| 4275 | .dso, .dso_exact => { | 4298 | .dso => { |
| 4276 | create_module.opts.any_dyn_libs = true; | 4299 | create_module.opts.any_dyn_libs = true; |
| 4277 | break; | 4300 | break; |
| 4278 | }, | 4301 | }, |