authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-02-04 01:44:12-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-02-04 01:44:12-08:00
logd3fc2648cc94f0e98ab1299711c02bb5b3f2864c
tree0b85fdd16ee2d07b7a0fb87a0ff51724f9f4b40c
parent9bf97b8494524074b1d3cfe71cd08aae335ba576
parent3dad7312b2c0f84c557b1cf01cfbbbaa04ffc79c
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #18778 from ziglang/system-package-mode

Implement system package mode and lazy dependencies

21 files changed, 1169 insertions(+), 719 deletions(-)

build.zig+2-2
......@@ -45,7 +45,7 @@ pub fn build(b: *std.Build) !void {
4545 });
4646
4747 const docgen_cmd = b.addRunArtifact(docgen_exe);
48 docgen_cmd.addArgs(&.{ "--zig", b.zig_exe });
48 docgen_cmd.addArgs(&.{ "--zig", b.graph.zig_exe });
4949 if (b.zig_lib_dir) |p| {
5050 docgen_cmd.addArg("--zig-lib-dir");
5151 docgen_cmd.addDirectoryArg(p);
......@@ -884,7 +884,7 @@ fn findConfigH(b: *std.Build, config_h_path_option: ?[]const u8) ?[]const u8 {
884884 }
885885 }
886886
887 var check_dir = fs.path.dirname(b.zig_exe).?;
887 var check_dir = fs.path.dirname(b.graph.zig_exe).?;
888888 while (true) {
889889 var dir = fs.cwd().openDir(check_dir, .{}) catch unreachable;
890890 defer dir.close();
deps/aro/build/GenerateDef.zig+1-1
......@@ -53,7 +53,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
5353 const self = @fieldParentPtr(GenerateDef, "step", step);
5454 const arena = b.allocator;
5555
56 var man = b.cache.obtain();
56 var man = b.graph.cache.obtain();
5757 defer man.deinit();
5858
5959 // Random bytes to make GenerateDef unique. Refresh this with new
lib/build_runner.zig+205-136
......@@ -46,11 +46,6 @@ pub fn main() !void {
4646 return error.InvalidArgs;
4747 };
4848
49 const host: std.Build.ResolvedTarget = .{
50 .query = .{},
51 .result = try std.zig.system.resolveTargetQuery(.{}),
52 };
53
5449 const build_root_directory: std.Build.Cache.Directory = .{
5550 .path = build_root,
5651 .handle = try std.fs.cwd().openDir(build_root, .{}),
......@@ -66,27 +61,29 @@ pub fn main() !void {
6661 .handle = try std.fs.cwd().makeOpenPath(global_cache_root, .{}),
6762 };
6863
69 var cache: std.Build.Cache = .{
70 .gpa = arena,
71 .manifest_dir = try local_cache_directory.handle.makeOpenPath("h", .{}),
64 var graph: std.Build.Graph = .{
65 .arena = arena,
66 .cache = .{
67 .gpa = arena,
68 .manifest_dir = try local_cache_directory.handle.makeOpenPath("h", .{}),
69 },
70 .zig_exe = zig_exe,
71 .env_map = try process.getEnvMap(arena),
72 .global_cache_root = global_cache_directory,
7273 };
73 cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
74 cache.addPrefix(build_root_directory);
75 cache.addPrefix(local_cache_directory);
76 cache.addPrefix(global_cache_directory);
77 cache.hash.addBytes(builtin.zig_version_string);
74
75 graph.cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
76 graph.cache.addPrefix(build_root_directory);
77 graph.cache.addPrefix(local_cache_directory);
78 graph.cache.addPrefix(global_cache_directory);
79 graph.cache.hash.addBytes(builtin.zig_version_string);
7880
7981 const builder = try std.Build.create(
80 arena,
81 zig_exe,
82 &graph,
8283 build_root_directory,
8384 local_cache_directory,
84 global_cache_directory,
85 host,
86 &cache,
8785 dependencies.root_deps,
8886 );
89 defer builder.destroy();
9087
9188 var targets = ArrayList([]const u8).init(arena);
9289 var debug_log_scopes = ArrayList([]const u8).init(arena);
......@@ -100,64 +97,67 @@ pub fn main() !void {
10097 var color: Color = .auto;
10198 var seed: u32 = 0;
10299 var prominent_compile_errors: bool = false;
103
104 const stderr_stream = io.getStdErr().writer();
105 const stdout_stream = io.getStdOut().writer();
100 var help_menu: bool = false;
101 var steps_menu: bool = false;
102 var output_tmp_nonce: ?[16]u8 = null;
106103
107104 while (nextArg(args, &arg_idx)) |arg| {
108 if (mem.startsWith(u8, arg, "-D")) {
105 if (mem.startsWith(u8, arg, "-Z")) {
106 if (arg.len != 18) fatalWithHint("bad argument: '{s}'", .{arg});
107 output_tmp_nonce = arg[2..18].*;
108 } else if (mem.startsWith(u8, arg, "-D")) {
109109 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 }
110 if (option_contents.len == 0)
111 fatalWithHint("expected option name after '-D'", .{});
114112 if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| {
115113 const option_name = option_contents[0..name_end];
116114 const option_value = option_contents[name_end + 1 ..];
117115 if (try builder.addUserInputOption(option_name, option_value))
118 usageAndErr(builder, false, stderr_stream);
116 fatal(" access the help menu with 'zig build -h'", .{});
119117 } else {
120118 if (try builder.addUserInputFlag(option_contents))
121 usageAndErr(builder, false, stderr_stream);
119 fatal(" access the help menu with 'zig build -h'", .{});
122120 }
123121 } else if (mem.startsWith(u8, arg, "-")) {
124122 if (mem.eql(u8, arg, "--verbose")) {
125123 builder.verbose = true;
126124 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
127 return usage(builder, false, stdout_stream);
125 help_menu = true;
128126 } 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 };
127 install_prefix = nextArgOrFatal(args, &arg_idx);
133128 } else if (mem.eql(u8, arg, "-l") or mem.eql(u8, arg, "--list-steps")) {
134 return steps(builder, false, stdout_stream);
135 } 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);
129 steps_menu = true;
130 } else if (mem.startsWith(u8, arg, "-fsys=")) {
131 const name = arg["-fsys=".len..];
132 graph.system_library_options.put(arena, name, .user_enabled) catch @panic("OOM");
133 } else if (mem.startsWith(u8, arg, "-fno-sys=")) {
134 const name = arg["-fno-sys=".len..];
135 graph.system_library_options.put(arena, name, .user_disabled) catch @panic("OOM");
136 } else if (mem.eql(u8, arg, "--release")) {
137 builder.release_mode = .any;
138 } else if (mem.startsWith(u8, arg, "--release=")) {
139 const text = arg["--release=".len..];
140 builder.release_mode = std.meta.stringToEnum(std.Build.ReleaseMode, text) orelse {
141 fatalWithHint("expected [off|any|fast|safe|small] in '{s}', found '{s}'", .{
142 arg, text,
143 });
139144 };
145 } else if (mem.eql(u8, arg, "--host-target")) {
146 graph.host_query_options.arch_os_abi = nextArgOrFatal(args, &arg_idx);
147 } else if (mem.eql(u8, arg, "--host-cpu")) {
148 graph.host_query_options.cpu_features = nextArgOrFatal(args, &arg_idx);
149 } else if (mem.eql(u8, arg, "--host-dynamic-linker")) {
150 graph.host_query_options.dynamic_linker = nextArgOrFatal(args, &arg_idx);
151 } else if (mem.eql(u8, arg, "--prefix-lib-dir")) {
152 dir_list.lib_dir = nextArgOrFatal(args, &arg_idx);
140153 } 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 };
154 dir_list.exe_dir = nextArgOrFatal(args, &arg_idx);
145155 } 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 };
156 dir_list.include_dir = nextArgOrFatal(args, &arg_idx);
150157 } 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;
158 builder.sysroot = nextArgOrFatal(args, &arg_idx);
156159 } 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 };
160 const max_rss_text = nextArgOrFatal(args, &arg_idx);
161161 max_rss = std.fmt.parseIntSizeSuffix(max_rss_text, 10) catch |err| {
162162 std.debug.print("invalid byte size: '{s}': {s}\n", .{
163163 max_rss_text, @errorName(err),
......@@ -167,66 +167,50 @@ pub fn main() !void {
167167 } else if (mem.eql(u8, arg, "--skip-oom-steps")) {
168168 skip_oom_steps = true;
169169 } 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 };
170 const search_prefix = nextArgOrFatal(args, &arg_idx);
174171 builder.addSearchPrefix(search_prefix);
175172 } 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;
173 builder.libc_file = nextArgOrFatal(args, &arg_idx);
181174 } 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 };
175 const next_arg = nextArg(args, &arg_idx) orelse
176 fatalWithHint("expected [auto|on|off] after '{s}'", .{arg});
186177 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);
178 fatalWithHint("expected [auto|on|off] after '{s}', found '{s}'", .{
179 arg, next_arg,
180 });
189181 };
190182 } 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 };
183 const next_arg = nextArg(args, &arg_idx) orelse
184 fatalWithHint("expected [all|failures|none] after '{s}'", .{arg});
195185 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);
186 fatalWithHint("expected [all|failures|none] after '{s}', found '{s}'", .{
187 arg, next_arg,
188 });
198189 };
199190 } 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 } };
191 builder.zig_lib_dir = .{ .cwd_relative = nextArgOrFatal(args, &arg_idx) };
204192 } 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 };
193 const next_arg = nextArg(args, &arg_idx) orelse
194 fatalWithHint("expected u32 after '{s}'", .{arg});
209195 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", .{
196 fatal("unable to parse seed '{s}' as 32-bit integer: {s}\n", .{
211197 next_arg, @errorName(err),
212198 });
213 process.exit(1);
214199 };
215200 } 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 };
201 const next_arg = nextArgOrFatal(args, &arg_idx);
220202 try debug_log_scopes.append(next_arg);
221203 } else if (mem.eql(u8, arg, "--debug-pkg-config")) {
222204 builder.debug_pkg_config = true;
223205 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
224206 builder.debug_compile_errors = true;
207 } else if (mem.eql(u8, arg, "--system")) {
208 // The usage text shows another argument after this parameter
209 // but it is handled by the parent process. The build runner
210 // only sees this flag.
211 graph.system_package_mode = true;
225212 } 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 };
213 builder.glibc_runtimes_dir = nextArgOrFatal(args, &arg_idx);
230214 } else if (mem.eql(u8, arg, "--verbose-link")) {
231215 builder.verbose_link = true;
232216 } else if (mem.eql(u8, arg, "--verbose-air")) {
......@@ -292,19 +276,26 @@ pub fn main() !void {
292276 builder.args = argsRest(args, arg_idx);
293277 break;
294278 } else {
295 std.debug.print("Unrecognized argument: {s}\n\n", .{arg});
296 usageAndErr(builder, false, stderr_stream);
279 fatalWithHint("unrecognized argument: '{s}'", .{arg});
297280 }
298281 } else {
299282 try targets.append(arg);
300283 }
301284 }
302285
286 const host_query = std.Build.parseTargetQuery(graph.host_query_options) catch |err| switch (err) {
287 error.ParseFailed => process.exit(1),
288 };
289 builder.host = .{
290 .query = .{},
291 .result = try std.zig.system.resolveTargetQuery(host_query),
292 };
293
303294 const stderr = std.io.getStdErr();
304295 const ttyconf = get_tty_conf(color, stderr);
305296 switch (ttyconf) {
306 .no_color => try builder.env_map.put("NO_COLOR", "1"),
307 .escape_codes => try builder.env_map.put("YES_COLOR", "1"),
297 .no_color => try graph.env_map.put("NO_COLOR", "1"),
298 .escape_codes => try graph.env_map.put("YES_COLOR", "1"),
308299 .windows_api => {},
309300 }
310301
......@@ -319,8 +310,39 @@ pub fn main() !void {
319310 try builder.runBuild(root);
320311 }
321312
322 if (builder.validateUserInputDidItFail())
323 usageAndErr(builder, true, stderr_stream);
313 if (graph.needed_lazy_dependencies.entries.len != 0) {
314 var buffer: std.ArrayListUnmanaged(u8) = .{};
315 for (graph.needed_lazy_dependencies.keys()) |k| {
316 try buffer.appendSlice(arena, k);
317 try buffer.append(arena, '\n');
318 }
319 const s = std.fs.path.sep_str;
320 const tmp_sub_path = "tmp" ++ s ++ (output_tmp_nonce orelse fatal("missing -Z arg", .{}));
321 local_cache_directory.handle.writeFile2(.{
322 .sub_path = tmp_sub_path,
323 .data = buffer.items,
324 .flags = .{ .exclusive = true },
325 }) catch |err| {
326 fatal("unable to write configuration results to '{}{s}': {s}", .{
327 local_cache_directory, tmp_sub_path, @errorName(err),
328 });
329 };
330 process.exit(3); // Indicate configure phase failed with meaningful stdout.
331 }
332
333 if (builder.validateUserInputDidItFail()) {
334 fatal(" access the help menu with 'zig build -h'", .{});
335 }
336
337 validateSystemLibraryOptions(builder);
338
339 const stdout_writer = io.getStdOut().writer();
340
341 if (help_menu)
342 return usage(builder, stdout_writer);
343
344 if (steps_menu)
345 return steps(builder, stdout_writer);
324346
325347 var run: Run = .{
326348 .max_rss = max_rss,
......@@ -389,7 +411,7 @@ fn runStepNames(
389411 for (0..step_names.len) |i| {
390412 const step_name = step_names[step_names.len - i - 1];
391413 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});
414 std.debug.print("no step named '{s}'\n access the help menu with 'zig build -h'\n", .{step_name});
393415 process.exit(1);
394416 };
395417 step_stack.putAssumeCapacity(&s.step, {});
......@@ -1037,13 +1059,7 @@ fn printErrorMessages(b: *std.Build, failing_step: *Step, run: *const Run) !void
10371059 }
10381060}
10391061
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
1062fn steps(builder: *std.Build, out_stream: anytype) !void {
10471063 const allocator = builder.allocator;
10481064 for (builder.top_level_steps.values()) |top_level_step| {
10491065 const name = if (&top_level_step.step == builder.default_step)
......@@ -1054,33 +1070,25 @@ fn steps(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
10541070 }
10551071}
10561072
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
1073fn usage(b: *std.Build, out_stream: anytype) !void {
10641074 try out_stream.print(
1065 \\
10661075 \\Usage: {s} build [steps] [options]
10671076 \\
10681077 \\Steps:
10691078 \\
1070 , .{builder.zig_exe});
1071 try steps(builder, true, out_stream);
1079 , .{b.graph.zig_exe});
1080 try steps(b, out_stream);
10721081
10731082 try out_stream.writeAll(
10741083 \\
10751084 \\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
1085 \\ -p, --prefix [path] Where to install files (default: zig-out)
1086 \\ --prefix-lib-dir [path] Where to install libraries
1087 \\ --prefix-exe-dir [path] Where to install executables
1088 \\ --prefix-include-dir [path] Where to install C header files
10801089 \\
1081 \\ --sysroot [path] Set the system root directory (usually /)
1082 \\ --search-prefix [path] Add a path to look for binaries, libraries, headers
1083 \\ --libc [file] Provide a file which specifies libc paths
1090 \\ --release[=mode] Request release mode, optionally specifying a
1091 \\ preferred optimization mode: fast, safe, small
10841092 \\
10851093 \\ -fdarling, -fno-darling Integration with system-installed Darling to
10861094 \\ execute macOS programs on Linux hosts
......@@ -1116,16 +1124,15 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
11161124 \\
11171125 );
11181126
1119 const allocator = builder.allocator;
1120 if (builder.available_options_list.items.len == 0) {
1127 const arena = b.allocator;
1128 if (b.available_options_list.items.len == 0) {
11211129 try out_stream.print(" (none)\n", .{});
11221130 } else {
1123 for (builder.available_options_list.items) |option| {
1124 const name = try fmt.allocPrint(allocator, " -D{s}=[{s}]", .{
1131 for (b.available_options_list.items) |option| {
1132 const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{
11251133 option.name,
11261134 @tagName(option.type_id),
11271135 });
1128 defer allocator.free(name);
11291136 try out_stream.print("{s:<30} {s}\n", .{ name, option.description });
11301137 if (option.enum_options) |enum_options| {
11311138 const padding = " " ** 33;
......@@ -1137,6 +1144,37 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
11371144 }
11381145 }
11391146
1147 try out_stream.writeAll(
1148 \\
1149 \\System Integration Options:
1150 \\ --search-prefix [path] Add a path to look for binaries, libraries, headers
1151 \\ --sysroot [path] Set the system root directory (usually /)
1152 \\ --libc [file] Provide a file which specifies libc paths
1153 \\
1154 \\ --host-target [triple] Use the provided target as the host
1155 \\ --host-cpu [cpu] Use the provided CPU as the host
1156 \\ --host-dynamic-linker [path] Use the provided dynamic linker as the host
1157 \\
1158 \\ --system [pkgdir] Disable package fetching; enable all integrations
1159 \\ -fsys=[name] Enable a system integration
1160 \\ -fno-sys=[name] Disable a system integration
1161 \\
1162 \\ Available System Integrations: Enabled:
1163 \\
1164 );
1165 if (b.graph.system_library_options.entries.len == 0) {
1166 try out_stream.writeAll(" (none) -\n");
1167 } else {
1168 for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| {
1169 const status = switch (v) {
1170 .declared_enabled => "yes",
1171 .declared_disabled => "no",
1172 .user_enabled, .user_disabled => unreachable, // already emitted error
1173 };
1174 try out_stream.print(" {s:<43} {s}\n", .{ k, status });
1175 }
1176 }
1177
11401178 try out_stream.writeAll(
11411179 \\
11421180 \\Advanced Options:
......@@ -1161,17 +1199,19 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
11611199 );
11621200}
11631201
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
11691202fn nextArg(args: [][:0]const u8, idx: *usize) ?[:0]const u8 {
11701203 if (idx.* >= args.len) return null;
11711204 defer idx.* += 1;
11721205 return args[idx.*];
11731206}
11741207
1208fn nextArgOrFatal(args: [][:0]const u8, idx: *usize) [:0]const u8 {
1209 return nextArg(args, idx) orelse {
1210 std.debug.print("expected argument after '{s}'\n access the help menu with 'zig build -h'\n", .{args[idx.*]});
1211 process.exit(1);
1212 };
1213}
1214
11751215fn argsRest(args: [][:0]const u8, idx: usize) ?[][:0]const u8 {
11761216 if (idx >= args.len) return null;
11771217 return args[idx..];
......@@ -1202,3 +1242,32 @@ fn renderOptions(ttyconf: std.io.tty.Config) std.zig.ErrorBundle.RenderOptions {
12021242 .include_reference_trace = ttyconf != .no_color,
12031243 };
12041244}
1245
1246fn fatalWithHint(comptime f: []const u8, args: anytype) noreturn {
1247 std.debug.print(f ++ "\n access the help menu with 'zig build -h'\n", args);
1248 process.exit(1);
1249}
1250
1251fn fatal(comptime f: []const u8, args: anytype) noreturn {
1252 std.debug.print(f ++ "\n", args);
1253 process.exit(1);
1254}
1255
1256fn validateSystemLibraryOptions(b: *std.Build) void {
1257 var bad = false;
1258 for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| {
1259 switch (v) {
1260 .user_disabled, .user_enabled => {
1261 // The user tried to enable or disable a system library integration, but
1262 // the build script did not recognize that option.
1263 std.debug.print("system library name not recognized by build script: '{s}'\n", .{k});
1264 bad = true;
1265 },
1266 .declared_disabled, .declared_enabled => {},
1267 }
1268 }
1269 if (bad) {
1270 std.debug.print(" access the help menu with 'zig build -h'\n", .{});
1271 process.exit(1);
1272 }
1273}
lib/std/Build.zig+250-113
......@@ -22,6 +22,8 @@ pub const Cache = @import("Build/Cache.zig");
2222pub const Step = @import("Build/Step.zig");
2323pub const Module = @import("Build/Module.zig");
2424
25/// Shared state among all Build instances.
26graph: *Graph,
2527install_tls: TopLevelStep,
2628uninstall_tls: TopLevelStep,
2729allocator: Allocator,
......@@ -38,9 +40,7 @@ verbose_cimport: bool,
3840verbose_llvm_cpu_features: bool,
3941reference_trace: ?u32 = null,
4042invalid_user_input: bool,
41zig_exe: [:0]const u8,
4243default_step: *Step,
43env_map: *EnvMap,
4444top_level_steps: std.StringArrayHashMapUnmanaged(*TopLevelStep),
4545install_prefix: []const u8,
4646dest_dir: ?[]const u8,
......@@ -49,14 +49,12 @@ exe_dir: []const u8,
4949h_dir: []const u8,
5050install_path: []const u8,
5151sysroot: ?[]const u8 = null,
52search_prefixes: ArrayList([]const u8),
52search_prefixes: std.ArrayListUnmanaged([]const u8),
5353libc_file: ?[]const u8 = null,
5454installed_files: ArrayList(InstalledFile),
5555/// Path to the directory containing build.zig.
5656build_root: Cache.Directory,
5757cache_root: Cache.Directory,
58global_cache_root: Cache.Directory,
59cache: *Cache,
6058zig_lib_dir: ?LazyPath,
6159pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null,
6260args: ?[][]const u8 = null,
......@@ -98,8 +96,47 @@ initialized_deps: *InitializedDepMap,
9896/// A mapping from dependency names to package hashes.
9997available_deps: AvailableDeps,
10098
99release_mode: ReleaseMode,
100
101pub const ReleaseMode = enum {
102 off,
103 any,
104 fast,
105 safe,
106 small,
107};
108
109/// Shared state among all Build instances.
110/// Settings that are here rather than in Build are not configurable per-package.
111pub const Graph = struct {
112 arena: Allocator,
113 system_library_options: std.StringArrayHashMapUnmanaged(SystemLibraryMode) = .{},
114 system_package_mode: bool = false,
115 cache: Cache,
116 zig_exe: [:0]const u8,
117 env_map: EnvMap,
118 global_cache_root: Cache.Directory,
119 host_query_options: std.Target.Query.ParseOptions = .{},
120 needed_lazy_dependencies: std.StringArrayHashMapUnmanaged(void) = .{},
121};
122
101123const AvailableDeps = []const struct { []const u8, []const u8 };
102124
125const SystemLibraryMode = enum {
126 /// User asked for the library to be disabled.
127 /// The build runner has not confirmed whether the setting is recognized yet.
128 user_disabled,
129 /// User asked for the library to be enabled.
130 /// The build runner has not confirmed whether the setting is recognized yet.
131 user_enabled,
132 /// The build runner has confirmed that this setting is recognized.
133 /// System integration with this library has been resolved to off.
134 declared_disabled,
135 /// The build runner has confirmed that this setting is recognized.
136 /// System integration with this library has been resolved to on.
137 declared_enabled,
138};
139
103140const InitializedDepMap = std.HashMap(InitializedDepKey, *Dependency, InitializedDepContext, std.hash_map.default_max_load_percentage);
104141const InitializedDepKey = struct {
105142 build_root_string: []const u8,
......@@ -208,28 +245,20 @@ pub const DirList = struct {
208245};
209246
210247pub fn create(
211 allocator: Allocator,
212 zig_exe: [:0]const u8,
248 graph: *Graph,
213249 build_root: Cache.Directory,
214250 cache_root: Cache.Directory,
215 global_cache_root: Cache.Directory,
216 host: ResolvedTarget,
217 cache: *Cache,
218251 available_deps: AvailableDeps,
219252) !*Build {
220 const env_map = try allocator.create(EnvMap);
221 env_map.* = try process.getEnvMap(allocator);
253 const arena = graph.arena;
254 const initialized_deps = try arena.create(InitializedDepMap);
255 initialized_deps.* = InitializedDepMap.initContext(arena, .{ .allocator = arena });
222256
223 const initialized_deps = try allocator.create(InitializedDepMap);
224 initialized_deps.* = InitializedDepMap.initContext(allocator, .{ .allocator = allocator });
225
226 const self = try allocator.create(Build);
257 const self = try arena.create(Build);
227258 self.* = .{
228 .zig_exe = zig_exe,
259 .graph = graph,
229260 .build_root = build_root,
230261 .cache_root = cache_root,
231 .global_cache_root = global_cache_root,
232 .cache = cache,
233262 .verbose = false,
234263 .verbose_link = false,
235264 .verbose_cc = false,
......@@ -239,20 +268,19 @@ pub fn create(
239268 .verbose_cimport = false,
240269 .verbose_llvm_cpu_features = false,
241270 .invalid_user_input = false,
242 .allocator = allocator,
243 .user_input_options = UserInputOptionsMap.init(allocator),
244 .available_options_map = AvailableOptionsMap.init(allocator),
245 .available_options_list = ArrayList(AvailableOption).init(allocator),
271 .allocator = arena,
272 .user_input_options = UserInputOptionsMap.init(arena),
273 .available_options_map = AvailableOptionsMap.init(arena),
274 .available_options_list = ArrayList(AvailableOption).init(arena),
246275 .top_level_steps = .{},
247276 .default_step = undefined,
248 .env_map = env_map,
249 .search_prefixes = ArrayList([]const u8).init(allocator),
277 .search_prefixes = .{},
250278 .install_prefix = undefined,
251279 .lib_dir = undefined,
252280 .exe_dir = undefined,
253281 .h_dir = undefined,
254 .dest_dir = env_map.get("DESTDIR"),
255 .installed_files = ArrayList(InstalledFile).init(allocator),
282 .dest_dir = graph.env_map.get("DESTDIR"),
283 .installed_files = ArrayList(InstalledFile).init(arena),
256284 .install_tls = .{
257285 .step = Step.init(.{
258286 .id = .top_level,
......@@ -273,14 +301,15 @@ pub fn create(
273301 .zig_lib_dir = null,
274302 .install_path = undefined,
275303 .args = null,
276 .host = host,
277 .modules = std.StringArrayHashMap(*Module).init(allocator),
278 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator),
304 .host = undefined,
305 .modules = std.StringArrayHashMap(*Module).init(arena),
306 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(arena),
279307 .initialized_deps = initialized_deps,
280308 .available_deps = available_deps,
309 .release_mode = .off,
281310 };
282 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);
311 try self.top_level_steps.put(arena, self.install_tls.step.name, &self.install_tls);
312 try self.top_level_steps.put(arena, self.uninstall_tls.step.name, &self.uninstall_tls);
284313 self.default_step = &self.install_tls.step;
285314 return self;
286315}
......@@ -297,10 +326,17 @@ fn createChild(
297326 return child;
298327}
299328
300fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Directory, pkg_deps: AvailableDeps, user_input_options: UserInputOptionsMap) !*Build {
329fn createChildOnly(
330 parent: *Build,
331 dep_name: []const u8,
332 build_root: Cache.Directory,
333 pkg_deps: AvailableDeps,
334 user_input_options: UserInputOptionsMap,
335) !*Build {
301336 const allocator = parent.allocator;
302337 const child = try allocator.create(Build);
303338 child.* = .{
339 .graph = parent.graph,
304340 .allocator = allocator,
305341 .install_tls = .{
306342 .step = Step.init(.{
......@@ -332,9 +368,7 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc
332368 .verbose_llvm_cpu_features = parent.verbose_llvm_cpu_features,
333369 .reference_trace = parent.reference_trace,
334370 .invalid_user_input = false,
335 .zig_exe = parent.zig_exe,
336371 .default_step = undefined,
337 .env_map = parent.env_map,
338372 .top_level_steps = .{},
339373 .install_prefix = undefined,
340374 .dest_dir = parent.dest_dir,
......@@ -348,8 +382,6 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc
348382 .installed_files = ArrayList(InstalledFile).init(allocator),
349383 .build_root = build_root,
350384 .cache_root = parent.cache_root,
351 .global_cache_root = parent.global_cache_root,
352 .cache = parent.cache,
353385 .zig_lib_dir = parent.zig_lib_dir,
354386 .debug_log_scopes = parent.debug_log_scopes,
355387 .debug_compile_errors = parent.debug_compile_errors,
......@@ -366,6 +398,7 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc
366398 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator),
367399 .initialized_deps = parent.initialized_deps,
368400 .available_deps = pkg_deps,
401 .release_mode = parent.release_mode,
369402 };
370403 try child.top_level_steps.put(allocator, child.install_tls.step.name, &child.install_tls);
371404 try child.top_level_steps.put(allocator, child.uninstall_tls.step.name, &child.uninstall_tls);
......@@ -543,7 +576,7 @@ fn hashUserInputOptionsMap(allocator: Allocator, user_input_options: UserInputOp
543576fn determineAndApplyInstallPrefix(b: *Build) !void {
544577 // Create an installation directory local to this package. This will be used when
545578 // dependant packages require a standard prefix, such as include directories for C headers.
546 var hash = b.cache.hash;
579 var hash = b.graph.cache.hash;
547580 // Random bytes to make unique. Refresh this with new random bytes when
548581 // implementation is modified in a non-backwards-compatible way.
549582 hash.add(@as(u32, 0xd8cb0055));
......@@ -558,12 +591,6 @@ fn determineAndApplyInstallPrefix(b: *Build) !void {
558591 b.resolveInstallPrefix(install_prefix, .{});
559592}
560593
561pub fn destroy(b: *Build) void {
562 b.env_map.deinit();
563 b.top_level_steps.deinit(b.allocator);
564 b.allocator.destroy(b);
565}
566
567594/// This function is intended to be called by lib/build_runner.zig, not a build.zig file.
568595pub fn resolveInstallPrefix(self: *Build, install_prefix: ?[]const u8, dir_list: DirList) void {
569596 if (self.dest_dir) |dest_dir| {
......@@ -1216,20 +1243,33 @@ pub const StandardOptimizeOptionOptions = struct {
12161243 preferred_optimize_mode: ?std.builtin.OptimizeMode = null,
12171244};
12181245
1219pub fn standardOptimizeOption(self: *Build, options: StandardOptimizeOptionOptions) std.builtin.OptimizeMode {
1246pub fn standardOptimizeOption(b: *Build, options: StandardOptimizeOptionOptions) std.builtin.OptimizeMode {
12201247 if (options.preferred_optimize_mode) |mode| {
1221 if (self.option(bool, "release", "optimize for end users") orelse false) {
1248 if (b.option(bool, "release", "optimize for end users") orelse (b.release_mode != .off)) {
12221249 return mode;
12231250 } else {
12241251 return .Debug;
12251252 }
1226 } else {
1227 return self.option(
1228 std.builtin.OptimizeMode,
1229 "optimize",
1230 "Prioritize performance, safety, or binary size (-O flag)",
1231 ) orelse .Debug;
12321253 }
1254
1255 if (b.option(
1256 std.builtin.OptimizeMode,
1257 "optimize",
1258 "Prioritize performance, safety, or binary size",
1259 )) |mode| {
1260 return mode;
1261 }
1262
1263 return switch (b.release_mode) {
1264 .off => .Debug,
1265 .any => {
1266 std.debug.print("the project does not declare a preferred optimization mode. choose: --release=fast, --release=safe, or --release=small\n", .{});
1267 process.exit(1);
1268 },
1269 .fast => .ReleaseFast,
1270 .safe => .ReleaseSafe,
1271 .small => .ReleaseSmall,
1272 };
12331273}
12341274
12351275pub const StandardTargetOptionsArgs = struct {
......@@ -1244,67 +1284,83 @@ pub fn standardTargetOptions(b: *Build, args: StandardTargetOptionsArgs) Resolve
12441284 return b.resolveTargetQuery(query);
12451285}
12461286
1247/// Exposes standard `zig build` options for choosing a target.
1248pub fn standardTargetOptionsQueryOnly(b: *Build, args: StandardTargetOptionsArgs) Target.Query {
1249 const maybe_triple = b.option(
1250 []const u8,
1251 "target",
1252 "The CPU architecture, OS, and ABI to build for",
1253 );
1254 const mcpu = b.option([]const u8, "cpu", "Target CPU features to add or subtract");
1255
1256 if (maybe_triple == null and mcpu == null) {
1257 return args.default_target;
1258 }
1259
1260 const triple = maybe_triple orelse "native";
1261
1287pub fn parseTargetQuery(options: std.Target.Query.ParseOptions) error{ParseFailed}!std.Target.Query {
12621288 var diags: Target.Query.ParseOptions.Diagnostics = .{};
1263 const selected_target = Target.Query.parse(.{
1264 .arch_os_abi = triple,
1265 .cpu_features = mcpu,
1266 .diagnostics = &diags,
1267 }) catch |err| switch (err) {
1289 var opts_copy = options;
1290 opts_copy.diagnostics = &diags;
1291 return std.Target.Query.parse(options) catch |err| switch (err) {
12681292 error.UnknownCpuModel => {
1269 log.err("Unknown CPU: '{s}'\nAvailable CPUs for architecture '{s}':", .{
1270 diags.cpu_name.?,
1271 @tagName(diags.arch.?),
1293 std.debug.print("unknown CPU: '{s}'\navailable CPUs for architecture '{s}':\n", .{
1294 diags.cpu_name.?, @tagName(diags.arch.?),
12721295 });
12731296 for (diags.arch.?.allCpuModels()) |cpu| {
1274 log.err(" {s}", .{cpu.name});
1297 std.debug.print(" {s}\n", .{cpu.name});
12751298 }
1276 b.markInvalidUserInput();
1277 return args.default_target;
1299 return error.ParseFailed;
12781300 },
12791301 error.UnknownCpuFeature => {
1280 log.err(
1281 \\Unknown CPU feature: '{s}'
1282 \\Available CPU features for architecture '{s}':
1302 std.debug.print(
1303 \\unknown CPU feature: '{s}'
1304 \\available CPU features for architecture '{s}':
12831305 \\
12841306 , .{
12851307 diags.unknown_feature_name.?,
12861308 @tagName(diags.arch.?),
12871309 });
12881310 for (diags.arch.?.allFeaturesList()) |feature| {
1289 log.err(" {s}: {s}", .{ feature.name, feature.description });
1311 std.debug.print(" {s}: {s}\n", .{ feature.name, feature.description });
12901312 }
1291 b.markInvalidUserInput();
1292 return args.default_target;
1313 return error.ParseFailed;
12931314 },
12941315 error.UnknownOperatingSystem => {
1295 log.err(
1296 \\Unknown OS: '{s}'
1297 \\Available operating systems:
1316 std.debug.print(
1317 \\unknown OS: '{s}'
1318 \\available operating systems:
12981319 \\
12991320 , .{diags.os_name.?});
13001321 inline for (std.meta.fields(Target.Os.Tag)) |field| {
1301 log.err(" {s}", .{field.name});
1322 std.debug.print(" {s}\n", .{field.name});
13021323 }
1303 b.markInvalidUserInput();
1304 return args.default_target;
1324 return error.ParseFailed;
13051325 },
13061326 else => |e| {
1307 log.err("Unable to parse target '{s}': {s}\n", .{ triple, @errorName(e) });
1327 std.debug.print("unable to parse target '{s}': {s}\n", .{
1328 options.arch_os_abi, @errorName(e),
1329 });
1330 return error.ParseFailed;
1331 },
1332 };
1333}
1334
1335/// Exposes standard `zig build` options for choosing a target.
1336pub fn standardTargetOptionsQueryOnly(b: *Build, args: StandardTargetOptionsArgs) Target.Query {
1337 const maybe_triple = b.option(
1338 []const u8,
1339 "target",
1340 "The CPU architecture, OS, and ABI to build for",
1341 );
1342 const mcpu = b.option(
1343 []const u8,
1344 "cpu",
1345 "Target CPU features to add or subtract",
1346 );
1347 const dynamic_linker = b.option(
1348 []const u8,
1349 "dynamic-linker",
1350 "Path to interpreter on the target system",
1351 );
1352
1353 if (maybe_triple == null and mcpu == null and dynamic_linker == null)
1354 return args.default_target;
1355
1356 const triple = maybe_triple orelse "native";
1357
1358 const selected_target = parseTargetQuery(.{
1359 .arch_os_abi = triple,
1360 .cpu_features = mcpu,
1361 .dynamic_linker = dynamic_linker,
1362 }) catch |err| switch (err) {
1363 error.ParseFailed => {
13081364 b.markInvalidUserInput();
13091365 return args.default_target;
13101366 },
......@@ -1367,7 +1423,7 @@ pub fn addUserInputOption(self: *Build, name_raw: []const u8, value_raw: []const
13671423 });
13681424 },
13691425 .flag => {
1370 log.warn("Option '-D{s}={s}' conflicts with flag '-D{s}'.", .{ name, value, name });
1426 log.warn("option '-D{s}={s}' conflicts with flag '-D{s}'.", .{ name, value, name });
13711427 return true;
13721428 },
13731429 .map => |*map| {
......@@ -1427,17 +1483,17 @@ fn markInvalidUserInput(self: *Build) void {
14271483 self.invalid_user_input = true;
14281484}
14291485
1430pub fn validateUserInputDidItFail(self: *Build) bool {
1431 // make sure all args are used
1432 var it = self.user_input_options.iterator();
1486pub fn validateUserInputDidItFail(b: *Build) bool {
1487 // Make sure all args are used.
1488 var it = b.user_input_options.iterator();
14331489 while (it.next()) |entry| {
14341490 if (!entry.value_ptr.used) {
1435 log.err("Invalid option: -D{s}", .{entry.key_ptr.*});
1436 self.markInvalidUserInput();
1491 log.err("invalid option: -D{s}", .{entry.key_ptr.*});
1492 b.markInvalidUserInput();
14371493 }
14381494 }
14391495
1440 return self.invalid_user_input;
1496 return b.invalid_user_input;
14411497}
14421498
14431499fn allocPrintCmd(ally: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) ![]u8 {
......@@ -1593,7 +1649,7 @@ pub fn findProgram(self: *Build, names: []const []const u8, paths: []const []con
15931649 return fs.realpathAlloc(self.allocator, full_path) catch continue;
15941650 }
15951651 }
1596 if (self.env_map.get("PATH")) |PATH| {
1652 if (self.graph.env_map.get("PATH")) |PATH| {
15971653 for (names) |name| {
15981654 if (fs.path.isAbsolute(name)) {
15991655 return name;
......@@ -1639,7 +1695,7 @@ pub fn runAllowFail(
16391695 child.stdin_behavior = .Ignore;
16401696 child.stdout_behavior = .Pipe;
16411697 child.stderr_behavior = stderr_behavior;
1642 child.env_map = self.env_map;
1698 child.env_map = &self.graph.env_map;
16431699
16441700 try child.spawn();
16451701
......@@ -1685,8 +1741,8 @@ pub fn run(b: *Build, argv: []const []const u8) []u8 {
16851741 };
16861742}
16871743
1688pub fn addSearchPrefix(self: *Build, search_prefix: []const u8) void {
1689 self.search_prefixes.append(self.dupePath(search_prefix)) catch @panic("OOM");
1744pub fn addSearchPrefix(b: *Build, search_prefix: []const u8) void {
1745 b.search_prefixes.append(b.allocator, b.dupePath(search_prefix)) catch @panic("OOM");
16901746}
16911747
16921748pub fn getInstallPath(self: *Build, dir: InstallDir, dest_rel_path: []const u8) []const u8 {
......@@ -1747,21 +1803,63 @@ pub const Dependency = struct {
17471803 }
17481804};
17491805
1750pub fn dependency(b: *Build, name: []const u8, args: anytype) *Dependency {
1806fn findPkgHashOrFatal(b: *Build, name: []const u8) []const u8 {
1807 for (b.available_deps) |dep| {
1808 if (mem.eql(u8, dep[0], name)) return dep[1];
1809 }
1810
1811 const full_path = b.pathFromRoot("build.zig.zon");
1812 std.debug.panic("no dependency named '{s}' in '{s}'. All packages used in build.zig must be declared in this file", .{ name, full_path });
1813}
1814
1815fn markNeededLazyDep(b: *Build, pkg_hash: []const u8) void {
1816 b.graph.needed_lazy_dependencies.put(b.graph.arena, pkg_hash, {}) catch @panic("OOM");
1817}
1818
1819/// When this function is called, it means that the current build does, in
1820/// fact, require this dependency. If the dependency is already fetched, it
1821/// proceeds in the same manner as `dependency`. However if the dependency was
1822/// not fetched, then when the build script is finished running, the build will
1823/// not proceed to the make phase. Instead, the parent process will
1824/// additionally fetch all the lazy dependencies that were actually required by
1825/// running the build script, rebuild the build script, and then run it again.
1826/// In other words, if this function returns `null` it means that the only
1827/// purpose of completing the configure phase is to find out all the other lazy
1828/// dependencies that are also required.
1829/// It is allowed to use this function for non-lazy dependencies, in which case
1830/// it will never return `null`. This allows toggling laziness via
1831/// build.zig.zon without changing build.zig logic.
1832pub fn lazyDependency(b: *Build, name: []const u8, args: anytype) ?*Dependency {
17511833 const build_runner = @import("root");
17521834 const deps = build_runner.dependencies;
1835 const pkg_hash = findPkgHashOrFatal(b, name);
17531836
1754 const pkg_hash = for (b.available_deps) |dep| {
1755 if (mem.eql(u8, dep[0], name)) break dep[1];
1756 } else {
1757 const full_path = b.pathFromRoot("build.zig.zon");
1758 std.debug.print("no dependency named '{s}' in '{s}'. All packages used in build.zig must be declared in this file.\n", .{ name, full_path });
1759 process.exit(1);
1760 };
1837 inline for (@typeInfo(deps.packages).Struct.decls) |decl| {
1838 if (mem.eql(u8, decl.name, pkg_hash)) {
1839 const pkg = @field(deps.packages, decl.name);
1840 const available = !@hasDecl(pkg, "available") or pkg.available;
1841 if (!available) {
1842 markNeededLazyDep(b, pkg_hash);
1843 return null;
1844 }
1845 return dependencyInner(b, name, pkg.build_root, if (@hasDecl(pkg, "build_zig")) pkg.build_zig else null, pkg.deps, args);
1846 }
1847 }
1848
1849 unreachable; // Bad @dependencies source
1850}
1851
1852pub fn dependency(b: *Build, name: []const u8, args: anytype) *Dependency {
1853 const build_runner = @import("root");
1854 const deps = build_runner.dependencies;
1855 const pkg_hash = findPkgHashOrFatal(b, name);
17611856
17621857 inline for (@typeInfo(deps.packages).Struct.decls) |decl| {
17631858 if (mem.eql(u8, decl.name, pkg_hash)) {
17641859 const pkg = @field(deps.packages, decl.name);
1860 if (@hasDecl(pkg, "available")) {
1861 std.debug.panic("dependency '{s}{s}' is marked as lazy in build.zig.zon which means it must use the lazyDependency function instead", .{ b.dep_prefix, name });
1862 }
17651863 return dependencyInner(b, name, pkg.build_root, if (@hasDecl(pkg, "build_zig")) pkg.build_zig else null, pkg.deps, args);
17661864 }
17671865 }
......@@ -2281,9 +2379,14 @@ pub const ResolvedTarget = struct {
22812379/// Converts a target query into a fully resolved target that can be passed to
22822380/// various parts of the API.
22832381pub fn resolveTargetQuery(b: *Build, query: Target.Query) ResolvedTarget {
2284 // This context will likely be required in the future when the target is
2285 // resolved via a WASI API or via the build protocol.
2286 _ = b;
2382 if (query.isNative()) {
2383 var adjusted = b.host;
2384 if (query.ofmt) |ofmt| {
2385 adjusted.query.ofmt = ofmt;
2386 adjusted.result.ofmt = ofmt;
2387 }
2388 return adjusted;
2389 }
22872390
22882391 return .{
22892392 .query = query,
......@@ -2296,6 +2399,40 @@ pub fn wantSharedLibSymLinks(target: Target) bool {
22962399 return target.os.tag != .windows;
22972400}
22982401
2402pub const SystemIntegrationOptionConfig = struct {
2403 /// If left as null, then the default will depend on system_package_mode.
2404 default: ?bool = null,
2405};
2406
2407pub fn systemIntegrationOption(
2408 b: *Build,
2409 name: []const u8,
2410 config: SystemIntegrationOptionConfig,
2411) bool {
2412 const gop = b.graph.system_library_options.getOrPut(b.allocator, name) catch @panic("OOM");
2413 if (gop.found_existing) switch (gop.value_ptr.*) {
2414 .user_disabled => {
2415 gop.value_ptr.* = .declared_disabled;
2416 return false;
2417 },
2418 .user_enabled => {
2419 gop.value_ptr.* = .declared_enabled;
2420 return true;
2421 },
2422 .declared_disabled => return false,
2423 .declared_enabled => return true,
2424 } else {
2425 gop.key_ptr.* = b.dupe(name);
2426 if (config.default orelse b.graph.system_package_mode) {
2427 gop.value_ptr.* = .declared_enabled;
2428 return true;
2429 } else {
2430 gop.value_ptr.* = .declared_disabled;
2431 return false;
2432 }
2433 }
2434}
2435
22992436test {
23002437 _ = Cache;
23012438 _ = Step;
lib/std/Build/Step.zig+1-1
......@@ -314,7 +314,7 @@ pub fn evalZigProcess(
314314 try handleVerbose(s.owner, null, argv);
315315
316316 var child = std.ChildProcess.init(argv, arena);
317 child.env_map = b.env_map;
317 child.env_map = &b.graph.env_map;
318318 child.stdin_behavior = .Pipe;
319319 child.stdout_behavior = .Pipe;
320320 child.stderr_behavior = .Pipe;
lib/std/Build/Step/Compile.zig+12-2
......@@ -923,7 +923,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
923923 var zig_args = ArrayList([]const u8).init(arena);
924924 defer zig_args.deinit();
925925
926 try zig_args.append(b.zig_exe);
926 try zig_args.append(b.graph.zig_exe);
927927
928928 const cmd = switch (self.kind) {
929929 .lib => "build-lib",
......@@ -933,6 +933,16 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
933933 };
934934 try zig_args.append(cmd);
935935
936 if (!mem.eql(u8, b.graph.host_query_options.arch_os_abi, "native")) {
937 try zig_args.appendSlice(&.{ "--host-target", b.graph.host_query_options.arch_os_abi });
938 }
939 if (b.graph.host_query_options.cpu_features) |cpu| {
940 try zig_args.appendSlice(&.{ "--host-cpu", cpu });
941 }
942 if (b.graph.host_query_options.dynamic_linker) |dl| {
943 try zig_args.appendSlice(&.{ "--host-dynamic-linker", dl });
944 }
945
936946 if (b.reference_trace) |some| {
937947 try zig_args.append(try std.fmt.allocPrint(arena, "-freference-trace={d}", .{some}));
938948 }
......@@ -1393,7 +1403,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
13931403 try zig_args.append(b.cache_root.path orelse ".");
13941404
13951405 try zig_args.append("--global-cache-dir");
1396 try zig_args.append(b.global_cache_root.path orelse ".");
1406 try zig_args.append(b.graph.global_cache_root.path orelse ".");
13971407
13981408 try zig_args.append("--name");
13991409 try zig_args.append(self.name);
lib/std/Build/Step/ConfigHeader.zig+1-1
......@@ -171,7 +171,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
171171 const gpa = b.allocator;
172172 const arena = b.allocator;
173173
174 var man = b.cache.obtain();
174 var man = b.graph.cache.obtain();
175175 defer man.deinit();
176176
177177 // Random bytes to make ConfigHeader unique. Refresh this with new
lib/std/Build/Step/Fmt.zig+1-1
......@@ -52,7 +52,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
5252 var argv: std.ArrayListUnmanaged([]const u8) = .{};
5353 try argv.ensureUnusedCapacity(arena, 2 + 1 + self.paths.len + 2 * self.exclude_paths.len);
5454
55 argv.appendAssumeCapacity(b.zig_exe);
55 argv.appendAssumeCapacity(b.graph.zig_exe);
5656 argv.appendAssumeCapacity("fmt");
5757
5858 if (self.check) {
lib/std/Build/Step/ObjCopy.zig+2-2
......@@ -94,7 +94,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
9494 const b = step.owner;
9595 const self = @fieldParentPtr(ObjCopy, "step", step);
9696
97 var man = b.cache.obtain();
97 var man = b.graph.cache.obtain();
9898 defer man.deinit();
9999
100100 // Random bytes to make ObjCopy unique. Refresh this with new random
......@@ -133,7 +133,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
133133 };
134134
135135 var argv = std.ArrayList([]const u8).init(b.allocator);
136 try argv.appendSlice(&.{ b.zig_exe, "objcopy" });
136 try argv.appendSlice(&.{ b.graph.zig_exe, "objcopy" });
137137
138138 if (self.only_section) |only_section| {
139139 try argv.appendSlice(&.{ "-j", only_section });
lib/std/Build/Step/Options.zig+16-15
......@@ -222,7 +222,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
222222 const basename = "options.zig";
223223
224224 // Hash contents to file name.
225 var hash = b.cache.hash;
225 var hash = b.graph.cache.hash;
226226 // Random bytes to make unique. Refresh this with new random bytes when
227227 // implementation is modified in a non-backwards-compatible way.
228228 hash.add(@as(u32, 0xad95e922));
......@@ -301,27 +301,28 @@ test Options {
301301 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
302302 defer arena.deinit();
303303
304 const host: std.Build.ResolvedTarget = .{
305 .query = .{},
306 .result = try std.zig.system.resolveTargetQuery(.{}),
307 };
308
309 var cache: std.Build.Cache = .{
310 .gpa = arena.allocator(),
311 .manifest_dir = std.fs.cwd(),
304 var graph: std.Build.Graph = .{
305 .arena = arena.allocator(),
306 .cache = .{
307 .gpa = arena.allocator(),
308 .manifest_dir = std.fs.cwd(),
309 },
310 .zig_exe = "test",
311 .env_map = std.process.EnvMap.init(arena.allocator()),
312 .global_cache_root = .{ .path = "test", .handle = std.fs.cwd() },
312313 };
313314
314315 var builder = try std.Build.create(
315 arena.allocator(),
316 "test",
316 &graph,
317317 .{ .path = "test", .handle = std.fs.cwd() },
318318 .{ .path = "test", .handle = std.fs.cwd() },
319 .{ .path = "test", .handle = std.fs.cwd() },
320 host,
321 &cache,
322319 &.{},
323320 );
324 defer builder.destroy();
321
322 builder.host = .{
323 .query = .{},
324 .result = try std.zig.system.resolveTargetQuery(.{}),
325 };
325326
326327 const options = builder.addOptions();
327328
lib/std/Build/Step/Run.zig+2-2
......@@ -463,7 +463,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
463463 var argv_list = ArrayList([]const u8).init(arena);
464464 var output_placeholders = ArrayList(IndexedOutput).init(arena);
465465
466 var man = b.cache.obtain();
466 var man = b.graph.cache.obtain();
467467 defer man.deinit();
468468
469469 for (self.argv.items) |arg| {
......@@ -1036,7 +1036,7 @@ fn spawnChildAndCollect(
10361036 child.cwd = b.build_root.path;
10371037 child.cwd_dir = b.build_root.handle;
10381038 }
1039 child.env_map = self.env_map orelse b.env_map;
1039 child.env_map = self.env_map orelse &b.graph.env_map;
10401040 child.request_resource_usage_statistics = true;
10411041
10421042 child.stdin_behavior = switch (self.stdio) {
lib/std/Build/Step/TranslateC.zig+1-1
......@@ -121,7 +121,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
121121 const self = @fieldParentPtr(TranslateC, "step", step);
122122
123123 var argv_list = std.ArrayList([]const u8).init(b.allocator);
124 try argv_list.append(b.zig_exe);
124 try argv_list.append(b.graph.zig_exe);
125125 try argv_list.append("translate-c");
126126 if (self.link_libc) {
127127 try argv_list.append("-lc");
lib/std/Build/Step/WriteFile.zig+1-1
......@@ -190,7 +190,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
190190 // If, for example, a hard-coded path was used as the location to put WriteFile
191191 // files, then two WriteFiles executing in parallel might clobber each other.
192192
193 var man = b.cache.obtain();
193 var man = b.graph.cache.obtain();
194194 defer man.deinit();
195195
196196 // Random bytes to make WriteFile unique. Refresh this with
lib/std/Target/Query.zig+1-1
......@@ -468,7 +468,7 @@ pub fn zigTriple(self: Query, allocator: Allocator) Allocator.Error![]u8 {
468468 }
469469
470470 if (self.glibc_version) |v| {
471 const name = @tagName(self.abi orelse builtin.target.abi);
471 const name = if (self.abi) |abi| @tagName(abi) else "gnu";
472472 try result.ensureUnusedCapacity(name.len + 2);
473473 result.appendAssumeCapacity('-');
474474 result.appendSliceAssumeCapacity(name);
lib/std/child_process.zig+3-1
......@@ -298,7 +298,9 @@ pub const ChildProcess = struct {
298298 // we could make this work with multiple allocators but YAGNI
299299 if (stdout.allocator.ptr != stderr.allocator.ptr or
300300 stdout.allocator.vtable != stderr.allocator.vtable)
301 @panic("ChildProcess.collectOutput only supports 1 allocator");
301 {
302 unreachable; // ChildProcess.collectOutput only supports 1 allocator
303 }
302304
303305 var poller = std.io.poll(stdout.allocator, enum { stdout, stderr }, .{
304306 .stdout = child.stdout.?,
src/Compilation.zig+3
......@@ -4530,6 +4530,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
45304530 log.err("{}: failed to parse clang diagnostics: {s}", .{ err, stderr });
45314531 return comp.failCObj(c_object, "clang exited with code {d}", .{code});
45324532 };
4533 zig_cache_tmp_dir.deleteFile(out_diag_path) catch |err| {
4534 log.warn("failed to delete '{s}': {s}", .{ out_diag_path, @errorName(err) });
4535 };
45334536 return comp.failCObjWithOwnedDiagBundle(c_object, bundle);
45344537 }
45354538 },
src/Package/Fetch.zig+81-4
......@@ -31,6 +31,8 @@ arena: std.heap.ArenaAllocator,
3131location: Location,
3232location_tok: std.zig.Ast.TokenIndex,
3333hash_tok: std.zig.Ast.TokenIndex,
34name_tok: std.zig.Ast.TokenIndex,
35lazy_status: LazyStatus,
3436parent_package_root: Package.Path,
3537parent_manifest_ast: ?*const std.zig.Ast,
3638prog_node: *std.Progress.Node,
......@@ -64,6 +66,15 @@ oom_flag: bool,
6466/// the root source file.
6567module: ?*Package.Module,
6668
69pub const LazyStatus = enum {
70 /// Not lazy.
71 eager,
72 /// Lazy, found.
73 available,
74 /// Lazy, not found.
75 unavailable,
76};
77
6778/// Contains shared state among all `Fetch` tasks.
6879pub const JobQueue = struct {
6980 mutex: std.Thread.Mutex = .{},
......@@ -80,14 +91,27 @@ pub const JobQueue = struct {
8091 thread_pool: *ThreadPool,
8192 wait_group: WaitGroup = .{},
8293 global_cache: Cache.Directory,
94 /// If true then, no fetching occurs, and:
95 /// * The `global_cache` directory is assumed to be the direct parent
96 /// directory of on-disk packages rather than having the "p/" directory
97 /// prefix inside of it.
98 /// * An error occurs if any non-lazy packages are not already present in
99 /// the package cache directory.
100 /// * Missing hash field causes an error, and no fetching occurs so it does
101 /// not print the correct hash like usual.
102 read_only: bool,
83103 recursive: bool,
84104 /// Dumps hash information to stdout which can be used to troubleshoot why
85105 /// two hashes of the same package do not match.
86106 /// If this is true, `recursive` must be false.
87107 debug_hash: bool,
88108 work_around_btrfs_bug: bool,
109 /// Set of hashes that will be additionally fetched even if they are marked
110 /// as lazy.
111 unlazy_set: UnlazySet = .{},
89112
90113 pub const Table = std.AutoArrayHashMapUnmanaged(Manifest.MultiHashHexDigest, *Fetch);
114 pub const UnlazySet = std.AutoArrayHashMapUnmanaged(Manifest.MultiHashHexDigest, void);
91115
92116 pub fn deinit(jq: *JobQueue) void {
93117 if (jq.all_fetches.items.len == 0) return;
......@@ -141,11 +165,37 @@ pub const JobQueue = struct {
141165 // The first one is a dummy package for the current project.
142166 continue;
143167 }
168
144169 try buf.writer().print(
145170 \\ pub const {} = struct {{
171 \\
172 , .{std.zig.fmtId(&hash)});
173
174 lazy: {
175 switch (fetch.lazy_status) {
176 .eager => break :lazy,
177 .available => {
178 try buf.appendSlice(
179 \\ pub const available = true;
180 \\
181 );
182 break :lazy;
183 },
184 .unavailable => {
185 try buf.appendSlice(
186 \\ pub const available = false;
187 \\ };
188 \\
189 );
190 continue;
191 },
192 }
193 }
194
195 try buf.writer().print(
146196 \\ pub const build_root = "{q}";
147197 \\
148 , .{ std.zig.fmtId(&hash), fetch.package_root });
198 , .{fetch.package_root});
149199
150200 if (fetch.has_build_zig) {
151201 try buf.writer().print(
......@@ -270,7 +320,8 @@ pub fn run(f: *Fetch) RunError!void {
270320 // We want to fail unless the resolved relative path has a
271321 // prefix of "p/$hash/".
272322 const digest_len = @typeInfo(Manifest.MultiHashHexDigest).Array.len;
273 const expected_prefix = f.parent_package_root.sub_path[0 .. "p/".len + digest_len];
323 const prefix_len: usize = if (f.job_queue.read_only) 0 else "p/".len;
324 const expected_prefix = f.parent_package_root.sub_path[0 .. prefix_len + digest_len];
274325 if (!std.mem.startsWith(u8, pkg_root.sub_path, expected_prefix)) {
275326 return f.fail(
276327 f.location_tok,
......@@ -311,8 +362,11 @@ pub fn run(f: *Fetch) RunError!void {
311362
312363 const s = fs.path.sep_str;
313364 if (remote.hash) |expected_hash| {
314 const pkg_sub_path = "p" ++ s ++ expected_hash;
365 const prefixed_pkg_sub_path = "p" ++ s ++ expected_hash;
366 const prefix_len: usize = if (f.job_queue.read_only) "p/".len else 0;
367 const pkg_sub_path = prefixed_pkg_sub_path[prefix_len..];
315368 if (cache_root.handle.access(pkg_sub_path, .{})) |_| {
369 assert(f.lazy_status != .unavailable);
316370 f.package_root = .{
317371 .root_dir = cache_root,
318372 .sub_path = try arena.dupe(u8, pkg_sub_path),
......@@ -322,7 +376,22 @@ pub fn run(f: *Fetch) RunError!void {
322376 if (!f.job_queue.recursive) return;
323377 return queueJobsForDeps(f);
324378 } else |err| switch (err) {
325 error.FileNotFound => {},
379 error.FileNotFound => {
380 switch (f.lazy_status) {
381 .eager => {},
382 .available => if (!f.job_queue.unlazy_set.contains(expected_hash)) {
383 f.lazy_status = .unavailable;
384 return;
385 },
386 .unavailable => unreachable,
387 }
388 if (f.job_queue.read_only) return f.fail(
389 f.name_tok,
390 try eb.printString("package not found at '{}{s}'", .{
391 cache_root, pkg_sub_path,
392 }),
393 );
394 },
326395 else => |e| {
327396 try eb.addRootErrorMessage(.{
328397 .msg = try eb.printString("unable to open global package cache directory '{}{s}': {s}", .{
......@@ -332,6 +401,12 @@ pub fn run(f: *Fetch) RunError!void {
332401 return error.FetchFailed;
333402 },
334403 }
404 } else {
405 try eb.addRootErrorMessage(.{
406 .msg = try eb.addString("dependency is missing hash field"),
407 .src_loc = try f.srcLoc(f.location_tok),
408 });
409 return error.FetchFailed;
335410 }
336411
337412 // Fetch and unpack the remote into a temporary directory.
......@@ -602,6 +677,8 @@ fn queueJobsForDeps(f: *Fetch) RunError!void {
602677 .location = location,
603678 .location_tok = dep.location_tok,
604679 .hash_tok = dep.hash_tok,
680 .name_tok = dep.name_tok,
681 .lazy_status = if (dep.lazy) .available else .eager,
605682 .parent_package_root = f.package_root,
606683 .parent_manifest_ast = &f.manifest_ast,
607684 .prog_node = f.prog_node,
src/Package/Manifest.zig+28
......@@ -12,6 +12,8 @@ pub const Dependency = struct {
1212 hash: ?[]const u8,
1313 hash_tok: Ast.TokenIndex,
1414 node: Ast.Node.Index,
15 name_tok: Ast.TokenIndex,
16 lazy: bool,
1517
1618 pub const Location = union(enum) {
1719 url: []const u8,
......@@ -303,11 +305,14 @@ const Parse = struct {
303305 .hash = null,
304306 .hash_tok = 0,
305307 .node = node,
308 .name_tok = 0,
309 .lazy = false,
306310 };
307311 var has_location = false;
308312
309313 for (struct_init.ast.fields) |field_init| {
310314 const name_token = ast.firstToken(field_init) - 2;
315 dep.name_tok = name_token;
311316 const field_name = try identifierTokenString(p, name_token);
312317 // We could get fancy with reflection and comptime logic here but doing
313318 // things manually provides an opportunity to do any additional verification
......@@ -342,6 +347,11 @@ const Parse = struct {
342347 else => |e| return e,
343348 };
344349 dep.hash_tok = main_tokens[field_init];
350 } else if (mem.eql(u8, field_name, "lazy")) {
351 dep.lazy = parseBool(p, field_init) catch |err| switch (err) {
352 error.ParseFailure => continue,
353 else => |e| return e,
354 };
345355 } else {
346356 // Ignore unknown fields so that we can add fields in future zig
347357 // versions without breaking older zig versions.
......@@ -374,6 +384,24 @@ const Parse = struct {
374384 }
375385 }
376386
387 fn parseBool(p: *Parse, node: Ast.Node.Index) !bool {
388 const ast = p.ast;
389 const node_tags = ast.nodes.items(.tag);
390 const main_tokens = ast.nodes.items(.main_token);
391 if (node_tags[node] != .identifier) {
392 return fail(p, main_tokens[node], "expected identifier", .{});
393 }
394 const ident_token = main_tokens[node];
395 const token_bytes = ast.tokenSlice(ident_token);
396 if (mem.eql(u8, token_bytes, "true")) {
397 return true;
398 } else if (mem.eql(u8, token_bytes, "false")) {
399 return false;
400 } else {
401 return fail(p, ident_token, "expected boolean", .{});
402 }
403 }
404
377405 fn parseString(p: *Parse, node: Ast.Node.Index) ![]const u8 {
378406 const ast = p.ast;
379407 const node_tags = ast.nodes.items(.tag);
src/main.zig+545-422
......@@ -969,6 +969,9 @@ fn buildOutputType(
969969 .libc_paths_file = try EnvVar.ZIG_LIBC.get(arena),
970970 .link_objects = .{},
971971 .native_system_include_paths = &.{},
972 .host_triple = null,
973 .host_cpu = null,
974 .host_dynamic_linker = null,
972975 };
973976
974977 // before arg parsing, check for the NO_COLOR environment variable
......@@ -1262,6 +1265,12 @@ fn buildOutputType(
12621265 mod_opts.optimize_mode = parseOptimizeMode(arg["-O".len..]);
12631266 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
12641267 create_module.dynamic_linker = args_iter.nextOrFatal();
1268 } else if (mem.eql(u8, arg, "--host-target")) {
1269 create_module.host_triple = args_iter.nextOrFatal();
1270 } else if (mem.eql(u8, arg, "--host-cpu")) {
1271 create_module.host_cpu = args_iter.nextOrFatal();
1272 } else if (mem.eql(u8, arg, "--host-dynamic-linker")) {
1273 create_module.host_dynamic_linker = args_iter.nextOrFatal();
12651274 } else if (mem.eql(u8, arg, "--sysroot")) {
12661275 const next_arg = args_iter.nextOrFatal();
12671276 create_module.sysroot = next_arg;
......@@ -3455,6 +3464,9 @@ const CreateModule = struct {
34553464 each_lib_rpath: ?bool,
34563465 libc_paths_file: ?[]const u8,
34573466 link_objects: std.ArrayListUnmanaged(Compilation.LinkObject),
3467 host_triple: ?[]const u8,
3468 host_cpu: ?[]const u8,
3469 host_dynamic_linker: ?[]const u8,
34583470};
34593471
34603472fn createModule(
......@@ -3539,7 +3551,15 @@ fn createModule(
35393551 }
35403552
35413553 const target_query = parseTargetQueryOrReportFatalError(arena, target_parse_options);
3542 const target = resolveTargetQueryOrFatal(target_query);
3554 const adjusted_target_query = a: {
3555 if (!target_query.isNative()) break :a target_query;
3556 if (create_module.host_triple) |triple| target_parse_options.arch_os_abi = triple;
3557 if (create_module.host_cpu) |cpu| target_parse_options.cpu_features = cpu;
3558 if (create_module.host_dynamic_linker) |dl| target_parse_options.dynamic_linker = dl;
3559 break :a parseTargetQueryOrReportFatalError(arena, target_parse_options);
3560 };
3561
3562 const target = resolveTargetQueryOrFatal(adjusted_target_query);
35433563 break :t .{
35443564 .result = target,
35453565 .is_native_os = target_query.isNativeOs(),
......@@ -5130,476 +5150,576 @@ pub const usage_build =
51305150;
51315151
51325152pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
5133 const work_around_btrfs_bug = builtin.os.tag == .linux and
5134 EnvVar.ZIG_BTRFS_WORKAROUND.isSet();
5135 const color: Color = .auto;
5153 var progress: std.Progress = .{ .dont_print_on_dumb = true };
51365154
5137 // We want to release all the locks before executing the child process, so we make a nice
5138 // big block here to ensure the cleanup gets run when we extract out our argv.
5139 const child_argv = argv: {
5140 const self_exe_path = try introspect.findZigExePath(arena);
5155 var build_file: ?[]const u8 = null;
5156 var override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
5157 var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
5158 var override_local_cache_dir: ?[]const u8 = try EnvVar.ZIG_LOCAL_CACHE_DIR.get(arena);
5159 var override_build_runner: ?[]const u8 = try EnvVar.ZIG_BUILD_RUNNER.get(arena);
5160 var child_argv = std.ArrayList([]const u8).init(arena);
5161 var reference_trace: ?u32 = null;
5162 var debug_compile_errors = false;
5163 var verbose_link = (builtin.os.tag != .wasi or builtin.link_libc) and
5164 EnvVar.ZIG_VERBOSE_LINK.isSet();
5165 var verbose_cc = (builtin.os.tag != .wasi or builtin.link_libc) and
5166 EnvVar.ZIG_VERBOSE_CC.isSet();
5167 var verbose_air = false;
5168 var verbose_intern_pool = false;
5169 var verbose_generic_instances = false;
5170 var verbose_llvm_ir: ?[]const u8 = null;
5171 var verbose_llvm_bc: ?[]const u8 = null;
5172 var verbose_cimport = false;
5173 var verbose_llvm_cpu_features = false;
5174 var fetch_only = false;
5175 var system_pkg_dir_path: ?[]const u8 = null;
51415176
5142 var build_file: ?[]const u8 = null;
5143 var override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
5144 var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
5145 var override_local_cache_dir: ?[]const u8 = try EnvVar.ZIG_LOCAL_CACHE_DIR.get(arena);
5146 var override_build_runner: ?[]const u8 = try EnvVar.ZIG_BUILD_RUNNER.get(arena);
5147 var child_argv = std.ArrayList([]const u8).init(arena);
5148 var reference_trace: ?u32 = null;
5149 var debug_compile_errors = false;
5150 var verbose_link = (builtin.os.tag != .wasi or builtin.link_libc) and
5151 EnvVar.ZIG_VERBOSE_LINK.isSet();
5152 var verbose_cc = (builtin.os.tag != .wasi or builtin.link_libc) and
5153 EnvVar.ZIG_VERBOSE_CC.isSet();
5154 var verbose_air = false;
5155 var verbose_intern_pool = false;
5156 var verbose_generic_instances = false;
5157 var verbose_llvm_ir: ?[]const u8 = null;
5158 var verbose_llvm_bc: ?[]const u8 = null;
5159 var verbose_cimport = false;
5160 var verbose_llvm_cpu_features = false;
5161 var fetch_only = false;
5162
5163 const argv_index_exe = child_argv.items.len;
5164 _ = try child_argv.addOne();
5165
5166 try child_argv.append(self_exe_path);
5167
5168 const argv_index_build_file = child_argv.items.len;
5169 _ = try child_argv.addOne();
5170
5171 const argv_index_cache_dir = child_argv.items.len;
5172 _ = try child_argv.addOne();
5173
5174 const argv_index_global_cache_dir = child_argv.items.len;
5175 _ = try child_argv.addOne();
5176
5177 try child_argv.appendSlice(&.{
5178 "--seed",
5179 try std.fmt.allocPrint(arena, "0x{x}", .{std.crypto.random.int(u32)}),
5180 });
5181 const argv_index_seed = child_argv.items.len - 1;
5177 const argv_index_exe = child_argv.items.len;
5178 _ = try child_argv.addOne();
51825179
5183 {
5184 var i: usize = 0;
5185 while (i < args.len) : (i += 1) {
5186 const arg = args[i];
5187 if (mem.startsWith(u8, arg, "-")) {
5188 if (mem.eql(u8, arg, "--build-file")) {
5189 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5190 i += 1;
5191 build_file = args[i];
5192 continue;
5193 } else if (mem.eql(u8, arg, "--zig-lib-dir")) {
5194 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5195 i += 1;
5196 override_lib_dir = args[i];
5197 try child_argv.appendSlice(&.{ arg, args[i] });
5198 continue;
5199 } else if (mem.eql(u8, arg, "--build-runner")) {
5200 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5201 i += 1;
5202 override_build_runner = args[i];
5203 continue;
5204 } else if (mem.eql(u8, arg, "--cache-dir")) {
5205 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5206 i += 1;
5207 override_local_cache_dir = args[i];
5208 continue;
5209 } else if (mem.eql(u8, arg, "--global-cache-dir")) {
5210 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5211 i += 1;
5212 override_global_cache_dir = args[i];
5213 continue;
5214 } else if (mem.eql(u8, arg, "-freference-trace")) {
5215 reference_trace = 256;
5216 } else if (mem.eql(u8, arg, "--fetch")) {
5217 fetch_only = true;
5218 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {
5219 const num = arg["-freference-trace=".len..];
5220 reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
5221 fatal("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });
5222 };
5223 } else if (mem.eql(u8, arg, "-fno-reference-trace")) {
5224 reference_trace = null;
5225 } else if (mem.eql(u8, arg, "--debug-log")) {
5226 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5227 try child_argv.appendSlice(args[i .. i + 2]);
5228 i += 1;
5229 if (!build_options.enable_logging) {
5230 warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{});
5231 } else {
5232 try log_scopes.append(arena, args[i]);
5233 }
5234 continue;
5235 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
5236 if (!crash_report.is_enabled) {
5237 warn("Zig was compiled in a release mode. --debug-compile-errors has no effect.", .{});
5238 } else {
5239 debug_compile_errors = true;
5240 }
5241 } else if (mem.eql(u8, arg, "--verbose-link")) {
5242 verbose_link = true;
5243 } else if (mem.eql(u8, arg, "--verbose-cc")) {
5244 verbose_cc = true;
5245 } else if (mem.eql(u8, arg, "--verbose-air")) {
5246 verbose_air = true;
5247 } else if (mem.eql(u8, arg, "--verbose-intern-pool")) {
5248 verbose_intern_pool = true;
5249 } else if (mem.eql(u8, arg, "--verbose-generic-instances")) {
5250 verbose_generic_instances = true;
5251 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
5252 verbose_llvm_ir = "-";
5253 } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) {
5254 verbose_llvm_ir = arg["--verbose-llvm-ir=".len..];
5255 } else if (mem.startsWith(u8, arg, "--verbose-llvm-bc=")) {
5256 verbose_llvm_bc = arg["--verbose-llvm-bc=".len..];
5257 } else if (mem.eql(u8, arg, "--verbose-cimport")) {
5258 verbose_cimport = true;
5259 } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {
5260 verbose_llvm_cpu_features = true;
5261 } else if (mem.eql(u8, arg, "--seed")) {
5262 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5263 i += 1;
5264 child_argv.items[argv_index_seed] = args[i];
5265 continue;
5180 const self_exe_path = try introspect.findZigExePath(arena);
5181 try child_argv.append(self_exe_path);
5182
5183 const argv_index_build_file = child_argv.items.len;
5184 _ = try child_argv.addOne();
5185
5186 const argv_index_cache_dir = child_argv.items.len;
5187 _ = try child_argv.addOne();
5188
5189 const argv_index_global_cache_dir = child_argv.items.len;
5190 _ = try child_argv.addOne();
5191
5192 try child_argv.appendSlice(&.{
5193 "--seed",
5194 try std.fmt.allocPrint(arena, "0x{x}", .{std.crypto.random.int(u32)}),
5195 });
5196 const argv_index_seed = child_argv.items.len - 1;
5197
5198 // This parent process needs a way to obtain results from the configuration
5199 // phase of the child process. In the future, the make phase will be
5200 // executed in a separate process than the configure phase, and we can then
5201 // use stdout from the configuration phase for this purpose.
5202 //
5203 // However, currently, both phases are in the same process, and Run Step
5204 // provides API for making the runned subprocesses inherit stdout and stderr
5205 // which means these streams are not available for passing metadata back
5206 // to the parent.
5207 //
5208 // Until make and configure phases are separated into different processes,
5209 // the strategy is to choose a temporary file name ahead of time, and then
5210 // read this file in the parent to obtain the results, in the case the child
5211 // exits with code 3.
5212 const results_tmp_file_nonce = Package.Manifest.hex64(std.crypto.random.int(u64));
5213 try child_argv.append("-Z" ++ results_tmp_file_nonce);
5214
5215 {
5216 var i: usize = 0;
5217 while (i < args.len) : (i += 1) {
5218 const arg = args[i];
5219 if (mem.startsWith(u8, arg, "-")) {
5220 if (mem.eql(u8, arg, "--build-file")) {
5221 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5222 i += 1;
5223 build_file = args[i];
5224 continue;
5225 } else if (mem.eql(u8, arg, "--zig-lib-dir")) {
5226 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5227 i += 1;
5228 override_lib_dir = args[i];
5229 try child_argv.appendSlice(&.{ arg, args[i] });
5230 continue;
5231 } else if (mem.eql(u8, arg, "--build-runner")) {
5232 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5233 i += 1;
5234 override_build_runner = args[i];
5235 continue;
5236 } else if (mem.eql(u8, arg, "--cache-dir")) {
5237 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5238 i += 1;
5239 override_local_cache_dir = args[i];
5240 continue;
5241 } else if (mem.eql(u8, arg, "--global-cache-dir")) {
5242 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5243 i += 1;
5244 override_global_cache_dir = args[i];
5245 continue;
5246 } else if (mem.eql(u8, arg, "-freference-trace")) {
5247 reference_trace = 256;
5248 } else if (mem.eql(u8, arg, "--fetch")) {
5249 fetch_only = true;
5250 } else if (mem.eql(u8, arg, "--system")) {
5251 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5252 i += 1;
5253 system_pkg_dir_path = args[i];
5254 try child_argv.append("--system");
5255 continue;
5256 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {
5257 const num = arg["-freference-trace=".len..];
5258 reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
5259 fatal("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });
5260 };
5261 } else if (mem.eql(u8, arg, "-fno-reference-trace")) {
5262 reference_trace = null;
5263 } else if (mem.eql(u8, arg, "--debug-log")) {
5264 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5265 try child_argv.appendSlice(args[i .. i + 2]);
5266 i += 1;
5267 if (!build_options.enable_logging) {
5268 warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{});
5269 } else {
5270 try log_scopes.append(arena, args[i]);
5271 }
5272 continue;
5273 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
5274 if (!crash_report.is_enabled) {
5275 warn("Zig was compiled in a release mode. --debug-compile-errors has no effect.", .{});
5276 } else {
5277 debug_compile_errors = true;
52665278 }
5279 } else if (mem.eql(u8, arg, "--verbose-link")) {
5280 verbose_link = true;
5281 } else if (mem.eql(u8, arg, "--verbose-cc")) {
5282 verbose_cc = true;
5283 } else if (mem.eql(u8, arg, "--verbose-air")) {
5284 verbose_air = true;
5285 } else if (mem.eql(u8, arg, "--verbose-intern-pool")) {
5286 verbose_intern_pool = true;
5287 } else if (mem.eql(u8, arg, "--verbose-generic-instances")) {
5288 verbose_generic_instances = true;
5289 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
5290 verbose_llvm_ir = "-";
5291 } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) {
5292 verbose_llvm_ir = arg["--verbose-llvm-ir=".len..];
5293 } else if (mem.startsWith(u8, arg, "--verbose-llvm-bc=")) {
5294 verbose_llvm_bc = arg["--verbose-llvm-bc=".len..];
5295 } else if (mem.eql(u8, arg, "--verbose-cimport")) {
5296 verbose_cimport = true;
5297 } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {
5298 verbose_llvm_cpu_features = true;
5299 } else if (mem.eql(u8, arg, "--seed")) {
5300 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5301 i += 1;
5302 child_argv.items[argv_index_seed] = args[i];
5303 continue;
52675304 }
5268 try child_argv.append(arg);
52695305 }
5306 try child_argv.append(arg);
52705307 }
5308 }
52715309
5272 var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir| .{
5273 .path = lib_dir,
5274 .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| {
5275 fatal("unable to open zig lib directory from 'zig-lib-dir' argument: '{s}': {s}", .{ lib_dir, @errorName(err) });
5276 },
5277 } else introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
5278 fatal("unable to find zig installation directory '{s}': {s}", .{ self_exe_path, @errorName(err) });
5279 };
5280 defer zig_lib_directory.handle.close();
5310 const work_around_btrfs_bug = builtin.os.tag == .linux and
5311 EnvVar.ZIG_BTRFS_WORKAROUND.isSet();
5312 const color: Color = .auto;
52815313
5282 var cleanup_build_dir: ?fs.Dir = null;
5283 defer if (cleanup_build_dir) |*dir| dir.close();
5314 const target_query: std.Target.Query = .{};
5315 const resolved_target: Package.Module.ResolvedTarget = .{
5316 .result = resolveTargetQueryOrFatal(target_query),
5317 .is_native_os = true,
5318 .is_native_abi = true,
5319 };
52845320
5285 const cwd_path = try process.getCwdAlloc(arena);
5286 const build_root = try findBuildRoot(arena, .{
5287 .cwd_path = cwd_path,
5288 .build_file = build_file,
5289 });
5290 child_argv.items[argv_index_build_file] = build_root.directory.path orelse cwd_path;
5321 const exe_basename = try std.zig.binNameAlloc(arena, .{
5322 .root_name = "build",
5323 .target = resolved_target.result,
5324 .output_mode = .Exe,
5325 });
5326 const emit_bin: Compilation.EmitLoc = .{
5327 .directory = null, // Use the local zig-cache.
5328 .basename = exe_basename,
5329 };
52915330
5292 var global_cache_directory: Compilation.Directory = l: {
5293 const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);
5294 break :l .{
5295 .handle = try fs.cwd().makeOpenPath(p, .{}),
5296 .path = p,
5297 };
5331 gimmeMoreOfThoseSweetSweetFileDescriptors();
5332
5333 var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir| .{
5334 .path = lib_dir,
5335 .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| {
5336 fatal("unable to open zig lib directory from 'zig-lib-dir' argument: '{s}': {s}", .{ lib_dir, @errorName(err) });
5337 },
5338 } else introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
5339 fatal("unable to find zig installation directory '{s}': {s}", .{ self_exe_path, @errorName(err) });
5340 };
5341 defer zig_lib_directory.handle.close();
5342
5343 const cwd_path = try process.getCwdAlloc(arena);
5344 const build_root = try findBuildRoot(arena, .{
5345 .cwd_path = cwd_path,
5346 .build_file = build_file,
5347 });
5348 child_argv.items[argv_index_build_file] = build_root.directory.path orelse cwd_path;
5349
5350 var global_cache_directory: Compilation.Directory = l: {
5351 const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);
5352 break :l .{
5353 .handle = try fs.cwd().makeOpenPath(p, .{}),
5354 .path = p,
52985355 };
5299 defer global_cache_directory.handle.close();
5356 };
5357 defer global_cache_directory.handle.close();
53005358
5301 child_argv.items[argv_index_global_cache_dir] = global_cache_directory.path orelse cwd_path;
5359 child_argv.items[argv_index_global_cache_dir] = global_cache_directory.path orelse cwd_path;
53025360
5303 var local_cache_directory: Compilation.Directory = l: {
5304 if (override_local_cache_dir) |local_cache_dir_path| {
5305 break :l .{
5306 .handle = try fs.cwd().makeOpenPath(local_cache_dir_path, .{}),
5307 .path = local_cache_dir_path,
5308 };
5309 }
5310 const cache_dir_path = try build_root.directory.join(arena, &[_][]const u8{"zig-cache"});
5361 var local_cache_directory: Compilation.Directory = l: {
5362 if (override_local_cache_dir) |local_cache_dir_path| {
53115363 break :l .{
5312 .handle = try build_root.directory.handle.makeOpenPath("zig-cache", .{}),
5313 .path = cache_dir_path,
5364 .handle = try fs.cwd().makeOpenPath(local_cache_dir_path, .{}),
5365 .path = local_cache_dir_path,
53145366 };
5367 }
5368 const cache_dir_path = try build_root.directory.join(arena, &[_][]const u8{"zig-cache"});
5369 break :l .{
5370 .handle = try build_root.directory.handle.makeOpenPath("zig-cache", .{}),
5371 .path = cache_dir_path,
53155372 };
5316 defer local_cache_directory.handle.close();
5373 };
5374 defer local_cache_directory.handle.close();
53175375
5318 child_argv.items[argv_index_cache_dir] = local_cache_directory.path orelse cwd_path;
5376 child_argv.items[argv_index_cache_dir] = local_cache_directory.path orelse cwd_path;
53195377
5320 gimmeMoreOfThoseSweetSweetFileDescriptors();
5378 var thread_pool: ThreadPool = undefined;
5379 try thread_pool.init(.{ .allocator = gpa });
5380 defer thread_pool.deinit();
53215381
5322 const target_query: std.Target.Query = .{};
5323 const resolved_target: Package.Module.ResolvedTarget = .{
5324 .result = resolveTargetQueryOrFatal(target_query),
5325 .is_native_os = true,
5326 .is_native_abi = true,
5327 };
5382 // Dummy http client that is not actually used when only_core_functionality is enabled.
5383 // Prevents bootstrap from depending on a bunch of unnecessary stuff.
5384 const HttpClient = if (build_options.only_core_functionality) struct {
5385 allocator: Allocator,
5386 fn deinit(self: *@This()) void {
5387 _ = self;
5388 }
5389 } else std.http.Client;
53285390
5329 const exe_basename = try std.zig.binNameAlloc(arena, .{
5330 .root_name = "build",
5331 .target = resolved_target.result,
5332 .output_mode = .Exe,
5333 });
5334 const emit_bin: Compilation.EmitLoc = .{
5335 .directory = null, // Use the local zig-cache.
5336 .basename = exe_basename,
5337 };
5338 var thread_pool: ThreadPool = undefined;
5339 try thread_pool.init(.{ .allocator = gpa });
5340 defer thread_pool.deinit();
5391 var http_client: HttpClient = .{ .allocator = gpa };
5392 defer http_client.deinit();
53415393
5342 const main_mod_paths: Package.Module.CreateOptions.Paths = if (override_build_runner) |runner| .{
5343 .root = .{
5344 .root_dir = Cache.Directory.cwd(),
5345 .sub_path = fs.path.dirname(runner) orelse "",
5346 },
5347 .root_src_path = fs.path.basename(runner),
5348 } else .{
5349 .root = .{ .root_dir = zig_lib_directory },
5350 .root_src_path = "build_runner.zig",
5351 };
5394 var unlazy_set: Package.Fetch.JobQueue.UnlazySet = .{};
53525395
5353 const config = try Compilation.Config.resolve(.{
5354 .output_mode = .Exe,
5355 .resolved_target = resolved_target,
5356 .have_zcu = true,
5357 .emit_bin = true,
5358 .is_test = false,
5359 });
5396 // This loop is re-evaluated when the build script exits with an indication that it
5397 // could not continue due to missing lazy dependencies.
5398 while (true) {
5399 // We want to release all the locks before executing the child process, so we make a nice
5400 // big block here to ensure the cleanup gets run when we extract out our argv.
5401 {
5402 const main_mod_paths: Package.Module.CreateOptions.Paths = if (override_build_runner) |runner| .{
5403 .root = .{
5404 .root_dir = Cache.Directory.cwd(),
5405 .sub_path = fs.path.dirname(runner) orelse "",
5406 },
5407 .root_src_path = fs.path.basename(runner),
5408 } else .{
5409 .root = .{ .root_dir = zig_lib_directory },
5410 .root_src_path = "build_runner.zig",
5411 };
53605412
5361 const root_mod = try Package.Module.create(arena, .{
5362 .global_cache_directory = global_cache_directory,
5363 .paths = main_mod_paths,
5364 .fully_qualified_name = "root",
5365 .cc_argv = &.{},
5366 .inherited = .{
5413 const config = try Compilation.Config.resolve(.{
5414 .output_mode = .Exe,
53675415 .resolved_target = resolved_target,
5368 },
5369 .global = config,
5370 .parent = null,
5371 .builtin_mod = null,
5372 });
5416 .have_zcu = true,
5417 .emit_bin = true,
5418 .is_test = false,
5419 });
53735420
5374 const builtin_mod = root_mod.getBuiltinDependency();
5421 const root_mod = try Package.Module.create(arena, .{
5422 .global_cache_directory = global_cache_directory,
5423 .paths = main_mod_paths,
5424 .fully_qualified_name = "root",
5425 .cc_argv = &.{},
5426 .inherited = .{
5427 .resolved_target = resolved_target,
5428 },
5429 .global = config,
5430 .parent = null,
5431 .builtin_mod = null,
5432 });
53755433
5376 const build_mod = try Package.Module.create(arena, .{
5377 .global_cache_directory = global_cache_directory,
5378 .paths = .{
5379 .root = .{ .root_dir = build_root.directory },
5380 .root_src_path = build_root.build_zig_basename,
5381 },
5382 .fully_qualified_name = "root.@build",
5383 .cc_argv = &.{},
5384 .inherited = .{},
5385 .global = config,
5386 .parent = root_mod,
5387 .builtin_mod = builtin_mod,
5388 });
5389 if (build_options.only_core_functionality) {
5390 try createEmptyDependenciesModule(
5391 arena,
5392 root_mod,
5393 global_cache_directory,
5394 local_cache_directory,
5395 builtin_mod,
5396 config,
5397 );
5398 } else {
5399 var http_client: std.http.Client = .{ .allocator = gpa };
5400 defer http_client.deinit();
5434 const builtin_mod = root_mod.getBuiltinDependency();
54015435
5402 try http_client.loadDefaultProxies();
5436 const build_mod = try Package.Module.create(arena, .{
5437 .global_cache_directory = global_cache_directory,
5438 .paths = .{
5439 .root = .{ .root_dir = build_root.directory },
5440 .root_src_path = build_root.build_zig_basename,
5441 },
5442 .fully_qualified_name = "root.@build",
5443 .cc_argv = &.{},
5444 .inherited = .{},
5445 .global = config,
5446 .parent = root_mod,
5447 .builtin_mod = builtin_mod,
5448 });
54035449
5404 var progress: std.Progress = .{ .dont_print_on_dumb = true };
5405 const root_prog_node = progress.start("Fetch Packages", 0);
5406 defer root_prog_node.end();
5450 var cleanup_build_dir: ?fs.Dir = null;
5451 defer if (cleanup_build_dir) |*dir| dir.close();
5452
5453 if (build_options.only_core_functionality) {
5454 try createEmptyDependenciesModule(
5455 arena,
5456 root_mod,
5457 global_cache_directory,
5458 local_cache_directory,
5459 builtin_mod,
5460 config,
5461 );
5462 } else {
5463 const root_prog_node = progress.start("Fetch Packages", 0);
5464 defer root_prog_node.end();
5465
5466 var job_queue: Package.Fetch.JobQueue = .{
5467 .http_client = &http_client,
5468 .thread_pool = &thread_pool,
5469 .global_cache = global_cache_directory,
5470 .read_only = false,
5471 .recursive = true,
5472 .debug_hash = false,
5473 .work_around_btrfs_bug = work_around_btrfs_bug,
5474 .unlazy_set = unlazy_set,
5475 };
5476 defer job_queue.deinit();
5477
5478 if (system_pkg_dir_path) |p| {
5479 job_queue.global_cache = .{
5480 .path = p,
5481 .handle = fs.cwd().openDir(p, .{}) catch |err| {
5482 fatal("unable to open system package directory '{s}': {s}", .{
5483 p, @errorName(err),
5484 });
5485 },
5486 };
5487 job_queue.read_only = true;
5488 cleanup_build_dir = job_queue.global_cache.handle;
5489 } else {
5490 try http_client.loadDefaultProxies();
5491 }
54075492
5408 var job_queue: Package.Fetch.JobQueue = .{
5409 .http_client = &http_client,
5410 .thread_pool = &thread_pool,
5411 .global_cache = global_cache_directory,
5412 .recursive = true,
5413 .debug_hash = false,
5414 .work_around_btrfs_bug = work_around_btrfs_bug,
5415 };
5416 defer job_queue.deinit();
5417
5418 try job_queue.all_fetches.ensureUnusedCapacity(gpa, 1);
5419 try job_queue.table.ensureUnusedCapacity(gpa, 1);
5420
5421 var fetch: Package.Fetch = .{
5422 .arena = std.heap.ArenaAllocator.init(gpa),
5423 .location = .{ .relative_path = build_mod.root },
5424 .location_tok = 0,
5425 .hash_tok = 0,
5426 .parent_package_root = build_mod.root,
5427 .parent_manifest_ast = null,
5428 .prog_node = root_prog_node,
5429 .job_queue = &job_queue,
5430 .omit_missing_hash_error = true,
5431 .allow_missing_paths_field = false,
5432
5433 .package_root = undefined,
5434 .error_bundle = undefined,
5435 .manifest = null,
5436 .manifest_ast = undefined,
5437 .actual_hash = undefined,
5438 .has_build_zig = true,
5439 .oom_flag = false,
5440
5441 .module = build_mod,
5442 };
5443 job_queue.all_fetches.appendAssumeCapacity(&fetch);
5493 try job_queue.all_fetches.ensureUnusedCapacity(gpa, 1);
5494 try job_queue.table.ensureUnusedCapacity(gpa, 1);
5495
5496 var fetch: Package.Fetch = .{
5497 .arena = std.heap.ArenaAllocator.init(gpa),
5498 .location = .{ .relative_path = build_mod.root },
5499 .location_tok = 0,
5500 .hash_tok = 0,
5501 .name_tok = 0,
5502 .lazy_status = .eager,
5503 .parent_package_root = build_mod.root,
5504 .parent_manifest_ast = null,
5505 .prog_node = root_prog_node,
5506 .job_queue = &job_queue,
5507 .omit_missing_hash_error = true,
5508 .allow_missing_paths_field = false,
5509
5510 .package_root = undefined,
5511 .error_bundle = undefined,
5512 .manifest = null,
5513 .manifest_ast = undefined,
5514 .actual_hash = undefined,
5515 .has_build_zig = true,
5516 .oom_flag = false,
5517
5518 .module = build_mod,
5519 };
5520 job_queue.all_fetches.appendAssumeCapacity(&fetch);
54445521
5445 job_queue.table.putAssumeCapacityNoClobber(
5446 Package.Fetch.relativePathDigest(build_mod.root, global_cache_directory),
5447 &fetch,
5448 );
5522 job_queue.table.putAssumeCapacityNoClobber(
5523 Package.Fetch.relativePathDigest(build_mod.root, global_cache_directory),
5524 &fetch,
5525 );
54495526
5450 job_queue.wait_group.start();
5451 try job_queue.thread_pool.spawn(Package.Fetch.workerRun, .{ &fetch, "root" });
5452 job_queue.wait_group.wait();
5527 job_queue.wait_group.start();
5528 try job_queue.thread_pool.spawn(Package.Fetch.workerRun, .{ &fetch, "root" });
5529 job_queue.wait_group.wait();
54535530
5454 try job_queue.consolidateErrors();
5531 try job_queue.consolidateErrors();
54555532
5456 if (fetch.error_bundle.root_list.items.len > 0) {
5457 var errors = try fetch.error_bundle.toOwnedBundle("");
5458 errors.renderToStdErr(renderOptions(color));
5459 process.exit(1);
5460 }
5533 if (fetch.error_bundle.root_list.items.len > 0) {
5534 var errors = try fetch.error_bundle.toOwnedBundle("");
5535 errors.renderToStdErr(renderOptions(color));
5536 process.exit(1);
5537 }
54615538
5462 if (fetch_only) return cleanExit();
5463
5464 var source_buf = std.ArrayList(u8).init(gpa);
5465 defer source_buf.deinit();
5466 try job_queue.createDependenciesSource(&source_buf);
5467 const deps_mod = try createDependenciesModule(
5468 arena,
5469 source_buf.items,
5470 root_mod,
5471 global_cache_directory,
5472 local_cache_directory,
5473 builtin_mod,
5474 config,
5475 );
5539 if (fetch_only) return cleanExit();
5540
5541 var source_buf = std.ArrayList(u8).init(gpa);
5542 defer source_buf.deinit();
5543 try job_queue.createDependenciesSource(&source_buf);
5544 const deps_mod = try createDependenciesModule(
5545 arena,
5546 source_buf.items,
5547 root_mod,
5548 global_cache_directory,
5549 local_cache_directory,
5550 builtin_mod,
5551 config,
5552 );
54765553
5477 {
5478 // We need a Module for each package's build.zig.
5479 const hashes = job_queue.table.keys();
5480 const fetches = job_queue.table.values();
5481 try deps_mod.deps.ensureUnusedCapacity(arena, @intCast(hashes.len));
5482 for (hashes, fetches) |hash, f| {
5483 if (f == &fetch) {
5484 // The first one is a dummy package for the current project.
5485 continue;
5554 {
5555 // We need a Module for each package's build.zig.
5556 const hashes = job_queue.table.keys();
5557 const fetches = job_queue.table.values();
5558 try deps_mod.deps.ensureUnusedCapacity(arena, @intCast(hashes.len));
5559 for (hashes, fetches) |hash, f| {
5560 if (f == &fetch) {
5561 // The first one is a dummy package for the current project.
5562 continue;
5563 }
5564 if (!f.has_build_zig)
5565 continue;
5566 const m = try Package.Module.create(arena, .{
5567 .global_cache_directory = global_cache_directory,
5568 .paths = .{
5569 .root = try f.package_root.clone(arena),
5570 .root_src_path = Package.build_zig_basename,
5571 },
5572 .fully_qualified_name = try std.fmt.allocPrint(
5573 arena,
5574 "root.@dependencies.{s}",
5575 .{&hash},
5576 ),
5577 .cc_argv = &.{},
5578 .inherited = .{},
5579 .global = config,
5580 .parent = root_mod,
5581 .builtin_mod = builtin_mod,
5582 });
5583 const hash_cloned = try arena.dupe(u8, &hash);
5584 deps_mod.deps.putAssumeCapacityNoClobber(hash_cloned, m);
5585 f.module = m;
54865586 }
5487 if (!f.has_build_zig)
5488 continue;
5489 const m = try Package.Module.create(arena, .{
5490 .global_cache_directory = global_cache_directory,
5491 .paths = .{
5492 .root = try f.package_root.clone(arena),
5493 .root_src_path = Package.build_zig_basename,
5494 },
5495 .fully_qualified_name = try std.fmt.allocPrint(
5496 arena,
5497 "root.@dependencies.{s}",
5498 .{&hash},
5499 ),
5500 .cc_argv = &.{},
5501 .inherited = .{},
5502 .global = config,
5503 .parent = root_mod,
5504 .builtin_mod = builtin_mod,
5505 });
5506 const hash_cloned = try arena.dupe(u8, &hash);
5507 deps_mod.deps.putAssumeCapacityNoClobber(hash_cloned, m);
5508 f.module = m;
5509 }
55105587
5511 // Each build.zig module needs access to each of its
5512 // dependencies' build.zig modules by name.
5513 for (fetches) |f| {
5514 const mod = f.module orelse continue;
5515 const man = f.manifest orelse continue;
5516 const dep_names = man.dependencies.keys();
5517 try mod.deps.ensureUnusedCapacity(arena, @intCast(dep_names.len));
5518 for (dep_names, man.dependencies.values()) |name, dep| {
5519 const dep_digest = Package.Fetch.depDigest(
5520 f.package_root,
5521 global_cache_directory,
5522 dep,
5523 ) orelse continue;
5524 const dep_mod = job_queue.table.get(dep_digest).?.module orelse continue;
5525 const name_cloned = try arena.dupe(u8, name);
5526 mod.deps.putAssumeCapacityNoClobber(name_cloned, dep_mod);
5588 // Each build.zig module needs access to each of its
5589 // dependencies' build.zig modules by name.
5590 for (fetches) |f| {
5591 const mod = f.module orelse continue;
5592 const man = f.manifest orelse continue;
5593 const dep_names = man.dependencies.keys();
5594 try mod.deps.ensureUnusedCapacity(arena, @intCast(dep_names.len));
5595 for (dep_names, man.dependencies.values()) |name, dep| {
5596 const dep_digest = Package.Fetch.depDigest(
5597 f.package_root,
5598 global_cache_directory,
5599 dep,
5600 ) orelse continue;
5601 const dep_mod = job_queue.table.get(dep_digest).?.module orelse continue;
5602 const name_cloned = try arena.dupe(u8, name);
5603 mod.deps.putAssumeCapacityNoClobber(name_cloned, dep_mod);
5604 }
55275605 }
55285606 }
55295607 }
5530 }
55315608
5532 try root_mod.deps.put(arena, "@build", build_mod);
5609 try root_mod.deps.put(arena, "@build", build_mod);
55335610
5534 const comp = Compilation.create(gpa, arena, .{
5535 .zig_lib_directory = zig_lib_directory,
5536 .local_cache_directory = local_cache_directory,
5537 .global_cache_directory = global_cache_directory,
5538 .root_name = "build",
5539 .config = config,
5540 .root_mod = root_mod,
5541 .main_mod = build_mod,
5542 .emit_bin = emit_bin,
5543 .emit_h = null,
5544 .self_exe_path = self_exe_path,
5545 .thread_pool = &thread_pool,
5546 .verbose_cc = verbose_cc,
5547 .verbose_link = verbose_link,
5548 .verbose_air = verbose_air,
5549 .verbose_intern_pool = verbose_intern_pool,
5550 .verbose_generic_instances = verbose_generic_instances,
5551 .verbose_llvm_ir = verbose_llvm_ir,
5552 .verbose_llvm_bc = verbose_llvm_bc,
5553 .verbose_cimport = verbose_cimport,
5554 .verbose_llvm_cpu_features = verbose_llvm_cpu_features,
5555 .cache_mode = .whole,
5556 .reference_trace = reference_trace,
5557 .debug_compile_errors = debug_compile_errors,
5558 }) catch |err| {
5559 fatal("unable to create compilation: {s}", .{@errorName(err)});
5560 };
5561 defer comp.destroy();
5611 const comp = Compilation.create(gpa, arena, .{
5612 .zig_lib_directory = zig_lib_directory,
5613 .local_cache_directory = local_cache_directory,
5614 .global_cache_directory = global_cache_directory,
5615 .root_name = "build",
5616 .config = config,
5617 .root_mod = root_mod,
5618 .main_mod = build_mod,
5619 .emit_bin = emit_bin,
5620 .emit_h = null,
5621 .self_exe_path = self_exe_path,
5622 .thread_pool = &thread_pool,
5623 .verbose_cc = verbose_cc,
5624 .verbose_link = verbose_link,
5625 .verbose_air = verbose_air,
5626 .verbose_intern_pool = verbose_intern_pool,
5627 .verbose_generic_instances = verbose_generic_instances,
5628 .verbose_llvm_ir = verbose_llvm_ir,
5629 .verbose_llvm_bc = verbose_llvm_bc,
5630 .verbose_cimport = verbose_cimport,
5631 .verbose_llvm_cpu_features = verbose_llvm_cpu_features,
5632 .cache_mode = .whole,
5633 .reference_trace = reference_trace,
5634 .debug_compile_errors = debug_compile_errors,
5635 }) catch |err| {
5636 fatal("unable to create compilation: {s}", .{@errorName(err)});
5637 };
5638 defer comp.destroy();
55625639
5563 updateModule(comp, color) catch |err| switch (err) {
5564 error.SemanticAnalyzeFail => process.exit(2),
5565 else => |e| return e,
5566 };
5640 updateModule(comp, color) catch |err| switch (err) {
5641 error.SemanticAnalyzeFail => process.exit(2),
5642 else => |e| return e,
5643 };
55675644
5568 // Since incremental compilation isn't done yet, we use cache_mode = whole
5569 // above, and thus the output file is already closed.
5570 //try comp.makeBinFileExecutable();
5571 child_argv.items[argv_index_exe] =
5572 try local_cache_directory.join(arena, &.{comp.cache_use.whole.bin_sub_path.?});
5645 // Since incremental compilation isn't done yet, we use cache_mode = whole
5646 // above, and thus the output file is already closed.
5647 //try comp.makeBinFileExecutable();
5648 child_argv.items[argv_index_exe] =
5649 try local_cache_directory.join(arena, &.{comp.cache_use.whole.bin_sub_path.?});
5650 }
55735651
5574 break :argv child_argv.items;
5575 };
5652 if (process.can_spawn) {
5653 var child = std.ChildProcess.init(child_argv.items, gpa);
5654 child.stdin_behavior = .Inherit;
5655 child.stdout_behavior = .Inherit;
5656 child.stderr_behavior = .Inherit;
55765657
5577 if (process.can_spawn) {
5578 var child = std.ChildProcess.init(child_argv, gpa);
5579 child.stdin_behavior = .Inherit;
5580 child.stdout_behavior = .Inherit;
5581 child.stderr_behavior = .Inherit;
5658 const term = try child.spawnAndWait();
5659 switch (term) {
5660 .Exited => |code| {
5661 if (code == 0) return cleanExit();
5662 // Indicates that the build runner has reported compile errors
5663 // and this parent process does not need to report any further
5664 // diagnostics.
5665 if (code == 2) process.exit(2);
5666
5667 if (code == 3) {
5668 if (build_options.only_core_functionality) process.exit(3);
5669 // Indicates the configure phase failed due to missing lazy
5670 // dependencies and stdout contains the hashes of the ones
5671 // that are missing.
5672 const s = fs.path.sep_str;
5673 const tmp_sub_path = "tmp" ++ s ++ results_tmp_file_nonce;
5674 const stdout = local_cache_directory.handle.readFileAlloc(arena, tmp_sub_path, 50 * 1024 * 1024) catch |err| {
5675 fatal("unable to read results of configure phase from '{}{s}': {s}", .{
5676 local_cache_directory, tmp_sub_path, @errorName(err),
5677 });
5678 };
5679 local_cache_directory.handle.deleteFile(tmp_sub_path) catch {};
5680
5681 var it = mem.splitScalar(u8, stdout, '\n');
5682 var any_errors = false;
5683 while (it.next()) |hash| {
5684 if (hash.len == 0) continue;
5685 const digest_len = @typeInfo(Package.Manifest.MultiHashHexDigest).Array.len;
5686 if (hash.len != digest_len) {
5687 std.log.err("invalid digest (length {d} instead of {d}): '{s}'", .{
5688 hash.len, digest_len, hash,
5689 });
5690 any_errors = true;
5691 continue;
5692 }
5693 try unlazy_set.put(arena, hash[0..digest_len].*, {});
5694 }
5695 if (any_errors) process.exit(3);
5696 if (system_pkg_dir_path) |p| {
5697 // In this mode, the system needs to provide these packages; they
5698 // cannot be fetched by Zig.
5699 for (unlazy_set.keys()) |hash| {
5700 std.log.err("lazy dependency package not found: {s}" ++ s ++ "{s}", .{
5701 p, hash,
5702 });
5703 }
5704 std.log.info("remote package fetching disabled due to --system mode", .{});
5705 std.log.info("dependencies might be avoidable depending on build configuration", .{});
5706 process.exit(3);
5707 }
5708 continue;
5709 }
55825710
5583 const term = try child.spawnAndWait();
5584 switch (term) {
5585 .Exited => |code| {
5586 if (code == 0) return cleanExit();
5587 // Indicates that the build runner has reported compile errors
5588 // and this parent process does not need to report any further
5589 // diagnostics.
5590 if (code == 2) process.exit(2);
5591
5592 const cmd = try std.mem.join(arena, " ", child_argv);
5593 fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd });
5594 },
5595 else => {
5596 const cmd = try std.mem.join(arena, " ", child_argv);
5597 fatal("the following build command crashed:\n{s}", .{cmd});
5598 },
5711 const cmd = try std.mem.join(arena, " ", child_argv.items);
5712 fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd });
5713 },
5714 else => {
5715 const cmd = try std.mem.join(arena, " ", child_argv.items);
5716 fatal("the following build command crashed:\n{s}", .{cmd});
5717 },
5718 }
5719 } else {
5720 const cmd = try std.mem.join(arena, " ", child_argv.items);
5721 fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), cmd });
55995722 }
5600 } else {
5601 const cmd = try std.mem.join(arena, " ", child_argv);
5602 fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), cmd });
56035723 }
56045724}
56055725
......@@ -7343,6 +7463,7 @@ fn cmdFetch(
73437463 .thread_pool = &thread_pool,
73447464 .global_cache = global_cache_directory,
73457465 .recursive = false,
7466 .read_only = false,
73467467 .debug_hash = debug_hash,
73477468 .work_around_btrfs_bug = work_around_btrfs_bug,
73487469 };
......@@ -7353,6 +7474,8 @@ fn cmdFetch(
73537474 .location = .{ .path_or_url = path_or_url },
73547475 .location_tok = 0,
73557476 .hash_tok = 0,
7477 .name_tok = 0,
7478 .lazy_status = .eager,
73567479 .parent_package_root = undefined,
73577480 .parent_manifest_ast = null,
73587481 .prog_node = root_prog_node,
test/src/Cases.zig+2-2
......@@ -562,7 +562,7 @@ pub fn lowerToBuildSteps(
562562 run.setName(incr_case.base_path);
563563 run.addArgs(&.{
564564 case_base_path_with_dir,
565 b.zig_exe,
565 b.graph.zig_exe,
566566 });
567567 run.expectStdOutEqual("");
568568 parent_step.dependOn(&run.step);
......@@ -653,7 +653,7 @@ pub fn lowerToBuildSteps(
653653 break :no_exec;
654654 }
655655 const run_c = b.addSystemCommand(&.{
656 b.zig_exe,
656 b.graph.zig_exe,
657657 "run",
658658 "-cflags",
659659 "-Ilib",
test/tests.zig+11-11
......@@ -796,7 +796,7 @@ pub fn addCliTests(b: *std.Build) *Step {
796796 {
797797 // Test `zig init`.
798798 const tmp_path = b.makeTempPath();
799 const init_exe = b.addSystemCommand(&.{ b.zig_exe, "init" });
799 const init_exe = b.addSystemCommand(&.{ b.graph.zig_exe, "init" });
800800 init_exe.setCwd(.{ .cwd_relative = tmp_path });
801801 init_exe.setName("zig init");
802802 init_exe.expectStdOutEqual("");
......@@ -810,20 +810,20 @@ pub fn addCliTests(b: *std.Build) *Step {
810810 const bad_out_arg = "-femit-bin=does" ++ s ++ "not" ++ s ++ "exist" ++ s ++ "foo.exe";
811811 const ok_src_arg = "src" ++ s ++ "main.zig";
812812 const expected = "error: unable to open output directory 'does" ++ s ++ "not" ++ s ++ "exist': FileNotFound\n";
813 const run_bad = b.addSystemCommand(&.{ b.zig_exe, "build-exe", ok_src_arg, bad_out_arg });
813 const run_bad = b.addSystemCommand(&.{ b.graph.zig_exe, "build-exe", ok_src_arg, bad_out_arg });
814814 run_bad.setName("zig build-exe error message for bad -femit-bin arg");
815815 run_bad.expectExitCode(1);
816816 run_bad.expectStdErrEqual(expected);
817817 run_bad.expectStdOutEqual("");
818818 run_bad.step.dependOn(&init_exe.step);
819819
820 const run_test = b.addSystemCommand(&.{ b.zig_exe, "build", "test" });
820 const run_test = b.addSystemCommand(&.{ b.graph.zig_exe, "build", "test" });
821821 run_test.setCwd(.{ .cwd_relative = tmp_path });
822822 run_test.setName("zig build test");
823823 run_test.expectStdOutEqual("");
824824 run_test.step.dependOn(&init_exe.step);
825825
826 const run_run = b.addSystemCommand(&.{ b.zig_exe, "build", "run" });
826 const run_run = b.addSystemCommand(&.{ b.graph.zig_exe, "build", "run" });
827827 run_run.setCwd(.{ .cwd_relative = tmp_path });
828828 run_run.setName("zig build run");
829829 run_run.expectStdOutEqual("Run `zig build test` to run the tests.\n");
......@@ -857,7 +857,7 @@ pub fn addCliTests(b: *std.Build) *Step {
857857
858858 // This is intended to be the exact CLI usage used by godbolt.org.
859859 const run = b.addSystemCommand(&.{
860 b.zig_exe, "build-obj",
860 b.graph.zig_exe, "build-obj",
861861 "--cache-dir", tmp_path,
862862 "--name", "example",
863863 "-fno-emit-bin", "-fno-emit-h",
......@@ -900,7 +900,7 @@ pub fn addCliTests(b: *std.Build) *Step {
900900 subdir.writeFile("fmt3.zig", unformatted_code) catch @panic("unhandled");
901901
902902 // Test zig fmt affecting only the appropriate files.
903 const run1 = b.addSystemCommand(&.{ b.zig_exe, "fmt", "fmt1.zig" });
903 const run1 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "fmt1.zig" });
904904 run1.setName("run zig fmt one file");
905905 run1.setCwd(.{ .cwd_relative = tmp_path });
906906 run1.has_side_effects = true;
......@@ -908,7 +908,7 @@ pub fn addCliTests(b: *std.Build) *Step {
908908 run1.expectStdOutEqual("fmt1.zig\n");
909909
910910 // Test excluding files and directories from a run
911 const run2 = b.addSystemCommand(&.{ b.zig_exe, "fmt", "--exclude", "fmt2.zig", "--exclude", "subdir", "." });
911 const run2 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "--exclude", "fmt2.zig", "--exclude", "subdir", "." });
912912 run2.setName("run zig fmt on directory with exclusions");
913913 run2.setCwd(.{ .cwd_relative = tmp_path });
914914 run2.has_side_effects = true;
......@@ -916,7 +916,7 @@ pub fn addCliTests(b: *std.Build) *Step {
916916 run2.step.dependOn(&run1.step);
917917
918918 // Test excluding non-existent file
919 const run3 = b.addSystemCommand(&.{ b.zig_exe, "fmt", "--exclude", "fmt2.zig", "--exclude", "nonexistent.zig", "." });
919 const run3 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "--exclude", "fmt2.zig", "--exclude", "nonexistent.zig", "." });
920920 run3.setName("run zig fmt on directory with non-existent exclusion");
921921 run3.setCwd(.{ .cwd_relative = tmp_path });
922922 run3.has_side_effects = true;
......@@ -924,7 +924,7 @@ pub fn addCliTests(b: *std.Build) *Step {
924924 run3.step.dependOn(&run2.step);
925925
926926 // running it on the dir, only the new file should be changed
927 const run4 = b.addSystemCommand(&.{ b.zig_exe, "fmt", "." });
927 const run4 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "." });
928928 run4.setName("run zig fmt the directory");
929929 run4.setCwd(.{ .cwd_relative = tmp_path });
930930 run4.has_side_effects = true;
......@@ -932,7 +932,7 @@ pub fn addCliTests(b: *std.Build) *Step {
932932 run4.step.dependOn(&run3.step);
933933
934934 // both files have been formatted, nothing should change now
935 const run5 = b.addSystemCommand(&.{ b.zig_exe, "fmt", "." });
935 const run5 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "." });
936936 run5.setName("run zig fmt with nothing to do");
937937 run5.setCwd(.{ .cwd_relative = tmp_path });
938938 run5.has_side_effects = true;
......@@ -946,7 +946,7 @@ pub fn addCliTests(b: *std.Build) *Step {
946946 write6.step.dependOn(&run5.step);
947947
948948 // Test `zig fmt` handling UTF-16 decoding.
949 const run6 = b.addSystemCommand(&.{ b.zig_exe, "fmt", "." });
949 const run6 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "." });
950950 run6.setName("run zig fmt convert UTF-16 to UTF-8");
951951 run6.setCwd(.{ .cwd_relative = tmp_path });
952952 run6.has_side_effects = true;