| ... | @@ -1891,30 +1891,69 @@ pub fn resolveInputs( | ... | @@ -1891,30 +1891,69 @@ pub fn resolveInputs( |
| 1891 | syslib: while (unresolved_inputs.pop()) |unresolved_input| { | 1891 | syslib: while (unresolved_inputs.pop()) |unresolved_input| { |
| 1892 | const name_query: UnresolvedInput.NameQuery = switch (unresolved_input) { | 1892 | const name_query: UnresolvedInput.NameQuery = switch (unresolved_input) { |
| 1893 | .name_query => |nq| nq, | 1893 | .name_query => |nq| nq, |
| 1894 | .ambiguous_name => |an| an: { | 1894 | .ambiguous_name => |an| { |
| 1895 | const lib_name, const link_mode = stripLibPrefixAndSuffix(an.name, target) orelse { | 1895 | // First check the path relative to the current working directory. |
| 1896 | try resolvePathInput(gpa, arena, unresolved_inputs, resolved_inputs, &ld_script_bytes, target, .{ | 1896 | // If the file is a library and is not found there, check the library search paths as well. |
| | 1897 | // This is consistent with the behavior of GNU ld. |
| | 1898 | if (try resolvePathInput( |
| | 1899 | gpa, |
| | 1900 | arena, |
| | 1901 | unresolved_inputs, |
| | 1902 | resolved_inputs, |
| | 1903 | &ld_script_bytes, |
| | 1904 | target, |
| | 1905 | .{ |
| 1897 | .path = Path.initCwd(an.name), | 1906 | .path = Path.initCwd(an.name), |
| 1898 | .query = an.query, | 1907 | .query = an.query, |
| 1899 | }, color); | | |
| 1900 | continue; | | |
| 1901 | }; | | |
| 1902 | break :an .{ | | |
| 1903 | .name = lib_name, | | |
| 1904 | .query = .{ | | |
| 1905 | .needed = an.query.needed, | | |
| 1906 | .weak = an.query.weak, | | |
| 1907 | .reexport = an.query.reexport, | | |
| 1908 | .must_link = an.query.must_link, | | |
| 1909 | .hidden = an.query.hidden, | | |
| 1910 | .allow_so_scripts = an.query.allow_so_scripts, | | |
| 1911 | .preferred_mode = link_mode, | | |
| 1912 | .search_strategy = .no_fallback, | | |
| 1913 | }, | 1908 | }, |
| 1914 | }; | 1909 | color, |
| | 1910 | )) |lib_result| { |
| | 1911 | switch (lib_result) { |
| | 1912 | .ok => continue :syslib, |
| | 1913 | .no_match => { |
| | 1914 | for (lib_directories) |lib_directory| { |
| | 1915 | switch ((try resolvePathInput( |
| | 1916 | gpa, |
| | 1917 | arena, |
| | 1918 | unresolved_inputs, |
| | 1919 | resolved_inputs, |
| | 1920 | &ld_script_bytes, |
| | 1921 | target, |
| | 1922 | .{ |
| | 1923 | .path = .{ |
| | 1924 | .root_dir = lib_directory, |
| | 1925 | .sub_path = an.name, |
| | 1926 | }, |
| | 1927 | .query = an.query, |
| | 1928 | }, |
| | 1929 | color, |
| | 1930 | )).?) { |
| | 1931 | .ok => continue :syslib, |
| | 1932 | .no_match => {}, |
| | 1933 | } |
| | 1934 | } |
| | 1935 | fatal("{s}: file listed in linker script not found", .{an.name}); |
| | 1936 | }, |
| | 1937 | } |
| | 1938 | } |
| | 1939 | continue; |
| 1915 | }, | 1940 | }, |
| 1916 | .path_query => |pq| { | 1941 | .path_query => |pq| { |
| 1917 | try resolvePathInput(gpa, arena, unresolved_inputs, resolved_inputs, &ld_script_bytes, target, pq, color); | 1942 | if (try resolvePathInput( |
| | 1943 | gpa, |
| | 1944 | arena, |
| | 1945 | unresolved_inputs, |
| | 1946 | resolved_inputs, |
| | 1947 | &ld_script_bytes, |
| | 1948 | target, |
| | 1949 | pq, |
| | 1950 | color, |
| | 1951 | )) |lib_result| { |
| | 1952 | switch (lib_result) { |
| | 1953 | .ok => {}, |
| | 1954 | .no_match => fatal("{}: file not found", .{pq.path}), |
| | 1955 | } |
| | 1956 | } |
| 1918 | continue; | 1957 | continue; |
| 1919 | }, | 1958 | }, |
| 1920 | .dso_exact => |dso_exact| { | 1959 | .dso_exact => |dso_exact| { |
| ... | @@ -2176,10 +2215,10 @@ fn resolvePathInput( | ... | @@ -2176,10 +2215,10 @@ fn resolvePathInput( |
| 2176 | target: std.Target, | 2215 | target: std.Target, |
| 2177 | pq: UnresolvedInput.PathQuery, | 2216 | pq: UnresolvedInput.PathQuery, |
| 2178 | color: std.zig.Color, | 2217 | color: std.zig.Color, |
| 2179 | ) Allocator.Error!void { | 2218 | ) Allocator.Error!?ResolveLibInputResult { |
| 2180 | switch (switch (Compilation.classifyFileExt(pq.path.sub_path)) { | 2219 | switch (Compilation.classifyFileExt(pq.path.sub_path)) { |
| 2181 | .static_library => try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .static, color), | 2220 | .static_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .static, color), |
| 2182 | .shared_library => try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .dynamic, color), | 2221 | .shared_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .dynamic, color), |
| 2183 | .object => { | 2222 | .object => { |
| 2184 | var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err| | 2223 | var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err| |
| 2185 | fatal("failed to open object {}: {s}", .{ pq.path, @errorName(err) }); | 2224 | fatal("failed to open object {}: {s}", .{ pq.path, @errorName(err) }); |
| ... | @@ -2190,7 +2229,7 @@ fn resolvePathInput( | ... | @@ -2190,7 +2229,7 @@ fn resolvePathInput( |
| 2190 | .must_link = pq.query.must_link, | 2229 | .must_link = pq.query.must_link, |
| 2191 | .hidden = pq.query.hidden, | 2230 | .hidden = pq.query.hidden, |
| 2192 | } }); | 2231 | } }); |
| 2193 | return; | 2232 | return null; |
| 2194 | }, | 2233 | }, |
| 2195 | .res => { | 2234 | .res => { |
| 2196 | var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err| | 2235 | var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err| |
| ... | @@ -2200,12 +2239,9 @@ fn resolvePathInput( | ... | @@ -2200,12 +2239,9 @@ fn resolvePathInput( |
| 2200 | .path = pq.path, | 2239 | .path = pq.path, |
| 2201 | .file = file, | 2240 | .file = file, |
| 2202 | } }); | 2241 | } }); |
| 2203 | return; | 2242 | return null; |
| 2204 | }, | 2243 | }, |
| 2205 | else => fatal("{}: unrecognized file extension", .{pq.path}), | 2244 | else => fatal("{}: unrecognized file extension", .{pq.path}), |
| 2206 | }) { | | |
| 2207 | .ok => {}, | | |
| 2208 | .no_match => fatal("{}: file not found", .{pq.path}), | | |
| 2209 | } | 2245 | } |
| 2210 | } | 2246 | } |
| 2211 | | 2247 | |
| ... | @@ -2226,9 +2262,11 @@ fn resolvePathInputLib( | ... | @@ -2226,9 +2262,11 @@ fn resolvePathInputLib( |
| 2226 | try resolved_inputs.ensureUnusedCapacity(gpa, 1); | 2262 | try resolved_inputs.ensureUnusedCapacity(gpa, 1); |
| 2227 | | 2263 | |
| 2228 | const test_path: Path = pq.path; | 2264 | const test_path: Path = pq.path; |
| 2229 | // In the case of .so files, they might actually be "linker scripts" | 2265 | // In the case of shared libraries, they might actually be "linker scripts" |
| 2230 | // that contain references to other libraries. | 2266 | // that contain references to other libraries. |
| 2231 | if (pq.query.allow_so_scripts and target.ofmt == .elf and mem.endsWith(u8, test_path.sub_path, ".so")) { | 2267 | if (pq.query.allow_so_scripts and target.ofmt == .elf and |
| | 2268 | Compilation.classifyFileExt(test_path.sub_path) == .shared_library) |
| | 2269 | { |
| 2232 | var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) { | 2270 | var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) { |
| 2233 | error.FileNotFound => return .no_match, | 2271 | error.FileNotFound => return .no_match, |
| 2234 | else => |e| fatal("unable to search for {s} library '{'}': {s}", .{ | 2272 | else => |e| fatal("unable to search for {s} library '{'}': {s}", .{ |
| ... | @@ -2354,21 +2392,6 @@ pub fn openDsoInput(diags: *Diags, path: Path, needed: bool, weak: bool, reexpor | ... | @@ -2354,21 +2392,6 @@ pub fn openDsoInput(diags: *Diags, path: Path, needed: bool, weak: bool, reexpor |
| 2354 | } }; | 2392 | } }; |
| 2355 | } | 2393 | } |
| 2356 | | 2394 | |
| 2357 | fn stripLibPrefixAndSuffix(path: []const u8, target: std.Target) ?struct { []const u8, std.builtin.LinkMode } { | | |
| 2358 | const prefix = target.libPrefix(); | | |
| 2359 | const static_suffix = target.staticLibSuffix(); | | |
| 2360 | const dynamic_suffix = target.dynamicLibSuffix(); | | |
| 2361 | const basename = fs.path.basename(path); | | |
| 2362 | const unlibbed = if (mem.startsWith(u8, basename, prefix)) basename[prefix.len..] else return null; | | |
| 2363 | if (mem.endsWith(u8, unlibbed, static_suffix)) return .{ | | |
| 2364 | unlibbed[0 .. unlibbed.len - static_suffix.len], .static, | | |
| 2365 | }; | | |
| 2366 | if (mem.endsWith(u8, unlibbed, dynamic_suffix)) return .{ | | |
| 2367 | unlibbed[0 .. unlibbed.len - dynamic_suffix.len], .dynamic, | | |
| 2368 | }; | | |
| 2369 | return null; | | |
| 2370 | } | | |
| 2371 | | | |
| 2372 | /// Returns true if and only if there is at least one input of type object, | 2395 | /// Returns true if and only if there is at least one input of type object, |
| 2373 | /// archive, or Windows resource file. | 2396 | /// archive, or Windows resource file. |
| 2374 | pub fn anyObjectInputs(inputs: []const Input) bool { | 2397 | pub fn anyObjectInputs(inputs: []const Input) bool { |