authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-03 22:21:13-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-25 18:54:35-07:00
logddabd57743579818a05016e031b4919c47b4428a
treef92f4f302401b787254c0ba1e282bd83be48a6d2
parentfa26566867cddbb0cd067cbc1d41bd41e68002a1

progress towards compiling zig's build script


17 files changed, 437 insertions(+), 248 deletions(-)

BRANCH_TODO+1
......@@ -17,6 +17,7 @@
1717
1818* implement {q} or delete {q} uses
1919* make the generated dependencies.zig be dependencies.zon and don't put absolute paths in there
20 - and adjust dependencyInner to not openDir()
2021
2122## Followup Issues
2223* reduce the size of Maker.Step.Extended (make Run smaller) probably by using an arena per make
build.zig+31-23
......@@ -16,6 +16,8 @@ const IoMode = enum { threaded, evented };
1616const ValueInterpretMode = enum { direct, by_name };
1717
1818pub fn build(b: *std.Build) !void {
19 const arena = b.graph.arena;
20
1921 const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse false;
2022 const target = b.standardTargetOptions(.{
2123 .default_target = .{
......@@ -35,7 +37,7 @@ pub fn build(b: *std.Build) !void {
3537 const no_bin = b.option(bool, "no-bin", "skip emitting compiler binary") orelse false;
3638 const enable_superhtml = b.option(bool, "enable-superhtml", "Check langref output HTML validity") orelse false;
3739
38 const langref_file = generateLangRef(b);
40 const langref_file = try generateLangRef(b);
3941 const install_langref = b.addInstallFileWithDir(langref_file, .prefix, "doc/langref.html");
4042 const check_langref = superHtmlCheck(b, langref_file);
4143 if (enable_superhtml) install_langref.step.dependOn(check_langref);
......@@ -262,7 +264,7 @@ pub fn build(b: *std.Build) !void {
262264 var code: u8 = undefined;
263265 const git_describe_untrimmed = b.runAllowFail(&[_][]const u8{
264266 "git",
265 "-C", b.build_root.path orelse ".", // affects the --git-dir argument
267 "-C", b.fmt("{f}", .{b.root}), // affects the --git-dir argument
266268 "--git-dir", ".git", // affected by the -C argument
267269 "describe", "--match", "*.*.*", //
268270 "--tags", "--abbrev=9",
......@@ -308,7 +310,7 @@ pub fn build(b: *std.Build) !void {
308310 },
309311 }
310312 };
311 const version = try b.allocator.dupeSentinel(u8, version_slice, 0);
313 const version = try arena.dupeSentinel(u8, version_slice, 0);
312314 exe_options.addOption([:0]const u8, "version", version);
313315
314316 if (enable_llvm) {
......@@ -316,7 +318,7 @@ pub fn build(b: *std.Build) !void {
316318 const io = b.graph.io;
317319 const cwd: Io.Dir = .cwd();
318320 if (findConfigH(b, config_h_path_option)) |config_h_path| {
319 const file_contents = cwd.readFileAlloc(io, config_h_path, b.allocator, .limited(max_config_h_bytes)) catch unreachable;
321 const file_contents = cwd.readFileAlloc(io, config_h_path, arena, .limited(max_config_h_bytes)) catch unreachable;
320322 break :blk parseConfigH(b, file_contents);
321323 } else {
322324 std.log.warn("config.h could not be located automatically. Consider providing it explicitly via \"-Dconfig_h\"", .{});
......@@ -976,11 +978,12 @@ fn addCxxKnownPath(
976978 errtxt: ?[]const u8,
977979 need_cpp_includes: bool,
978980) !void {
979 if (!std.process.can_spawn)
980 return error.RequiredLibraryNotFound;
981 if (!std.process.can_spawn) return error.RequiredLibraryNotFound;
982
983 const arena = b.graph.arena;
981984
982985 const path_padded = run: {
983 var args = std.array_list.Managed([]const u8).init(b.allocator);
986 var args = std.array_list.Managed([]const u8).init(arena);
984987 try args.append(ctx.cxx_compiler);
985988 var it = std.mem.tokenizeAny(u8, ctx.cxx_compiler_arg1, &std.ascii.whitespace);
986989 while (it.next()) |arg| try args.append(arg);
......@@ -1049,6 +1052,7 @@ const CMakeConfig = struct {
10491052const max_config_h_bytes = 1 * 1024 * 1024;
10501053
10511054fn findConfigH(b: *std.Build, config_h_path_option: ?[]const u8) ?[]const u8 {
1055 const arena = b.graph.arena;
10521056 const io = b.graph.io;
10531057 const cwd: Io.Dir = .cwd();
10541058
......@@ -1073,7 +1077,7 @@ fn findConfigH(b: *std.Build, config_h_path_option: ?[]const u8) ?[]const u8 {
10731077 if (config_h_or_err) |*file| {
10741078 file.close(io);
10751079 return fs.path.join(
1076 b.allocator,
1080 arena,
10771081 &[_][]const u8{ check_dir, "config.h" },
10781082 ) catch unreachable;
10791083 } else |e| switch (e) {
......@@ -1198,7 +1202,8 @@ fn parseConfigH(b: *std.Build, config_h_text: []const u8) ?CMakeConfig {
11981202}
11991203
12001204fn toNativePathSep(b: *std.Build, s: []const u8) []u8 {
1201 const duplicated = b.allocator.dupe(u8, s) catch unreachable;
1205 const arena = b.graph.arena;
1206 const duplicated = arena.dupe(u8, s) catch unreachable;
12021207 for (duplicated) |*byte| switch (byte.*) {
12031208 '/' => byte.* = fs.path.sep,
12041209 else => {},
......@@ -1487,8 +1492,9 @@ const llvm_libs_xtensa = [_][]const u8{
14871492 "LLVMXtensaInfo",
14881493};
14891494
1490fn generateLangRef(b: *std.Build) std.Build.LazyPath {
1495fn generateLangRef(b: *std.Build) !std.Build.LazyPath {
14911496 const io = b.graph.io;
1497 const arena = b.graph.arena;
14921498
14931499 const doctest_exe = b.addExecutable(.{
14941500 .name = "doctest",
......@@ -1499,10 +1505,7 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath {
14991505 }),
15001506 });
15011507
1502 const langref_path: std.Build.Cache.Path = .{
1503 .root_dir = b.build_root,
1504 .sub_path = "doc/langref",
1505 };
1508 const langref_path = try b.root.join(arena, "doc/langref");
15061509
15071510 var dir = langref_path.root_dir.handle.openDir(io, langref_path.sub_path, .{ .iterate = true }) catch |err|
15081511 std.debug.panic("unable to open directory {f}: {t}", .{ langref_path, err });
......@@ -1518,17 +1521,22 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath {
15181521
15191522 const out_basename = b.fmt("{s}.out", .{std.fs.path.stem(entry.name)});
15201523 const cmd = b.addRunArtifact(doctest_exe);
1521 cmd.addArgs(&.{
1522 "--zig", b.graph.zig_exe,
1523 // TODO: enhance doctest to use "--listen=-" rather than operating
1524 // in a temporary directory
1525 "--cache-root", b.cache_root.path orelse ".",
1526 });
1527 cmd.addArgs(&.{ "--zig-lib-dir", b.fmt("{f}", .{b.graph.zig_lib_directory}) });
1528 cmd.addArgs(&.{"-i"});
1524
1525 cmd.addArg("--zig");
1526 cmd.addFileArg(.zig_exe);
1527
1528 // TODO: enhance doctest to use "--listen=-" rather than operating in a
1529 // temporary directory
1530 cmd.addArg("--cache-root");
1531 cmd.addFileArg(.cache_root);
1532
1533 cmd.addArg("--zig-lib-dir");
1534 cmd.addFileArg(.zig_lib);
1535
1536 cmd.addArg("-i");
15291537 cmd.addFileArg(b.path(b.fmt("doc/langref/{s}", .{entry.name})));
15301538
1531 cmd.addArgs(&.{"-o"});
1539 cmd.addArg("-o");
15321540 _ = wf.addCopyFile(cmd.addOutputFileArg(out_basename), out_basename);
15331541 }
15341542
lib/compiler/Maker.zig+9
......@@ -1779,6 +1779,7 @@ pub fn relativePath(maker: *const Maker, relative: Configuration.LazyPath.Relati
17791779 const graph = maker.graph;
17801780 const c = &maker.scanned_config.configuration;
17811781 const sub_path = relative.sub_path.slice(c);
1782 if (relative.flags.base == .zig_exe and sub_path.len != 0) @panic("TODO");
17821783 return switch (relative.flags.base) {
17831784 .cwd => .{
17841785 .root_dir = .cwd(),
......@@ -1796,6 +1797,14 @@ pub fn relativePath(maker: *const Maker, relative: Configuration.LazyPath.Relati
17961797 .root_dir = graph.build_root_directory,
17971798 .sub_path = sub_path,
17981799 },
1800 .zig_exe => .{
1801 .root_dir = .cwd(),
1802 .sub_path = graph.zig_exe,
1803 },
1804 .zig_lib => .{
1805 .root_dir = graph.zig_lib_directory,
1806 .sub_path = sub_path,
1807 },
17991808 };
18001809}
18011810
lib/compiler/Maker/Graph.zig+5-4
......@@ -75,10 +75,11 @@ pub fn handleVerbose(
7575) error{OutOfMemory}!void {
7676 if (!graph.verbose) return;
7777 const arena = graph.arena;
78 const text = try std.zig.allocPrintCmd(arena, cwd, if (opt_env) |env| .{
79 .child = env,
80 .parent = &graph.environ_map,
81 } else null, argv);
78 const text = try std.zig.allocPrintCmd(arena, argv, .{
79 .cwd = cwd,
80 .parent_env = &graph.environ_map,
81 .child_env = opt_env,
82 });
8283 defer arena.free(text);
8384 std.log.scoped(.verbose).info("{s}", .{text});
8485}
lib/compiler/Maker/Step.zig+4-2
......@@ -70,6 +70,7 @@ pub const Extended = union(enum) {
7070 compile: Compile,
7171 config_header: Todo,
7272 fail: Todo,
73 find_program: Todo,
7374 fmt: Todo,
7475 install_artifact: InstallArtifact,
7576 install_dir: Todo,
......@@ -89,6 +90,7 @@ pub const Extended = union(enum) {
8990 .compile => .{ .compile = .{} },
9091 .config_header => .{ .config_header = .{} },
9192 .fail => .{ .fail = .{} },
93 .find_program => .{ .find_program = .{} },
9294 .fmt => .{ .fmt = .{} },
9395 .install_artifact => .{ .install_artifact = .{} },
9496 .install_dir => .{ .install_dir = .{} },
......@@ -314,7 +316,7 @@ pub fn captureChildProcess(
314316
315317 // If an error occurs, it's happened in this command:
316318 assert(s.result_failed_command == null);
317 s.result_failed_command = try std.zig.allocPrintCmd(gpa, .inherit, null, argv);
319 s.result_failed_command = try std.zig.allocPrintCmd(gpa, argv, .{});
318320
319321 try handleChildProcUnsupported(s, maker);
320322 try graph.handleVerbose(.inherit, null, argv);
......@@ -382,7 +384,7 @@ pub fn evalZigProcess(
382384
383385 // If an error occurs, it's happened in this command:
384386 assert(s.result_failed_command == null);
385 s.result_failed_command = try std.zig.allocPrintCmd(gpa, .inherit, null, argv);
387 s.result_failed_command = try std.zig.allocPrintCmd(gpa, argv, .{});
386388
387389 if (s.getZigProcess()) |zp| update: {
388390 assert(watch);
lib/compiler/Maker/Step/Run.zig+5-4
......@@ -2129,10 +2129,11 @@ fn spawnChildAndCollect(
21292129
21302130 // If an error occurs, it's caused by this command:
21312131 assert(step.result_failed_command == null);
2132 step.result_failed_command = try std.zig.allocPrintCmd(arena, child_cwd, .{
2133 .child = environ_map,
2134 .parent = &graph.environ_map,
2135 }, argv);
2132 step.result_failed_command = try std.zig.allocPrintCmd(arena, argv, .{
2133 .cwd = child_cwd,
2134 .child_env = environ_map,
2135 .parent_env = &graph.environ_map,
2136 });
21362137
21372138 try step.handleChildProcUnsupported(maker);
21382139
lib/compiler/Maker/WebServer.zig+6-6
......@@ -714,7 +714,7 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim
714714 if (code != 0) {
715715 log.err(
716716 "the following command exited with error code {d}:\n{s}",
717 .{ code, try std.zig.allocPrintCmd(arena, .inherit, null, argv.items) },
717 .{ code, try std.zig.allocPrintCmd(arena, argv.items, .{}) },
718718 );
719719 return error.WasmCompilationFailed;
720720 }
......@@ -722,21 +722,21 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim
722722 .signal => |sig| {
723723 log.err(
724724 "the following command terminated with signal {t}:\n{s}",
725 .{ sig, try std.zig.allocPrintCmd(arena, .inherit, null, argv.items) },
725 .{ sig, try std.zig.allocPrintCmd(arena, argv.items, .{}) },
726726 );
727727 return error.WasmCompilationFailed;
728728 },
729729 .stopped => |sig| {
730730 log.err(
731731 "the following command stopped unexpectedly with signal {t}:\n{s}",
732 .{ sig, try std.zig.allocPrintCmd(arena, .inherit, null, argv.items) },
732 .{ sig, try std.zig.allocPrintCmd(arena, argv.items, .{}) },
733733 );
734734 return error.WasmCompilationFailed;
735735 },
736736 .unknown => {
737737 log.err(
738738 "the following command terminated unexpectedly:\n{s}",
739 .{try std.zig.allocPrintCmd(arena, .inherit, null, argv.items)},
739 .{try std.zig.allocPrintCmd(arena, argv.items, .{})},
740740 );
741741 return error.WasmCompilationFailed;
742742 },
......@@ -746,14 +746,14 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim
746746 try result_error_bundle.renderToStderr(io, .{}, .auto);
747747 log.err("the following command failed with {d} compilation errors:\n{s}", .{
748748 result_error_bundle.errorMessageCount(),
749 try std.zig.allocPrintCmd(arena, .inherit, null, argv.items),
749 try std.zig.allocPrintCmd(arena, argv.items, .{}),
750750 });
751751 return error.WasmCompilationFailed;
752752 }
753753
754754 const base_path = result orelse {
755755 log.err("child process failed to report result\n{s}", .{
756 try std.zig.allocPrintCmd(arena, .inherit, null, argv.items),
756 try std.zig.allocPrintCmd(arena, argv.items, .{}),
757757 });
758758 return error.WasmCompilationFailed;
759759 };
lib/compiler/configurer.zig+30-2
......@@ -62,10 +62,22 @@ pub fn main(init: process.Init.Minimal) !void {
6262 assert(try graph.wip_configuration.addString("") == .empty);
6363 assert(try graph.wip_configuration.addString("root") == .root);
6464
65 const builder = try std.Build.create(&graph, dependencies.root_deps);
65 var arg_i: usize = 1; // Skip own executable name.
66
67 const build_root_sub_path = expectArgOrFatal(args, &arg_i, "--build-root");
68
69 const cwd: Io.Dir = .cwd();
70
71 const build_root: std.Build.Cache.Path = .{
72 .root_dir = .{
73 .handle = try cwd.openDir(io, build_root_sub_path, .{}),
74 .path = build_root_sub_path,
75 },
76 };
77
78 const builder = try std.Build.create(&graph, build_root, dependencies.root_deps);
6679
6780 var color: Color = .auto;
68 var arg_i: usize = 1; // Skip own executable name.
6981
7082 while (nextArg(args, &arg_i)) |arg| {
7183 if (mem.cutPrefix(u8, arg, "-D")) |option_contents| {
......@@ -98,6 +110,8 @@ pub fn main(init: process.Init.Minimal) !void {
98110 // but it is handled by the parent process. The build runner
99111 // only sees this flag.
100112 graph.system_package_mode = true;
113 } else if (mem.eql(u8, arg, "--verbose")) {
114 graph.verbose = true;
101115 } else {
102116 fatalWithHint("unrecognized argument: {s}", .{arg});
103117 }
......@@ -183,6 +197,12 @@ const Serialize = struct {
183197 .sub_path = sub_path,
184198 }));
185199 },
200 .relative => |relative| i: {
201 break :i try wc.addExtra(@as(Configuration.LazyPath.Relative, .{
202 .flags = .{ .base = relative.base },
203 .sub_path = relative.sub_path,
204 }));
205 },
186206 .dependency => |dependency| i: {
187207 const sub_path = try wc.addString(dependency.sub_path);
188208 break :i try wc.addExtra(@as(Configuration.LazyPath.SourcePath, .{
......@@ -840,6 +860,7 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
840860 .install_dir => @panic("TODO"),
841861 .remove_dir => @panic("TODO"),
842862 .fail => @panic("TODO"),
863 .find_program => @panic("TODO"),
843864 .fmt => @panic("TODO"),
844865 .translate_c => @panic("TODO"),
845866 .write_file => @panic("TODO"),
......@@ -1038,6 +1059,13 @@ fn nextArg(args: []const [:0]const u8, idx: *usize) ?[:0]const u8 {
10381059 return args[idx.*];
10391060}
10401061
1062fn expectArgOrFatal(args: []const [:0]const u8, index_ptr: *usize, first: []const u8) []const u8 {
1063 const next_arg = nextArg(args, index_ptr) orelse fatal("missing {q} argument", .{first});
1064 if (!mem.eql(u8, first, next_arg)) fatal("expected {q} instead of {q}", .{ first, next_arg });
1065 const arg = nextArg(args, index_ptr) orelse fatal("expected argument after {q}", .{first});
1066 return arg;
1067}
1068
10411069const ErrorStyle = enum {
10421070 verbose,
10431071 minimal,
lib/std/Build.zig+216-126
......@@ -34,6 +34,8 @@ available_options_map: std.array_hash_map.String(AvailableOption) = .empty,
3434invalid_user_input: bool,
3535default_step: *Step,
3636top_level_steps: std.StringArrayHashMapUnmanaged(*Step.TopLevel),
37/// Path to the directory containing build.zig.
38root: Cache.Path,
3739debug_log_scopes: []const []const u8 = &.{},
3840/// Number of stack frames captured when a `StackTrace` is recorded for debug purposes,
3941/// in particular at `Step` creation.
......@@ -85,6 +87,7 @@ pub const Graph = struct {
8587 dependency_cache: InitializedDepMap = .empty,
8688 allow_so_scripts: ?bool = null,
8789 time_report: bool = false,
90 verbose: bool = false,
8891 /// Similar to the `Io.Terminal.Mode` returned by `Io.lockStderr`, but also
8992 /// respects the '--color' flag.
9093 stderr_mode: ?Io.Terminal.Mode = null,
......@@ -117,6 +120,20 @@ pub const Graph = struct {
117120 for (array, strings) |*dest, source| dest.* = dupeString(graph, source);
118121 return array;
119122 }
123
124 /// An absolute path or a path relative to the current working directory of
125 /// the build runner process.
126 ///
127 /// Use of this function indicates a dependency on the host system.
128 pub fn cwdRelativePath(graph: *Graph, sub_path: []const u8) LazyPath {
129 const wc = &graph.wip_configuration;
130 return .{
131 .relative = .{
132 .base = .cwd,
133 .sub_path = wc.addString(sub_path) catch @panic("OOM"),
134 },
135 };
136 }
120137};
121138
122139const AvailableDeps = []const struct { []const u8, []const u8 };
......@@ -170,13 +187,6 @@ const InitializedDepContext = struct {
170187 }
171188};
172189
173pub const RunError = error{
174 ReadFailure,
175 ExitCodeFailure,
176 ProcessTerminated,
177 ExecNotSupported,
178} || std.process.SpawnError;
179
180190const UserInputOptionsMap = StringHashMap(UserInputOption);
181191
182192const AvailableOption = struct {
......@@ -204,6 +214,7 @@ const UserValue = union(enum) {
204214
205215pub fn create(
206216 graph: *Graph,
217 root: Cache.Path,
207218 available_deps: AvailableDeps,
208219) error{OutOfMemory}!*Build {
209220 const arena = graph.arena;
......@@ -211,6 +222,7 @@ pub fn create(
211222 const b = try arena.create(Build);
212223 b.* = .{
213224 .graph = graph,
225 .root = root,
214226 .invalid_user_input = false,
215227 .allocator = arena,
216228 .user_input_options = UserInputOptionsMap.init(arena),
......@@ -247,6 +259,7 @@ pub fn create(
247259fn createChild(
248260 parent: *Build,
249261 dep_name: []const u8,
262 root: Cache.Path,
250263 pkg_hash: []const u8,
251264 pkg_deps: AvailableDeps,
252265 user_input_options: UserInputOptionsMap,
......@@ -255,6 +268,7 @@ fn createChild(
255268 const child = try allocator.create(Build);
256269 child.* = .{
257270 .graph = parent.graph,
271 .root = root,
258272 .allocator = allocator,
259273 .install_tls = .{
260274 .step = .init(.{
......@@ -1143,7 +1157,7 @@ pub fn step(b: *Build, name: []const u8, description: []const u8) *Step {
11431157 .description = b.dupe(description),
11441158 };
11451159 const gop = b.top_level_steps.getOrPut(b.allocator, name) catch @panic("OOM");
1146 if (gop.found_existing) std.debug.panic("A top-level step with name \"{s}\" already exists", .{name});
1160 if (gop.found_existing) panic("A top-level step with name \"{s}\" already exists", .{name});
11471161
11481162 gop.key_ptr.* = step_info.step.name;
11491163 gop.value_ptr.* = step_info;
......@@ -1366,7 +1380,8 @@ pub fn addUserInputOption(b: *Build, name_raw: []const u8, value_raw: []const u8
13661380}
13671381
13681382pub fn addUserInputFlag(b: *Build, name_raw: []const u8) error{OutOfMemory}!bool {
1369 const name = b.dupe(name_raw);
1383 const graph = b.graph;
1384 const name = graph.dupeString(name_raw);
13701385 const gop = try b.user_input_options.getOrPut(name);
13711386 if (!gop.found_existing) {
13721387 gop.value_ptr.* = .{
......@@ -1388,7 +1403,7 @@ pub fn addUserInputFlag(b: *Build, name_raw: []const u8) error{OutOfMemory}!bool
13881403 return true;
13891404 },
13901405 .lazy_path => |lp| {
1391 log.err("Flag '-D{s}' conflicts with option '-D{s}={s}'.", .{ name, name, lp.getDisplayName() });
1406 log.err("Flag '-D{s}' conflicts with option '-D{s}={f}'.", .{ name, name, lp.fmt(graph) });
13921407 return true;
13931408 },
13941409
......@@ -1538,7 +1553,7 @@ pub fn truncateFile(b: *Build, dest_path: []const u8) (Io.Dir.CreateDirError ||
15381553/// References a file or directory relative to the source root.
15391554pub fn path(b: *Build, sub_path: []const u8) LazyPath {
15401555 if (fs.path.isAbsolute(sub_path)) {
1541 std.debug.panic("sub_path is expected to be relative to the build root, but was this absolute path: '{s}'. It is best avoid absolute paths, but if you must, it is supported by LazyPath.cwd_relative", .{
1556 panic("sub_path is expected to be relative to the build root, but was this absolute path: '{s}'. It is best avoid absolute paths, but if you must, it is supported by LazyPath.cwd_relative", .{
15421557 sub_path,
15431558 });
15441559 }
......@@ -1560,117 +1575,164 @@ pub fn fmt(b: *Build, comptime format: []const u8, args: anytype) []u8 {
15601575 return std.fmt.allocPrint(b.allocator, format, args) catch @panic("OOM");
15611576}
15621577
1563fn supportedWindowsProgramExtension(ext: []const u8) bool {
1564 inline for (@typeInfo(std.process.WindowsExtension).@"enum".fields) |field| {
1565 if (std.ascii.eqlIgnoreCase(ext, "." ++ field.name)) return true;
1566 }
1567 return false;
1578/// Creates an anonymous `Step` that searches for an executable on the host that
1579/// has more than one possible name.
1580///
1581/// Names are searched in order, observing search prefixes first and then PATH
1582/// environment variable.
1583///
1584/// Returns the `LazyPath` of the found executable. The search only takes place
1585/// if the `LazyPath` will be used by a depending `Step`.
1586pub fn findProgram(b: *Build, names: []const []const u8) LazyPath {
1587 const graph = b.graph;
1588 const wc = &graph.wip_configuration;
1589 const string_list = wc.addStringList(names) catch @panic("OOM");
1590 _ = string_list;
1591 @panic("TODO");
15681592}
15691593
1570fn tryFindProgram(b: *Build, full_path: []const u8) ?[]const u8 {
1571 const io = b.graph.io;
1572 const arena = b.allocator;
1573
1574 if (b.build_root.handle.realPathFileAlloc(io, full_path, arena)) |p| {
1575 return p;
1576 } else |err| switch (err) {
1577 error.OutOfMemory => @panic("OOM"),
1578 else => {},
1579 }
1580
1581 if (builtin.os.tag == .windows) {
1582 if (b.graph.environ_map.get("PATHEXT")) |PATHEXT| {
1583 var it = mem.tokenizeScalar(u8, PATHEXT, fs.path.delimiter);
1584
1585 while (it.next()) |ext| {
1586 if (!supportedWindowsProgramExtension(ext)) continue;
1587
1588 return b.build_root.handle.realPathFileAlloc(
1589 io,
1590 b.fmt("{s}{s}", .{ full_path, ext }),
1591 arena,
1592 ) catch |err| switch (err) {
1593 error.OutOfMemory => @panic("OOM"),
1594 else => continue,
1595 };
1596 }
1597 }
1594/// Deprecated; use `runFallible`.
1595pub fn runAllowFail(
1596 b: *Build,
1597 argv: []const []const u8,
1598 exit_code: *u8,
1599 stderr_behavior: process.SpawnOptions.StdIo,
1600) anyerror![]u8 {
1601 if (!process.can_spawn) return error.ExecNotSupported;
1602 switch (runFallible(b, argv, .{
1603 .stderr_behavior = stderr_behavior,
1604 })) {
1605 .success => |stdout| return stdout,
1606 .spawn_failed => |err| return err,
1607 .bad_exit_code => |code| {
1608 exit_code.* = code;
1609 return error.ExitCodeFailure;
1610 },
1611 .crashed => {
1612 exit_code.* = 255;
1613 return error.ProcessTerminated;
1614 },
15981615 }
1599
1600 return null;
16011616}
16021617
1603pub fn findProgram(b: *Build, names: []const []const u8, paths: []const []const u8) LazyPath {
1604 _ = b;
1605 _ = names;
1606 _ = paths;
1607 @panic("TODO rework findProgram to be based on LazyPath");
1608}
1618pub const RunOptions = struct {
1619 stderr_behavior: process.SpawnOptions.StdIo = .inherit,
1620 /// Fail the configuration if stdout is larger than this.
1621 stdout_limit: Io.Limit = .limited(1_000_000),
1622 /// Set to change the current working directory when spawning the child
1623 /// process.
1624 cwd: process.Child.Cwd = .inherit,
1625 /// Replaces the child environment when provided. The PATH value from here
1626 /// is not used to resolve `argv[0]`; that resolution always uses parent
1627 /// environment.
1628 environ_map: ?*const process.Environ.Map = null,
1629 expand_arg0: process.ArgExpansion = .no_expand,
1630};
16091631
1610pub fn runAllowFail(
1611 b: *Build,
1612 argv: []const []const u8,
1613 out_code: *u8,
1614 stderr_behavior: std.process.SpawnOptions.StdIo,
1615) RunError![]u8 {
1616 assert(argv.len != 0);
1632pub const RunResult = union(enum) {
1633 /// Thild process exited with code 0, writing this stdout.
1634 success: []u8,
1635 /// The child process could not be created.
1636 spawn_failed: process.SpawnError,
1637 /// The child process indicated failure.
1638 bad_exit_code: u8,
1639 /// The child process terminated abnormally.
1640 crashed,
1641};
16171642
1618 if (!process.can_spawn)
1619 return error.ExecNotSupported;
1643/// Executes the provided command immediately, allowing failure.
1644///
1645/// If the program exits successfully, stdout is returned. Otherwise, returns
1646/// an indication of failure.
1647///
1648/// See also:
1649/// * `run`.
1650pub fn runFallible(b: *Build, argv: []const []const u8, options: RunOptions) RunResult {
1651 assert(argv.len != 0);
16201652
16211653 const graph = b.graph;
16221654 const io = graph.io;
16231655 const arena = graph.arena;
16241656
1625 const max_output_size = 400 * 1024;
1657 const print_opts: std.zig.AllocPrintCmdOptions = .{
1658 .cwd = options.cwd,
1659 .child_env = options.environ_map,
1660 .parent_env = &graph.environ_map,
1661 };
1662
16261663 if (graph.verbose) {
1627 const text = std.zig.allocPrintCmd(arena, .inherit, null, argv);
1664 const text = std.zig.allocPrintCmd(arena, argv, print_opts) catch @panic("OOM");
16281665 std.log.scoped(.verbose).info("{s}", .{text});
16291666 }
16301667
1631 var child = try std.process.spawn(io, .{
1668 var child = process.spawn(io, .{
16321669 .argv = argv,
1633 .environ_map = &graph.environ_map,
16341670 .stdin = .ignore,
16351671 .stdout = .pipe,
1636 .stderr = stderr_behavior,
1637 });
1672 .stderr = options.stderr_behavior,
1673 .cwd = options.cwd,
1674 .environ_map = &graph.environ_map,
1675 .expand_arg0 = options.expand_arg0,
1676 }) catch |err| return .{ .spawn_failed = err };
16381677
16391678 var stdout_reader = child.stdout.?.readerStreaming(io, &.{});
1640 const stdout = stdout_reader.interface.allocRemaining(arena, .limited(max_output_size)) catch {
1641 return error.ReadFailure;
1679 const stdout = stdout_reader.interface.allocRemaining(arena, options.stdout_limit) catch |err| switch (err) {
1680 error.ReadFailed => panic("failed to read from child: {t}", .{stdout_reader.err.?}),
1681 else => |e| panic("failed to read from child: {t}", .{e}),
16421682 };
1643 errdefer arena.free(stdout);
1644
1645 const term = try child.wait(io);
1646 switch (term) {
1647 .exited => |code| {
1648 if (code != 0) {
1649 out_code.* = @as(u8, @truncate(code));
1650 return error.ExitCodeFailure;
1651 }
1652 return stdout;
1653 },
1654 .signal, .stopped => |sig| {
1655 out_code.* = @as(u8, @truncate(@intFromEnum(sig)));
1656 return error.ProcessTerminated;
1657 },
1658 .unknown => |code| {
1659 out_code.* = @as(u8, @truncate(code));
1660 return error.ProcessTerminated;
1683
1684 const term = child.wait(io) catch @panic("unexpected");
1685
1686 return switch (term) {
1687 .exited => |code| switch (code) {
1688 0 => .{ .success = stdout },
1689 else => .{ .bad_exit_code = code },
16611690 },
1662 }
1691 .signal, .stopped, .unknown => .crashed,
1692 };
16631693}
16641694
1665/// This is a helper function to be called from build.zig scripts, *not* from
1666/// inside step make() functions. If any errors occur, it fails the build with
1667/// a helpful message.
1695/// Executes the provided command immediately.
1696///
1697/// If the program exits successfully, stdout is returned. Otherwise, fails the
1698/// build with a helpful message.
1699///
1700/// See also:
1701/// * `runFallible`.
16681702pub fn run(b: *Build, argv: []const []const u8) []u8 {
1669 var code: u8 = undefined;
1670 return b.runAllowFail(argv, &code, .inherit) catch |err| process.fatal(
1671 "the following command failed with {t}:\n{s}",
1672 .{ err, Step.allocPrintCmd(b.allocator, .inherit, null, argv) catch @panic("OOM") },
1673 );
1703 const graph = b.graph;
1704 const arena = graph.arena;
1705 switch (b.runFallible(argv, .{
1706 .stderr_behavior = .inherit,
1707 })) {
1708 .success => |stdout| return stdout,
1709 .spawn_failed => |err| process.fatal("the following command failed with {t}:\n{s}", .{
1710 err, std.zig.allocPrintCmd(arena, argv, .{}) catch @panic("OOM"),
1711 }),
1712 .bad_exit_code => |code| process.fatal("the following command exited with code {d}:\n{s}", .{
1713 code, std.zig.allocPrintCmd(arena, argv, .{}) catch @panic("OOM"),
1714 }),
1715 .crashed => process.fatal("the following command crashed:\n{s}", .{
1716 std.zig.allocPrintCmd(arena, argv, .{}) catch @panic("OOM"),
1717 }),
1718 }
1719}
1720
1721/// Adds additional paths, equivalent to the `--search-prefix` arguments
1722/// provided by the user. Paths added with this function have lower precedence
1723/// than the ones specified by the user on the command line.
1724///
1725/// It is generally best practice to avoid calling this function, instead
1726/// relying on the user to provide these paths via the standard build system
1727/// interface. However, when integrating with other build systems, the user may
1728/// have already provided the information to the other build system, and thus
1729/// it is desirable to use that same information without requiring the user to
1730/// provide it again.
1731pub fn addSearchPrefix(b: *Build, search_prefix: []const u8) void {
1732 _ = b;
1733 _ = search_prefix;
1734 @panic("TODO");
1735 //b.search_prefixes.append(b.allocator, b.dupePath(search_prefix)) catch @panic("OOM");
16741736}
16751737
16761738pub const Dependency = struct {
......@@ -1727,8 +1789,8 @@ fn findPkgHashOrFatal(b: *Build, name: []const u8) []const u8 {
17271789 if (mem.eql(u8, dep[0], name)) return dep[1];
17281790 }
17291791 std.log.info("all dependencies used by build.zig must be declared in corresponding build.zig.zon", .{});
1730 if (b.pkg_hash.len == 0) std.debug.panic("no dependency named {s}", .{name});
1731 std.debug.panic("no dependency named {s} in {s} ({s})", .{ name, b.dep_prefix, b.pkg_hash });
1792 if (b.pkg_hash.len == 0) panic("no dependency named {s}", .{name});
1793 panic("no dependency named {s} in {s} ({s})", .{ name, b.dep_prefix, b.pkg_hash });
17321794}
17331795
17341796inline fn findImportPkgHashOrFatal(b: *Build, comptime asking_build_zig: type, comptime dep_name: []const u8) []const u8 {
......@@ -1741,7 +1803,7 @@ inline fn findImportPkgHashOrFatal(b: *Build, comptime asking_build_zig: type, c
17411803 if (@hasDecl(pkg, "build_zig") and pkg.build_zig == asking_build_zig) break .{ pkg_hash, pkg.deps };
17421804 } else .{ "", deps.root_deps };
17431805 if (!std.mem.eql(u8, b_pkg_hash, b.pkg_hash)) {
1744 std.debug.panic("'{}' is not the struct that corresponds to '{s}'", .{
1806 panic("'{}' is not the struct that corresponds to '{s}'", .{
17451807 asking_build_zig, b.pathFromRoot("build.zig"),
17461808 });
17471809 }
......@@ -1750,7 +1812,7 @@ inline fn findImportPkgHashOrFatal(b: *Build, comptime asking_build_zig: type, c
17501812 };
17511813
17521814 const full_path = b.pathFromRoot("build.zig.zon");
1753 std.debug.panic("no dependency named '{s}' in '{s}'. All packages used in build.zig must be declared in this file", .{ dep_name, full_path });
1815 panic("no dependency named '{s}' in '{s}'. All packages used in build.zig must be declared in this file", .{ dep_name, full_path });
17541816}
17551817
17561818fn markNeededLazyDep(b: *Build, pkg_hash: []const u8) void {
......@@ -1799,7 +1861,7 @@ pub fn dependency(b: *Build, name: []const u8, args: anytype) *Dependency {
17991861 if (mem.eql(u8, decl.name, pkg_hash)) {
18001862 const pkg = @field(deps.packages, decl.name);
18011863 if (@hasDecl(pkg, "available")) {
1802 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 });
1864 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 });
18031865 }
18041866 return dependencyInner(b, name, pkg.build_root, if (@hasDecl(pkg, "build_zig")) pkg.build_zig else null, pkg_hash, pkg.deps, args);
18051867 }
......@@ -1866,7 +1928,7 @@ pub fn dependencyFromBuildZig(
18661928 }
18671929
18681930 const full_path = b.pathFromRoot("build.zig.zon");
1869 std.debug.panic("'{}' is not a build.zig struct of a dependency in '{s}'", .{ build_zig, full_path });
1931 panic("'{}' is not a build.zig struct of a dependency in '{s}'", .{ build_zig, full_path });
18701932}
18711933
18721934fn userValuesAreSame(lhs: UserValue, rhs: UserValue) bool {
......@@ -1960,14 +2022,23 @@ fn dependencyInner(
19602022 pkg_deps: AvailableDeps,
19612023 args: anytype,
19622024) *Dependency {
1963 const user_input_options = userInputOptionsFromArgs(b.allocator, args);
2025 const io = b.graph.io;
2026 const arena = b.graph.arena;
2027 const user_input_options = userInputOptionsFromArgs(arena, args);
19642028 if (b.graph.dependency_cache.getContext(.{
19652029 .build_root_string = build_root_string,
19662030 .user_input_options = user_input_options,
1967 }, .{ .allocator = b.graph.arena })) |dep|
1968 return dep;
2031 }, .{ .allocator = arena })) |dep| return dep;
2032
2033 const dep_root: Cache.Path = .{
2034 .root_dir = .{
2035 .path = build_root_string,
2036 .handle = Io.Dir.cwd().openDir(io, build_root_string, .{}) catch |err|
2037 process.fatal("unable to open {s}: {t}", .{ build_root_string, err }),
2038 },
2039 };
19692040
1970 const sub_builder = b.createChild(name, pkg_hash, pkg_deps, user_input_options) catch
2041 const sub_builder = b.createChild(name, dep_root, pkg_hash, pkg_deps, user_input_options) catch
19712042 @panic("unhandled error");
19722043 if (build_zig) |bz| {
19732044 sub_builder.runBuild(bz) catch @panic("unhandled error");
......@@ -1977,13 +2048,13 @@ fn dependencyInner(
19772048 }
19782049 }
19792050
1980 const dep = b.allocator.create(Dependency) catch @panic("OOM");
2051 const dep = arena.create(Dependency) catch @panic("OOM");
19812052 dep.* = .{ .builder = sub_builder };
19822053
19832054 b.graph.dependency_cache.putContext(b.graph.arena, .{
19842055 .build_root_string = build_root_string,
19852056 .user_input_options = user_input_options,
1986 }, dep, .{ .allocator = b.graph.arena }) catch @panic("OOM");
2057 }, dep, .{ .allocator = arena }) catch @panic("OOM");
19872058 return dep;
19882059}
19892060
......@@ -2046,14 +2117,7 @@ pub const LazyPath = union(enum) {
20462117 sub_path: []const u8 = "",
20472118 },
20482119
2049 /// An absolute path or a path relative to the current working directory of
2050 /// the build runner process.
2051 ///
2052 /// This is uncommon but used for system environment paths such as `--zig-lib-dir` which
2053 /// ignore the file system path of build.zig and instead are relative to the directory from
2054 /// which `zig build` was invoked.
2055 ///
2056 /// Use of this tag indicates a dependency on the host system.
2120 /// Deprecated; call `Graph.cwdRelativePath` instead.
20572121 cwd_relative: []const u8,
20582122
20592123 dependency: struct {
......@@ -2061,6 +2125,19 @@ pub const LazyPath = union(enum) {
20612125 sub_path: []const u8,
20622126 },
20632127
2128 relative: struct {
2129 base: Configuration.Path.Base,
2130 sub_path: Configuration.String = .empty,
2131 },
2132
2133 /// Path to the Zig executable being used to execute "zig build".
2134 pub const zig_exe: LazyPath = .{ .relative = .{ .base = .zig_exe } };
2135 /// Path to the "lib/" directory from the Zig installation being used to
2136 /// execute "zig build".
2137 pub const zig_lib: LazyPath = .{ .relative = .{ .base = .zig_lib } };
2138 /// Path to the project's local cache directory (usually called ".zig-cache").
2139 pub const cache_root: LazyPath = .{ .relative = .{ .base = .local_cache } };
2140
20642141 /// Returns a lazy path referring to the directory containing this path.
20652142 ///
20662143 /// The dirname is not allowed to escape the logical root for underlying path.
......@@ -2147,21 +2224,33 @@ pub const LazyPath = union(enum) {
21472224 };
21482225 }
21492226
2150 /// Returns a string that can be shown to represent the file source.
2151 /// Either returns the path, `"generated"`, or `"dependency"`.
2152 pub fn getDisplayName(lazy_path: LazyPath) []const u8 {
2153 return switch (lazy_path) {
2154 .src_path => |sp| sp.sub_path,
2155 .cwd_relative => |p| p,
2156 .generated => "generated",
2157 .dependency => "dependency",
2158 };
2227 pub const Format = struct {
2228 graph: *const Graph,
2229 lazy_path: *const LazyPath,
2230
2231 pub fn format(f: Format, w: *Io.Writer) Io.Writer.Error!void {
2232 switch (f.lazy_path.*) {
2233 .src_path => |sp| try w.writeAll(sp.sub_path),
2234 .cwd_relative => |p| try w.writeAll(p),
2235 .generated => try w.writeAll("generated"),
2236 .dependency => try w.writeAll("dependency"),
2237 .relative => |r| {
2238 const wc = &f.graph.wip_configuration;
2239 try w.writeAll(@tagName(r.base));
2240 try w.writeAll(wc.stringSlice(r.sub_path));
2241 },
2242 }
2243 }
2244 };
2245
2246 pub fn fmt(lp: *const LazyPath, graph: *const Graph) Format {
2247 return .{ .graph = graph, .lazy_path = lp };
21592248 }
21602249
21612250 /// Adds dependencies this file source implies to the given step.
21622251 pub fn addStepDependencies(lazy_path: LazyPath, other_step: *Step) void {
21632252 switch (lazy_path) {
2164 .src_path, .cwd_relative, .dependency => {},
2253 .src_path, .cwd_relative, .relative, .dependency => {},
21652254 .generated => |gen| {
21662255 const graph = other_step.owner.graph;
21672256 const generated_owner_step = graph.generated_files.items[@intFromEnum(gen.index)];
......@@ -2190,6 +2279,7 @@ pub const LazyPath = union(enum) {
21902279 return switch (lazy_path) {
21912280 .src_path => |sp| .{ .src_path = .{ .owner = sp.owner, .sub_path = sp.owner.dupePath(sp.sub_path) } },
21922281 .cwd_relative => |p| .{ .cwd_relative = graph.dupePath(p) },
2282 .relative => |r| .{ .relative = r },
21932283 .generated => |gen| .{ .generated = .{
21942284 .index = gen.index,
21952285 .up = gen.up,
lib/std/Build/Configuration.zig+21
......@@ -402,6 +402,12 @@ pub const Wip = struct {
402402 defer wip.next_generated_file_index += 1;
403403 return @enumFromInt(wip.next_generated_file_index);
404404 }
405
406 /// Returned slice expires upon next append to the configuration.
407 pub fn stringSlice(wip: *const Wip, s: String) [:0]const u8 {
408 const start_slice = wip.string_bytes.items[@intFromEnum(s)..];
409 return start_slice[0..std.mem.indexOfScalar(u8, start_slice, 0).? :0];
410 }
405411};
406412
407413pub const SystemIntegration = extern struct {
......@@ -445,6 +451,7 @@ pub const Step = extern struct {
445451 compile: Compile,
446452 config_header: ConfigHeader,
447453 fail: Fail,
454 find_program: FindProgram,
448455 fmt: Fmt,
449456 install_artifact: InstallArtifact,
450457 install_dir: InstallDir,
......@@ -479,6 +486,7 @@ pub const Step = extern struct {
479486 compile,
480487 config_header,
481488 fail,
489 find_program,
482490 fmt,
483491 install_artifact,
484492 install_dir,
......@@ -1037,6 +1045,17 @@ pub const Step = extern struct {
10371045 };
10381046 };
10391047
1048 pub const FindProgram = struct {
1049 flags: @This().Flags,
1050 names: StringList,
1051 generated_file: GeneratedFileIndex,
1052
1053 pub const Flags = packed struct(u32) {
1054 tag: Tag = .find_program,
1055 _: u27 = 0,
1056 };
1057 };
1058
10401059 pub const InstallDir = struct {
10411060 flags: @This().Flags,
10421061 source_dir: LazyPath.Index,
......@@ -1516,6 +1535,8 @@ pub const Path = extern struct {
15161535 local_cache,
15171536 global_cache,
15181537 build_root,
1538 zig_exe,
1539 zig_lib,
15191540 };
15201541
15211542 pub fn toCachePath(path: Path, c: *const Configuration, arena: Allocator) std.Build.Cache.Path {
lib/std/Build/Module.zig+79-57
......@@ -118,10 +118,10 @@ pub const CSourceFile = struct {
118118 /// By default, determines language of each file individually based on its file extension
119119 language: ?CSourceLanguage = null,
120120
121 pub fn dupe(file: CSourceFile, b: *std.Build) CSourceFile {
121 pub fn dupe(file: CSourceFile, graph: *const std.Build.Graph) CSourceFile {
122122 return .{
123 .file = file.file.dupe(b),
124 .flags = b.dupeStrings(file.flags),
123 .file = file.file.dupe(graph),
124 .flags = graph.dupeStrings(file.flags),
125125 .language = file.language,
126126 };
127127 }
......@@ -146,10 +146,12 @@ pub const RcSourceFile = struct {
146146 include_paths: []const LazyPath = &.{},
147147
148148 pub fn dupe(file: RcSourceFile, b: *std.Build) RcSourceFile {
149 const include_paths = b.allocator.alloc(LazyPath, file.include_paths.len) catch @panic("OOM");
150 for (include_paths, file.include_paths) |*dest, lazy_path| dest.* = lazy_path.dupe(b);
149 const graph = b.owner.graph;
150 const arena = graph.arena;
151 const include_paths = arena.alloc(LazyPath, file.include_paths.len) catch @panic("OOM");
152 for (include_paths, file.include_paths) |*dest, lazy_path| dest.* = lazy_path.dupe(graph);
151153 return .{
152 .file = file.file.dupe(b),
154 .file = file.file.dupe(graph),
153155 .flags = b.dupeStrings(file.flags),
154156 .include_paths = include_paths,
155157 };
......@@ -290,15 +292,18 @@ pub fn init(
290292}
291293
292294pub fn create(owner: *std.Build, options: CreateOptions) *Module {
293 const m = owner.allocator.create(Module) catch @panic("OOM");
295 const graph = owner.graph;
296 const arena = graph.arena;
297 const m = arena.create(Module) catch @panic("OOM");
294298 m.init(owner, .{ .options = options });
295299 return m;
296300}
297301
298302/// Adds an existing module to be used with `@import`.
299303pub fn addImport(m: *Module, name: []const u8, module: *Module) void {
300 const b = m.owner;
301 m.import_table.put(b.allocator, b.dupe(name), module) catch @panic("OOM");
304 const graph = m.owner.graph;
305 const arena = graph.arena;
306 m.import_table.put(arena, graph.dupeString(name), module) catch @panic("OOM");
302307}
303308
304309/// Creates a new module and adds it to be used with `@import`.
......@@ -338,7 +343,8 @@ pub fn linkSystemLibrary(
338343 name: []const u8,
339344 options: LinkSystemLibraryOptions,
340345) void {
341 const b = m.owner;
346 const graph = m.owner.graph;
347 const arena = graph.arena;
342348
343349 const target = m.requireKnownTarget();
344350 if (std.zig.target.isLibCLibName(target, name)) {
......@@ -350,9 +356,9 @@ pub fn linkSystemLibrary(
350356 return;
351357 }
352358
353 m.link_objects.append(b.allocator, .{
359 m.link_objects.append(arena, .{
354360 .system_lib = .{
355 .name = b.dupe(name),
361 .name = graph.dupeString(name),
356362 .needed = options.needed,
357363 .weak = options.weak,
358364 .use_pkg_config = options.use_pkg_config,
......@@ -363,8 +369,9 @@ pub fn linkSystemLibrary(
363369}
364370
365371pub fn linkFramework(m: *Module, name: []const u8, options: LinkFrameworkOptions) void {
366 const b = m.owner;
367 m.frameworks.put(b.allocator, b.dupe(name), options) catch @panic("OOM");
372 const graph = m.owner.graph;
373 const arena = graph.arena;
374 m.frameworks.put(arena, graph.dupeString(name), options) catch @panic("OOM");
368375}
369376
370377pub const AddCSourceFilesOptions = struct {
......@@ -380,7 +387,8 @@ pub const AddCSourceFilesOptions = struct {
380387/// Handy when you have many non-Zig source files and want them all to have the same flags.
381388pub fn addCSourceFiles(m: *Module, options: AddCSourceFilesOptions) void {
382389 const b = m.owner;
383 const allocator = b.allocator;
390 const graph = m.owner.graph;
391 const arena = graph.arena;
384392
385393 for (options.files) |path| {
386394 if (std.fs.path.isAbsolute(path)) {
......@@ -391,48 +399,50 @@ pub fn addCSourceFiles(m: *Module, options: AddCSourceFilesOptions) void {
391399 }
392400 }
393401
394 const c_source_files = allocator.create(CSourceFiles) catch @panic("OOM");
402 const c_source_files = arena.create(CSourceFiles) catch @panic("OOM");
395403 c_source_files.* = .{
396404 .root = options.root orelse b.path(""),
397405 .files = b.dupeStrings(options.files),
398406 .flags = b.dupeStrings(options.flags),
399407 .language = options.language,
400408 };
401 m.link_objects.append(allocator, .{ .c_source_files = c_source_files }) catch @panic("OOM");
409 m.link_objects.append(arena, .{ .c_source_files = c_source_files }) catch @panic("OOM");
402410}
403411
404412pub fn addCSourceFile(m: *Module, source: CSourceFile) void {
405 const b = m.owner;
406 const allocator = b.allocator;
407 const c_source_file = allocator.create(CSourceFile) catch @panic("OOM");
408 c_source_file.* = source.dupe(b);
409 m.link_objects.append(allocator, .{ .c_source_file = c_source_file }) catch @panic("OOM");
413 const graph = m.owner.graph;
414 const arena = graph.arena;
415 const c_source_file = arena.create(CSourceFile) catch @panic("OOM");
416 c_source_file.* = source.dupe(graph);
417 m.link_objects.append(arena, .{ .c_source_file = c_source_file }) catch @panic("OOM");
410418}
411419
412420/// Resource files must have the extension `.rc`.
413421/// Can be called regardless of target. The .rc file will be ignored
414422/// if the target object format does not support embedded resources.
415423pub fn addWin32ResourceFile(m: *Module, source: RcSourceFile) void {
416 const b = m.owner;
417 const allocator = b.allocator;
424 const graph = m.owner.graph;
425 const arena = graph.arena;
418426 const target = m.requireKnownTarget();
419427 // Only the PE/COFF format has a Resource Table, so for any other target
420428 // the resource file is ignored.
421429 if (target.ofmt != .coff) return;
422430
423 const rc_source_file = allocator.create(RcSourceFile) catch @panic("OOM");
424 rc_source_file.* = source.dupe(b);
425 m.link_objects.append(allocator, .{ .win32_resource_file = rc_source_file }) catch @panic("OOM");
431 const rc_source_file = arena.create(RcSourceFile) catch @panic("OOM");
432 rc_source_file.* = source.dupe(graph);
433 m.link_objects.append(arena, .{ .win32_resource_file = rc_source_file }) catch @panic("OOM");
426434}
427435
428436pub fn addAssemblyFile(m: *Module, source: LazyPath) void {
429 const b = m.owner;
430 m.link_objects.append(b.allocator, .{ .assembly_file = source.dupe(b) }) catch @panic("OOM");
437 const graph = m.owner.graph;
438 const arena = graph.arena;
439 m.link_objects.append(arena, .{ .assembly_file = source.dupe(graph) }) catch @panic("OOM");
431440}
432441
433442pub fn addObjectFile(m: *Module, object: LazyPath) void {
434 const b = m.owner;
435 m.link_objects.append(b.allocator, .{ .static_path = object.dupe(b) }) catch @panic("OOM");
443 const graph = m.owner.graph;
444 const arena = graph.arena;
445 m.link_objects.append(arena, .{ .static_path = object.dupe(graph) }) catch @panic("OOM");
436446}
437447
438448pub fn addObject(m: *Module, object: *Step.Compile) void {
......@@ -446,55 +456,63 @@ pub fn linkLibrary(m: *Module, library: *Step.Compile) void {
446456}
447457
448458pub fn addAfterIncludePath(m: *Module, lazy_path: LazyPath) void {
449 const b = m.owner;
450 m.include_dirs.append(b.allocator, .{ .path_after = lazy_path.dupe(b) }) catch @panic("OOM");
459 const graph = m.owner.graph;
460 const arena = graph.arena;
461 m.include_dirs.append(arena, .{ .path_after = lazy_path.dupe(graph) }) catch @panic("OOM");
451462}
452463
453464pub fn addSystemIncludePath(m: *Module, lazy_path: LazyPath) void {
454 const b = m.owner;
455 m.include_dirs.append(b.allocator, .{ .path_system = lazy_path.dupe(b) }) catch @panic("OOM");
465 const graph = m.owner.graph;
466 const arena = graph.arena;
467 m.include_dirs.append(arena, .{ .path_system = lazy_path.dupe(graph) }) catch @panic("OOM");
456468}
457469
458470pub fn addIncludePath(m: *Module, lazy_path: LazyPath) void {
459 const b = m.owner;
460 m.include_dirs.append(b.allocator, .{ .path = lazy_path.dupe(b) }) catch @panic("OOM");
471 const graph = m.owner.graph;
472 const arena = graph.arena;
473 m.include_dirs.append(arena, .{ .path = lazy_path.dupe(graph) }) catch @panic("OOM");
461474}
462475
463476pub fn addConfigHeader(m: *Module, config_header: *Step.ConfigHeader) void {
464 const allocator = m.owner.allocator;
465 m.include_dirs.append(allocator, .{ .config_header_step = config_header }) catch @panic("OOM");
477 const graph = m.owner.graph;
478 const arena = graph.arena;
479 m.include_dirs.append(arena, .{ .config_header_step = config_header }) catch @panic("OOM");
466480}
467481
468482pub fn addSystemFrameworkPath(m: *Module, directory_path: LazyPath) void {
469 const b = m.owner;
470 m.include_dirs.append(b.allocator, .{ .framework_path_system = directory_path.dupe(b) }) catch
471 @panic("OOM");
483 const graph = m.owner.graph;
484 const arena = graph.arena;
485 m.include_dirs.append(arena, .{ .framework_path_system = directory_path.dupe(graph) }) catch @panic("OOM");
472486}
473487
474488pub fn addFrameworkPath(m: *Module, directory_path: LazyPath) void {
475 const b = m.owner;
476 m.include_dirs.append(b.allocator, .{ .framework_path = directory_path.dupe(b) }) catch
477 @panic("OOM");
489 const graph = m.owner.graph;
490 const arena = graph.arena;
491 m.include_dirs.append(arena, .{ .framework_path = directory_path.dupe(graph) }) catch @panic("OOM");
478492}
479493
480494pub fn addEmbedPath(m: *Module, lazy_path: LazyPath) void {
481 const b = m.owner;
482 m.include_dirs.append(b.allocator, .{ .embed_path = lazy_path.dupe(b) }) catch @panic("OOM");
495 const graph = m.owner.graph;
496 const arena = graph.arena;
497 m.include_dirs.append(arena, .{ .embed_path = lazy_path.dupe(graph) }) catch @panic("OOM");
483498}
484499
485500pub fn addLibraryPath(m: *Module, directory_path: LazyPath) void {
486 const b = m.owner;
487 m.lib_paths.append(b.allocator, directory_path.dupe(b)) catch @panic("OOM");
501 const graph = m.owner.graph;
502 const arena = graph.arena;
503 m.lib_paths.append(arena, directory_path.dupe(graph)) catch @panic("OOM");
488504}
489505
490506pub fn addRPath(m: *Module, directory_path: LazyPath) void {
491 const b = m.owner;
492 m.rpaths.append(b.allocator, .{ .lazy_path = directory_path.dupe(b) }) catch @panic("OOM");
507 const graph = m.owner.graph;
508 const arena = graph.arena;
509 m.rpaths.append(arena, .{ .lazy_path = directory_path.dupe(graph) }) catch @panic("OOM");
493510}
494511
495512pub fn addRPathSpecial(m: *Module, bytes: []const u8) void {
496 const b = m.owner;
497 m.rpaths.append(b.allocator, .{ .special = b.dupe(bytes) }) catch @panic("OOM");
513 const graph = m.owner.graph;
514 const arena = graph.arena;
515 m.rpaths.append(arena, .{ .special = graph.dupeString(bytes) }) catch @panic("OOM");
498516}
499517
500518/// Equvialent to the following C code, applied to all C source files owned by
......@@ -505,19 +523,23 @@ pub fn addRPathSpecial(m: *Module, bytes: []const u8) void {
505523/// `name` and `value` need not live longer than the function call.
506524pub fn addCMacro(m: *Module, name: []const u8, value: []const u8) void {
507525 const b = m.owner;
508 m.c_macros.append(b.allocator, b.fmt("-D{s}={s}", .{ name, value })) catch @panic("OOM");
526 const graph = m.owner.graph;
527 const arena = graph.arena;
528 m.c_macros.append(arena, b.fmt("-D{s}={s}", .{ name, value })) catch @panic("OOM");
509529}
510530
511531fn linkLibraryOrObject(m: *Module, other: *Step.Compile) void {
512 const allocator = m.owner.allocator;
532 const graph = m.owner.graph;
533 const arena = graph.arena;
534
513535 _ = other.getEmittedBin(); // Indicate there is a dependency on the outputted binary.
514536
515537 if (other.rootModuleTarget().os.tag == .windows and other.isDynamicLibrary()) {
516538 _ = other.getEmittedImplib(); // Indicate dependency on the outputted implib.
517539 }
518540
519 m.link_objects.append(allocator, .{ .other_step = other }) catch @panic("OOM");
520 m.include_dirs.append(allocator, .{ .other_step = other }) catch @panic("OOM");
541 m.link_objects.append(arena, .{ .other_step = other }) catch @panic("OOM");
542 m.include_dirs.append(arena, .{ .other_step = other }) catch @panic("OOM");
521543}
522544
523545fn requireKnownTarget(m: *Module) *const std.Target {
lib/std/Build/Step/ConfigHeader.zig+1-1
......@@ -83,7 +83,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader {
8383 }
8484
8585 const name = if (options.style.getPath()) |s|
86 owner.fmt("configure {t} header {s} to {s}", .{ options.style, s.getDisplayName(), include_path })
86 owner.fmt("configure {t} header {f} to {s}", .{ options.style, s.fmt(graph), include_path })
8787 else
8888 owner.fmt("configure {t} header to {s}", .{ options.style, include_path });
8989
lib/std/Build/Step/InstallDir.zig+1-1
......@@ -47,7 +47,7 @@ pub fn create(owner: *std.Build, options: Options) *InstallDir {
4747 install_dir.* = .{
4848 .step = Step.init(.{
4949 .tag = base_tag,
50 .name = owner.fmt("install {s}/", .{options.source_dir.getDisplayName()}),
50 .name = owner.fmt("install {f}/", .{options.source_dir.fmt(graph)}),
5151 .owner = owner,
5252 }),
5353 .options = options.dupe(graph),
lib/std/Build/Step/InstallFile.zig+1-1
......@@ -26,7 +26,7 @@ pub fn create(
2626 install_file.* = .{
2727 .step = Step.init(.{
2828 .tag = base_tag,
29 .name = owner.fmt("install {s} to {s}", .{ source.getDisplayName(), dest_rel_path }),
29 .name = owner.fmt("install {f} to {s}", .{ source.fmt(graph), dest_rel_path }),
3030 .owner = owner,
3131 }),
3232 .source = source.dupe(graph),
lib/std/Build/Step/ObjCopy.zig+2-2
......@@ -116,12 +116,12 @@ pub fn create(
116116 objcopy.* = ObjCopy{
117117 .step = Step.init(.{
118118 .tag = base_tag,
119 .name = owner.fmt("objcopy {s}", .{input_file.getDisplayName()}),
119 .name = owner.fmt("objcopy {f}", .{input_file.fmt(graph)}),
120120 .owner = owner,
121121 .makeFn = make,
122122 }),
123123 .input_file = input_file,
124 .basename = options.basename orelse input_file.getDisplayName(),
124 .basename = options.basename orelse std.fmt.allocPrint("{f}", .{input_file.fmt(graph)}) catch @panic("OOM"),
125125 .output_file = graph.addGeneratedFile(&objcopy.step),
126126 .output_file_debug = if (options.strip != .none and options.extract_to_separate_file)
127127 .init(graph.addGeneratedFile(&objcopy.step))
lib/std/zig.zig+14-17
......@@ -1165,15 +1165,13 @@ pub const ClangCliParam = struct {
11651165 }
11661166};
11671167
1168pub fn allocPrintCmd(
1169 gpa: Allocator,
1170 cwd: std.process.Child.Cwd,
1171 opt_env: ?struct {
1172 child: *const std.process.Environ.Map,
1173 parent: *const std.process.Environ.Map,
1174 },
1175 argv: []const []const u8,
1176) Allocator.Error![]u8 {
1168pub const AllocPrintCmdOptions = struct {
1169 cwd: std.process.Child.Cwd = .inherit,
1170 parent_env: ?*const std.process.Environ.Map = null,
1171 child_env: ?*const std.process.Environ.Map = null,
1172};
1173
1174pub fn allocPrintCmd(gpa: Allocator, argv: []const []const u8, options: AllocPrintCmdOptions) Allocator.Error![]u8 {
11771175 const shell = struct {
11781176 fn escape(writer: *Io.Writer, string: []const u8, is_argv0: bool) !void {
11791177 for (string) |c| {
......@@ -1212,18 +1210,17 @@ pub fn allocPrintCmd(
12121210 var aw: Io.Writer.Allocating = .init(gpa);
12131211 defer aw.deinit();
12141212 const writer = &aw.writer;
1215 switch (cwd) {
1213 switch (options.cwd) {
12161214 .inherit => {},
12171215 .path => |path| writer.print("cd {s} && ", .{path}) catch return error.OutOfMemory,
12181216 .dir => @panic("TODO"),
12191217 }
1220 if (opt_env) |env| {
1221 var it = env.child.iterator();
1222 while (it.next()) |entry| {
1223 const key = entry.key_ptr.*;
1224 const value = entry.value_ptr.*;
1225 if (env.parent.get(key)) |process_value| {
1226 if (std.mem.eql(u8, value, process_value)) continue;
1218 if (options.child_env) |child_env| {
1219 for (child_env.keys(), child_env.values()) |key, value| {
1220 if (options.parent_env) |parent_env| {
1221 if (parent_env.get(key)) |process_value| {
1222 if (std.mem.eql(u8, value, process_value)) continue;
1223 }
12271224 }
12281225 writer.print("{s}=", .{key}) catch return error.OutOfMemory;
12291226 shell.escape(writer, value, false) catch return error.OutOfMemory;
src/main.zig+11-2
......@@ -4987,7 +4987,7 @@ fn cmdBuild(
49874987 const argv_index_zig_lib_dir = make_argv.items.len - 1;
49884988
49894989 make_argv.addManyAsArrayAssumeCapacity(2).* = .{ "--build-root", undefined };
4990 const argv_index_build_file = make_argv.items.len - 1;
4990 const make_argv_index_build_root = make_argv.items.len - 1;
49914991
49924992 make_argv.addManyAsArrayAssumeCapacity(2).* = .{ "--local-cache", undefined };
49934993 const argv_index_cache_dir = make_argv.items.len - 1;
......@@ -5001,6 +5001,9 @@ fn cmdBuild(
50015001 make_argv.addManyAsArrayAssumeCapacity(2).* = .{ "--seed", default_seed };
50025002 const argv_index_seed = make_argv.items.len - 1;
50035003
5004 configure_argv.addManyAsArrayAssumeCapacity(2).* = .{ "--build-root", undefined };
5005 const conf_argv_index_build_root = configure_argv.items.len - 1;
5006
50045007 var color: Color = .auto;
50055008 var n_jobs: ?u32 = null;
50065009
......@@ -5065,6 +5068,10 @@ fn cmdBuild(
50655068 i += 1;
50665069 override_global_cache_dir = args[i];
50675070 continue;
5071 } else if (mem.eql(u8, arg, "--verbose")) {
5072 // Intentionally is added both to make and configure but
5073 // does not go into the cache hash.
5074 configure_argv.appendAssumeCapacity(arg);
50685075 } else if (mem.eql(u8, arg, "-freference-trace")) {
50695076 reference_trace = 256;
50705077 } else if (mem.eql(u8, arg, "--fetch")) {
......@@ -5283,10 +5290,12 @@ fn cmdBuild(
52835290 defer _ = make_runner_task.cancel(io) catch {};
52845291
52855292 make_argv.items[argv_index_zig_lib_dir] = dirs.zig_lib.path orelse cwd_path;
5286 make_argv.items[argv_index_build_file] = build_root.directory.path orelse cwd_path;
5293 make_argv.items[make_argv_index_build_root] = build_root.directory.path orelse cwd_path;
52875294 make_argv.items[argv_index_global_cache_dir] = dirs.global_cache.path orelse cwd_path;
52885295 make_argv.items[argv_index_cache_dir] = dirs.local_cache.path orelse cwd_path;
52895296
5297 configure_argv.items[conf_argv_index_build_root] = build_root.directory.path orelse cwd_path;
5298
52905299 // Dummy http client that is not actually used when fetch_command is unsupported.
52915300 // Prevents bootstrap from depending on a bunch of unnecessary stuff.
52925301 var http_client: if (dev.env.supports(.fetch_command)) std.http.Client else struct {