Maker.Step.Compile: progress towards lowering zig args

This commit is contained in:
Andrew Kelley 2026-02-19 13:50:56 -08:00
parent 224d0598e3
commit 8fbfcf34d1
9 changed files with 412 additions and 585 deletions

View file

@ -124,7 +124,6 @@ pub fn main(init: process.Init.Minimal) !void {
graph.cache.hash.addBytes(builtin.zig_version_string);
var step_names: std.ArrayList([]const u8) = .empty;
var debug_log_scopes: std.ArrayList([]const u8) = .empty;
var help_menu = false;
var steps_menu = false;
var print_configuration = false;
@ -143,10 +142,6 @@ pub fn main(init: process.Init.Minimal) !void {
var fuzz: ?Fuzz.Mode = null;
var debounce_interval_ms: u16 = 50;
var webui_listen: ?Io.net.IpAddress = null;
var verbose = false;
var sysroot: ?[]const u8 = null;
var search_prefixes: std.ArrayList([]const u8) = .empty;
var libc_file: ?[]const u8 = null;
var debug_pkg_config: bool = false;
// After following the steps in https://codeberg.org/ziglang/infra/src/branch/master/libc-update/glibc.md,
// this will be the directory $glibc-build-dir/install/glibcs
@ -159,7 +154,6 @@ pub fn main(init: process.Init.Minimal) !void {
var enable_wasmtime = false;
var enable_darling = false;
var enable_rosetta = false;
var reference_trace: ?u32 = null;
var run_args: ?[]const []const u8 = null;
if (std.zig.EnvVar.ZIG_BUILD_ERROR_STYLE.get(&graph.environ_map)) |str| {
@ -182,8 +176,6 @@ pub fn main(init: process.Init.Minimal) !void {
steps_menu = true;
} else if (mem.eql(u8, arg, "--print-configuration")) {
print_configuration = true;
} else if (mem.eql(u8, arg, "--verbose")) {
verbose = true;
} else if (mem.eql(u8, arg, "-p") or mem.eql(u8, arg, "--prefix")) {
override_install_prefix = nextArgOrFatal(args, &arg_idx);
} else if (mem.eql(u8, arg, "--prefix-lib-dir")) {
@ -193,11 +185,12 @@ pub fn main(init: process.Init.Minimal) !void {
} else if (mem.eql(u8, arg, "--prefix-include-dir")) {
override_include_dir = nextArgOrFatal(args, &arg_idx);
} else if (mem.eql(u8, arg, "--sysroot")) {
sysroot = nextArgOrFatal(args, &arg_idx);
graph.sysroot = nextArgOrFatal(args, &arg_idx);
} else if (mem.eql(u8, arg, "--maxrss")) {
// TODO refactor and reuse the fuzz number parsing here
const max_rss_text = nextArgOrFatal(args, &arg_idx);
max_rss = std.fmt.parseIntSizeSuffix(max_rss_text, 10) catch |err|
fatal("invalid byte size: '{s}': {t}", .{ max_rss_text, err });
fatal("invalid byte size {q}: {t}", .{ max_rss_text, err });
} else if (mem.eql(u8, arg, "--skip-oom-steps")) {
skip_oom_steps = true;
} else if (mem.eql(u8, arg, "--test-timeout")) {
@ -217,7 +210,7 @@ pub fn main(init: process.Init.Minimal) !void {
};
const timeout_str = nextArgOrFatal(args, &arg_idx);
const num_end_idx = std.mem.findLastNone(u8, timeout_str, "abcdefghijklmnopqrstuvwxyz") orelse fatal(
"invalid timeout '{s}': expected unit (ns, us, ms, s, m, h)",
"invalid timeout {q}: expected unit (ns, us, ms, s, m, h)",
.{timeout_str},
);
const num_str = timeout_str[0 .. num_end_idx + 1];
@ -227,57 +220,63 @@ pub fn main(init: process.Init.Minimal) !void {
break @floatFromInt(unit_and_factor[1]);
}
} else fatal(
"invalid timeout '{s}': invalid unit '{s}' (expected ns, us, ms, s, m, h)",
"invalid timeout {q}: invalid unit {q} (expected ns, us, ms, s, m, h)",
.{ timeout_str, unit_str },
);
const num_parsed = std.fmt.parseFloat(f64, num_str) catch |err| fatal(
"invalid timeout '{s}': invalid number '{s}' ({t})",
"invalid timeout {q}: invalid number {q} ({t})",
.{ timeout_str, num_str, err },
);
test_timeout_ns = std.math.lossyCast(u64, unit_factor * num_parsed);
} else if (mem.eql(u8, arg, "--search-prefix")) {
try search_prefixes.append(arena, nextArgOrFatal(args, &arg_idx));
try graph.search_prefixes.append(arena, nextArgOrFatal(args, &arg_idx));
} else if (mem.eql(u8, arg, "--libc")) {
libc_file = nextArgOrFatal(args, &arg_idx);
graph.libc_file = nextArgOrFatal(args, &arg_idx);
} else if (mem.eql(u8, arg, "--color")) {
const next_arg = nextArg(args, &arg_idx) orelse
fatalWithHint("expected [auto|on|off] after '{s}'", .{arg});
fatalWithHint("expected [auto|on|off] after {q}", .{arg});
color = std.meta.stringToEnum(Color, next_arg) orelse {
fatalWithHint("expected [auto|on|off] after '{s}', found '{s}'", .{
fatalWithHint("expected [auto|on|off] after {q}, found {q}", .{
arg, next_arg,
});
};
} else if (mem.eql(u8, arg, "--error-style")) {
const next_arg = nextArg(args, &arg_idx) orelse
fatalWithHint("expected style after '{s}'", .{arg});
fatalWithHint("expected style after {q}", .{arg});
error_style = std.meta.stringToEnum(ErrorStyle, next_arg) orelse {
fatalWithHint("expected style after '{s}', found '{s}'", .{ arg, next_arg });
fatalWithHint("expected style after {q}, found {q}", .{ arg, next_arg });
};
} else if (mem.eql(u8, arg, "--multiline-errors")) {
const next_arg = nextArg(args, &arg_idx) orelse
fatalWithHint("expected style after '{s}'", .{arg});
fatalWithHint("expected style after {q}", .{arg});
multiline_errors = std.meta.stringToEnum(MultilineErrors, next_arg) orelse {
fatalWithHint("expected style after '{s}', found '{s}'", .{ arg, next_arg });
fatalWithHint("expected style after {q}, found {q}", .{ arg, next_arg });
};
} else if (mem.eql(u8, arg, "--summary")) {
const next_arg = nextArg(args, &arg_idx) orelse
fatalWithHint("expected [all|new|failures|line|none] after '{s}'", .{arg});
fatalWithHint("expected [all|new|failures|line|none] after {q}", .{arg});
summary = std.meta.stringToEnum(Summary, next_arg) orelse {
fatalWithHint("expected [all|new|failures|line|none] after '{s}', found '{s}'", .{
fatalWithHint("expected [all|new|failures|line|none] after {q}, found {q}", .{
arg, next_arg,
});
};
} else if (mem.eql(u8, arg, "--seed")) {
const next_arg = nextArg(args, &arg_idx) orelse
fatalWithHint("expected u32 after '{s}'", .{arg});
fatalWithHint("expected u32 after {q}", .{arg});
graph.random_seed = std.fmt.parseUnsigned(u32, next_arg, 0) catch |err| {
fatal("unable to parse seed '{s}' as unsigned 32-bit integer: {t}", .{ next_arg, err });
fatal("unable to parse seed {q} as unsigned 32-bit integer: {t}", .{ next_arg, err });
};
} else if (mem.eql(u8, arg, "--build-id")) {
graph.build_id = .fast;
} else if (mem.cutPrefix(u8, arg, "--build-id=")) |style| {
graph.build_id = std.zig.BuildId.parse(style) catch |err|
fatal("unable to parse --build-id style {q}: {t}", .{ style, err });
} else if (mem.eql(u8, arg, "--debounce")) {
// TODO refactor and reuse the timeout parsing code also here
const next_arg = nextArg(args, &arg_idx) orelse
fatalWithHint("expected u16 after '{s}'", .{arg});
fatalWithHint("expected u16 after {q}", .{arg});
debounce_interval_ms = std.fmt.parseUnsigned(u16, next_arg, 0) catch |err| {
fatal("unable to parse debounce interval '{s}' as unsigned 16-bit integer: {t}\n", .{
fatal("unable to parse debounce interval {q} as unsigned 16-bit integer: {t}", .{
next_arg, err,
});
};
@ -287,11 +286,15 @@ pub fn main(init: process.Init.Minimal) !void {
const addr_str = arg["--webui=".len..];
if (std.mem.eql(u8, addr_str, "-")) fatal("web interface cannot listen on stdio", .{});
webui_listen = Io.net.IpAddress.parseLiteral(addr_str) catch |err| {
fatal("invalid web UI address '{s}': {t}", .{ addr_str, err });
fatal("invalid web UI address {q}: {t}", .{ addr_str, err });
};
} else if (mem.eql(u8, arg, "--debug-log")) {
const next_arg = nextArgOrFatal(args, &arg_idx);
try debug_log_scopes.append(arena, next_arg);
try graph.debug_log_scopes.append(arena, next_arg);
} else if (mem.eql(u8, arg, "--debug-compile-errors")) {
graph.debug_compile_errors = true;
} else if (mem.eql(u8, arg, "--debug-incremental")) {
graph.debug_incremental = true;
} else if (mem.eql(u8, arg, "--debug-pkg-config")) {
debug_pkg_config = true;
} else if (mem.eql(u8, arg, "--debug-rt")) {
@ -301,6 +304,16 @@ pub fn main(init: process.Init.Minimal) !void {
fatal("unrecognized optimization mode: {s}", .{rest});
} else if (mem.eql(u8, arg, "--libc-runtimes")) {
libc_runtimes_dir = nextArgOrFatal(args, &arg_idx);
} else if (mem.eql(u8, arg, "--verbose")) {
graph.verbose = true;
} else if (mem.eql(u8, arg, "--verbose-cimport")) {
graph.verbose_cimport = true;
} else if (mem.eql(u8, arg, "--verbose-air")) {
graph.verbose_air = true;
} else if (mem.eql(u8, arg, "--verbose-cc")) {
graph.verbose_cc = true;
} else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
graph.verbose_llvm_ir = true;
} else if (mem.eql(u8, arg, "--watch")) {
watch = true;
} else if (mem.eql(u8, arg, "--time-report")) {
@ -372,25 +385,22 @@ pub fn main(init: process.Init.Minimal) !void {
} else if (mem.eql(u8, arg, "-fno-allow-so-scripts")) {
graph.allow_so_scripts = false;
} else if (mem.eql(u8, arg, "-freference-trace")) {
reference_trace = 256;
} else if (mem.startsWith(u8, arg, "-freference-trace=")) {
const num = arg["-freference-trace=".len..];
reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
std.debug.print("unable to parse reference_trace count '{s}': {t}", .{ num, err });
process.exit(1);
};
graph.reference_trace = 256;
} else if (mem.cutPrefix(u8, arg, "-freference-trace=")) |num| {
graph.reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err|
fatal("unable to parse reference_trace count {q}: {t}", .{ num, err });
} else if (mem.eql(u8, arg, "-fno-reference-trace")) {
reference_trace = null;
graph.reference_trace = null;
} else if (mem.cutPrefix(u8, arg, "-j")) |text| {
const n = std.fmt.parseUnsigned(u32, text, 10) catch |err|
fatal("unable to parse jobs count '{s}': {t}", .{ text, err });
fatal("unable to parse jobs count {q}: {t}", .{ text, err });
if (n < 1) fatal("number of jobs must be at least 1", .{});
threaded.setAsyncLimit(.limited(n));
} else if (mem.eql(u8, arg, "--")) {
run_args = argsRest(args, arg_idx);
break;
} else {
fatalWithHint("unrecognized argument: '{s}'", .{arg});
fatalWithHint("unrecognized argument: {s}", .{arg});
}
} else {
try step_names.append(arena, arg);
@ -1841,8 +1851,7 @@ const ScannedConfig = struct {
\\ --debug-rt Debug compiler runtime libraries
\\ --verbose-link Enable compiler debug output for linking
\\ --verbose-air Enable compiler debug output for Zig AIR
\\ --verbose-llvm-ir[=file] Enable compiler debug output for LLVM IR
\\ --verbose-llvm-bc=[file] Enable compiler debug output for LLVM BC
\\ --verbose-llvm-ir Enable compiler debug output for LLVM IR
\\ --verbose-cimport Enable compiler debug output for C imports
\\ --verbose-cc Enable compiler debug output for C compilation
\\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features

View file

@ -23,3 +23,24 @@ time_report: bool = false,
/// Similar to the `Io.Terminal.Mode` returned by `Io.lockStderr`, but also
/// respects the '--color' flag.
stderr_mode: ?Io.Terminal.Mode = null,
reference_trace: ?u32 = null,
debug_log_scopes: std.ArrayList([]const u8) = .empty,
debug_compile_errors: bool = false,
debug_incremental: bool = false,
verbose: bool = false,
verbose_air: bool = false,
verbose_cc: bool = false,
verbose_cimport: bool = false,
verbose_link: bool = false,
verbose_llvm_cpu_features: bool = false,
verbose_llvm_ir: bool = false,
libc_file: ?[]const u8 = null,
/// What does this do? Nobody bothered to document it, and I think it's a
/// smelly option. So unless somebody deletes these passive aggressive comments
/// and replaces them with actual documentation, I'm going to delete this
/// option from the build system in a future release. In other words, this is
/// deprecated due to lack of test coverage, lack of documentation, and a hunch
/// that it's a bad option that should be avoided.
sysroot: ?[]const u8 = null,
search_prefixes: std.ArrayList([]const u8) = .empty,
build_id: ?std.zig.BuildId = null,

View file

@ -298,7 +298,7 @@ pub fn captureChildProcess(
// If an error occurs, it's happened in this command:
assert(s.result_failed_command == null);
s.result_failed_command = try allocPrintCmd(gpa, .inherit, null, argv);
s.result_failed_command = try std.zig.allocPrintCmd(gpa, .inherit, null, argv);
try handleChildProcUnsupported(s);
try handleVerbose(s, .inherit, argv);
@ -354,15 +354,15 @@ pub fn evalZigProcess(
argv: []const []const u8,
prog_node: std.Progress.Node,
watch: bool,
web_server: ?*WebServer,
gpa: Allocator,
maker: *Maker,
) !?Cache.Path {
const gpa = maker.gpa;
const b = s.owner;
const io = b.graph.io;
// If an error occurs, it's happened in this command:
assert(s.result_failed_command == null);
s.result_failed_command = try allocPrintCmd(gpa, .inherit, null, argv);
s.result_failed_command = try std.zig.allocPrintCmd(gpa, .inherit, null, argv);
if (s.getZigProcess()) |zp| update: {
assert(watch);
@ -374,7 +374,7 @@ pub fn evalZigProcess(
zp.deinit(io);
gpa.destroy(zp);
} else zp.saveState(prog_node);
const result = zigProcessUpdate(s, zp, watch, web_server, gpa) catch |err| switch (err) {
const result = zigProcessUpdate(s, zp, watch, maker) catch |err| switch (err) {
error.BrokenPipe, error.EndOfStream => |reason| {
std.log.info("{s} restart required: {t}", .{ argv[0], reason });
// Process restart required.
@ -431,7 +431,7 @@ pub fn evalZigProcess(
const result = result: {
defer if (watch) zp.saveState(prog_node);
break :result try zigProcessUpdate(s, zp, watch, web_server, gpa);
break :result try zigProcessUpdate(s, zp, watch, maker);
};
if (!watch) {
@ -485,7 +485,8 @@ pub fn installDir(s: *Step, dest_path: []const u8) !Io.Dir.CreatePathStatus {
return s.fail("unable to create dir '{s}': {t}", .{ dest_path, err });
}
fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool, web_server: ?*WebServer, gpa: Allocator) !?Path {
fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool, maker: *Maker) !?Path {
const gpa = maker.gpa;
const b = s.owner;
const arena = b.allocator;
const io = b.graph.io;
@ -586,7 +587,7 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool, web_server: ?*WebSer
}
}
},
.time_report => if (web_server) |ws| {
.time_report => if (maker.web_server) |ws| {
const TimeReport = std.zig.Server.Message.TimeReport;
const tr: *align(1) const TimeReport = @ptrCast(body[0..@sizeOf(TimeReport)]);
ws.updateTimeReportCompile(.{
@ -641,11 +642,11 @@ pub fn handleVerbose(
opt_env: ?*const std.process.Environ.Map,
argv: []const []const u8,
) error{OutOfMemory}!void {
if (!s.verbose) return;
const graph = s.graph;
if (!graph.verbose) return;
// Intention of verbose is to print all sub-process command lines to
// stderr before spawning them.
const text = try allocPrintCmd(arena, cwd, if (opt_env) |env| .{
const text = try std.zig.allocPrintCmd(arena, cwd, if (opt_env) |env| .{
.child = env,
.parent = &graph.environ_map,
} else null, argv);
@ -843,79 +844,6 @@ fn addWatchInputFromPath(step: *Step, path: Cache.Path, basename: []const u8) !v
try gop.value_ptr.append(gpa, basename);
}
pub fn allocPrintCmd(
gpa: Allocator,
cwd: std.process.Child.Cwd,
opt_env: ?struct {
child: *const std.process.Environ.Map,
parent: *const std.process.Environ.Map,
},
argv: []const []const u8,
) Allocator.Error![]u8 {
const shell = struct {
fn escape(writer: *Io.Writer, string: []const u8, is_argv0: bool) !void {
for (string) |c| {
if (switch (c) {
else => true,
'%', '+'...':', '@'...'Z', '_', 'a'...'z' => false,
'=' => is_argv0,
}) break;
} else return writer.writeAll(string);
try writer.writeByte('"');
for (string) |c| {
if (switch (c) {
std.ascii.control_code.nul => break,
'!', '"', '$', '\\', '`' => true,
else => !std.ascii.isPrint(c),
}) try writer.writeByte('\\');
switch (c) {
std.ascii.control_code.nul => unreachable,
std.ascii.control_code.bel => try writer.writeByte('a'),
std.ascii.control_code.bs => try writer.writeByte('b'),
std.ascii.control_code.ht => try writer.writeByte('t'),
std.ascii.control_code.lf => try writer.writeByte('n'),
std.ascii.control_code.vt => try writer.writeByte('v'),
std.ascii.control_code.ff => try writer.writeByte('f'),
std.ascii.control_code.cr => try writer.writeByte('r'),
std.ascii.control_code.esc => try writer.writeByte('E'),
' '...'~' => try writer.writeByte(c),
else => try writer.print("{o:0>3}", .{c}),
}
}
try writer.writeByte('"');
}
};
var aw: Io.Writer.Allocating = .init(gpa);
defer aw.deinit();
const writer = &aw.writer;
switch (cwd) {
.inherit => {},
.path => |path| writer.print("cd {s} && ", .{path}) catch return error.OutOfMemory,
.dir => @panic("TODO"),
}
if (opt_env) |env| {
var it = env.child.iterator();
while (it.next()) |entry| {
const key = entry.key_ptr.*;
const value = entry.value_ptr.*;
if (env.parent.get(key)) |process_value| {
if (std.mem.eql(u8, value, process_value)) continue;
}
writer.print("{s}=", .{key}) catch return error.OutOfMemory;
shell.escape(writer, value, false) catch return error.OutOfMemory;
writer.writeByte(' ') catch return error.OutOfMemory;
}
}
shell.escape(writer, argv[0], true) catch return error.OutOfMemory;
for (argv[1..]) |arg| {
writer.writeByte(' ') catch return error.OutOfMemory;
shell.escape(writer, arg, false) catch return error.OutOfMemory;
}
return aw.toOwnedSlice();
}
fn oomWrap(s: *Step, result: error{OutOfMemory}!void) void {
result catch {
s.result_oom = true;

View file

@ -10,6 +10,7 @@ const Io = std.Io;
const Sha256 = std.crypto.hash.sha2.Sha256;
const assert = std.debug.assert;
const mem = std.mem;
const allocPrint = std.fmt.allocPrint;
const Step = @import("../Step.zig");
const Maker = @import("../../Maker.zig");
@ -17,6 +18,8 @@ const Maker = @import("../../Maker.zig");
/// Populated during the make phase when there is a long-lived compiler process.
/// Managed by the build runner, not user build script.
zig_process: ?*Step.ZigProcess = null,
/// Persisted to reuse memory on subsequent make.
zig_args: std.ArrayList([]const u8) = .empty,
pub fn make(
compile: *Compile,
@ -24,14 +27,15 @@ pub fn make(
maker: *Maker,
progress_node: std.Progress.Node,
) Step.ExtendedMakeError!void {
if (true) @panic("TODO implement compile.make()");
const graph = maker.graph;
const step = maker.stepByIndex(step_index);
const zig_args = try getZigArgs(compile, maker, false);
compile.zig_args.clearRetainingCapacity();
if (true) @panic("TODO implement compile.make()");
try lowerZigArgs(compile, step_index, maker, &compile.zig_args, false);
const process_arena = graph.arena; // TODO don't leak into the process_arena
const maybe_output_dir = step.evalZigProcess(
zig_args,
compile.zig_args.items,
progress_node,
(graph.incremental == true) and (maker.watch or maker.web_server != null),
maker,
@ -47,7 +51,7 @@ pub fn make(
// Update generated files
if (maybe_output_dir) |output_dir| {
if (compile.emit_directory) |lp| {
lp.path = try std.fmt.allocPrint(process_arena, "{f}", .{output_dir});
lp.path = try allocPrint(process_arena, "{f}", .{output_dir});
}
// zig fmt: off
@ -68,23 +72,26 @@ pub fn make(
{
try doAtomicSymLinks(
step,
compile.getEmittedBin().getPath2(step.owner, step),
compile.getEmittedBin().getPath2(step),
compile.major_only_filename.?,
compile.name_only_filename.?,
);
}
}
fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
const step = &compile.step;
const b = step.owner;
fn lowerZigArgs(
compile: *Compile,
step_index: Configuration.Step.Index,
maker: *Maker,
zig_args: *std.ArrayList([]const u8),
fuzz: bool,
) Allocator.Error!void {
const step = maker.stepByIndex(step_index);
const graph = maker.graph;
const arena = graph.arena; // TODO don't leak into the process arena
const gpa = maker.gpa;
var zig_args = std.array_list.Managed([]const u8).init(arena);
defer zig_args.deinit();
try zig_args.append(graph.zig_exe);
try zig_args.append(gpa, graph.zig_exe);
const cmd = switch (compile.kind) {
.lib => "build-lib",
@ -93,10 +100,10 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
.@"test" => "test",
.test_obj => "test-obj",
};
try zig_args.append(cmd);
try zig_args.append(gpa, cmd);
if (b.reference_trace) |some| {
try zig_args.append(try std.fmt.allocPrint(arena, "-freference-trace={d}", .{some}));
if (graph.reference_trace) |some| {
try zig_args.append(gpa, try allocPrint(arena, "-freference-trace={d}", .{some}));
}
try addFlag(&zig_args, "allow-so-scripts", compile.allow_so_scripts orelse graph.allow_so_scripts);
@ -105,33 +112,31 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
try addFlag(&zig_args, "new-linker", compile.use_new_linker);
if (compile.root_module.resolved_target.?.query.ofmt) |ofmt| {
try zig_args.append(try std.fmt.allocPrint(arena, "-ofmt={s}", .{@tagName(ofmt)}));
try zig_args.append(gpa, try allocPrint(arena, "-ofmt={t}", .{ofmt}));
}
switch (compile.entry) {
.default => {},
.disabled => try zig_args.append("-fno-entry"),
.enabled => try zig_args.append("-fentry"),
.disabled => try zig_args.append(gpa, "-fno-entry"),
.enabled => try zig_args.append(gpa, "-fentry"),
.symbol_name => |entry_name| {
try zig_args.append(try std.fmt.allocPrint(arena, "-fentry={s}", .{entry_name}));
try zig_args.append(gpa, try allocPrint(arena, "-fentry={s}", .{entry_name}));
},
}
{
for (compile.force_undefined_symbols.keys()) |symbol_name| {
try zig_args.append("--force_undefined");
try zig_args.append(symbol_name.*);
try zig_args.append(gpa, "--force_undefined");
try zig_args.append(gpa, symbol_name.*);
}
}
if (compile.stack_size) |stack_size| {
try zig_args.append("--stack");
try zig_args.append(try std.fmt.allocPrint(arena, "{}", .{stack_size}));
try zig_args.append(gpa, "--stack");
try zig_args.append(gpa, try allocPrint(arena, "{}", .{stack_size}));
}
if (fuzz) {
try zig_args.append("-ffuzz");
}
try addBool(gpa, zig_args, fuzz, "-ffuzz");
{
// Stores system libraries that have already been seen for at least one
@ -181,14 +186,14 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
switch (link_object) {
.static_path => |static_path| {
if (my_responsibility) {
try zig_args.append(static_path.getPath2(mod.owner, step));
try zig_args.append(gpa, static_path.getPath2(step));
total_linker_objects += 1;
}
},
.system_lib => |system_lib| {
const system_lib_gop = try seen_system_libs.getOrPut(arena, system_lib.name);
if (system_lib_gop.found_existing) {
try zig_args.appendSlice(system_lib_gop.value_ptr.*);
try zig_args.appendSlice(gpa, system_lib_gop.value_ptr.*);
continue;
} else {
system_lib_gop.value_ptr.* = &.{};
@ -203,16 +208,16 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
{
switch (system_lib.search_strategy) {
.no_fallback => switch (system_lib.preferred_link_mode) {
.dynamic => try zig_args.append("-search_dylibs_only"),
.static => try zig_args.append("-search_static_only"),
.dynamic => try zig_args.append(gpa, "-search_dylibs_only"),
.static => try zig_args.append(gpa, "-search_static_only"),
},
.paths_first => switch (system_lib.preferred_link_mode) {
.dynamic => try zig_args.append("-search_paths_first"),
.static => try zig_args.append("-search_paths_first_static"),
.dynamic => try zig_args.append(gpa, "-search_paths_first"),
.static => try zig_args.append(gpa, "-search_paths_first_static"),
},
.mode_first => switch (system_lib.preferred_link_mode) {
.dynamic => try zig_args.append("-search_dylibs_first"),
.static => try zig_args.append("-search_static_first"),
.dynamic => try zig_args.append(gpa, "-search_dylibs_first"),
.static => try zig_args.append(gpa, "-search_static_first"),
},
}
prev_search_strategy = system_lib.search_strategy;
@ -225,11 +230,11 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
break :prefix "-l";
};
switch (system_lib.use_pkg_config) {
.no => try zig_args.append(b.fmt("{s}{s}", .{ prefix, system_lib.name })),
.no => try zig_args.append(gpa, try allocPrint(arena, "{s}{s}", .{ prefix, system_lib.name })),
.yes, .force => {
if (compile.runPkgConfig(maker, system_lib.name)) |result| {
try zig_args.appendSlice(result.cflags);
try zig_args.appendSlice(result.libs);
try zig_args.appendSlice(gpa, result.cflags);
try zig_args.appendSlice(gpa, result.libs);
try seen_system_libs.put(arena, system_lib.name, result.cflags);
} else |err| switch (err) {
error.PkgConfigInvalidOutput,
@ -241,7 +246,7 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
.yes => {
// pkg-config failed, so fall back to linking the library
// by name directly.
try zig_args.append(b.fmt("{s}{s}", .{
try zig_args.append(gpa, try allocPrint(arena, "{s}{s}", .{
prefix,
system_lib.name,
}));
@ -265,7 +270,7 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
const included_in_lib_or_obj = !my_responsibility and
(dep_compile.kind == .lib or dep_compile.kind == .obj or dep_compile.kind == .test_obj);
if (!already_linked and !included_in_lib_or_obj) {
try zig_args.append(other.getEmittedBin().getPath2(b, step));
try zig_args.append(gpa, other.getEmittedBin().getPath2(step));
total_linker_objects += 1;
}
},
@ -286,15 +291,15 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
else
try other.getGeneratedFilePath("generated_bin", &compile.step);
try zig_args.append(full_path_lib);
try zig_args.append(gpa, full_path_lib);
total_linker_objects += 1;
if (other.linkage == .dynamic and
compile.rootModuleTarget().os.tag != .windows)
{
if (Dir.path.dirname(full_path_lib)) |dirname| {
try zig_args.append("-rpath");
try zig_args.append(dirname);
try zig_args.append(gpa, "-rpath");
try zig_args.append(gpa, dirname);
}
}
},
@ -304,11 +309,11 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
if (!my_responsibility) break :l;
if (prev_has_cflags) {
try zig_args.append("-cflags");
try zig_args.append("--");
try zig_args.append(gpa, "-cflags");
try zig_args.append(gpa, "--");
prev_has_cflags = false;
}
try zig_args.append(asm_file.getPath2(mod.owner, step));
try zig_args.append(gpa, asm_file.getPath2(mod.owner, step));
total_linker_objects += 1;
},
@ -316,24 +321,24 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
if (!my_responsibility) break :l;
if (prev_has_cflags or c_source_file.flags.len != 0) {
try zig_args.append("-cflags");
try zig_args.append(gpa, "-cflags");
for (c_source_file.flags) |arg| {
try zig_args.append(arg);
try zig_args.append(gpa, arg);
}
try zig_args.append("--");
try zig_args.append(gpa, "--");
}
prev_has_cflags = (c_source_file.flags.len != 0);
if (c_source_file.language) |lang| {
try zig_args.append("-x");
try zig_args.append(lang.internalIdentifier());
try zig_args.append(gpa, "-x");
try zig_args.append(gpa, lang.internalIdentifier());
}
try zig_args.append(c_source_file.file.getPath2(mod.owner, step));
try zig_args.append(gpa, c_source_file.file.getPath2(mod.owner, step));
if (c_source_file.language != null) {
try zig_args.append("-x");
try zig_args.append("none");
try zig_args.append(gpa, "-x");
try zig_args.append(gpa, "none");
}
total_linker_objects += 1;
},
@ -342,27 +347,27 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
if (!my_responsibility) break :l;
if (prev_has_cflags or c_source_files.flags.len != 0) {
try zig_args.append("-cflags");
try zig_args.append(gpa, "-cflags");
for (c_source_files.flags) |arg| {
try zig_args.append(arg);
try zig_args.append(gpa, arg);
}
try zig_args.append("--");
try zig_args.append(gpa, "--");
}
prev_has_cflags = (c_source_files.flags.len != 0);
if (c_source_files.language) |lang| {
try zig_args.append("-x");
try zig_args.append(lang.internalIdentifier());
try zig_args.append(gpa, "-x");
try zig_args.append(gpa, lang.internalIdentifier());
}
const root_path = c_source_files.root.getPath2(mod.owner, step);
for (c_source_files.files) |file| {
try zig_args.append(b.pathJoin(&.{ root_path, file }));
try zig_args.append(gpa, try Dir.path.join(arena, &.{ root_path, file }));
}
if (c_source_files.language != null) {
try zig_args.append("-x");
try zig_args.append("none");
try zig_args.append(gpa, "-x");
try zig_args.append(gpa, "none");
}
total_linker_objects += c_source_files.files.len;
@ -373,23 +378,23 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
if (rc_source_file.flags.len == 0 and rc_source_file.include_paths.len == 0) {
if (prev_has_rcflags) {
try zig_args.append("-rcflags");
try zig_args.append("--");
try zig_args.append(gpa, "-rcflags");
try zig_args.append(gpa, "--");
prev_has_rcflags = false;
}
} else {
try zig_args.append("-rcflags");
try zig_args.append(gpa, "-rcflags");
for (rc_source_file.flags) |arg| {
try zig_args.append(arg);
try zig_args.append(gpa, arg);
}
for (rc_source_file.include_paths) |include_path| {
try zig_args.append("/I");
try zig_args.append(include_path.getPath2(mod.owner, step));
try zig_args.append(gpa, "/I");
try zig_args.append(gpa, include_path.getPath2(mod.owner, step));
}
try zig_args.append("--");
try zig_args.append(gpa, "--");
prev_has_rcflags = true;
}
try zig_args.append(rc_source_file.file.getPath2(mod.owner, step));
try zig_args.append(gpa, rc_source_file.file.getPath2(mod.owner, step));
total_linker_objects += 1;
},
}
@ -412,7 +417,7 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
if (std.mem.eql(u8, import_cli_name, name)) {
zig_args.appendAssumeCapacity(import_cli_name);
} else {
zig_args.appendAssumeCapacity(b.fmt("{s}={s}", .{ name, import_cli_name }));
zig_args.appendAssumeCapacity(try allocPrint(arena, "{s}={s}", .{ name, import_cli_name }));
}
}
@ -425,9 +430,9 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
// files must have a module parent.
if (mod.root_source_file) |lp| {
const src = lp.getPath2(mod.owner, step);
try zig_args.append(b.fmt("-M{s}={s}", .{ module_cli_name, src }));
try zig_args.append(gpa, try allocPrint(arena, "-M{s}={s}", .{ module_cli_name, src }));
} else if (moduleNeedsCliArg(mod)) {
try zig_args.append(b.fmt("-M{s}", .{module_cli_name}));
try zig_args.append(gpa, try allocPrint(arena, "-M{s}", .{module_cli_name}));
}
}
}
@ -439,276 +444,249 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
for (frameworks.keys(), frameworks.values()) |name, info| {
if (info.needed) {
try zig_args.append("-needed_framework");
try zig_args.append(gpa, "-needed_framework");
} else if (info.weak) {
try zig_args.append("-weak_framework");
try zig_args.append(gpa, "-weak_framework");
} else {
try zig_args.append("-framework");
try zig_args.append(gpa, "-framework");
}
try zig_args.append(name);
try zig_args.append(gpa, name);
}
if (compile.is_linking_libcpp) {
try zig_args.append("-lc++");
try zig_args.append(gpa, "-lc++");
}
if (compile.is_linking_libc) {
try zig_args.append("-lc");
try zig_args.append(gpa, "-lc");
}
}
if (compile.win32_manifest) |manifest_file| {
try zig_args.append(manifest_file.getPath2(b, step));
try zig_args.append(gpa, manifest_file.getPath2(step));
}
if (compile.win32_module_definition) |module_file| {
try zig_args.append(module_file.getPath2(b, step));
try zig_args.append(gpa, module_file.getPath2(step));
}
if (compile.image_base) |image_base| {
try zig_args.append("--image-base");
try zig_args.append(b.fmt("0x{x}", .{image_base}));
try zig_args.appendSlice(gpa, &.{
"--image-base", try allocPrint(arena, "0x{x}", .{image_base}),
});
}
for (compile.filters) |filter| {
try zig_args.append("--test-filter");
try zig_args.append(filter);
try zig_args.appendSlice(gpa, &.{ "--test-filter", filter });
}
if (compile.test_runner) |test_runner| {
try zig_args.append("--test-runner");
try zig_args.append(test_runner.path.getPath2(b, step));
try zig_args.appendSlice(gpa, &.{ "--test-runner", test_runner.path.getPath2(step) });
}
for (b.debug_log_scopes) |log_scope| {
try zig_args.append("--debug-log");
try zig_args.append(log_scope);
for (graph.debug_log_scopes) |log_scope| {
try zig_args.appendSlice(gpa, &.{ "--debug-log", log_scope });
}
if (b.debug_compile_errors) {
try zig_args.append("--debug-compile-errors");
}
try addBool(gpa, zig_args, graph.debug_compile_errors, "--debug-compile-errors");
try addBool(gpa, zig_args, graph.debug_incremental, "--debug-incremental");
try addBool(gpa, zig_args, graph.verbose_cimport, "--verbose-cimport");
try addBool(gpa, zig_args, graph.verbose_air, "--verbose-air");
try addBool(gpa, zig_args, graph.verbose_llvm_ir, "--verbose-llvm-ir");
try addBool(gpa, zig_args, graph.verbose_link or compile.verbose_link, "--verbose-link");
try addBool(gpa, zig_args, graph.verbose_cc or compile.verbose_cc, "--verbose-cc");
try addBool(gpa, zig_args, graph.verbose_llvm_cpu_features, "--verbose-llvm-cpu-features");
try addBool(gpa, zig_args, graph.time_report, "--time-report");
if (b.debug_incremental) {
try zig_args.append("--debug-incremental");
}
if (b.verbose_cimport) try zig_args.append("--verbose-cimport");
if (b.verbose_air) try zig_args.append("--verbose-air");
if (b.verbose_llvm_ir) |path| try zig_args.append(b.fmt("--verbose-llvm-ir={s}", .{path}));
if (b.verbose_llvm_bc) |path| try zig_args.append(b.fmt("--verbose-llvm-bc={s}", .{path}));
if (b.verbose_link or compile.verbose_link) try zig_args.append("--verbose-link");
if (b.verbose_cc or compile.verbose_cc) try zig_args.append("--verbose-cc");
if (b.verbose_llvm_cpu_features) try zig_args.append("--verbose-llvm-cpu-features");
if (graph.time_report) try zig_args.append("--time-report");
if (compile.generated_asm != null) try zig_args.append("-femit-asm");
if (compile.generated_bin == null) try zig_args.append("-fno-emit-bin");
if (compile.generated_docs != null) try zig_args.append("-femit-docs");
if (compile.generated_implib != null) try zig_args.append("-femit-implib");
if (compile.generated_llvm_bc != null) try zig_args.append("-femit-llvm-bc");
if (compile.generated_llvm_ir != null) try zig_args.append("-femit-llvm-ir");
if (compile.generated_h != null) try zig_args.append("-femit-h");
if (compile.generated_asm != null) try zig_args.append(gpa, "-femit-asm");
if (compile.generated_bin == null) try zig_args.append(gpa, "-fno-emit-bin");
if (compile.generated_docs != null) try zig_args.append(gpa, "-femit-docs");
if (compile.generated_implib != null) try zig_args.append(gpa, "-femit-implib");
if (compile.generated_llvm_bc != null) try zig_args.append(gpa, "-femit-llvm-bc");
if (compile.generated_llvm_ir != null) try zig_args.append(gpa, "-femit-llvm-ir");
if (compile.generated_h != null) try zig_args.append(gpa, "-femit-h");
try addFlag(&zig_args, "formatted-panics", compile.formatted_panics);
switch (compile.compress_debug_sections) {
.none => {},
.zlib => try zig_args.append("--compress-debug-sections=zlib"),
.zstd => try zig_args.append("--compress-debug-sections=zstd"),
.zlib => try zig_args.append(gpa, "--compress-debug-sections=zlib"),
.zstd => try zig_args.append(gpa, "--compress-debug-sections=zstd"),
}
if (compile.link_eh_frame_hdr) {
try zig_args.append("--eh-frame-hdr");
try zig_args.append(gpa, "--eh-frame-hdr");
}
if (compile.link_emit_relocs) {
try zig_args.append("--emit-relocs");
try zig_args.append(gpa, "--emit-relocs");
}
if (compile.link_function_sections) {
try zig_args.append("-ffunction-sections");
try zig_args.append(gpa, "-ffunction-sections");
}
if (compile.link_data_sections) {
try zig_args.append("-fdata-sections");
try zig_args.append(gpa, "-fdata-sections");
}
if (compile.link_gc_sections) |x| {
try zig_args.append(if (x) "--gc-sections" else "--no-gc-sections");
try zig_args.append(gpa, if (x) "--gc-sections" else "--no-gc-sections");
}
if (!compile.linker_dynamicbase) {
try zig_args.append("--no-dynamicbase");
try zig_args.append(gpa, "--no-dynamicbase");
}
if (compile.linker_allow_shlib_undefined) |x| {
try zig_args.append(if (x) "-fallow-shlib-undefined" else "-fno-allow-shlib-undefined");
}
if (compile.link_z_notext) {
try zig_args.append("-z");
try zig_args.append("notext");
}
if (!compile.link_z_relro) {
try zig_args.append("-z");
try zig_args.append("norelro");
}
if (compile.link_z_lazy) {
try zig_args.append("-z");
try zig_args.append("lazy");
}
if (compile.link_z_common_page_size) |size| {
try zig_args.append("-z");
try zig_args.append(b.fmt("common-page-size={d}", .{size}));
}
if (compile.link_z_max_page_size) |size| {
try zig_args.append("-z");
try zig_args.append(b.fmt("max-page-size={d}", .{size}));
}
if (compile.link_z_defs) {
try zig_args.append("-z");
try zig_args.append("defs");
try zig_args.append(gpa, if (x) "-fallow-shlib-undefined" else "-fno-allow-shlib-undefined");
}
if (compile.link_z_notext) try zig_args.appendSlice(gpa, &.{ "-z", "notext" });
if (!compile.link_z_relro) try zig_args.appendSlice(gpa, &.{ "-z", "norelro" });
if (compile.link_z_lazy) try zig_args.appendSlice(gpa, &.{ "-z", "lazy" });
if (compile.link_z_common_page_size) |size| try zig_args.appendSlice(gpa, &.{
"-z",
try allocPrint(arena, "common-page-size={d}", .{size}),
});
if (compile.link_z_max_page_size) |size| try zig_args.appendSlice(gpa, &.{
"-z",
try allocPrint(arena, "max-page-size={d}", .{size}),
});
if (compile.link_z_defs) try zig_args.appendSlice(gpa, &.{ "-z", "defs" });
if (compile.libc_file) |libc_file| {
try zig_args.append("--libc");
try zig_args.append(libc_file.getPath2(b, step));
} else if (b.libc_file) |libc_file| {
try zig_args.append("--libc");
try zig_args.append(libc_file);
try zig_args.appendSlice(gpa, &.{ "--libc", libc_file.getPath2(step) });
} else if (graph.libc_file) |libc_file| {
try zig_args.appendSlice(gpa, &.{ "--libc", libc_file });
}
try zig_args.append("--cache-dir");
try zig_args.append(b.cache_root.path orelse ".");
try zig_args.append(gpa, "--cache-dir");
try zig_args.append(gpa, graph.cache_root.path orelse ".");
try zig_args.append("--global-cache-dir");
try zig_args.append(graph.global_cache_root.path orelse ".");
try zig_args.append(gpa, "--global-cache-dir");
try zig_args.append(gpa, graph.global_cache_root.path orelse ".");
if (graph.debug_compiler_runtime_libs) |mode|
try zig_args.append(b.fmt("--debug-rt={t}", .{mode}));
try zig_args.append(gpa, try allocPrint(arena, "--debug-rt={t}", .{mode}));
try zig_args.append("--name");
try zig_args.append(compile.name);
try zig_args.append(gpa, "--name");
try zig_args.append(gpa, compile.name);
if (compile.linkage) |some| switch (some) {
.dynamic => try zig_args.append("-dynamic"),
.static => try zig_args.append("-static"),
.dynamic => try zig_args.append(gpa, "-dynamic"),
.static => try zig_args.append(gpa, "-static"),
};
if (compile.kind == .lib and compile.linkage != null and compile.linkage.? == .dynamic) {
if (compile.version) |version| {
try zig_args.append("--version");
try zig_args.append(b.fmt("{f}", .{version}));
try zig_args.append(gpa, "--version");
try zig_args.append(gpa, try allocPrint(arena, "{f}", .{version}));
}
if (compile.rootModuleTarget().os.tag.isDarwin()) {
const install_name = compile.install_name orelse b.fmt("@rpath/{s}{s}{s}", .{
const install_name = compile.install_name orelse try allocPrint(arena, "@rpath/{s}{s}{s}", .{
compile.rootModuleTarget().libPrefix(),
compile.name,
compile.rootModuleTarget().dynamicLibSuffix(),
});
try zig_args.append("-install_name");
try zig_args.append(install_name);
try zig_args.append(gpa, "-install_name");
try zig_args.append(gpa, install_name);
}
}
if (compile.entitlements) |entitlements| {
try zig_args.appendSlice(&[_][]const u8{ "--entitlements", entitlements });
try zig_args.appendSlice(gpa, &[_][]const u8{ "--entitlements", entitlements });
}
if (compile.pagezero_size) |pagezero_size| {
const size = try std.fmt.allocPrint(arena, "{x}", .{pagezero_size});
try zig_args.appendSlice(&[_][]const u8{ "-pagezero_size", size });
const size = try allocPrint(arena, "{x}", .{pagezero_size});
try zig_args.appendSlice(gpa, &[_][]const u8{ "-pagezero_size", size });
}
if (compile.headerpad_size) |headerpad_size| {
const size = try std.fmt.allocPrint(arena, "{x}", .{headerpad_size});
try zig_args.appendSlice(&[_][]const u8{ "-headerpad", size });
const size = try allocPrint(arena, "{x}", .{headerpad_size});
try zig_args.appendSlice(gpa, &[_][]const u8{ "-headerpad", size });
}
if (compile.headerpad_max_install_names) {
try zig_args.append("-headerpad_max_install_names");
try zig_args.append(gpa, "-headerpad_max_install_names");
}
if (compile.dead_strip_dylibs) {
try zig_args.append("-dead_strip_dylibs");
try zig_args.append(gpa, "-dead_strip_dylibs");
}
if (compile.force_load_objc) {
try zig_args.append("-ObjC");
try zig_args.append(gpa, "-ObjC");
}
if (compile.discard_local_symbols) {
try zig_args.append("--discard-all");
try zig_args.append(gpa, "--discard-all");
}
try addFlag(&zig_args, "compiler-rt", compile.bundle_compiler_rt);
try addFlag(&zig_args, "ubsan-rt", compile.bundle_ubsan_rt);
try addFlag(&zig_args, "dll-export-fns", compile.dll_export_fns);
if (compile.rdynamic) {
try zig_args.append("-rdynamic");
try zig_args.append(gpa, "-rdynamic");
}
if (compile.import_memory) {
try zig_args.append("--import-memory");
try zig_args.append(gpa, "--import-memory");
}
if (compile.export_memory) {
try zig_args.append("--export-memory");
try zig_args.append(gpa, "--export-memory");
}
if (compile.import_symbols) {
try zig_args.append("--import-symbols");
try zig_args.append(gpa, "--import-symbols");
}
if (compile.import_table) {
try zig_args.append("--import-table");
try zig_args.append(gpa, "--import-table");
}
if (compile.export_table) {
try zig_args.append("--export-table");
try zig_args.append(gpa, "--export-table");
}
if (compile.initial_memory) |initial_memory| {
try zig_args.append(b.fmt("--initial-memory={d}", .{initial_memory}));
try zig_args.append(gpa, try allocPrint(arena, "--initial-memory={d}", .{initial_memory}));
}
if (compile.max_memory) |max_memory| {
try zig_args.append(b.fmt("--max-memory={d}", .{max_memory}));
try zig_args.append(gpa, try allocPrint(arena, "--max-memory={d}", .{max_memory}));
}
if (compile.shared_memory) {
try zig_args.append("--shared-memory");
try zig_args.append(gpa, "--shared-memory");
}
if (compile.global_base) |global_base| {
try zig_args.append(b.fmt("--global-base={d}", .{global_base}));
try zig_args.append(gpa, try allocPrint(arena, "--global-base={d}", .{global_base}));
}
if (compile.wasi_exec_model) |model| {
try zig_args.append(b.fmt("-mexec-model={s}", .{@tagName(model)}));
try zig_args.append(gpa, try allocPrint(arena, "-mexec-model={t}", .{model}));
}
if (compile.linker_script) |linker_script| {
try zig_args.append("--script");
try zig_args.append(linker_script.getPath2(b, step));
try zig_args.append(gpa, "--script");
try zig_args.append(gpa, linker_script.getPath2(step));
}
if (compile.version_script) |version_script| {
try zig_args.append("--version-script");
try zig_args.append(version_script.getPath2(b, step));
try zig_args.append(gpa, "--version-script");
try zig_args.append(gpa, version_script.getPath2(step));
}
if (compile.linker_allow_undefined_version) |x| {
try zig_args.append(if (x) "--undefined-version" else "--no-undefined-version");
try zig_args.append(gpa, if (x) "--undefined-version" else "--no-undefined-version");
}
if (compile.linker_enable_new_dtags) |enabled| {
try zig_args.append(if (enabled) "--enable-new-dtags" else "--disable-new-dtags");
try zig_args.append(gpa, if (enabled) "--enable-new-dtags" else "--disable-new-dtags");
}
if (compile.kind == .@"test") {
if (compile.exec_cmd_args) |exec_cmd_args| {
for (exec_cmd_args) |cmd_arg| {
if (cmd_arg) |arg| {
try zig_args.append("--test-cmd");
try zig_args.append(arg);
try zig_args.append(gpa, "--test-cmd");
try zig_args.append(gpa, arg);
} else {
try zig_args.append("--test-cmd-bin");
try zig_args.append(gpa, "--test-cmd-bin");
}
}
}
}
if (b.sysroot) |sysroot| {
try zig_args.appendSlice(&[_][]const u8{ "--sysroot", sysroot });
}
if (graph.sysroot) |sysroot| try zig_args.appendSlice(gpa, &.{ "--sysroot", sysroot });
// -I and -L arguments that appear after the last --mod argument apply to all modules.
const cwd: Io.Dir = .cwd();
const io = graph.io;
for (b.search_prefixes.items) |search_prefix| {
for (graph.search_prefixes.items) |search_prefix| {
var prefix_dir = cwd.openDir(io, search_prefix, .{}) catch |err| {
return step.fail("unable to open prefix directory '{s}': {s}", .{
search_prefix, @errorName(err),
});
return step.fail("unable to open prefix directory '{s}': {t}", .{ search_prefix, err });
};
defer prefix_dir.close(io);
@ -717,58 +695,53 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
// CLI parsing code, when the linker sees an -L directory that does not exist.
if (prefix_dir.access(io, "lib", .{})) |_| {
try zig_args.appendSlice(&.{
"-L", b.pathJoin(&.{ search_prefix, "lib" }),
try zig_args.appendSlice(gpa, &.{
"-L", try Dir.path.join(arena, &.{ search_prefix, "lib" }),
});
} else |err| switch (err) {
error.FileNotFound => {},
else => |e| return step.fail("unable to access '{s}/lib' directory: {s}", .{
search_prefix, @errorName(e),
}),
else => |e| return step.fail("unable to access '{s}/lib' directory: {t}", .{ search_prefix, e }),
}
if (prefix_dir.access(io, "include", .{})) |_| {
try zig_args.appendSlice(&.{
"-I", b.pathJoin(&.{ search_prefix, "include" }),
try zig_args.appendSlice(gpa, &.{
"-I", try Dir.path.join(arena, &.{ search_prefix, "include" }),
});
} else |err| switch (err) {
error.FileNotFound => {},
else => |e| return step.fail("unable to access '{s}/include' directory: {s}", .{
search_prefix, @errorName(e),
}),
else => |e| return step.fail("unable to access '{s}/include' directory: {t}", .{ search_prefix, e }),
}
}
if (compile.rc_includes != .any) {
try zig_args.append("-rcincludes");
try zig_args.append(@tagName(compile.rc_includes));
try zig_args.appendSlice(gpa, &.{ "-rcincludes", @tagName(compile.rc_includes) });
}
try addFlag(&zig_args, "each-lib-rpath", compile.each_lib_rpath);
if (compile.build_id orelse b.build_id) |build_id| {
try zig_args.append(switch (build_id) {
.hexstring => |hs| b.fmt("--build-id=0x{x}", .{hs.toSlice()}),
.none, .fast, .uuid, .sha1, .md5 => b.fmt("--build-id={s}", .{@tagName(build_id)}),
if (compile.build_id orelse graph.build_id) |build_id| {
try zig_args.append(gpa, switch (build_id) {
.hexstring => |hs| try allocPrint(arena, "--build-id=0x{x}", .{hs.toSlice()}),
.none, .fast, .uuid, .sha1, .md5 => try allocPrint(arena, "--build-id={t}", .{build_id}),
});
}
const opt_zig_lib_dir = if (compile.zig_lib_dir) |dir|
dir.getPath2(b, step)
dir.getPath2(step)
else if (graph.zig_lib_directory.path) |_|
b.fmt("{f}", .{graph.zig_lib_directory})
try allocPrint(arena, "{f}", .{graph.zig_lib_directory})
else
null;
if (opt_zig_lib_dir) |zig_lib_dir| {
try zig_args.append("--zig-lib-dir");
try zig_args.append(zig_lib_dir);
try zig_args.append(gpa, "--zig-lib-dir");
try zig_args.append(gpa, zig_lib_dir);
}
try addFlag(&zig_args, "PIE", compile.pie);
if (compile.lto) |lto| {
try zig_args.append(switch (lto) {
try zig_args.append(gpa, switch (lto) {
.full => "-flto=full",
.thin => "-flto=thin",
.none => "-fno-lto",
@ -778,21 +751,20 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
try addFlag(&zig_args, "sanitize-coverage-trace-pc-guard", compile.sanitize_coverage_trace_pc_guard);
if (compile.subsystem) |subsystem| {
try zig_args.append("--subsystem");
try zig_args.append(@tagName(subsystem));
try zig_args.appendSlice(gpa, &.{ "--subsystem", @tagName(subsystem) });
}
if (compile.mingw_unicode_entry_point) {
try zig_args.append("-municode");
try zig_args.append(gpa, "-municode");
}
if (compile.error_limit) |err_limit| try zig_args.appendSlice(&.{
"--error-limit", b.fmt("{d}", .{err_limit}),
if (compile.error_limit) |err_limit| try zig_args.appendSlice(gpa, &.{
"--error-limit", try allocPrint(arena, "{d}", .{err_limit}),
});
try addFlag(&zig_args, "incremental", graph.incremental);
try zig_args.append("--listen=-");
try zig_args.append(gpa, "--listen=-");
// Windows has an argument length limit of 32,766 characters, macOS 262,144 and Linux
// 2,097,152. If our args exceed 30 KiB, we instead write them to a "response file" and
@ -803,7 +775,7 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
args_length += arg.len + 1; // +1 to account for null terminator
}
if (args_length >= 30 * 1024) {
try b.cache_root.handle.createDirPath(io, "args");
try graph.cache_root.handle.createDirPath(io, "args");
const args_to_escape = zig_args.items[2..];
var escaped_args = try std.array_list.Managed([]const u8).initCapacity(arena, args_to_escape.len);
@ -836,21 +808,21 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
_ = try std.fmt.bufPrint(&args_hex_hash, "{x}", .{&args_hash});
const args_file = "args" ++ Dir.path.sep_str ++ args_hex_hash;
if (b.cache_root.handle.access(io, args_file, .{})) |_| {
if (graph.cache_root.handle.access(io, args_file, .{})) |_| {
// The args file is already present from a previous run.
} else |err| switch (err) {
error.FileNotFound => {
var af = b.cache_root.handle.createFileAtomic(io, args_file, .{
var af = graph.cache_root.handle.createFileAtomic(io, args_file, .{
.replace = false,
.make_path = true,
}) catch |e| return step.fail("failed creating tmp args file {f}{s}: {t}", .{
b.cache_root, args_file, e,
graph.cache_root, args_file, e,
});
defer af.deinit(io);
af.file.writeStreamingAll(io, args) catch |e| {
return step.fail("failed writing args data to tmp file {f}{s}: {t}", .{
b.cache_root, args_file, e,
graph.cache_root, args_file, e,
});
};
// Note we can't clean up this file, not even after build
@ -861,7 +833,7 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
// The args file was created by another concurrent build process.
},
else => |other_err| return step.fail("failed linking tmp file {f}{s}: {t}", .{
b.cache_root, args_file, other_err,
graph.cache_root, args_file, other_err,
}),
};
},
@ -870,32 +842,34 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 {
const resolved_args_file = try mem.concat(arena, u8, &.{
"@",
try b.cache_root.join(arena, &.{args_file}),
try graph.cache_root.join(arena, &.{args_file}),
});
zig_args.shrinkRetainingCapacity(2);
try zig_args.append(resolved_args_file);
try zig_args.append(gpa, resolved_args_file);
}
return try zig_args.toOwnedSlice();
}
pub fn rebuildInFuzzMode(c: *Compile, maker: *Maker, progress_node: std.Progress.Node) !Path {
pub fn rebuildInFuzzMode(compile: *Compile, maker: *Maker, progress_node: std.Progress.Node) !Path {
const gpa = maker.graph.gpa;
c.step.result_error_msgs.clearRetainingCapacity();
c.step.result_stderr = "";
compile.step.result_error_msgs.clearRetainingCapacity();
compile.step.result_stderr = "";
c.step.result_error_bundle.deinit(gpa);
c.step.result_error_bundle = std.zig.ErrorBundle.empty;
compile.step.result_error_bundle.deinit(gpa);
compile.step.result_error_bundle = std.zig.ErrorBundle.empty;
if (c.step.result_failed_command) |cmd| {
if (compile.step.result_failed_command) |cmd| {
gpa.free(cmd);
c.step.result_failed_command = null;
compile.step.result_failed_command = null;
}
const zig_args = try getZigArgs(c, maker, true);
const maybe_output_bin_path = try c.step.evalZigProcess(zig_args, progress_node, false, null, gpa);
const zig_args = &compile.zig_args;
zig_args.clearRetainingCapacity();
try lowerZigArgs(compile, maker, zig_args, true);
const maybe_output_bin_path = try compile.step.evalZigProcess(zig_args.items, progress_node, false, maker);
return maybe_output_bin_path.?;
}
@ -906,24 +880,24 @@ pub fn doAtomicSymLinks(
filename_major_only: []const u8,
filename_name_only: []const u8,
) !void {
const b = step.owner;
const graph = maker.graph;
const arena = graph.arena; // TODO don't leak into process arena
const io = graph.io;
const out_dir = Dir.path.dirname(output_path) orelse ".";
const out_basename = Dir.path.basename(output_path);
// sym link for libfoo.so.1 to libfoo.so.1.2.3
const major_only_path = b.pathJoin(&.{ out_dir, filename_major_only });
const major_only_path = try Dir.path.join(arena, &.{ out_dir, filename_major_only });
const cwd: Io.Dir = .cwd();
cwd.symLinkAtomic(io, out_basename, major_only_path, .{}) catch |err| {
return step.fail("unable to symlink {s} -> {s}: {s}", .{
major_only_path, out_basename, @errorName(err),
return step.fail("unable to symlink {s} -> {s}: {t}", .{
major_only_path, out_basename, err,
});
};
// sym link for libfoo.so to libfoo.so.1
const name_only_path = b.pathJoin(&.{ out_dir, filename_name_only });
const name_only_path = try Dir.path.join(arena, &.{ out_dir, filename_name_only });
cwd.symLinkAtomic(io, filename_major_only, name_only_path, .{}) catch |err| {
return step.fail("Unable to symlink {s} -> {s}: {s}", .{
name_only_path, filename_major_only, @errorName(err),
return step.fail("unable to symlink {s} -> {s}: {t}", .{
name_only_path, filename_major_only, err,
});
};
}
@ -982,14 +956,13 @@ fn getPkgConfigList(b: *std.Build) ![]const PkgConfigPkg {
}
}
fn addFlag(args: *std.array_list.Managed([]const u8), comptime name: []const u8, opt: ?bool) !void {
fn addBool(gpa: Allocator, args: *std.ArrayList([]const u8), arg: []const u8, opt: bool) !void {
if (opt) try args.append(gpa, arg);
}
fn addFlag(gpa: Allocator, args: *std.ArrayList([]const u8), comptime name: []const u8, opt: ?bool) !void {
const cond = opt orelse return;
try args.ensureUnusedCapacity(1);
if (cond) {
args.appendAssumeCapacity("-f" ++ name);
} else {
args.appendAssumeCapacity("-fno-" ++ name);
}
try args.append(gpa, if (cond) "-f" ++ name else "-fno-" ++ name);
}
const PkgConfigResult = struct {
@ -1262,7 +1235,7 @@ const CliNamedModules = struct {
try compile.modules.putNoClobber(arena, mod, {});
break;
}
name = try std.fmt.allocPrint(arena, "{s}{d}", .{ orig_name, n });
name = try allocPrint(arena, "{s}{d}", .{ orig_name, n });
n += 1;
}
}

View file

@ -1091,7 +1091,7 @@ fn runCommand(
const cwd: process.Child.Cwd = if (run.cwd) |lazy_cwd| .{ .path = lazy_cwd.getPath2(b, step) } else .inherit;
try step.handleChildProcUnsupported();
try Step.handleVerbose2(step.owner, cwd, run.environ_map, argv);
try Step.handleVerbose(step.owner, cwd, run.environ_map, argv);
const allow_skip = switch (run.stdio) {
.check, .zig_test => run.skip_foreign_checks,
@ -1241,7 +1241,7 @@ fn runCommand(
gpa.free(step.result_failed_command.?);
step.result_failed_command = null;
try Step.handleVerbose2(step.owner, cwd, run.environ_map, interp_argv.items);
try Step.handleVerbose(step.owner, cwd, run.environ_map, interp_argv.items);
break :term spawnChildAndCollect(run, maker, progress_node, interp_argv.items, &environ_map, has_side_effects, fuzz_context) catch |e| {
if (!run.failing_to_execute_foreign_is_an_error) return error.MakeSkipped;

View file

@ -148,39 +148,30 @@ pub fn main(init: process.Init.Minimal) !void {
graph.release_mode = .any;
} else if (mem.cutPrefix(u8, arg, "--release=")) |text| {
graph.release_mode = std.meta.stringToEnum(std.Build.ReleaseMode, text) orelse {
fatalWithHint("expected [off|any|fast|safe|small] in '{s}', found '{s}'", .{
fatalWithHint("expected [off|any|fast|safe|small] in {q}, found {q}", .{
arg, text,
});
};
} else if (mem.eql(u8, arg, "--color")) {
const next_arg = nextArg(args, &arg_idx) orelse
fatalWithHint("expected [auto|on|off] after '{s}'", .{arg});
fatalWithHint("expected [auto|on|off] after {q}", .{arg});
color = std.meta.stringToEnum(Color, next_arg) orelse {
fatalWithHint("expected [auto|on|off] after '{s}', found '{s}'", .{
fatalWithHint("expected [auto|on|off] after {q}, found {q}", .{
arg, next_arg,
});
};
} else if (mem.eql(u8, arg, "--error-style")) {
const next_arg = nextArg(args, &arg_idx) orelse
fatalWithHint("expected style after '{s}'", .{arg});
fatalWithHint("expected style after {q}", .{arg});
error_style = std.meta.stringToEnum(ErrorStyle, next_arg) orelse {
fatalWithHint("expected style after '{s}', found '{s}'", .{ arg, next_arg });
fatalWithHint("expected style after {q}, found {q}", .{ arg, next_arg });
};
} else if (mem.eql(u8, arg, "--multiline-errors")) {
const next_arg = nextArg(args, &arg_idx) orelse
fatalWithHint("expected style after '{s}'", .{arg});
fatalWithHint("expected style after {q}", .{arg});
multiline_errors = std.meta.stringToEnum(MultilineErrors, next_arg) orelse {
fatalWithHint("expected style after '{s}', found '{s}'", .{ arg, next_arg });
fatalWithHint("expected style after {q}, found {q}", .{ arg, next_arg });
};
} else if (mem.eql(u8, arg, "--build-id")) {
builder.build_id = .fast;
} else if (mem.cutPrefix(u8, arg, "--build-id=")) |style| {
builder.build_id = std.zig.BuildId.parse(style) catch |err|
fatal("unable to parse --build-id style '{s}': {t}", .{ style, err });
} else if (mem.eql(u8, arg, "--debug-compile-errors")) {
builder.debug_compile_errors = true;
} else if (mem.eql(u8, arg, "--debug-incremental")) {
builder.debug_incremental = true;
} else if (mem.eql(u8, arg, "--system")) {
// The usage text shows another argument after this parameter
// but it is handled by the parent process. The build runner
@ -189,7 +180,7 @@ pub fn main(init: process.Init.Minimal) !void {
} else if (mem.eql(u8, arg, "--have-run-args")) {
graph.have_run_args = true;
} else {
fatalWithHint("unrecognized argument: '{s}'", .{arg});
fatalWithHint("unrecognized argument: {q}", .{arg});
}
}

View file

@ -31,14 +31,6 @@ allocator: Allocator,
user_input_options: UserInputOptionsMap,
available_options_map: AvailableOptionsMap,
available_options_list: std.array_list.Managed(AvailableOption),
verbose: bool,
verbose_link: bool,
verbose_cc: bool,
verbose_air: bool,
verbose_llvm_ir: ?[]const u8,
verbose_llvm_bc: ?[]const u8,
verbose_cimport: bool,
verbose_llvm_cpu_features: bool,
invalid_user_input: bool,
default_step: *Step,
top_level_steps: std.StringArrayHashMapUnmanaged(*Step.TopLevel),
@ -47,8 +39,6 @@ install_prefix: []const u8,
build_root: Cache.Directory,
cache_root: Cache.Directory,
debug_log_scopes: []const []const u8 = &.{},
debug_compile_errors: bool = false,
debug_incremental: bool = false,
/// Number of stack frames captured when a `StackTrace` is recorded for debug purposes,
/// in particular at `Step` creation.
/// Set to 0 to disable stack collection.
@ -76,8 +66,6 @@ pkg_hash: []const u8,
/// A mapping from dependency names to package hashes.
available_deps: AvailableDeps,
build_id: ?std.zig.BuildId = null,
pub const ReleaseMode = enum {
off,
any,
@ -225,14 +213,6 @@ pub fn create(
.graph = graph,
.build_root = build_root,
.cache_root = cache_root,
.verbose = false,
.verbose_link = false,
.verbose_cc = false,
.verbose_air = false,
.verbose_llvm_ir = null,
.verbose_llvm_bc = null,
.verbose_cimport = false,
.verbose_llvm_cpu_features = false,
.invalid_user_input = false,
.allocator = arena,
.user_input_options = UserInputOptionsMap.init(arena),
@ -301,23 +281,12 @@ fn createChild(
.user_input_options = user_input_options,
.available_options_map = AvailableOptionsMap.init(allocator),
.available_options_list = std.array_list.Managed(AvailableOption).init(allocator),
.verbose = parent.verbose,
.verbose_link = parent.verbose_link,
.verbose_cc = parent.verbose_cc,
.verbose_air = parent.verbose_air,
.verbose_llvm_ir = parent.verbose_llvm_ir,
.verbose_llvm_bc = parent.verbose_llvm_bc,
.verbose_cimport = parent.verbose_cimport,
.verbose_llvm_cpu_features = parent.verbose_llvm_cpu_features,
.invalid_user_input = false,
.default_step = undefined,
.top_level_steps = .{},
.sysroot = parent.sysroot,
.build_root = build_root,
.cache_root = parent.cache_root,
.debug_log_scopes = parent.debug_log_scopes,
.debug_compile_errors = parent.debug_compile_errors,
.debug_incremental = parent.debug_incremental,
.enable_darling = parent.enable_darling,
.enable_qemu = parent.enable_qemu,
.enable_rosetta = parent.enable_rosetta,
@ -1125,7 +1094,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
if (std.zig.BuildId.parse(s)) |build_id| {
return build_id;
} else |err| {
log.err("unable to parse option '-D{s}': {s}", .{ name, @errorName(err) });
log.err("unable to parse option '-D{s}': {t}", .{ name, err });
b.markInvalidUserInput();
return null;
}
@ -1594,8 +1563,9 @@ pub fn addCheckFile(
}
pub fn truncateFile(b: *Build, dest_path: []const u8) (Io.Dir.CreateDirError || Io.Dir.StatFileError)!void {
const io = b.graph.io;
if (b.verbose) log.info("truncate {s}", .{dest_path});
const graph = b.graph;
const io = graph.io;
if (graph.verbose) log.info("truncate {s}", .{dest_path});
const cwd = Io.Dir.cwd();
var src_file = cwd.createFile(io, dest_path, .{}) catch |err| switch (err) {
error.FileNotFound => blk: {
@ -1705,9 +1675,13 @@ pub fn runAllowFail(
const graph = b.graph;
const io = graph.io;
const arena = graph.arena;
const max_output_size = 400 * 1024;
try Step.handleVerbose2(b, .inherit, &graph.environ_map, argv);
if (graph.verbose) {
const text = std.zig.allocPrintCmd(arena, .inherit, null, argv);
std.log.scoped(.verbose).info("{s}", .{text});
}
var child = try std.process.spawn(io, .{
.argv = argv,
@ -1718,10 +1692,10 @@ pub fn runAllowFail(
});
var stdout_reader = child.stdout.?.readerStreaming(io, &.{});
const stdout = stdout_reader.interface.allocRemaining(b.allocator, .limited(max_output_size)) catch {
const stdout = stdout_reader.interface.allocRemaining(arena, .limited(max_output_size)) catch {
return error.ReadFailure;
};
errdefer b.allocator.free(stdout);
errdefer arena.free(stdout);
const term = try child.wait(io);
switch (term) {
@ -2089,34 +2063,6 @@ pub fn runBuild(b: *Build, build_zig: anytype) anyerror!void {
pub const GeneratedFile = struct {
/// The step that generates the file.
step: *Step,
/// The path to the generated file. Must be either absolute or relative to the build runner cwd.
/// This value must be set in the `fn make()` of the `step` and must not be `null` afterwards.
path: ?[]const u8 = null,
/// Deprecated, see `getPath3`.
pub fn getPath(gen: GeneratedFile) []const u8 {
return gen.step.owner.pathFromCwd(gen.path orelse std.debug.panic(
"getPath() was called on a GeneratedFile that wasn't built yet. Is there a missing Step dependency on step '{s}'?",
.{gen.step.name},
));
}
/// Deprecated, see `getPath3`.
pub fn getPath2(gen: GeneratedFile, src_builder: *Build, asking_step: ?*Step) []const u8 {
return getPath3(gen, src_builder, asking_step) catch |err| switch (err) {
error.Canceled => std.process.exit(1),
};
}
pub fn getPath3(gen: GeneratedFile, src_builder: *Build, asking_step: ?*Step) Io.Cancelable![]const u8 {
return gen.path orelse {
const graph = gen.step.owner.graph;
const io = graph.io;
const stderr = try io.lockStderr(&.{}, graph.stderr_mode);
dumpBadGetPathHelp(gen.step, stderr.terminal(), src_builder, asking_step) catch {};
@panic("misconfigured build script");
};
}
};
// dirnameAllowEmpty is a variant of fs.path.dirname
@ -2290,94 +2236,6 @@ pub const LazyPath = union(enum) {
}
}
/// Deprecated, see `getPath4`.
pub fn getPath(lazy_path: LazyPath, src_builder: *Build) []const u8 {
return getPath2(lazy_path, src_builder, null);
}
/// Deprecated, see `getPath4`.
pub fn getPath2(lazy_path: LazyPath, src_builder: *Build, asking_step: ?*Step) []const u8 {
const p = getPath3(lazy_path, src_builder, asking_step);
return src_builder.pathResolve(&.{ p.root_dir.path orelse ".", p.sub_path });
}
/// Deprecated, see `getPath4`.
pub fn getPath3(lazy_path: LazyPath, src_builder: *Build, asking_step: ?*Step) Cache.Path {
return getPath4(lazy_path, src_builder, asking_step) catch |err| switch (err) {
error.Canceled => std.process.exit(1),
};
}
/// Intended to be used during the make phase only.
///
/// `asking_step` is only used for debugging purposes; it's the step being
/// run that is asking for the path.
pub fn getPath4(lazy_path: LazyPath, src_builder: *Build, asking_step: ?*Step) Io.Cancelable!Cache.Path {
switch (lazy_path) {
.src_path => |sp| return .{
.root_dir = sp.owner.build_root,
.sub_path = sp.sub_path,
},
.cwd_relative => |sub_path| return .{
.root_dir = Cache.Directory.cwd(),
.sub_path = sub_path,
},
.generated => |gen| {
// TODO make gen.file.path not be absolute and use that as the
// basis for not traversing up too many directories.
const graph = src_builder.graph;
var file_path: Cache.Path = .{
.root_dir = Cache.Directory.cwd(),
.sub_path = gen.file.path orelse {
const io = graph.io;
const stderr = try io.lockStderr(&.{}, graph.stderr_mode);
dumpBadGetPathHelp(gen.file.step, stderr.terminal(), src_builder, asking_step) catch {};
io.unlockStderr();
@panic("misconfigured build script");
},
};
if (gen.up > 0) {
const cache_root_path = src_builder.cache_root.path orelse
(src_builder.cache_root.join(src_builder.allocator, &.{"."}) catch @panic("OOM"));
for (0..gen.up) |_| {
if (mem.eql(u8, file_path.sub_path, cache_root_path)) {
// If we hit the cache root and there's still more to go,
// the script attempted to go too far.
dumpBadDirnameHelp(gen.file.step, asking_step,
\\dirname() attempted to traverse outside the cache root.
\\This is not allowed.
\\
, .{}) catch {};
@panic("misconfigured build script");
}
// path is absolute.
// dirname will return null only if we're at root.
// Typically, we'll stop well before that at the cache root.
file_path.sub_path = fs.path.dirname(file_path.sub_path) orelse {
dumpBadDirnameHelp(gen.file.step, asking_step,
\\dirname() reached root.
\\No more directories left to go up.
\\
, .{}) catch {};
@panic("misconfigured build script");
};
}
}
return file_path.join(src_builder.allocator, gen.sub_path) catch @panic("OOM");
},
.dependency => |dep| return .{
.root_dir = dep.dependency.builder.build_root,
.sub_path = dep.sub_path,
},
}
}
pub fn basename(lazy_path: LazyPath, src_builder: *Build, asking_step: ?*Step) []const u8 {
return fs.path.basename(switch (lazy_path) {
.src_path => |sp| sp.sub_path,
@ -2451,36 +2309,6 @@ fn dumpBadDirnameHelp(
stderr.setColor(.reset) catch {};
}
/// In this function the stderr mutex has already been locked.
pub fn dumpBadGetPathHelp(s: *Step, t: Io.Terminal, src_builder: *Build, asking_step: ?*Step) anyerror!void {
const w = t.writer;
try w.print(
\\getPath() was called on a GeneratedFile that wasn't built yet.
\\ source package path: {s}
\\ Is there a missing Step dependency on step '{s}'?
\\
, .{
src_builder.build_root.path orelse ".",
s.name,
});
t.setColor(.red) catch {};
try w.writeAll(" The step was created by this stack trace:\n");
t.setColor(.reset) catch {};
s.dump(t);
if (asking_step) |as| {
t.setColor(.red) catch {};
try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
t.setColor(.reset) catch {};
as.dump(t);
}
t.setColor(.red) catch {};
try w.writeAll(" Proceeding to panic.\n");
t.setColor(.reset) catch {};
}
pub const InstallDir = union(enum) {
prefix: void,
lib: void,

View file

@ -87,9 +87,13 @@ libc_file: ?LazyPath = null,
each_lib_rpath: ?bool = null,
/// On ELF targets, this will emit a link section called ".note.gnu.build-id"
/// which can be used to coordinate a stripped binary with its debug symbols.
///
/// As an example, the bloaty project refuses to work unless its inputs have
/// build ids, in order to prevent accidental mismatches.
///
/// The default is to not include this section because it slows down linking.
///
/// This option overrides the CLI argument passed to `zig build`.
build_id: ?std.zig.BuildId = null,
/// Create a .eh_frame_hdr section and a PT_GNU_EH_FRAME segment in the ELF

View file

@ -983,6 +983,79 @@ pub const EmitArtifact = enum {
}
};
pub fn allocPrintCmd(
gpa: Allocator,
cwd: std.process.Child.Cwd,
opt_env: ?struct {
child: *const std.process.Environ.Map,
parent: *const std.process.Environ.Map,
},
argv: []const []const u8,
) Allocator.Error![]u8 {
const shell = struct {
fn escape(writer: *Io.Writer, string: []const u8, is_argv0: bool) !void {
for (string) |c| {
if (switch (c) {
else => true,
'%', '+'...':', '@'...'Z', '_', 'a'...'z' => false,
'=' => is_argv0,
}) break;
} else return writer.writeAll(string);
try writer.writeByte('"');
for (string) |c| {
if (switch (c) {
std.ascii.control_code.nul => break,
'!', '"', '$', '\\', '`' => true,
else => !std.ascii.isPrint(c),
}) try writer.writeByte('\\');
switch (c) {
std.ascii.control_code.nul => unreachable,
std.ascii.control_code.bel => try writer.writeByte('a'),
std.ascii.control_code.bs => try writer.writeByte('b'),
std.ascii.control_code.ht => try writer.writeByte('t'),
std.ascii.control_code.lf => try writer.writeByte('n'),
std.ascii.control_code.vt => try writer.writeByte('v'),
std.ascii.control_code.ff => try writer.writeByte('f'),
std.ascii.control_code.cr => try writer.writeByte('r'),
std.ascii.control_code.esc => try writer.writeByte('E'),
' '...'~' => try writer.writeByte(c),
else => try writer.print("{o:0>3}", .{c}),
}
}
try writer.writeByte('"');
}
};
var aw: Io.Writer.Allocating = .init(gpa);
defer aw.deinit();
const writer = &aw.writer;
switch (cwd) {
.inherit => {},
.path => |path| writer.print("cd {s} && ", .{path}) catch return error.OutOfMemory,
.dir => @panic("TODO"),
}
if (opt_env) |env| {
var it = env.child.iterator();
while (it.next()) |entry| {
const key = entry.key_ptr.*;
const value = entry.value_ptr.*;
if (env.parent.get(key)) |process_value| {
if (std.mem.eql(u8, value, process_value)) continue;
}
writer.print("{s}=", .{key}) catch return error.OutOfMemory;
shell.escape(writer, value, false) catch return error.OutOfMemory;
writer.writeByte(' ') catch return error.OutOfMemory;
}
}
shell.escape(writer, argv[0], true) catch return error.OutOfMemory;
for (argv[1..]) |arg| {
writer.writeByte(' ') catch return error.OutOfMemory;
shell.escape(writer, arg, false) catch return error.OutOfMemory;
}
return aw.toOwnedSlice();
}
test {
_ = Ast;
_ = AstRlAnnotate;