| ... | @@ -1600,12 +1600,26 @@ pub const LibExeObjStep = struct { | ... | @@ -1600,12 +1600,26 @@ pub const LibExeObjStep = struct { |
| 1600 | pub const LinkObject = union(enum) { | 1600 | pub const LinkObject = union(enum) { |
| 1601 | static_path: FileSource, | 1601 | static_path: FileSource, |
| 1602 | other_step: *LibExeObjStep, | 1602 | other_step: *LibExeObjStep, |
| 1603 | system_lib: []const u8, | 1603 | system_lib: SystemLib, |
| 1604 | assembly_file: FileSource, | 1604 | assembly_file: FileSource, |
| 1605 | c_source_file: *CSourceFile, | 1605 | c_source_file: *CSourceFile, |
| 1606 | c_source_files: *CSourceFiles, | 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 | pub const IncludeDir = union(enum) { | 1623 | pub const IncludeDir = union(enum) { |
| 1610 | raw_path: []const u8, | 1624 | raw_path: []const u8, |
| 1611 | raw_path_system: []const u8, | 1625 | raw_path_system: []const u8, |
| ... | @@ -1854,7 +1868,7 @@ pub const LibExeObjStep = struct { | ... | @@ -1854,7 +1868,7 @@ pub const LibExeObjStep = struct { |
| 1854 | } | 1868 | } |
| 1855 | for (self.link_objects.items) |link_object| { | 1869 | for (self.link_objects.items) |link_object| { |
| 1856 | switch (link_object) { | 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 | else => continue, | 1872 | else => continue, |
| 1859 | } | 1873 | } |
| 1860 | } | 1874 | } |
| ... | @@ -1879,14 +1893,24 @@ pub const LibExeObjStep = struct { | ... | @@ -1879,14 +1893,24 @@ pub const LibExeObjStep = struct { |
| 1879 | pub fn linkLibC(self: *LibExeObjStep) void { | 1893 | pub fn linkLibC(self: *LibExeObjStep) void { |
| 1880 | if (!self.is_linking_libc) { | 1894 | if (!self.is_linking_libc) { |
| 1881 | self.is_linking_libc = true; | 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 | pub fn linkLibCpp(self: *LibExeObjStep) void { | 1905 | pub fn linkLibCpp(self: *LibExeObjStep) void { |
| 1887 | if (!self.is_linking_libcpp) { | 1906 | if (!self.is_linking_libcpp) { |
| 1888 | self.is_linking_libcpp = true; | 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,12 +1929,28 @@ pub const LibExeObjStep = struct { |
| 1905 | /// This one has no integration with anything, it just puts -lname on the command line. | 1929 | /// This one has no integration with anything, it just puts -lname on the command line. |
| 1906 | /// Prefer to use `linkSystemLibrary` instead. | 1930 | /// Prefer to use `linkSystemLibrary` instead. |
| 1907 | pub fn linkSystemLibraryName(self: *LibExeObjStep, name: []const u8) void { | 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 | /// This links against a system library, exclusively using pkg-config to find the library. | 1940 | /// This links against a system library, exclusively using pkg-config to find the library. |
| 1912 | /// Prefer to use `linkSystemLibrary` instead. | 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 | const pkg_name = match: { | 1954 | const pkg_name = match: { |
| 1915 | // First we have to map the library name to pkg config name. Unfortunately, | 1955 | // First we have to map the library name to pkg config name. Unfortunately, |
| 1916 | // there are several examples where this is not straightforward: | 1956 | // there are several examples where this is not straightforward: |
| ... | @@ -1970,34 +2010,38 @@ pub const LibExeObjStep = struct { | ... | @@ -1970,34 +2010,38 @@ pub const LibExeObjStep = struct { |
| 1970 | error.ChildExecFailed => return error.PkgConfigFailed, | 2010 | error.ChildExecFailed => return error.PkgConfigFailed, |
| 1971 | else => return err, | 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 | var it = mem.tokenize(u8, stdout, " \r\n\t"); | 2017 | var it = mem.tokenize(u8, stdout, " \r\n\t"); |
| 1974 | while (it.next()) |tok| { | 2018 | while (it.next()) |tok| { |
| 1975 | if (mem.eql(u8, tok, "-I")) { | 2019 | if (mem.eql(u8, tok, "-I")) { |
| 1976 | const dir = it.next() orelse return error.PkgConfigInvalidOutput; | 2020 | const dir = it.next() orelse return error.PkgConfigInvalidOutput; |
| 1977 | self.addIncludePath(dir); | 2021 | try zig_args.appendSlice(&[_][]const u8{ "-I", dir }); |
| 1978 | } else if (mem.startsWith(u8, tok, "-I")) { | 2022 | } else if (mem.startsWith(u8, tok, "-I")) { |
| 1979 | self.addIncludePath(tok["-I".len..]); | 2023 | try zig_args.append(tok); |
| 1980 | } else if (mem.eql(u8, tok, "-L")) { | 2024 | } else if (mem.eql(u8, tok, "-L")) { |
| 1981 | const dir = it.next() orelse return error.PkgConfigInvalidOutput; | 2025 | const dir = it.next() orelse return error.PkgConfigInvalidOutput; |
| 1982 | self.addLibraryPath(dir); | 2026 | try zig_args.appendSlice(&[_][]const u8{ "-L", dir }); |
| 1983 | } else if (mem.startsWith(u8, tok, "-L")) { | 2027 | } else if (mem.startsWith(u8, tok, "-L")) { |
| 1984 | self.addLibraryPath(tok["-L".len..]); | 2028 | try zig_args.append(tok); |
| 1985 | } else if (mem.eql(u8, tok, "-l")) { | 2029 | } else if (mem.eql(u8, tok, "-l")) { |
| 1986 | const lib = it.next() orelse return error.PkgConfigInvalidOutput; | 2030 | const lib = it.next() orelse return error.PkgConfigInvalidOutput; |
| 1987 | self.linkSystemLibraryName(lib); | 2031 | try zig_args.appendSlice(&[_][]const u8{ "-l", lib }); |
| 1988 | } else if (mem.startsWith(u8, tok, "-l")) { | 2032 | } else if (mem.startsWith(u8, tok, "-l")) { |
| 1989 | self.linkSystemLibraryName(tok["-l".len..]); | 2033 | try zig_args.append(tok); |
| 1990 | } else if (mem.eql(u8, tok, "-D")) { | 2034 | } else if (mem.eql(u8, tok, "-D")) { |
| 1991 | const macro = it.next() orelse return error.PkgConfigInvalidOutput; | 2035 | const macro = it.next() orelse return error.PkgConfigInvalidOutput; |
| 1992 | self.defineCMacroRaw(macro); | 2036 | try zig_args.appendSlice(&[_][]const u8{ "-D", macro }); |
| 1993 | } else if (mem.startsWith(u8, tok, "-D")) { | 2037 | } else if (mem.startsWith(u8, tok, "-D")) { |
| 1994 | self.defineCMacroRaw(tok["-D".len..]); | 2038 | try zig_args.append(tok); |
| 1995 | } else if (mem.eql(u8, tok, "-pthread")) { | | |
| 1996 | self.linkLibC(); | | |
| 1997 | } else if (self.builder.verbose) { | 2039 | } else if (self.builder.verbose) { |
| 1998 | warn("Ignoring pkg-config flag '{s}'\n", .{tok}); | 2040 | warn("Ignoring pkg-config flag '{s}'\n", .{tok}); |
| 1999 | } | 2041 | } |
| 2000 | } | 2042 | } |
| | 2043 | |
| | 2044 | return zig_args.toOwnedSlice(); |
| 2001 | } | 2045 | } |
| 2002 | | 2046 | |
| 2003 | pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void { | 2047 | pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void { |
| ... | @@ -2009,21 +2053,13 @@ pub const LibExeObjStep = struct { | ... | @@ -2009,21 +2053,13 @@ pub const LibExeObjStep = struct { |
| 2009 | self.linkLibCpp(); | 2053 | self.linkLibCpp(); |
| 2010 | return; | 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 | pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void { | 2065 | pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void { |
| ... | @@ -2317,27 +2353,34 @@ pub const LibExeObjStep = struct { | ... | @@ -2317,27 +2353,34 @@ pub const LibExeObjStep = struct { |
| 2317 | var prev_has_extra_flags = false; | 2353 | var prev_has_extra_flags = false; |
| 2318 | | 2354 | |
| 2319 | // Resolve transitive dependencies | 2355 | // Resolve transitive dependencies |
| 2320 | for (self.link_objects.items) |link_object| { | 2356 | { |
| 2321 | switch (link_object) { | 2357 | var transitive_dependencies = std.ArrayList(LinkObject).init(builder.allocator); |
| 2322 | .other_step => |other| { | 2358 | defer transitive_dependencies.deinit(); |
| 2323 | // Inherit dependency on system libraries | 2359 | |
| 2324 | for (other.link_objects.items) |other_link_object| { | 2360 | for (self.link_objects.items) |link_object| { |
| 2325 | switch (other_link_object) { | 2361 | switch (link_object) { |
| 2326 | .system_lib => |name| self.linkSystemLibrary(name), | 2362 | .other_step => |other| { |
| 2327 | else => continue, | 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 | 2371 | // Inherit dependencies on darwin frameworks |
| 2332 | if (!other.isDynamicLibrary()) { | 2372 | if (!other.isDynamicLibrary()) { |
| 2333 | var it = other.frameworks.iterator(); | 2373 | var it = other.frameworks.iterator(); |
| 2334 | while (it.next()) |framework| { | 2374 | while (it.next()) |framework| { |
| 2335 | self.frameworks.insert(framework.*) catch unreachable; | 2375 | self.frameworks.insert(framework.*) catch unreachable; |
| | 2376 | } |
| 2336 | } | 2377 | } |
| 2337 | } | 2378 | }, |
| 2338 | }, | 2379 | else => continue, |
| 2339 | else => continue, | 2380 | } |
| 2340 | } | 2381 | } |
| | 2382 | |
| | 2383 | try self.link_objects.appendSlice(transitive_dependencies.items); |
| 2341 | } | 2384 | } |
| 2342 | | 2385 | |
| 2343 | for (self.link_objects.items) |link_object| { | 2386 | for (self.link_objects.items) |link_object| { |
| ... | @@ -2363,8 +2406,35 @@ pub const LibExeObjStep = struct { | ... | @@ -2363,8 +2406,35 @@ pub const LibExeObjStep = struct { |
| 2363 | } | 2406 | } |
| 2364 | }, | 2407 | }, |
| 2365 | }, | 2408 | }, |
| 2366 | .system_lib => |name| { | 2409 | |
| 2367 | try zig_args.append(builder.fmt("-l{s}", .{name})); | 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 | .assembly_file => |asm_file| { | 2440 | .assembly_file => |asm_file| { |