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 {...@@ -76,6 +76,8 @@ pub fn main() !void {
76 cache.addPrefix(global_cache_directory);76 cache.addPrefix(global_cache_directory);
77 cache.hash.addBytes(builtin.zig_version_string);77 cache.hash.addBytes(builtin.zig_version_string);
7878
79 var system_library_options: std.StringArrayHashMapUnmanaged(std.Build.SystemLibraryMode) = .{};
80
79 const builder = try std.Build.create(81 const builder = try std.Build.create(
80 arena,82 arena,
81 zig_exe,83 zig_exe,
...@@ -85,8 +87,8 @@ pub fn main() !void {...@@ -85,8 +87,8 @@ pub fn main() !void {
85 host,87 host,
86 &cache,88 &cache,
87 dependencies.root_deps,89 dependencies.root_deps,
90 &system_library_options,
88 );91 );
89 defer builder.destroy();
9092
91 var targets = ArrayList([]const u8).init(arena);93 var targets = ArrayList([]const u8).init(arena);
92 var debug_log_scopes = ArrayList([]const u8).init(arena);94 var debug_log_scopes = ArrayList([]const u8).init(arena);
...@@ -100,64 +102,50 @@ pub fn main() !void {...@@ -100,64 +102,50 @@ pub fn main() !void {
100 var color: Color = .auto;102 var color: Color = .auto;
101 var seed: u32 = 0;103 var seed: u32 = 0;
102 var prominent_compile_errors: bool = false;104 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();
105 const stdout_stream = io.getStdOut().writer();108 const stdout_stream = io.getStdOut().writer();
106109
107 while (nextArg(args, &arg_idx)) |arg| {110 while (nextArg(args, &arg_idx)) |arg| {
108 if (mem.startsWith(u8, arg, "-D")) {111 if (mem.startsWith(u8, arg, "-D")) {
109 const option_contents = arg[2..];112 const option_contents = arg[2..];
110 if (option_contents.len == 0) {113 if (option_contents.len == 0)
111 std.debug.print("Expected option name after '-D'\n\n", .{});114 fatalWithHint("expected option name after '-D'", .{});
112 usageAndErr(builder, false, stderr_stream);
113 }
114 if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| {115 if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| {
115 const option_name = option_contents[0..name_end];116 const option_name = option_contents[0..name_end];
116 const option_value = option_contents[name_end + 1 ..];117 const option_value = option_contents[name_end + 1 ..];
117 if (try builder.addUserInputOption(option_name, option_value))118 if (try builder.addUserInputOption(option_name, option_value))
118 usageAndErr(builder, false, stderr_stream);119 fatal(" access the help menu with 'zig build -h'", .{});
119 } else {120 } else {
120 if (try builder.addUserInputFlag(option_contents))121 if (try builder.addUserInputFlag(option_contents))
121 usageAndErr(builder, false, stderr_stream);122 fatal(" access the help menu with 'zig build -h'", .{});
122 }123 }
123 } else if (mem.startsWith(u8, arg, "-")) {124 } else if (mem.startsWith(u8, arg, "-")) {
124 if (mem.eql(u8, arg, "--verbose")) {125 if (mem.eql(u8, arg, "--verbose")) {
125 builder.verbose = true;126 builder.verbose = true;
126 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {127 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
127 return usage(builder, false, stdout_stream);128 help_menu = true;
128 } else if (mem.eql(u8, arg, "-p") or mem.eql(u8, arg, "--prefix")) {129 } else if (mem.eql(u8, arg, "-p") or mem.eql(u8, arg, "--prefix")) {
129 install_prefix = nextArg(args, &arg_idx) orelse {130 install_prefix = nextArgOrFatal(args, &arg_idx);
130 std.debug.print("Expected argument after {s}\n\n", .{arg});
131 usageAndErr(builder, false, stderr_stream);
132 };
133 } else if (mem.eql(u8, arg, "-l") or mem.eql(u8, arg, "--list-steps")) {131 } 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");
135 } else if (mem.eql(u8, arg, "--prefix-lib-dir")) {139 } else if (mem.eql(u8, arg, "--prefix-lib-dir")) {
136 dir_list.lib_dir = nextArg(args, &arg_idx) orelse {140 dir_list.lib_dir = nextArgOrFatal(args, &arg_idx);
137 std.debug.print("Expected argument after {s}\n\n", .{arg});
138 usageAndErr(builder, false, stderr_stream);
139 };
140 } else if (mem.eql(u8, arg, "--prefix-exe-dir")) {141 } else if (mem.eql(u8, arg, "--prefix-exe-dir")) {
141 dir_list.exe_dir = nextArg(args, &arg_idx) orelse {142 dir_list.exe_dir = nextArgOrFatal(args, &arg_idx);
142 std.debug.print("Expected argument after {s}\n\n", .{arg});
143 usageAndErr(builder, false, stderr_stream);
144 };
145 } else if (mem.eql(u8, arg, "--prefix-include-dir")) {143 } else if (mem.eql(u8, arg, "--prefix-include-dir")) {
146 dir_list.include_dir = nextArg(args, &arg_idx) orelse {144 dir_list.include_dir = nextArgOrFatal(args, &arg_idx);
147 std.debug.print("Expected argument after {s}\n\n", .{arg});
148 usageAndErr(builder, false, stderr_stream);
149 };
150 } else if (mem.eql(u8, arg, "--sysroot")) {145 } else if (mem.eql(u8, arg, "--sysroot")) {
151 const sysroot = nextArg(args, &arg_idx) orelse {146 builder.sysroot = nextArgOrFatal(args, &arg_idx);
152 std.debug.print("Expected argument after {s}\n\n", .{arg});
153 usageAndErr(builder, false, stderr_stream);
154 };
155 builder.sysroot = sysroot;
156 } else if (mem.eql(u8, arg, "--maxrss")) {147 } else if (mem.eql(u8, arg, "--maxrss")) {
157 const max_rss_text = nextArg(args, &arg_idx) orelse {148 const max_rss_text = nextArgOrFatal(args, &arg_idx);
158 std.debug.print("Expected argument after {s}\n\n", .{arg});
159 usageAndErr(builder, false, stderr_stream);
160 };
161 max_rss = std.fmt.parseIntSizeSuffix(max_rss_text, 10) catch |err| {149 max_rss = std.fmt.parseIntSizeSuffix(max_rss_text, 10) catch |err| {
162 std.debug.print("invalid byte size: '{s}': {s}\n", .{150 std.debug.print("invalid byte size: '{s}': {s}\n", .{
163 max_rss_text, @errorName(err),151 max_rss_text, @errorName(err),
...@@ -167,66 +155,45 @@ pub fn main() !void {...@@ -167,66 +155,45 @@ pub fn main() !void {
167 } else if (mem.eql(u8, arg, "--skip-oom-steps")) {155 } else if (mem.eql(u8, arg, "--skip-oom-steps")) {
168 skip_oom_steps = true;156 skip_oom_steps = true;
169 } else if (mem.eql(u8, arg, "--search-prefix")) {157 } else if (mem.eql(u8, arg, "--search-prefix")) {
170 const search_prefix = nextArg(args, &arg_idx) orelse {158 const search_prefix = nextArgOrFatal(args, &arg_idx);
171 std.debug.print("Expected argument after {s}\n\n", .{arg});
172 usageAndErr(builder, false, stderr_stream);
173 };
174 builder.addSearchPrefix(search_prefix);159 builder.addSearchPrefix(search_prefix);
175 } else if (mem.eql(u8, arg, "--libc")) {160 } else if (mem.eql(u8, arg, "--libc")) {
176 const libc_file = nextArg(args, &arg_idx) orelse {161 builder.libc_file = nextArgOrFatal(args, &arg_idx);
177 std.debug.print("Expected argument after {s}\n\n", .{arg});
178 usageAndErr(builder, false, stderr_stream);
179 };
180 builder.libc_file = libc_file;
181 } else if (mem.eql(u8, arg, "--color")) {162 } else if (mem.eql(u8, arg, "--color")) {
182 const next_arg = nextArg(args, &arg_idx) orelse {163 const next_arg = nextArg(args, &arg_idx) orelse
183 std.debug.print("Expected [auto|on|off] after {s}\n\n", .{arg});164 fatalWithHint("expected [auto|on|off] after '{s}'", .{arg});
184 usageAndErr(builder, false, stderr_stream);
185 };
186 color = std.meta.stringToEnum(Color, next_arg) orelse {165 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 });166 fatalWithHint("expected [auto|on|off] after '{s}', found '{s}'", .{
188 usageAndErr(builder, false, stderr_stream);167 arg, next_arg,
168 });
189 };169 };
190 } else if (mem.eql(u8, arg, "--summary")) {170 } else if (mem.eql(u8, arg, "--summary")) {
191 const next_arg = nextArg(args, &arg_idx) orelse {171 const next_arg = nextArg(args, &arg_idx) orelse
192 std.debug.print("Expected [all|failures|none] after {s}\n\n", .{arg});172 fatalWithHint("expected [all|failures|none] after '{s}'", .{arg});
193 usageAndErr(builder, false, stderr_stream);
194 };
195 summary = std.meta.stringToEnum(Summary, next_arg) orelse {173 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 });174 fatalWithHint("expected [all|failures|none] after '{s}', found '{s}'", .{
197 usageAndErr(builder, false, stderr_stream);175 arg, next_arg,
176 });
198 };177 };
199 } else if (mem.eql(u8, arg, "--zig-lib-dir")) {178 } else if (mem.eql(u8, arg, "--zig-lib-dir")) {
200 builder.zig_lib_dir = .{ .cwd_relative = nextArg(args, &arg_idx) orelse {179 builder.zig_lib_dir = .{ .cwd_relative = nextArgOrFatal(args, &arg_idx) };
201 std.debug.print("Expected argument after {s}\n\n", .{arg});
202 usageAndErr(builder, false, stderr_stream);
203 } };
204 } else if (mem.eql(u8, arg, "--seed")) {180 } else if (mem.eql(u8, arg, "--seed")) {
205 const next_arg = nextArg(args, &arg_idx) orelse {181 const next_arg = nextArg(args, &arg_idx) orelse
206 std.debug.print("Expected u32 after {s}\n\n", .{arg});182 fatalWithHint("expected u32 after '{s}'", .{arg});
207 usageAndErr(builder, false, stderr_stream);
208 };
209 seed = std.fmt.parseUnsigned(u32, next_arg, 0) catch |err| {183 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", .{
211 next_arg, @errorName(err),185 next_arg, @errorName(err),
212 });186 });
213 process.exit(1);
214 };187 };
215 } else if (mem.eql(u8, arg, "--debug-log")) {188 } else if (mem.eql(u8, arg, "--debug-log")) {
216 const next_arg = nextArg(args, &arg_idx) orelse {189 const next_arg = nextArgOrFatal(args, &arg_idx);
217 std.debug.print("Expected argument after {s}\n\n", .{arg});
218 usageAndErr(builder, false, stderr_stream);
219 };
220 try debug_log_scopes.append(next_arg);190 try debug_log_scopes.append(next_arg);
221 } else if (mem.eql(u8, arg, "--debug-pkg-config")) {191 } else if (mem.eql(u8, arg, "--debug-pkg-config")) {
222 builder.debug_pkg_config = true;192 builder.debug_pkg_config = true;
223 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {193 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
224 builder.debug_compile_errors = true;194 builder.debug_compile_errors = true;
225 } else if (mem.eql(u8, arg, "--glibc-runtimes")) {195 } else if (mem.eql(u8, arg, "--glibc-runtimes")) {
226 builder.glibc_runtimes_dir = nextArg(args, &arg_idx) orelse {196 builder.glibc_runtimes_dir = nextArgOrFatal(args, &arg_idx);
227 std.debug.print("Expected argument after {s}\n\n", .{arg});
228 usageAndErr(builder, false, stderr_stream);
229 };
230 } else if (mem.eql(u8, arg, "--verbose-link")) {197 } else if (mem.eql(u8, arg, "--verbose-link")) {
231 builder.verbose_link = true;198 builder.verbose_link = true;
232 } else if (mem.eql(u8, arg, "--verbose-air")) {199 } else if (mem.eql(u8, arg, "--verbose-air")) {
...@@ -292,8 +259,7 @@ pub fn main() !void {...@@ -292,8 +259,7 @@ pub fn main() !void {
292 builder.args = argsRest(args, arg_idx);259 builder.args = argsRest(args, arg_idx);
293 break;260 break;
294 } else {261 } else {
295 std.debug.print("Unrecognized argument: {s}\n\n", .{arg});262 fatalWithHint("unrecognized argument: '{s}'", .{arg});
296 usageAndErr(builder, false, stderr_stream);
297 }263 }
298 } else {264 } else {
299 try targets.append(arg);265 try targets.append(arg);
...@@ -319,8 +285,17 @@ pub fn main() !void {...@@ -319,8 +285,17 @@ pub fn main() !void {
319 try builder.runBuild(root);285 try builder.runBuild(root);
320 }286 }
321287
322 if (builder.validateUserInputDidItFail())288 if (builder.validateUserInputDidItFail()) {
323 usageAndErr(builder, true, stderr_stream);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
325 var run: Run = .{300 var run: Run = .{
326 .max_rss = max_rss,301 .max_rss = max_rss,
...@@ -389,7 +364,7 @@ fn runStepNames(...@@ -389,7 +364,7 @@ fn runStepNames(
389 for (0..step_names.len) |i| {364 for (0..step_names.len) |i| {
390 const step_name = step_names[step_names.len - i - 1];365 const step_name = step_names[step_names.len - i - 1];
391 const s = b.top_level_steps.get(step_name) orelse {366 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});
393 process.exit(1);368 process.exit(1);
394 };369 };
395 step_stack.putAssumeCapacity(&s.step, {});370 step_stack.putAssumeCapacity(&s.step, {});
...@@ -1037,13 +1012,7 @@ fn printErrorMessages(b: *std.Build, failing_step: *Step, run: *const Run) !void...@@ -1037,13 +1012,7 @@ fn printErrorMessages(b: *std.Build, failing_step: *Step, run: *const Run) !void
1037 }1012 }
1038}1013}
10391014
1040fn steps(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !void {1015fn steps(builder: *std.Build, 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
1047 const allocator = builder.allocator;1016 const allocator = builder.allocator;
1048 for (builder.top_level_steps.values()) |top_level_step| {1017 for (builder.top_level_steps.values()) |top_level_step| {
1049 const name = if (&top_level_step.step == builder.default_step)1018 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...@@ -1054,29 +1023,22 @@ fn steps(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
1054 }1023 }
1055}1024}
10561025
1057fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !void {1026fn usage(b: *std.Build, 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
1064 try out_stream.print(1027 try out_stream.print(
1065 \\
1066 \\Usage: {s} build [steps] [options]1028 \\Usage: {s} build [steps] [options]
1067 \\1029 \\
1068 \\Steps:1030 \\Steps:
1069 \\1031 \\
1070 , .{builder.zig_exe});1032 , .{b.zig_exe});
1071 try steps(builder, true, out_stream);1033 try steps(b, out_stream);
10721034
1073 try out_stream.writeAll(1035 try out_stream.writeAll(
1074 \\1036 \\
1075 \\General Options:1037 \\General Options:
1076 \\ -p, --prefix [path] Override default install prefix1038 \\ -p, --prefix [path] Where to put installed files (default: zig-out)
1077 \\ --prefix-lib-dir [path] Override default library directory path1039 \\ --prefix-lib-dir [path] Where to put installed libraries
1078 \\ --prefix-exe-dir [path] Override default executable directory path1040 \\ --prefix-exe-dir [path] Where to put installed executables
1079 \\ --prefix-include-dir [path] Override default include directory path1041 \\ --prefix-include-dir [path] Where to put installed C header files
1080 \\1042 \\
1081 \\ --sysroot [path] Set the system root directory (usually /)1043 \\ --sysroot [path] Set the system root directory (usually /)
1082 \\ --search-prefix [path] Add a path to look for binaries, libraries, headers1044 \\ --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...@@ -1116,16 +1078,15 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
1116 \\1078 \\
1117 );1079 );
11181080
1119 const allocator = builder.allocator;1081 const arena = b.allocator;
1120 if (builder.available_options_list.items.len == 0) {1082 if (b.available_options_list.items.len == 0) {
1121 try out_stream.print(" (none)\n", .{});1083 try out_stream.print(" (none)\n", .{});
1122 } else {1084 } else {
1123 for (builder.available_options_list.items) |option| {1085 for (b.available_options_list.items) |option| {
1124 const name = try fmt.allocPrint(allocator, " -D{s}=[{s}]", .{1086 const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{
1125 option.name,1087 option.name,
1126 @tagName(option.type_id),1088 @tagName(option.type_id),
1127 });1089 });
1128 defer allocator.free(name);
1129 try out_stream.print("{s:<30} {s}\n", .{ name, option.description });1090 try out_stream.print("{s:<30} {s}\n", .{ name, option.description });
1130 if (option.enum_options) |enum_options| {1091 if (option.enum_options) |enum_options| {
1131 const padding = " " ** 33;1092 const padding = " " ** 33;
...@@ -1137,6 +1098,31 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi...@@ -1137,6 +1098,31 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
1137 }1098 }
1138 }1099 }
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
1140 try out_stream.writeAll(1126 try out_stream.writeAll(
1141 \\1127 \\
1142 \\Advanced Options:1128 \\Advanced Options:
...@@ -1161,17 +1147,19 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi...@@ -1161,17 +1147,19 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
1161 );1147 );
1162}1148}
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
1169fn nextArg(args: [][:0]const u8, idx: *usize) ?[:0]const u8 {1150fn nextArg(args: [][:0]const u8, idx: *usize) ?[:0]const u8 {
1170 if (idx.* >= args.len) return null;1151 if (idx.* >= args.len) return null;
1171 defer idx.* += 1;1152 defer idx.* += 1;
1172 return args[idx.*];1153 return args[idx.*];
1173}1154}
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
1175fn argsRest(args: [][:0]const u8, idx: usize) ?[][:0]const u8 {1163fn argsRest(args: [][:0]const u8, idx: usize) ?[][:0]const u8 {
1176 if (idx >= args.len) return null;1164 if (idx >= args.len) return null;
1177 return args[idx..];1165 return args[idx..];
...@@ -1202,3 +1190,32 @@ fn renderOptions(ttyconf: std.io.tty.Config) std.zig.ErrorBundle.RenderOptions {...@@ -1202,3 +1190,32 @@ fn renderOptions(ttyconf: std.io.tty.Config) std.zig.ErrorBundle.RenderOptions {
1202 .include_reference_trace = ttyconf != .no_color,1190 .include_reference_trace = ttyconf != .no_color,
1203 };1191 };
1204}1192}
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,...@@ -28,6 +28,9 @@ allocator: Allocator,
28user_input_options: UserInputOptionsMap,28user_input_options: UserInputOptionsMap,
29available_options_map: AvailableOptionsMap,29available_options_map: AvailableOptionsMap,
30available_options_list: ArrayList(AvailableOption),30available_options_list: ArrayList(AvailableOption),
31/// All Build instances share this hash map.
32system_library_options: *std.StringArrayHashMapUnmanaged(SystemLibraryMode),
33system_package_mode: bool,
31verbose: bool,34verbose: bool,
32verbose_link: bool,35verbose_link: bool,
33verbose_cc: bool,36verbose_cc: bool,
...@@ -100,6 +103,21 @@ available_deps: AvailableDeps,...@@ -100,6 +103,21 @@ available_deps: AvailableDeps,
100103
101const AvailableDeps = []const struct { []const u8, []const u8 };104const 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
103const InitializedDepMap = std.HashMap(InitializedDepKey, *Dependency, InitializedDepContext, std.hash_map.default_max_load_percentage);121const InitializedDepMap = std.HashMap(InitializedDepKey, *Dependency, InitializedDepContext, std.hash_map.default_max_load_percentage);
104const InitializedDepKey = struct {122const InitializedDepKey = struct {
105 build_root_string: []const u8,123 build_root_string: []const u8,
...@@ -216,6 +234,7 @@ pub fn create(...@@ -216,6 +234,7 @@ pub fn create(
216 host: ResolvedTarget,234 host: ResolvedTarget,
217 cache: *Cache,235 cache: *Cache,
218 available_deps: AvailableDeps,236 available_deps: AvailableDeps,
237 system_library_options: *std.StringArrayHashMapUnmanaged(SystemLibraryMode),
219) !*Build {238) !*Build {
220 const env_map = try allocator.create(EnvMap);239 const env_map = try allocator.create(EnvMap);
221 env_map.* = try process.getEnvMap(allocator);240 env_map.* = try process.getEnvMap(allocator);
...@@ -278,6 +297,8 @@ pub fn create(...@@ -278,6 +297,8 @@ pub fn create(
278 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator),297 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator),
279 .initialized_deps = initialized_deps,298 .initialized_deps = initialized_deps,
280 .available_deps = available_deps,299 .available_deps = available_deps,
300 .system_library_options = system_library_options,
301 .system_package_mode = false,
281 };302 };
282 try self.top_level_steps.put(allocator, self.install_tls.step.name, &self.install_tls);303 try self.top_level_steps.put(allocator, self.install_tls.step.name, &self.install_tls);
283 try self.top_level_steps.put(allocator, self.uninstall_tls.step.name, &self.uninstall_tls);304 try self.top_level_steps.put(allocator, self.uninstall_tls.step.name, &self.uninstall_tls);
...@@ -297,7 +318,13 @@ fn createChild(...@@ -297,7 +318,13 @@ fn createChild(
297 return child;318 return child;
298}319}
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 {
301 const allocator = parent.allocator;328 const allocator = parent.allocator;
302 const child = try allocator.create(Build);329 const child = try allocator.create(Build);
303 child.* = .{330 child.* = .{
...@@ -366,6 +393,8 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc...@@ -366,6 +393,8 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc
366 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator),393 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator),
367 .initialized_deps = parent.initialized_deps,394 .initialized_deps = parent.initialized_deps,
368 .available_deps = pkg_deps,395 .available_deps = pkg_deps,
396 .system_library_options = parent.system_library_options,
397 .system_package_mode = parent.system_package_mode,
369 };398 };
370 try child.top_level_steps.put(allocator, child.install_tls.step.name, &child.install_tls);399 try child.top_level_steps.put(allocator, child.install_tls.step.name, &child.install_tls);
371 try child.top_level_steps.put(allocator, child.uninstall_tls.step.name, &child.uninstall_tls);400 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...@@ -1367,7 +1396,7 @@ pub fn addUserInputOption(self: *Build, name_raw: []const u8, value_raw: []const
1367 });1396 });
1368 },1397 },
1369 .flag => {1398 .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 });
1371 return true;1400 return true;
1372 },1401 },
1373 .map => |*map| {1402 .map => |*map| {
...@@ -1427,17 +1456,17 @@ fn markInvalidUserInput(self: *Build) void {...@@ -1427,17 +1456,17 @@ fn markInvalidUserInput(self: *Build) void {
1427 self.invalid_user_input = true;1456 self.invalid_user_input = true;
1428}1457}
14291458
1430pub fn validateUserInputDidItFail(self: *Build) bool {1459pub fn validateUserInputDidItFail(b: *Build) bool {
1431 // make sure all args are used1460 // Make sure all args are used.
1432 var it = self.user_input_options.iterator();1461 var it = b.user_input_options.iterator();
1433 while (it.next()) |entry| {1462 while (it.next()) |entry| {
1434 if (!entry.value_ptr.used) {1463 if (!entry.value_ptr.used) {
1435 log.err("Invalid option: -D{s}", .{entry.key_ptr.*});1464 log.err("invalid option: -D{s}", .{entry.key_ptr.*});
1436 self.markInvalidUserInput();1465 b.markInvalidUserInput();
1437 }1466 }
1438 }1467 }
14391468
1440 return self.invalid_user_input;1469 return b.invalid_user_input;
1441}1470}
14421471
1443fn allocPrintCmd(ally: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) ![]u8 {1472fn allocPrintCmd(ally: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) ![]u8 {
...@@ -2296,6 +2325,31 @@ pub fn wantSharedLibSymLinks(target: Target) bool {...@@ -2296,6 +2325,31 @@ pub fn wantSharedLibSymLinks(target: Target) bool {
2296 return target.os.tag != .windows;2325 return target.os.tag != .windows;
2297}2326}
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
2299test {2353test {
2300 _ = Cache;2354 _ = Cache;
2301 _ = Step;2355 _ = Step;