| ... | ... | @@ -1600,12 +1600,26 @@ pub const LibExeObjStep = struct { |
| 1600 | 1600 | pub const LinkObject = union(enum) { |
| 1601 | 1601 | static_path: FileSource, |
| 1602 | 1602 | other_step: *LibExeObjStep, |
| 1603 | | system_lib: []const u8, |
| 1603 | system_lib: SystemLib, |
| 1604 | 1604 | assembly_file: FileSource, |
| 1605 | 1605 | c_source_file: *CSourceFile, |
| 1606 | 1606 | c_source_files: *CSourceFiles, |
| 1607 | 1607 | }; |
| 1608 | 1608 | |
| 1609 | pub const SystemLib = struct { |
| 1610 | name: []const u8, |
| 1611 | use_pkg_config: enum { |
| 1612 | /// Don't use pkg-config, just pass -lfoo where foo is name. |
| 1613 | no, |
| 1614 | /// Try to get information on how to link the library from pkg-config. |
| 1615 | /// If that fails, fall back to passing -lfoo where foo is name. |
| 1616 | yes, |
| 1617 | /// Try to get information on how to link the library from pkg-config. |
| 1618 | /// If that fails, error out. |
| 1619 | force, |
| 1620 | }, |
| 1621 | }; |
| 1622 | |
| 1609 | 1623 | pub const IncludeDir = union(enum) { |
| 1610 | 1624 | raw_path: []const u8, |
| 1611 | 1625 | raw_path_system: []const u8, |
| ... | ... | @@ -1854,7 +1868,7 @@ pub const LibExeObjStep = struct { |
| 1854 | 1868 | } |
| 1855 | 1869 | for (self.link_objects.items) |link_object| { |
| 1856 | 1870 | switch (link_object) { |
| 1857 | | .system_lib => |n| if (mem.eql(u8, n, name)) return true, |
| 1871 | .system_lib => |lib| if (mem.eql(u8, lib.name, name)) return true, |
| 1858 | 1872 | else => continue, |
| 1859 | 1873 | } |
| 1860 | 1874 | } |
| ... | ... | @@ -1879,14 +1893,24 @@ pub const LibExeObjStep = struct { |
| 1879 | 1893 | pub fn linkLibC(self: *LibExeObjStep) void { |
| 1880 | 1894 | if (!self.is_linking_libc) { |
| 1881 | 1895 | self.is_linking_libc = true; |
| 1882 | | self.link_objects.append(.{ .system_lib = "c" }) catch unreachable; |
| 1896 | self.link_objects.append(.{ |
| 1897 | .system_lib = .{ |
| 1898 | .name = "c", |
| 1899 | .use_pkg_config = .no, |
| 1900 | }, |
| 1901 | }) catch unreachable; |
| 1883 | 1902 | } |
| 1884 | 1903 | } |
| 1885 | 1904 | |
| 1886 | 1905 | pub fn linkLibCpp(self: *LibExeObjStep) void { |
| 1887 | 1906 | if (!self.is_linking_libcpp) { |
| 1888 | 1907 | self.is_linking_libcpp = true; |
| 1889 | | self.link_objects.append(.{ .system_lib = "c++" }) catch unreachable; |
| 1908 | self.link_objects.append(.{ |
| 1909 | .system_lib = .{ |
| 1910 | .name = "c++", |
| 1911 | .use_pkg_config = .no, |
| 1912 | }, |
| 1913 | }) catch unreachable; |
| 1890 | 1914 | } |
| 1891 | 1915 | } |
| 1892 | 1916 | |
| ... | ... | @@ -1905,12 +1929,28 @@ pub const LibExeObjStep = struct { |
| 1905 | 1929 | /// This one has no integration with anything, it just puts -lname on the command line. |
| 1906 | 1930 | /// Prefer to use `linkSystemLibrary` instead. |
| 1907 | 1931 | pub fn linkSystemLibraryName(self: *LibExeObjStep, name: []const u8) void { |
| 1908 | | self.link_objects.append(.{ .system_lib = self.builder.dupe(name) }) catch unreachable; |
| 1932 | self.link_objects.append(.{ |
| 1933 | .system_lib = .{ |
| 1934 | .name = self.builder.dupe(name), |
| 1935 | .use_pkg_config = .no, |
| 1936 | }, |
| 1937 | }) catch unreachable; |
| 1909 | 1938 | } |
| 1910 | 1939 | |
| 1911 | 1940 | /// This links against a system library, exclusively using pkg-config to find the library. |
| 1912 | 1941 | /// Prefer to use `linkSystemLibrary` instead. |
| 1913 | | pub fn linkSystemLibraryPkgConfigOnly(self: *LibExeObjStep, lib_name: []const u8) !void { |
| 1942 | pub fn linkSystemLibraryPkgConfigOnly(self: *LibExeObjStep, lib_name: []const u8) void { |
| 1943 | self.link_objects.append(.{ |
| 1944 | .system_lib = .{ |
| 1945 | .name = self.builder.dupe(lib_name), |
| 1946 | .use_pkg_config = .force, |
| 1947 | }, |
| 1948 | }) catch unreachable; |
| 1949 | } |
| 1950 | |
| 1951 | /// Run pkg-config for the given library name and parse the output, returning the arguments |
| 1952 | /// that should be passed to zig to link the given library. |
| 1953 | fn runPkgConfig(self: *LibExeObjStep, lib_name: []const u8) ![]const []const u8 { |
| 1914 | 1954 | const pkg_name = match: { |
| 1915 | 1955 | // First we have to map the library name to pkg config name. Unfortunately, |
| 1916 | 1956 | // there are several examples where this is not straightforward: |
| ... | ... | @@ -1970,34 +2010,38 @@ pub const LibExeObjStep = struct { |
| 1970 | 2010 | error.ChildExecFailed => return error.PkgConfigFailed, |
| 1971 | 2011 | else => return err, |
| 1972 | 2012 | }; |
| 2013 | |
| 2014 | var zig_args = std.ArrayList([]const u8).init(self.builder.allocator); |
| 2015 | defer zig_args.deinit(); |
| 2016 | |
| 1973 | 2017 | var it = mem.tokenize(u8, stdout, " \r\n\t"); |
| 1974 | 2018 | while (it.next()) |tok| { |
| 1975 | 2019 | if (mem.eql(u8, tok, "-I")) { |
| 1976 | 2020 | const dir = it.next() orelse return error.PkgConfigInvalidOutput; |
| 1977 | | self.addIncludePath(dir); |
| 2021 | try zig_args.appendSlice(&[_][]const u8{ "-I", dir }); |
| 1978 | 2022 | } else if (mem.startsWith(u8, tok, "-I")) { |
| 1979 | | self.addIncludePath(tok["-I".len..]); |
| 2023 | try zig_args.append(tok); |
| 1980 | 2024 | } else if (mem.eql(u8, tok, "-L")) { |
| 1981 | 2025 | const dir = it.next() orelse return error.PkgConfigInvalidOutput; |
| 1982 | | self.addLibraryPath(dir); |
| 2026 | try zig_args.appendSlice(&[_][]const u8{ "-L", dir }); |
| 1983 | 2027 | } else if (mem.startsWith(u8, tok, "-L")) { |
| 1984 | | self.addLibraryPath(tok["-L".len..]); |
| 2028 | try zig_args.append(tok); |
| 1985 | 2029 | } else if (mem.eql(u8, tok, "-l")) { |
| 1986 | 2030 | const lib = it.next() orelse return error.PkgConfigInvalidOutput; |
| 1987 | | self.linkSystemLibraryName(lib); |
| 2031 | try zig_args.appendSlice(&[_][]const u8{ "-l", lib }); |
| 1988 | 2032 | } else if (mem.startsWith(u8, tok, "-l")) { |
| 1989 | | self.linkSystemLibraryName(tok["-l".len..]); |
| 2033 | try zig_args.append(tok); |
| 1990 | 2034 | } else if (mem.eql(u8, tok, "-D")) { |
| 1991 | 2035 | const macro = it.next() orelse return error.PkgConfigInvalidOutput; |
| 1992 | | self.defineCMacroRaw(macro); |
| 2036 | try zig_args.appendSlice(&[_][]const u8{ "-D", macro }); |
| 1993 | 2037 | } else if (mem.startsWith(u8, tok, "-D")) { |
| 1994 | | self.defineCMacroRaw(tok["-D".len..]); |
| 1995 | | } else if (mem.eql(u8, tok, "-pthread")) { |
| 1996 | | self.linkLibC(); |
| 2038 | try zig_args.append(tok); |
| 1997 | 2039 | } else if (self.builder.verbose) { |
| 1998 | 2040 | warn("Ignoring pkg-config flag '{s}'\n", .{tok}); |
| 1999 | 2041 | } |
| 2000 | 2042 | } |
| 2043 | |
| 2044 | return zig_args.toOwnedSlice(); |
| 2001 | 2045 | } |
| 2002 | 2046 | |
| 2003 | 2047 | pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void { |
| ... | ... | @@ -2009,21 +2053,13 @@ pub const LibExeObjStep = struct { |
| 2009 | 2053 | self.linkLibCpp(); |
| 2010 | 2054 | return; |
| 2011 | 2055 | } |
| 2012 | | if (self.linkSystemLibraryPkgConfigOnly(name)) |_| { |
| 2013 | | // pkg-config worked, so nothing further needed to do. |
| 2014 | | return; |
| 2015 | | } else |err| switch (err) { |
| 2016 | | error.PkgConfigInvalidOutput, |
| 2017 | | error.PkgConfigCrashed, |
| 2018 | | error.PkgConfigFailed, |
| 2019 | | error.PkgConfigNotInstalled, |
| 2020 | | error.PackageNotFound, |
| 2021 | | => {}, |
| 2022 | | |
| 2023 | | else => unreachable, |
| 2024 | | } |
| 2025 | 2056 | |
| 2026 | | self.linkSystemLibraryName(name); |
| 2057 | self.link_objects.append(.{ |
| 2058 | .system_lib = .{ |
| 2059 | .name = self.builder.dupe(name), |
| 2060 | .use_pkg_config = .yes, |
| 2061 | }, |
| 2062 | }) catch unreachable; |
| 2027 | 2063 | } |
| 2028 | 2064 | |
| 2029 | 2065 | pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void { |
| ... | ... | @@ -2317,27 +2353,34 @@ pub const LibExeObjStep = struct { |
| 2317 | 2353 | var prev_has_extra_flags = false; |
| 2318 | 2354 | |
| 2319 | 2355 | // Resolve transitive dependencies |
| 2320 | | for (self.link_objects.items) |link_object| { |
| 2321 | | switch (link_object) { |
| 2322 | | .other_step => |other| { |
| 2323 | | // Inherit dependency on system libraries |
| 2324 | | for (other.link_objects.items) |other_link_object| { |
| 2325 | | switch (other_link_object) { |
| 2326 | | .system_lib => |name| self.linkSystemLibrary(name), |
| 2327 | | else => continue, |
| 2356 | { |
| 2357 | var transitive_dependencies = std.ArrayList(LinkObject).init(builder.allocator); |
| 2358 | defer transitive_dependencies.deinit(); |
| 2359 | |
| 2360 | for (self.link_objects.items) |link_object| { |
| 2361 | switch (link_object) { |
| 2362 | .other_step => |other| { |
| 2363 | // Inherit dependency on system libraries |
| 2364 | for (other.link_objects.items) |other_link_object| { |
| 2365 | switch (other_link_object) { |
| 2366 | .system_lib => try transitive_dependencies.append(other_link_object), |
| 2367 | else => continue, |
| 2368 | } |
| 2328 | 2369 | } |
| 2329 | | } |
| 2330 | 2370 | |
| 2331 | | // Inherit dependencies on darwin frameworks |
| 2332 | | if (!other.isDynamicLibrary()) { |
| 2333 | | var it = other.frameworks.iterator(); |
| 2334 | | while (it.next()) |framework| { |
| 2335 | | self.frameworks.insert(framework.*) catch unreachable; |
| 2371 | // Inherit dependencies on darwin frameworks |
| 2372 | if (!other.isDynamicLibrary()) { |
| 2373 | var it = other.frameworks.iterator(); |
| 2374 | while (it.next()) |framework| { |
| 2375 | self.frameworks.insert(framework.*) catch unreachable; |
| 2376 | } |
| 2336 | 2377 | } |
| 2337 | | } |
| 2338 | | }, |
| 2339 | | else => continue, |
| 2378 | }, |
| 2379 | else => continue, |
| 2380 | } |
| 2340 | 2381 | } |
| 2382 | |
| 2383 | try self.link_objects.appendSlice(transitive_dependencies.items); |
| 2341 | 2384 | } |
| 2342 | 2385 | |
| 2343 | 2386 | for (self.link_objects.items) |link_object| { |
| ... | ... | @@ -2363,8 +2406,35 @@ pub const LibExeObjStep = struct { |
| 2363 | 2406 | } |
| 2364 | 2407 | }, |
| 2365 | 2408 | }, |
| 2366 | | .system_lib => |name| { |
| 2367 | | try zig_args.append(builder.fmt("-l{s}", .{name})); |
| 2409 | |
| 2410 | .system_lib => |system_lib| { |
| 2411 | switch (system_lib.use_pkg_config) { |
| 2412 | .no => try zig_args.append(builder.fmt("-l{s}", .{system_lib.name})), |
| 2413 | .yes, .force => { |
| 2414 | if (self.runPkgConfig(system_lib.name)) |args| { |
| 2415 | try zig_args.appendSlice(args); |
| 2416 | } else |err| switch (err) { |
| 2417 | error.PkgConfigInvalidOutput, |
| 2418 | error.PkgConfigCrashed, |
| 2419 | error.PkgConfigFailed, |
| 2420 | error.PkgConfigNotInstalled, |
| 2421 | error.PackageNotFound, |
| 2422 | => switch (system_lib.use_pkg_config) { |
| 2423 | .yes => { |
| 2424 | // pkg-config failed, so fall back to linking the library |
| 2425 | // by name directly. |
| 2426 | try zig_args.append(builder.fmt("-l{s}", .{system_lib.name})); |
| 2427 | }, |
| 2428 | .force => { |
| 2429 | panic("pkg-config failed for library {s}", .{system_lib.name}); |
| 2430 | }, |
| 2431 | .no => unreachable, |
| 2432 | }, |
| 2433 | |
| 2434 | else => |e| return e, |
| 2435 | } |
| 2436 | }, |
| 2437 | } |
| 2368 | 2438 | }, |
| 2369 | 2439 | |
| 2370 | 2440 | .assembly_file => |asm_file| { |