| ... | @@ -11,32 +11,31 @@ const warn = std.debug.warn; | ... | @@ -11,32 +11,31 @@ const warn = std.debug.warn; |
| 11 | const File = std.fs.File; | 11 | const File = std.fs.File; |
| 12 | | 12 | |
| 13 | pub fn main() !void { | 13 | pub fn main() !void { |
| 14 | var arg_it = process.args(); | | |
| 15 | | | |
| 16 | // Here we use an ArenaAllocator backed by a DirectAllocator because a build is a short-lived, | 14 | // Here we use an ArenaAllocator backed by a DirectAllocator because a build is a short-lived, |
| 17 | // one shot program. We don't need to waste time freeing memory and finding places to squish | 15 | // one shot program. We don't need to waste time freeing memory and finding places to squish |
| 18 | // bytes into. So we free everything all at once at the very end. | 16 | // bytes into. So we free everything all at once at the very end. |
| 19 | | | |
| 20 | var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | 17 | var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); |
| 21 | defer arena.deinit(); | 18 | defer arena.deinit(); |
| 22 | | 19 | |
| 23 | const allocator = &arena.allocator; | 20 | const allocator = &arena.allocator; |
| | 21 | var args = try process.argsAlloc(allocator); |
| | 22 | defer process.argsFree(allocator, args); |
| 24 | | 23 | |
| 25 | // skip my own exe name | 24 | // skip my own exe name |
| 26 | _ = arg_it.skip(); | 25 | var arg_idx: usize = 1; |
| 27 | | 26 | |
| 28 | const zig_exe = try unwrapArg(arg_it.next(allocator) orelse { | 27 | const zig_exe = nextArg(args, &arg_idx) orelse { |
| 29 | warn("Expected first argument to be path to zig compiler\n", .{}); | 28 | warn("Expected first argument to be path to zig compiler\n", .{}); |
| 30 | return error.InvalidArgs; | 29 | return error.InvalidArgs; |
| 31 | }); | 30 | }; |
| 32 | const build_root = try unwrapArg(arg_it.next(allocator) orelse { | 31 | const build_root = nextArg(args, &arg_idx) orelse { |
| 33 | warn("Expected second argument to be build root directory path\n", .{}); | 32 | warn("Expected second argument to be build root directory path\n", .{}); |
| 34 | return error.InvalidArgs; | 33 | return error.InvalidArgs; |
| 35 | }); | 34 | }; |
| 36 | const cache_root = try unwrapArg(arg_it.next(allocator) orelse { | 35 | const cache_root = nextArg(args, &arg_idx) orelse { |
| 37 | warn("Expected third argument to be cache root directory path\n", .{}); | 36 | warn("Expected third argument to be cache root directory path\n", .{}); |
| 38 | return error.InvalidArgs; | 37 | return error.InvalidArgs; |
| 39 | }); | 38 | }; |
| 40 | | 39 | |
| 41 | const builder = try Builder.create(allocator, zig_exe, build_root, cache_root); | 40 | const builder = try Builder.create(allocator, zig_exe, build_root, cache_root); |
| 42 | defer builder.destroy(); | 41 | defer builder.destroy(); |
| ... | @@ -46,8 +45,7 @@ pub fn main() !void { | ... | @@ -46,8 +45,7 @@ pub fn main() !void { |
| 46 | const stderr_stream = &io.getStdErr().outStream().stream; | 45 | const stderr_stream = &io.getStdErr().outStream().stream; |
| 47 | const stdout_stream = &io.getStdOut().outStream().stream; | 46 | const stdout_stream = &io.getStdOut().outStream().stream; |
| 48 | | 47 | |
| 49 | while (arg_it.next(allocator)) |err_or_arg| { | 48 | while (nextArg(args, &arg_idx)) |arg| { |
| 50 | const arg = try unwrapArg(err_or_arg); | | |
| 51 | if (mem.startsWith(u8, arg, "-D")) { | 49 | if (mem.startsWith(u8, arg, "-D")) { |
| 52 | const option_contents = arg[2..]; | 50 | const option_contents = arg[2..]; |
| 53 | if (option_contents.len == 0) { | 51 | if (option_contents.len == 0) { |
| ... | @@ -69,21 +67,21 @@ pub fn main() !void { | ... | @@ -69,21 +67,21 @@ pub fn main() !void { |
| 69 | } else if (mem.eql(u8, arg, "--help")) { | 67 | } else if (mem.eql(u8, arg, "--help")) { |
| 70 | return usage(builder, false, stdout_stream); | 68 | return usage(builder, false, stdout_stream); |
| 71 | } else if (mem.eql(u8, arg, "--prefix")) { | 69 | } else if (mem.eql(u8, arg, "--prefix")) { |
| 72 | builder.install_prefix = try unwrapArg(arg_it.next(allocator) orelse { | 70 | builder.install_prefix = nextArg(args, &arg_idx) orelse { |
| 73 | warn("Expected argument after --prefix\n\n", .{}); | 71 | warn("Expected argument after --prefix\n\n", .{}); |
| 74 | return usageAndErr(builder, false, stderr_stream); | 72 | return usageAndErr(builder, false, stderr_stream); |
| 75 | }); | 73 | }; |
| 76 | } else if (mem.eql(u8, arg, "--search-prefix")) { | 74 | } else if (mem.eql(u8, arg, "--search-prefix")) { |
| 77 | const search_prefix = try unwrapArg(arg_it.next(allocator) orelse { | 75 | const search_prefix = nextArg(args, &arg_idx) orelse { |
| 78 | warn("Expected argument after --search-prefix\n\n", .{}); | 76 | warn("Expected argument after --search-prefix\n\n", .{}); |
| 79 | return usageAndErr(builder, false, stderr_stream); | 77 | return usageAndErr(builder, false, stderr_stream); |
| 80 | }); | 78 | }; |
| 81 | builder.addSearchPrefix(search_prefix); | 79 | builder.addSearchPrefix(search_prefix); |
| 82 | } else if (mem.eql(u8, arg, "--override-lib-dir")) { | 80 | } else if (mem.eql(u8, arg, "--override-lib-dir")) { |
| 83 | builder.override_lib_dir = try unwrapArg(arg_it.next(allocator) orelse { | 81 | builder.override_lib_dir = nextArg(args, &arg_idx) orelse { |
| 84 | warn("Expected argument after --override-lib-dir\n\n", .{}); | 82 | warn("Expected argument after --override-lib-dir\n\n", .{}); |
| 85 | return usageAndErr(builder, false, stderr_stream); | 83 | return usageAndErr(builder, false, stderr_stream); |
| 86 | }); | 84 | }; |
| 87 | } else if (mem.eql(u8, arg, "--verbose-tokenize")) { | 85 | } else if (mem.eql(u8, arg, "--verbose-tokenize")) { |
| 88 | builder.verbose_tokenize = true; | 86 | builder.verbose_tokenize = true; |
| 89 | } else if (mem.eql(u8, arg, "--verbose-ast")) { | 87 | } else if (mem.eql(u8, arg, "--verbose-ast")) { |
| ... | @@ -98,6 +96,9 @@ pub fn main() !void { | ... | @@ -98,6 +96,9 @@ pub fn main() !void { |
| 98 | builder.verbose_cimport = true; | 96 | builder.verbose_cimport = true; |
| 99 | } else if (mem.eql(u8, arg, "--verbose-cc")) { | 97 | } else if (mem.eql(u8, arg, "--verbose-cc")) { |
| 100 | builder.verbose_cc = true; | 98 | builder.verbose_cc = true; |
| | 99 | } else if (mem.eql(u8, arg, "--")) { |
| | 100 | builder.args = argsRest(args, arg_idx); |
| | 101 | break; |
| 101 | } else { | 102 | } else { |
| 102 | warn("Unrecognized argument: {}\n\n", .{arg}); | 103 | warn("Unrecognized argument: {}\n\n", .{arg}); |
| 103 | return usageAndErr(builder, false, stderr_stream); | 104 | return usageAndErr(builder, false, stderr_stream); |
| ... | @@ -203,11 +204,13 @@ fn usageAndErr(builder: *Builder, already_ran_build: bool, out_stream: var) void | ... | @@ -203,11 +204,13 @@ fn usageAndErr(builder: *Builder, already_ran_build: bool, out_stream: var) void |
| 203 | process.exit(1); | 204 | process.exit(1); |
| 204 | } | 205 | } |
| 205 | | 206 | |
| 206 | const UnwrapArgError = error{OutOfMemory}; | 207 | fn nextArg(args: [][]const u8, idx: *usize) ?[]const u8 { |
| | 208 | if (idx.* >= args.len) return null; |
| | 209 | defer idx.* += 1; |
| | 210 | return args[idx.*]; |
| | 211 | } |
| 207 | | 212 | |
| 208 | fn unwrapArg(arg: UnwrapArgError![]u8) UnwrapArgError![]u8 { | 213 | fn argsRest(args: [][]const u8, idx: usize) ?[][]const u8 { |
| 209 | return arg catch |err| { | 214 | if (idx >= args.len) return null; |
| 210 | warn("Unable to parse command line: {}\n", .{err}); | 215 | return args[idx..]; |
| 211 | return err; | | |
| 212 | }; | | |
| 213 | } | 216 | } |