| ... | ... | @@ -14,6 +14,7 @@ const allocPrint = std.fmt.allocPrint; |
| 14 | 14 | |
| 15 | 15 | const Step = @import("../Step.zig"); |
| 16 | 16 | const Maker = @import("../../Maker.zig"); |
| 17 | const PkgConfig = @import("../PkgConfig.zig"); |
| 17 | 18 | |
| 18 | 19 | /// Populated when there is compiler process that lives across multiple calls |
| 19 | 20 | /// to `make`. |
| ... | ... | @@ -40,7 +41,7 @@ pub fn make( |
| 40 | 41 | // Reset / repopulate persistent state. |
| 41 | 42 | compile.zig_args.clearRetainingCapacity(); |
| 42 | 43 | |
| 43 | | try lowerZigArgs(compile, compile_index, maker, &compile.zig_args, false); |
| 44 | try lowerZigArgs(compile, compile_index, maker, progress_node, &compile.zig_args, false); |
| 44 | 45 | |
| 45 | 46 | const maybe_output_dir = Step.evalZigProcess( |
| 46 | 47 | compile_index, |
| ... | ... | @@ -148,10 +149,11 @@ const ModuleListContext = struct { |
| 148 | 149 | fn lowerZigArgs( |
| 149 | 150 | compile: *Compile, |
| 150 | 151 | compile_index: Configuration.Step.Index, |
| 151 | | maker: *const Maker, |
| 152 | maker: *Maker, |
| 153 | progress_node: std.Progress.Node, |
| 152 | 154 | zig_args: *std.ArrayList([]const u8), |
| 153 | 155 | fuzz: bool, |
| 154 | | ) error{ OutOfMemory, MakeFailed }!void { |
| 156 | ) Step.ExtendedMakeError!void { |
| 155 | 157 | const step = maker.stepByIndex(compile_index); |
| 156 | 158 | const graph = maker.graph; |
| 157 | 159 | const arena = graph.arena; // TODO don't leak into the process arena |
| ... | ... | @@ -312,40 +314,36 @@ fn lowerZigArgs( |
| 312 | 314 | if (system_lib.flags.weak) break :prefix "-weak-l"; |
| 313 | 315 | break :prefix "-l"; |
| 314 | 316 | }; |
| 315 | | switch (system_lib.flags.use_pkg_config) { |
| 316 | | .no => try zig_args.append(gpa, try allocPrint(arena, "{s}{s}", .{ |
| 317 | | prefix, system_lib_name, |
| 318 | | })), |
| 319 | | .yes, .force => { |
| 320 | | if (compile.runPkgConfig(maker, system_lib_name)) |result| { |
| 317 | l: { |
| 318 | pc: { |
| 319 | const force = switch (system_lib.flags.use_pkg_config) { |
| 320 | .no => break :pc, |
| 321 | .yes => false, |
| 322 | .force => true, |
| 323 | }; |
| 324 | |
| 325 | const pkg_conf_node = progress_node.start("pkg-config", 0); |
| 326 | defer pkg_conf_node.end(); |
| 327 | |
| 328 | if (PkgConfig.run(maker, step, pkg_conf_node, system_lib_name, force)) |result| { |
| 321 | 329 | try zig_args.appendSlice(gpa, result.cflags); |
| 322 | 330 | try zig_args.appendSlice(gpa, result.libs); |
| 323 | 331 | try seen_system_libs.put(arena, system_lib.name, result.cflags); |
| 332 | break :l; |
| 324 | 333 | } else |err| switch (err) { |
| 325 | | error.PkgConfigInvalidOutput, |
| 326 | | error.PkgConfigCrashed, |
| 327 | | error.PkgConfigFailed, |
| 328 | | error.PkgConfigNotInstalled, |
| 334 | error.PkgConfigUnavailable, |
| 329 | 335 | error.PackageNotFound, |
| 330 | | => switch (system_lib.flags.use_pkg_config) { |
| 331 | | .yes => { |
| 332 | | // pkg-config failed, so fall back to linking the library |
| 333 | | // by name directly. |
| 334 | | try zig_args.append(gpa, try allocPrint(arena, "{s}{s}", .{ |
| 335 | | prefix, system_lib_name, |
| 336 | | })); |
| 337 | | }, |
| 338 | | .force => { |
| 339 | | return step.fail(maker, "pkg-config failed for library {s}", .{ |
| 340 | | system_lib_name, |
| 341 | | }); |
| 342 | | }, |
| 343 | | .no => unreachable, |
| 336 | => { |
| 337 | // pkg-config failed, so fall back to linking the library by name directly. |
| 338 | assert(!force); |
| 339 | break :pc; |
| 344 | 340 | }, |
| 345 | | |
| 346 | 341 | else => |e| return e, |
| 347 | 342 | } |
| 348 | | }, |
| 343 | } |
| 344 | try zig_args.append(gpa, try allocPrint(arena, "{s}{s}", .{ |
| 345 | prefix, system_lib_name, |
| 346 | })); |
| 349 | 347 | } |
| 350 | 348 | }, |
| 351 | 349 | .other_step => |other_step_index| { |
| ... | ... | @@ -961,65 +959,11 @@ pub fn rebuildInFuzzMode(compile: *Compile, maker: *Maker, progress_node: std.Pr |
| 961 | 959 | |
| 962 | 960 | const zig_args = &compile.zig_args; |
| 963 | 961 | zig_args.clearRetainingCapacity(); |
| 964 | | try lowerZigArgs(compile, maker, zig_args, true); |
| 962 | try lowerZigArgs(compile, maker, progress_node, zig_args, true); |
| 965 | 963 | const maybe_output_bin_path = try compile.step.evalZigProcess(zig_args.items, progress_node, false, maker); |
| 966 | 964 | return maybe_output_bin_path.?; |
| 967 | 965 | } |
| 968 | 966 | |
| 969 | | pub const PkgConfigError = error{ |
| 970 | | PkgConfigCrashed, |
| 971 | | PkgConfigFailed, |
| 972 | | PkgConfigNotInstalled, |
| 973 | | PkgConfigInvalidOutput, |
| 974 | | }; |
| 975 | | |
| 976 | | pub const PkgConfigPkg = struct { |
| 977 | | name: []const u8, |
| 978 | | desc: []const u8, |
| 979 | | }; |
| 980 | | |
| 981 | | fn execPkgConfigList(maker: *Maker, out_code: *u8) (PkgConfigError || Maker.RunError)![]const PkgConfigPkg { |
| 982 | | const graph = maker.graph; |
| 983 | | const process_arena = graph.arena; // TODO don't leak into process arena |
| 984 | | const pkg_config_exe = graph.environ_map.get("PKG_CONFIG") orelse "pkg-config"; |
| 985 | | const stdout = try maker.runAllowFail(&[_][]const u8{ pkg_config_exe, "--list-all" }, out_code, .ignore); |
| 986 | | var list = std.array_list.Managed(PkgConfigPkg).init(process_arena); |
| 987 | | errdefer list.deinit(); |
| 988 | | var line_it = mem.tokenizeAny(u8, stdout, "\r\n"); |
| 989 | | while (line_it.next()) |line| { |
| 990 | | if (mem.trim(u8, line, " \t").len == 0) continue; |
| 991 | | var tok_it = mem.tokenizeAny(u8, line, " \t"); |
| 992 | | try list.append(PkgConfigPkg{ |
| 993 | | .name = tok_it.next() orelse return error.PkgConfigInvalidOutput, |
| 994 | | .desc = tok_it.rest(), |
| 995 | | }); |
| 996 | | } |
| 997 | | return list.toOwnedSlice(); |
| 998 | | } |
| 999 | | |
| 1000 | | fn getPkgConfigList(b: *std.Build) ![]const PkgConfigPkg { |
| 1001 | | if (b.pkg_config_pkg_list) |res| { |
| 1002 | | return res; |
| 1003 | | } |
| 1004 | | var code: u8 = undefined; |
| 1005 | | if (execPkgConfigList(b, &code)) |list| { |
| 1006 | | b.pkg_config_pkg_list = list; |
| 1007 | | return list; |
| 1008 | | } else |err| { |
| 1009 | | const result = switch (err) { |
| 1010 | | error.ProcessTerminated => error.PkgConfigCrashed, |
| 1011 | | error.ExecNotSupported => error.PkgConfigFailed, |
| 1012 | | error.ExitCodeFailure => error.PkgConfigFailed, |
| 1013 | | error.FileNotFound => error.PkgConfigNotInstalled, |
| 1014 | | error.InvalidName => error.PkgConfigNotInstalled, |
| 1015 | | error.PkgConfigInvalidOutput => error.PkgConfigInvalidOutput, |
| 1016 | | else => return err, |
| 1017 | | }; |
| 1018 | | b.pkg_config_pkg_list = result; |
| 1019 | | return result; |
| 1020 | | } |
| 1021 | | } |
| 1022 | | |
| 1023 | 967 | fn addBool(gpa: Allocator, args: *std.ArrayList([]const u8), arg: []const u8, opt: bool) !void { |
| 1024 | 968 | if (opt) try args.append(gpa, arg); |
| 1025 | 969 | } |
| ... | ... | @@ -1029,125 +973,6 @@ fn addFlag(gpa: Allocator, args: *std.ArrayList([]const u8), comptime name: []co |
| 1029 | 973 | try args.append(gpa, if (cond) "-f" ++ name else "-fno-" ++ name); |
| 1030 | 974 | } |
| 1031 | 975 | |
| 1032 | | const PkgConfigResult = struct { |
| 1033 | | cflags: []const []const u8, |
| 1034 | | libs: []const []const u8, |
| 1035 | | }; |
| 1036 | | |
| 1037 | | /// Run pkg-config for the given library name and parse the output, returning the arguments |
| 1038 | | /// that should be passed to zig to link the given library. |
| 1039 | | fn runPkgConfig(compile: *const Compile, maker: *const Maker, lib_name: []const u8) !PkgConfigResult { |
| 1040 | | if (true) @panic("TODO runPkgConfig"); |
| 1041 | | const graph = maker.graph; |
| 1042 | | const wl_rpath_prefix = "-Wl,-rpath,"; |
| 1043 | | |
| 1044 | | const b = compile.step.owner; |
| 1045 | | const arena = b.allocator; |
| 1046 | | const pkg_name = match: { |
| 1047 | | // First we have to map the library name to pkg config name. Unfortunately, |
| 1048 | | // there are several examples where this is not straightforward: |
| 1049 | | // -lSDL2 -> pkg-config sdl2 |
| 1050 | | // -lgdk-3 -> pkg-config gdk-3.0 |
| 1051 | | // -latk-1.0 -> pkg-config atk |
| 1052 | | // -lpulse -> pkg-config libpulse |
| 1053 | | const pkgs = try getPkgConfigList(b); |
| 1054 | | |
| 1055 | | // Exact match means instant winner. |
| 1056 | | for (pkgs) |pkg| { |
| 1057 | | if (mem.eql(u8, pkg.name, lib_name)) { |
| 1058 | | break :match pkg.name; |
| 1059 | | } |
| 1060 | | } |
| 1061 | | |
| 1062 | | // Next we'll try ignoring case. |
| 1063 | | for (pkgs) |pkg| { |
| 1064 | | if (std.ascii.eqlIgnoreCase(pkg.name, lib_name)) { |
| 1065 | | break :match pkg.name; |
| 1066 | | } |
| 1067 | | } |
| 1068 | | |
| 1069 | | // Prefixed "lib" or suffixed ".0". |
| 1070 | | for (pkgs) |pkg| { |
| 1071 | | if (std.ascii.findIgnoreCase(pkg.name, lib_name)) |pos| { |
| 1072 | | const prefix = pkg.name[0..pos]; |
| 1073 | | const suffix = pkg.name[pos + lib_name.len ..]; |
| 1074 | | if (prefix.len > 0 and !mem.eql(u8, prefix, "lib")) continue; |
| 1075 | | if (suffix.len > 0 and !mem.eql(u8, suffix, ".0")) continue; |
| 1076 | | break :match pkg.name; |
| 1077 | | } |
| 1078 | | } |
| 1079 | | |
| 1080 | | // Trimming "-1.0". |
| 1081 | | if (mem.endsWith(u8, lib_name, "-1.0")) { |
| 1082 | | const trimmed_lib_name = lib_name[0 .. lib_name.len - "-1.0".len]; |
| 1083 | | for (pkgs) |pkg| { |
| 1084 | | if (std.ascii.eqlIgnoreCase(pkg.name, trimmed_lib_name)) { |
| 1085 | | break :match pkg.name; |
| 1086 | | } |
| 1087 | | } |
| 1088 | | } |
| 1089 | | |
| 1090 | | return error.PackageNotFound; |
| 1091 | | }; |
| 1092 | | |
| 1093 | | var code: u8 = undefined; |
| 1094 | | const pkg_config_exe = graph.environ_map.get("PKG_CONFIG") orelse "pkg-config"; |
| 1095 | | const stdout = if (b.runAllowFail(&[_][]const u8{ |
| 1096 | | pkg_config_exe, |
| 1097 | | pkg_name, |
| 1098 | | "--cflags", |
| 1099 | | "--libs", |
| 1100 | | }, &code, .ignore)) |stdout| stdout else |err| switch (err) { |
| 1101 | | error.ProcessTerminated => return error.PkgConfigCrashed, |
| 1102 | | error.ExecNotSupported => return error.PkgConfigFailed, |
| 1103 | | error.ExitCodeFailure => return error.PkgConfigFailed, |
| 1104 | | error.FileNotFound => return error.PkgConfigNotInstalled, |
| 1105 | | else => return err, |
| 1106 | | }; |
| 1107 | | |
| 1108 | | var zig_cflags: std.ArrayList([]const u8) = .empty; |
| 1109 | | defer zig_cflags.deinit(arena); |
| 1110 | | var zig_libs: std.ArrayList([]const u8) = .empty; |
| 1111 | | defer zig_libs.deinit(arena); |
| 1112 | | |
| 1113 | | var arg_it = mem.tokenizeAny(u8, stdout, " \r\n\t"); |
| 1114 | | while (arg_it.next()) |arg| { |
| 1115 | | if (mem.eql(u8, arg, "-I")) { |
| 1116 | | const dir = arg_it.next() orelse return error.PkgConfigInvalidOutput; |
| 1117 | | try zig_cflags.appendSlice(arena, &.{ "-I", dir }); |
| 1118 | | } else if (mem.startsWith(u8, arg, "-I")) { |
| 1119 | | try zig_cflags.append(arena, arg); |
| 1120 | | } else if (mem.eql(u8, arg, "-L")) { |
| 1121 | | const dir = arg_it.next() orelse return error.PkgConfigInvalidOutput; |
| 1122 | | try zig_libs.appendSlice(arena, &.{ "-L", dir }); |
| 1123 | | } else if (mem.startsWith(u8, arg, "-L")) { |
| 1124 | | try zig_libs.append(arena, arg); |
| 1125 | | } else if (mem.eql(u8, arg, "-l")) { |
| 1126 | | const lib = arg_it.next() orelse return error.PkgConfigInvalidOutput; |
| 1127 | | try zig_libs.appendSlice(arena, &.{ "-l", lib }); |
| 1128 | | } else if (mem.startsWith(u8, arg, "-l")) { |
| 1129 | | try zig_libs.append(arena, arg); |
| 1130 | | } else if (mem.eql(u8, arg, "-D")) { |
| 1131 | | const macro = arg_it.next() orelse return error.PkgConfigInvalidOutput; |
| 1132 | | try zig_cflags.appendSlice(arena, &.{ "-D", macro }); |
| 1133 | | } else if (mem.startsWith(u8, arg, "-D")) { |
| 1134 | | try zig_cflags.append(arena, arg); |
| 1135 | | } else if (mem.startsWith(u8, arg, wl_rpath_prefix)) { |
| 1136 | | try zig_cflags.appendSlice(arena, &.{ "-rpath", arg[wl_rpath_prefix.len..] }); |
| 1137 | | } else if (b.debug_pkg_config) { |
| 1138 | | return compile.step.fail(maker, "unknown pkg-config flag '{s}'", .{arg}); |
| 1139 | | } |
| 1140 | | } |
| 1141 | | |
| 1142 | | try zig_cflags.shrinkToLen(arena); |
| 1143 | | try zig_libs.shrinkToLen(arena); |
| 1144 | | |
| 1145 | | return .{ |
| 1146 | | .cflags = zig_cflags.toOwnedSliceAssert(), |
| 1147 | | .libs = zig_libs.toOwnedSliceAssert(), |
| 1148 | | }; |
| 1149 | | } |
| 1150 | | |
| 1151 | 976 | fn checkCompileErrors(compile: *Compile, maker: *Maker) !void { |
| 1152 | 977 | if (true) @panic("TODO checkCompileErrors"); |
| 1153 | 978 | // Clear this field so that it does not get printed by the build runner. |