aboutsummaryrefslogtreecommitdiff
path: root/lib/std/special/build_runner.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2019-09-26 01:54:45 -0400
committerGitHub <noreply@github.com>2019-09-26 01:54:45 -0400
commit68bb3945708c43109c48bda3664176307d45b62c (patch)
treeafb9731e10cef9d192560b52cd9ae2cf179775c4 /lib/std/special/build_runner.zig
parent6128bc728d1e1024a178c16c2149f5b1a167a013 (diff)
parent4637e8f9699af9c3c6cf4df50ef5bb67c7a318a4 (diff)
downloadzig-68bb3945708c43109c48bda3664176307d45b62c.tar.gz
zig-68bb3945708c43109c48bda3664176307d45b62c.zip
Merge pull request #3315 from ziglang/mv-std-lib
Move std/ to lib/std/
Diffstat (limited to 'lib/std/special/build_runner.zig')
-rw-r--r--lib/std/special/build_runner.zig221
1 files changed, 221 insertions, 0 deletions
diff --git a/lib/std/special/build_runner.zig b/lib/std/special/build_runner.zig
new file mode 100644
index 0000000000..efe3275fe6
--- /dev/null
+++ b/lib/std/special/build_runner.zig
@@ -0,0 +1,221 @@
+const root = @import("@build");
+const std = @import("std");
+const builtin = @import("builtin");
+const io = std.io;
+const fmt = std.fmt;
+const Builder = std.build.Builder;
+const mem = std.mem;
+const process = std.process;
+const ArrayList = std.ArrayList;
+const warn = std.debug.warn;
+const File = std.fs.File;
+
+pub fn main() !void {
+ var arg_it = process.args();
+
+ // Here we use an ArenaAllocator backed by a DirectAllocator because a build is a short-lived,
+ // one shot program. We don't need to waste time freeing memory and finding places to squish
+ // bytes into. So we free everything all at once at the very end.
+
+ var arena = std.heap.ArenaAllocator.init(std.heap.direct_allocator);
+ defer arena.deinit();
+
+ const allocator = &arena.allocator;
+
+ // skip my own exe name
+ _ = arg_it.skip();
+
+ const zig_exe = try unwrapArg(arg_it.next(allocator) orelse {
+ warn("Expected first argument to be path to zig compiler\n");
+ return error.InvalidArgs;
+ });
+ const build_root = try unwrapArg(arg_it.next(allocator) orelse {
+ warn("Expected second argument to be build root directory path\n");
+ return error.InvalidArgs;
+ });
+ const cache_root = try unwrapArg(arg_it.next(allocator) orelse {
+ warn("Expected third argument to be cache root directory path\n");
+ return error.InvalidArgs;
+ });
+
+ const builder = try Builder.create(allocator, zig_exe, build_root, cache_root);
+ defer builder.destroy();
+
+ var targets = ArrayList([]const u8).init(allocator);
+
+ var stderr_file = io.getStdErr();
+ var stderr_file_stream: File.OutStream = undefined;
+ var stderr_stream = if (stderr_file) |f| x: {
+ stderr_file_stream = f.outStream();
+ break :x &stderr_file_stream.stream;
+ } else |err| err;
+
+ var stdout_file = io.getStdOut();
+ var stdout_file_stream: File.OutStream = undefined;
+ var stdout_stream = if (stdout_file) |f| x: {
+ stdout_file_stream = f.outStream();
+ break :x &stdout_file_stream.stream;
+ } else |err| err;
+
+ while (arg_it.next(allocator)) |err_or_arg| {
+ const arg = try unwrapArg(err_or_arg);
+ if (mem.startsWith(u8, arg, "-D")) {
+ const option_contents = arg[2..];
+ if (option_contents.len == 0) {
+ warn("Expected option name after '-D'\n\n");
+ return usageAndErr(builder, false, try stderr_stream);
+ }
+ 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))
+ return usageAndErr(builder, false, try stderr_stream);
+ } else {
+ if (try builder.addUserInputFlag(option_contents))
+ return usageAndErr(builder, false, try stderr_stream);
+ }
+ } else if (mem.startsWith(u8, arg, "-")) {
+ if (mem.eql(u8, arg, "--verbose")) {
+ builder.verbose = true;
+ } else if (mem.eql(u8, arg, "--help")) {
+ return usage(builder, false, try stdout_stream);
+ } else if (mem.eql(u8, arg, "--prefix")) {
+ builder.install_prefix = try unwrapArg(arg_it.next(allocator) orelse {
+ warn("Expected argument after --prefix\n\n");
+ return usageAndErr(builder, false, try stderr_stream);
+ });
+ } else if (mem.eql(u8, arg, "--search-prefix")) {
+ const search_prefix = try unwrapArg(arg_it.next(allocator) orelse {
+ warn("Expected argument after --search-prefix\n\n");
+ return usageAndErr(builder, false, try stderr_stream);
+ });
+ builder.addSearchPrefix(search_prefix);
+ } else if (mem.eql(u8, arg, "--override-lib-dir")) {
+ builder.override_lib_dir = try unwrapArg(arg_it.next(allocator) orelse {
+ warn("Expected argument after --override-lib-dir\n\n");
+ return usageAndErr(builder, false, try stderr_stream);
+ });
+ } else if (mem.eql(u8, arg, "--verbose-tokenize")) {
+ builder.verbose_tokenize = true;
+ } else if (mem.eql(u8, arg, "--verbose-ast")) {
+ builder.verbose_ast = true;
+ } else if (mem.eql(u8, arg, "--verbose-link")) {
+ builder.verbose_link = true;
+ } else if (mem.eql(u8, arg, "--verbose-ir")) {
+ builder.verbose_ir = true;
+ } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
+ builder.verbose_llvm_ir = true;
+ } else if (mem.eql(u8, arg, "--verbose-cimport")) {
+ builder.verbose_cimport = true;
+ } else if (mem.eql(u8, arg, "--verbose-cc")) {
+ builder.verbose_cc = true;
+ } else {
+ warn("Unrecognized argument: {}\n\n", arg);
+ return usageAndErr(builder, false, try stderr_stream);
+ }
+ } else {
+ try targets.append(arg);
+ }
+ }
+
+ builder.resolveInstallPrefix();
+ try runBuild(builder);
+
+ if (builder.validateUserInputDidItFail())
+ return usageAndErr(builder, true, try stderr_stream);
+
+ builder.make(targets.toSliceConst()) catch |err| {
+ switch (err) {
+ error.InvalidStepName => {
+ return usageAndErr(builder, true, try stderr_stream);
+ },
+ error.UncleanExit => process.exit(1),
+ else => return err,
+ }
+ };
+}
+
+fn runBuild(builder: *Builder) anyerror!void {
+ switch (@typeId(@typeOf(root.build).ReturnType)) {
+ .Void => root.build(builder),
+ .ErrorUnion => try root.build(builder),
+ else => @compileError("expected return type of build to be 'void' or '!void'"),
+ }
+}
+
+fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
+ // run the build script to collect the options
+ if (!already_ran_build) {
+ builder.setInstallPrefix(null);
+ builder.resolveInstallPrefix();
+ try runBuild(builder);
+ }
+
+ try out_stream.print(
+ \\Usage: {} build [steps] [options]
+ \\
+ \\Steps:
+ \\
+ , builder.zig_exe);
+
+ const allocator = builder.allocator;
+ for (builder.top_level_steps.toSliceConst()) |top_level_step| {
+ const name = if (&top_level_step.step == builder.default_step)
+ try fmt.allocPrint(allocator, "{} (default)", top_level_step.step.name)
+ else
+ top_level_step.step.name;
+ try out_stream.print(" {s:22} {}\n", name, top_level_step.description);
+ }
+
+ try out_stream.write(
+ \\
+ \\General Options:
+ \\ --help Print this help and exit
+ \\ --verbose Print commands before executing them
+ \\ --prefix [path] Override default install prefix
+ \\ --search-prefix [path] Add a path to look for binaries, libraries, headers
+ \\
+ \\Project-Specific Options:
+ \\
+ );
+
+ if (builder.available_options_list.len == 0) {
+ try out_stream.print(" (none)\n");
+ } else {
+ for (builder.available_options_list.toSliceConst()) |option| {
+ const name = try fmt.allocPrint(allocator, " -D{}=[{}]", option.name, Builder.typeIdName(option.type_id));
+ defer allocator.free(name);
+ try out_stream.print("{s:24} {}\n", name, option.description);
+ }
+ }
+
+ try out_stream.write(
+ \\
+ \\Advanced Options:
+ \\ --build-file [file] Override path to build.zig
+ \\ --cache-dir [path] Override path to zig cache directory
+ \\ --override-lib-dir [arg] Override path to Zig lib directory
+ \\ --verbose-tokenize Enable compiler debug output for tokenization
+ \\ --verbose-ast Enable compiler debug output for parsing into an AST
+ \\ --verbose-link Enable compiler debug output for linking
+ \\ --verbose-ir Enable compiler debug output for Zig IR
+ \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR
+ \\ --verbose-cimport Enable compiler debug output for C imports
+ \\ --verbose-cc Enable compiler debug output for C compilation
+ \\
+ );
+}
+
+fn usageAndErr(builder: *Builder, already_ran_build: bool, out_stream: var) void {
+ usage(builder, already_ran_build, out_stream) catch {};
+ process.exit(1);
+}
+
+const UnwrapArgError = error{OutOfMemory};
+
+fn unwrapArg(arg: UnwrapArgError![]u8) UnwrapArgError![]u8 {
+ return arg catch |err| {
+ warn("Unable to parse command line: {}\n", err);
+ return err;
+ };
+}