build system: implement --release[=mode]

This allows a `zig build` command to specify intention to create a
release build, regardless of what per-project options exist. It also
allows the command to specify a "preferred optimization mode", which is
chosen if the project itself does not choose one (in other words, the
project gets first choice). If neither the build command nor the project
specify a preferred release mode, an error occurs.
This commit is contained in:
Andrew Kelley 2024-02-01 20:17:07 -07:00
parent f18576afad
commit 22537873f4
2 changed files with 45 additions and 8 deletions

View File

@ -131,6 +131,15 @@ pub fn main() !void {
} else if (mem.startsWith(u8, arg, "-fno-sys=")) {
const name = arg["-fno-sys=".len..];
graph.system_library_options.put(arena, name, .user_disabled) catch @panic("OOM");
} else if (mem.eql(u8, arg, "--release")) {
builder.release_mode = .any;
} else if (mem.startsWith(u8, arg, "--release=")) {
const text = arg["--release=".len..];
builder.release_mode = std.meta.stringToEnum(std.Build.ReleaseMode, text) orelse {
fatalWithHint("expected [off|any|fast|safe|small] in '{s}', found '{s}'", .{
arg, text,
});
};
} else if (mem.eql(u8, arg, "--host-target")) {
graph.host_query_options.arch_os_abi = nextArgOrFatal(args, &arg_idx);
} else if (mem.eql(u8, arg, "--host-cpu")) {
@ -1049,6 +1058,9 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
\\ --prefix-exe-dir [path] Where to put installed executables
\\ --prefix-include-dir [path] Where to put installed C header files
\\
\\ --release[=mode] Request release mode, optionally specifying a
\\ preferred optimization mode: fast, safe, small
\\
\\ --sysroot [path] Set the system root directory (usually /)
\\ --search-prefix [path] Add a path to look for binaries, libraries, headers
\\ --libc [file] Provide a file which specifies libc paths

View File

@ -96,6 +96,16 @@ initialized_deps: *InitializedDepMap,
/// A mapping from dependency names to package hashes.
available_deps: AvailableDeps,
release_mode: ReleaseMode,
pub const ReleaseMode = enum {
off,
any,
fast,
safe,
small,
};
/// Shared state among all Build instances.
/// Settings that are here rather than in Build are not configurable per-package.
pub const Graph = struct {
@ -295,6 +305,7 @@ pub fn create(
.named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(arena),
.initialized_deps = initialized_deps,
.available_deps = available_deps,
.release_mode = .off,
};
try self.top_level_steps.put(arena, self.install_tls.step.name, &self.install_tls);
try self.top_level_steps.put(arena, self.uninstall_tls.step.name, &self.uninstall_tls);
@ -386,6 +397,7 @@ fn createChildOnly(
.named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator),
.initialized_deps = parent.initialized_deps,
.available_deps = pkg_deps,
.release_mode = parent.release_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);
@ -1230,20 +1242,33 @@ pub const StandardOptimizeOptionOptions = struct {
preferred_optimize_mode: ?std.builtin.OptimizeMode = null,
};
pub fn standardOptimizeOption(self: *Build, options: StandardOptimizeOptionOptions) std.builtin.OptimizeMode {
pub fn standardOptimizeOption(b: *Build, options: StandardOptimizeOptionOptions) std.builtin.OptimizeMode {
if (options.preferred_optimize_mode) |mode| {
if (self.option(bool, "release", "optimize for end users") orelse false) {
if (b.option(bool, "release", "optimize for end users") orelse (b.release_mode != .off)) {
return mode;
} else {
return .Debug;
}
} else {
return self.option(
std.builtin.OptimizeMode,
"optimize",
"Prioritize performance, safety, or binary size (-O flag)",
) orelse .Debug;
}
if (b.option(
std.builtin.OptimizeMode,
"optimize",
"Prioritize performance, safety, or binary size (-O flag)",
)) |mode| {
return mode;
}
return switch (b.release_mode) {
.off => .Debug,
.any => {
std.debug.print("the project does not declare a preferred optimization mode. choose: --release=fast, --release=safe, or --release=small\n", .{});
process.exit(1);
},
.fast => .ReleaseFast,
.safe => .ReleaseSafe,
.small => .ReleaseSmall,
};
}
pub const StandardTargetOptionsArgs = struct {