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 {...@@ -131,6 +131,15 @@ pub fn main() !void {
131 } else if (mem.startsWith(u8, arg, "-fno-sys=")) {131 } else if (mem.startsWith(u8, arg, "-fno-sys=")) {
132 const name = arg["-fno-sys=".len..];132 const name = arg["-fno-sys=".len..];
133 graph.system_library_options.put(arena, name, .user_disabled) catch @panic("OOM");133 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 };
134 } else if (mem.eql(u8, arg, "--host-target")) {143 } else if (mem.eql(u8, arg, "--host-target")) {
135 graph.host_query_options.arch_os_abi = nextArgOrFatal(args, &arg_idx);144 graph.host_query_options.arch_os_abi = nextArgOrFatal(args, &arg_idx);
136 } else if (mem.eql(u8, arg, "--host-cpu")) {145 } else if (mem.eql(u8, arg, "--host-cpu")) {
...@@ -1049,6 +1058,9 @@ fn usage(b: *std.Build, out_stream: anytype) !void {...@@ -1049,6 +1058,9 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
1049 \\ --prefix-exe-dir [path] Where to put installed executables1058 \\ --prefix-exe-dir [path] Where to put installed executables
1050 \\ --prefix-include-dir [path] Where to put installed C header files1059 \\ --prefix-include-dir [path] Where to put installed C header files
1051 \\1060 \\
1061 \\ --release[=mode] Request release mode, optionally specifying a
1062 \\ preferred optimization mode: fast, safe, small
1063 \\
1052 \\ --sysroot [path] Set the system root directory (usually /)1064 \\ --sysroot [path] Set the system root directory (usually /)
1053 \\ --search-prefix [path] Add a path to look for binaries, libraries, headers1065 \\ --search-prefix [path] Add a path to look for binaries, libraries, headers
1054 \\ --libc [file] Provide a file which specifies libc paths1066 \\ --libc [file] Provide a file which specifies libc paths
lib/std/Build.zig+33-8
...@@ -96,6 +96,16 @@ initialized_deps: *InitializedDepMap,...@@ -96,6 +96,16 @@ initialized_deps: *InitializedDepMap,
96/// A mapping from dependency names to package hashes.96/// A mapping from dependency names to package hashes.
97available_deps: AvailableDeps,97available_deps: AvailableDeps,
9898
99release_mode: ReleaseMode,
100
101pub const ReleaseMode = enum {
102 off,
103 any,
104 fast,
105 safe,
106 small,
107};
108
99/// Shared state among all Build instances.109/// Shared state among all Build instances.
100/// Settings that are here rather than in Build are not configurable per-package.110/// Settings that are here rather than in Build are not configurable per-package.
101pub const Graph = struct {111pub const Graph = struct {
...@@ -295,6 +305,7 @@ pub fn create(...@@ -295,6 +305,7 @@ pub fn create(
295 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(arena),305 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(arena),
296 .initialized_deps = initialized_deps,306 .initialized_deps = initialized_deps,
297 .available_deps = available_deps,307 .available_deps = available_deps,
308 .release_mode = .off,
298 };309 };
299 try self.top_level_steps.put(arena, self.install_tls.step.name, &self.install_tls);310 try self.top_level_steps.put(arena, self.install_tls.step.name, &self.install_tls);
300 try self.top_level_steps.put(arena, self.uninstall_tls.step.name, &self.uninstall_tls);311 try self.top_level_steps.put(arena, self.uninstall_tls.step.name, &self.uninstall_tls);
...@@ -386,6 +397,7 @@ fn createChildOnly(...@@ -386,6 +397,7 @@ fn createChildOnly(
386 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator),397 .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator),
387 .initialized_deps = parent.initialized_deps,398 .initialized_deps = parent.initialized_deps,
388 .available_deps = pkg_deps,399 .available_deps = pkg_deps,
400 .release_mode = parent.release_mode,
389 };401 };
390 try child.top_level_steps.put(allocator, child.install_tls.step.name, &child.install_tls);402 try child.top_level_steps.put(allocator, child.install_tls.step.name, &child.install_tls);
391 try child.top_level_steps.put(allocator, child.uninstall_tls.step.name, &child.uninstall_tls);403 try child.top_level_steps.put(allocator, child.uninstall_tls.step.name, &child.uninstall_tls);
...@@ -1230,20 +1242,33 @@ pub const StandardOptimizeOptionOptions = struct {...@@ -1230,20 +1242,33 @@ pub const StandardOptimizeOptionOptions = struct {
1230 preferred_optimize_mode: ?std.builtin.OptimizeMode = null,1242 preferred_optimize_mode: ?std.builtin.OptimizeMode = null,
1231};1243};
12321244
1233pub fn standardOptimizeOption(self: *Build, options: StandardOptimizeOptionOptions) std.builtin.OptimizeMode {1245pub fn standardOptimizeOption(b: *Build, options: StandardOptimizeOptionOptions) std.builtin.OptimizeMode {
1234 if (options.preferred_optimize_mode) |mode| {1246 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)) {
1236 return mode;1248 return mode;
1237 } else {1249 } else {
1238 return .Debug;1250 return .Debug;
1239 }1251 }
1240 } else {
1241 return self.option(
1242 std.builtin.OptimizeMode,
1243 "optimize",
1244 "Prioritize performance, safety, or binary size (-O flag)",
1245 ) orelse .Debug;
1246 }1252 }
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 };
1247}1272}
12481273
1249pub const StandardTargetOptionsArgs = struct {1274pub const StandardTargetOptionsArgs = struct {