From 22537873f4e80fa1caca6b7b8a4b14c8d7284de2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 1 Feb 2024 20:17:07 -0700 Subject: [PATCH] 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. --- lib/build_runner.zig | 12 ++++++++++++ lib/std/Build.zig | 41 +++++++++++++++++++++++++++++++++-------- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/lib/build_runner.zig b/lib/build_runner.zig index bcefa350d3..2fd8ecd034 100644 --- a/lib/build_runner.zig +++ b/lib/build_runner.zig @@ -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 diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 8105b7330d..6bdd391430 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -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 {