| ... | @@ -1891,144 +1891,184 @@ pub fn resolveInputs( | ... | @@ -1891,144 +1891,184 @@ pub fn resolveInputs( |
| 1891 | mem.reverse(UnresolvedInput, unresolved_inputs.items); | 1891 | mem.reverse(UnresolvedInput, unresolved_inputs.items); |
| 1892 | | 1892 | |
| 1893 | syslib: while (unresolved_inputs.pop()) |unresolved_input| { | 1893 | syslib: while (unresolved_inputs.pop()) |unresolved_input| { |
| 1894 | const name_query: UnresolvedInput.NameQuery = switch (unresolved_input) { | 1894 | switch (unresolved_input) { |
| 1895 | .name_query => |nq| nq, | 1895 | .name_query => |name_query| { |
| 1896 | .ambiguous_name => |an| an: { | 1896 | const query = name_query.query; |
| 1897 | const lib_name, const link_mode = stripLibPrefixAndSuffix(an.name, target) orelse { | 1897 | |
| 1898 | try resolvePathInput(gpa, arena, unresolved_inputs, resolved_inputs, &ld_script_bytes, target, .{ | 1898 | // Checked in the first pass above while looking for libc libraries. |
| 1899 | .path = Path.initCwd(an.name), | 1899 | assert(!fs.path.isAbsolute(name_query.name)); |
| 1900 | .query = an.query, | 1900 | |
| 1901 | }, color); | 1901 | checked_paths.clearRetainingCapacity(); |
| 1902 | continue; | 1902 | |
| 1903 | }; | 1903 | switch (query.search_strategy) { |
| 1904 | break :an .{ | 1904 | .mode_first, .no_fallback => { |
| 1905 | .name = lib_name, | 1905 | // check for preferred mode |
| 1906 | .query = .{ | 1906 | for (lib_directories) |lib_directory| switch (try resolveLibInput( |
| 1907 | .needed = an.query.needed, | 1907 | gpa, |
| 1908 | .weak = an.query.weak, | 1908 | arena, |
| 1909 | .reexport = an.query.reexport, | 1909 | unresolved_inputs, |
| 1910 | .must_link = an.query.must_link, | 1910 | resolved_inputs, |
| 1911 | .hidden = an.query.hidden, | 1911 | &checked_paths, |
| 1912 | .allow_so_scripts = an.query.allow_so_scripts, | 1912 | &ld_script_bytes, |
| 1913 | .preferred_mode = link_mode, | 1913 | lib_directory, |
| 1914 | .search_strategy = .no_fallback, | 1914 | name_query, |
| | 1915 | target, |
| | 1916 | query.preferred_mode, |
| | 1917 | color, |
| | 1918 | )) { |
| | 1919 | .ok => continue :syslib, |
| | 1920 | .no_match => {}, |
| | 1921 | }; |
| | 1922 | // check for fallback mode |
| | 1923 | if (query.search_strategy == .no_fallback) { |
| | 1924 | try failed_libs.append(arena, .{ |
| | 1925 | .name = name_query.name, |
| | 1926 | .strategy = query.search_strategy, |
| | 1927 | .checked_paths = try arena.dupe(u8, checked_paths.items), |
| | 1928 | .preferred_mode = query.preferred_mode, |
| | 1929 | }); |
| | 1930 | continue :syslib; |
| | 1931 | } |
| | 1932 | for (lib_directories) |lib_directory| switch (try resolveLibInput( |
| | 1933 | gpa, |
| | 1934 | arena, |
| | 1935 | unresolved_inputs, |
| | 1936 | resolved_inputs, |
| | 1937 | &checked_paths, |
| | 1938 | &ld_script_bytes, |
| | 1939 | lib_directory, |
| | 1940 | name_query, |
| | 1941 | target, |
| | 1942 | query.fallbackMode(), |
| | 1943 | color, |
| | 1944 | )) { |
| | 1945 | .ok => continue :syslib, |
| | 1946 | .no_match => {}, |
| | 1947 | }; |
| | 1948 | try failed_libs.append(arena, .{ |
| | 1949 | .name = name_query.name, |
| | 1950 | .strategy = query.search_strategy, |
| | 1951 | .checked_paths = try arena.dupe(u8, checked_paths.items), |
| | 1952 | .preferred_mode = query.preferred_mode, |
| | 1953 | }); |
| | 1954 | continue :syslib; |
| 1915 | }, | 1955 | }, |
| 1916 | }; | 1956 | .paths_first => { |
| 1917 | }, | 1957 | for (lib_directories) |lib_directory| { |
| 1918 | .path_query => |pq| { | 1958 | // check for preferred mode |
| 1919 | try resolvePathInput(gpa, arena, unresolved_inputs, resolved_inputs, &ld_script_bytes, target, pq, color); | 1959 | switch (try resolveLibInput( |
| 1920 | continue; | 1960 | gpa, |
| 1921 | }, | 1961 | arena, |
| 1922 | .dso_exact => |dso_exact| { | 1962 | unresolved_inputs, |
| 1923 | try resolved_inputs.append(gpa, .{ .dso_exact = dso_exact }); | 1963 | resolved_inputs, |
| 1924 | continue; | 1964 | &checked_paths, |
| 1925 | }, | 1965 | &ld_script_bytes, |
| 1926 | }; | 1966 | lib_directory, |
| 1927 | const query = name_query.query; | 1967 | name_query, |
| 1928 | | 1968 | target, |
| 1929 | // Checked in the first pass above while looking for libc libraries. | 1969 | query.preferred_mode, |
| 1930 | assert(!fs.path.isAbsolute(name_query.name)); | 1970 | color, |
| 1931 | | 1971 | )) { |
| 1932 | checked_paths.clearRetainingCapacity(); | 1972 | .ok => continue :syslib, |
| | 1973 | .no_match => {}, |
| | 1974 | } |
| 1933 | | 1975 | |
| 1934 | switch (query.search_strategy) { | 1976 | // check for fallback mode |
| 1935 | .mode_first, .no_fallback => { | 1977 | switch (try resolveLibInput( |
| 1936 | // check for preferred mode | 1978 | gpa, |
| 1937 | for (lib_directories) |lib_directory| switch (try resolveLibInput( | 1979 | arena, |
| | 1980 | unresolved_inputs, |
| | 1981 | resolved_inputs, |
| | 1982 | &checked_paths, |
| | 1983 | &ld_script_bytes, |
| | 1984 | lib_directory, |
| | 1985 | name_query, |
| | 1986 | target, |
| | 1987 | query.fallbackMode(), |
| | 1988 | color, |
| | 1989 | )) { |
| | 1990 | .ok => continue :syslib, |
| | 1991 | .no_match => {}, |
| | 1992 | } |
| | 1993 | } |
| | 1994 | try failed_libs.append(arena, .{ |
| | 1995 | .name = name_query.name, |
| | 1996 | .strategy = query.search_strategy, |
| | 1997 | .checked_paths = try arena.dupe(u8, checked_paths.items), |
| | 1998 | .preferred_mode = query.preferred_mode, |
| | 1999 | }); |
| | 2000 | continue :syslib; |
| | 2001 | }, |
| | 2002 | } |
| | 2003 | }, |
| | 2004 | .ambiguous_name => |an| { |
| | 2005 | // First check the path relative to the current working directory. |
| | 2006 | // If the file is a library and is not found there, check the library search paths as well. |
| | 2007 | // This is consistent with the behavior of GNU ld. |
| | 2008 | if (try resolvePathInput( |
| 1938 | gpa, | 2009 | gpa, |
| 1939 | arena, | 2010 | arena, |
| 1940 | unresolved_inputs, | 2011 | unresolved_inputs, |
| 1941 | resolved_inputs, | 2012 | resolved_inputs, |
| 1942 | &checked_paths, | | |
| 1943 | &ld_script_bytes, | 2013 | &ld_script_bytes, |
| 1944 | lib_directory, | | |
| 1945 | name_query, | | |
| 1946 | target, | 2014 | target, |
| 1947 | query.preferred_mode, | 2015 | .{ |
| | 2016 | .path = Path.initCwd(an.name), |
| | 2017 | .query = an.query, |
| | 2018 | }, |
| 1948 | color, | 2019 | color, |
| 1949 | )) { | 2020 | )) |lib_result| { |
| 1950 | .ok => continue :syslib, | 2021 | switch (lib_result) { |
| 1951 | .no_match => {}, | 2022 | .ok => continue :syslib, |
| 1952 | }; | 2023 | .no_match => { |
| 1953 | // check for fallback mode | 2024 | for (lib_directories) |lib_directory| { |
| 1954 | if (query.search_strategy == .no_fallback) { | 2025 | switch ((try resolvePathInput( |
| 1955 | try failed_libs.append(arena, .{ | 2026 | gpa, |
| 1956 | .name = name_query.name, | 2027 | arena, |
| 1957 | .strategy = query.search_strategy, | 2028 | unresolved_inputs, |
| 1958 | .checked_paths = try arena.dupe(u8, checked_paths.items), | 2029 | resolved_inputs, |
| 1959 | .preferred_mode = query.preferred_mode, | 2030 | &ld_script_bytes, |
| 1960 | }); | 2031 | target, |
| 1961 | continue :syslib; | 2032 | .{ |
| | 2033 | .path = .{ |
| | 2034 | .root_dir = lib_directory, |
| | 2035 | .sub_path = an.name, |
| | 2036 | }, |
| | 2037 | .query = an.query, |
| | 2038 | }, |
| | 2039 | color, |
| | 2040 | )).?) { |
| | 2041 | .ok => continue :syslib, |
| | 2042 | .no_match => {}, |
| | 2043 | } |
| | 2044 | } |
| | 2045 | fatal("{s}: file listed in linker script not found", .{an.name}); |
| | 2046 | }, |
| | 2047 | } |
| 1962 | } | 2048 | } |
| 1963 | for (lib_directories) |lib_directory| switch (try resolveLibInput( | 2049 | continue; |
| | 2050 | }, |
| | 2051 | .path_query => |pq| { |
| | 2052 | if (try resolvePathInput( |
| 1964 | gpa, | 2053 | gpa, |
| 1965 | arena, | 2054 | arena, |
| 1966 | unresolved_inputs, | 2055 | unresolved_inputs, |
| 1967 | resolved_inputs, | 2056 | resolved_inputs, |
| 1968 | &checked_paths, | | |
| 1969 | &ld_script_bytes, | 2057 | &ld_script_bytes, |
| 1970 | lib_directory, | | |
| 1971 | name_query, | | |
| 1972 | target, | 2058 | target, |
| 1973 | query.fallbackMode(), | 2059 | pq, |
| 1974 | color, | 2060 | color, |
| 1975 | )) { | 2061 | )) |lib_result| { |
| 1976 | .ok => continue :syslib, | 2062 | switch (lib_result) { |
| 1977 | .no_match => {}, | 2063 | .ok => {}, |
| 1978 | }; | 2064 | .no_match => fatal("{}: file not found", .{pq.path}), |
| 1979 | try failed_libs.append(arena, .{ | | |
| 1980 | .name = name_query.name, | | |
| 1981 | .strategy = query.search_strategy, | | |
| 1982 | .checked_paths = try arena.dupe(u8, checked_paths.items), | | |
| 1983 | .preferred_mode = query.preferred_mode, | | |
| 1984 | }); | | |
| 1985 | continue :syslib; | | |
| 1986 | }, | | |
| 1987 | .paths_first => { | | |
| 1988 | for (lib_directories) |lib_directory| { | | |
| 1989 | // check for preferred mode | | |
| 1990 | switch (try resolveLibInput( | | |
| 1991 | gpa, | | |
| 1992 | arena, | | |
| 1993 | unresolved_inputs, | | |
| 1994 | resolved_inputs, | | |
| 1995 | &checked_paths, | | |
| 1996 | &ld_script_bytes, | | |
| 1997 | lib_directory, | | |
| 1998 | name_query, | | |
| 1999 | target, | | |
| 2000 | query.preferred_mode, | | |
| 2001 | color, | | |
| 2002 | )) { | | |
| 2003 | .ok => continue :syslib, | | |
| 2004 | .no_match => {}, | | |
| 2005 | } | | |
| 2006 | | | |
| 2007 | // check for fallback mode | | |
| 2008 | switch (try resolveLibInput( | | |
| 2009 | gpa, | | |
| 2010 | arena, | | |
| 2011 | unresolved_inputs, | | |
| 2012 | resolved_inputs, | | |
| 2013 | &checked_paths, | | |
| 2014 | &ld_script_bytes, | | |
| 2015 | lib_directory, | | |
| 2016 | name_query, | | |
| 2017 | target, | | |
| 2018 | query.fallbackMode(), | | |
| 2019 | color, | | |
| 2020 | )) { | | |
| 2021 | .ok => continue :syslib, | | |
| 2022 | .no_match => {}, | | |
| 2023 | } | 2065 | } |
| 2024 | } | 2066 | } |
| 2025 | try failed_libs.append(arena, .{ | 2067 | continue; |
| 2026 | .name = name_query.name, | 2068 | }, |
| 2027 | .strategy = query.search_strategy, | 2069 | .dso_exact => |dso_exact| { |
| 2028 | .checked_paths = try arena.dupe(u8, checked_paths.items), | 2070 | try resolved_inputs.append(gpa, .{ .dso_exact = dso_exact }); |
| 2029 | .preferred_mode = query.preferred_mode, | 2071 | continue; |
| 2030 | }); | | |
| 2031 | continue :syslib; | | |
| 2032 | }, | 2072 | }, |
| 2033 | } | 2073 | } |
| 2034 | @compileError("unreachable"); | 2074 | @compileError("unreachable"); |
| ... | @@ -2178,10 +2218,10 @@ fn resolvePathInput( | ... | @@ -2178,10 +2218,10 @@ fn resolvePathInput( |
| 2178 | target: std.Target, | 2218 | target: std.Target, |
| 2179 | pq: UnresolvedInput.PathQuery, | 2219 | pq: UnresolvedInput.PathQuery, |
| 2180 | color: std.zig.Color, | 2220 | color: std.zig.Color, |
| 2181 | ) Allocator.Error!void { | 2221 | ) Allocator.Error!?ResolveLibInputResult { |
| 2182 | switch (switch (Compilation.classifyFileExt(pq.path.sub_path)) { | 2222 | switch (Compilation.classifyFileExt(pq.path.sub_path)) { |
| 2183 | .static_library => try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .static, color), | 2223 | .static_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .static, color), |
| 2184 | .shared_library => try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .dynamic, color), | 2224 | .shared_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .dynamic, color), |
| 2185 | .object => { | 2225 | .object => { |
| 2186 | var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err| | 2226 | var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err| |
| 2187 | fatal("failed to open object {}: {s}", .{ pq.path, @errorName(err) }); | 2227 | fatal("failed to open object {}: {s}", .{ pq.path, @errorName(err) }); |
| ... | @@ -2192,7 +2232,7 @@ fn resolvePathInput( | ... | @@ -2192,7 +2232,7 @@ fn resolvePathInput( |
| 2192 | .must_link = pq.query.must_link, | 2232 | .must_link = pq.query.must_link, |
| 2193 | .hidden = pq.query.hidden, | 2233 | .hidden = pq.query.hidden, |
| 2194 | } }); | 2234 | } }); |
| 2195 | return; | 2235 | return null; |
| 2196 | }, | 2236 | }, |
| 2197 | .res => { | 2237 | .res => { |
| 2198 | var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err| | 2238 | var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err| |
| ... | @@ -2202,12 +2242,9 @@ fn resolvePathInput( | ... | @@ -2202,12 +2242,9 @@ fn resolvePathInput( |
| 2202 | .path = pq.path, | 2242 | .path = pq.path, |
| 2203 | .file = file, | 2243 | .file = file, |
| 2204 | } }); | 2244 | } }); |
| 2205 | return; | 2245 | return null; |
| 2206 | }, | 2246 | }, |
| 2207 | else => fatal("{}: unrecognized file extension", .{pq.path}), | 2247 | else => fatal("{}: unrecognized file extension", .{pq.path}), |
| 2208 | }) { | | |
| 2209 | .ok => {}, | | |
| 2210 | .no_match => fatal("{}: file not found", .{pq.path}), | | |
| 2211 | } | 2248 | } |
| 2212 | } | 2249 | } |
| 2213 | | 2250 | |
| ... | @@ -2228,9 +2265,11 @@ fn resolvePathInputLib( | ... | @@ -2228,9 +2265,11 @@ fn resolvePathInputLib( |
| 2228 | try resolved_inputs.ensureUnusedCapacity(gpa, 1); | 2265 | try resolved_inputs.ensureUnusedCapacity(gpa, 1); |
| 2229 | | 2266 | |
| 2230 | const test_path: Path = pq.path; | 2267 | const test_path: Path = pq.path; |
| 2231 | // In the case of .so files, they might actually be "linker scripts" | 2268 | // In the case of shared libraries, they might actually be "linker scripts" |
| 2232 | // that contain references to other libraries. | 2269 | // that contain references to other libraries. |
| 2233 | if (pq.query.allow_so_scripts and target.ofmt == .elf and mem.endsWith(u8, test_path.sub_path, ".so")) { | 2270 | if (pq.query.allow_so_scripts and target.ofmt == .elf and |
| | 2271 | Compilation.classifyFileExt(test_path.sub_path) == .shared_library) |
| | 2272 | { |
| 2234 | var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) { | 2273 | var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) { |
| 2235 | error.FileNotFound => return .no_match, | 2274 | error.FileNotFound => return .no_match, |
| 2236 | else => |e| fatal("unable to search for {s} library '{'}': {s}", .{ | 2275 | else => |e| fatal("unable to search for {s} library '{'}': {s}", .{ |
| ... | @@ -2356,21 +2395,6 @@ pub fn openDsoInput(diags: *Diags, path: Path, needed: bool, weak: bool, reexpor | ... | @@ -2356,21 +2395,6 @@ pub fn openDsoInput(diags: *Diags, path: Path, needed: bool, weak: bool, reexpor |
| 2356 | } }; | 2395 | } }; |
| 2357 | } | 2396 | } |
| 2358 | | 2397 | |
| 2359 | fn stripLibPrefixAndSuffix(path: []const u8, target: std.Target) ?struct { []const u8, std.builtin.LinkMode } { | | |
| 2360 | const prefix = target.libPrefix(); | | |
| 2361 | const static_suffix = target.staticLibSuffix(); | | |
| 2362 | const dynamic_suffix = target.dynamicLibSuffix(); | | |
| 2363 | const basename = fs.path.basename(path); | | |
| 2364 | const unlibbed = if (mem.startsWith(u8, basename, prefix)) basename[prefix.len..] else return null; | | |
| 2365 | if (mem.endsWith(u8, unlibbed, static_suffix)) return .{ | | |
| 2366 | unlibbed[0 .. unlibbed.len - static_suffix.len], .static, | | |
| 2367 | }; | | |
| 2368 | if (mem.endsWith(u8, unlibbed, dynamic_suffix)) return .{ | | |
| 2369 | unlibbed[0 .. unlibbed.len - dynamic_suffix.len], .dynamic, | | |
| 2370 | }; | | |
| 2371 | return null; | | |
| 2372 | } | | |
| 2373 | | | |
| 2374 | /// Returns true if and only if there is at least one input of type object, | 2398 | /// Returns true if and only if there is at least one input of type object, |
| 2375 | /// archive, or Windows resource file. | 2399 | /// archive, or Windows resource file. |
| 2376 | pub fn anyObjectInputs(inputs: []const Input) bool { | 2400 | pub fn anyObjectInputs(inputs: []const Input) bool { |