| ... | @@ -14,6 +14,7 @@ const allocPrint = std.fmt.allocPrint; | ... | @@ -14,6 +14,7 @@ const allocPrint = std.fmt.allocPrint; |
| 14 | | 14 | |
| 15 | const Step = @import("../Step.zig"); | 15 | const Step = @import("../Step.zig"); |
| 16 | const Maker = @import("../../Maker.zig"); | 16 | const Maker = @import("../../Maker.zig"); |
| | 17 | const PkgConfig = @import("../PkgConfig.zig"); |
| 17 | | 18 | |
| 18 | /// Populated when there is compiler process that lives across multiple calls | 19 | /// Populated when there is compiler process that lives across multiple calls |
| 19 | /// to `make`. | 20 | /// to `make`. |
| ... | @@ -40,7 +41,7 @@ pub fn make( | ... | @@ -40,7 +41,7 @@ pub fn make( |
| 40 | // Reset / repopulate persistent state. | 41 | // Reset / repopulate persistent state. |
| 41 | compile.zig_args.clearRetainingCapacity(); | 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 | const maybe_output_dir = Step.evalZigProcess( | 46 | const maybe_output_dir = Step.evalZigProcess( |
| 46 | compile_index, | 47 | compile_index, |
| ... | @@ -148,10 +149,11 @@ const ModuleListContext = struct { | ... | @@ -148,10 +149,11 @@ const ModuleListContext = struct { |
| 148 | fn lowerZigArgs( | 149 | fn lowerZigArgs( |
| 149 | compile: *Compile, | 150 | compile: *Compile, |
| 150 | compile_index: Configuration.Step.Index, | 151 | compile_index: Configuration.Step.Index, |
| 151 | maker: *const Maker, | 152 | maker: *Maker, |
| | 153 | progress_node: std.Progress.Node, |
| 152 | zig_args: *std.ArrayList([]const u8), | 154 | zig_args: *std.ArrayList([]const u8), |
| 153 | fuzz: bool, | 155 | fuzz: bool, |
| 154 | ) error{ OutOfMemory, MakeFailed }!void { | 156 | ) Step.ExtendedMakeError!void { |
| 155 | const step = maker.stepByIndex(compile_index); | 157 | const step = maker.stepByIndex(compile_index); |
| 156 | const graph = maker.graph; | 158 | const graph = maker.graph; |
| 157 | const arena = graph.arena; // TODO don't leak into the process arena | 159 | const arena = graph.arena; // TODO don't leak into the process arena |
| ... | @@ -312,40 +314,36 @@ fn lowerZigArgs( | ... | @@ -312,40 +314,36 @@ fn lowerZigArgs( |
| 312 | if (system_lib.flags.weak) break :prefix "-weak-l"; | 314 | if (system_lib.flags.weak) break :prefix "-weak-l"; |
| 313 | break :prefix "-l"; | 315 | break :prefix "-l"; |
| 314 | }; | 316 | }; |
| 315 | switch (system_lib.flags.use_pkg_config) { | 317 | l: { |
| 316 | .no => try zig_args.append(gpa, try allocPrint(arena, "{s}{s}", .{ | 318 | pc: { |
| 317 | prefix, system_lib_name, | 319 | const force = switch (system_lib.flags.use_pkg_config) { |
| 318 | })), | 320 | .no => break :pc, |
| 319 | .yes, .force => { | 321 | .yes => false, |
| 320 | if (compile.runPkgConfig(maker, system_lib_name)) |result| { | 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 | try zig_args.appendSlice(gpa, result.cflags); | 329 | try zig_args.appendSlice(gpa, result.cflags); |
| 322 | try zig_args.appendSlice(gpa, result.libs); | 330 | try zig_args.appendSlice(gpa, result.libs); |
| 323 | try seen_system_libs.put(arena, system_lib.name, result.cflags); | 331 | try seen_system_libs.put(arena, system_lib.name, result.cflags); |
| | 332 | break :l; |
| 324 | } else |err| switch (err) { | 333 | } else |err| switch (err) { |
| 325 | error.PkgConfigInvalidOutput, | 334 | error.PkgConfigUnavailable, |
| 326 | error.PkgConfigCrashed, | | |
| 327 | error.PkgConfigFailed, | | |
| 328 | error.PkgConfigNotInstalled, | | |
| 329 | error.PackageNotFound, | 335 | error.PackageNotFound, |
| 330 | => switch (system_lib.flags.use_pkg_config) { | 336 | => { |
| 331 | .yes => { | 337 | // pkg-config failed, so fall back to linking the library by name directly. |
| 332 | // pkg-config failed, so fall back to linking the library | 338 | assert(!force); |
| 333 | // by name directly. | 339 | break :pc; |
| 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, | | |
| 344 | }, | 340 | }, |
| 345 | | | |
| 346 | else => |e| return e, | 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 | .other_step => |other_step_index| { | 349 | .other_step => |other_step_index| { |
| ... | @@ -961,65 +959,11 @@ pub fn rebuildInFuzzMode(compile: *Compile, maker: *Maker, progress_node: std.Pr | ... | @@ -961,65 +959,11 @@ pub fn rebuildInFuzzMode(compile: *Compile, maker: *Maker, progress_node: std.Pr |
| 961 | | 959 | |
| 962 | const zig_args = &compile.zig_args; | 960 | const zig_args = &compile.zig_args; |
| 963 | zig_args.clearRetainingCapacity(); | 961 | zig_args.clearRetainingCapacity(); |
| 964 | try lowerZigArgs(compile, maker, zig_args, true); | 962 | try lowerZigArgs(compile, maker, progress_node, zig_args, true); |
| 965 | const maybe_output_bin_path = try compile.step.evalZigProcess(zig_args.items, progress_node, false, maker); | 963 | const maybe_output_bin_path = try compile.step.evalZigProcess(zig_args.items, progress_node, false, maker); |
| 966 | return maybe_output_bin_path.?; | 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 | fn addBool(gpa: Allocator, args: *std.ArrayList([]const u8), arg: []const u8, opt: bool) !void { | 967 | fn addBool(gpa: Allocator, args: *std.ArrayList([]const u8), arg: []const u8, opt: bool) !void { |
| 1024 | if (opt) try args.append(gpa, arg); | 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,125 +973,6 @@ fn addFlag(gpa: Allocator, args: *std.ArrayList([]const u8), comptime name: []co |
| 1029 | try args.append(gpa, if (cond) "-f" ++ name else "-fno-" ++ name); | 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 | fn checkCompileErrors(compile: *Compile, maker: *Maker) !void { | 976 | fn checkCompileErrors(compile: *Compile, maker: *Maker) !void { |
| 1152 | if (true) @panic("TODO checkCompileErrors"); | 977 | if (true) @panic("TODO checkCompileErrors"); |
| 1153 | // Clear this field so that it does not get printed by the build runner. | 978 | // Clear this field so that it does not get printed by the build runner. |