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 @@...@@ -17,6 +17,7 @@
1717
18* implement {q} or delete {q} uses18* implement {q} or delete {q} uses
19* make the generated dependencies.zig be dependencies.zon and don't put absolute paths in there19* make the generated dependencies.zig be dependencies.zon and don't put absolute paths in there
20 - and adjust dependencyInner to not openDir()
2021
21## Followup Issues22## Followup Issues
22* reduce the size of Maker.Step.Extended (make Run smaller) probably by using an arena per make23* 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 };...@@ -16,6 +16,8 @@ const IoMode = enum { threaded, evented };
16const ValueInterpretMode = enum { direct, by_name };16const ValueInterpretMode = enum { direct, by_name };
1717
18pub fn build(b: *std.Build) !void {18pub fn build(b: *std.Build) !void {
19 const arena = b.graph.arena;
20
19 const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse false;21 const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse false;
20 const target = b.standardTargetOptions(.{22 const target = b.standardTargetOptions(.{
21 .default_target = .{23 .default_target = .{
...@@ -35,7 +37,7 @@ pub fn build(b: *std.Build) !void {...@@ -35,7 +37,7 @@ pub fn build(b: *std.Build) !void {
35 const no_bin = b.option(bool, "no-bin", "skip emitting compiler binary") orelse false;37 const no_bin = b.option(bool, "no-bin", "skip emitting compiler binary") orelse false;
36 const enable_superhtml = b.option(bool, "enable-superhtml", "Check langref output HTML validity") orelse false;38 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);
39 const install_langref = b.addInstallFileWithDir(langref_file, .prefix, "doc/langref.html");41 const install_langref = b.addInstallFileWithDir(langref_file, .prefix, "doc/langref.html");
40 const check_langref = superHtmlCheck(b, langref_file);42 const check_langref = superHtmlCheck(b, langref_file);
41 if (enable_superhtml) install_langref.step.dependOn(check_langref);43 if (enable_superhtml) install_langref.step.dependOn(check_langref);
...@@ -262,7 +264,7 @@ pub fn build(b: *std.Build) !void {...@@ -262,7 +264,7 @@ pub fn build(b: *std.Build) !void {
262 var code: u8 = undefined;264 var code: u8 = undefined;
263 const git_describe_untrimmed = b.runAllowFail(&[_][]const u8{265 const git_describe_untrimmed = b.runAllowFail(&[_][]const u8{
264 "git",266 "git",
265 "-C", b.build_root.path orelse ".", // affects the --git-dir argument267 "-C", b.fmt("{f}", .{b.root}), // affects the --git-dir argument
266 "--git-dir", ".git", // affected by the -C argument268 "--git-dir", ".git", // affected by the -C argument
267 "describe", "--match", "*.*.*", //269 "describe", "--match", "*.*.*", //
268 "--tags", "--abbrev=9",270 "--tags", "--abbrev=9",
...@@ -308,7 +310,7 @@ pub fn build(b: *std.Build) !void {...@@ -308,7 +310,7 @@ pub fn build(b: *std.Build) !void {
308 },310 },
309 }311 }
310 };312 };
311 const version = try b.allocator.dupeSentinel(u8, version_slice, 0);313 const version = try arena.dupeSentinel(u8, version_slice, 0);
312 exe_options.addOption([:0]const u8, "version", version);314 exe_options.addOption([:0]const u8, "version", version);
313315
314 if (enable_llvm) {316 if (enable_llvm) {
...@@ -316,7 +318,7 @@ pub fn build(b: *std.Build) !void {...@@ -316,7 +318,7 @@ pub fn build(b: *std.Build) !void {
316 const io = b.graph.io;318 const io = b.graph.io;
317 const cwd: Io.Dir = .cwd();319 const cwd: Io.Dir = .cwd();
318 if (findConfigH(b, config_h_path_option)) |config_h_path| {320 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;
320 break :blk parseConfigH(b, file_contents);322 break :blk parseConfigH(b, file_contents);
321 } else {323 } else {
322 std.log.warn("config.h could not be located automatically. Consider providing it explicitly via \"-Dconfig_h\"", .{});324 std.log.warn("config.h could not be located automatically. Consider providing it explicitly via \"-Dconfig_h\"", .{});
...@@ -976,11 +978,12 @@ fn addCxxKnownPath(...@@ -976,11 +978,12 @@ fn addCxxKnownPath(
976 errtxt: ?[]const u8,978 errtxt: ?[]const u8,
977 need_cpp_includes: bool,979 need_cpp_includes: bool,
978) !void {980) !void {
979 if (!std.process.can_spawn)981 if (!std.process.can_spawn) return error.RequiredLibraryNotFound;
980 return error.RequiredLibraryNotFound;982
983 const arena = b.graph.arena;
981984
982 const path_padded = run: {985 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);
984 try args.append(ctx.cxx_compiler);987 try args.append(ctx.cxx_compiler);
985 var it = std.mem.tokenizeAny(u8, ctx.cxx_compiler_arg1, &std.ascii.whitespace);988 var it = std.mem.tokenizeAny(u8, ctx.cxx_compiler_arg1, &std.ascii.whitespace);
986 while (it.next()) |arg| try args.append(arg);989 while (it.next()) |arg| try args.append(arg);
...@@ -1049,6 +1052,7 @@ const CMakeConfig = struct {...@@ -1049,6 +1052,7 @@ const CMakeConfig = struct {
1049const max_config_h_bytes = 1 * 1024 * 1024;1052const max_config_h_bytes = 1 * 1024 * 1024;
10501053
1051fn findConfigH(b: *std.Build, config_h_path_option: ?[]const u8) ?[]const u8 {1054fn findConfigH(b: *std.Build, config_h_path_option: ?[]const u8) ?[]const u8 {
1055 const arena = b.graph.arena;
1052 const io = b.graph.io;1056 const io = b.graph.io;
1053 const cwd: Io.Dir = .cwd();1057 const cwd: Io.Dir = .cwd();
10541058
...@@ -1073,7 +1077,7 @@ fn findConfigH(b: *std.Build, config_h_path_option: ?[]const u8) ?[]const u8 {...@@ -1073,7 +1077,7 @@ fn findConfigH(b: *std.Build, config_h_path_option: ?[]const u8) ?[]const u8 {
1073 if (config_h_or_err) |*file| {1077 if (config_h_or_err) |*file| {
1074 file.close(io);1078 file.close(io);
1075 return fs.path.join(1079 return fs.path.join(
1076 b.allocator,1080 arena,
1077 &[_][]const u8{ check_dir, "config.h" },1081 &[_][]const u8{ check_dir, "config.h" },
1078 ) catch unreachable;1082 ) catch unreachable;
1079 } else |e| switch (e) {1083 } else |e| switch (e) {
...@@ -1198,7 +1202,8 @@ fn parseConfigH(b: *std.Build, config_h_text: []const u8) ?CMakeConfig {...@@ -1198,7 +1202,8 @@ fn parseConfigH(b: *std.Build, config_h_text: []const u8) ?CMakeConfig {
1198}1202}
11991203
1200fn toNativePathSep(b: *std.Build, s: []const u8) []u8 {1204fn 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;
1202 for (duplicated) |*byte| switch (byte.*) {1207 for (duplicated) |*byte| switch (byte.*) {
1203 '/' => byte.* = fs.path.sep,1208 '/' => byte.* = fs.path.sep,
1204 else => {},1209 else => {},
...@@ -1487,8 +1492,9 @@ const llvm_libs_xtensa = [_][]const u8{...@@ -1487,8 +1492,9 @@ const llvm_libs_xtensa = [_][]const u8{
1487 "LLVMXtensaInfo",1492 "LLVMXtensaInfo",
1488};1493};
14891494
1490fn generateLangRef(b: *std.Build) std.Build.LazyPath {1495fn generateLangRef(b: *std.Build) !std.Build.LazyPath {
1491 const io = b.graph.io;1496 const io = b.graph.io;
1497 const arena = b.graph.arena;
14921498
1493 const doctest_exe = b.addExecutable(.{1499 const doctest_exe = b.addExecutable(.{
1494 .name = "doctest",1500 .name = "doctest",
...@@ -1499,10 +1505,7 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath {...@@ -1499,10 +1505,7 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath {
1499 }),1505 }),
1500 });1506 });
15011507
1502 const langref_path: std.Build.Cache.Path = .{1508 const langref_path = try b.root.join(arena, "doc/langref");
1503 .root_dir = b.build_root,
1504 .sub_path = "doc/langref",
1505 };
15061509
1507 var dir = langref_path.root_dir.handle.openDir(io, langref_path.sub_path, .{ .iterate = true }) catch |err|1510 var dir = langref_path.root_dir.handle.openDir(io, langref_path.sub_path, .{ .iterate = true }) catch |err|
1508 std.debug.panic("unable to open directory {f}: {t}", .{ langref_path, err });1511 std.debug.panic("unable to open directory {f}: {t}", .{ langref_path, err });
...@@ -1518,17 +1521,22 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath {...@@ -1518,17 +1521,22 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath {
15181521
1519 const out_basename = b.fmt("{s}.out", .{std.fs.path.stem(entry.name)});1522 const out_basename = b.fmt("{s}.out", .{std.fs.path.stem(entry.name)});
1520 const cmd = b.addRunArtifact(doctest_exe);1523 const cmd = b.addRunArtifact(doctest_exe);
1521 cmd.addArgs(&.{1524
1522 "--zig", b.graph.zig_exe,1525 cmd.addArg("--zig");
1523 // TODO: enhance doctest to use "--listen=-" rather than operating1526 cmd.addFileArg(.zig_exe);
1524 // in a temporary directory1527
1525 "--cache-root", b.cache_root.path orelse ".",1528 // TODO: enhance doctest to use "--listen=-" rather than operating in a
1526 });1529 // temporary directory
1527 cmd.addArgs(&.{ "--zig-lib-dir", b.fmt("{f}", .{b.graph.zig_lib_directory}) });1530 cmd.addArg("--cache-root");
1528 cmd.addArgs(&.{"-i"});1531 cmd.addFileArg(.cache_root);
1532
1533 cmd.addArg("--zig-lib-dir");
1534 cmd.addFileArg(.zig_lib);
1535
1536 cmd.addArg("-i");
1529 cmd.addFileArg(b.path(b.fmt("doc/langref/{s}", .{entry.name})));1537 cmd.addFileArg(b.path(b.fmt("doc/langref/{s}", .{entry.name})));
15301538
1531 cmd.addArgs(&.{"-o"});1539 cmd.addArg("-o");
1532 _ = wf.addCopyFile(cmd.addOutputFileArg(out_basename), out_basename);1540 _ = wf.addCopyFile(cmd.addOutputFileArg(out_basename), out_basename);
1533 }1541 }
15341542
lib/compiler/Maker.zig+9
...@@ -1779,6 +1779,7 @@ pub fn relativePath(maker: *const Maker, relative: Configuration.LazyPath.Relati...@@ -1779,6 +1779,7 @@ pub fn relativePath(maker: *const Maker, relative: Configuration.LazyPath.Relati
1779 const graph = maker.graph;1779 const graph = maker.graph;
1780 const c = &maker.scanned_config.configuration;1780 const c = &maker.scanned_config.configuration;
1781 const sub_path = relative.sub_path.slice(c);1781 const sub_path = relative.sub_path.slice(c);
1782 if (relative.flags.base == .zig_exe and sub_path.len != 0) @panic("TODO");
1782 return switch (relative.flags.base) {1783 return switch (relative.flags.base) {
1783 .cwd => .{1784 .cwd => .{
1784 .root_dir = .cwd(),1785 .root_dir = .cwd(),
...@@ -1796,6 +1797,14 @@ pub fn relativePath(maker: *const Maker, relative: Configuration.LazyPath.Relati...@@ -1796,6 +1797,14 @@ pub fn relativePath(maker: *const Maker, relative: Configuration.LazyPath.Relati
1796 .root_dir = graph.build_root_directory,1797 .root_dir = graph.build_root_directory,
1797 .sub_path = sub_path,1798 .sub_path = sub_path,
1798 },1799 },
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 },
1799 };1808 };
1800}1809}
18011810
lib/compiler/Maker/Graph.zig+5-4
...@@ -75,10 +75,11 @@ pub fn handleVerbose(...@@ -75,10 +75,11 @@ pub fn handleVerbose(
75) error{OutOfMemory}!void {75) error{OutOfMemory}!void {
76 if (!graph.verbose) return;76 if (!graph.verbose) return;
77 const arena = graph.arena;77 const arena = graph.arena;
78 const text = try std.zig.allocPrintCmd(arena, cwd, if (opt_env) |env| .{78 const text = try std.zig.allocPrintCmd(arena, argv, .{
79 .child = env,79 .cwd = cwd,
80 .parent = &graph.environ_map,80 .parent_env = &graph.environ_map,
81 } else null, argv);81 .child_env = opt_env,
82 });
82 defer arena.free(text);83 defer arena.free(text);
83 std.log.scoped(.verbose).info("{s}", .{text});84 std.log.scoped(.verbose).info("{s}", .{text});
84}85}
lib/compiler/Maker/Step.zig+4-2
...@@ -70,6 +70,7 @@ pub const Extended = union(enum) {...@@ -70,6 +70,7 @@ pub const Extended = union(enum) {
70 compile: Compile,70 compile: Compile,
71 config_header: Todo,71 config_header: Todo,
72 fail: Todo,72 fail: Todo,
73 find_program: Todo,
73 fmt: Todo,74 fmt: Todo,
74 install_artifact: InstallArtifact,75 install_artifact: InstallArtifact,
75 install_dir: Todo,76 install_dir: Todo,
...@@ -89,6 +90,7 @@ pub const Extended = union(enum) {...@@ -89,6 +90,7 @@ pub const Extended = union(enum) {
89 .compile => .{ .compile = .{} },90 .compile => .{ .compile = .{} },
90 .config_header => .{ .config_header = .{} },91 .config_header => .{ .config_header = .{} },
91 .fail => .{ .fail = .{} },92 .fail => .{ .fail = .{} },
93 .find_program => .{ .find_program = .{} },
92 .fmt => .{ .fmt = .{} },94 .fmt => .{ .fmt = .{} },
93 .install_artifact => .{ .install_artifact = .{} },95 .install_artifact => .{ .install_artifact = .{} },
94 .install_dir => .{ .install_dir = .{} },96 .install_dir => .{ .install_dir = .{} },
...@@ -314,7 +316,7 @@ pub fn captureChildProcess(...@@ -314,7 +316,7 @@ pub fn captureChildProcess(
314316
315 // If an error occurs, it's happened in this command:317 // If an error occurs, it's happened in this command:
316 assert(s.result_failed_command == null);318 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
319 try handleChildProcUnsupported(s, maker);321 try handleChildProcUnsupported(s, maker);
320 try graph.handleVerbose(.inherit, null, argv);322 try graph.handleVerbose(.inherit, null, argv);
...@@ -382,7 +384,7 @@ pub fn evalZigProcess(...@@ -382,7 +384,7 @@ pub fn evalZigProcess(
382384
383 // If an error occurs, it's happened in this command:385 // If an error occurs, it's happened in this command:
384 assert(s.result_failed_command == null);386 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
387 if (s.getZigProcess()) |zp| update: {389 if (s.getZigProcess()) |zp| update: {
388 assert(watch);390 assert(watch);
lib/compiler/Maker/Step/Run.zig+5-4
...@@ -2129,10 +2129,11 @@ fn spawnChildAndCollect(...@@ -2129,10 +2129,11 @@ fn spawnChildAndCollect(
21292129
2130 // If an error occurs, it's caused by this command:2130 // If an error occurs, it's caused by this command:
2131 assert(step.result_failed_command == null);2131 assert(step.result_failed_command == null);
2132 step.result_failed_command = try std.zig.allocPrintCmd(arena, child_cwd, .{2132 step.result_failed_command = try std.zig.allocPrintCmd(arena, argv, .{
2133 .child = environ_map,2133 .cwd = child_cwd,
2134 .parent = &graph.environ_map,2134 .child_env = environ_map,
2135 }, argv);2135 .parent_env = &graph.environ_map,
2136 });
21362137
2137 try step.handleChildProcUnsupported(maker);2138 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...@@ -714,7 +714,7 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim
714 if (code != 0) {714 if (code != 0) {
715 log.err(715 log.err(
716 "the following command exited with error code {d}:\n{s}",716 "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, .{}) },
718 );718 );
719 return error.WasmCompilationFailed;719 return error.WasmCompilationFailed;
720 }720 }
...@@ -722,21 +722,21 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim...@@ -722,21 +722,21 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim
722 .signal => |sig| {722 .signal => |sig| {
723 log.err(723 log.err(
724 "the following command terminated with signal {t}:\n{s}",724 "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, .{}) },
726 );726 );
727 return error.WasmCompilationFailed;727 return error.WasmCompilationFailed;
728 },728 },
729 .stopped => |sig| {729 .stopped => |sig| {
730 log.err(730 log.err(
731 "the following command stopped unexpectedly with signal {t}:\n{s}",731 "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, .{}) },
733 );733 );
734 return error.WasmCompilationFailed;734 return error.WasmCompilationFailed;
735 },735 },
736 .unknown => {736 .unknown => {
737 log.err(737 log.err(
738 "the following command terminated unexpectedly:\n{s}",738 "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, .{})},
740 );740 );
741 return error.WasmCompilationFailed;741 return error.WasmCompilationFailed;
742 },742 },
...@@ -746,14 +746,14 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim...@@ -746,14 +746,14 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim
746 try result_error_bundle.renderToStderr(io, .{}, .auto);746 try result_error_bundle.renderToStderr(io, .{}, .auto);
747 log.err("the following command failed with {d} compilation errors:\n{s}", .{747 log.err("the following command failed with {d} compilation errors:\n{s}", .{
748 result_error_bundle.errorMessageCount(),748 result_error_bundle.errorMessageCount(),
749 try std.zig.allocPrintCmd(arena, .inherit, null, argv.items),749 try std.zig.allocPrintCmd(arena, argv.items, .{}),
750 });750 });
751 return error.WasmCompilationFailed;751 return error.WasmCompilationFailed;
752 }752 }
753753
754 const base_path = result orelse {754 const base_path = result orelse {
755 log.err("child process failed to report result\n{s}", .{755 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, .{}),
757 });757 });
758 return error.WasmCompilationFailed;758 return error.WasmCompilationFailed;
759 };759 };
lib/compiler/configurer.zig+30-2
...@@ -62,10 +62,22 @@ pub fn main(init: process.Init.Minimal) !void {...@@ -62,10 +62,22 @@ pub fn main(init: process.Init.Minimal) !void {
62 assert(try graph.wip_configuration.addString("") == .empty);62 assert(try graph.wip_configuration.addString("") == .empty);
63 assert(try graph.wip_configuration.addString("root") == .root);63 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
67 var color: Color = .auto;80 var color: Color = .auto;
68 var arg_i: usize = 1; // Skip own executable name.
6981
70 while (nextArg(args, &arg_i)) |arg| {82 while (nextArg(args, &arg_i)) |arg| {
71 if (mem.cutPrefix(u8, arg, "-D")) |option_contents| {83 if (mem.cutPrefix(u8, arg, "-D")) |option_contents| {
...@@ -98,6 +110,8 @@ pub fn main(init: process.Init.Minimal) !void {...@@ -98,6 +110,8 @@ pub fn main(init: process.Init.Minimal) !void {
98 // but it is handled by the parent process. The build runner110 // but it is handled by the parent process. The build runner
99 // only sees this flag.111 // only sees this flag.
100 graph.system_package_mode = true;112 graph.system_package_mode = true;
113 } else if (mem.eql(u8, arg, "--verbose")) {
114 graph.verbose = true;
101 } else {115 } else {
102 fatalWithHint("unrecognized argument: {s}", .{arg});116 fatalWithHint("unrecognized argument: {s}", .{arg});
103 }117 }
...@@ -183,6 +197,12 @@ const Serialize = struct {...@@ -183,6 +197,12 @@ const Serialize = struct {
183 .sub_path = sub_path,197 .sub_path = sub_path,
184 }));198 }));
185 },199 },
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 },
186 .dependency => |dependency| i: {206 .dependency => |dependency| i: {
187 const sub_path = try wc.addString(dependency.sub_path);207 const sub_path = try wc.addString(dependency.sub_path);
188 break :i try wc.addExtra(@as(Configuration.LazyPath.SourcePath, .{208 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 {...@@ -840,6 +860,7 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
840 .install_dir => @panic("TODO"),860 .install_dir => @panic("TODO"),
841 .remove_dir => @panic("TODO"),861 .remove_dir => @panic("TODO"),
842 .fail => @panic("TODO"),862 .fail => @panic("TODO"),
863 .find_program => @panic("TODO"),
843 .fmt => @panic("TODO"),864 .fmt => @panic("TODO"),
844 .translate_c => @panic("TODO"),865 .translate_c => @panic("TODO"),
845 .write_file => @panic("TODO"),866 .write_file => @panic("TODO"),
...@@ -1038,6 +1059,13 @@ fn nextArg(args: []const [:0]const u8, idx: *usize) ?[:0]const u8 {...@@ -1038,6 +1059,13 @@ fn nextArg(args: []const [:0]const u8, idx: *usize) ?[:0]const u8 {
1038 return args[idx.*];1059 return args[idx.*];
1039}1060}
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
1041const ErrorStyle = enum {1069const ErrorStyle = enum {
1042 verbose,1070 verbose,
1043 minimal,1071 minimal,
lib/std/Build.zig+216-126
...@@ -34,6 +34,8 @@ available_options_map: std.array_hash_map.String(AvailableOption) = .empty,...@@ -34,6 +34,8 @@ available_options_map: std.array_hash_map.String(AvailableOption) = .empty,
34invalid_user_input: bool,34invalid_user_input: bool,
35default_step: *Step,35default_step: *Step,
36top_level_steps: std.StringArrayHashMapUnmanaged(*Step.TopLevel),36top_level_steps: std.StringArrayHashMapUnmanaged(*Step.TopLevel),
37/// Path to the directory containing build.zig.
38root: Cache.Path,
37debug_log_scopes: []const []const u8 = &.{},39debug_log_scopes: []const []const u8 = &.{},
38/// Number of stack frames captured when a `StackTrace` is recorded for debug purposes,40/// Number of stack frames captured when a `StackTrace` is recorded for debug purposes,
39/// in particular at `Step` creation.41/// in particular at `Step` creation.
...@@ -85,6 +87,7 @@ pub const Graph = struct {...@@ -85,6 +87,7 @@ pub const Graph = struct {
85 dependency_cache: InitializedDepMap = .empty,87 dependency_cache: InitializedDepMap = .empty,
86 allow_so_scripts: ?bool = null,88 allow_so_scripts: ?bool = null,
87 time_report: bool = false,89 time_report: bool = false,
90 verbose: bool = false,
88 /// Similar to the `Io.Terminal.Mode` returned by `Io.lockStderr`, but also91 /// Similar to the `Io.Terminal.Mode` returned by `Io.lockStderr`, but also
89 /// respects the '--color' flag.92 /// respects the '--color' flag.
90 stderr_mode: ?Io.Terminal.Mode = null,93 stderr_mode: ?Io.Terminal.Mode = null,
...@@ -117,6 +120,20 @@ pub const Graph = struct {...@@ -117,6 +120,20 @@ pub const Graph = struct {
117 for (array, strings) |*dest, source| dest.* = dupeString(graph, source);120 for (array, strings) |*dest, source| dest.* = dupeString(graph, source);
118 return array;121 return array;
119 }122 }
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 }
120};137};
121138
122const AvailableDeps = []const struct { []const u8, []const u8 };139const AvailableDeps = []const struct { []const u8, []const u8 };
...@@ -170,13 +187,6 @@ const InitializedDepContext = struct {...@@ -170,13 +187,6 @@ const InitializedDepContext = struct {
170 }187 }
171};188};
172189
173pub const RunError = error{
174 ReadFailure,
175 ExitCodeFailure,
176 ProcessTerminated,
177 ExecNotSupported,
178} || std.process.SpawnError;
179
180const UserInputOptionsMap = StringHashMap(UserInputOption);190const UserInputOptionsMap = StringHashMap(UserInputOption);
181191
182const AvailableOption = struct {192const AvailableOption = struct {
...@@ -204,6 +214,7 @@ const UserValue = union(enum) {...@@ -204,6 +214,7 @@ const UserValue = union(enum) {
204214
205pub fn create(215pub fn create(
206 graph: *Graph,216 graph: *Graph,
217 root: Cache.Path,
207 available_deps: AvailableDeps,218 available_deps: AvailableDeps,
208) error{OutOfMemory}!*Build {219) error{OutOfMemory}!*Build {
209 const arena = graph.arena;220 const arena = graph.arena;
...@@ -211,6 +222,7 @@ pub fn create(...@@ -211,6 +222,7 @@ pub fn create(
211 const b = try arena.create(Build);222 const b = try arena.create(Build);
212 b.* = .{223 b.* = .{
213 .graph = graph,224 .graph = graph,
225 .root = root,
214 .invalid_user_input = false,226 .invalid_user_input = false,
215 .allocator = arena,227 .allocator = arena,
216 .user_input_options = UserInputOptionsMap.init(arena),228 .user_input_options = UserInputOptionsMap.init(arena),
...@@ -247,6 +259,7 @@ pub fn create(...@@ -247,6 +259,7 @@ pub fn create(
247fn createChild(259fn createChild(
248 parent: *Build,260 parent: *Build,
249 dep_name: []const u8,261 dep_name: []const u8,
262 root: Cache.Path,
250 pkg_hash: []const u8,263 pkg_hash: []const u8,
251 pkg_deps: AvailableDeps,264 pkg_deps: AvailableDeps,
252 user_input_options: UserInputOptionsMap,265 user_input_options: UserInputOptionsMap,
...@@ -255,6 +268,7 @@ fn createChild(...@@ -255,6 +268,7 @@ fn createChild(
255 const child = try allocator.create(Build);268 const child = try allocator.create(Build);
256 child.* = .{269 child.* = .{
257 .graph = parent.graph,270 .graph = parent.graph,
271 .root = root,
258 .allocator = allocator,272 .allocator = allocator,
259 .install_tls = .{273 .install_tls = .{
260 .step = .init(.{274 .step = .init(.{
...@@ -1143,7 +1157,7 @@ pub fn step(b: *Build, name: []const u8, description: []const u8) *Step {...@@ -1143,7 +1157,7 @@ pub fn step(b: *Build, name: []const u8, description: []const u8) *Step {
1143 .description = b.dupe(description),1157 .description = b.dupe(description),
1144 };1158 };
1145 const gop = b.top_level_steps.getOrPut(b.allocator, name) catch @panic("OOM");1159 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
1148 gop.key_ptr.* = step_info.step.name;1162 gop.key_ptr.* = step_info.step.name;
1149 gop.value_ptr.* = step_info;1163 gop.value_ptr.* = step_info;
...@@ -1366,7 +1380,8 @@ pub fn addUserInputOption(b: *Build, name_raw: []const u8, value_raw: []const u8...@@ -1366,7 +1380,8 @@ pub fn addUserInputOption(b: *Build, name_raw: []const u8, value_raw: []const u8
1366}1380}
13671381
1368pub fn addUserInputFlag(b: *Build, name_raw: []const u8) error{OutOfMemory}!bool {1382pub 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);
1370 const gop = try b.user_input_options.getOrPut(name);1385 const gop = try b.user_input_options.getOrPut(name);
1371 if (!gop.found_existing) {1386 if (!gop.found_existing) {
1372 gop.value_ptr.* = .{1387 gop.value_ptr.* = .{
...@@ -1388,7 +1403,7 @@ pub fn addUserInputFlag(b: *Build, name_raw: []const u8) error{OutOfMemory}!bool...@@ -1388,7 +1403,7 @@ pub fn addUserInputFlag(b: *Build, name_raw: []const u8) error{OutOfMemory}!bool
1388 return true;1403 return true;
1389 },1404 },
1390 .lazy_path => |lp| {1405 .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) });
1392 return true;1407 return true;
1393 },1408 },
13941409
...@@ -1538,7 +1553,7 @@ pub fn truncateFile(b: *Build, dest_path: []const u8) (Io.Dir.CreateDirError ||...@@ -1538,7 +1553,7 @@ pub fn truncateFile(b: *Build, dest_path: []const u8) (Io.Dir.CreateDirError ||
1538/// References a file or directory relative to the source root.1553/// References a file or directory relative to the source root.
1539pub fn path(b: *Build, sub_path: []const u8) LazyPath {1554pub fn path(b: *Build, sub_path: []const u8) LazyPath {
1540 if (fs.path.isAbsolute(sub_path)) {1555 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", .{
1542 sub_path,1557 sub_path,
1543 });1558 });
1544 }1559 }
...@@ -1560,117 +1575,164 @@ pub fn fmt(b: *Build, comptime format: []const u8, args: anytype) []u8 {...@@ -1560,117 +1575,164 @@ pub fn fmt(b: *Build, comptime format: []const u8, args: anytype) []u8 {
1560 return std.fmt.allocPrint(b.allocator, format, args) catch @panic("OOM");1575 return std.fmt.allocPrint(b.allocator, format, args) catch @panic("OOM");
1561}1576}
15621577
1563fn supportedWindowsProgramExtension(ext: []const u8) bool {1578/// Creates an anonymous `Step` that searches for an executable on the host that
1564 inline for (@typeInfo(std.process.WindowsExtension).@"enum".fields) |field| {1579/// has more than one possible name.
1565 if (std.ascii.eqlIgnoreCase(ext, "." ++ field.name)) return true;1580///
1566 }1581/// Names are searched in order, observing search prefixes first and then PATH
1567 return false;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");
1568}1592}
15691593
1570fn tryFindProgram(b: *Build, full_path: []const u8) ?[]const u8 {1594/// Deprecated; use `runFallible`.
1571 const io = b.graph.io;1595pub fn runAllowFail(
1572 const arena = b.allocator;1596 b: *Build,
15731597 argv: []const []const u8,
1574 if (b.build_root.handle.realPathFileAlloc(io, full_path, arena)) |p| {1598 exit_code: *u8,
1575 return p;1599 stderr_behavior: process.SpawnOptions.StdIo,
1576 } else |err| switch (err) {1600) anyerror![]u8 {
1577 error.OutOfMemory => @panic("OOM"),1601 if (!process.can_spawn) return error.ExecNotSupported;
1578 else => {},1602 switch (runFallible(b, argv, .{
1579 }1603 .stderr_behavior = stderr_behavior,
15801604 })) {
1581 if (builtin.os.tag == .windows) {1605 .success => |stdout| return stdout,
1582 if (b.graph.environ_map.get("PATHEXT")) |PATHEXT| {1606 .spawn_failed => |err| return err,
1583 var it = mem.tokenizeScalar(u8, PATHEXT, fs.path.delimiter);1607 .bad_exit_code => |code| {
15841608 exit_code.* = code;
1585 while (it.next()) |ext| {1609 return error.ExitCodeFailure;
1586 if (!supportedWindowsProgramExtension(ext)) continue;1610 },
15871611 .crashed => {
1588 return b.build_root.handle.realPathFileAlloc(1612 exit_code.* = 255;
1589 io,1613 return error.ProcessTerminated;
1590 b.fmt("{s}{s}", .{ full_path, ext }),1614 },
1591 arena,
1592 ) catch |err| switch (err) {
1593 error.OutOfMemory => @panic("OOM"),
1594 else => continue,
1595 };
1596 }
1597 }
1598 }1615 }
1599
1600 return null;
1601}1616}
16021617
1603pub fn findProgram(b: *Build, names: []const []const u8, paths: []const []const u8) LazyPath {1618pub const RunOptions = struct {
1604 _ = b;1619 stderr_behavior: process.SpawnOptions.StdIo = .inherit,
1605 _ = names;1620 /// Fail the configuration if stdout is larger than this.
1606 _ = paths;1621 stdout_limit: Io.Limit = .limited(1_000_000),
1607 @panic("TODO rework findProgram to be based on LazyPath");1622 /// Set to change the current working directory when spawning the child
1608}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(1632pub const RunResult = union(enum) {
1611 b: *Build,1633 /// Thild process exited with code 0, writing this stdout.
1612 argv: []const []const u8,1634 success: []u8,
1613 out_code: *u8,1635 /// The child process could not be created.
1614 stderr_behavior: std.process.SpawnOptions.StdIo,1636 spawn_failed: process.SpawnError,
1615) RunError![]u8 {1637 /// The child process indicated failure.
1616 assert(argv.len != 0);1638 bad_exit_code: u8,
1639 /// The child process terminated abnormally.
1640 crashed,
1641};
16171642
1618 if (!process.can_spawn)1643/// Executes the provided command immediately, allowing failure.
1619 return error.ExecNotSupported;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
1621 const graph = b.graph;1653 const graph = b.graph;
1622 const io = graph.io;1654 const io = graph.io;
1623 const arena = graph.arena;1655 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
1626 if (graph.verbose) {1663 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");
1628 std.log.scoped(.verbose).info("{s}", .{text});1665 std.log.scoped(.verbose).info("{s}", .{text});
1629 }1666 }
16301667
1631 var child = try std.process.spawn(io, .{1668 var child = process.spawn(io, .{
1632 .argv = argv,1669 .argv = argv,
1633 .environ_map = &graph.environ_map,
1634 .stdin = .ignore,1670 .stdin = .ignore,
1635 .stdout = .pipe,1671 .stdout = .pipe,
1636 .stderr = stderr_behavior,1672 .stderr = options.stderr_behavior,
1637 });1673 .cwd = options.cwd,
1674 .environ_map = &graph.environ_map,
1675 .expand_arg0 = options.expand_arg0,
1676 }) catch |err| return .{ .spawn_failed = err };
16381677
1639 var stdout_reader = child.stdout.?.readerStreaming(io, &.{});1678 var stdout_reader = child.stdout.?.readerStreaming(io, &.{});
1640 const stdout = stdout_reader.interface.allocRemaining(arena, .limited(max_output_size)) catch {1679 const stdout = stdout_reader.interface.allocRemaining(arena, options.stdout_limit) catch |err| switch (err) {
1641 return error.ReadFailure;1680 error.ReadFailed => panic("failed to read from child: {t}", .{stdout_reader.err.?}),
1681 else => |e| panic("failed to read from child: {t}", .{e}),
1642 };1682 };
1643 errdefer arena.free(stdout);1683
16441684 const term = child.wait(io) catch @panic("unexpected");
1645 const term = try child.wait(io);1685
1646 switch (term) {1686 return switch (term) {
1647 .exited => |code| {1687 .exited => |code| switch (code) {
1648 if (code != 0) {1688 0 => .{ .success = stdout },
1649 out_code.* = @as(u8, @truncate(code));1689 else => .{ .bad_exit_code = 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;
1661 },1690 },
1662 }1691 .signal, .stopped, .unknown => .crashed,
1692 };
1663}1693}
16641694
1665/// This is a helper function to be called from build.zig scripts, *not* from1695/// Executes the provided command immediately.
1666/// inside step make() functions. If any errors occur, it fails the build with1696///
1667/// a helpful message.1697/// If the program exits successfully, stdout is returned. Otherwise, fails the
1698/// build with a helpful message.
1699///
1700/// See also:
1701/// * `runFallible`.
1668pub fn run(b: *Build, argv: []const []const u8) []u8 {1702pub fn run(b: *Build, argv: []const []const u8) []u8 {
1669 var code: u8 = undefined;1703 const graph = b.graph;
1670 return b.runAllowFail(argv, &code, .inherit) catch |err| process.fatal(1704 const arena = graph.arena;
1671 "the following command failed with {t}:\n{s}",1705 switch (b.runFallible(argv, .{
1672 .{ err, Step.allocPrintCmd(b.allocator, .inherit, null, argv) catch @panic("OOM") },1706 .stderr_behavior = .inherit,
1673 );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");
1674}1736}
16751737
1676pub const Dependency = struct {1738pub const Dependency = struct {
...@@ -1727,8 +1789,8 @@ fn findPkgHashOrFatal(b: *Build, name: []const u8) []const u8 {...@@ -1727,8 +1789,8 @@ fn findPkgHashOrFatal(b: *Build, name: []const u8) []const u8 {
1727 if (mem.eql(u8, dep[0], name)) return dep[1];1789 if (mem.eql(u8, dep[0], name)) return dep[1];
1728 }1790 }
1729 std.log.info("all dependencies used by build.zig must be declared in corresponding build.zig.zon", .{});1791 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});1792 if (b.pkg_hash.len == 0) panic("no dependency named {s}", .{name});
1731 std.debug.panic("no dependency named {s} in {s} ({s})", .{ name, b.dep_prefix, b.pkg_hash });1793 panic("no dependency named {s} in {s} ({s})", .{ name, b.dep_prefix, b.pkg_hash });
1732}1794}
17331795
1734inline fn findImportPkgHashOrFatal(b: *Build, comptime asking_build_zig: type, comptime dep_name: []const u8) []const u8 {1796inline 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...@@ -1741,7 +1803,7 @@ inline fn findImportPkgHashOrFatal(b: *Build, comptime asking_build_zig: type, c
1741 if (@hasDecl(pkg, "build_zig") and pkg.build_zig == asking_build_zig) break .{ pkg_hash, pkg.deps };1803 if (@hasDecl(pkg, "build_zig") and pkg.build_zig == asking_build_zig) break .{ pkg_hash, pkg.deps };
1742 } else .{ "", deps.root_deps };1804 } else .{ "", deps.root_deps };
1743 if (!std.mem.eql(u8, b_pkg_hash, b.pkg_hash)) {1805 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}'", .{
1745 asking_build_zig, b.pathFromRoot("build.zig"),1807 asking_build_zig, b.pathFromRoot("build.zig"),
1746 });1808 });
1747 }1809 }
...@@ -1750,7 +1812,7 @@ inline fn findImportPkgHashOrFatal(b: *Build, comptime asking_build_zig: type, c...@@ -1750,7 +1812,7 @@ inline fn findImportPkgHashOrFatal(b: *Build, comptime asking_build_zig: type, c
1750 };1812 };
17511813
1752 const full_path = b.pathFromRoot("build.zig.zon");1814 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 });
1754}1816}
17551817
1756fn markNeededLazyDep(b: *Build, pkg_hash: []const u8) void {1818fn markNeededLazyDep(b: *Build, pkg_hash: []const u8) void {
...@@ -1799,7 +1861,7 @@ pub fn dependency(b: *Build, name: []const u8, args: anytype) *Dependency {...@@ -1799,7 +1861,7 @@ pub fn dependency(b: *Build, name: []const u8, args: anytype) *Dependency {
1799 if (mem.eql(u8, decl.name, pkg_hash)) {1861 if (mem.eql(u8, decl.name, pkg_hash)) {
1800 const pkg = @field(deps.packages, decl.name);1862 const pkg = @field(deps.packages, decl.name);
1801 if (@hasDecl(pkg, "available")) {1863 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 });
1803 }1865 }
1804 return dependencyInner(b, name, pkg.build_root, if (@hasDecl(pkg, "build_zig")) pkg.build_zig else null, pkg_hash, pkg.deps, args);1866 return dependencyInner(b, name, pkg.build_root, if (@hasDecl(pkg, "build_zig")) pkg.build_zig else null, pkg_hash, pkg.deps, args);
1805 }1867 }
...@@ -1866,7 +1928,7 @@ pub fn dependencyFromBuildZig(...@@ -1866,7 +1928,7 @@ pub fn dependencyFromBuildZig(
1866 }1928 }
18671929
1868 const full_path = b.pathFromRoot("build.zig.zon");1930 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 });
1870}1932}
18711933
1872fn userValuesAreSame(lhs: UserValue, rhs: UserValue) bool {1934fn userValuesAreSame(lhs: UserValue, rhs: UserValue) bool {
...@@ -1960,14 +2022,23 @@ fn dependencyInner(...@@ -1960,14 +2022,23 @@ fn dependencyInner(
1960 pkg_deps: AvailableDeps,2022 pkg_deps: AvailableDeps,
1961 args: anytype,2023 args: anytype,
1962) *Dependency {2024) *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);
1964 if (b.graph.dependency_cache.getContext(.{2028 if (b.graph.dependency_cache.getContext(.{
1965 .build_root_string = build_root_string,2029 .build_root_string = build_root_string,
1966 .user_input_options = user_input_options,2030 .user_input_options = user_input_options,
1967 }, .{ .allocator = b.graph.arena })) |dep|2031 }, .{ .allocator = arena })) |dep| return dep;
1968 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) catch2041 const sub_builder = b.createChild(name, dep_root, pkg_hash, pkg_deps, user_input_options) catch
1971 @panic("unhandled error");2042 @panic("unhandled error");
1972 if (build_zig) |bz| {2043 if (build_zig) |bz| {
1973 sub_builder.runBuild(bz) catch @panic("unhandled error");2044 sub_builder.runBuild(bz) catch @panic("unhandled error");
...@@ -1977,13 +2048,13 @@ fn dependencyInner(...@@ -1977,13 +2048,13 @@ fn dependencyInner(
1977 }2048 }
1978 }2049 }
19792050
1980 const dep = b.allocator.create(Dependency) catch @panic("OOM");2051 const dep = arena.create(Dependency) catch @panic("OOM");
1981 dep.* = .{ .builder = sub_builder };2052 dep.* = .{ .builder = sub_builder };
19822053
1983 b.graph.dependency_cache.putContext(b.graph.arena, .{2054 b.graph.dependency_cache.putContext(b.graph.arena, .{
1984 .build_root_string = build_root_string,2055 .build_root_string = build_root_string,
1985 .user_input_options = user_input_options,2056 .user_input_options = user_input_options,
1986 }, dep, .{ .allocator = b.graph.arena }) catch @panic("OOM");2057 }, dep, .{ .allocator = arena }) catch @panic("OOM");
1987 return dep;2058 return dep;
1988}2059}
19892060
...@@ -2046,14 +2117,7 @@ pub const LazyPath = union(enum) {...@@ -2046,14 +2117,7 @@ pub const LazyPath = union(enum) {
2046 sub_path: []const u8 = "",2117 sub_path: []const u8 = "",
2047 },2118 },
20482119
2049 /// An absolute path or a path relative to the current working directory of2120 /// Deprecated; call `Graph.cwdRelativePath` instead.
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.
2057 cwd_relative: []const u8,2121 cwd_relative: []const u8,
20582122
2059 dependency: struct {2123 dependency: struct {
...@@ -2061,6 +2125,19 @@ pub const LazyPath = union(enum) {...@@ -2061,6 +2125,19 @@ pub const LazyPath = union(enum) {
2061 sub_path: []const u8,2125 sub_path: []const u8,
2062 },2126 },
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
2064 /// Returns a lazy path referring to the directory containing this path.2141 /// Returns a lazy path referring to the directory containing this path.
2065 ///2142 ///
2066 /// The dirname is not allowed to escape the logical root for underlying path.2143 /// The dirname is not allowed to escape the logical root for underlying path.
...@@ -2147,21 +2224,33 @@ pub const LazyPath = union(enum) {...@@ -2147,21 +2224,33 @@ pub const LazyPath = union(enum) {
2147 };2224 };
2148 }2225 }
21492226
2150 /// Returns a string that can be shown to represent the file source.2227 pub const Format = struct {
2151 /// Either returns the path, `"generated"`, or `"dependency"`.2228 graph: *const Graph,
2152 pub fn getDisplayName(lazy_path: LazyPath) []const u8 {2229 lazy_path: *const LazyPath,
2153 return switch (lazy_path) {2230
2154 .src_path => |sp| sp.sub_path,2231 pub fn format(f: Format, w: *Io.Writer) Io.Writer.Error!void {
2155 .cwd_relative => |p| p,2232 switch (f.lazy_path.*) {
2156 .generated => "generated",2233 .src_path => |sp| try w.writeAll(sp.sub_path),
2157 .dependency => "dependency",2234 .cwd_relative => |p| try w.writeAll(p),
2158 };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 };
2159 }2248 }
21602249
2161 /// Adds dependencies this file source implies to the given step.2250 /// Adds dependencies this file source implies to the given step.
2162 pub fn addStepDependencies(lazy_path: LazyPath, other_step: *Step) void {2251 pub fn addStepDependencies(lazy_path: LazyPath, other_step: *Step) void {
2163 switch (lazy_path) {2252 switch (lazy_path) {
2164 .src_path, .cwd_relative, .dependency => {},2253 .src_path, .cwd_relative, .relative, .dependency => {},
2165 .generated => |gen| {2254 .generated => |gen| {
2166 const graph = other_step.owner.graph;2255 const graph = other_step.owner.graph;
2167 const generated_owner_step = graph.generated_files.items[@intFromEnum(gen.index)];2256 const generated_owner_step = graph.generated_files.items[@intFromEnum(gen.index)];
...@@ -2190,6 +2279,7 @@ pub const LazyPath = union(enum) {...@@ -2190,6 +2279,7 @@ pub const LazyPath = union(enum) {
2190 return switch (lazy_path) {2279 return switch (lazy_path) {
2191 .src_path => |sp| .{ .src_path = .{ .owner = sp.owner, .sub_path = sp.owner.dupePath(sp.sub_path) } },2280 .src_path => |sp| .{ .src_path = .{ .owner = sp.owner, .sub_path = sp.owner.dupePath(sp.sub_path) } },
2192 .cwd_relative => |p| .{ .cwd_relative = graph.dupePath(p) },2281 .cwd_relative => |p| .{ .cwd_relative = graph.dupePath(p) },
2282 .relative => |r| .{ .relative = r },
2193 .generated => |gen| .{ .generated = .{2283 .generated => |gen| .{ .generated = .{
2194 .index = gen.index,2284 .index = gen.index,
2195 .up = gen.up,2285 .up = gen.up,
lib/std/Build/Configuration.zig+21
...@@ -402,6 +402,12 @@ pub const Wip = struct {...@@ -402,6 +402,12 @@ pub const Wip = struct {
402 defer wip.next_generated_file_index += 1;402 defer wip.next_generated_file_index += 1;
403 return @enumFromInt(wip.next_generated_file_index);403 return @enumFromInt(wip.next_generated_file_index);
404 }404 }
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 }
405};411};
406412
407pub const SystemIntegration = extern struct {413pub const SystemIntegration = extern struct {
...@@ -445,6 +451,7 @@ pub const Step = extern struct {...@@ -445,6 +451,7 @@ pub const Step = extern struct {
445 compile: Compile,451 compile: Compile,
446 config_header: ConfigHeader,452 config_header: ConfigHeader,
447 fail: Fail,453 fail: Fail,
454 find_program: FindProgram,
448 fmt: Fmt,455 fmt: Fmt,
449 install_artifact: InstallArtifact,456 install_artifact: InstallArtifact,
450 install_dir: InstallDir,457 install_dir: InstallDir,
...@@ -479,6 +486,7 @@ pub const Step = extern struct {...@@ -479,6 +486,7 @@ pub const Step = extern struct {
479 compile,486 compile,
480 config_header,487 config_header,
481 fail,488 fail,
489 find_program,
482 fmt,490 fmt,
483 install_artifact,491 install_artifact,
484 install_dir,492 install_dir,
...@@ -1037,6 +1045,17 @@ pub const Step = extern struct {...@@ -1037,6 +1045,17 @@ pub const Step = extern struct {
1037 };1045 };
1038 };1046 };
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
1040 pub const InstallDir = struct {1059 pub const InstallDir = struct {
1041 flags: @This().Flags,1060 flags: @This().Flags,
1042 source_dir: LazyPath.Index,1061 source_dir: LazyPath.Index,
...@@ -1516,6 +1535,8 @@ pub const Path = extern struct {...@@ -1516,6 +1535,8 @@ pub const Path = extern struct {
1516 local_cache,1535 local_cache,
1517 global_cache,1536 global_cache,
1518 build_root,1537 build_root,
1538 zig_exe,
1539 zig_lib,
1519 };1540 };
15201541
1521 pub fn toCachePath(path: Path, c: *const Configuration, arena: Allocator) std.Build.Cache.Path {1542 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 {...@@ -118,10 +118,10 @@ pub const CSourceFile = struct {
118 /// By default, determines language of each file individually based on its file extension118 /// By default, determines language of each file individually based on its file extension
119 language: ?CSourceLanguage = null,119 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 {
122 return .{122 return .{
123 .file = file.file.dupe(b),123 .file = file.file.dupe(graph),
124 .flags = b.dupeStrings(file.flags),124 .flags = graph.dupeStrings(file.flags),
125 .language = file.language,125 .language = file.language,
126 };126 };
127 }127 }
...@@ -146,10 +146,12 @@ pub const RcSourceFile = struct {...@@ -146,10 +146,12 @@ pub const RcSourceFile = struct {
146 include_paths: []const LazyPath = &.{},146 include_paths: []const LazyPath = &.{},
147147
148 pub fn dupe(file: RcSourceFile, b: *std.Build) RcSourceFile {148 pub fn dupe(file: RcSourceFile, b: *std.Build) RcSourceFile {
149 const include_paths = b.allocator.alloc(LazyPath, file.include_paths.len) catch @panic("OOM");149 const graph = b.owner.graph;
150 for (include_paths, file.include_paths) |*dest, lazy_path| dest.* = lazy_path.dupe(b);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);
151 return .{153 return .{
152 .file = file.file.dupe(b),154 .file = file.file.dupe(graph),
153 .flags = b.dupeStrings(file.flags),155 .flags = b.dupeStrings(file.flags),
154 .include_paths = include_paths,156 .include_paths = include_paths,
155 };157 };
...@@ -290,15 +292,18 @@ pub fn init(...@@ -290,15 +292,18 @@ pub fn init(
290}292}
291293
292pub fn create(owner: *std.Build, options: CreateOptions) *Module {294pub 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");
294 m.init(owner, .{ .options = options });298 m.init(owner, .{ .options = options });
295 return m;299 return m;
296}300}
297301
298/// Adds an existing module to be used with `@import`.302/// Adds an existing module to be used with `@import`.
299pub fn addImport(m: *Module, name: []const u8, module: *Module) void {303pub fn addImport(m: *Module, name: []const u8, module: *Module) void {
300 const b = m.owner;304 const graph = m.owner.graph;
301 m.import_table.put(b.allocator, b.dupe(name), module) catch @panic("OOM");305 const arena = graph.arena;
306 m.import_table.put(arena, graph.dupeString(name), module) catch @panic("OOM");
302}307}
303308
304/// Creates a new module and adds it to be used with `@import`.309/// Creates a new module and adds it to be used with `@import`.
...@@ -338,7 +343,8 @@ pub fn linkSystemLibrary(...@@ -338,7 +343,8 @@ pub fn linkSystemLibrary(
338 name: []const u8,343 name: []const u8,
339 options: LinkSystemLibraryOptions,344 options: LinkSystemLibraryOptions,
340) void {345) void {
341 const b = m.owner;346 const graph = m.owner.graph;
347 const arena = graph.arena;
342348
343 const target = m.requireKnownTarget();349 const target = m.requireKnownTarget();
344 if (std.zig.target.isLibCLibName(target, name)) {350 if (std.zig.target.isLibCLibName(target, name)) {
...@@ -350,9 +356,9 @@ pub fn linkSystemLibrary(...@@ -350,9 +356,9 @@ pub fn linkSystemLibrary(
350 return;356 return;
351 }357 }
352358
353 m.link_objects.append(b.allocator, .{359 m.link_objects.append(arena, .{
354 .system_lib = .{360 .system_lib = .{
355 .name = b.dupe(name),361 .name = graph.dupeString(name),
356 .needed = options.needed,362 .needed = options.needed,
357 .weak = options.weak,363 .weak = options.weak,
358 .use_pkg_config = options.use_pkg_config,364 .use_pkg_config = options.use_pkg_config,
...@@ -363,8 +369,9 @@ pub fn linkSystemLibrary(...@@ -363,8 +369,9 @@ pub fn linkSystemLibrary(
363}369}
364370
365pub fn linkFramework(m: *Module, name: []const u8, options: LinkFrameworkOptions) void {371pub fn linkFramework(m: *Module, name: []const u8, options: LinkFrameworkOptions) void {
366 const b = m.owner;372 const graph = m.owner.graph;
367 m.frameworks.put(b.allocator, b.dupe(name), options) catch @panic("OOM");373 const arena = graph.arena;
374 m.frameworks.put(arena, graph.dupeString(name), options) catch @panic("OOM");
368}375}
369376
370pub const AddCSourceFilesOptions = struct {377pub const AddCSourceFilesOptions = struct {
...@@ -380,7 +387,8 @@ pub const AddCSourceFilesOptions = struct {...@@ -380,7 +387,8 @@ pub const AddCSourceFilesOptions = struct {
380/// Handy when you have many non-Zig source files and want them all to have the same flags.387/// Handy when you have many non-Zig source files and want them all to have the same flags.
381pub fn addCSourceFiles(m: *Module, options: AddCSourceFilesOptions) void {388pub fn addCSourceFiles(m: *Module, options: AddCSourceFilesOptions) void {
382 const b = m.owner;389 const b = m.owner;
383 const allocator = b.allocator;390 const graph = m.owner.graph;
391 const arena = graph.arena;
384392
385 for (options.files) |path| {393 for (options.files) |path| {
386 if (std.fs.path.isAbsolute(path)) {394 if (std.fs.path.isAbsolute(path)) {
...@@ -391,48 +399,50 @@ pub fn addCSourceFiles(m: *Module, options: AddCSourceFilesOptions) void {...@@ -391,48 +399,50 @@ pub fn addCSourceFiles(m: *Module, options: AddCSourceFilesOptions) void {
391 }399 }
392 }400 }
393401
394 const c_source_files = allocator.create(CSourceFiles) catch @panic("OOM");402 const c_source_files = arena.create(CSourceFiles) catch @panic("OOM");
395 c_source_files.* = .{403 c_source_files.* = .{
396 .root = options.root orelse b.path(""),404 .root = options.root orelse b.path(""),
397 .files = b.dupeStrings(options.files),405 .files = b.dupeStrings(options.files),
398 .flags = b.dupeStrings(options.flags),406 .flags = b.dupeStrings(options.flags),
399 .language = options.language,407 .language = options.language,
400 };408 };
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");
402}410}
403411
404pub fn addCSourceFile(m: *Module, source: CSourceFile) void {412pub fn addCSourceFile(m: *Module, source: CSourceFile) void {
405 const b = m.owner;413 const graph = m.owner.graph;
406 const allocator = b.allocator;414 const arena = graph.arena;
407 const c_source_file = allocator.create(CSourceFile) catch @panic("OOM");415 const c_source_file = arena.create(CSourceFile) catch @panic("OOM");
408 c_source_file.* = source.dupe(b);416 c_source_file.* = source.dupe(graph);
409 m.link_objects.append(allocator, .{ .c_source_file = c_source_file }) catch @panic("OOM");417 m.link_objects.append(arena, .{ .c_source_file = c_source_file }) catch @panic("OOM");
410}418}
411419
412/// Resource files must have the extension `.rc`.420/// Resource files must have the extension `.rc`.
413/// Can be called regardless of target. The .rc file will be ignored421/// Can be called regardless of target. The .rc file will be ignored
414/// if the target object format does not support embedded resources.422/// if the target object format does not support embedded resources.
415pub fn addWin32ResourceFile(m: *Module, source: RcSourceFile) void {423pub fn addWin32ResourceFile(m: *Module, source: RcSourceFile) void {
416 const b = m.owner;424 const graph = m.owner.graph;
417 const allocator = b.allocator;425 const arena = graph.arena;
418 const target = m.requireKnownTarget();426 const target = m.requireKnownTarget();
419 // Only the PE/COFF format has a Resource Table, so for any other target427 // Only the PE/COFF format has a Resource Table, so for any other target
420 // the resource file is ignored.428 // the resource file is ignored.
421 if (target.ofmt != .coff) return;429 if (target.ofmt != .coff) return;
422430
423 const rc_source_file = allocator.create(RcSourceFile) catch @panic("OOM");431 const rc_source_file = arena.create(RcSourceFile) catch @panic("OOM");
424 rc_source_file.* = source.dupe(b);432 rc_source_file.* = source.dupe(graph);
425 m.link_objects.append(allocator, .{ .win32_resource_file = rc_source_file }) catch @panic("OOM");433 m.link_objects.append(arena, .{ .win32_resource_file = rc_source_file }) catch @panic("OOM");
426}434}
427435
428pub fn addAssemblyFile(m: *Module, source: LazyPath) void {436pub fn addAssemblyFile(m: *Module, source: LazyPath) void {
429 const b = m.owner;437 const graph = m.owner.graph;
430 m.link_objects.append(b.allocator, .{ .assembly_file = source.dupe(b) }) catch @panic("OOM");438 const arena = graph.arena;
439 m.link_objects.append(arena, .{ .assembly_file = source.dupe(graph) }) catch @panic("OOM");
431}440}
432441
433pub fn addObjectFile(m: *Module, object: LazyPath) void {442pub fn addObjectFile(m: *Module, object: LazyPath) void {
434 const b = m.owner;443 const graph = m.owner.graph;
435 m.link_objects.append(b.allocator, .{ .static_path = object.dupe(b) }) catch @panic("OOM");444 const arena = graph.arena;
445 m.link_objects.append(arena, .{ .static_path = object.dupe(graph) }) catch @panic("OOM");
436}446}
437447
438pub fn addObject(m: *Module, object: *Step.Compile) void {448pub fn addObject(m: *Module, object: *Step.Compile) void {
...@@ -446,55 +456,63 @@ pub fn linkLibrary(m: *Module, library: *Step.Compile) void {...@@ -446,55 +456,63 @@ pub fn linkLibrary(m: *Module, library: *Step.Compile) void {
446}456}
447457
448pub fn addAfterIncludePath(m: *Module, lazy_path: LazyPath) void {458pub fn addAfterIncludePath(m: *Module, lazy_path: LazyPath) void {
449 const b = m.owner;459 const graph = m.owner.graph;
450 m.include_dirs.append(b.allocator, .{ .path_after = lazy_path.dupe(b) }) catch @panic("OOM");460 const arena = graph.arena;
461 m.include_dirs.append(arena, .{ .path_after = lazy_path.dupe(graph) }) catch @panic("OOM");
451}462}
452463
453pub fn addSystemIncludePath(m: *Module, lazy_path: LazyPath) void {464pub fn addSystemIncludePath(m: *Module, lazy_path: LazyPath) void {
454 const b = m.owner;465 const graph = m.owner.graph;
455 m.include_dirs.append(b.allocator, .{ .path_system = lazy_path.dupe(b) }) catch @panic("OOM");466 const arena = graph.arena;
467 m.include_dirs.append(arena, .{ .path_system = lazy_path.dupe(graph) }) catch @panic("OOM");
456}468}
457469
458pub fn addIncludePath(m: *Module, lazy_path: LazyPath) void {470pub fn addIncludePath(m: *Module, lazy_path: LazyPath) void {
459 const b = m.owner;471 const graph = m.owner.graph;
460 m.include_dirs.append(b.allocator, .{ .path = lazy_path.dupe(b) }) catch @panic("OOM");472 const arena = graph.arena;
473 m.include_dirs.append(arena, .{ .path = lazy_path.dupe(graph) }) catch @panic("OOM");
461}474}
462475
463pub fn addConfigHeader(m: *Module, config_header: *Step.ConfigHeader) void {476pub fn addConfigHeader(m: *Module, config_header: *Step.ConfigHeader) void {
464 const allocator = m.owner.allocator;477 const graph = m.owner.graph;
465 m.include_dirs.append(allocator, .{ .config_header_step = config_header }) catch @panic("OOM");478 const arena = graph.arena;
479 m.include_dirs.append(arena, .{ .config_header_step = config_header }) catch @panic("OOM");
466}480}
467481
468pub fn addSystemFrameworkPath(m: *Module, directory_path: LazyPath) void {482pub fn addSystemFrameworkPath(m: *Module, directory_path: LazyPath) void {
469 const b = m.owner;483 const graph = m.owner.graph;
470 m.include_dirs.append(b.allocator, .{ .framework_path_system = directory_path.dupe(b) }) catch484 const arena = graph.arena;
471 @panic("OOM");485 m.include_dirs.append(arena, .{ .framework_path_system = directory_path.dupe(graph) }) catch @panic("OOM");
472}486}
473487
474pub fn addFrameworkPath(m: *Module, directory_path: LazyPath) void {488pub fn addFrameworkPath(m: *Module, directory_path: LazyPath) void {
475 const b = m.owner;489 const graph = m.owner.graph;
476 m.include_dirs.append(b.allocator, .{ .framework_path = directory_path.dupe(b) }) catch490 const arena = graph.arena;
477 @panic("OOM");491 m.include_dirs.append(arena, .{ .framework_path = directory_path.dupe(graph) }) catch @panic("OOM");
478}492}
479493
480pub fn addEmbedPath(m: *Module, lazy_path: LazyPath) void {494pub fn addEmbedPath(m: *Module, lazy_path: LazyPath) void {
481 const b = m.owner;495 const graph = m.owner.graph;
482 m.include_dirs.append(b.allocator, .{ .embed_path = lazy_path.dupe(b) }) catch @panic("OOM");496 const arena = graph.arena;
497 m.include_dirs.append(arena, .{ .embed_path = lazy_path.dupe(graph) }) catch @panic("OOM");
483}498}
484499
485pub fn addLibraryPath(m: *Module, directory_path: LazyPath) void {500pub fn addLibraryPath(m: *Module, directory_path: LazyPath) void {
486 const b = m.owner;501 const graph = m.owner.graph;
487 m.lib_paths.append(b.allocator, directory_path.dupe(b)) catch @panic("OOM");502 const arena = graph.arena;
503 m.lib_paths.append(arena, directory_path.dupe(graph)) catch @panic("OOM");
488}504}
489505
490pub fn addRPath(m: *Module, directory_path: LazyPath) void {506pub fn addRPath(m: *Module, directory_path: LazyPath) void {
491 const b = m.owner;507 const graph = m.owner.graph;
492 m.rpaths.append(b.allocator, .{ .lazy_path = directory_path.dupe(b) }) catch @panic("OOM");508 const arena = graph.arena;
509 m.rpaths.append(arena, .{ .lazy_path = directory_path.dupe(graph) }) catch @panic("OOM");
493}510}
494511
495pub fn addRPathSpecial(m: *Module, bytes: []const u8) void {512pub fn addRPathSpecial(m: *Module, bytes: []const u8) void {
496 const b = m.owner;513 const graph = m.owner.graph;
497 m.rpaths.append(b.allocator, .{ .special = b.dupe(bytes) }) catch @panic("OOM");514 const arena = graph.arena;
515 m.rpaths.append(arena, .{ .special = graph.dupeString(bytes) }) catch @panic("OOM");
498}516}
499517
500/// Equvialent to the following C code, applied to all C source files owned by518/// 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 {...@@ -505,19 +523,23 @@ pub fn addRPathSpecial(m: *Module, bytes: []const u8) void {
505/// `name` and `value` need not live longer than the function call.523/// `name` and `value` need not live longer than the function call.
506pub fn addCMacro(m: *Module, name: []const u8, value: []const u8) void {524pub fn addCMacro(m: *Module, name: []const u8, value: []const u8) void {
507 const b = m.owner;525 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");
509}529}
510530
511fn linkLibraryOrObject(m: *Module, other: *Step.Compile) void {531fn 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
513 _ = other.getEmittedBin(); // Indicate there is a dependency on the outputted binary.535 _ = other.getEmittedBin(); // Indicate there is a dependency on the outputted binary.
514536
515 if (other.rootModuleTarget().os.tag == .windows and other.isDynamicLibrary()) {537 if (other.rootModuleTarget().os.tag == .windows and other.isDynamicLibrary()) {
516 _ = other.getEmittedImplib(); // Indicate dependency on the outputted implib.538 _ = other.getEmittedImplib(); // Indicate dependency on the outputted implib.
517 }539 }
518540
519 m.link_objects.append(allocator, .{ .other_step = other }) catch @panic("OOM");541 m.link_objects.append(arena, .{ .other_step = other }) catch @panic("OOM");
520 m.include_dirs.append(allocator, .{ .other_step = other }) catch @panic("OOM");542 m.include_dirs.append(arena, .{ .other_step = other }) catch @panic("OOM");
521}543}
522544
523fn requireKnownTarget(m: *Module) *const std.Target {545fn 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 {...@@ -83,7 +83,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader {
83 }83 }
8484
85 const name = if (options.style.getPath()) |s|85 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 })
87 else87 else
88 owner.fmt("configure {t} header to {s}", .{ options.style, include_path });88 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 {...@@ -47,7 +47,7 @@ pub fn create(owner: *std.Build, options: Options) *InstallDir {
47 install_dir.* = .{47 install_dir.* = .{
48 .step = Step.init(.{48 .step = Step.init(.{
49 .tag = base_tag,49 .tag = base_tag,
50 .name = owner.fmt("install {s}/", .{options.source_dir.getDisplayName()}),50 .name = owner.fmt("install {f}/", .{options.source_dir.fmt(graph)}),
51 .owner = owner,51 .owner = owner,
52 }),52 }),
53 .options = options.dupe(graph),53 .options = options.dupe(graph),
lib/std/Build/Step/InstallFile.zig+1-1
...@@ -26,7 +26,7 @@ pub fn create(...@@ -26,7 +26,7 @@ pub fn create(
26 install_file.* = .{26 install_file.* = .{
27 .step = Step.init(.{27 .step = Step.init(.{
28 .tag = base_tag,28 .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 }),
30 .owner = owner,30 .owner = owner,
31 }),31 }),
32 .source = source.dupe(graph),32 .source = source.dupe(graph),
lib/std/Build/Step/ObjCopy.zig+2-2
...@@ -116,12 +116,12 @@ pub fn create(...@@ -116,12 +116,12 @@ pub fn create(
116 objcopy.* = ObjCopy{116 objcopy.* = ObjCopy{
117 .step = Step.init(.{117 .step = Step.init(.{
118 .tag = base_tag,118 .tag = base_tag,
119 .name = owner.fmt("objcopy {s}", .{input_file.getDisplayName()}),119 .name = owner.fmt("objcopy {f}", .{input_file.fmt(graph)}),
120 .owner = owner,120 .owner = owner,
121 .makeFn = make,121 .makeFn = make,
122 }),122 }),
123 .input_file = input_file,123 .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"),
125 .output_file = graph.addGeneratedFile(&objcopy.step),125 .output_file = graph.addGeneratedFile(&objcopy.step),
126 .output_file_debug = if (options.strip != .none and options.extract_to_separate_file)126 .output_file_debug = if (options.strip != .none and options.extract_to_separate_file)
127 .init(graph.addGeneratedFile(&objcopy.step))127 .init(graph.addGeneratedFile(&objcopy.step))
lib/std/zig.zig+14-17
...@@ -1165,15 +1165,13 @@ pub const ClangCliParam = struct {...@@ -1165,15 +1165,13 @@ pub const ClangCliParam = struct {
1165 }1165 }
1166};1166};
11671167
1168pub fn allocPrintCmd(1168pub const AllocPrintCmdOptions = struct {
1169 gpa: Allocator,1169 cwd: std.process.Child.Cwd = .inherit,
1170 cwd: std.process.Child.Cwd,1170 parent_env: ?*const std.process.Environ.Map = null,
1171 opt_env: ?struct {1171 child_env: ?*const std.process.Environ.Map = null,
1172 child: *const std.process.Environ.Map,1172};
1173 parent: *const std.process.Environ.Map,1173
1174 },1174pub fn allocPrintCmd(gpa: Allocator, argv: []const []const u8, options: AllocPrintCmdOptions) Allocator.Error![]u8 {
1175 argv: []const []const u8,
1176) Allocator.Error![]u8 {
1177 const shell = struct {1175 const shell = struct {
1178 fn escape(writer: *Io.Writer, string: []const u8, is_argv0: bool) !void {1176 fn escape(writer: *Io.Writer, string: []const u8, is_argv0: bool) !void {
1179 for (string) |c| {1177 for (string) |c| {
...@@ -1212,18 +1210,17 @@ pub fn allocPrintCmd(...@@ -1212,18 +1210,17 @@ pub fn allocPrintCmd(
1212 var aw: Io.Writer.Allocating = .init(gpa);1210 var aw: Io.Writer.Allocating = .init(gpa);
1213 defer aw.deinit();1211 defer aw.deinit();
1214 const writer = &aw.writer;1212 const writer = &aw.writer;
1215 switch (cwd) {1213 switch (options.cwd) {
1216 .inherit => {},1214 .inherit => {},
1217 .path => |path| writer.print("cd {s} && ", .{path}) catch return error.OutOfMemory,1215 .path => |path| writer.print("cd {s} && ", .{path}) catch return error.OutOfMemory,
1218 .dir => @panic("TODO"),1216 .dir => @panic("TODO"),
1219 }1217 }
1220 if (opt_env) |env| {1218 if (options.child_env) |child_env| {
1221 var it = env.child.iterator();1219 for (child_env.keys(), child_env.values()) |key, value| {
1222 while (it.next()) |entry| {1220 if (options.parent_env) |parent_env| {
1223 const key = entry.key_ptr.*;1221 if (parent_env.get(key)) |process_value| {
1224 const value = entry.value_ptr.*;1222 if (std.mem.eql(u8, value, process_value)) continue;
1225 if (env.parent.get(key)) |process_value| {1223 }
1226 if (std.mem.eql(u8, value, process_value)) continue;
1227 }1224 }
1228 writer.print("{s}=", .{key}) catch return error.OutOfMemory;1225 writer.print("{s}=", .{key}) catch return error.OutOfMemory;
1229 shell.escape(writer, value, false) catch return error.OutOfMemory;1226 shell.escape(writer, value, false) catch return error.OutOfMemory;
src/main.zig+11-2
...@@ -4987,7 +4987,7 @@ fn cmdBuild(...@@ -4987,7 +4987,7 @@ fn cmdBuild(
4987 const argv_index_zig_lib_dir = make_argv.items.len - 1;4987 const argv_index_zig_lib_dir = make_argv.items.len - 1;
49884988
4989 make_argv.addManyAsArrayAssumeCapacity(2).* = .{ "--build-root", undefined };4989 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
4992 make_argv.addManyAsArrayAssumeCapacity(2).* = .{ "--local-cache", undefined };4992 make_argv.addManyAsArrayAssumeCapacity(2).* = .{ "--local-cache", undefined };
4993 const argv_index_cache_dir = make_argv.items.len - 1;4993 const argv_index_cache_dir = make_argv.items.len - 1;
...@@ -5001,6 +5001,9 @@ fn cmdBuild(...@@ -5001,6 +5001,9 @@ fn cmdBuild(
5001 make_argv.addManyAsArrayAssumeCapacity(2).* = .{ "--seed", default_seed };5001 make_argv.addManyAsArrayAssumeCapacity(2).* = .{ "--seed", default_seed };
5002 const argv_index_seed = make_argv.items.len - 1;5002 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
5004 var color: Color = .auto;5007 var color: Color = .auto;
5005 var n_jobs: ?u32 = null;5008 var n_jobs: ?u32 = null;
50065009
...@@ -5065,6 +5068,10 @@ fn cmdBuild(...@@ -5065,6 +5068,10 @@ fn cmdBuild(
5065 i += 1;5068 i += 1;
5066 override_global_cache_dir = args[i];5069 override_global_cache_dir = args[i];
5067 continue;5070 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);
5068 } else if (mem.eql(u8, arg, "-freference-trace")) {5075 } else if (mem.eql(u8, arg, "-freference-trace")) {
5069 reference_trace = 256;5076 reference_trace = 256;
5070 } else if (mem.eql(u8, arg, "--fetch")) {5077 } else if (mem.eql(u8, arg, "--fetch")) {
...@@ -5283,10 +5290,12 @@ fn cmdBuild(...@@ -5283,10 +5290,12 @@ fn cmdBuild(
5283 defer _ = make_runner_task.cancel(io) catch {};5290 defer _ = make_runner_task.cancel(io) catch {};
52845291
5285 make_argv.items[argv_index_zig_lib_dir] = dirs.zig_lib.path orelse cwd_path;5292 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;
5287 make_argv.items[argv_index_global_cache_dir] = dirs.global_cache.path orelse cwd_path;5294 make_argv.items[argv_index_global_cache_dir] = dirs.global_cache.path orelse cwd_path;
5288 make_argv.items[argv_index_cache_dir] = dirs.local_cache.path orelse cwd_path;5295 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
5290 // Dummy http client that is not actually used when fetch_command is unsupported.5299 // Dummy http client that is not actually used when fetch_command is unsupported.
5291 // Prevents bootstrap from depending on a bunch of unnecessary stuff.5300 // Prevents bootstrap from depending on a bunch of unnecessary stuff.
5292 var http_client: if (dev.env.supports(.fetch_command)) std.http.Client else struct {5301 var http_client: if (dev.env.supports(.fetch_command)) std.http.Client else struct {