extract some logic from std.Build to build_runner.zig

This commit is contained in:
Andrew Kelley 2023-02-13 13:10:20 -07:00
parent a2c6ecd6dc
commit c6a895f667
2 changed files with 75 additions and 85 deletions

View File

@ -92,23 +92,23 @@ pub fn main() !void {
// before arg parsing, check for the NO_COLOR environment variable
// if it exists, default the color setting to .off
// explicit --color arguments will still override this setting.
builder.color = if (std.process.hasEnvVarConstant("NO_COLOR")) .off else .auto;
builder.color = if (process.hasEnvVarConstant("NO_COLOR")) .off else .auto;
while (nextArg(args, &arg_idx)) |arg| {
if (mem.startsWith(u8, arg, "-D")) {
const option_contents = arg[2..];
if (option_contents.len == 0) {
std.debug.print("Expected option name after '-D'\n\n", .{});
return usageAndErr(builder, false, stderr_stream);
usageAndErr(builder, false, stderr_stream);
}
if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| {
const option_name = option_contents[0..name_end];
const option_value = option_contents[name_end + 1 ..];
if (try builder.addUserInputOption(option_name, option_value))
return usageAndErr(builder, false, stderr_stream);
usageAndErr(builder, false, stderr_stream);
} else {
if (try builder.addUserInputFlag(option_contents))
return usageAndErr(builder, false, stderr_stream);
usageAndErr(builder, false, stderr_stream);
}
} else if (mem.startsWith(u8, arg, "-")) {
if (mem.eql(u8, arg, "--verbose")) {
@ -118,61 +118,61 @@ pub fn main() !void {
} else if (mem.eql(u8, arg, "-p") or mem.eql(u8, arg, "--prefix")) {
install_prefix = nextArg(args, &arg_idx) orelse {
std.debug.print("Expected argument after {s}\n\n", .{arg});
return usageAndErr(builder, false, stderr_stream);
usageAndErr(builder, false, stderr_stream);
};
} else if (mem.eql(u8, arg, "-l") or mem.eql(u8, arg, "--list-steps")) {
return steps(builder, false, stdout_stream);
} else if (mem.eql(u8, arg, "--prefix-lib-dir")) {
dir_list.lib_dir = nextArg(args, &arg_idx) orelse {
std.debug.print("Expected argument after {s}\n\n", .{arg});
return usageAndErr(builder, false, stderr_stream);
usageAndErr(builder, false, stderr_stream);
};
} else if (mem.eql(u8, arg, "--prefix-exe-dir")) {
dir_list.exe_dir = nextArg(args, &arg_idx) orelse {
std.debug.print("Expected argument after {s}\n\n", .{arg});
return usageAndErr(builder, false, stderr_stream);
usageAndErr(builder, false, stderr_stream);
};
} else if (mem.eql(u8, arg, "--prefix-include-dir")) {
dir_list.include_dir = nextArg(args, &arg_idx) orelse {
std.debug.print("Expected argument after {s}\n\n", .{arg});
return usageAndErr(builder, false, stderr_stream);
usageAndErr(builder, false, stderr_stream);
};
} else if (mem.eql(u8, arg, "--sysroot")) {
const sysroot = nextArg(args, &arg_idx) orelse {
std.debug.print("Expected argument after --sysroot\n\n", .{});
return usageAndErr(builder, false, stderr_stream);
usageAndErr(builder, false, stderr_stream);
};
builder.sysroot = sysroot;
} else if (mem.eql(u8, arg, "--search-prefix")) {
const search_prefix = nextArg(args, &arg_idx) orelse {
std.debug.print("Expected argument after --search-prefix\n\n", .{});
return usageAndErr(builder, false, stderr_stream);
usageAndErr(builder, false, stderr_stream);
};
builder.addSearchPrefix(search_prefix);
} else if (mem.eql(u8, arg, "--libc")) {
const libc_file = nextArg(args, &arg_idx) orelse {
std.debug.print("Expected argument after --libc\n\n", .{});
return usageAndErr(builder, false, stderr_stream);
usageAndErr(builder, false, stderr_stream);
};
builder.libc_file = libc_file;
} else if (mem.eql(u8, arg, "--color")) {
const next_arg = nextArg(args, &arg_idx) orelse {
std.debug.print("expected [auto|on|off] after --color", .{});
return usageAndErr(builder, false, stderr_stream);
usageAndErr(builder, false, stderr_stream);
};
builder.color = std.meta.stringToEnum(@TypeOf(builder.color), next_arg) orelse {
std.debug.print("expected [auto|on|off] after --color, found '{s}'", .{next_arg});
return usageAndErr(builder, false, stderr_stream);
usageAndErr(builder, false, stderr_stream);
};
} else if (mem.eql(u8, arg, "--zig-lib-dir")) {
builder.zig_lib_dir = nextArg(args, &arg_idx) orelse {
std.debug.print("Expected argument after --zig-lib-dir\n\n", .{});
return usageAndErr(builder, false, stderr_stream);
usageAndErr(builder, false, stderr_stream);
};
} else if (mem.eql(u8, arg, "--debug-log")) {
const next_arg = nextArg(args, &arg_idx) orelse {
std.debug.print("Expected argument after {s}\n\n", .{arg});
return usageAndErr(builder, false, stderr_stream);
usageAndErr(builder, false, stderr_stream);
};
try debug_log_scopes.append(next_arg);
} else if (mem.eql(u8, arg, "--debug-compile-errors")) {
@ -180,7 +180,7 @@ pub fn main() !void {
} else if (mem.eql(u8, arg, "--glibc-runtimes")) {
builder.glibc_runtimes_dir = nextArg(args, &arg_idx) orelse {
std.debug.print("Expected argument after --glibc-runtimes\n\n", .{});
return usageAndErr(builder, false, stderr_stream);
usageAndErr(builder, false, stderr_stream);
};
} else if (mem.eql(u8, arg, "--verbose-link")) {
builder.verbose_link = true;
@ -231,7 +231,7 @@ pub fn main() !void {
break;
} else {
std.debug.print("Unrecognized argument: {s}\n\n", .{arg});
return usageAndErr(builder, false, stderr_stream);
usageAndErr(builder, false, stderr_stream);
}
} else {
try targets.append(arg);
@ -243,13 +243,10 @@ pub fn main() !void {
try builder.runBuild(root);
if (builder.validateUserInputDidItFail())
return usageAndErr(builder, true, stderr_stream);
usageAndErr(builder, true, stderr_stream);
builder.make(targets.items) catch |err| {
make(builder, targets.items) catch |err| {
switch (err) {
error.InvalidStepName => {
return usageAndErr(builder, true, stderr_stream);
},
error.UncleanExit => process.exit(1),
// This error is intended to indicate that the step has already
// logged an error message and so printing the error return trace
@ -261,6 +258,48 @@ pub fn main() !void {
};
}
fn make(b: *std.Build, step_names: []const []const u8) !void {
var wanted_steps = ArrayList(*std.Build.Step).init(b.allocator);
defer wanted_steps.deinit();
if (step_names.len == 0) {
try wanted_steps.append(b.default_step);
} else {
for (step_names) |step_name| {
const s = b.top_level_steps.get(step_name) orelse {
std.debug.print("no step named '{s}'. Access the help menu with 'zig build -h'\n", .{step_name});
process.exit(1);
};
try wanted_steps.append(&s.step);
}
}
for (wanted_steps.items) |s| {
try makeOneStep(b, s);
}
}
fn makeOneStep(b: *std.Build, s: *std.Build.Step) anyerror!void {
if (s.loop_flag) {
std.debug.print("dependency loop detected:\n {s}\n", .{s.name});
return error.DependencyLoopDetected;
}
s.loop_flag = true;
for (s.dependencies.items) |dep| {
makeOneStep(b, dep) catch |err| {
if (err == error.DependencyLoopDetected) {
std.debug.print(" {s}\n", .{s.name});
}
return err;
};
}
s.loop_flag = false;
try s.make();
}
fn steps(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !void {
// run the build script to collect the options
if (!already_ran_build) {
@ -269,7 +308,7 @@ fn steps(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
}
const allocator = builder.allocator;
for (builder.top_level_steps.items) |top_level_step| {
for (builder.top_level_steps.values()) |top_level_step| {
const name = if (&top_level_step.step == builder.default_step)
try fmt.allocPrint(allocator, "{s} (default)", .{top_level_step.step.name})
else
@ -374,7 +413,7 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
);
}
fn usageAndErr(builder: *std.Build, already_ran_build: bool, out_stream: anytype) void {
fn usageAndErr(builder: *std.Build, already_ran_build: bool, out_stream: anytype) noreturn {
usage(builder, already_ran_build, out_stream) catch {};
process.exit(1);
}

View File

@ -67,7 +67,7 @@ invalid_user_input: bool,
zig_exe: []const u8,
default_step: *Step,
env_map: *EnvMap,
top_level_steps: ArrayList(*TopLevelStep),
top_level_steps: std.StringArrayHashMapUnmanaged(*TopLevelStep),
install_prefix: []const u8,
dest_dir: ?[]const u8,
lib_dir: []const u8,
@ -217,7 +217,7 @@ pub fn create(
.user_input_options = UserInputOptionsMap.init(allocator),
.available_options_map = AvailableOptionsMap.init(allocator),
.available_options_list = ArrayList(AvailableOption).init(allocator),
.top_level_steps = ArrayList(*TopLevelStep).init(allocator),
.top_level_steps = .{},
.default_step = undefined,
.env_map = env_map,
.search_prefixes = ArrayList([]const u8).init(allocator),
@ -241,8 +241,8 @@ pub fn create(
.host = host,
.modules = std.StringArrayHashMap(*Module).init(allocator),
};
try self.top_level_steps.append(&self.install_tls);
try self.top_level_steps.append(&self.uninstall_tls);
try self.top_level_steps.put(allocator, self.install_tls.step.name, &self.install_tls);
try self.top_level_steps.put(allocator, self.uninstall_tls.step.name, &self.uninstall_tls);
self.default_step = &self.install_tls.step;
return self;
}
@ -288,7 +288,7 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc
.zig_exe = parent.zig_exe,
.default_step = undefined,
.env_map = parent.env_map,
.top_level_steps = ArrayList(*TopLevelStep).init(allocator),
.top_level_steps = .{},
.install_prefix = undefined,
.dest_dir = parent.dest_dir,
.lib_dir = parent.lib_dir,
@ -316,8 +316,8 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc
.dep_prefix = parent.fmt("{s}{s}.", .{ parent.dep_prefix, dep_name }),
.modules = std.StringArrayHashMap(*Module).init(allocator),
};
try child.top_level_steps.append(&child.install_tls);
try child.top_level_steps.append(&child.uninstall_tls);
try child.top_level_steps.put(allocator, child.install_tls.step.name, &child.install_tls);
try child.top_level_steps.put(allocator, child.uninstall_tls.step.name, &child.uninstall_tls);
child.default_step = &child.install_tls.step;
return child;
}
@ -389,10 +389,10 @@ fn applyArgs(b: *Build, args: anytype) !void {
b.resolveInstallPrefix(install_prefix, .{});
}
pub fn destroy(self: *Build) void {
self.env_map.deinit();
self.top_level_steps.deinit();
self.allocator.destroy(self);
pub fn destroy(b: *Build) void {
b.env_map.deinit();
b.top_level_steps.deinit(b.allocator);
b.allocator.destroy(b);
}
/// This function is intended to be called by lib/build_runner.zig, not a build.zig file.
@ -698,24 +698,6 @@ pub fn addTranslateC(self: *Build, options: TranslateCStep.Options) *TranslateCS
return TranslateCStep.create(self, options);
}
pub fn make(self: *Build, step_names: []const []const u8) !void {
var wanted_steps = ArrayList(*Step).init(self.allocator);
defer wanted_steps.deinit();
if (step_names.len == 0) {
try wanted_steps.append(self.default_step);
} else {
for (step_names) |step_name| {
const s = try self.getTopLevelStepByName(step_name);
try wanted_steps.append(s);
}
}
for (wanted_steps.items) |s| {
try self.makeOneStep(s);
}
}
pub fn getInstallStep(self: *Build) *Step {
return &self.install_tls.step;
}
@ -739,37 +721,6 @@ fn makeUninstall(uninstall_step: *Step) anyerror!void {
// TODO remove empty directories
}
fn makeOneStep(self: *Build, s: *Step) anyerror!void {
if (s.loop_flag) {
log.err("Dependency loop detected:\n {s}", .{s.name});
return error.DependencyLoopDetected;
}
s.loop_flag = true;
for (s.dependencies.items) |dep| {
self.makeOneStep(dep) catch |err| {
if (err == error.DependencyLoopDetected) {
log.err(" {s}", .{s.name});
}
return err;
};
}
s.loop_flag = false;
try s.make();
}
fn getTopLevelStepByName(self: *Build, name: []const u8) !*Step {
for (self.top_level_steps.items) |top_level_step| {
if (mem.eql(u8, top_level_step.step.name, name)) {
return &top_level_step.step;
}
}
log.err("Cannot run step '{s}' because it does not exist", .{name});
return error.InvalidStepName;
}
pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_raw: []const u8) ?T {
const name = self.dupe(name_raw);
const description = self.dupe(description_raw);
@ -910,7 +861,7 @@ pub fn step(self: *Build, name: []const u8, description: []const u8) *Step {
.step = Step.initNoOp(.top_level, name, self.allocator),
.description = self.dupe(description),
};
self.top_level_steps.append(step_info) catch @panic("OOM");
self.top_level_steps.put(self.allocator, step_info.step.name, step_info) catch @panic("OOM");
return &step_info.step;
}