authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-02-01 20:17:07-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-02-02 20:43:01-07:00
log22537873f4e80fa1caca6b7b8a4b14c8d7284de2
tree62c068c73037e1a72142aff67c074b92cf82164f
parentf18576afad6b385377ba8fd18be3d05f7dc98c57

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.

2 files changed, 45 insertions(+), 8 deletions(-)

lib/build_runner.zig+12
......@@ -131,6 +131,15 @@ pub fn main() !void {
131131 } else if (mem.startsWith(u8, arg, "-fno-sys=")) {
132132 const name = arg["-fno-sys=".len..];
133133 graph.system_library_options.put(arena, name, .user_disabled) catch @panic("OOM");
134 } else if (mem.eql(u8, arg, "--release")) {
135 builder.release_mode = .any;
136 } else if (mem.startsWith(u8, arg, "--release=")) {
137 const text = arg["--release=".len..];
138 builder.release_mode = std.meta.stringToEnum(std.Build.ReleaseMode, text) orelse {
139 fatalWithHint("expected [off|any|fast|safe|small] in '{s}', found '{s}'", .{
140 arg, text,
141 });
142 };
134143 } else if (mem.eql(u8, arg, "--host-target")) {
135144 graph.host_query_options.arch_os_abi = nextArgOrFatal(args, &arg_idx);
136145 } else if (mem.eql(u8, arg, "--host-cpu")) {
......@@ -1049,6 +1058,9 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
10491058 \\ --prefix-exe-dir [path] Where to put installed executables
10501059 \\ --prefix-include-dir [path] Where to put installed C header files
10511060 \\
1061 \\ --release[=mode] Request release mode, optionally specifying a
1062 \\ preferred optimization mode: fast, safe, small
1063 \\
10521064 \\ --sysroot [path] Set the system root directory (usually /)
10531065 \\ --search-prefix [path] Add a path to look for binaries, libraries, headers
10541066 \\ --libc [file] Provide a file which specifies libc paths
lib/std/Build.zig+33-8
......@@ -96,6 +96,16 @@ initialized_deps: *InitializedDepMap,
9696/// A mapping from dependency names to package hashes.
9797available_deps: AvailableDeps,
9898
99release_mode: ReleaseMode,
100
101pub const ReleaseMode = enum {
102 off,
103 any,
104 fast,
105 safe,
106 small,
107};
108
99109/// Shared state among all Build instances.
100110/// Settings that are here rather than in Build are not configurable per-package.
101111pub const Graph = struct {
......@@ -295,6 +305,7 @@ pub fn create(
295305 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(arena),
296306 .initialized_deps = initialized_deps,
297307 .available_deps = available_deps,
308 .release_mode = .off,
298309 };
299310 try self.top_level_steps.put(arena, self.install_tls.step.name, &self.install_tls);
300311 try self.top_level_steps.put(arena, self.uninstall_tls.step.name, &self.uninstall_tls);
......@@ -386,6 +397,7 @@ fn createChildOnly(
386397 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator),
387398 .initialized_deps = parent.initialized_deps,
388399 .available_deps = pkg_deps,
400 .release_mode = parent.release_mode,
389401 };
390402 try child.top_level_steps.put(allocator, child.install_tls.step.name, &child.install_tls);
391403 try child.top_level_steps.put(allocator, child.uninstall_tls.step.name, &child.uninstall_tls);
......@@ -1230,20 +1242,33 @@ pub const StandardOptimizeOptionOptions = struct {
12301242 preferred_optimize_mode: ?std.builtin.OptimizeMode = null,
12311243};
12321244
1233pub fn standardOptimizeOption(self: *Build, options: StandardOptimizeOptionOptions) std.builtin.OptimizeMode {
1245pub fn standardOptimizeOption(b: *Build, options: StandardOptimizeOptionOptions) std.builtin.OptimizeMode {
12341246 if (options.preferred_optimize_mode) |mode| {
1235 if (self.option(bool, "release", "optimize for end users") orelse false) {
1247 if (b.option(bool, "release", "optimize for end users") orelse (b.release_mode != .off)) {
12361248 return mode;
12371249 } else {
12381250 return .Debug;
12391251 }
1240 } else {
1241 return self.option(
1242 std.builtin.OptimizeMode,
1243 "optimize",
1244 "Prioritize performance, safety, or binary size (-O flag)",
1245 ) orelse .Debug;
12461252 }
1253
1254 if (b.option(
1255 std.builtin.OptimizeMode,
1256 "optimize",
1257 "Prioritize performance, safety, or binary size (-O flag)",
1258 )) |mode| {
1259 return mode;
1260 }
1261
1262 return switch (b.release_mode) {
1263 .off => .Debug,
1264 .any => {
1265 std.debug.print("the project does not declare a preferred optimization mode. choose: --release=fast, --release=safe, or --release=small\n", .{});
1266 process.exit(1);
1267 },
1268 .fast => .ReleaseFast,
1269 .safe => .ReleaseSafe,
1270 .small => .ReleaseSmall,
1271 };
12471272}
12481273
12491274pub const StandardTargetOptionsArgs = struct {