Commit 8f867eaf84
Changed files (2)
lib
lib/std/Build.zig
@@ -28,6 +28,9 @@ allocator: Allocator,
user_input_options: UserInputOptionsMap,
available_options_map: AvailableOptionsMap,
available_options_list: ArrayList(AvailableOption),
+/// All Build instances share this hash map.
+system_library_options: *std.StringArrayHashMapUnmanaged(SystemLibraryMode),
+system_package_mode: bool,
verbose: bool,
verbose_link: bool,
verbose_cc: bool,
@@ -100,6 +103,21 @@ available_deps: AvailableDeps,
const AvailableDeps = []const struct { []const u8, []const u8 };
+pub const SystemLibraryMode = enum {
+ /// User asked for the library to be disabled.
+ /// The build runner has not confirmed whether the setting is recognized yet.
+ user_disabled,
+ /// User asked for the library to be enabled.
+ /// The build runner has not confirmed whether the setting is recognized yet.
+ user_enabled,
+ /// The build runner has confirmed that this setting is recognized.
+ /// System integration with this library has been resolved to off.
+ declared_disabled,
+ /// The build runner has confirmed that this setting is recognized.
+ /// System integration with this library has been resolved to on.
+ declared_enabled,
+};
+
const InitializedDepMap = std.HashMap(InitializedDepKey, *Dependency, InitializedDepContext, std.hash_map.default_max_load_percentage);
const InitializedDepKey = struct {
build_root_string: []const u8,
@@ -216,6 +234,7 @@ pub fn create(
host: ResolvedTarget,
cache: *Cache,
available_deps: AvailableDeps,
+ system_library_options: *std.StringArrayHashMapUnmanaged(SystemLibraryMode),
) !*Build {
const env_map = try allocator.create(EnvMap);
env_map.* = try process.getEnvMap(allocator);
@@ -278,6 +297,8 @@ pub fn create(
.named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator),
.initialized_deps = initialized_deps,
.available_deps = available_deps,
+ .system_library_options = system_library_options,
+ .system_package_mode = false,
};
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);
@@ -297,7 +318,13 @@ fn createChild(
return child;
}
-fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Directory, pkg_deps: AvailableDeps, user_input_options: UserInputOptionsMap) !*Build {
+fn createChildOnly(
+ parent: *Build,
+ dep_name: []const u8,
+ build_root: Cache.Directory,
+ pkg_deps: AvailableDeps,
+ user_input_options: UserInputOptionsMap,
+) !*Build {
const allocator = parent.allocator;
const child = try allocator.create(Build);
child.* = .{
@@ -366,6 +393,8 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc
.named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator),
.initialized_deps = parent.initialized_deps,
.available_deps = pkg_deps,
+ .system_library_options = parent.system_library_options,
+ .system_package_mode = parent.system_package_mode,
};
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);
@@ -1367,7 +1396,7 @@ pub fn addUserInputOption(self: *Build, name_raw: []const u8, value_raw: []const
});
},
.flag => {
- log.warn("Option '-D{s}={s}' conflicts with flag '-D{s}'.", .{ name, value, name });
+ log.warn("option '-D{s}={s}' conflicts with flag '-D{s}'.", .{ name, value, name });
return true;
},
.map => |*map| {
@@ -1427,17 +1456,17 @@ fn markInvalidUserInput(self: *Build) void {
self.invalid_user_input = true;
}
-pub fn validateUserInputDidItFail(self: *Build) bool {
- // make sure all args are used
- var it = self.user_input_options.iterator();
+pub fn validateUserInputDidItFail(b: *Build) bool {
+ // Make sure all args are used.
+ var it = b.user_input_options.iterator();
while (it.next()) |entry| {
if (!entry.value_ptr.used) {
- log.err("Invalid option: -D{s}", .{entry.key_ptr.*});
- self.markInvalidUserInput();
+ log.err("invalid option: -D{s}", .{entry.key_ptr.*});
+ b.markInvalidUserInput();
}
}
- return self.invalid_user_input;
+ return b.invalid_user_input;
}
fn allocPrintCmd(ally: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) ![]u8 {
@@ -2296,6 +2325,31 @@ pub fn wantSharedLibSymLinks(target: Target) bool {
return target.os.tag != .windows;
}
+pub fn systemLibraryOption(b: *Build, name: []const u8) bool {
+ const gop = b.system_library_options.getOrPut(b.allocator, name) catch @panic("OOM");
+ if (gop.found_existing) switch (gop.value_ptr.*) {
+ .user_disabled => {
+ gop.value_ptr.* = .declared_disabled;
+ return false;
+ },
+ .user_enabled => {
+ gop.value_ptr.* = .declared_enabled;
+ return true;
+ },
+ .declared_disabled => return false,
+ .declared_enabled => return true,
+ } else {
+ gop.key_ptr.* = b.dupe(name);
+ if (b.system_package_mode) {
+ gop.value_ptr.* = .declared_enabled;
+ return true;
+ } else {
+ gop.value_ptr.* = .declared_disabled;
+ return false;
+ }
+ }
+}
+
test {
_ = Cache;
_ = Step;
lib/build_runner.zig
@@ -76,6 +76,8 @@ pub fn main() !void {
cache.addPrefix(global_cache_directory);
cache.hash.addBytes(builtin.zig_version_string);
+ var system_library_options: std.StringArrayHashMapUnmanaged(std.Build.SystemLibraryMode) = .{};
+
const builder = try std.Build.create(
arena,
zig_exe,
@@ -85,8 +87,8 @@ pub fn main() !void {
host,
&cache,
dependencies.root_deps,
+ &system_library_options,
);
- defer builder.destroy();
var targets = ArrayList([]const u8).init(arena);
var debug_log_scopes = ArrayList([]const u8).init(arena);
@@ -100,64 +102,50 @@ pub fn main() !void {
var color: Color = .auto;
var seed: u32 = 0;
var prominent_compile_errors: bool = false;
+ var help_menu: bool = false;
+ var steps_menu: bool = false;
- const stderr_stream = io.getStdErr().writer();
const stdout_stream = io.getStdOut().writer();
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", .{});
- usageAndErr(builder, false, stderr_stream);
- }
+ if (option_contents.len == 0)
+ fatalWithHint("expected option name after '-D'", .{});
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))
- usageAndErr(builder, false, stderr_stream);
+ fatal(" access the help menu with 'zig build -h'", .{});
} else {
if (try builder.addUserInputFlag(option_contents))
- usageAndErr(builder, false, stderr_stream);
+ fatal(" access the help menu with 'zig build -h'", .{});
}
} else if (mem.startsWith(u8, arg, "-")) {
if (mem.eql(u8, arg, "--verbose")) {
builder.verbose = true;
} else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
- return usage(builder, false, stdout_stream);
+ help_menu = true;
} 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});
- usageAndErr(builder, false, stderr_stream);
- };
+ install_prefix = nextArgOrFatal(args, &arg_idx);
} else if (mem.eql(u8, arg, "-l") or mem.eql(u8, arg, "--list-steps")) {
- return steps(builder, false, stdout_stream);
+ steps_menu = true;
+ } else if (mem.eql(u8, arg, "--system-lib")) {
+ const name = nextArgOrFatal(args, &arg_idx);
+ builder.system_library_options.put(arena, name, .user_enabled) catch @panic("OOM");
+ } else if (mem.eql(u8, arg, "--no-system-lib")) {
+ const name = nextArgOrFatal(args, &arg_idx);
+ builder.system_library_options.put(arena, name, .user_disabled) catch @panic("OOM");
} 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});
- usageAndErr(builder, false, stderr_stream);
- };
+ dir_list.lib_dir = nextArgOrFatal(args, &arg_idx);
} 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});
- usageAndErr(builder, false, stderr_stream);
- };
+ dir_list.exe_dir = nextArgOrFatal(args, &arg_idx);
} 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});
- usageAndErr(builder, false, stderr_stream);
- };
+ dir_list.include_dir = nextArgOrFatal(args, &arg_idx);
} else if (mem.eql(u8, arg, "--sysroot")) {
- const sysroot = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected argument after {s}\n\n", .{arg});
- usageAndErr(builder, false, stderr_stream);
- };
- builder.sysroot = sysroot;
+ builder.sysroot = nextArgOrFatal(args, &arg_idx);
} else if (mem.eql(u8, arg, "--maxrss")) {
- const max_rss_text = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected argument after {s}\n\n", .{arg});
- usageAndErr(builder, false, stderr_stream);
- };
+ const max_rss_text = nextArgOrFatal(args, &arg_idx);
max_rss = std.fmt.parseIntSizeSuffix(max_rss_text, 10) catch |err| {
std.debug.print("invalid byte size: '{s}': {s}\n", .{
max_rss_text, @errorName(err),
@@ -167,66 +155,45 @@ pub fn main() !void {
} else if (mem.eql(u8, arg, "--skip-oom-steps")) {
skip_oom_steps = true;
} else if (mem.eql(u8, arg, "--search-prefix")) {
- const search_prefix = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected argument after {s}\n\n", .{arg});
- usageAndErr(builder, false, stderr_stream);
- };
+ const search_prefix = nextArgOrFatal(args, &arg_idx);
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 {s}\n\n", .{arg});
- usageAndErr(builder, false, stderr_stream);
- };
- builder.libc_file = libc_file;
+ builder.libc_file = nextArgOrFatal(args, &arg_idx);
} else if (mem.eql(u8, arg, "--color")) {
- const next_arg = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected [auto|on|off] after {s}\n\n", .{arg});
- usageAndErr(builder, false, stderr_stream);
- };
+ const next_arg = nextArg(args, &arg_idx) orelse
+ fatalWithHint("expected [auto|on|off] after '{s}'", .{arg});
color = std.meta.stringToEnum(Color, next_arg) orelse {
- std.debug.print("Expected [auto|on|off] after {s}, found '{s}'\n\n", .{ arg, next_arg });
- usageAndErr(builder, false, stderr_stream);
+ fatalWithHint("expected [auto|on|off] after '{s}', found '{s}'", .{
+ arg, next_arg,
+ });
};
} else if (mem.eql(u8, arg, "--summary")) {
- const next_arg = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected [all|failures|none] after {s}\n\n", .{arg});
- usageAndErr(builder, false, stderr_stream);
- };
+ const next_arg = nextArg(args, &arg_idx) orelse
+ fatalWithHint("expected [all|failures|none] after '{s}'", .{arg});
summary = std.meta.stringToEnum(Summary, next_arg) orelse {
- std.debug.print("Expected [all|failures|none] after {s}, found '{s}'\n\n", .{ arg, next_arg });
- usageAndErr(builder, false, stderr_stream);
+ fatalWithHint("expected [all|failures|none] after '{s}', found '{s}'", .{
+ arg, next_arg,
+ });
};
} else if (mem.eql(u8, arg, "--zig-lib-dir")) {
- builder.zig_lib_dir = .{ .cwd_relative = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected argument after {s}\n\n", .{arg});
- usageAndErr(builder, false, stderr_stream);
- } };
+ builder.zig_lib_dir = .{ .cwd_relative = nextArgOrFatal(args, &arg_idx) };
} else if (mem.eql(u8, arg, "--seed")) {
- const next_arg = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected u32 after {s}\n\n", .{arg});
- usageAndErr(builder, false, stderr_stream);
- };
+ const next_arg = nextArg(args, &arg_idx) orelse
+ fatalWithHint("expected u32 after '{s}'", .{arg});
seed = std.fmt.parseUnsigned(u32, next_arg, 0) catch |err| {
- std.debug.print("unable to parse seed '{s}' as 32-bit integer: {s}\n", .{
+ fatal("unable to parse seed '{s}' as 32-bit integer: {s}\n", .{
next_arg, @errorName(err),
});
- process.exit(1);
};
} 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});
- usageAndErr(builder, false, stderr_stream);
- };
+ const next_arg = nextArgOrFatal(args, &arg_idx);
try debug_log_scopes.append(next_arg);
} else if (mem.eql(u8, arg, "--debug-pkg-config")) {
builder.debug_pkg_config = true;
} else if (mem.eql(u8, arg, "--debug-compile-errors")) {
builder.debug_compile_errors = true;
} else if (mem.eql(u8, arg, "--glibc-runtimes")) {
- builder.glibc_runtimes_dir = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected argument after {s}\n\n", .{arg});
- usageAndErr(builder, false, stderr_stream);
- };
+ builder.glibc_runtimes_dir = nextArgOrFatal(args, &arg_idx);
} else if (mem.eql(u8, arg, "--verbose-link")) {
builder.verbose_link = true;
} else if (mem.eql(u8, arg, "--verbose-air")) {
@@ -292,8 +259,7 @@ pub fn main() !void {
builder.args = argsRest(args, arg_idx);
break;
} else {
- std.debug.print("Unrecognized argument: {s}\n\n", .{arg});
- usageAndErr(builder, false, stderr_stream);
+ fatalWithHint("unrecognized argument: '{s}'", .{arg});
}
} else {
try targets.append(arg);
@@ -319,8 +285,17 @@ pub fn main() !void {
try builder.runBuild(root);
}
- if (builder.validateUserInputDidItFail())
- usageAndErr(builder, true, stderr_stream);
+ if (builder.validateUserInputDidItFail()) {
+ fatal(" access the help menu with 'zig build -h'", .{});
+ }
+
+ validateSystemLibraryOptions(builder);
+
+ if (help_menu)
+ return usage(builder, stdout_stream);
+
+ if (steps_menu)
+ return steps(builder, stdout_stream);
var run: Run = .{
.max_rss = max_rss,
@@ -389,7 +364,7 @@ fn runStepNames(
for (0..step_names.len) |i| {
const step_name = step_names[step_names.len - i - 1];
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});
+ std.debug.print("no step named '{s}'\n access the help menu with 'zig build -h'\n", .{step_name});
process.exit(1);
};
step_stack.putAssumeCapacity(&s.step, {});
@@ -1037,13 +1012,7 @@ fn printErrorMessages(b: *std.Build, failing_step: *Step, run: *const Run) !void
}
}
-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) {
- builder.resolveInstallPrefix(null, .{});
- try builder.runBuild(root);
- }
-
+fn steps(builder: *std.Build, out_stream: anytype) !void {
const allocator = builder.allocator;
for (builder.top_level_steps.values()) |top_level_step| {
const name = if (&top_level_step.step == builder.default_step)
@@ -1054,29 +1023,22 @@ fn steps(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
}
}
-fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !void {
- // run the build script to collect the options
- if (!already_ran_build) {
- builder.resolveInstallPrefix(null, .{});
- try builder.runBuild(root);
- }
-
+fn usage(b: *std.Build, out_stream: anytype) !void {
try out_stream.print(
- \\
\\Usage: {s} build [steps] [options]
\\
\\Steps:
\\
- , .{builder.zig_exe});
- try steps(builder, true, out_stream);
+ , .{b.zig_exe});
+ try steps(b, out_stream);
try out_stream.writeAll(
\\
\\General Options:
- \\ -p, --prefix [path] Override default install prefix
- \\ --prefix-lib-dir [path] Override default library directory path
- \\ --prefix-exe-dir [path] Override default executable directory path
- \\ --prefix-include-dir [path] Override default include directory path
+ \\ -p, --prefix [path] Where to put installed files (default: zig-out)
+ \\ --prefix-lib-dir [path] Where to put installed libraries
+ \\ --prefix-exe-dir [path] Where to put installed executables
+ \\ --prefix-include-dir [path] Where to put installed C header files
\\
\\ --sysroot [path] Set the system root directory (usually /)
\\ --search-prefix [path] Add a path to look for binaries, libraries, headers
@@ -1116,16 +1078,15 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
\\
);
- const allocator = builder.allocator;
- if (builder.available_options_list.items.len == 0) {
+ const arena = b.allocator;
+ if (b.available_options_list.items.len == 0) {
try out_stream.print(" (none)\n", .{});
} else {
- for (builder.available_options_list.items) |option| {
- const name = try fmt.allocPrint(allocator, " -D{s}=[{s}]", .{
+ for (b.available_options_list.items) |option| {
+ const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{
option.name,
@tagName(option.type_id),
});
- defer allocator.free(name);
try out_stream.print("{s:<30} {s}\n", .{ name, option.description });
if (option.enum_options) |enum_options| {
const padding = " " ** 33;
@@ -1137,6 +1098,31 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
}
}
+ try out_stream.writeAll(
+ \\
+ \\System Integration Options:
+ \\ --system [dir] System Package Mode. Disable fetching; prefer system libs
+ \\ --host-target [triple] Use the provided target as the host
+ \\ --host-cpu [cpu] Use the provided CPU as the host
+ \\ --system-lib [name] Use the system-provided library
+ \\ --no-system-lib [name] Do not use the system-provided library
+ \\
+ \\ Available System Library Integrations: Enabled:
+ \\
+ );
+ if (b.system_library_options.entries.len == 0) {
+ try out_stream.writeAll(" (none) -\n");
+ } else {
+ for (b.system_library_options.keys(), b.system_library_options.values()) |name, v| {
+ const status = switch (v) {
+ .declared_enabled => "yes",
+ .declared_disabled => "no",
+ .user_enabled, .user_disabled => unreachable, // already emitted error
+ };
+ try out_stream.print(" {s:<43} {s}\n", .{ name, status });
+ }
+ }
+
try out_stream.writeAll(
\\
\\Advanced Options:
@@ -1161,17 +1147,19 @@ 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) noreturn {
- usage(builder, already_ran_build, out_stream) catch {};
- process.exit(1);
-}
-
fn nextArg(args: [][:0]const u8, idx: *usize) ?[:0]const u8 {
if (idx.* >= args.len) return null;
defer idx.* += 1;
return args[idx.*];
}
+fn nextArgOrFatal(args: [][:0]const u8, idx: *usize) [:0]const u8 {
+ return nextArg(args, idx) orelse {
+ std.debug.print("expected argument after '{s}'\n access the help menu with 'zig build -h'\n", .{args[idx.*]});
+ process.exit(1);
+ };
+}
+
fn argsRest(args: [][:0]const u8, idx: usize) ?[][:0]const u8 {
if (idx >= args.len) return null;
return args[idx..];
@@ -1202,3 +1190,32 @@ fn renderOptions(ttyconf: std.io.tty.Config) std.zig.ErrorBundle.RenderOptions {
.include_reference_trace = ttyconf != .no_color,
};
}
+
+fn fatalWithHint(comptime f: []const u8, args: anytype) noreturn {
+ std.debug.print(f ++ "\n access the help menu with 'zig build -h'\n", args);
+ process.exit(1);
+}
+
+fn fatal(comptime f: []const u8, args: anytype) noreturn {
+ std.debug.print(f ++ "\n", args);
+ process.exit(1);
+}
+
+fn validateSystemLibraryOptions(b: *std.Build) void {
+ var bad = false;
+ for (b.system_library_options.keys(), b.system_library_options.values()) |k, v| {
+ switch (v) {
+ .user_disabled, .user_enabled => {
+ // The user tried to enable or disable a system library integration, but
+ // the build script did not recognize that option.
+ std.debug.print("system library name not recognized by build script: '{s}'\n", .{k});
+ bad = true;
+ },
+ .declared_disabled, .declared_enabled => {},
+ }
+ }
+ if (bad) {
+ std.debug.print(" access the help menu with 'zig build -h'\n", .{});
+ process.exit(1);
+ }
+}