authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-31 22:02:27-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-02-02 20:43:01-07:00
log8f867eaf84a2c270a2d1eb7208730519036eb364
treeb483e04cf7aa9d16533b2c377daae1dd66612fb1
parentf2e249e92020462ac29f34fc3d45cef3dc90a3b2

build system: introduce system library integration

* New --help section * Add b.systemLibraryOption * Rework the build runner CLI logic a bit

2 files changed, 189 insertions(+), 118 deletions(-)

lib/build_runner.zig+127-110
......@@ -76,6 +76,8 @@ pub fn main() !void {
7676 cache.addPrefix(global_cache_directory);
7777 cache.hash.addBytes(builtin.zig_version_string);
7878
79 var system_library_options: std.StringArrayHashMapUnmanaged(std.Build.SystemLibraryMode) = .{};
80
7981 const builder = try std.Build.create(
8082 arena,
8183 zig_exe,
......@@ -85,8 +87,8 @@ pub fn main() !void {
8587 host,
8688 &cache,
8789 dependencies.root_deps,
90 &system_library_options,
8891 );
89 defer builder.destroy();
9092
9193 var targets = ArrayList([]const u8).init(arena);
9294 var debug_log_scopes = ArrayList([]const u8).init(arena);
......@@ -100,64 +102,50 @@ pub fn main() !void {
100102 var color: Color = .auto;
101103 var seed: u32 = 0;
102104 var prominent_compile_errors: bool = false;
105 var help_menu: bool = false;
106 var steps_menu: bool = false;
103107
104 const stderr_stream = io.getStdErr().writer();
105108 const stdout_stream = io.getStdOut().writer();
106109
107110 while (nextArg(args, &arg_idx)) |arg| {
108111 if (mem.startsWith(u8, arg, "-D")) {
109112 const option_contents = arg[2..];
110 if (option_contents.len == 0) {
111 std.debug.print("Expected option name after '-D'\n\n", .{});
112 usageAndErr(builder, false, stderr_stream);
113 }
113 if (option_contents.len == 0)
114 fatalWithHint("expected option name after '-D'", .{});
114115 if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| {
115116 const option_name = option_contents[0..name_end];
116117 const option_value = option_contents[name_end + 1 ..];
117118 if (try builder.addUserInputOption(option_name, option_value))
118 usageAndErr(builder, false, stderr_stream);
119 fatal(" access the help menu with 'zig build -h'", .{});
119120 } else {
120121 if (try builder.addUserInputFlag(option_contents))
121 usageAndErr(builder, false, stderr_stream);
122 fatal(" access the help menu with 'zig build -h'", .{});
122123 }
123124 } else if (mem.startsWith(u8, arg, "-")) {
124125 if (mem.eql(u8, arg, "--verbose")) {
125126 builder.verbose = true;
126127 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
127 return usage(builder, false, stdout_stream);
128 help_menu = true;
128129 } else if (mem.eql(u8, arg, "-p") or mem.eql(u8, arg, "--prefix")) {
129 install_prefix = nextArg(args, &arg_idx) orelse {
130 std.debug.print("Expected argument after {s}\n\n", .{arg});
131 usageAndErr(builder, false, stderr_stream);
132 };
130 install_prefix = nextArgOrFatal(args, &arg_idx);
133131 } else if (mem.eql(u8, arg, "-l") or mem.eql(u8, arg, "--list-steps")) {
134 return steps(builder, false, stdout_stream);
132 steps_menu = true;
133 } else if (mem.eql(u8, arg, "--system-lib")) {
134 const name = nextArgOrFatal(args, &arg_idx);
135 builder.system_library_options.put(arena, name, .user_enabled) catch @panic("OOM");
136 } else if (mem.eql(u8, arg, "--no-system-lib")) {
137 const name = nextArgOrFatal(args, &arg_idx);
138 builder.system_library_options.put(arena, name, .user_disabled) catch @panic("OOM");
135139 } else if (mem.eql(u8, arg, "--prefix-lib-dir")) {
136 dir_list.lib_dir = nextArg(args, &arg_idx) orelse {
137 std.debug.print("Expected argument after {s}\n\n", .{arg});
138 usageAndErr(builder, false, stderr_stream);
139 };
140 dir_list.lib_dir = nextArgOrFatal(args, &arg_idx);
140141 } else if (mem.eql(u8, arg, "--prefix-exe-dir")) {
141 dir_list.exe_dir = nextArg(args, &arg_idx) orelse {
142 std.debug.print("Expected argument after {s}\n\n", .{arg});
143 usageAndErr(builder, false, stderr_stream);
144 };
142 dir_list.exe_dir = nextArgOrFatal(args, &arg_idx);
145143 } else if (mem.eql(u8, arg, "--prefix-include-dir")) {
146 dir_list.include_dir = nextArg(args, &arg_idx) orelse {
147 std.debug.print("Expected argument after {s}\n\n", .{arg});
148 usageAndErr(builder, false, stderr_stream);
149 };
144 dir_list.include_dir = nextArgOrFatal(args, &arg_idx);
150145 } else if (mem.eql(u8, arg, "--sysroot")) {
151 const sysroot = nextArg(args, &arg_idx) orelse {
152 std.debug.print("Expected argument after {s}\n\n", .{arg});
153 usageAndErr(builder, false, stderr_stream);
154 };
155 builder.sysroot = sysroot;
146 builder.sysroot = nextArgOrFatal(args, &arg_idx);
156147 } else if (mem.eql(u8, arg, "--maxrss")) {
157 const max_rss_text = nextArg(args, &arg_idx) orelse {
158 std.debug.print("Expected argument after {s}\n\n", .{arg});
159 usageAndErr(builder, false, stderr_stream);
160 };
148 const max_rss_text = nextArgOrFatal(args, &arg_idx);
161149 max_rss = std.fmt.parseIntSizeSuffix(max_rss_text, 10) catch |err| {
162150 std.debug.print("invalid byte size: '{s}': {s}\n", .{
163151 max_rss_text, @errorName(err),
......@@ -167,66 +155,45 @@ pub fn main() !void {
167155 } else if (mem.eql(u8, arg, "--skip-oom-steps")) {
168156 skip_oom_steps = true;
169157 } else if (mem.eql(u8, arg, "--search-prefix")) {
170 const search_prefix = nextArg(args, &arg_idx) orelse {
171 std.debug.print("Expected argument after {s}\n\n", .{arg});
172 usageAndErr(builder, false, stderr_stream);
173 };
158 const search_prefix = nextArgOrFatal(args, &arg_idx);
174159 builder.addSearchPrefix(search_prefix);
175160 } else if (mem.eql(u8, arg, "--libc")) {
176 const libc_file = nextArg(args, &arg_idx) orelse {
177 std.debug.print("Expected argument after {s}\n\n", .{arg});
178 usageAndErr(builder, false, stderr_stream);
179 };
180 builder.libc_file = libc_file;
161 builder.libc_file = nextArgOrFatal(args, &arg_idx);
181162 } else if (mem.eql(u8, arg, "--color")) {
182 const next_arg = nextArg(args, &arg_idx) orelse {
183 std.debug.print("Expected [auto|on|off] after {s}\n\n", .{arg});
184 usageAndErr(builder, false, stderr_stream);
185 };
163 const next_arg = nextArg(args, &arg_idx) orelse
164 fatalWithHint("expected [auto|on|off] after '{s}'", .{arg});
186165 color = std.meta.stringToEnum(Color, next_arg) orelse {
187 std.debug.print("Expected [auto|on|off] after {s}, found '{s}'\n\n", .{ arg, next_arg });
188 usageAndErr(builder, false, stderr_stream);
166 fatalWithHint("expected [auto|on|off] after '{s}', found '{s}'", .{
167 arg, next_arg,
168 });
189169 };
190170 } else if (mem.eql(u8, arg, "--summary")) {
191 const next_arg = nextArg(args, &arg_idx) orelse {
192 std.debug.print("Expected [all|failures|none] after {s}\n\n", .{arg});
193 usageAndErr(builder, false, stderr_stream);
194 };
171 const next_arg = nextArg(args, &arg_idx) orelse
172 fatalWithHint("expected [all|failures|none] after '{s}'", .{arg});
195173 summary = std.meta.stringToEnum(Summary, next_arg) orelse {
196 std.debug.print("Expected [all|failures|none] after {s}, found '{s}'\n\n", .{ arg, next_arg });
197 usageAndErr(builder, false, stderr_stream);
174 fatalWithHint("expected [all|failures|none] after '{s}', found '{s}'", .{
175 arg, next_arg,
176 });
198177 };
199178 } else if (mem.eql(u8, arg, "--zig-lib-dir")) {
200 builder.zig_lib_dir = .{ .cwd_relative = nextArg(args, &arg_idx) orelse {
201 std.debug.print("Expected argument after {s}\n\n", .{arg});
202 usageAndErr(builder, false, stderr_stream);
203 } };
179 builder.zig_lib_dir = .{ .cwd_relative = nextArgOrFatal(args, &arg_idx) };
204180 } else if (mem.eql(u8, arg, "--seed")) {
205 const next_arg = nextArg(args, &arg_idx) orelse {
206 std.debug.print("Expected u32 after {s}\n\n", .{arg});
207 usageAndErr(builder, false, stderr_stream);
208 };
181 const next_arg = nextArg(args, &arg_idx) orelse
182 fatalWithHint("expected u32 after '{s}'", .{arg});
209183 seed = std.fmt.parseUnsigned(u32, next_arg, 0) catch |err| {
210 std.debug.print("unable to parse seed '{s}' as 32-bit integer: {s}\n", .{
184 fatal("unable to parse seed '{s}' as 32-bit integer: {s}\n", .{
211185 next_arg, @errorName(err),
212186 });
213 process.exit(1);
214187 };
215188 } else if (mem.eql(u8, arg, "--debug-log")) {
216 const next_arg = nextArg(args, &arg_idx) orelse {
217 std.debug.print("Expected argument after {s}\n\n", .{arg});
218 usageAndErr(builder, false, stderr_stream);
219 };
189 const next_arg = nextArgOrFatal(args, &arg_idx);
220190 try debug_log_scopes.append(next_arg);
221191 } else if (mem.eql(u8, arg, "--debug-pkg-config")) {
222192 builder.debug_pkg_config = true;
223193 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
224194 builder.debug_compile_errors = true;
225195 } else if (mem.eql(u8, arg, "--glibc-runtimes")) {
226 builder.glibc_runtimes_dir = nextArg(args, &arg_idx) orelse {
227 std.debug.print("Expected argument after {s}\n\n", .{arg});
228 usageAndErr(builder, false, stderr_stream);
229 };
196 builder.glibc_runtimes_dir = nextArgOrFatal(args, &arg_idx);
230197 } else if (mem.eql(u8, arg, "--verbose-link")) {
231198 builder.verbose_link = true;
232199 } else if (mem.eql(u8, arg, "--verbose-air")) {
......@@ -292,8 +259,7 @@ pub fn main() !void {
292259 builder.args = argsRest(args, arg_idx);
293260 break;
294261 } else {
295 std.debug.print("Unrecognized argument: {s}\n\n", .{arg});
296 usageAndErr(builder, false, stderr_stream);
262 fatalWithHint("unrecognized argument: '{s}'", .{arg});
297263 }
298264 } else {
299265 try targets.append(arg);
......@@ -319,8 +285,17 @@ pub fn main() !void {
319285 try builder.runBuild(root);
320286 }
321287
322 if (builder.validateUserInputDidItFail())
323 usageAndErr(builder, true, stderr_stream);
288 if (builder.validateUserInputDidItFail()) {
289 fatal(" access the help menu with 'zig build -h'", .{});
290 }
291
292 validateSystemLibraryOptions(builder);
293
294 if (help_menu)
295 return usage(builder, stdout_stream);
296
297 if (steps_menu)
298 return steps(builder, stdout_stream);
324299
325300 var run: Run = .{
326301 .max_rss = max_rss,
......@@ -389,7 +364,7 @@ fn runStepNames(
389364 for (0..step_names.len) |i| {
390365 const step_name = step_names[step_names.len - i - 1];
391366 const s = b.top_level_steps.get(step_name) orelse {
392 std.debug.print("no step named '{s}'. Access the help menu with 'zig build -h'\n", .{step_name});
367 std.debug.print("no step named '{s}'\n access the help menu with 'zig build -h'\n", .{step_name});
393368 process.exit(1);
394369 };
395370 step_stack.putAssumeCapacity(&s.step, {});
......@@ -1037,13 +1012,7 @@ fn printErrorMessages(b: *std.Build, failing_step: *Step, run: *const Run) !void
10371012 }
10381013}
10391014
1040fn steps(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !void {
1041 // run the build script to collect the options
1042 if (!already_ran_build) {
1043 builder.resolveInstallPrefix(null, .{});
1044 try builder.runBuild(root);
1045 }
1046
1015fn steps(builder: *std.Build, out_stream: anytype) !void {
10471016 const allocator = builder.allocator;
10481017 for (builder.top_level_steps.values()) |top_level_step| {
10491018 const name = if (&top_level_step.step == builder.default_step)
......@@ -1054,29 +1023,22 @@ fn steps(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
10541023 }
10551024}
10561025
1057fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !void {
1058 // run the build script to collect the options
1059 if (!already_ran_build) {
1060 builder.resolveInstallPrefix(null, .{});
1061 try builder.runBuild(root);
1062 }
1063
1026fn usage(b: *std.Build, out_stream: anytype) !void {
10641027 try out_stream.print(
1065 \\
10661028 \\Usage: {s} build [steps] [options]
10671029 \\
10681030 \\Steps:
10691031 \\
1070 , .{builder.zig_exe});
1071 try steps(builder, true, out_stream);
1032 , .{b.zig_exe});
1033 try steps(b, out_stream);
10721034
10731035 try out_stream.writeAll(
10741036 \\
10751037 \\General Options:
1076 \\ -p, --prefix [path] Override default install prefix
1077 \\ --prefix-lib-dir [path] Override default library directory path
1078 \\ --prefix-exe-dir [path] Override default executable directory path
1079 \\ --prefix-include-dir [path] Override default include directory path
1038 \\ -p, --prefix [path] Where to put installed files (default: zig-out)
1039 \\ --prefix-lib-dir [path] Where to put installed libraries
1040 \\ --prefix-exe-dir [path] Where to put installed executables
1041 \\ --prefix-include-dir [path] Where to put installed C header files
10801042 \\
10811043 \\ --sysroot [path] Set the system root directory (usually /)
10821044 \\ --search-prefix [path] Add a path to look for binaries, libraries, headers
......@@ -1116,16 +1078,15 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
11161078 \\
11171079 );
11181080
1119 const allocator = builder.allocator;
1120 if (builder.available_options_list.items.len == 0) {
1081 const arena = b.allocator;
1082 if (b.available_options_list.items.len == 0) {
11211083 try out_stream.print(" (none)\n", .{});
11221084 } else {
1123 for (builder.available_options_list.items) |option| {
1124 const name = try fmt.allocPrint(allocator, " -D{s}=[{s}]", .{
1085 for (b.available_options_list.items) |option| {
1086 const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{
11251087 option.name,
11261088 @tagName(option.type_id),
11271089 });
1128 defer allocator.free(name);
11291090 try out_stream.print("{s:<30} {s}\n", .{ name, option.description });
11301091 if (option.enum_options) |enum_options| {
11311092 const padding = " " ** 33;
......@@ -1137,6 +1098,31 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
11371098 }
11381099 }
11391100
1101 try out_stream.writeAll(
1102 \\
1103 \\System Integration Options:
1104 \\ --system [dir] System Package Mode. Disable fetching; prefer system libs
1105 \\ --host-target [triple] Use the provided target as the host
1106 \\ --host-cpu [cpu] Use the provided CPU as the host
1107 \\ --system-lib [name] Use the system-provided library
1108 \\ --no-system-lib [name] Do not use the system-provided library
1109 \\
1110 \\ Available System Library Integrations: Enabled:
1111 \\
1112 );
1113 if (b.system_library_options.entries.len == 0) {
1114 try out_stream.writeAll(" (none) -\n");
1115 } else {
1116 for (b.system_library_options.keys(), b.system_library_options.values()) |name, v| {
1117 const status = switch (v) {
1118 .declared_enabled => "yes",
1119 .declared_disabled => "no",
1120 .user_enabled, .user_disabled => unreachable, // already emitted error
1121 };
1122 try out_stream.print(" {s:<43} {s}\n", .{ name, status });
1123 }
1124 }
1125
11401126 try out_stream.writeAll(
11411127 \\
11421128 \\Advanced Options:
......@@ -1161,17 +1147,19 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
11611147 );
11621148}
11631149
1164fn usageAndErr(builder: *std.Build, already_ran_build: bool, out_stream: anytype) noreturn {
1165 usage(builder, already_ran_build, out_stream) catch {};
1166 process.exit(1);
1167}
1168
11691150fn nextArg(args: [][:0]const u8, idx: *usize) ?[:0]const u8 {
11701151 if (idx.* >= args.len) return null;
11711152 defer idx.* += 1;
11721153 return args[idx.*];
11731154}
11741155
1156fn nextArgOrFatal(args: [][:0]const u8, idx: *usize) [:0]const u8 {
1157 return nextArg(args, idx) orelse {
1158 std.debug.print("expected argument after '{s}'\n access the help menu with 'zig build -h'\n", .{args[idx.*]});
1159 process.exit(1);
1160 };
1161}
1162
11751163fn argsRest(args: [][:0]const u8, idx: usize) ?[][:0]const u8 {
11761164 if (idx >= args.len) return null;
11771165 return args[idx..];
......@@ -1202,3 +1190,32 @@ fn renderOptions(ttyconf: std.io.tty.Config) std.zig.ErrorBundle.RenderOptions {
12021190 .include_reference_trace = ttyconf != .no_color,
12031191 };
12041192}
1193
1194fn fatalWithHint(comptime f: []const u8, args: anytype) noreturn {
1195 std.debug.print(f ++ "\n access the help menu with 'zig build -h'\n", args);
1196 process.exit(1);
1197}
1198
1199fn fatal(comptime f: []const u8, args: anytype) noreturn {
1200 std.debug.print(f ++ "\n", args);
1201 process.exit(1);
1202}
1203
1204fn validateSystemLibraryOptions(b: *std.Build) void {
1205 var bad = false;
1206 for (b.system_library_options.keys(), b.system_library_options.values()) |k, v| {
1207 switch (v) {
1208 .user_disabled, .user_enabled => {
1209 // The user tried to enable or disable a system library integration, but
1210 // the build script did not recognize that option.
1211 std.debug.print("system library name not recognized by build script: '{s}'\n", .{k});
1212 bad = true;
1213 },
1214 .declared_disabled, .declared_enabled => {},
1215 }
1216 }
1217 if (bad) {
1218 std.debug.print(" access the help menu with 'zig build -h'\n", .{});
1219 process.exit(1);
1220 }
1221}
lib/std/Build.zig+62-8
......@@ -28,6 +28,9 @@ allocator: Allocator,
2828user_input_options: UserInputOptionsMap,
2929available_options_map: AvailableOptionsMap,
3030available_options_list: ArrayList(AvailableOption),
31/// All Build instances share this hash map.
32system_library_options: *std.StringArrayHashMapUnmanaged(SystemLibraryMode),
33system_package_mode: bool,
3134verbose: bool,
3235verbose_link: bool,
3336verbose_cc: bool,
......@@ -100,6 +103,21 @@ available_deps: AvailableDeps,
100103
101104const AvailableDeps = []const struct { []const u8, []const u8 };
102105
106pub const SystemLibraryMode = enum {
107 /// User asked for the library to be disabled.
108 /// The build runner has not confirmed whether the setting is recognized yet.
109 user_disabled,
110 /// User asked for the library to be enabled.
111 /// The build runner has not confirmed whether the setting is recognized yet.
112 user_enabled,
113 /// The build runner has confirmed that this setting is recognized.
114 /// System integration with this library has been resolved to off.
115 declared_disabled,
116 /// The build runner has confirmed that this setting is recognized.
117 /// System integration with this library has been resolved to on.
118 declared_enabled,
119};
120
103121const InitializedDepMap = std.HashMap(InitializedDepKey, *Dependency, InitializedDepContext, std.hash_map.default_max_load_percentage);
104122const InitializedDepKey = struct {
105123 build_root_string: []const u8,
......@@ -216,6 +234,7 @@ pub fn create(
216234 host: ResolvedTarget,
217235 cache: *Cache,
218236 available_deps: AvailableDeps,
237 system_library_options: *std.StringArrayHashMapUnmanaged(SystemLibraryMode),
219238) !*Build {
220239 const env_map = try allocator.create(EnvMap);
221240 env_map.* = try process.getEnvMap(allocator);
......@@ -278,6 +297,8 @@ pub fn create(
278297 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator),
279298 .initialized_deps = initialized_deps,
280299 .available_deps = available_deps,
300 .system_library_options = system_library_options,
301 .system_package_mode = false,
281302 };
282303 try self.top_level_steps.put(allocator, self.install_tls.step.name, &self.install_tls);
283304 try self.top_level_steps.put(allocator, self.uninstall_tls.step.name, &self.uninstall_tls);
......@@ -297,7 +318,13 @@ fn createChild(
297318 return child;
298319}
299320
300fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Directory, pkg_deps: AvailableDeps, user_input_options: UserInputOptionsMap) !*Build {
321fn createChildOnly(
322 parent: *Build,
323 dep_name: []const u8,
324 build_root: Cache.Directory,
325 pkg_deps: AvailableDeps,
326 user_input_options: UserInputOptionsMap,
327) !*Build {
301328 const allocator = parent.allocator;
302329 const child = try allocator.create(Build);
303330 child.* = .{
......@@ -366,6 +393,8 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc
366393 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator),
367394 .initialized_deps = parent.initialized_deps,
368395 .available_deps = pkg_deps,
396 .system_library_options = parent.system_library_options,
397 .system_package_mode = parent.system_package_mode,
369398 };
370399 try child.top_level_steps.put(allocator, child.install_tls.step.name, &child.install_tls);
371400 try child.top_level_steps.put(allocator, child.uninstall_tls.step.name, &child.uninstall_tls);
......@@ -1367,7 +1396,7 @@ pub fn addUserInputOption(self: *Build, name_raw: []const u8, value_raw: []const
13671396 });
13681397 },
13691398 .flag => {
1370 log.warn("Option '-D{s}={s}' conflicts with flag '-D{s}'.", .{ name, value, name });
1399 log.warn("option '-D{s}={s}' conflicts with flag '-D{s}'.", .{ name, value, name });
13711400 return true;
13721401 },
13731402 .map => |*map| {
......@@ -1427,17 +1456,17 @@ fn markInvalidUserInput(self: *Build) void {
14271456 self.invalid_user_input = true;
14281457}
14291458
1430pub fn validateUserInputDidItFail(self: *Build) bool {
1431 // make sure all args are used
1432 var it = self.user_input_options.iterator();
1459pub fn validateUserInputDidItFail(b: *Build) bool {
1460 // Make sure all args are used.
1461 var it = b.user_input_options.iterator();
14331462 while (it.next()) |entry| {
14341463 if (!entry.value_ptr.used) {
1435 log.err("Invalid option: -D{s}", .{entry.key_ptr.*});
1436 self.markInvalidUserInput();
1464 log.err("invalid option: -D{s}", .{entry.key_ptr.*});
1465 b.markInvalidUserInput();
14371466 }
14381467 }
14391468
1440 return self.invalid_user_input;
1469 return b.invalid_user_input;
14411470}
14421471
14431472fn allocPrintCmd(ally: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) ![]u8 {
......@@ -2296,6 +2325,31 @@ pub fn wantSharedLibSymLinks(target: Target) bool {
22962325 return target.os.tag != .windows;
22972326}
22982327
2328pub fn systemLibraryOption(b: *Build, name: []const u8) bool {
2329 const gop = b.system_library_options.getOrPut(b.allocator, name) catch @panic("OOM");
2330 if (gop.found_existing) switch (gop.value_ptr.*) {
2331 .user_disabled => {
2332 gop.value_ptr.* = .declared_disabled;
2333 return false;
2334 },
2335 .user_enabled => {
2336 gop.value_ptr.* = .declared_enabled;
2337 return true;
2338 },
2339 .declared_disabled => return false,
2340 .declared_enabled => return true,
2341 } else {
2342 gop.key_ptr.* = b.dupe(name);
2343 if (b.system_package_mode) {
2344 gop.value_ptr.* = .declared_enabled;
2345 return true;
2346 } else {
2347 gop.value_ptr.* = .declared_disabled;
2348 return false;
2349 }
2350 }
2351}
2352
22992353test {
23002354 _ = Cache;
23012355 _ = Step;