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 {...@@ -45,7 +45,7 @@ pub fn build(b: *std.Build) !void {
45 });45 });
4646
47 const docgen_cmd = b.addRunArtifact(docgen_exe);47 const docgen_cmd = b.addRunArtifact(docgen_exe);
48 docgen_cmd.addArgs(&.{ "--zig", b.zig_exe });48 docgen_cmd.addArgs(&.{ "--zig", b.graph.zig_exe });
49 if (b.zig_lib_dir) |p| {49 if (b.zig_lib_dir) |p| {
50 docgen_cmd.addArg("--zig-lib-dir");50 docgen_cmd.addArg("--zig-lib-dir");
51 docgen_cmd.addDirectoryArg(p);51 docgen_cmd.addDirectoryArg(p);
...@@ -884,7 +884,7 @@ fn findConfigH(b: *std.Build, config_h_path_option: ?[]const u8) ?[]const u8 {...@@ -884,7 +884,7 @@ fn findConfigH(b: *std.Build, config_h_path_option: ?[]const u8) ?[]const u8 {
884 }884 }
885 }885 }
886886
887 var check_dir = fs.path.dirname(b.zig_exe).?;887 var check_dir = fs.path.dirname(b.graph.zig_exe).?;
888 while (true) {888 while (true) {
889 var dir = fs.cwd().openDir(check_dir, .{}) catch unreachable;889 var dir = fs.cwd().openDir(check_dir, .{}) catch unreachable;
890 defer dir.close();890 defer dir.close();
deps/aro/build/GenerateDef.zig+1-1
...@@ -53,7 +53,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -53,7 +53,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
53 const self = @fieldParentPtr(GenerateDef, "step", step);53 const self = @fieldParentPtr(GenerateDef, "step", step);
54 const arena = b.allocator;54 const arena = b.allocator;
5555
56 var man = b.cache.obtain();56 var man = b.graph.cache.obtain();
57 defer man.deinit();57 defer man.deinit();
5858
59 // Random bytes to make GenerateDef unique. Refresh this with new59 // Random bytes to make GenerateDef unique. Refresh this with new
lib/build_runner.zig+205-136
...@@ -46,11 +46,6 @@ pub fn main() !void {...@@ -46,11 +46,6 @@ pub fn main() !void {
46 return error.InvalidArgs;46 return error.InvalidArgs;
47 };47 };
4848
49 const host: std.Build.ResolvedTarget = .{
50 .query = .{},
51 .result = try std.zig.system.resolveTargetQuery(.{}),
52 };
53
54 const build_root_directory: std.Build.Cache.Directory = .{49 const build_root_directory: std.Build.Cache.Directory = .{
55 .path = build_root,50 .path = build_root,
56 .handle = try std.fs.cwd().openDir(build_root, .{}),51 .handle = try std.fs.cwd().openDir(build_root, .{}),
...@@ -66,27 +61,29 @@ pub fn main() !void {...@@ -66,27 +61,29 @@ pub fn main() !void {
66 .handle = try std.fs.cwd().makeOpenPath(global_cache_root, .{}),61 .handle = try std.fs.cwd().makeOpenPath(global_cache_root, .{}),
67 };62 };
6863
69 var cache: std.Build.Cache = .{64 var graph: std.Build.Graph = .{
70 .gpa = arena,65 .arena = arena,
71 .manifest_dir = try local_cache_directory.handle.makeOpenPath("h", .{}),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,
72 };73 };
73 cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });74
74 cache.addPrefix(build_root_directory);75 graph.cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
75 cache.addPrefix(local_cache_directory);76 graph.cache.addPrefix(build_root_directory);
76 cache.addPrefix(global_cache_directory);77 graph.cache.addPrefix(local_cache_directory);
77 cache.hash.addBytes(builtin.zig_version_string);78 graph.cache.addPrefix(global_cache_directory);
79 graph.cache.hash.addBytes(builtin.zig_version_string);
7880
79 const builder = try std.Build.create(81 const builder = try std.Build.create(
80 arena,82 &graph,
81 zig_exe,
82 build_root_directory,83 build_root_directory,
83 local_cache_directory,84 local_cache_directory,
84 global_cache_directory,
85 host,
86 &cache,
87 dependencies.root_deps,85 dependencies.root_deps,
88 );86 );
89 defer builder.destroy();
9087
91 var targets = ArrayList([]const u8).init(arena);88 var targets = ArrayList([]const u8).init(arena);
92 var debug_log_scopes = ArrayList([]const u8).init(arena);89 var debug_log_scopes = ArrayList([]const u8).init(arena);
...@@ -100,64 +97,67 @@ pub fn main() !void {...@@ -100,64 +97,67 @@ pub fn main() !void {
100 var color: Color = .auto;97 var color: Color = .auto;
101 var seed: u32 = 0;98 var seed: u32 = 0;
102 var prominent_compile_errors: bool = false;99 var prominent_compile_errors: bool = false;
103100 var help_menu: bool = false;
104 const stderr_stream = io.getStdErr().writer();101 var steps_menu: bool = false;
105 const stdout_stream = io.getStdOut().writer();102 var output_tmp_nonce: ?[16]u8 = null;
106103
107 while (nextArg(args, &arg_idx)) |arg| {104 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")) {
109 const option_contents = arg[2..];109 const option_contents = arg[2..];
110 if (option_contents.len == 0) {110 if (option_contents.len == 0)
111 std.debug.print("Expected option name after '-D'\n\n", .{});111 fatalWithHint("expected option name after '-D'", .{});
112 usageAndErr(builder, false, stderr_stream);
113 }
114 if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| {112 if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| {
115 const option_name = option_contents[0..name_end];113 const option_name = option_contents[0..name_end];
116 const option_value = option_contents[name_end + 1 ..];114 const option_value = option_contents[name_end + 1 ..];
117 if (try builder.addUserInputOption(option_name, option_value))115 if (try builder.addUserInputOption(option_name, option_value))
118 usageAndErr(builder, false, stderr_stream);116 fatal(" access the help menu with 'zig build -h'", .{});
119 } else {117 } else {
120 if (try builder.addUserInputFlag(option_contents))118 if (try builder.addUserInputFlag(option_contents))
121 usageAndErr(builder, false, stderr_stream);119 fatal(" access the help menu with 'zig build -h'", .{});
122 }120 }
123 } else if (mem.startsWith(u8, arg, "-")) {121 } else if (mem.startsWith(u8, arg, "-")) {
124 if (mem.eql(u8, arg, "--verbose")) {122 if (mem.eql(u8, arg, "--verbose")) {
125 builder.verbose = true;123 builder.verbose = true;
126 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {124 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
127 return usage(builder, false, stdout_stream);125 help_menu = true;
128 } else if (mem.eql(u8, arg, "-p") or mem.eql(u8, arg, "--prefix")) {126 } else if (mem.eql(u8, arg, "-p") or mem.eql(u8, arg, "--prefix")) {
129 install_prefix = nextArg(args, &arg_idx) orelse {127 install_prefix = nextArgOrFatal(args, &arg_idx);
130 std.debug.print("Expected argument after {s}\n\n", .{arg});
131 usageAndErr(builder, false, stderr_stream);
132 };
133 } else if (mem.eql(u8, arg, "-l") or mem.eql(u8, arg, "--list-steps")) {128 } else if (mem.eql(u8, arg, "-l") or mem.eql(u8, arg, "--list-steps")) {
134 return steps(builder, false, stdout_stream);129 steps_menu = true;
135 } else if (mem.eql(u8, arg, "--prefix-lib-dir")) {130 } else if (mem.startsWith(u8, arg, "-fsys=")) {
136 dir_list.lib_dir = nextArg(args, &arg_idx) orelse {131 const name = arg["-fsys=".len..];
137 std.debug.print("Expected argument after {s}\n\n", .{arg});132 graph.system_library_options.put(arena, name, .user_enabled) catch @panic("OOM");
138 usageAndErr(builder, false, stderr_stream);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 });
139 };144 };
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);
140 } else if (mem.eql(u8, arg, "--prefix-exe-dir")) {153 } else if (mem.eql(u8, arg, "--prefix-exe-dir")) {
141 dir_list.exe_dir = nextArg(args, &arg_idx) orelse {154 dir_list.exe_dir = nextArgOrFatal(args, &arg_idx);
142 std.debug.print("Expected argument after {s}\n\n", .{arg});
143 usageAndErr(builder, false, stderr_stream);
144 };
145 } else if (mem.eql(u8, arg, "--prefix-include-dir")) {155 } else if (mem.eql(u8, arg, "--prefix-include-dir")) {
146 dir_list.include_dir = nextArg(args, &arg_idx) orelse {156 dir_list.include_dir = nextArgOrFatal(args, &arg_idx);
147 std.debug.print("Expected argument after {s}\n\n", .{arg});
148 usageAndErr(builder, false, stderr_stream);
149 };
150 } else if (mem.eql(u8, arg, "--sysroot")) {157 } else if (mem.eql(u8, arg, "--sysroot")) {
151 const sysroot = nextArg(args, &arg_idx) orelse {158 builder.sysroot = nextArgOrFatal(args, &arg_idx);
152 std.debug.print("Expected argument after {s}\n\n", .{arg});
153 usageAndErr(builder, false, stderr_stream);
154 };
155 builder.sysroot = sysroot;
156 } else if (mem.eql(u8, arg, "--maxrss")) {159 } else if (mem.eql(u8, arg, "--maxrss")) {
157 const max_rss_text = nextArg(args, &arg_idx) orelse {160 const max_rss_text = nextArgOrFatal(args, &arg_idx);
158 std.debug.print("Expected argument after {s}\n\n", .{arg});
159 usageAndErr(builder, false, stderr_stream);
160 };
161 max_rss = std.fmt.parseIntSizeSuffix(max_rss_text, 10) catch |err| {161 max_rss = std.fmt.parseIntSizeSuffix(max_rss_text, 10) catch |err| {
162 std.debug.print("invalid byte size: '{s}': {s}\n", .{162 std.debug.print("invalid byte size: '{s}': {s}\n", .{
163 max_rss_text, @errorName(err),163 max_rss_text, @errorName(err),
...@@ -167,66 +167,50 @@ pub fn main() !void {...@@ -167,66 +167,50 @@ pub fn main() !void {
167 } else if (mem.eql(u8, arg, "--skip-oom-steps")) {167 } else if (mem.eql(u8, arg, "--skip-oom-steps")) {
168 skip_oom_steps = true;168 skip_oom_steps = true;
169 } else if (mem.eql(u8, arg, "--search-prefix")) {169 } else if (mem.eql(u8, arg, "--search-prefix")) {
170 const search_prefix = nextArg(args, &arg_idx) orelse {170 const search_prefix = nextArgOrFatal(args, &arg_idx);
171 std.debug.print("Expected argument after {s}\n\n", .{arg});
172 usageAndErr(builder, false, stderr_stream);
173 };
174 builder.addSearchPrefix(search_prefix);171 builder.addSearchPrefix(search_prefix);
175 } else if (mem.eql(u8, arg, "--libc")) {172 } else if (mem.eql(u8, arg, "--libc")) {
176 const libc_file = nextArg(args, &arg_idx) orelse {173 builder.libc_file = nextArgOrFatal(args, &arg_idx);
177 std.debug.print("Expected argument after {s}\n\n", .{arg});
178 usageAndErr(builder, false, stderr_stream);
179 };
180 builder.libc_file = libc_file;
181 } else if (mem.eql(u8, arg, "--color")) {174 } else if (mem.eql(u8, arg, "--color")) {
182 const next_arg = nextArg(args, &arg_idx) orelse {175 const next_arg = nextArg(args, &arg_idx) orelse
183 std.debug.print("Expected [auto|on|off] after {s}\n\n", .{arg});176 fatalWithHint("expected [auto|on|off] after '{s}'", .{arg});
184 usageAndErr(builder, false, stderr_stream);
185 };
186 color = std.meta.stringToEnum(Color, next_arg) orelse {177 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 });178 fatalWithHint("expected [auto|on|off] after '{s}', found '{s}'", .{
188 usageAndErr(builder, false, stderr_stream);179 arg, next_arg,
180 });
189 };181 };
190 } else if (mem.eql(u8, arg, "--summary")) {182 } else if (mem.eql(u8, arg, "--summary")) {
191 const next_arg = nextArg(args, &arg_idx) orelse {183 const next_arg = nextArg(args, &arg_idx) orelse
192 std.debug.print("Expected [all|failures|none] after {s}\n\n", .{arg});184 fatalWithHint("expected [all|failures|none] after '{s}'", .{arg});
193 usageAndErr(builder, false, stderr_stream);
194 };
195 summary = std.meta.stringToEnum(Summary, next_arg) orelse {185 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 });186 fatalWithHint("expected [all|failures|none] after '{s}', found '{s}'", .{
197 usageAndErr(builder, false, stderr_stream);187 arg, next_arg,
188 });
198 };189 };
199 } else if (mem.eql(u8, arg, "--zig-lib-dir")) {190 } else if (mem.eql(u8, arg, "--zig-lib-dir")) {
200 builder.zig_lib_dir = .{ .cwd_relative = nextArg(args, &arg_idx) orelse {191 builder.zig_lib_dir = .{ .cwd_relative = nextArgOrFatal(args, &arg_idx) };
201 std.debug.print("Expected argument after {s}\n\n", .{arg});
202 usageAndErr(builder, false, stderr_stream);
203 } };
204 } else if (mem.eql(u8, arg, "--seed")) {192 } else if (mem.eql(u8, arg, "--seed")) {
205 const next_arg = nextArg(args, &arg_idx) orelse {193 const next_arg = nextArg(args, &arg_idx) orelse
206 std.debug.print("Expected u32 after {s}\n\n", .{arg});194 fatalWithHint("expected u32 after '{s}'", .{arg});
207 usageAndErr(builder, false, stderr_stream);
208 };
209 seed = std.fmt.parseUnsigned(u32, next_arg, 0) catch |err| {195 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", .{
211 next_arg, @errorName(err),197 next_arg, @errorName(err),
212 });198 });
213 process.exit(1);
214 };199 };
215 } else if (mem.eql(u8, arg, "--debug-log")) {200 } else if (mem.eql(u8, arg, "--debug-log")) {
216 const next_arg = nextArg(args, &arg_idx) orelse {201 const next_arg = nextArgOrFatal(args, &arg_idx);
217 std.debug.print("Expected argument after {s}\n\n", .{arg});
218 usageAndErr(builder, false, stderr_stream);
219 };
220 try debug_log_scopes.append(next_arg);202 try debug_log_scopes.append(next_arg);
221 } else if (mem.eql(u8, arg, "--debug-pkg-config")) {203 } else if (mem.eql(u8, arg, "--debug-pkg-config")) {
222 builder.debug_pkg_config = true;204 builder.debug_pkg_config = true;
223 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {205 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
224 builder.debug_compile_errors = true;206 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;
225 } else if (mem.eql(u8, arg, "--glibc-runtimes")) {212 } else if (mem.eql(u8, arg, "--glibc-runtimes")) {
226 builder.glibc_runtimes_dir = nextArg(args, &arg_idx) orelse {213 builder.glibc_runtimes_dir = nextArgOrFatal(args, &arg_idx);
227 std.debug.print("Expected argument after {s}\n\n", .{arg});
228 usageAndErr(builder, false, stderr_stream);
229 };
230 } else if (mem.eql(u8, arg, "--verbose-link")) {214 } else if (mem.eql(u8, arg, "--verbose-link")) {
231 builder.verbose_link = true;215 builder.verbose_link = true;
232 } else if (mem.eql(u8, arg, "--verbose-air")) {216 } else if (mem.eql(u8, arg, "--verbose-air")) {
...@@ -292,19 +276,26 @@ pub fn main() !void {...@@ -292,19 +276,26 @@ pub fn main() !void {
292 builder.args = argsRest(args, arg_idx);276 builder.args = argsRest(args, arg_idx);
293 break;277 break;
294 } else {278 } else {
295 std.debug.print("Unrecognized argument: {s}\n\n", .{arg});279 fatalWithHint("unrecognized argument: '{s}'", .{arg});
296 usageAndErr(builder, false, stderr_stream);
297 }280 }
298 } else {281 } else {
299 try targets.append(arg);282 try targets.append(arg);
300 }283 }
301 }284 }
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
303 const stderr = std.io.getStdErr();294 const stderr = std.io.getStdErr();
304 const ttyconf = get_tty_conf(color, stderr);295 const ttyconf = get_tty_conf(color, stderr);
305 switch (ttyconf) {296 switch (ttyconf) {
306 .no_color => try builder.env_map.put("NO_COLOR", "1"),297 .no_color => try graph.env_map.put("NO_COLOR", "1"),
307 .escape_codes => try builder.env_map.put("YES_COLOR", "1"),298 .escape_codes => try graph.env_map.put("YES_COLOR", "1"),
308 .windows_api => {},299 .windows_api => {},
309 }300 }
310301
...@@ -319,8 +310,39 @@ pub fn main() !void {...@@ -319,8 +310,39 @@ pub fn main() !void {
319 try builder.runBuild(root);310 try builder.runBuild(root);
320 }311 }
321312
322 if (builder.validateUserInputDidItFail())313 if (graph.needed_lazy_dependencies.entries.len != 0) {
323 usageAndErr(builder, true, stderr_stream);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
325 var run: Run = .{347 var run: Run = .{
326 .max_rss = max_rss,348 .max_rss = max_rss,
...@@ -389,7 +411,7 @@ fn runStepNames(...@@ -389,7 +411,7 @@ fn runStepNames(
389 for (0..step_names.len) |i| {411 for (0..step_names.len) |i| {
390 const step_name = step_names[step_names.len - i - 1];412 const step_name = step_names[step_names.len - i - 1];
391 const s = b.top_level_steps.get(step_name) orelse {413 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});
393 process.exit(1);415 process.exit(1);
394 };416 };
395 step_stack.putAssumeCapacity(&s.step, {});417 step_stack.putAssumeCapacity(&s.step, {});
...@@ -1037,13 +1059,7 @@ fn printErrorMessages(b: *std.Build, failing_step: *Step, run: *const Run) !void...@@ -1037,13 +1059,7 @@ fn printErrorMessages(b: *std.Build, failing_step: *Step, run: *const Run) !void
1037 }1059 }
1038}1060}
10391061
1040fn steps(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !void {1062fn steps(builder: *std.Build, out_stream: anytype) !void {
1041 // run the build script to collect the options
1042 if (!already_ran_build) {
1043 builder.resolveInstallPrefix(null, .{});
1044 try builder.runBuild(root);
1045 }
1046
1047 const allocator = builder.allocator;1063 const allocator = builder.allocator;
1048 for (builder.top_level_steps.values()) |top_level_step| {1064 for (builder.top_level_steps.values()) |top_level_step| {
1049 const name = if (&top_level_step.step == builder.default_step)1065 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...@@ -1054,33 +1070,25 @@ fn steps(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
1054 }1070 }
1055}1071}
10561072
1057fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !void {1073fn usage(b: *std.Build, out_stream: anytype) !void {
1058 // run the build script to collect the options
1059 if (!already_ran_build) {
1060 builder.resolveInstallPrefix(null, .{});
1061 try builder.runBuild(root);
1062 }
1063
1064 try out_stream.print(1074 try out_stream.print(
1065 \\
1066 \\Usage: {s} build [steps] [options]1075 \\Usage: {s} build [steps] [options]
1067 \\1076 \\
1068 \\Steps:1077 \\Steps:
1069 \\1078 \\
1070 , .{builder.zig_exe});1079 , .{b.graph.zig_exe});
1071 try steps(builder, true, out_stream);1080 try steps(b, out_stream);
10721081
1073 try out_stream.writeAll(1082 try out_stream.writeAll(
1074 \\1083 \\
1075 \\General Options:1084 \\General Options:
1076 \\ -p, --prefix [path] Override default install prefix1085 \\ -p, --prefix [path] Where to install files (default: zig-out)
1077 \\ --prefix-lib-dir [path] Override default library directory path1086 \\ --prefix-lib-dir [path] Where to install libraries
1078 \\ --prefix-exe-dir [path] Override default executable directory path1087 \\ --prefix-exe-dir [path] Where to install executables
1079 \\ --prefix-include-dir [path] Override default include directory path1088 \\ --prefix-include-dir [path] Where to install C header files
1080 \\1089 \\
1081 \\ --sysroot [path] Set the system root directory (usually /)1090 \\ --release[=mode] Request release mode, optionally specifying a
1082 \\ --search-prefix [path] Add a path to look for binaries, libraries, headers1091 \\ preferred optimization mode: fast, safe, small
1083 \\ --libc [file] Provide a file which specifies libc paths
1084 \\1092 \\
1085 \\ -fdarling, -fno-darling Integration with system-installed Darling to1093 \\ -fdarling, -fno-darling Integration with system-installed Darling to
1086 \\ execute macOS programs on Linux hosts1094 \\ execute macOS programs on Linux hosts
...@@ -1116,16 +1124,15 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi...@@ -1116,16 +1124,15 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
1116 \\1124 \\
1117 );1125 );
11181126
1119 const allocator = builder.allocator;1127 const arena = b.allocator;
1120 if (builder.available_options_list.items.len == 0) {1128 if (b.available_options_list.items.len == 0) {
1121 try out_stream.print(" (none)\n", .{});1129 try out_stream.print(" (none)\n", .{});
1122 } else {1130 } else {
1123 for (builder.available_options_list.items) |option| {1131 for (b.available_options_list.items) |option| {
1124 const name = try fmt.allocPrint(allocator, " -D{s}=[{s}]", .{1132 const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{
1125 option.name,1133 option.name,
1126 @tagName(option.type_id),1134 @tagName(option.type_id),
1127 });1135 });
1128 defer allocator.free(name);
1129 try out_stream.print("{s:<30} {s}\n", .{ name, option.description });1136 try out_stream.print("{s:<30} {s}\n", .{ name, option.description });
1130 if (option.enum_options) |enum_options| {1137 if (option.enum_options) |enum_options| {
1131 const padding = " " ** 33;1138 const padding = " " ** 33;
...@@ -1137,6 +1144,37 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi...@@ -1137,6 +1144,37 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
1137 }1144 }
1138 }1145 }
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
1140 try out_stream.writeAll(1178 try out_stream.writeAll(
1141 \\1179 \\
1142 \\Advanced Options:1180 \\Advanced Options:
...@@ -1161,17 +1199,19 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi...@@ -1161,17 +1199,19 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
1161 );1199 );
1162}1200}
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
1169fn nextArg(args: [][:0]const u8, idx: *usize) ?[:0]const u8 {1202fn nextArg(args: [][:0]const u8, idx: *usize) ?[:0]const u8 {
1170 if (idx.* >= args.len) return null;1203 if (idx.* >= args.len) return null;
1171 defer idx.* += 1;1204 defer idx.* += 1;
1172 return args[idx.*];1205 return args[idx.*];
1173}1206}
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
1175fn argsRest(args: [][:0]const u8, idx: usize) ?[][:0]const u8 {1215fn argsRest(args: [][:0]const u8, idx: usize) ?[][:0]const u8 {
1176 if (idx >= args.len) return null;1216 if (idx >= args.len) return null;
1177 return args[idx..];1217 return args[idx..];
...@@ -1202,3 +1242,32 @@ fn renderOptions(ttyconf: std.io.tty.Config) std.zig.ErrorBundle.RenderOptions {...@@ -1202,3 +1242,32 @@ fn renderOptions(ttyconf: std.io.tty.Config) std.zig.ErrorBundle.RenderOptions {
1202 .include_reference_trace = ttyconf != .no_color,1242 .include_reference_trace = ttyconf != .no_color,
1203 };1243 };
1204}1244}
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");...@@ -22,6 +22,8 @@ pub const Cache = @import("Build/Cache.zig");
22pub const Step = @import("Build/Step.zig");22pub const Step = @import("Build/Step.zig");
23pub const Module = @import("Build/Module.zig");23pub const Module = @import("Build/Module.zig");
2424
25/// Shared state among all Build instances.
26graph: *Graph,
25install_tls: TopLevelStep,27install_tls: TopLevelStep,
26uninstall_tls: TopLevelStep,28uninstall_tls: TopLevelStep,
27allocator: Allocator,29allocator: Allocator,
...@@ -38,9 +40,7 @@ verbose_cimport: bool,...@@ -38,9 +40,7 @@ verbose_cimport: bool,
38verbose_llvm_cpu_features: bool,40verbose_llvm_cpu_features: bool,
39reference_trace: ?u32 = null,41reference_trace: ?u32 = null,
40invalid_user_input: bool,42invalid_user_input: bool,
41zig_exe: [:0]const u8,
42default_step: *Step,43default_step: *Step,
43env_map: *EnvMap,
44top_level_steps: std.StringArrayHashMapUnmanaged(*TopLevelStep),44top_level_steps: std.StringArrayHashMapUnmanaged(*TopLevelStep),
45install_prefix: []const u8,45install_prefix: []const u8,
46dest_dir: ?[]const u8,46dest_dir: ?[]const u8,
...@@ -49,14 +49,12 @@ exe_dir: []const u8,...@@ -49,14 +49,12 @@ exe_dir: []const u8,
49h_dir: []const u8,49h_dir: []const u8,
50install_path: []const u8,50install_path: []const u8,
51sysroot: ?[]const u8 = null,51sysroot: ?[]const u8 = null,
52search_prefixes: ArrayList([]const u8),52search_prefixes: std.ArrayListUnmanaged([]const u8),
53libc_file: ?[]const u8 = null,53libc_file: ?[]const u8 = null,
54installed_files: ArrayList(InstalledFile),54installed_files: ArrayList(InstalledFile),
55/// Path to the directory containing build.zig.55/// Path to the directory containing build.zig.
56build_root: Cache.Directory,56build_root: Cache.Directory,
57cache_root: Cache.Directory,57cache_root: Cache.Directory,
58global_cache_root: Cache.Directory,
59cache: *Cache,
60zig_lib_dir: ?LazyPath,58zig_lib_dir: ?LazyPath,
61pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null,59pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null,
62args: ?[][]const u8 = null,60args: ?[][]const u8 = null,
...@@ -98,8 +96,47 @@ initialized_deps: *InitializedDepMap,...@@ -98,8 +96,47 @@ initialized_deps: *InitializedDepMap,
98/// A mapping from dependency names to package hashes.96/// A mapping from dependency names to package hashes.
99available_deps: AvailableDeps,97available_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
101const AvailableDeps = []const struct { []const u8, []const u8 };123const 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
103const InitializedDepMap = std.HashMap(InitializedDepKey, *Dependency, InitializedDepContext, std.hash_map.default_max_load_percentage);140const InitializedDepMap = std.HashMap(InitializedDepKey, *Dependency, InitializedDepContext, std.hash_map.default_max_load_percentage);
104const InitializedDepKey = struct {141const InitializedDepKey = struct {
105 build_root_string: []const u8,142 build_root_string: []const u8,
...@@ -208,28 +245,20 @@ pub const DirList = struct {...@@ -208,28 +245,20 @@ pub const DirList = struct {
208};245};
209246
210pub fn create(247pub fn create(
211 allocator: Allocator,248 graph: *Graph,
212 zig_exe: [:0]const u8,
213 build_root: Cache.Directory,249 build_root: Cache.Directory,
214 cache_root: Cache.Directory,250 cache_root: Cache.Directory,
215 global_cache_root: Cache.Directory,
216 host: ResolvedTarget,
217 cache: *Cache,
218 available_deps: AvailableDeps,251 available_deps: AvailableDeps,
219) !*Build {252) !*Build {
220 const env_map = try allocator.create(EnvMap);253 const arena = graph.arena;
221 env_map.* = try process.getEnvMap(allocator);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);257 const self = try arena.create(Build);
224 initialized_deps.* = InitializedDepMap.initContext(allocator, .{ .allocator = allocator });
225
226 const self = try allocator.create(Build);
227 self.* = .{258 self.* = .{
228 .zig_exe = zig_exe,259 .graph = graph,
229 .build_root = build_root,260 .build_root = build_root,
230 .cache_root = cache_root,261 .cache_root = cache_root,
231 .global_cache_root = global_cache_root,
232 .cache = cache,
233 .verbose = false,262 .verbose = false,
234 .verbose_link = false,263 .verbose_link = false,
235 .verbose_cc = false,264 .verbose_cc = false,
...@@ -239,20 +268,19 @@ pub fn create(...@@ -239,20 +268,19 @@ pub fn create(
239 .verbose_cimport = false,268 .verbose_cimport = false,
240 .verbose_llvm_cpu_features = false,269 .verbose_llvm_cpu_features = false,
241 .invalid_user_input = false,270 .invalid_user_input = false,
242 .allocator = allocator,271 .allocator = arena,
243 .user_input_options = UserInputOptionsMap.init(allocator),272 .user_input_options = UserInputOptionsMap.init(arena),
244 .available_options_map = AvailableOptionsMap.init(allocator),273 .available_options_map = AvailableOptionsMap.init(arena),
245 .available_options_list = ArrayList(AvailableOption).init(allocator),274 .available_options_list = ArrayList(AvailableOption).init(arena),
246 .top_level_steps = .{},275 .top_level_steps = .{},
247 .default_step = undefined,276 .default_step = undefined,
248 .env_map = env_map,277 .search_prefixes = .{},
249 .search_prefixes = ArrayList([]const u8).init(allocator),
250 .install_prefix = undefined,278 .install_prefix = undefined,
251 .lib_dir = undefined,279 .lib_dir = undefined,
252 .exe_dir = undefined,280 .exe_dir = undefined,
253 .h_dir = undefined,281 .h_dir = undefined,
254 .dest_dir = env_map.get("DESTDIR"),282 .dest_dir = graph.env_map.get("DESTDIR"),
255 .installed_files = ArrayList(InstalledFile).init(allocator),283 .installed_files = ArrayList(InstalledFile).init(arena),
256 .install_tls = .{284 .install_tls = .{
257 .step = Step.init(.{285 .step = Step.init(.{
258 .id = .top_level,286 .id = .top_level,
...@@ -273,14 +301,15 @@ pub fn create(...@@ -273,14 +301,15 @@ pub fn create(
273 .zig_lib_dir = null,301 .zig_lib_dir = null,
274 .install_path = undefined,302 .install_path = undefined,
275 .args = null,303 .args = null,
276 .host = host,304 .host = undefined,
277 .modules = std.StringArrayHashMap(*Module).init(allocator),305 .modules = std.StringArrayHashMap(*Module).init(arena),
278 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator),306 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(arena),
279 .initialized_deps = initialized_deps,307 .initialized_deps = initialized_deps,
280 .available_deps = available_deps,308 .available_deps = available_deps,
309 .release_mode = .off,
281 };310 };
282 try self.top_level_steps.put(allocator, self.install_tls.step.name, &self.install_tls);311 try self.top_level_steps.put(arena, self.install_tls.step.name, &self.install_tls);
283 try self.top_level_steps.put(allocator, self.uninstall_tls.step.name, &self.uninstall_tls);312 try self.top_level_steps.put(arena, self.uninstall_tls.step.name, &self.uninstall_tls);
284 self.default_step = &self.install_tls.step;313 self.default_step = &self.install_tls.step;
285 return self;314 return self;
286}315}
...@@ -297,10 +326,17 @@ fn createChild(...@@ -297,10 +326,17 @@ fn createChild(
297 return child;326 return child;
298}327}
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 {
301 const allocator = parent.allocator;336 const allocator = parent.allocator;
302 const child = try allocator.create(Build);337 const child = try allocator.create(Build);
303 child.* = .{338 child.* = .{
339 .graph = parent.graph,
304 .allocator = allocator,340 .allocator = allocator,
305 .install_tls = .{341 .install_tls = .{
306 .step = Step.init(.{342 .step = Step.init(.{
...@@ -332,9 +368,7 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc...@@ -332,9 +368,7 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc
332 .verbose_llvm_cpu_features = parent.verbose_llvm_cpu_features,368 .verbose_llvm_cpu_features = parent.verbose_llvm_cpu_features,
333 .reference_trace = parent.reference_trace,369 .reference_trace = parent.reference_trace,
334 .invalid_user_input = false,370 .invalid_user_input = false,
335 .zig_exe = parent.zig_exe,
336 .default_step = undefined,371 .default_step = undefined,
337 .env_map = parent.env_map,
338 .top_level_steps = .{},372 .top_level_steps = .{},
339 .install_prefix = undefined,373 .install_prefix = undefined,
340 .dest_dir = parent.dest_dir,374 .dest_dir = parent.dest_dir,
...@@ -348,8 +382,6 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc...@@ -348,8 +382,6 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc
348 .installed_files = ArrayList(InstalledFile).init(allocator),382 .installed_files = ArrayList(InstalledFile).init(allocator),
349 .build_root = build_root,383 .build_root = build_root,
350 .cache_root = parent.cache_root,384 .cache_root = parent.cache_root,
351 .global_cache_root = parent.global_cache_root,
352 .cache = parent.cache,
353 .zig_lib_dir = parent.zig_lib_dir,385 .zig_lib_dir = parent.zig_lib_dir,
354 .debug_log_scopes = parent.debug_log_scopes,386 .debug_log_scopes = parent.debug_log_scopes,
355 .debug_compile_errors = parent.debug_compile_errors,387 .debug_compile_errors = parent.debug_compile_errors,
...@@ -366,6 +398,7 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc...@@ -366,6 +398,7 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc
366 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator),398 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator),
367 .initialized_deps = parent.initialized_deps,399 .initialized_deps = parent.initialized_deps,
368 .available_deps = pkg_deps,400 .available_deps = pkg_deps,
401 .release_mode = parent.release_mode,
369 };402 };
370 try child.top_level_steps.put(allocator, child.install_tls.step.name, &child.install_tls);403 try child.top_level_steps.put(allocator, child.install_tls.step.name, &child.install_tls);
371 try child.top_level_steps.put(allocator, child.uninstall_tls.step.name, &child.uninstall_tls);404 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...@@ -543,7 +576,7 @@ fn hashUserInputOptionsMap(allocator: Allocator, user_input_options: UserInputOp
543fn determineAndApplyInstallPrefix(b: *Build) !void {576fn determineAndApplyInstallPrefix(b: *Build) !void {
544 // Create an installation directory local to this package. This will be used when577 // Create an installation directory local to this package. This will be used when
545 // dependant packages require a standard prefix, such as include directories for C headers.578 // 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;
547 // Random bytes to make unique. Refresh this with new random bytes when580 // Random bytes to make unique. Refresh this with new random bytes when
548 // implementation is modified in a non-backwards-compatible way.581 // implementation is modified in a non-backwards-compatible way.
549 hash.add(@as(u32, 0xd8cb0055));582 hash.add(@as(u32, 0xd8cb0055));
...@@ -558,12 +591,6 @@ fn determineAndApplyInstallPrefix(b: *Build) !void {...@@ -558,12 +591,6 @@ fn determineAndApplyInstallPrefix(b: *Build) !void {
558 b.resolveInstallPrefix(install_prefix, .{});591 b.resolveInstallPrefix(install_prefix, .{});
559}592}
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
567/// This function is intended to be called by lib/build_runner.zig, not a build.zig file.594/// This function is intended to be called by lib/build_runner.zig, not a build.zig file.
568pub fn resolveInstallPrefix(self: *Build, install_prefix: ?[]const u8, dir_list: DirList) void {595pub fn resolveInstallPrefix(self: *Build, install_prefix: ?[]const u8, dir_list: DirList) void {
569 if (self.dest_dir) |dest_dir| {596 if (self.dest_dir) |dest_dir| {
...@@ -1216,20 +1243,33 @@ pub const StandardOptimizeOptionOptions = struct {...@@ -1216,20 +1243,33 @@ pub const StandardOptimizeOptionOptions = struct {
1216 preferred_optimize_mode: ?std.builtin.OptimizeMode = null,1243 preferred_optimize_mode: ?std.builtin.OptimizeMode = null,
1217};1244};
12181245
1219pub fn standardOptimizeOption(self: *Build, options: StandardOptimizeOptionOptions) std.builtin.OptimizeMode {1246pub fn standardOptimizeOption(b: *Build, options: StandardOptimizeOptionOptions) std.builtin.OptimizeMode {
1220 if (options.preferred_optimize_mode) |mode| {1247 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)) {
1222 return mode;1249 return mode;
1223 } else {1250 } else {
1224 return .Debug;1251 return .Debug;
1225 }1252 }
1226 } else {
1227 return self.option(
1228 std.builtin.OptimizeMode,
1229 "optimize",
1230 "Prioritize performance, safety, or binary size (-O flag)",
1231 ) orelse .Debug;
1232 }1253 }
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 };
1233}1273}
12341274
1235pub const StandardTargetOptionsArgs = struct {1275pub const StandardTargetOptionsArgs = struct {
...@@ -1244,67 +1284,83 @@ pub fn standardTargetOptions(b: *Build, args: StandardTargetOptionsArgs) Resolve...@@ -1244,67 +1284,83 @@ pub fn standardTargetOptions(b: *Build, args: StandardTargetOptionsArgs) Resolve
1244 return b.resolveTargetQuery(query);1284 return b.resolveTargetQuery(query);
1245}1285}
12461286
1247/// Exposes standard `zig build` options for choosing a target.1287pub fn parseTargetQuery(options: std.Target.Query.ParseOptions) error{ParseFailed}!std.Target.Query {
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
1262 var diags: Target.Query.ParseOptions.Diagnostics = .{};1288 var diags: Target.Query.ParseOptions.Diagnostics = .{};
1263 const selected_target = Target.Query.parse(.{1289 var opts_copy = options;
1264 .arch_os_abi = triple,1290 opts_copy.diagnostics = &diags;
1265 .cpu_features = mcpu,1291 return std.Target.Query.parse(options) catch |err| switch (err) {
1266 .diagnostics = &diags,
1267 }) catch |err| switch (err) {
1268 error.UnknownCpuModel => {1292 error.UnknownCpuModel => {
1269 log.err("Unknown CPU: '{s}'\nAvailable CPUs for architecture '{s}':", .{1293 std.debug.print("unknown CPU: '{s}'\navailable CPUs for architecture '{s}':\n", .{
1270 diags.cpu_name.?,1294 diags.cpu_name.?, @tagName(diags.arch.?),
1271 @tagName(diags.arch.?),
1272 });1295 });
1273 for (diags.arch.?.allCpuModels()) |cpu| {1296 for (diags.arch.?.allCpuModels()) |cpu| {
1274 log.err(" {s}", .{cpu.name});1297 std.debug.print(" {s}\n", .{cpu.name});
1275 }1298 }
1276 b.markInvalidUserInput();1299 return error.ParseFailed;
1277 return args.default_target;
1278 },1300 },
1279 error.UnknownCpuFeature => {1301 error.UnknownCpuFeature => {
1280 log.err(1302 std.debug.print(
1281 \\Unknown CPU feature: '{s}'1303 \\unknown CPU feature: '{s}'
1282 \\Available CPU features for architecture '{s}':1304 \\available CPU features for architecture '{s}':
1283 \\1305 \\
1284 , .{1306 , .{
1285 diags.unknown_feature_name.?,1307 diags.unknown_feature_name.?,
1286 @tagName(diags.arch.?),1308 @tagName(diags.arch.?),
1287 });1309 });
1288 for (diags.arch.?.allFeaturesList()) |feature| {1310 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 });
1290 }1312 }
1291 b.markInvalidUserInput();1313 return error.ParseFailed;
1292 return args.default_target;
1293 },1314 },
1294 error.UnknownOperatingSystem => {1315 error.UnknownOperatingSystem => {
1295 log.err(1316 std.debug.print(
1296 \\Unknown OS: '{s}'1317 \\unknown OS: '{s}'
1297 \\Available operating systems:1318 \\available operating systems:
1298 \\1319 \\
1299 , .{diags.os_name.?});1320 , .{diags.os_name.?});
1300 inline for (std.meta.fields(Target.Os.Tag)) |field| {1321 inline for (std.meta.fields(Target.Os.Tag)) |field| {
1301 log.err(" {s}", .{field.name});1322 std.debug.print(" {s}\n", .{field.name});
1302 }1323 }
1303 b.markInvalidUserInput();1324 return error.ParseFailed;
1304 return args.default_target;
1305 },1325 },
1306 else => |e| {1326 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 => {
1308 b.markInvalidUserInput();1364 b.markInvalidUserInput();
1309 return args.default_target;1365 return args.default_target;
1310 },1366 },
...@@ -1367,7 +1423,7 @@ pub fn addUserInputOption(self: *Build, name_raw: []const u8, value_raw: []const...@@ -1367,7 +1423,7 @@ pub fn addUserInputOption(self: *Build, name_raw: []const u8, value_raw: []const
1367 });1423 });
1368 },1424 },
1369 .flag => {1425 .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 });
1371 return true;1427 return true;
1372 },1428 },
1373 .map => |*map| {1429 .map => |*map| {
...@@ -1427,17 +1483,17 @@ fn markInvalidUserInput(self: *Build) void {...@@ -1427,17 +1483,17 @@ fn markInvalidUserInput(self: *Build) void {
1427 self.invalid_user_input = true;1483 self.invalid_user_input = true;
1428}1484}
14291485
1430pub fn validateUserInputDidItFail(self: *Build) bool {1486pub fn validateUserInputDidItFail(b: *Build) bool {
1431 // make sure all args are used1487 // Make sure all args are used.
1432 var it = self.user_input_options.iterator();1488 var it = b.user_input_options.iterator();
1433 while (it.next()) |entry| {1489 while (it.next()) |entry| {
1434 if (!entry.value_ptr.used) {1490 if (!entry.value_ptr.used) {
1435 log.err("Invalid option: -D{s}", .{entry.key_ptr.*});1491 log.err("invalid option: -D{s}", .{entry.key_ptr.*});
1436 self.markInvalidUserInput();1492 b.markInvalidUserInput();
1437 }1493 }
1438 }1494 }
14391495
1440 return self.invalid_user_input;1496 return b.invalid_user_input;
1441}1497}
14421498
1443fn allocPrintCmd(ally: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) ![]u8 {1499fn 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...@@ -1593,7 +1649,7 @@ pub fn findProgram(self: *Build, names: []const []const u8, paths: []const []con
1593 return fs.realpathAlloc(self.allocator, full_path) catch continue;1649 return fs.realpathAlloc(self.allocator, full_path) catch continue;
1594 }1650 }
1595 }1651 }
1596 if (self.env_map.get("PATH")) |PATH| {1652 if (self.graph.env_map.get("PATH")) |PATH| {
1597 for (names) |name| {1653 for (names) |name| {
1598 if (fs.path.isAbsolute(name)) {1654 if (fs.path.isAbsolute(name)) {
1599 return name;1655 return name;
...@@ -1639,7 +1695,7 @@ pub fn runAllowFail(...@@ -1639,7 +1695,7 @@ pub fn runAllowFail(
1639 child.stdin_behavior = .Ignore;1695 child.stdin_behavior = .Ignore;
1640 child.stdout_behavior = .Pipe;1696 child.stdout_behavior = .Pipe;
1641 child.stderr_behavior = stderr_behavior;1697 child.stderr_behavior = stderr_behavior;
1642 child.env_map = self.env_map;1698 child.env_map = &self.graph.env_map;
16431699
1644 try child.spawn();1700 try child.spawn();
16451701
...@@ -1685,8 +1741,8 @@ pub fn run(b: *Build, argv: []const []const u8) []u8 {...@@ -1685,8 +1741,8 @@ pub fn run(b: *Build, argv: []const []const u8) []u8 {
1685 };1741 };
1686}1742}
16871743
1688pub fn addSearchPrefix(self: *Build, search_prefix: []const u8) void {1744pub fn addSearchPrefix(b: *Build, search_prefix: []const u8) void {
1689 self.search_prefixes.append(self.dupePath(search_prefix)) catch @panic("OOM");1745 b.search_prefixes.append(b.allocator, b.dupePath(search_prefix)) catch @panic("OOM");
1690}1746}
16911747
1692pub fn getInstallPath(self: *Build, dir: InstallDir, dest_rel_path: []const u8) []const u8 {1748pub fn getInstallPath(self: *Build, dir: InstallDir, dest_rel_path: []const u8) []const u8 {
...@@ -1747,21 +1803,63 @@ pub const Dependency = struct {...@@ -1747,21 +1803,63 @@ pub const Dependency = struct {
1747 }1803 }
1748};1804};
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 {
1751 const build_runner = @import("root");1833 const build_runner = @import("root");
1752 const deps = build_runner.dependencies;1834 const deps = build_runner.dependencies;
1835 const pkg_hash = findPkgHashOrFatal(b, name);
17531836
1754 const pkg_hash = for (b.available_deps) |dep| {1837 inline for (@typeInfo(deps.packages).Struct.decls) |decl| {
1755 if (mem.eql(u8, dep[0], name)) break dep[1];1838 if (mem.eql(u8, decl.name, pkg_hash)) {
1756 } else {1839 const pkg = @field(deps.packages, decl.name);
1757 const full_path = b.pathFromRoot("build.zig.zon");1840 const available = !@hasDecl(pkg, "available") or pkg.available;
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 });1841 if (!available) {
1759 process.exit(1);1842 markNeededLazyDep(b, pkg_hash);
1760 };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
1762 inline for (@typeInfo(deps.packages).Struct.decls) |decl| {1857 inline for (@typeInfo(deps.packages).Struct.decls) |decl| {
1763 if (mem.eql(u8, decl.name, pkg_hash)) {1858 if (mem.eql(u8, decl.name, pkg_hash)) {
1764 const pkg = @field(deps.packages, decl.name);1859 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 }
1765 return dependencyInner(b, name, pkg.build_root, if (@hasDecl(pkg, "build_zig")) pkg.build_zig else null, pkg.deps, args);1863 return dependencyInner(b, name, pkg.build_root, if (@hasDecl(pkg, "build_zig")) pkg.build_zig else null, pkg.deps, args);
1766 }1864 }
1767 }1865 }
...@@ -2281,9 +2379,14 @@ pub const ResolvedTarget = struct {...@@ -2281,9 +2379,14 @@ pub const ResolvedTarget = struct {
2281/// Converts a target query into a fully resolved target that can be passed to2379/// Converts a target query into a fully resolved target that can be passed to
2282/// various parts of the API.2380/// various parts of the API.
2283pub fn resolveTargetQuery(b: *Build, query: Target.Query) ResolvedTarget {2381pub fn resolveTargetQuery(b: *Build, query: Target.Query) ResolvedTarget {
2284 // This context will likely be required in the future when the target is2382 if (query.isNative()) {
2285 // resolved via a WASI API or via the build protocol.2383 var adjusted = b.host;
2286 _ = b;2384 if (query.ofmt) |ofmt| {
2385 adjusted.query.ofmt = ofmt;
2386 adjusted.result.ofmt = ofmt;
2387 }
2388 return adjusted;
2389 }
22872390
2288 return .{2391 return .{
2289 .query = query,2392 .query = query,
...@@ -2296,6 +2399,40 @@ pub fn wantSharedLibSymLinks(target: Target) bool {...@@ -2296,6 +2399,40 @@ pub fn wantSharedLibSymLinks(target: Target) bool {
2296 return target.os.tag != .windows;2399 return target.os.tag != .windows;
2297}2400}
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
2299test {2436test {
2300 _ = Cache;2437 _ = Cache;
2301 _ = Step;2438 _ = Step;
lib/std/Build/Step.zig+1-1
...@@ -314,7 +314,7 @@ pub fn evalZigProcess(...@@ -314,7 +314,7 @@ pub fn evalZigProcess(
314 try handleVerbose(s.owner, null, argv);314 try handleVerbose(s.owner, null, argv);
315315
316 var child = std.ChildProcess.init(argv, arena);316 var child = std.ChildProcess.init(argv, arena);
317 child.env_map = b.env_map;317 child.env_map = &b.graph.env_map;
318 child.stdin_behavior = .Pipe;318 child.stdin_behavior = .Pipe;
319 child.stdout_behavior = .Pipe;319 child.stdout_behavior = .Pipe;
320 child.stderr_behavior = .Pipe;320 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 {...@@ -923,7 +923,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
923 var zig_args = ArrayList([]const u8).init(arena);923 var zig_args = ArrayList([]const u8).init(arena);
924 defer zig_args.deinit();924 defer zig_args.deinit();
925925
926 try zig_args.append(b.zig_exe);926 try zig_args.append(b.graph.zig_exe);
927927
928 const cmd = switch (self.kind) {928 const cmd = switch (self.kind) {
929 .lib => "build-lib",929 .lib => "build-lib",
...@@ -933,6 +933,16 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -933,6 +933,16 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
933 };933 };
934 try zig_args.append(cmd);934 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
936 if (b.reference_trace) |some| {946 if (b.reference_trace) |some| {
937 try zig_args.append(try std.fmt.allocPrint(arena, "-freference-trace={d}", .{some}));947 try zig_args.append(try std.fmt.allocPrint(arena, "-freference-trace={d}", .{some}));
938 }948 }
...@@ -1393,7 +1403,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -1393,7 +1403,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
1393 try zig_args.append(b.cache_root.path orelse ".");1403 try zig_args.append(b.cache_root.path orelse ".");
13941404
1395 try zig_args.append("--global-cache-dir");1405 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
1398 try zig_args.append("--name");1408 try zig_args.append("--name");
1399 try zig_args.append(self.name);1409 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 {...@@ -171,7 +171,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
171 const gpa = b.allocator;171 const gpa = b.allocator;
172 const arena = b.allocator;172 const arena = b.allocator;
173173
174 var man = b.cache.obtain();174 var man = b.graph.cache.obtain();
175 defer man.deinit();175 defer man.deinit();
176176
177 // Random bytes to make ConfigHeader unique. Refresh this with new177 // 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 {...@@ -52,7 +52,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
52 var argv: std.ArrayListUnmanaged([]const u8) = .{};52 var argv: std.ArrayListUnmanaged([]const u8) = .{};
53 try argv.ensureUnusedCapacity(arena, 2 + 1 + self.paths.len + 2 * self.exclude_paths.len);53 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);
56 argv.appendAssumeCapacity("fmt");56 argv.appendAssumeCapacity("fmt");
5757
58 if (self.check) {58 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 {...@@ -94,7 +94,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
94 const b = step.owner;94 const b = step.owner;
95 const self = @fieldParentPtr(ObjCopy, "step", step);95 const self = @fieldParentPtr(ObjCopy, "step", step);
9696
97 var man = b.cache.obtain();97 var man = b.graph.cache.obtain();
98 defer man.deinit();98 defer man.deinit();
9999
100 // Random bytes to make ObjCopy unique. Refresh this with new random100 // 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 {...@@ -133,7 +133,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
133 };133 };
134134
135 var argv = std.ArrayList([]const u8).init(b.allocator);135 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
138 if (self.only_section) |only_section| {138 if (self.only_section) |only_section| {
139 try argv.appendSlice(&.{ "-j", only_section });139 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 {...@@ -222,7 +222,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
222 const basename = "options.zig";222 const basename = "options.zig";
223223
224 // Hash contents to file name.224 // Hash contents to file name.
225 var hash = b.cache.hash;225 var hash = b.graph.cache.hash;
226 // Random bytes to make unique. Refresh this with new random bytes when226 // Random bytes to make unique. Refresh this with new random bytes when
227 // implementation is modified in a non-backwards-compatible way.227 // implementation is modified in a non-backwards-compatible way.
228 hash.add(@as(u32, 0xad95e922));228 hash.add(@as(u32, 0xad95e922));
...@@ -301,27 +301,28 @@ test Options {...@@ -301,27 +301,28 @@ test Options {
301 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);301 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
302 defer arena.deinit();302 defer arena.deinit();
303303
304 const host: std.Build.ResolvedTarget = .{304 var graph: std.Build.Graph = .{
305 .query = .{},305 .arena = arena.allocator(),
306 .result = try std.zig.system.resolveTargetQuery(.{}),306 .cache = .{
307 };307 .gpa = arena.allocator(),
308308 .manifest_dir = std.fs.cwd(),
309 var cache: std.Build.Cache = .{309 },
310 .gpa = arena.allocator(),310 .zig_exe = "test",
311 .manifest_dir = std.fs.cwd(),311 .env_map = std.process.EnvMap.init(arena.allocator()),
312 .global_cache_root = .{ .path = "test", .handle = std.fs.cwd() },
312 };313 };
313314
314 var builder = try std.Build.create(315 var builder = try std.Build.create(
315 arena.allocator(),316 &graph,
316 "test",
317 .{ .path = "test", .handle = std.fs.cwd() },317 .{ .path = "test", .handle = std.fs.cwd() },
318 .{ .path = "test", .handle = std.fs.cwd() },318 .{ .path = "test", .handle = std.fs.cwd() },
319 .{ .path = "test", .handle = std.fs.cwd() },
320 host,
321 &cache,
322 &.{},319 &.{},
323 );320 );
324 defer builder.destroy();321
322 builder.host = .{
323 .query = .{},
324 .result = try std.zig.system.resolveTargetQuery(.{}),
325 };
325326
326 const options = builder.addOptions();327 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 {...@@ -463,7 +463,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
463 var argv_list = ArrayList([]const u8).init(arena);463 var argv_list = ArrayList([]const u8).init(arena);
464 var output_placeholders = ArrayList(IndexedOutput).init(arena);464 var output_placeholders = ArrayList(IndexedOutput).init(arena);
465465
466 var man = b.cache.obtain();466 var man = b.graph.cache.obtain();
467 defer man.deinit();467 defer man.deinit();
468468
469 for (self.argv.items) |arg| {469 for (self.argv.items) |arg| {
...@@ -1036,7 +1036,7 @@ fn spawnChildAndCollect(...@@ -1036,7 +1036,7 @@ fn spawnChildAndCollect(
1036 child.cwd = b.build_root.path;1036 child.cwd = b.build_root.path;
1037 child.cwd_dir = b.build_root.handle;1037 child.cwd_dir = b.build_root.handle;
1038 }1038 }
1039 child.env_map = self.env_map orelse b.env_map;1039 child.env_map = self.env_map orelse &b.graph.env_map;
1040 child.request_resource_usage_statistics = true;1040 child.request_resource_usage_statistics = true;
10411041
1042 child.stdin_behavior = switch (self.stdio) {1042 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 {...@@ -121,7 +121,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
121 const self = @fieldParentPtr(TranslateC, "step", step);121 const self = @fieldParentPtr(TranslateC, "step", step);
122122
123 var argv_list = std.ArrayList([]const u8).init(b.allocator);123 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);
125 try argv_list.append("translate-c");125 try argv_list.append("translate-c");
126 if (self.link_libc) {126 if (self.link_libc) {
127 try argv_list.append("-lc");127 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 {...@@ -190,7 +190,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
190 // If, for example, a hard-coded path was used as the location to put WriteFile190 // If, for example, a hard-coded path was used as the location to put WriteFile
191 // files, then two WriteFiles executing in parallel might clobber each other.191 // 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();
194 defer man.deinit();194 defer man.deinit();
195195
196 // Random bytes to make WriteFile unique. Refresh this with196 // 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 {...@@ -468,7 +468,7 @@ pub fn zigTriple(self: Query, allocator: Allocator) Allocator.Error![]u8 {
468 }468 }
469469
470 if (self.glibc_version) |v| {470 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";
472 try result.ensureUnusedCapacity(name.len + 2);472 try result.ensureUnusedCapacity(name.len + 2);
473 result.appendAssumeCapacity('-');473 result.appendAssumeCapacity('-');
474 result.appendSliceAssumeCapacity(name);474 result.appendSliceAssumeCapacity(name);
lib/std/child_process.zig+3-1
...@@ -298,7 +298,9 @@ pub const ChildProcess = struct {...@@ -298,7 +298,9 @@ pub const ChildProcess = struct {
298 // we could make this work with multiple allocators but YAGNI298 // we could make this work with multiple allocators but YAGNI
299 if (stdout.allocator.ptr != stderr.allocator.ptr or299 if (stdout.allocator.ptr != stderr.allocator.ptr or
300 stdout.allocator.vtable != stderr.allocator.vtable)300 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
303 var poller = std.io.poll(stdout.allocator, enum { stdout, stderr }, .{305 var poller = std.io.poll(stdout.allocator, enum { stdout, stderr }, .{
304 .stdout = child.stdout.?,306 .stdout = child.stdout.?,
src/Compilation.zig+3
...@@ -4530,6 +4530,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P...@@ -4530,6 +4530,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
4530 log.err("{}: failed to parse clang diagnostics: {s}", .{ err, stderr });4530 log.err("{}: failed to parse clang diagnostics: {s}", .{ err, stderr });
4531 return comp.failCObj(c_object, "clang exited with code {d}", .{code});4531 return comp.failCObj(c_object, "clang exited with code {d}", .{code});
4532 };4532 };
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 };
4533 return comp.failCObjWithOwnedDiagBundle(c_object, bundle);4536 return comp.failCObjWithOwnedDiagBundle(c_object, bundle);
4534 }4537 }
4535 },4538 },
src/Package/Fetch.zig+81-4
...@@ -31,6 +31,8 @@ arena: std.heap.ArenaAllocator,...@@ -31,6 +31,8 @@ arena: std.heap.ArenaAllocator,
31location: Location,31location: Location,
32location_tok: std.zig.Ast.TokenIndex,32location_tok: std.zig.Ast.TokenIndex,
33hash_tok: std.zig.Ast.TokenIndex,33hash_tok: std.zig.Ast.TokenIndex,
34name_tok: std.zig.Ast.TokenIndex,
35lazy_status: LazyStatus,
34parent_package_root: Package.Path,36parent_package_root: Package.Path,
35parent_manifest_ast: ?*const std.zig.Ast,37parent_manifest_ast: ?*const std.zig.Ast,
36prog_node: *std.Progress.Node,38prog_node: *std.Progress.Node,
...@@ -64,6 +66,15 @@ oom_flag: bool,...@@ -64,6 +66,15 @@ oom_flag: bool,
64/// the root source file.66/// the root source file.
65module: ?*Package.Module,67module: ?*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
67/// Contains shared state among all `Fetch` tasks.78/// Contains shared state among all `Fetch` tasks.
68pub const JobQueue = struct {79pub const JobQueue = struct {
69 mutex: std.Thread.Mutex = .{},80 mutex: std.Thread.Mutex = .{},
...@@ -80,14 +91,27 @@ pub const JobQueue = struct {...@@ -80,14 +91,27 @@ pub const JobQueue = struct {
80 thread_pool: *ThreadPool,91 thread_pool: *ThreadPool,
81 wait_group: WaitGroup = .{},92 wait_group: WaitGroup = .{},
82 global_cache: Cache.Directory,93 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,
83 recursive: bool,103 recursive: bool,
84 /// Dumps hash information to stdout which can be used to troubleshoot why104 /// Dumps hash information to stdout which can be used to troubleshoot why
85 /// two hashes of the same package do not match.105 /// two hashes of the same package do not match.
86 /// If this is true, `recursive` must be false.106 /// If this is true, `recursive` must be false.
87 debug_hash: bool,107 debug_hash: bool,
88 work_around_btrfs_bug: bool,108 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
90 pub const Table = std.AutoArrayHashMapUnmanaged(Manifest.MultiHashHexDigest, *Fetch);113 pub const Table = std.AutoArrayHashMapUnmanaged(Manifest.MultiHashHexDigest, *Fetch);
114 pub const UnlazySet = std.AutoArrayHashMapUnmanaged(Manifest.MultiHashHexDigest, void);
91115
92 pub fn deinit(jq: *JobQueue) void {116 pub fn deinit(jq: *JobQueue) void {
93 if (jq.all_fetches.items.len == 0) return;117 if (jq.all_fetches.items.len == 0) return;
...@@ -141,11 +165,37 @@ pub const JobQueue = struct {...@@ -141,11 +165,37 @@ pub const JobQueue = struct {
141 // The first one is a dummy package for the current project.165 // The first one is a dummy package for the current project.
142 continue;166 continue;
143 }167 }
168
144 try buf.writer().print(169 try buf.writer().print(
145 \\ pub const {} = struct {{170 \\ 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(
146 \\ pub const build_root = "{q}";196 \\ pub const build_root = "{q}";
147 \\197 \\
148 , .{ std.zig.fmtId(&hash), fetch.package_root });198 , .{fetch.package_root});
149199
150 if (fetch.has_build_zig) {200 if (fetch.has_build_zig) {
151 try buf.writer().print(201 try buf.writer().print(
...@@ -270,7 +320,8 @@ pub fn run(f: *Fetch) RunError!void {...@@ -270,7 +320,8 @@ pub fn run(f: *Fetch) RunError!void {
270 // We want to fail unless the resolved relative path has a320 // We want to fail unless the resolved relative path has a
271 // prefix of "p/$hash/".321 // prefix of "p/$hash/".
272 const digest_len = @typeInfo(Manifest.MultiHashHexDigest).Array.len;322 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];
274 if (!std.mem.startsWith(u8, pkg_root.sub_path, expected_prefix)) {325 if (!std.mem.startsWith(u8, pkg_root.sub_path, expected_prefix)) {
275 return f.fail(326 return f.fail(
276 f.location_tok,327 f.location_tok,
...@@ -311,8 +362,11 @@ pub fn run(f: *Fetch) RunError!void {...@@ -311,8 +362,11 @@ pub fn run(f: *Fetch) RunError!void {
311362
312 const s = fs.path.sep_str;363 const s = fs.path.sep_str;
313 if (remote.hash) |expected_hash| {364 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..];
315 if (cache_root.handle.access(pkg_sub_path, .{})) |_| {368 if (cache_root.handle.access(pkg_sub_path, .{})) |_| {
369 assert(f.lazy_status != .unavailable);
316 f.package_root = .{370 f.package_root = .{
317 .root_dir = cache_root,371 .root_dir = cache_root,
318 .sub_path = try arena.dupe(u8, pkg_sub_path),372 .sub_path = try arena.dupe(u8, pkg_sub_path),
...@@ -322,7 +376,22 @@ pub fn run(f: *Fetch) RunError!void {...@@ -322,7 +376,22 @@ pub fn run(f: *Fetch) RunError!void {
322 if (!f.job_queue.recursive) return;376 if (!f.job_queue.recursive) return;
323 return queueJobsForDeps(f);377 return queueJobsForDeps(f);
324 } else |err| switch (err) {378 } 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 },
326 else => |e| {395 else => |e| {
327 try eb.addRootErrorMessage(.{396 try eb.addRootErrorMessage(.{
328 .msg = try eb.printString("unable to open global package cache directory '{}{s}': {s}", .{397 .msg = try eb.printString("unable to open global package cache directory '{}{s}': {s}", .{
...@@ -332,6 +401,12 @@ pub fn run(f: *Fetch) RunError!void {...@@ -332,6 +401,12 @@ pub fn run(f: *Fetch) RunError!void {
332 return error.FetchFailed;401 return error.FetchFailed;
333 },402 },
334 }403 }
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;
335 }410 }
336411
337 // Fetch and unpack the remote into a temporary directory.412 // Fetch and unpack the remote into a temporary directory.
...@@ -602,6 +677,8 @@ fn queueJobsForDeps(f: *Fetch) RunError!void {...@@ -602,6 +677,8 @@ fn queueJobsForDeps(f: *Fetch) RunError!void {
602 .location = location,677 .location = location,
603 .location_tok = dep.location_tok,678 .location_tok = dep.location_tok,
604 .hash_tok = dep.hash_tok,679 .hash_tok = dep.hash_tok,
680 .name_tok = dep.name_tok,
681 .lazy_status = if (dep.lazy) .available else .eager,
605 .parent_package_root = f.package_root,682 .parent_package_root = f.package_root,
606 .parent_manifest_ast = &f.manifest_ast,683 .parent_manifest_ast = &f.manifest_ast,
607 .prog_node = f.prog_node,684 .prog_node = f.prog_node,
src/Package/Manifest.zig+28
...@@ -12,6 +12,8 @@ pub const Dependency = struct {...@@ -12,6 +12,8 @@ pub const Dependency = struct {
12 hash: ?[]const u8,12 hash: ?[]const u8,
13 hash_tok: Ast.TokenIndex,13 hash_tok: Ast.TokenIndex,
14 node: Ast.Node.Index,14 node: Ast.Node.Index,
15 name_tok: Ast.TokenIndex,
16 lazy: bool,
1517
16 pub const Location = union(enum) {18 pub const Location = union(enum) {
17 url: []const u8,19 url: []const u8,
...@@ -303,11 +305,14 @@ const Parse = struct {...@@ -303,11 +305,14 @@ const Parse = struct {
303 .hash = null,305 .hash = null,
304 .hash_tok = 0,306 .hash_tok = 0,
305 .node = node,307 .node = node,
308 .name_tok = 0,
309 .lazy = false,
306 };310 };
307 var has_location = false;311 var has_location = false;
308312
309 for (struct_init.ast.fields) |field_init| {313 for (struct_init.ast.fields) |field_init| {
310 const name_token = ast.firstToken(field_init) - 2;314 const name_token = ast.firstToken(field_init) - 2;
315 dep.name_tok = name_token;
311 const field_name = try identifierTokenString(p, name_token);316 const field_name = try identifierTokenString(p, name_token);
312 // We could get fancy with reflection and comptime logic here but doing317 // We could get fancy with reflection and comptime logic here but doing
313 // things manually provides an opportunity to do any additional verification318 // things manually provides an opportunity to do any additional verification
...@@ -342,6 +347,11 @@ const Parse = struct {...@@ -342,6 +347,11 @@ const Parse = struct {
342 else => |e| return e,347 else => |e| return e,
343 };348 };
344 dep.hash_tok = main_tokens[field_init];349 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 };
345 } else {355 } else {
346 // Ignore unknown fields so that we can add fields in future zig356 // Ignore unknown fields so that we can add fields in future zig
347 // versions without breaking older zig versions.357 // versions without breaking older zig versions.
...@@ -374,6 +384,24 @@ const Parse = struct {...@@ -374,6 +384,24 @@ const Parse = struct {
374 }384 }
375 }385 }
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
377 fn parseString(p: *Parse, node: Ast.Node.Index) ![]const u8 {405 fn parseString(p: *Parse, node: Ast.Node.Index) ![]const u8 {
378 const ast = p.ast;406 const ast = p.ast;
379 const node_tags = ast.nodes.items(.tag);407 const node_tags = ast.nodes.items(.tag);
src/main.zig+545-422
...@@ -969,6 +969,9 @@ fn buildOutputType(...@@ -969,6 +969,9 @@ fn buildOutputType(
969 .libc_paths_file = try EnvVar.ZIG_LIBC.get(arena),969 .libc_paths_file = try EnvVar.ZIG_LIBC.get(arena),
970 .link_objects = .{},970 .link_objects = .{},
971 .native_system_include_paths = &.{},971 .native_system_include_paths = &.{},
972 .host_triple = null,
973 .host_cpu = null,
974 .host_dynamic_linker = null,
972 };975 };
973976
974 // before arg parsing, check for the NO_COLOR environment variable977 // before arg parsing, check for the NO_COLOR environment variable
...@@ -1262,6 +1265,12 @@ fn buildOutputType(...@@ -1262,6 +1265,12 @@ fn buildOutputType(
1262 mod_opts.optimize_mode = parseOptimizeMode(arg["-O".len..]);1265 mod_opts.optimize_mode = parseOptimizeMode(arg["-O".len..]);
1263 } else if (mem.eql(u8, arg, "--dynamic-linker")) {1266 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
1264 create_module.dynamic_linker = args_iter.nextOrFatal();1267 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();
1265 } else if (mem.eql(u8, arg, "--sysroot")) {1274 } else if (mem.eql(u8, arg, "--sysroot")) {
1266 const next_arg = args_iter.nextOrFatal();1275 const next_arg = args_iter.nextOrFatal();
1267 create_module.sysroot = next_arg;1276 create_module.sysroot = next_arg;
...@@ -3455,6 +3464,9 @@ const CreateModule = struct {...@@ -3455,6 +3464,9 @@ const CreateModule = struct {
3455 each_lib_rpath: ?bool,3464 each_lib_rpath: ?bool,
3456 libc_paths_file: ?[]const u8,3465 libc_paths_file: ?[]const u8,
3457 link_objects: std.ArrayListUnmanaged(Compilation.LinkObject),3466 link_objects: std.ArrayListUnmanaged(Compilation.LinkObject),
3467 host_triple: ?[]const u8,
3468 host_cpu: ?[]const u8,
3469 host_dynamic_linker: ?[]const u8,
3458};3470};
34593471
3460fn createModule(3472fn createModule(
...@@ -3539,7 +3551,15 @@ fn createModule(...@@ -3539,7 +3551,15 @@ fn createModule(
3539 }3551 }
35403552
3541 const target_query = parseTargetQueryOrReportFatalError(arena, target_parse_options);3553 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);
3543 break :t .{3563 break :t .{
3544 .result = target,3564 .result = target,
3545 .is_native_os = target_query.isNativeOs(),3565 .is_native_os = target_query.isNativeOs(),
...@@ -5130,476 +5150,576 @@ pub const usage_build =...@@ -5130,476 +5150,576 @@ pub const usage_build =
5130;5150;
51315151
5132pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {5152pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
5133 const work_around_btrfs_bug = builtin.os.tag == .linux and5153 var progress: std.Progress = .{ .dont_print_on_dumb = true };
5134 EnvVar.ZIG_BTRFS_WORKAROUND.isSet();
5135 const color: Color = .auto;
51365154
5137 // We want to release all the locks before executing the child process, so we make a nice5155 var build_file: ?[]const u8 = null;
5138 // big block here to ensure the cleanup gets run when we extract out our argv.5156 var override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
5139 const child_argv = argv: {5157 var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
5140 const self_exe_path = try introspect.findZigExePath(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;5177 const argv_index_exe = child_argv.items.len;
5143 var override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);5178 _ = try child_argv.addOne();
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;
51825179
5183 {5180 const self_exe_path = try introspect.findZigExePath(arena);
5184 var i: usize = 0;5181 try child_argv.append(self_exe_path);
5185 while (i < args.len) : (i += 1) {5182
5186 const arg = args[i];5183 const argv_index_build_file = child_argv.items.len;
5187 if (mem.startsWith(u8, arg, "-")) {5184 _ = try child_argv.addOne();
5188 if (mem.eql(u8, arg, "--build-file")) {5185
5189 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});5186 const argv_index_cache_dir = child_argv.items.len;
5190 i += 1;5187 _ = try child_argv.addOne();
5191 build_file = args[i];5188
5192 continue;5189 const argv_index_global_cache_dir = child_argv.items.len;
5193 } else if (mem.eql(u8, arg, "--zig-lib-dir")) {5190 _ = try child_argv.addOne();
5194 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});5191
5195 i += 1;5192 try child_argv.appendSlice(&.{
5196 override_lib_dir = args[i];5193 "--seed",
5197 try child_argv.appendSlice(&.{ arg, args[i] });5194 try std.fmt.allocPrint(arena, "0x{x}", .{std.crypto.random.int(u32)}),
5198 continue;5195 });
5199 } else if (mem.eql(u8, arg, "--build-runner")) {5196 const argv_index_seed = child_argv.items.len - 1;
5200 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});5197
5201 i += 1;5198 // This parent process needs a way to obtain results from the configuration
5202 override_build_runner = args[i];5199 // phase of the child process. In the future, the make phase will be
5203 continue;5200 // executed in a separate process than the configure phase, and we can then
5204 } else if (mem.eql(u8, arg, "--cache-dir")) {5201 // use stdout from the configuration phase for this purpose.
5205 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});5202 //
5206 i += 1;5203 // However, currently, both phases are in the same process, and Run Step
5207 override_local_cache_dir = args[i];5204 // provides API for making the runned subprocesses inherit stdout and stderr
5208 continue;5205 // which means these streams are not available for passing metadata back
5209 } else if (mem.eql(u8, arg, "--global-cache-dir")) {5206 // to the parent.
5210 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});5207 //
5211 i += 1;5208 // Until make and configure phases are separated into different processes,
5212 override_global_cache_dir = args[i];5209 // the strategy is to choose a temporary file name ahead of time, and then
5213 continue;5210 // read this file in the parent to obtain the results, in the case the child
5214 } else if (mem.eql(u8, arg, "-freference-trace")) {5211 // exits with code 3.
5215 reference_trace = 256;5212 const results_tmp_file_nonce = Package.Manifest.hex64(std.crypto.random.int(u64));
5216 } else if (mem.eql(u8, arg, "--fetch")) {5213 try child_argv.append("-Z" ++ results_tmp_file_nonce);
5217 fetch_only = true;5214
5218 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {5215 {
5219 const num = arg["-freference-trace=".len..];5216 var i: usize = 0;
5220 reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {5217 while (i < args.len) : (i += 1) {
5221 fatal("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });5218 const arg = args[i];
5222 };5219 if (mem.startsWith(u8, arg, "-")) {
5223 } else if (mem.eql(u8, arg, "-fno-reference-trace")) {5220 if (mem.eql(u8, arg, "--build-file")) {
5224 reference_trace = null;5221 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5225 } else if (mem.eql(u8, arg, "--debug-log")) {5222 i += 1;
5226 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});5223 build_file = args[i];
5227 try child_argv.appendSlice(args[i .. i + 2]);5224 continue;
5228 i += 1;5225 } else if (mem.eql(u8, arg, "--zig-lib-dir")) {
5229 if (!build_options.enable_logging) {5226 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5230 warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{});5227 i += 1;
5231 } else {5228 override_lib_dir = args[i];
5232 try log_scopes.append(arena, args[i]);5229 try child_argv.appendSlice(&.{ arg, args[i] });
5233 }5230 continue;
5234 continue;5231 } else if (mem.eql(u8, arg, "--build-runner")) {
5235 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {5232 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5236 if (!crash_report.is_enabled) {5233 i += 1;
5237 warn("Zig was compiled in a release mode. --debug-compile-errors has no effect.", .{});5234 override_build_runner = args[i];
5238 } else {5235 continue;
5239 debug_compile_errors = true;5236 } else if (mem.eql(u8, arg, "--cache-dir")) {
5240 }5237 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5241 } else if (mem.eql(u8, arg, "--verbose-link")) {5238 i += 1;
5242 verbose_link = true;5239 override_local_cache_dir = args[i];
5243 } else if (mem.eql(u8, arg, "--verbose-cc")) {5240 continue;
5244 verbose_cc = true;5241 } else if (mem.eql(u8, arg, "--global-cache-dir")) {
5245 } else if (mem.eql(u8, arg, "--verbose-air")) {5242 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5246 verbose_air = true;5243 i += 1;
5247 } else if (mem.eql(u8, arg, "--verbose-intern-pool")) {5244 override_global_cache_dir = args[i];
5248 verbose_intern_pool = true;5245 continue;
5249 } else if (mem.eql(u8, arg, "--verbose-generic-instances")) {5246 } else if (mem.eql(u8, arg, "-freference-trace")) {
5250 verbose_generic_instances = true;5247 reference_trace = 256;
5251 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {5248 } else if (mem.eql(u8, arg, "--fetch")) {
5252 verbose_llvm_ir = "-";5249 fetch_only = true;
5253 } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) {5250 } else if (mem.eql(u8, arg, "--system")) {
5254 verbose_llvm_ir = arg["--verbose-llvm-ir=".len..];5251 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
5255 } else if (mem.startsWith(u8, arg, "--verbose-llvm-bc=")) {5252 i += 1;
5256 verbose_llvm_bc = arg["--verbose-llvm-bc=".len..];5253 system_pkg_dir_path = args[i];
5257 } else if (mem.eql(u8, arg, "--verbose-cimport")) {5254 try child_argv.append("--system");
5258 verbose_cimport = true;5255 continue;
5259 } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {5256 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {
5260 verbose_llvm_cpu_features = true;5257 const num = arg["-freference-trace=".len..];
5261 } else if (mem.eql(u8, arg, "--seed")) {5258 reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
5262 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});5259 fatal("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });
5263 i += 1;5260 };
5264 child_argv.items[argv_index_seed] = args[i];5261 } else if (mem.eql(u8, arg, "-fno-reference-trace")) {
5265 continue;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;
5266 }5278 }
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;
5267 }5304 }
5268 try child_argv.append(arg);
5269 }5305 }
5306 try child_argv.append(arg);
5270 }5307 }
5308 }
52715309
5272 var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir| .{5310 const work_around_btrfs_bug = builtin.os.tag == .linux and
5273 .path = lib_dir,5311 EnvVar.ZIG_BTRFS_WORKAROUND.isSet();
5274 .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| {5312 const color: Color = .auto;
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();
52815313
5282 var cleanup_build_dir: ?fs.Dir = null;5314 const target_query: std.Target.Query = .{};
5283 defer if (cleanup_build_dir) |*dir| dir.close();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);5321 const exe_basename = try std.zig.binNameAlloc(arena, .{
5286 const build_root = try findBuildRoot(arena, .{5322 .root_name = "build",
5287 .cwd_path = cwd_path,5323 .target = resolved_target.result,
5288 .build_file = build_file,5324 .output_mode = .Exe,
5289 });5325 });
5290 child_argv.items[argv_index_build_file] = build_root.directory.path orelse cwd_path;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: {5331 gimmeMoreOfThoseSweetSweetFileDescriptors();
5293 const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);5332
5294 break :l .{5333 var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir| .{
5295 .handle = try fs.cwd().makeOpenPath(p, .{}),5334 .path = lib_dir,
5296 .path = p,5335 .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| {
5297 };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,
5298 };5355 };
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: {5361 var local_cache_directory: Compilation.Directory = l: {
5304 if (override_local_cache_dir) |local_cache_dir_path| {5362 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"});
5311 break :l .{5363 break :l .{
5312 .handle = try build_root.directory.handle.makeOpenPath("zig-cache", .{}),5364 .handle = try fs.cwd().makeOpenPath(local_cache_dir_path, .{}),
5313 .path = cache_dir_path,5365 .path = local_cache_dir_path,
5314 };5366 };
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,
5315 };5372 };
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 = .{};5382 // Dummy http client that is not actually used when only_core_functionality is enabled.
5323 const resolved_target: Package.Module.ResolvedTarget = .{5383 // Prevents bootstrap from depending on a bunch of unnecessary stuff.
5324 .result = resolveTargetQueryOrFatal(target_query),5384 const HttpClient = if (build_options.only_core_functionality) struct {
5325 .is_native_os = true,5385 allocator: Allocator,
5326 .is_native_abi = true,5386 fn deinit(self: *@This()) void {
5327 };5387 _ = self;
5388 }
5389 } else std.http.Client;
53285390
5329 const exe_basename = try std.zig.binNameAlloc(arena, .{5391 var http_client: HttpClient = .{ .allocator = gpa };
5330 .root_name = "build",5392 defer http_client.deinit();
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();
53415393
5342 const main_mod_paths: Package.Module.CreateOptions.Paths = if (override_build_runner) |runner| .{5394 var unlazy_set: Package.Fetch.JobQueue.UnlazySet = .{};
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 };
53525395
5353 const config = try Compilation.Config.resolve(.{5396 // This loop is re-evaluated when the build script exits with an indication that it
5354 .output_mode = .Exe,5397 // could not continue due to missing lazy dependencies.
5355 .resolved_target = resolved_target,5398 while (true) {
5356 .have_zcu = true,5399 // We want to release all the locks before executing the child process, so we make a nice
5357 .emit_bin = true,5400 // big block here to ensure the cleanup gets run when we extract out our argv.
5358 .is_test = false,5401 {
5359 });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, .{5413 const config = try Compilation.Config.resolve(.{
5362 .global_cache_directory = global_cache_directory,5414 .output_mode = .Exe,
5363 .paths = main_mod_paths,
5364 .fully_qualified_name = "root",
5365 .cc_argv = &.{},
5366 .inherited = .{
5367 .resolved_target = resolved_target,5415 .resolved_target = resolved_target,
5368 },5416 .have_zcu = true,
5369 .global = config,5417 .emit_bin = true,
5370 .parent = null,5418 .is_test = false,
5371 .builtin_mod = null,5419 });
5372 });
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, .{5434 const builtin_mod = root_mod.getBuiltinDependency();
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();
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 };5450 var cleanup_build_dir: ?fs.Dir = null;
5405 const root_prog_node = progress.start("Fetch Packages", 0);5451 defer if (cleanup_build_dir) |*dir| dir.close();
5406 defer root_prog_node.end();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 = .{5493 try job_queue.all_fetches.ensureUnusedCapacity(gpa, 1);
5409 .http_client = &http_client,5494 try job_queue.table.ensureUnusedCapacity(gpa, 1);
5410 .thread_pool = &thread_pool,5495
5411 .global_cache = global_cache_directory,5496 var fetch: Package.Fetch = .{
5412 .recursive = true,5497 .arena = std.heap.ArenaAllocator.init(gpa),
5413 .debug_hash = false,5498 .location = .{ .relative_path = build_mod.root },
5414 .work_around_btrfs_bug = work_around_btrfs_bug,5499 .location_tok = 0,
5415 };5500 .hash_tok = 0,
5416 defer job_queue.deinit();5501 .name_tok = 0,
54175502 .lazy_status = .eager,
5418 try job_queue.all_fetches.ensureUnusedCapacity(gpa, 1);5503 .parent_package_root = build_mod.root,
5419 try job_queue.table.ensureUnusedCapacity(gpa, 1);5504 .parent_manifest_ast = null,
54205505 .prog_node = root_prog_node,
5421 var fetch: Package.Fetch = .{5506 .job_queue = &job_queue,
5422 .arena = std.heap.ArenaAllocator.init(gpa),5507 .omit_missing_hash_error = true,
5423 .location = .{ .relative_path = build_mod.root },5508 .allow_missing_paths_field = false,
5424 .location_tok = 0,5509
5425 .hash_tok = 0,5510 .package_root = undefined,
5426 .parent_package_root = build_mod.root,5511 .error_bundle = undefined,
5427 .parent_manifest_ast = null,5512 .manifest = null,
5428 .prog_node = root_prog_node,5513 .manifest_ast = undefined,
5429 .job_queue = &job_queue,5514 .actual_hash = undefined,
5430 .omit_missing_hash_error = true,5515 .has_build_zig = true,
5431 .allow_missing_paths_field = false,5516 .oom_flag = false,
54325517
5433 .package_root = undefined,5518 .module = build_mod,
5434 .error_bundle = undefined,5519 };
5435 .manifest = null,5520 job_queue.all_fetches.appendAssumeCapacity(&fetch);
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);
54445521
5445 job_queue.table.putAssumeCapacityNoClobber(5522 job_queue.table.putAssumeCapacityNoClobber(
5446 Package.Fetch.relativePathDigest(build_mod.root, global_cache_directory),5523 Package.Fetch.relativePathDigest(build_mod.root, global_cache_directory),
5447 &fetch,5524 &fetch,
5448 );5525 );
54495526
5450 job_queue.wait_group.start();5527 job_queue.wait_group.start();
5451 try job_queue.thread_pool.spawn(Package.Fetch.workerRun, .{ &fetch, "root" });5528 try job_queue.thread_pool.spawn(Package.Fetch.workerRun, .{ &fetch, "root" });
5452 job_queue.wait_group.wait();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) {5533 if (fetch.error_bundle.root_list.items.len > 0) {
5457 var errors = try fetch.error_bundle.toOwnedBundle("");5534 var errors = try fetch.error_bundle.toOwnedBundle("");
5458 errors.renderToStdErr(renderOptions(color));5535 errors.renderToStdErr(renderOptions(color));
5459 process.exit(1);5536 process.exit(1);
5460 }5537 }
54615538
5462 if (fetch_only) return cleanExit();5539 if (fetch_only) return cleanExit();
54635540
5464 var source_buf = std.ArrayList(u8).init(gpa);5541 var source_buf = std.ArrayList(u8).init(gpa);
5465 defer source_buf.deinit();5542 defer source_buf.deinit();
5466 try job_queue.createDependenciesSource(&source_buf);5543 try job_queue.createDependenciesSource(&source_buf);
5467 const deps_mod = try createDependenciesModule(5544 const deps_mod = try createDependenciesModule(
5468 arena,5545 arena,
5469 source_buf.items,5546 source_buf.items,
5470 root_mod,5547 root_mod,
5471 global_cache_directory,5548 global_cache_directory,
5472 local_cache_directory,5549 local_cache_directory,
5473 builtin_mod,5550 builtin_mod,
5474 config,5551 config,
5475 );5552 );
54765553
5477 {5554 {
5478 // We need a Module for each package's build.zig.5555 // We need a Module for each package's build.zig.
5479 const hashes = job_queue.table.keys();5556 const hashes = job_queue.table.keys();
5480 const fetches = job_queue.table.values();5557 const fetches = job_queue.table.values();
5481 try deps_mod.deps.ensureUnusedCapacity(arena, @intCast(hashes.len));5558 try deps_mod.deps.ensureUnusedCapacity(arena, @intCast(hashes.len));
5482 for (hashes, fetches) |hash, f| {5559 for (hashes, fetches) |hash, f| {
5483 if (f == &fetch) {5560 if (f == &fetch) {
5484 // The first one is a dummy package for the current project.5561 // The first one is a dummy package for the current project.
5485 continue;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;
5486 }5586 }
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 its5588 // Each build.zig module needs access to each of its
5512 // dependencies' build.zig modules by name.5589 // dependencies' build.zig modules by name.
5513 for (fetches) |f| {5590 for (fetches) |f| {
5514 const mod = f.module orelse continue;5591 const mod = f.module orelse continue;
5515 const man = f.manifest orelse continue;5592 const man = f.manifest orelse continue;
5516 const dep_names = man.dependencies.keys();5593 const dep_names = man.dependencies.keys();
5517 try mod.deps.ensureUnusedCapacity(arena, @intCast(dep_names.len));5594 try mod.deps.ensureUnusedCapacity(arena, @intCast(dep_names.len));
5518 for (dep_names, man.dependencies.values()) |name, dep| {5595 for (dep_names, man.dependencies.values()) |name, dep| {
5519 const dep_digest = Package.Fetch.depDigest(5596 const dep_digest = Package.Fetch.depDigest(
5520 f.package_root,5597 f.package_root,
5521 global_cache_directory,5598 global_cache_directory,
5522 dep,5599 dep,
5523 ) orelse continue;5600 ) orelse continue;
5524 const dep_mod = job_queue.table.get(dep_digest).?.module orelse continue;5601 const dep_mod = job_queue.table.get(dep_digest).?.module orelse continue;
5525 const name_cloned = try arena.dupe(u8, name);5602 const name_cloned = try arena.dupe(u8, name);
5526 mod.deps.putAssumeCapacityNoClobber(name_cloned, dep_mod);5603 mod.deps.putAssumeCapacityNoClobber(name_cloned, dep_mod);
5604 }
5527 }5605 }
5528 }5606 }
5529 }5607 }
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, .{5611 const comp = Compilation.create(gpa, arena, .{
5535 .zig_lib_directory = zig_lib_directory,5612 .zig_lib_directory = zig_lib_directory,
5536 .local_cache_directory = local_cache_directory,5613 .local_cache_directory = local_cache_directory,
5537 .global_cache_directory = global_cache_directory,5614 .global_cache_directory = global_cache_directory,
5538 .root_name = "build",5615 .root_name = "build",
5539 .config = config,5616 .config = config,
5540 .root_mod = root_mod,5617 .root_mod = root_mod,
5541 .main_mod = build_mod,5618 .main_mod = build_mod,
5542 .emit_bin = emit_bin,5619 .emit_bin = emit_bin,
5543 .emit_h = null,5620 .emit_h = null,
5544 .self_exe_path = self_exe_path,5621 .self_exe_path = self_exe_path,
5545 .thread_pool = &thread_pool,5622 .thread_pool = &thread_pool,
5546 .verbose_cc = verbose_cc,5623 .verbose_cc = verbose_cc,
5547 .verbose_link = verbose_link,5624 .verbose_link = verbose_link,
5548 .verbose_air = verbose_air,5625 .verbose_air = verbose_air,
5549 .verbose_intern_pool = verbose_intern_pool,5626 .verbose_intern_pool = verbose_intern_pool,
5550 .verbose_generic_instances = verbose_generic_instances,5627 .verbose_generic_instances = verbose_generic_instances,
5551 .verbose_llvm_ir = verbose_llvm_ir,5628 .verbose_llvm_ir = verbose_llvm_ir,
5552 .verbose_llvm_bc = verbose_llvm_bc,5629 .verbose_llvm_bc = verbose_llvm_bc,
5553 .verbose_cimport = verbose_cimport,5630 .verbose_cimport = verbose_cimport,
5554 .verbose_llvm_cpu_features = verbose_llvm_cpu_features,5631 .verbose_llvm_cpu_features = verbose_llvm_cpu_features,
5555 .cache_mode = .whole,5632 .cache_mode = .whole,
5556 .reference_trace = reference_trace,5633 .reference_trace = reference_trace,
5557 .debug_compile_errors = debug_compile_errors,5634 .debug_compile_errors = debug_compile_errors,
5558 }) catch |err| {5635 }) catch |err| {
5559 fatal("unable to create compilation: {s}", .{@errorName(err)});5636 fatal("unable to create compilation: {s}", .{@errorName(err)});
5560 };5637 };
5561 defer comp.destroy();5638 defer comp.destroy();
55625639
5563 updateModule(comp, color) catch |err| switch (err) {5640 updateModule(comp, color) catch |err| switch (err) {
5564 error.SemanticAnalyzeFail => process.exit(2),5641 error.SemanticAnalyzeFail => process.exit(2),
5565 else => |e| return e,5642 else => |e| return e,
5566 };5643 };
55675644
5568 // Since incremental compilation isn't done yet, we use cache_mode = whole5645 // Since incremental compilation isn't done yet, we use cache_mode = whole
5569 // above, and thus the output file is already closed.5646 // above, and thus the output file is already closed.
5570 //try comp.makeBinFileExecutable();5647 //try comp.makeBinFileExecutable();
5571 child_argv.items[argv_index_exe] =5648 child_argv.items[argv_index_exe] =
5572 try local_cache_directory.join(arena, &.{comp.cache_use.whole.bin_sub_path.?});5649 try local_cache_directory.join(arena, &.{comp.cache_use.whole.bin_sub_path.?});
5650 }
55735651
5574 break :argv child_argv.items;5652 if (process.can_spawn) {
5575 };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) {5658 const term = try child.spawnAndWait();
5578 var child = std.ChildProcess.init(child_argv, gpa);5659 switch (term) {
5579 child.stdin_behavior = .Inherit;5660 .Exited => |code| {
5580 child.stdout_behavior = .Inherit;5661 if (code == 0) return cleanExit();
5581 child.stderr_behavior = .Inherit;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();5711 const cmd = try std.mem.join(arena, " ", child_argv.items);
5584 switch (term) {5712 fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd });
5585 .Exited => |code| {5713 },
5586 if (code == 0) return cleanExit();5714 else => {
5587 // Indicates that the build runner has reported compile errors5715 const cmd = try std.mem.join(arena, " ", child_argv.items);
5588 // and this parent process does not need to report any further5716 fatal("the following build command crashed:\n{s}", .{cmd});
5589 // diagnostics.5717 },
5590 if (code == 2) process.exit(2);5718 }
55915719 } else {
5592 const cmd = try std.mem.join(arena, " ", child_argv);5720 const cmd = try std.mem.join(arena, " ", child_argv.items);
5593 fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd });5721 fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), 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 },
5599 }5722 }
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 });
5603 }5723 }
5604}5724}
56055725
...@@ -7343,6 +7463,7 @@ fn cmdFetch(...@@ -7343,6 +7463,7 @@ fn cmdFetch(
7343 .thread_pool = &thread_pool,7463 .thread_pool = &thread_pool,
7344 .global_cache = global_cache_directory,7464 .global_cache = global_cache_directory,
7345 .recursive = false,7465 .recursive = false,
7466 .read_only = false,
7346 .debug_hash = debug_hash,7467 .debug_hash = debug_hash,
7347 .work_around_btrfs_bug = work_around_btrfs_bug,7468 .work_around_btrfs_bug = work_around_btrfs_bug,
7348 };7469 };
...@@ -7353,6 +7474,8 @@ fn cmdFetch(...@@ -7353,6 +7474,8 @@ fn cmdFetch(
7353 .location = .{ .path_or_url = path_or_url },7474 .location = .{ .path_or_url = path_or_url },
7354 .location_tok = 0,7475 .location_tok = 0,
7355 .hash_tok = 0,7476 .hash_tok = 0,
7477 .name_tok = 0,
7478 .lazy_status = .eager,
7356 .parent_package_root = undefined,7479 .parent_package_root = undefined,
7357 .parent_manifest_ast = null,7480 .parent_manifest_ast = null,
7358 .prog_node = root_prog_node,7481 .prog_node = root_prog_node,
test/src/Cases.zig+2-2
...@@ -562,7 +562,7 @@ pub fn lowerToBuildSteps(...@@ -562,7 +562,7 @@ pub fn lowerToBuildSteps(
562 run.setName(incr_case.base_path);562 run.setName(incr_case.base_path);
563 run.addArgs(&.{563 run.addArgs(&.{
564 case_base_path_with_dir,564 case_base_path_with_dir,
565 b.zig_exe,565 b.graph.zig_exe,
566 });566 });
567 run.expectStdOutEqual("");567 run.expectStdOutEqual("");
568 parent_step.dependOn(&run.step);568 parent_step.dependOn(&run.step);
...@@ -653,7 +653,7 @@ pub fn lowerToBuildSteps(...@@ -653,7 +653,7 @@ pub fn lowerToBuildSteps(
653 break :no_exec;653 break :no_exec;
654 }654 }
655 const run_c = b.addSystemCommand(&.{655 const run_c = b.addSystemCommand(&.{
656 b.zig_exe,656 b.graph.zig_exe,
657 "run",657 "run",
658 "-cflags",658 "-cflags",
659 "-Ilib",659 "-Ilib",
test/tests.zig+11-11
...@@ -796,7 +796,7 @@ pub fn addCliTests(b: *std.Build) *Step {...@@ -796,7 +796,7 @@ pub fn addCliTests(b: *std.Build) *Step {
796 {796 {
797 // Test `zig init`.797 // Test `zig init`.
798 const tmp_path = b.makeTempPath();798 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" });
800 init_exe.setCwd(.{ .cwd_relative = tmp_path });800 init_exe.setCwd(.{ .cwd_relative = tmp_path });
801 init_exe.setName("zig init");801 init_exe.setName("zig init");
802 init_exe.expectStdOutEqual("");802 init_exe.expectStdOutEqual("");
...@@ -810,20 +810,20 @@ pub fn addCliTests(b: *std.Build) *Step {...@@ -810,20 +810,20 @@ pub fn addCliTests(b: *std.Build) *Step {
810 const bad_out_arg = "-femit-bin=does" ++ s ++ "not" ++ s ++ "exist" ++ s ++ "foo.exe";810 const bad_out_arg = "-femit-bin=does" ++ s ++ "not" ++ s ++ "exist" ++ s ++ "foo.exe";
811 const ok_src_arg = "src" ++ s ++ "main.zig";811 const ok_src_arg = "src" ++ s ++ "main.zig";
812 const expected = "error: unable to open output directory 'does" ++ s ++ "not" ++ s ++ "exist': FileNotFound\n";812 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 });
814 run_bad.setName("zig build-exe error message for bad -femit-bin arg");814 run_bad.setName("zig build-exe error message for bad -femit-bin arg");
815 run_bad.expectExitCode(1);815 run_bad.expectExitCode(1);
816 run_bad.expectStdErrEqual(expected);816 run_bad.expectStdErrEqual(expected);
817 run_bad.expectStdOutEqual("");817 run_bad.expectStdOutEqual("");
818 run_bad.step.dependOn(&init_exe.step);818 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" });
821 run_test.setCwd(.{ .cwd_relative = tmp_path });821 run_test.setCwd(.{ .cwd_relative = tmp_path });
822 run_test.setName("zig build test");822 run_test.setName("zig build test");
823 run_test.expectStdOutEqual("");823 run_test.expectStdOutEqual("");
824 run_test.step.dependOn(&init_exe.step);824 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" });
827 run_run.setCwd(.{ .cwd_relative = tmp_path });827 run_run.setCwd(.{ .cwd_relative = tmp_path });
828 run_run.setName("zig build run");828 run_run.setName("zig build run");
829 run_run.expectStdOutEqual("Run `zig build test` to run the tests.\n");829 run_run.expectStdOutEqual("Run `zig build test` to run the tests.\n");
...@@ -857,7 +857,7 @@ pub fn addCliTests(b: *std.Build) *Step {...@@ -857,7 +857,7 @@ pub fn addCliTests(b: *std.Build) *Step {
857857
858 // This is intended to be the exact CLI usage used by godbolt.org.858 // This is intended to be the exact CLI usage used by godbolt.org.
859 const run = b.addSystemCommand(&.{859 const run = b.addSystemCommand(&.{
860 b.zig_exe, "build-obj",860 b.graph.zig_exe, "build-obj",
861 "--cache-dir", tmp_path,861 "--cache-dir", tmp_path,
862 "--name", "example",862 "--name", "example",
863 "-fno-emit-bin", "-fno-emit-h",863 "-fno-emit-bin", "-fno-emit-h",
...@@ -900,7 +900,7 @@ pub fn addCliTests(b: *std.Build) *Step {...@@ -900,7 +900,7 @@ pub fn addCliTests(b: *std.Build) *Step {
900 subdir.writeFile("fmt3.zig", unformatted_code) catch @panic("unhandled");900 subdir.writeFile("fmt3.zig", unformatted_code) catch @panic("unhandled");
901901
902 // Test zig fmt affecting only the appropriate files.902 // 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" });
904 run1.setName("run zig fmt one file");904 run1.setName("run zig fmt one file");
905 run1.setCwd(.{ .cwd_relative = tmp_path });905 run1.setCwd(.{ .cwd_relative = tmp_path });
906 run1.has_side_effects = true;906 run1.has_side_effects = true;
...@@ -908,7 +908,7 @@ pub fn addCliTests(b: *std.Build) *Step {...@@ -908,7 +908,7 @@ pub fn addCliTests(b: *std.Build) *Step {
908 run1.expectStdOutEqual("fmt1.zig\n");908 run1.expectStdOutEqual("fmt1.zig\n");
909909
910 // Test excluding files and directories from a run910 // 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", "." });
912 run2.setName("run zig fmt on directory with exclusions");912 run2.setName("run zig fmt on directory with exclusions");
913 run2.setCwd(.{ .cwd_relative = tmp_path });913 run2.setCwd(.{ .cwd_relative = tmp_path });
914 run2.has_side_effects = true;914 run2.has_side_effects = true;
...@@ -916,7 +916,7 @@ pub fn addCliTests(b: *std.Build) *Step {...@@ -916,7 +916,7 @@ pub fn addCliTests(b: *std.Build) *Step {
916 run2.step.dependOn(&run1.step);916 run2.step.dependOn(&run1.step);
917917
918 // Test excluding non-existent file918 // 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", "." });
920 run3.setName("run zig fmt on directory with non-existent exclusion");920 run3.setName("run zig fmt on directory with non-existent exclusion");
921 run3.setCwd(.{ .cwd_relative = tmp_path });921 run3.setCwd(.{ .cwd_relative = tmp_path });
922 run3.has_side_effects = true;922 run3.has_side_effects = true;
...@@ -924,7 +924,7 @@ pub fn addCliTests(b: *std.Build) *Step {...@@ -924,7 +924,7 @@ pub fn addCliTests(b: *std.Build) *Step {
924 run3.step.dependOn(&run2.step);924 run3.step.dependOn(&run2.step);
925925
926 // running it on the dir, only the new file should be changed926 // 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", "." });
928 run4.setName("run zig fmt the directory");928 run4.setName("run zig fmt the directory");
929 run4.setCwd(.{ .cwd_relative = tmp_path });929 run4.setCwd(.{ .cwd_relative = tmp_path });
930 run4.has_side_effects = true;930 run4.has_side_effects = true;
...@@ -932,7 +932,7 @@ pub fn addCliTests(b: *std.Build) *Step {...@@ -932,7 +932,7 @@ pub fn addCliTests(b: *std.Build) *Step {
932 run4.step.dependOn(&run3.step);932 run4.step.dependOn(&run3.step);
933933
934 // both files have been formatted, nothing should change now934 // 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", "." });
936 run5.setName("run zig fmt with nothing to do");936 run5.setName("run zig fmt with nothing to do");
937 run5.setCwd(.{ .cwd_relative = tmp_path });937 run5.setCwd(.{ .cwd_relative = tmp_path });
938 run5.has_side_effects = true;938 run5.has_side_effects = true;
...@@ -946,7 +946,7 @@ pub fn addCliTests(b: *std.Build) *Step {...@@ -946,7 +946,7 @@ pub fn addCliTests(b: *std.Build) *Step {
946 write6.step.dependOn(&run5.step);946 write6.step.dependOn(&run5.step);
947947
948 // Test `zig fmt` handling UTF-16 decoding.948 // 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", "." });
950 run6.setName("run zig fmt convert UTF-16 to UTF-8");950 run6.setName("run zig fmt convert UTF-16 to UTF-8");
951 run6.setCwd(.{ .cwd_relative = tmp_path });951 run6.setCwd(.{ .cwd_relative = tmp_path });
952 run6.has_side_effects = true;952 run6.has_side_effects = true;