authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-04-12 22:23:58+12:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-04-12 22:28:47+12:00
log803f0a295b168de058ac915d9ac45add44a41f40
tree75cb2dff513bdb34e56bfb6af5ea3ac9fd135bb9
parent281c17f6ae3c294d0b7139fe640dd0cb30123ea1

Revise self-hosted command line interface

Commands are now separated more precisely from one another. Arguments are parsed mostly using a custom argument parser instead of manually. This should be on parity feature-wise with the previous main.zig but adds a few extra code-paths as well that were not yet implemented. Subcommands are much more prominent and consistent. The first argument is always a sub-command and then all following arguments refer to that command. Different commands display there own usage messages and options based on what they can do instead of a one-for-all usage message that was only applicable for the build commands previously. The `cc` command is added and is intended for driving a c compiler. See #490. This is currently a wrapper over the system cc and assumes that it exists, but it should suffice as a starting point.

5 files changed, 1409 insertions(+), 683 deletions(-)

src-self-hosted/arg.zig created+284
......@@ -0,0 +1,284 @@
1const std = @import("std");
2const debug = std.debug;
3const mem = std.mem;
4
5const Allocator = mem.Allocator;
6const ArrayList = std.ArrayList;
7const HashMap = std.HashMap;
8
9fn trimStart(slice: []const u8, ch: u8) []const u8 {
10 var i: usize = 0;
11 for (slice) |b| {
12 if (b != '-') break;
13 i += 1;
14 }
15
16 return slice[i..];
17}
18
19fn argInAllowedSet(maybe_set: ?[]const []const u8, arg: []const u8) bool {
20 if (maybe_set) |set| {
21 for (set) |possible| {
22 if (mem.eql(u8, arg, possible)) {
23 return true;
24 }
25 }
26 return false;
27 } else {
28 return true;
29 }
30}
31
32// Modifies the current argument index during iteration
33fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required: usize,
34 allowed_set: ?[]const []const u8, index: &usize) !FlagArg {
35
36 switch (required) {
37 0 => return FlagArg { .None = undefined }, // TODO: Required to force non-tag but value?
38 1 => {
39 if (*index + 1 >= args.len) {
40 return error.MissingFlagArguments;
41 }
42
43 *index += 1;
44 const arg = args[*index];
45
46 if (!argInAllowedSet(allowed_set, arg)) {
47 return error.ArgumentNotInAllowedSet;
48 }
49
50 return FlagArg { .Single = arg };
51 },
52 else => |needed| {
53 var extra = ArrayList([]const u8).init(allocator);
54 errdefer extra.deinit();
55
56 var j: usize = 0;
57 while (j < needed) : (j += 1) {
58 if (*index + 1 >= args.len) {
59 return error.MissingFlagArguments;
60 }
61
62 *index += 1;
63 const arg = args[*index];
64
65 if (!argInAllowedSet(allowed_set, arg)) {
66 return error.ArgumentNotInAllowedSet;
67 }
68
69 try extra.append(arg);
70 }
71
72 return FlagArg { .Many = extra };
73 },
74 }
75}
76
77const HashMapFlags = HashMap([]const u8, FlagArg, std.hash.Fnv1a_32.hash, mem.eql_slice_u8);
78
79// A store for querying found flags and positional arguments.
80pub const Args = struct {
81 flags: HashMapFlags,
82 positionals: ArrayList([]const u8),
83
84 pub fn parse(allocator: &Allocator, comptime spec: []const Flag, args: []const []const u8) !Args {
85 var parsed = Args {
86 .flags = HashMapFlags.init(allocator),
87 .positionals = ArrayList([]const u8).init(allocator),
88 };
89
90 var i: usize = 0;
91 next: while (i < args.len) : (i += 1) {
92 const arg = args[i];
93
94 if (arg.len != 0 and arg[0] == '-') {
95 // TODO: hashmap, although the linear scan is okay for small argument sets as is
96 for (spec) |flag| {
97 if (mem.eql(u8, arg, flag.name)) {
98 const flag_name_trimmed = trimStart(flag.name, '-');
99 const flag_args = readFlagArguments(allocator, args, flag.required, flag.allowed_set, &i) catch |err| {
100 switch (err) {
101 error.ArgumentNotInAllowedSet => {
102 std.debug.warn("argument '{}' is invalid for flag '{}'\n", args[i], arg);
103 std.debug.warn("allowed options are ");
104 for (??flag.allowed_set) |possible| {
105 std.debug.warn("'{}' ", possible);
106 }
107 std.debug.warn("\n");
108 },
109 error.MissingFlagArguments => {
110 std.debug.warn("missing argument for flag: {}\n", arg);
111 },
112 else => {},
113 }
114
115 return err;
116 };
117
118 if (flag.mergable) {
119 var prev =
120 if (parsed.flags.get(flag_name_trimmed)) |entry|
121 entry.value.Many
122 else
123 ArrayList([]const u8).init(allocator);
124
125 // MergeN creation disallows 0 length flag entry (doesn't make sense)
126 switch (flag_args) {
127 FlagArg.None => unreachable,
128 FlagArg.Single => |inner| try prev.append(inner),
129 FlagArg.Many => |inner| try prev.appendSlice(inner.toSliceConst()),
130 }
131
132 _ = try parsed.flags.put(flag_name_trimmed, FlagArg { .Many = prev });
133 } else {
134 _ = try parsed.flags.put(flag_name_trimmed, flag_args);
135 }
136
137 continue :next;
138 }
139 }
140
141 // TODO: Better errors with context, global error state and return is sufficient.
142 std.debug.warn("could not match flag: {}\n", arg);
143 return error.UnknownFlag;
144 } else {
145 try parsed.positionals.append(arg);
146 }
147 }
148
149 return parsed;
150 }
151
152 pub fn deinit(self: &Args) void {
153 self.flags.deinit();
154 self.positionals.deinit();
155 }
156
157 // e.g. --help
158 pub fn present(self: &Args, name: []const u8) bool {
159 return self.flags.contains(name);
160 }
161
162 // e.g. --name value
163 pub fn single(self: &Args, name: []const u8) ?[]const u8 {
164 if (self.flags.get(name)) |entry| {
165 switch (entry.value) {
166 FlagArg.Single => |inner| { return inner; },
167 else => @panic("attempted to retrieve flag with wrong type"),
168 }
169 } else {
170 return null;
171 }
172 }
173
174 // e.g. --names value1 value2 value3
175 pub fn many(self: &Args, name: []const u8) ?[]const []const u8 {
176 if (self.flags.get(name)) |entry| {
177 switch (entry.value) {
178 FlagArg.Many => |inner| { return inner.toSliceConst(); },
179 else => @panic("attempted to retrieve flag with wrong type"),
180 }
181 } else {
182 return null;
183 }
184 }
185};
186
187// Arguments for a flag. e.g. arg1, arg2 in `--command arg1 arg2`.
188const FlagArg = union(enum) {
189 None,
190 Single: []const u8,
191 Many: ArrayList([]const u8),
192};
193
194// Specification for how a flag should be parsed.
195pub const Flag = struct {
196 name: []const u8,
197 required: usize,
198 mergable: bool,
199 allowed_set: ?[]const []const u8,
200
201 pub fn Bool(comptime name: []const u8) Flag {
202 return ArgN(name, 0);
203 }
204
205 pub fn Arg1(comptime name: []const u8) Flag {
206 return ArgN(name, 1);
207 }
208
209 pub fn ArgN(comptime name: []const u8, comptime n: usize) Flag {
210 return Flag {
211 .name = name,
212 .required = n,
213 .mergable = false,
214 .allowed_set = null,
215 };
216 }
217
218 pub fn ArgMergeN(comptime name: []const u8, comptime n: usize) Flag {
219 if (n == 0) {
220 @compileError("n must be greater than 0");
221 }
222
223 return Flag {
224 .name = name,
225 .required = n,
226 .mergable = true,
227 .allowed_set = null,
228 };
229 }
230
231 pub fn Option(comptime name: []const u8, comptime set: []const []const u8) Flag {
232 return Flag {
233 .name = name,
234 .required = 1,
235 .mergable = false,
236 .allowed_set = set,
237 };
238 }
239};
240
241test "parse arguments" {
242 const spec1 = comptime []const Flag {
243 Flag.Bool("--help"),
244 Flag.Bool("--init"),
245 Flag.Arg1("--build-file"),
246 Flag.Option("--color", []const []const u8 { "on", "off", "auto" }),
247 Flag.ArgN("--pkg-begin", 2),
248 Flag.ArgMergeN("--object", 1),
249 Flag.ArgN("--library", 1),
250 };
251
252 const cliargs = []const []const u8 {
253 "build",
254 "--help",
255 "pos1",
256 "--build-file", "build.zig",
257 "--object", "obj1",
258 "--object", "obj2",
259 "--library", "lib1",
260 "--library", "lib2",
261 "--color", "on",
262 "pos2",
263 };
264
265 var args = try Args.parse(std.debug.global_allocator, spec1, cliargs);
266
267 debug.assert(args.present("help"));
268 debug.assert(!args.present("help2"));
269 debug.assert(!args.present("init"));
270
271 debug.assert(mem.eql(u8, ??args.single("build-file"), "build.zig"));
272 debug.assert(mem.eql(u8, ??args.single("color"), "on"));
273
274 const objects = ??args.many("object");
275 debug.assert(mem.eql(u8, objects[0], "obj1"));
276 debug.assert(mem.eql(u8, objects[1], "obj2"));
277
278 debug.assert(mem.eql(u8, ??args.single("library"), "lib2"));
279
280 const pos = args.positionals.toSliceConst();
281 debug.assert(mem.eql(u8, pos[0], "build"));
282 debug.assert(mem.eql(u8, pos[1], "pos1"));
283 debug.assert(mem.eql(u8, pos[2], "pos2"));
284}
src-self-hosted/introspect.zig created+71
......@@ -0,0 +1,71 @@
1// Introspection and determination of system libraries needed by zig.
2
3const std = @import("std");
4const mem = std.mem;
5const os = std.os;
6
7const warn = std.debug.warn;
8
9/// Caller must free result
10pub fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) ![]u8 {
11 const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig");
12 errdefer allocator.free(test_zig_dir);
13
14 const test_index_file = try os.path.join(allocator, test_zig_dir, "std", "index.zig");
15 defer allocator.free(test_index_file);
16
17 var file = try os.File.openRead(allocator, test_index_file);
18 file.close();
19
20 return test_zig_dir;
21}
22
23/// Caller must free result
24pub fn findZigLibDir(allocator: &mem.Allocator) ![]u8 {
25 const self_exe_path = try os.selfExeDirPath(allocator);
26 defer allocator.free(self_exe_path);
27
28 var cur_path: []const u8 = self_exe_path;
29 while (true) {
30 const test_dir = os.path.dirname(cur_path);
31
32 if (mem.eql(u8, test_dir, cur_path)) {
33 break;
34 }
35
36 return testZigInstallPrefix(allocator, test_dir) catch |err| {
37 cur_path = test_dir;
38 continue;
39 };
40 }
41
42 // TODO look in hard coded installation path from configuration
43 //if (ZIG_INSTALL_PREFIX != nullptr) {
44 // if (test_zig_install_prefix(buf_create_from_str(ZIG_INSTALL_PREFIX), out_path)) {
45 // return 0;
46 // }
47 //}
48
49 return error.FileNotFound;
50}
51
52pub fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const u8) ![]u8 {
53 if (zig_install_prefix_arg) |zig_install_prefix| {
54 return testZigInstallPrefix(allocator, zig_install_prefix) catch |err| {
55 warn("No Zig installation found at prefix {}: {}\n", zig_install_prefix_arg, @errorName(err));
56 return error.ZigInstallationNotFound;
57 };
58 } else {
59 return findZigLibDir(allocator) catch |err| {
60 warn(
61 \\Unable to find zig lib directory: {}.
62 \\Reinstall Zig or use --zig-install-prefix.
63 \\
64 ,
65 @errorName(err)
66 );
67
68 return error.ZigLibDirNotFound;
69 };
70 }
71}
src-self-hosted/main.zig+1023-683
......@@ -1,731 +1,720 @@
11const std = @import("std");
2const mem = std.mem;
3const io = std.io;
4const os = std.os;
5const heap = std.heap;
6const warn = std.debug.warn;
7const assert = std.debug.assert;
8const target = @import("target.zig");
9const Target = target.Target;
10const Module = @import("module.zig").Module;
11const ErrColor = Module.ErrColor;
12const Emit = Module.Emit;
132const builtin = @import("builtin");
14const ArrayList = std.ArrayList;
15const c = @import("c.zig");
163
17const default_zig_cache_name = "zig-cache";
4const os = std.os;
5const io = std.io;
6const mem = std.mem;
7const Allocator = mem.Allocator;
8const ArrayList = std.ArrayList;
9const Buffer = std.Buffer;
1810
19const Cmd = enum {
20 None,
21 Build,
22 Test,
23 Version,
24 Zen,
25 TranslateC,
26 Targets,
11const arg = @import("arg.zig");
12const c = @import("c.zig");
13const introspect = @import("introspect.zig");
14const Args = arg.Args;
15const Flag = arg.Flag;
16const Module = @import("module.zig").Module;
17const Target = @import("target.zig").Target;
18
19var stderr: &io.OutStream(io.FileOutStream.Error) = undefined;
20var stdout: &io.OutStream(io.FileOutStream.Error) = undefined;
21
22const usage =
23 \\usage: zig [command] [options]
24 \\
25 \\Commands:
26 \\
27 \\ build Build project from build.zig
28 \\ build-exe [source] Create executable from source or object files
29 \\ build-lib [source] Create library from source or object files
30 \\ build-obj [source] Create object from source or assembly
31 \\ cc [args] Call the system c compiler and pass args through
32 \\ fmt [source] Parse file and render in canonical zig format
33 \\ run [source] Create executable and run immediately
34 \\ targets List available compilation targets
35 \\ test [source] Create and run a test build
36 \\ translate-c [source] Convert c code to zig code
37 \\ version Print version number and exit
38 \\ zen Print zen of zig and exit
39 \\
40 \\
41 ;
42
43const Command = struct {
44 name: []const u8,
45 exec: fn(&Allocator, []const []const u8) error!void,
2746};
2847
29fn badArgs(comptime format: []const u8, args: ...) noreturn {
30 var stderr = io.getStdErr() catch std.os.exit(1);
31 var stderr_stream_adapter = io.FileOutStream.init(&stderr);
32 const stderr_stream = &stderr_stream_adapter.stream;
33 stderr_stream.print(format ++ "\n\n", args) catch std.os.exit(1);
34 printUsage(&stderr_stream_adapter.stream) catch std.os.exit(1);
35 std.os.exit(1);
36}
37
3848pub fn main() !void {
39 const allocator = std.heap.c_allocator;
49 var allocator = std.heap.c_allocator;
50
51 var stdout_file = try std.io.getStdOut();
52 var stdout_out_stream = std.io.FileOutStream.init(&stdout_file);
53 stdout = &stdout_out_stream.stream;
54
55 var stderr_file = try std.io.getStdErr();
56 var stderr_out_stream = std.io.FileOutStream.init(&stderr_file);
57 stderr = &stderr_out_stream.stream;
4058
4159 const args = try os.argsAlloc(allocator);
4260 defer os.argsFree(allocator, args);
4361
44 if (args.len >= 2 and mem.eql(u8, args[1], "build")) {
45 return buildMain(allocator, args[2..]);
46 }
47
48 if (args.len >= 2 and mem.eql(u8, args[1], "fmt")) {
49 return fmtMain(allocator, args[2..]);
50 }
51
52 var cmd = Cmd.None;
53 var build_kind: Module.Kind = undefined;
54 var build_mode: builtin.Mode = builtin.Mode.Debug;
55 var color = ErrColor.Auto;
56 var emit_file_type = Emit.Binary;
57
58 var strip = false;
59 var is_static = false;
60 var verbose_tokenize = false;
61 var verbose_ast_tree = false;
62 var verbose_ast_fmt = false;
63 var verbose_link = false;
64 var verbose_ir = false;
65 var verbose_llvm_ir = false;
66 var verbose_cimport = false;
67 var mwindows = false;
68 var mconsole = false;
69 var rdynamic = false;
70 var each_lib_rpath = false;
71 var timing_info = false;
72
73 var in_file_arg: ?[]u8 = null;
74 var out_file: ?[]u8 = null;
75 var out_file_h: ?[]u8 = null;
76 var out_name_arg: ?[]u8 = null;
77 var libc_lib_dir_arg: ?[]u8 = null;
78 var libc_static_lib_dir_arg: ?[]u8 = null;
79 var libc_include_dir_arg: ?[]u8 = null;
80 var msvc_lib_dir_arg: ?[]u8 = null;
81 var kernel32_lib_dir_arg: ?[]u8 = null;
82 var zig_install_prefix: ?[]u8 = null;
83 var dynamic_linker_arg: ?[]u8 = null;
84 var cache_dir_arg: ?[]const u8 = null;
85 var target_arch: ?[]u8 = null;
86 var target_os: ?[]u8 = null;
87 var target_environ: ?[]u8 = null;
88 var mmacosx_version_min: ?[]u8 = null;
89 var mios_version_min: ?[]u8 = null;
90 var linker_script_arg: ?[]u8 = null;
91 var test_name_prefix_arg: ?[]u8 = null;
92
93 var test_filters = ArrayList([]const u8).init(allocator);
94 defer test_filters.deinit();
95
96 var lib_dirs = ArrayList([]const u8).init(allocator);
97 defer lib_dirs.deinit();
98
99 var clang_argv = ArrayList([]const u8).init(allocator);
100 defer clang_argv.deinit();
101
102 var llvm_argv = ArrayList([]const u8).init(allocator);
103 defer llvm_argv.deinit();
104
105 var link_libs = ArrayList([]const u8).init(allocator);
106 defer link_libs.deinit();
107
108 var frameworks = ArrayList([]const u8).init(allocator);
109 defer frameworks.deinit();
110
111 var objects = ArrayList([]const u8).init(allocator);
112 defer objects.deinit();
113
114 var asm_files = ArrayList([]const u8).init(allocator);
115 defer asm_files.deinit();
116
117 var rpath_list = ArrayList([]const u8).init(allocator);
118 defer rpath_list.deinit();
119
120 var ver_major: u32 = 0;
121 var ver_minor: u32 = 0;
122 var ver_patch: u32 = 0;
123
124 var arg_i: usize = 1;
125 while (arg_i < args.len) : (arg_i += 1) {
126 const arg = args[arg_i];
127
128 if (arg.len != 0 and arg[0] == '-') {
129 if (mem.eql(u8, arg, "--release-fast")) {
130 build_mode = builtin.Mode.ReleaseFast;
131 } else if (mem.eql(u8, arg, "--release-safe")) {
132 build_mode = builtin.Mode.ReleaseSafe;
133 } else if (mem.eql(u8, arg, "--strip")) {
134 strip = true;
135 } else if (mem.eql(u8, arg, "--static")) {
136 is_static = true;
137 } else if (mem.eql(u8, arg, "--verbose-tokenize")) {
138 verbose_tokenize = true;
139 } else if (mem.eql(u8, arg, "--verbose-ast-tree")) {
140 verbose_ast_tree = true;
141 } else if (mem.eql(u8, arg, "--verbose-ast-fmt")) {
142 verbose_ast_fmt = true;
143 } else if (mem.eql(u8, arg, "--verbose-link")) {
144 verbose_link = true;
145 } else if (mem.eql(u8, arg, "--verbose-ir")) {
146 verbose_ir = true;
147 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
148 verbose_llvm_ir = true;
149 } else if (mem.eql(u8, arg, "--verbose-cimport")) {
150 verbose_cimport = true;
151 } else if (mem.eql(u8, arg, "-mwindows")) {
152 mwindows = true;
153 } else if (mem.eql(u8, arg, "-mconsole")) {
154 mconsole = true;
155 } else if (mem.eql(u8, arg, "-rdynamic")) {
156 rdynamic = true;
157 } else if (mem.eql(u8, arg, "--each-lib-rpath")) {
158 each_lib_rpath = true;
159 } else if (mem.eql(u8, arg, "--enable-timing-info")) {
160 timing_info = true;
161 } else if (mem.eql(u8, arg, "--test-cmd-bin")) {
162 @panic("TODO --test-cmd-bin");
163 } else if (arg[1] == 'L' and arg.len > 2) {
164 // alias for --library-path
165 try lib_dirs.append(arg[1..]);
166 } else if (mem.eql(u8, arg, "--pkg-begin")) {
167 @panic("TODO --pkg-begin");
168 } else if (mem.eql(u8, arg, "--pkg-end")) {
169 @panic("TODO --pkg-end");
170 } else if (arg_i + 1 >= args.len) {
171 badArgs("expected another argument after {}", arg);
172 } else {
173 arg_i += 1;
174 if (mem.eql(u8, arg, "--output")) {
175 out_file = args[arg_i];
176 } else if (mem.eql(u8, arg, "--output-h")) {
177 out_file_h = args[arg_i];
178 } else if (mem.eql(u8, arg, "--color")) {
179 if (mem.eql(u8, args[arg_i], "auto")) {
180 color = ErrColor.Auto;
181 } else if (mem.eql(u8, args[arg_i], "on")) {
182 color = ErrColor.On;
183 } else if (mem.eql(u8, args[arg_i], "off")) {
184 color = ErrColor.Off;
185 } else {
186 badArgs("--color options are 'auto', 'on', or 'off'");
187 }
188 } else if (mem.eql(u8, arg, "--emit")) {
189 if (mem.eql(u8, args[arg_i], "asm")) {
190 emit_file_type = Emit.Assembly;
191 } else if (mem.eql(u8, args[arg_i], "bin")) {
192 emit_file_type = Emit.Binary;
193 } else if (mem.eql(u8, args[arg_i], "llvm-ir")) {
194 emit_file_type = Emit.LlvmIr;
195 } else {
196 badArgs("--emit options are 'asm', 'bin', or 'llvm-ir'");
197 }
198 } else if (mem.eql(u8, arg, "--name")) {
199 out_name_arg = args[arg_i];
200 } else if (mem.eql(u8, arg, "--libc-lib-dir")) {
201 libc_lib_dir_arg = args[arg_i];
202 } else if (mem.eql(u8, arg, "--libc-static-lib-dir")) {
203 libc_static_lib_dir_arg = args[arg_i];
204 } else if (mem.eql(u8, arg, "--libc-include-dir")) {
205 libc_include_dir_arg = args[arg_i];
206 } else if (mem.eql(u8, arg, "--msvc-lib-dir")) {
207 msvc_lib_dir_arg = args[arg_i];
208 } else if (mem.eql(u8, arg, "--kernel32-lib-dir")) {
209 kernel32_lib_dir_arg = args[arg_i];
210 } else if (mem.eql(u8, arg, "--zig-install-prefix")) {
211 zig_install_prefix = args[arg_i];
212 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
213 dynamic_linker_arg = args[arg_i];
214 } else if (mem.eql(u8, arg, "-isystem")) {
215 try clang_argv.append("-isystem");
216 try clang_argv.append(args[arg_i]);
217 } else if (mem.eql(u8, arg, "-dirafter")) {
218 try clang_argv.append("-dirafter");
219 try clang_argv.append(args[arg_i]);
220 } else if (mem.eql(u8, arg, "-mllvm")) {
221 try clang_argv.append("-mllvm");
222 try clang_argv.append(args[arg_i]);
223
224 try llvm_argv.append(args[arg_i]);
225 } else if (mem.eql(u8, arg, "--library-path") or mem.eql(u8, arg, "-L")) {
226 try lib_dirs.append(args[arg_i]);
227 } else if (mem.eql(u8, arg, "--library")) {
228 try link_libs.append(args[arg_i]);
229 } else if (mem.eql(u8, arg, "--object")) {
230 try objects.append(args[arg_i]);
231 } else if (mem.eql(u8, arg, "--assembly")) {
232 try asm_files.append(args[arg_i]);
233 } else if (mem.eql(u8, arg, "--cache-dir")) {
234 cache_dir_arg = args[arg_i];
235 } else if (mem.eql(u8, arg, "--target-arch")) {
236 target_arch = args[arg_i];
237 } else if (mem.eql(u8, arg, "--target-os")) {
238 target_os = args[arg_i];
239 } else if (mem.eql(u8, arg, "--target-environ")) {
240 target_environ = args[arg_i];
241 } else if (mem.eql(u8, arg, "-mmacosx-version-min")) {
242 mmacosx_version_min = args[arg_i];
243 } else if (mem.eql(u8, arg, "-mios-version-min")) {
244 mios_version_min = args[arg_i];
245 } else if (mem.eql(u8, arg, "-framework")) {
246 try frameworks.append(args[arg_i]);
247 } else if (mem.eql(u8, arg, "--linker-script")) {
248 linker_script_arg = args[arg_i];
249 } else if (mem.eql(u8, arg, "-rpath")) {
250 try rpath_list.append(args[arg_i]);
251 } else if (mem.eql(u8, arg, "--test-filter")) {
252 try test_filters.append(args[arg_i]);
253 } else if (mem.eql(u8, arg, "--test-name-prefix")) {
254 test_name_prefix_arg = args[arg_i];
255 } else if (mem.eql(u8, arg, "--ver-major")) {
256 ver_major = try std.fmt.parseUnsigned(u32, args[arg_i], 10);
257 } else if (mem.eql(u8, arg, "--ver-minor")) {
258 ver_minor = try std.fmt.parseUnsigned(u32, args[arg_i], 10);
259 } else if (mem.eql(u8, arg, "--ver-patch")) {
260 ver_patch = try std.fmt.parseUnsigned(u32, args[arg_i], 10);
261 } else if (mem.eql(u8, arg, "--test-cmd")) {
262 @panic("TODO --test-cmd");
263 } else {
264 badArgs("invalid argument: {}", arg);
265 }
266 }
267 } else if (cmd == Cmd.None) {
268 if (mem.eql(u8, arg, "build-obj")) {
269 cmd = Cmd.Build;
270 build_kind = Module.Kind.Obj;
271 } else if (mem.eql(u8, arg, "build-exe")) {
272 cmd = Cmd.Build;
273 build_kind = Module.Kind.Exe;
274 } else if (mem.eql(u8, arg, "build-lib")) {
275 cmd = Cmd.Build;
276 build_kind = Module.Kind.Lib;
277 } else if (mem.eql(u8, arg, "version")) {
278 cmd = Cmd.Version;
279 } else if (mem.eql(u8, arg, "zen")) {
280 cmd = Cmd.Zen;
281 } else if (mem.eql(u8, arg, "translate-c")) {
282 cmd = Cmd.TranslateC;
283 } else if (mem.eql(u8, arg, "test")) {
284 cmd = Cmd.Test;
285 build_kind = Module.Kind.Exe;
286 } else {
287 badArgs("unrecognized command: {}", arg);
288 }
289 } else switch (cmd) {
290 Cmd.Build, Cmd.TranslateC, Cmd.Test => {
291 if (in_file_arg == null) {
292 in_file_arg = arg;
293 } else {
294 badArgs("unexpected extra parameter: {}", arg);
295 }
296 },
297 Cmd.Version, Cmd.Zen, Cmd.Targets => {
298 badArgs("unexpected extra parameter: {}", arg);
299 },
300 Cmd.None => unreachable,
62 if (args.len <= 1) {
63 try stderr.write(usage);
64 os.exit(1);
65 }
66
67 const commands = []Command {
68 Command { .name = "build", .exec = cmdBuild },
69 Command { .name = "build-exe", .exec = cmdBuildExe },
70 Command { .name = "build-lib", .exec = cmdBuildLib },
71 Command { .name = "build-obj", .exec = cmdBuildObj },
72 Command { .name = "cc", .exec = cmdCc },
73 Command { .name = "fmt", .exec = cmdFmt },
74 Command { .name = "run", .exec = cmdRun },
75 Command { .name = "targets", .exec = cmdTargets },
76 Command { .name = "test", .exec = cmdTest },
77 Command { .name = "translate-c", .exec = cmdTranslateC },
78 Command { .name = "version", .exec = cmdVersion },
79 Command { .name = "zen", .exec = cmdZen },
80
81 // undocumented commands
82 Command { .name = "help", .exec = cmdHelp },
83 Command { .name = "internal", .exec = cmdInternal },
84 };
85
86 for (commands) |command| {
87 if (mem.eql(u8, command.name, args[1])) {
88 try command.exec(allocator, args[2..]);
89 return;
30190 }
30291 }
30392
304 target.initializeAll();
305
306 // TODO
307// ZigTarget alloc_target;
308// ZigTarget *target;
309// if (!target_arch && !target_os && !target_environ) {
310// target = nullptr;
311// } else {
312// target = &alloc_target;
313// get_unknown_target(target);
314// if (target_arch) {
315// if (parse_target_arch(target_arch, &target->arch)) {
316// fprintf(stderr, "invalid --target-arch argument\n");
317// return usage(arg0);
318// }
319// }
320// if (target_os) {
321// if (parse_target_os(target_os, &target->os)) {
322// fprintf(stderr, "invalid --target-os argument\n");
323// return usage(arg0);
324// }
325// }
326// if (target_environ) {
327// if (parse_target_environ(target_environ, &target->env_type)) {
328// fprintf(stderr, "invalid --target-environ argument\n");
329// return usage(arg0);
330// }
331// }
332// }
333
334 switch (cmd) {
335 Cmd.None => badArgs("expected command"),
336 Cmd.Zen => return printZen(),
337 Cmd.Build, Cmd.Test, Cmd.TranslateC => {
338 if (cmd == Cmd.Build and in_file_arg == null and objects.len == 0 and asm_files.len == 0) {
339 badArgs("expected source file argument or at least one --object or --assembly argument");
340 } else if ((cmd == Cmd.TranslateC or cmd == Cmd.Test) and in_file_arg == null) {
341 badArgs("expected source file argument");
342 } else if (cmd == Cmd.Build and build_kind == Module.Kind.Obj and objects.len != 0) {
343 badArgs("When building an object file, --object arguments are invalid");
344 }
93 try stderr.print("unknown command: {}\n\n", args[1]);
94 try stderr.write(usage);
95}
34596
346 const root_name = switch (cmd) {
347 Cmd.Build, Cmd.TranslateC => x: {
348 if (out_name_arg) |out_name| {
349 break :x out_name;
350 } else if (in_file_arg) |in_file_path| {
351 const basename = os.path.basename(in_file_path);
352 var it = mem.split(basename, ".");
353 break :x it.next() ?? badArgs("file name cannot be empty");
354 } else {
355 badArgs("--name [name] not provided and unable to infer");
356 }
357 },
358 Cmd.Test => "test",
359 else => unreachable,
360 };
361
362 const zig_root_source_file = if (cmd == Cmd.TranslateC) null else in_file_arg;
363
364 const chosen_cache_dir = cache_dir_arg ?? default_zig_cache_name;
365 const full_cache_dir = try os.path.resolve(allocator, ".", chosen_cache_dir);
366 defer allocator.free(full_cache_dir);
367
368 const zig_lib_dir = try resolveZigLibDir(allocator, zig_install_prefix);
369 errdefer allocator.free(zig_lib_dir);
370
371 const module = try Module.create(allocator, root_name, zig_root_source_file,
372 Target.Native, build_kind, build_mode, zig_lib_dir, full_cache_dir);
373 defer module.destroy();
374
375 module.version_major = ver_major;
376 module.version_minor = ver_minor;
377 module.version_patch = ver_patch;
378
379 module.is_test = cmd == Cmd.Test;
380 if (linker_script_arg) |linker_script| {
381 module.linker_script = linker_script;
382 }
383 module.each_lib_rpath = each_lib_rpath;
384 module.clang_argv = clang_argv.toSliceConst();
385 module.llvm_argv = llvm_argv.toSliceConst();
386 module.strip = strip;
387 module.is_static = is_static;
388
389 if (libc_lib_dir_arg) |libc_lib_dir| {
390 module.libc_lib_dir = libc_lib_dir;
391 }
392 if (libc_static_lib_dir_arg) |libc_static_lib_dir| {
393 module.libc_static_lib_dir = libc_static_lib_dir;
394 }
395 if (libc_include_dir_arg) |libc_include_dir| {
396 module.libc_include_dir = libc_include_dir;
397 }
398 if (msvc_lib_dir_arg) |msvc_lib_dir| {
399 module.msvc_lib_dir = msvc_lib_dir;
400 }
401 if (kernel32_lib_dir_arg) |kernel32_lib_dir| {
402 module.kernel32_lib_dir = kernel32_lib_dir;
403 }
404 if (dynamic_linker_arg) |dynamic_linker| {
405 module.dynamic_linker = dynamic_linker;
406 }
407 module.verbose_tokenize = verbose_tokenize;
408 module.verbose_ast_tree = verbose_ast_tree;
409 module.verbose_ast_fmt = verbose_ast_fmt;
410 module.verbose_link = verbose_link;
411 module.verbose_ir = verbose_ir;
412 module.verbose_llvm_ir = verbose_llvm_ir;
413 module.verbose_cimport = verbose_cimport;
414
415 module.err_color = color;
416
417 module.lib_dirs = lib_dirs.toSliceConst();
418 module.darwin_frameworks = frameworks.toSliceConst();
419 module.rpath_list = rpath_list.toSliceConst();
420
421 for (link_libs.toSliceConst()) |name| {
422 _ = try module.addLinkLib(name, true);
423 }
97// cmd:build ///////////////////////////////////////////////////////////////////////////////////////
98
99const usage_build =
100 \\usage: zig build <options>
101 \\
102 \\General Options:
103 \\ --help Print this help and exit
104 \\ --init Generate a build.zig template
105 \\ --build-file [file] Override path to build.zig
106 \\ --cache-dir [path] Override path to cache directory
107 \\ --verbose Print commands before executing them
108 \\ --prefix [path] Override default install prefix
109 \\ --zig-install-prefix [path] Override directory where zig thinks it is installed
110 \\
111 \\Project-Specific Options:
112 \\
113 \\ Project-specific options become available when the build file is found.
114 \\
115 \\Advanced Options:
116 \\ --build-file [file] Override path to build.zig
117 \\ --cache-dir [path] Override path to cache directory
118 \\ --verbose-tokenize Enable compiler debug output for tokenization
119 \\ --verbose-ast Enable compiler debug output for parsing into an AST
120 \\ --verbose-link Enable compiler debug output for linking
121 \\ --verbose-ir Enable compiler debug output for Zig IR
122 \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR
123 \\ --verbose-cimport Enable compiler debug output for C imports
124 \\
125 \\
126 ;
127
128const args_build_spec = []Flag {
129 Flag.Bool("--help"),
130 Flag.Bool("--init"),
131 Flag.Arg1("--build-file"),
132 Flag.Arg1("--cache-dir"),
133 Flag.Bool("--verbose"),
134 Flag.Arg1("--prefix"),
135 Flag.Arg1("--zig-install-prefix"),
136
137 Flag.Arg1("--build-file"),
138 Flag.Arg1("--cache-dir"),
139 Flag.Bool("--verbose-tokenize"),
140 Flag.Bool("--verbose-ast"),
141 Flag.Bool("--verbose-link"),
142 Flag.Bool("--verbose-ir"),
143 Flag.Bool("--verbose-llvm-ir"),
144 Flag.Bool("--verbose-cimport"),
145};
424146
425 module.windows_subsystem_windows = mwindows;
426 module.windows_subsystem_console = mconsole;
427 module.linker_rdynamic = rdynamic;
147const missing_build_file =
148 \\No 'build.zig' file found.
149 \\
150 \\Initialize a 'build.zig' template file with `zig build --init`,
151 \\or build an executable directly with `zig build-exe $FILENAME.zig`.
152 \\
153 \\See: `zig build --help` or `zig help` for more options.
154 \\
155 ;
156
157fn cmdBuild(allocator: &Allocator, args: []const []const u8) !void {
158 var flags = try Args.parse(allocator, args_build_spec, args);
159 defer flags.deinit();
160
161 if (flags.present("help")) {
162 try stderr.write(usage_build);
163 os.exit(0);
164 }
428165
429 if (mmacosx_version_min != null and mios_version_min != null) {
430 badArgs("-mmacosx-version-min and -mios-version-min options not allowed together");
431 }
166 const zig_lib_dir = try introspect.resolveZigLibDir(allocator, flags.single("zig-install-prefix") ?? null);
167 defer allocator.free(zig_lib_dir);
432168
433 if (mmacosx_version_min) |ver| {
434 module.darwin_version_min = Module.DarwinVersionMin { .MacOS = ver };
435 } else if (mios_version_min) |ver| {
436 module.darwin_version_min = Module.DarwinVersionMin { .Ios = ver };
437 }
169 const zig_std_dir = try os.path.join(allocator, zig_lib_dir, "std");
170 defer allocator.free(zig_std_dir);
171
172 const special_dir = try os.path.join(allocator, zig_std_dir, "special");
173 defer allocator.free(special_dir);
174
175 const build_runner_path = try os.path.join(allocator, special_dir, "build_runner.zig");
176 defer allocator.free(build_runner_path);
177
178 const build_file = flags.single("build-file") ?? "build.zig";
179 const build_file_abs = try os.path.resolve(allocator, ".", build_file);
180 defer allocator.free(build_file_abs);
181
182 const build_file_exists = os.File.exists(allocator, build_file_abs);
183
184 if (flags.present("init")) {
185 if (build_file_exists) {
186 try stderr.print("build.zig already exists\n");
187 os.exit(1);
188 }
189
190 // need a new scope for proper defer scope finalization on exit
191 {
192 const build_template_path = try os.path.join(allocator, special_dir, "build_file_template.zig");
193 defer allocator.free(build_template_path);
194
195 try os.copyFile(allocator, build_template_path, build_file_abs);
196 try stderr.print("wrote build.zig template\n");
197 }
198
199 os.exit(0);
200 }
201
202 if (!build_file_exists) {
203 try stderr.write(missing_build_file);
204 os.exit(1);
205 }
206
207 // TODO: Invoke build.zig entrypoint directly?
208 var zig_exe_path = try os.selfExePath(allocator);
209 defer allocator.free(zig_exe_path);
210
211 var build_args = ArrayList([]const u8).init(allocator);
212 defer build_args.deinit();
213
214 const build_file_basename = os.path.basename(build_file_abs);
215 const build_file_dirname = os.path.dirname(build_file_abs);
216
217 var full_cache_dir: []u8 = undefined;
218 if (flags.single("cache-dir")) |cache_dir| {
219 full_cache_dir = try os.path.resolve(allocator, ".", cache_dir, full_cache_dir);
220 } else {
221 full_cache_dir = try os.path.join(allocator, build_file_dirname, "zig-cache");
222 }
223 defer allocator.free(full_cache_dir);
438224
439 module.test_filters = test_filters.toSliceConst();
440 module.test_name_prefix = test_name_prefix_arg;
441 module.out_h_path = out_file_h;
225 const path_to_build_exe = try os.path.join(allocator, full_cache_dir, "build");
226 defer allocator.free(path_to_build_exe);
442227
443 // TODO
444 //add_package(g, cur_pkg, g->root_package);
228 try build_args.append(path_to_build_exe);
229 try build_args.append(zig_exe_path);
230 try build_args.append(build_file_dirname);
231 try build_args.append(full_cache_dir);
445232
446 switch (cmd) {
447 Cmd.Build => {
448 module.emit_file_type = emit_file_type;
233 if (flags.single("zig-install-prefix")) |zig_install_prefix| {
234 try build_args.append(zig_install_prefix);
235 }
449236
450 module.link_objects = objects.toSliceConst();
451 module.assembly_files = asm_files.toSliceConst();
237 var proc = try os.ChildProcess.init(build_args.toSliceConst(), allocator);
238 defer proc.deinit();
452239
453 try module.build();
454 try module.link(out_file);
455 },
456 Cmd.TranslateC => @panic("TODO translate-c"),
457 Cmd.Test => @panic("TODO test cmd"),
458 else => unreachable,
240 var term = try proc.spawnAndWait();
241 switch (term) {
242 os.ChildProcess.Term.Exited => |status| {
243 if (status != 0) {
244 try stderr.print("{} exited with status {}\n", build_args.at(0), status);
245 os.exit(1);
459246 }
460247 },
461 Cmd.Version => {
462 var stdout_file = try io.getStdErr();
463 try stdout_file.write(std.cstr.toSliceConst(c.ZIG_VERSION_STRING));
464 try stdout_file.write("\n");
248 os.ChildProcess.Term.Signal => |signal| {
249 try stderr.print("{} killed by signal {}\n", build_args.at(0), signal);
250 os.exit(1);
251 },
252 os.ChildProcess.Term.Stopped => |signal| {
253 try stderr.print("{} stopped by signal {}\n", build_args.at(0), signal);
254 os.exit(1);
255 },
256 os.ChildProcess.Term.Unknown => |status| {
257 try stderr.print("{} encountered unknown failure {}\n", build_args.at(0), status);
258 os.exit(1);
465259 },
466 Cmd.Targets => @panic("TODO zig targets"),
467260 }
468261}
469262
470fn printUsage(stream: var) !void {
471 try stream.write(
472 \\Usage: zig [command] [options]
473 \\
474 \\Commands:
475 \\ build build project from build.zig
476 \\ build-exe [source] create executable from source or object files
477 \\ build-lib [source] create library from source or object files
478 \\ build-obj [source] create object from source or assembly
479 \\ fmt [file] parse file and render in canonical zig format
480 \\ translate-c [source] convert c code to zig code
481 \\ targets list available compilation targets
482 \\ test [source] create and run a test build
483 \\ version print version number and exit
484 \\ zen print zen of zig and exit
485 \\Compile Options:
486 \\ --assembly [source] add assembly file to build
487 \\ --cache-dir [path] override the cache directory
488 \\ --color [auto|off|on] enable or disable colored error messages
489 \\ --emit [filetype] emit a specific file format as compilation output
490 \\ --enable-timing-info print timing diagnostics
491 \\ --libc-include-dir [path] directory where libc stdlib.h resides
492 \\ --name [name] override output name
493 \\ --output [file] override destination path
494 \\ --output-h [file] override generated header file path
495 \\ --pkg-begin [name] [path] make package available to import and push current pkg
496 \\ --pkg-end pop current pkg
497 \\ --release-fast build with optimizations on and safety off
498 \\ --release-safe build with optimizations on and safety on
499 \\ --static output will be statically linked
500 \\ --strip exclude debug symbols
501 \\ --target-arch [name] specify target architecture
502 \\ --target-environ [name] specify target environment
503 \\ --target-os [name] specify target operating system
504 \\ --verbose-tokenize enable compiler debug info: tokenization
505 \\ --verbose-ast-tree enable compiler debug info: parsing into an AST (treeview)
506 \\ --verbose-ast-fmt enable compiler debug info: parsing into an AST (render source)
507 \\ --verbose-cimport enable compiler debug info: C imports
508 \\ --verbose-ir enable compiler debug info: Zig IR
509 \\ --verbose-llvm-ir enable compiler debug info: LLVM IR
510 \\ --verbose-link enable compiler debug info: linking
511 \\ --zig-install-prefix [path] override directory where zig thinks it is installed
512 \\ -dirafter [dir] same as -isystem but do it last
513 \\ -isystem [dir] add additional search path for other .h files
514 \\ -mllvm [arg] additional arguments to forward to LLVM's option processing
515 \\Link Options:
516 \\ --ar-path [path] set the path to ar
517 \\ --dynamic-linker [path] set the path to ld.so
518 \\ --each-lib-rpath add rpath for each used dynamic library
519 \\ --libc-lib-dir [path] directory where libc crt1.o resides
520 \\ --libc-static-lib-dir [path] directory where libc crtbegin.o resides
521 \\ --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides
522 \\ --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides
523 \\ --library [lib] link against lib
524 \\ --library-path [dir] add a directory to the library search path
525 \\ --linker-script [path] use a custom linker script
526 \\ --object [obj] add object file to build
527 \\ -L[dir] alias for --library-path
528 \\ -rdynamic add all symbols to the dynamic symbol table
529 \\ -rpath [path] add directory to the runtime library search path
530 \\ -mconsole (windows) --subsystem console to the linker
531 \\ -mwindows (windows) --subsystem windows to the linker
532 \\ -framework [name] (darwin) link against framework
533 \\ -mios-version-min [ver] (darwin) set iOS deployment target
534 \\ -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target
535 \\ --ver-major [ver] dynamic library semver major version
536 \\ --ver-minor [ver] dynamic library semver minor version
537 \\ --ver-patch [ver] dynamic library semver patch version
538 \\Test Options:
539 \\ --test-filter [text] skip tests that do not match filter
540 \\ --test-name-prefix [text] add prefix to all tests
541 \\ --test-cmd [arg] specify test execution command one arg at a time
542 \\ --test-cmd-bin appends test binary path to test cmd args
543 \\
544 );
545}
263// cmd:build-exe ///////////////////////////////////////////////////////////////////////////////////
264
265const usage_build_generic =
266 \\usage: zig build-exe <options> [file]
267 \\ zig build-lib <options> [file]
268 \\ zig build-obj <options> [file]
269 \\
270 \\General Options:
271 \\ --help Print this help and exit
272 \\ --color [auto|off|on] Enable or disable colored error messages
273 \\
274 \\Compile Options:
275 \\ --assembly [source] Add assembly file to build
276 \\ --cache-dir [path] Override the cache directory
277 \\ --emit [filetype] Emit a specific file format as compilation output
278 \\ --enable-timing-info Print timing diagnostics
279 \\ --libc-include-dir [path] Directory where libc stdlib.h resides
280 \\ --name [name] Override output name
281 \\ --output [file] Override destination path
282 \\ --output-h [file] Override generated header file path
283 \\ --pkg-begin [name] [path] Make package available to import and push current pkg
284 \\ --pkg-end Pop current pkg
285 \\ --release-fast Build with optimizations on and safety off
286 \\ --release-safe Build with optimizations on and safety on
287 \\ --static Output will be statically linked
288 \\ --strip Exclude debug symbols
289 \\ --target-arch [name] Specify target architecture
290 \\ --target-environ [name] Specify target environment
291 \\ --target-os [name] Specify target operating system
292 \\ --verbose-tokenize Turn on compiler debug output for tokenization
293 \\ --verbose-ast-tree Turn on compiler debug output for parsing into an AST (tree view)
294 \\ --verbose-ast-fmt Turn on compiler debug output for parsing into an AST (render source)
295 \\ --verbose-link Turn on compiler debug output for linking
296 \\ --verbose-ir Turn on compiler debug output for Zig IR
297 \\ --verbose-llvm-ir Turn on compiler debug output for LLVM IR
298 \\ --verbose-cimport Turn on compiler debug output for C imports
299 \\ --zig-install-prefix [path] Override directory where zig thinks it is installed
300 \\ -dirafter [dir] Same as -isystem but do it last
301 \\ -isystem [dir] Add additional search path for other .h files
302 \\ -mllvm [arg] Additional arguments to forward to LLVM's option processing
303 \\
304 \\Link Options:
305 \\ --ar-path [path] Set the path to ar
306 \\ --dynamic-linker [path] Set the path to ld.so
307 \\ --each-lib-rpath Add rpath for each used dynamic library
308 \\ --libc-lib-dir [path] Directory where libc crt1.o resides
309 \\ --libc-static-lib-dir [path] Directory where libc crtbegin.o resides
310 \\ --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides
311 \\ --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides
312 \\ --library [lib] Link against lib
313 \\ --forbid-library [lib] Make it an error to link against lib
314 \\ --library-path [dir] Add a directory to the library search path
315 \\ --linker-script [path] Use a custom linker script
316 \\ --object [obj] Add object file to build
317 \\ -rdynamic Add all symbols to the dynamic symbol table
318 \\ -rpath [path] Add directory to the runtime library search path
319 \\ -mconsole (windows) --subsystem console to the linker
320 \\ -mwindows (windows) --subsystem windows to the linker
321 \\ -framework [name] (darwin) link against framework
322 \\ -mios-version-min [ver] (darwin) set iOS deployment target
323 \\ -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target
324 \\ --ver-major [ver] Dynamic library semver major version
325 \\ --ver-minor [ver] Dynamic library semver minor version
326 \\ --ver-patch [ver] Dynamic library semver patch version
327 \\
328 \\
329 ;
330
331const args_build_generic = []Flag {
332 Flag.Bool("--help"),
333 Flag.Option("--color", []const []const u8 { "auto", "off", "on" }),
334
335 Flag.ArgMergeN("--assembly", 1),
336 Flag.Arg1("--cache-dir"),
337 Flag.Option("--emit", []const []const u8 { "asm", "bin", "llvm-ir" }),
338 Flag.Bool("--enable-timing-info"),
339 Flag.Arg1("--libc-include-dir"),
340 Flag.Arg1("--name"),
341 Flag.Arg1("--output"),
342 Flag.Arg1("--output-h"),
343 // NOTE: Parsed manually after initial check
344 Flag.ArgN("--pkg-begin", 2),
345 Flag.Bool("--pkg-end"),
346 Flag.Bool("--release-fast"),
347 Flag.Bool("--release-safe"),
348 Flag.Bool("--static"),
349 Flag.Bool("--strip"),
350 Flag.Arg1("--target-arch"),
351 Flag.Arg1("--target-environ"),
352 Flag.Arg1("--target-os"),
353 Flag.Bool("--verbose-tokenize"),
354 Flag.Bool("--verbose-ast-tree"),
355 Flag.Bool("--verbose-ast-fmt"),
356 Flag.Bool("--verbose-link"),
357 Flag.Bool("--verbose-ir"),
358 Flag.Bool("--verbose-llvm-ir"),
359 Flag.Bool("--verbose-cimport"),
360 Flag.Arg1("--zig-install-prefix"),
361 Flag.Arg1("-dirafter"),
362 Flag.ArgMergeN("-isystem", 1),
363 Flag.Arg1("-mllvm"),
364
365 Flag.Arg1("--ar-path"),
366 Flag.Arg1("--dynamic-linker"),
367 Flag.Bool("--each-lib-rpath"),
368 Flag.Arg1("--libc-lib-dir"),
369 Flag.Arg1("--libc-static-lib-dir"),
370 Flag.Arg1("--msvc-lib-dir"),
371 Flag.Arg1("--kernel32-lib-dir"),
372 Flag.ArgMergeN("--library", 1),
373 Flag.ArgMergeN("--forbid-library", 1),
374 Flag.ArgMergeN("--library-path", 1),
375 Flag.Arg1("--linker-script"),
376 Flag.ArgMergeN("--object", 1),
377 // NOTE: Removed -L since it would need to be special-cased and we have an alias in library-path
378 Flag.Bool("-rdynamic"),
379 Flag.Arg1("-rpath"),
380 Flag.Bool("-mconsole"),
381 Flag.Bool("-mwindows"),
382 Flag.ArgMergeN("-framework", 1),
383 Flag.Arg1("-mios-version-min"),
384 Flag.Arg1("-mmacosx-version-min"),
385 Flag.Arg1("--ver-major"),
386 Flag.Arg1("--ver-minor"),
387 Flag.Arg1("--ver-patch"),
388};
546389
547fn printZen() !void {
548 var stdout_file = try io.getStdErr();
549 try stdout_file.write(
550 \\
551 \\ * Communicate intent precisely.
552 \\ * Edge cases matter.
553 \\ * Favor reading code over writing code.
554 \\ * Only one obvious way to do things.
555 \\ * Runtime crashes are better than bugs.
556 \\ * Compile errors are better than runtime crashes.
557 \\ * Incremental improvements.
558 \\ * Avoid local maximums.
559 \\ * Reduce the amount one must remember.
560 \\ * Minimize energy spent on coding style.
561 \\ * Together we serve end users.
562 \\
563 \\
564 );
565}
390fn buildOutputType(allocator: &Allocator, args: []const []const u8, out_type: Module.Kind) !void {
391 var flags = try Args.parse(allocator, args_build_generic, args);
392 defer flags.deinit();
566393
567fn buildMain(allocator: &mem.Allocator, argv: []const []const u8) !void {
568 var build_file: [] const u8 = "build.zig";
569 var cache_dir: ?[] const u8 = null;
570 var zig_install_prefix: ?[] const u8 = null;
571 var asked_for_help = false;
572 var asked_for_init = false;
394 if (flags.present("help")) {
395 try stderr.write(usage_build_generic);
396 os.exit(0);
397 }
573398
574 var args = ArrayList([] const u8).init(allocator);
575 defer args.deinit();
399 var build_mode = builtin.Mode.Debug;
400 if (flags.present("release-fast")) {
401 build_mode = builtin.Mode.ReleaseFast;
402 } else if (flags.present("release-safe")) {
403 build_mode = builtin.Mode.ReleaseSafe;
404 }
576405
577 var zig_exe_path = try os.selfExePath(allocator);
578 defer allocator.free(zig_exe_path);
406 var color = Module.ErrColor.Auto;
407 if (flags.single("color")) |color_flag| {
408 if (mem.eql(u8, color_flag, "auto")) {
409 color = Module.ErrColor.Auto;
410 } else if (mem.eql(u8, color_flag, "on")) {
411 color = Module.ErrColor.On;
412 } else if (mem.eql(u8, color_flag, "off")) {
413 color = Module.ErrColor.Off;
414 } else {
415 unreachable;
416 }
417 }
579418
580 try args.append(""); // Placeholder for zig-cache/build
581 try args.append(""); // Placeholder for zig_exe_path
582 try args.append(""); // Placeholder for build_file_dirname
583 try args.append(""); // Placeholder for full_cache_dir
419 var emit_type = Module.Emit.Binary;
420 if (flags.single("emit")) |emit_flag| {
421 if (mem.eql(u8, emit_flag, "asm")) {
422 emit_type = Module.Emit.Assembly;
423 } else if (mem.eql(u8, emit_flag, "bin")) {
424 emit_type = Module.Emit.Binary;
425 } else if (mem.eql(u8, emit_flag, "llvm-ir")) {
426 emit_type = Module.Emit.LlvmIr;
427 } else {
428 unreachable;
429 }
430 }
431
432 var cur_pkg = try Module.CliPkg.init(allocator, "", "", null); // TODO: Need a path, name?
433 defer cur_pkg.deinit();
584434
585435 var i: usize = 0;
586 while (i < argv.len) : (i += 1) {
587 var arg = argv[i];
588 if (mem.eql(u8, arg, "--help")) {
589 asked_for_help = true;
590 try args.append(argv[i]);
591 } else if (mem.eql(u8, arg, "--init")) {
592 asked_for_init = true;
593 try args.append(argv[i]);
594 } else if (i + 1 < argv.len and mem.eql(u8, arg, "--build-file")) {
595 build_file = argv[i + 1];
596 i += 1;
597 } else if (i + 1 < argv.len and mem.eql(u8, arg, "--cache-dir")) {
598 cache_dir = argv[i + 1];
436 while (i < args.len) : (i += 1) {
437 const arg_name = args[i];
438 if (mem.eql(u8, "--pkg-begin", arg_name)) {
439 // following two arguments guaranteed to exist due to arg parsing
599440 i += 1;
600 } else if (i + 1 < argv.len and mem.eql(u8, arg, "--zig-install-prefix")) {
601 try args.append(arg);
441 const new_pkg_name = args[i];
602442 i += 1;
603 zig_install_prefix = argv[i];
604 try args.append(argv[i]);
605 } else {
606 try args.append(arg);
443 const new_pkg_path = args[i];
444
445 var new_cur_pkg = try Module.CliPkg.init(allocator, new_pkg_name, new_pkg_path, cur_pkg);
446 try cur_pkg.children.append(new_cur_pkg);
447 cur_pkg = new_cur_pkg;
448 } else if (mem.eql(u8, "--pkg-end", arg_name)) {
449 if (cur_pkg.parent == null) {
450 try stderr.print("encountered --pkg-end with no matching --pkg-begin\n");
451 os.exit(1);
452 }
453 cur_pkg = ??cur_pkg.parent;
607454 }
608455 }
609456
610 const zig_lib_dir = try resolveZigLibDir(allocator, zig_install_prefix);
611 defer allocator.free(zig_lib_dir);
457 if (cur_pkg.parent != null) {
458 try stderr.print("unmatched --pkg-begin\n");
459 os.exit(1);
460 }
612461
613 const zig_std_dir = try os.path.join(allocator, zig_lib_dir, "std");
614 defer allocator.free(zig_std_dir);
462 var in_file: ?[]const u8 = undefined;
463 switch (flags.positionals.len) {
464 0 => {
465 try stderr.write("--name [name] not provided and unable to infer\n");
466 os.exit(1);
467 },
468 1 => {
469 in_file = flags.positionals.at(0);
470 },
471 else => {
472 try stderr.write("only one zig input file is accepted during build\n");
473 os.exit(1);
474 },
475 }
615476
616 const special_dir = try os.path.join(allocator, zig_std_dir, "special");
617 defer allocator.free(special_dir);
477 const basename = os.path.basename(??in_file);
478 var it = mem.split(basename, ".");
479 const root_name = it.next() ?? {
480 try stderr.write("file name cannot be empty\n");
481 os.exit(1);
482 };
618483
619 const build_runner_path = try os.path.join(allocator, special_dir, "build_runner.zig");
620 defer allocator.free(build_runner_path);
484 const asm_a= flags.many("assembly");
485 const obj_a = flags.many("object");
486 if (in_file == null and (obj_a == null or (??obj_a).len == 0) and (asm_a == null or (??asm_a).len == 0)) {
487 try stderr.write("Expected source file argument or at least one --object or --assembly argument\n");
488 os.exit(1);
489 }
621490
622 // g = codegen_create(build_runner_path, ...)
623 // codegen_set_out_name(g, "build")
491 if (out_type == Module.Kind.Obj and (obj_a != null and (??obj_a).len != 0)) {
492 try stderr.write("When building an object file, --object arguments are invalid\n");
493 os.exit(1);
494 }
624495
625 const build_file_abs = try os.path.resolve(allocator, ".", build_file);
626 defer allocator.free(build_file_abs);
496 const zig_root_source_file = in_file;
627497
628 const build_file_basename = os.path.basename(build_file_abs);
629 const build_file_dirname = os.path.dirname(build_file_abs);
498 const full_cache_dir = os.path.resolve(allocator, ".", flags.single("cache-dir") ?? "zig-cache"[0..]) catch {
499 os.exit(1);
500 };
501 defer allocator.free(full_cache_dir);
630502
631 var full_cache_dir: []u8 = undefined;
632 if (cache_dir == null) {
633 full_cache_dir = try os.path.join(allocator, build_file_dirname, "zig-cache");
634 } else {
635 full_cache_dir = try os.path.resolve(allocator, ".", ??cache_dir, full_cache_dir);
503 const zig_lib_dir = introspect.resolveZigLibDir(allocator, flags.single("zig-install-prefix") ?? null) catch {
504 os.exit(1);
505 };
506 defer allocator.free(zig_lib_dir);
507
508 var module =
509 try Module.create(
510 allocator,
511 root_name,
512 zig_root_source_file,
513 Target.Native,
514 out_type,
515 build_mode,
516 zig_lib_dir,
517 full_cache_dir
518 );
519 defer module.destroy();
520
521 module.version_major = try std.fmt.parseUnsigned(u32, flags.single("ver-major") ?? "0", 10);
522 module.version_minor = try std.fmt.parseUnsigned(u32, flags.single("ver-minor") ?? "0", 10);
523 module.version_patch = try std.fmt.parseUnsigned(u32, flags.single("ver-patch") ?? "0", 10);
524
525 module.is_test = false;
526
527 if (flags.single("linker-script")) |linker_script| {
528 module.linker_script = linker_script;
636529 }
637 defer allocator.free(full_cache_dir);
638530
639 const path_to_build_exe = try os.path.join(allocator, full_cache_dir, "build");
640 defer allocator.free(path_to_build_exe);
641 // codegen_set_cache_dir(g, full_cache_dir)
531 module.each_lib_rpath = flags.present("each-lib-rpath");
642532
643 args.items[0] = path_to_build_exe;
644 args.items[1] = zig_exe_path;
645 args.items[2] = build_file_dirname;
646 args.items[3] = full_cache_dir;
533 var clang_argv_buf = ArrayList([]const u8).init(allocator);
534 defer clang_argv_buf.deinit();
535 if (flags.many("mllvm")) |mllvm_flags| {
536 for (mllvm_flags) |mllvm| {
537 try clang_argv_buf.append("-mllvm");
538 try clang_argv_buf.append(mllvm);
539 }
647540
648 var build_file_exists: bool = undefined;
649 if (os.File.openRead(allocator, build_file_abs)) |*file| {
650 file.close();
651 build_file_exists = true;
652 } else |_| {
653 build_file_exists = false;
541 module.llvm_argv = mllvm_flags;
542 module.clang_argv = clang_argv_buf.toSliceConst();
654543 }
655544
656 if (!build_file_exists and asked_for_help) {
657 // TODO(bnoordhuis) Print help message from std/special/build_runner.zig
658 return;
545 module.strip = flags.present("strip");
546 module.is_static = flags.present("static");
547
548 if (flags.single("libc-lib-dir")) |libc_lib_dir| {
549 module.libc_lib_dir = libc_lib_dir;
550 }
551 if (flags.single("libc-static-lib-dir")) |libc_static_lib_dir| {
552 module.libc_static_lib_dir = libc_static_lib_dir;
553 }
554 if (flags.single("libc-include-dir")) |libc_include_dir| {
555 module.libc_include_dir = libc_include_dir;
556 }
557 if (flags.single("msvc-lib-dir")) |msvc_lib_dir| {
558 module.msvc_lib_dir = msvc_lib_dir;
559 }
560 if (flags.single("kernel32-lib-dir")) |kernel32_lib_dir| {
561 module.kernel32_lib_dir = kernel32_lib_dir;
562 }
563 if (flags.single("dynamic-linker")) |dynamic_linker| {
564 module.dynamic_linker = dynamic_linker;
659565 }
660566
661 if (!build_file_exists and asked_for_init) {
662 const build_template_path = try os.path.join(allocator, special_dir, "build_file_template.zig");
663 defer allocator.free(build_template_path);
567 module.verbose_tokenize = flags.present("verbose-tokenize");
568 module.verbose_ast_tree = flags.present("verbose-ast-tree");
569 module.verbose_ast_fmt = flags.present("verbose-ast-fmt");
570 module.verbose_link = flags.present("verbose-link");
571 module.verbose_ir = flags.present("verbose-ir");
572 module.verbose_llvm_ir = flags.present("verbose-llvm-ir");
573 module.verbose_cimport = flags.present("verbose-cimport");
664574
665 var srcfile = try os.File.openRead(allocator, build_template_path);
666 defer srcfile.close();
575 module.err_color = color;
667576
668 var dstfile = try os.File.openWrite(allocator, build_file_abs);
669 defer dstfile.close();
577 if (flags.many("library-path")) |lib_dirs| {
578 module.lib_dirs = lib_dirs;
579 }
670580
671 while (true) {
672 var buffer: [4096]u8 = undefined;
673 const n = try srcfile.read(buffer[0..]);
674 if (n == 0) break;
675 try dstfile.write(buffer[0..n]);
676 }
581 if (flags.many("framework")) |frameworks| {
582 module.darwin_frameworks = frameworks;
583 }
677584
678 return;
585 if (flags.many("rpath")) |rpath_list| {
586 module.rpath_list = rpath_list;
679587 }
680588
681 if (!build_file_exists) {
682 warn(
683 \\No 'build.zig' file found.
684 \\Initialize a 'build.zig' template file with `zig build --init`,
685 \\or build an executable directly with `zig build-exe $FILENAME.zig`.
686 \\See: `zig build --help` or `zig help` for more options.
687 \\
688 );
589 if (flags.single("output-h")) |output_h| {
590 module.out_h_path = output_h;
591 }
592
593 module.windows_subsystem_windows = flags.present("mwindows");
594 module.windows_subsystem_console = flags.present("mconsole");
595 module.linker_rdynamic = flags.present("rdynamic");
596
597 if (flags.single("mmacosx-version-min") != null and flags.single("mios-version-min") != null) {
598 try stderr.write("-mmacosx-version-min and -mios-version-min options not allowed together\n");
689599 os.exit(1);
690600 }
691601
692 // codegen_build(g)
693 // codegen_link(g, path_to_build_exe)
694 // codegen_destroy(g)
602 if (flags.single("mmacosx-version-min")) |ver| {
603 module.darwin_version_min = Module.DarwinVersionMin { .MacOS = ver };
604 }
605 if (flags.single("mios-version-min")) |ver| {
606 module.darwin_version_min = Module.DarwinVersionMin { .Ios = ver };
607 }
608
609 module.emit_file_type = emit_type;
610 if (flags.many("object")) |objects| {
611 module.link_objects = objects;
612 }
613 if (flags.many("assembly")) |assembly_files| {
614 module.assembly_files = assembly_files;
615 }
616
617 try module.build();
618 try module.link(flags.single("out-file") ?? null);
695619
696 var proc = try os.ChildProcess.init(args.toSliceConst(), allocator);
620 if (flags.present("print-timing-info")) {
621 // codegen_print_timing_info(g, stderr);
622 }
623
624 try stderr.print("building {}: {}\n", @tagName(out_type), in_file);
625}
626
627fn cmdBuildExe(allocator: &Allocator, args: []const []const u8) !void {
628 try buildOutputType(allocator, args, Module.Kind.Exe);
629}
630
631// cmd:build-lib ///////////////////////////////////////////////////////////////////////////////////
632
633fn cmdBuildLib(allocator: &Allocator, args: []const []const u8) !void {
634 try buildOutputType(allocator, args, Module.Kind.Lib);
635}
636
637// cmd:build-obj ///////////////////////////////////////////////////////////////////////////////////
638
639fn cmdBuildObj(allocator: &Allocator, args: []const []const u8) !void {
640 try buildOutputType(allocator, args, Module.Kind.Obj);
641}
642
643// cmd:cc //////////////////////////////////////////////////////////////////////////////////////////
644
645fn cmdCc(allocator: &Allocator, args: []const []const u8) !void {
646 // TODO: using libclang directly would be nice, but it may not expose argument parsing nicely
647 var command = ArrayList([]const u8).init(allocator);
648 defer command.deinit();
649
650 try command.append("cc");
651 try command.appendSlice(args);
652
653 var proc = try os.ChildProcess.init(command.toSliceConst(), allocator);
697654 defer proc.deinit();
698655
699656 var term = try proc.spawnAndWait();
700657 switch (term) {
701658 os.ChildProcess.Term.Exited => |status| {
702659 if (status != 0) {
703 warn("{} exited with status {}\n", args.at(0), status);
660 try stderr.print("cc exited with status {}\n", status);
704661 os.exit(1);
705662 }
706663 },
707664 os.ChildProcess.Term.Signal => |signal| {
708 warn("{} killed by signal {}\n", args.at(0), signal);
665 try stderr.print("cc killed by signal {}\n", signal);
709666 os.exit(1);
710667 },
711668 os.ChildProcess.Term.Stopped => |signal| {
712 warn("{} stopped by signal {}\n", args.at(0), signal);
669 try stderr.print("cc stopped by signal {}\n", signal);
713670 os.exit(1);
714671 },
715672 os.ChildProcess.Term.Unknown => |status| {
716 warn("{} encountered unknown failure {}\n", args.at(0), status);
673 try stderr.print("cc encountered unknown failure {}\n", status);
717674 os.exit(1);
718675 },
719676 }
720677}
721678
722fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {
723 for (file_paths) |file_path| {
679// cmd:fmt /////////////////////////////////////////////////////////////////////////////////////////
680
681const usage_fmt =
682 \\usage: zig fmt [file]...
683 \\
684 \\ Formats the input files and modifies them in-place.
685 \\
686 \\Options:
687 \\ --help Print this help and exit
688 \\ --keep-backups Retain backup entries for every file
689 \\
690 \\
691 ;
692
693const args_fmt_spec = []Flag {
694 Flag.Bool("--help"),
695 Flag.Bool("--keep-backups"),
696};
697
698fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {
699 var flags = try Args.parse(allocator, args_fmt_spec, args);
700 defer flags.deinit();
701
702 if (flags.present("help")) {
703 try stderr.write(usage_fmt);
704 os.exit(0);
705 }
706
707 if (flags.positionals.len == 0) {
708 try stderr.write("expected at least one source file argument\n");
709 os.exit(1);
710 }
711
712 for (flags.positionals.toSliceConst()) |file_path| {
724713 var file = try os.File.openRead(allocator, file_path);
725714 defer file.close();
726715
727716 const source_code = io.readFileAlloc(allocator, file_path) catch |err| {
728 warn("unable to open '{}': {}", file_path, err);
717 try stderr.print("unable to open '{}': {}", file_path, err);
729718 continue;
730719 };
731720 defer allocator.free(source_code);
......@@ -734,72 +723,423 @@ fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {
734723 var parser = std.zig.Parser.init(&tokenizer, allocator, file_path);
735724 defer parser.deinit();
736725
737 var tree = try parser.parse();
726 var tree = parser.parse() catch |err| {
727 try stderr.print("error parsing file '{}': {}\n", file_path, err);
728 continue;
729 };
738730 defer tree.deinit();
739731
740 const baf = try io.BufferedAtomicFile.create(allocator, file_path);
741 defer baf.destroy();
732 var original_file_backup = try Buffer.init(allocator, file_path);
733 defer original_file_backup.deinit();
734 try original_file_backup.append(".backup");
735
736 try os.rename(allocator, file_path, original_file_backup.toSliceConst());
737
738 try stderr.print("{}\n", file_path);
742739
743 try parser.renderSource(baf.stream(), tree.root_node);
744 try baf.finish();
740 // TODO: BufferedAtomicFile has some access problems.
741 var out_file = try os.File.openWrite(allocator, file_path);
742 defer out_file.close();
743
744 var out_file_stream = io.FileOutStream.init(&out_file);
745 try parser.renderSource(out_file_stream.stream, tree.root_node);
746
747 if (!flags.present("keep-backups")) {
748 try os.deleteFile(allocator, original_file_backup.toSliceConst());
749 }
745750 }
746751}
747752
748/// Caller must free result
749fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const u8) ![]u8 {
750 if (zig_install_prefix_arg) |zig_install_prefix| {
751 return testZigInstallPrefix(allocator, zig_install_prefix) catch |err| {
752 warn("No Zig installation found at prefix {}: {}\n", zig_install_prefix_arg, @errorName(err));
753 return error.ZigInstallationNotFound;
754 };
755 } else {
756 return findZigLibDir(allocator) catch |err| {
757 warn("Unable to find zig lib directory: {}.\nReinstall Zig or use --zig-install-prefix.\n",
758 @errorName(err));
759 return error.ZigLibDirNotFound;
760 };
753// cmd:targets /////////////////////////////////////////////////////////////////////////////////////
754
755// TODO: comptime '@fields' for iteration here instead so we are always in sync.
756const Os = builtin.Os;
757pub const os_list = []const Os {
758 Os.freestanding,
759 Os.ananas,
760 Os.cloudabi,
761 Os.dragonfly,
762 Os.freebsd,
763 Os.fuchsia,
764 Os.ios,
765 Os.kfreebsd,
766 Os.linux,
767 Os.lv2,
768 Os.macosx,
769 Os.netbsd,
770 Os.openbsd,
771 Os.solaris,
772 Os.windows,
773 Os.haiku,
774 Os.minix,
775 Os.rtems,
776 Os.nacl,
777 Os.cnk,
778 Os.aix,
779 Os.cuda,
780 Os.nvcl,
781 Os.amdhsa,
782 Os.ps4,
783 Os.elfiamcu,
784 Os.tvos,
785 Os.watchos,
786 Os.mesa3d,
787 Os.contiki,
788 Os.zen,
789};
790
791const Arch = builtin.Arch;
792pub const arch_list = []const Arch {
793 Arch.armv8_2a,
794 Arch.armv8_1a,
795 Arch.armv8,
796 Arch.armv8r,
797 Arch.armv8m_baseline,
798 Arch.armv8m_mainline,
799 Arch.armv7,
800 Arch.armv7em,
801 Arch.armv7m,
802 Arch.armv7s,
803 Arch.armv7k,
804 Arch.armv7ve,
805 Arch.armv6,
806 Arch.armv6m,
807 Arch.armv6k,
808 Arch.armv6t2,
809 Arch.armv5,
810 Arch.armv5te,
811 Arch.armv4t,
812 Arch.aarch64,
813 Arch.aarch64_be,
814 Arch.avr,
815 Arch.bpfel,
816 Arch.bpfeb,
817 Arch.hexagon,
818 Arch.mips,
819 Arch.mipsel,
820 Arch.mips64,
821 Arch.mips64el,
822 Arch.msp430,
823 Arch.nios2,
824 Arch.powerpc,
825 Arch.powerpc64,
826 Arch.powerpc64le,
827 Arch.r600,
828 Arch.amdgcn,
829 Arch.riscv32,
830 Arch.riscv64,
831 Arch.sparc,
832 Arch.sparcv9,
833 Arch.sparcel,
834 Arch.s390x,
835 Arch.tce,
836 Arch.tcele,
837 Arch.thumb,
838 Arch.thumbeb,
839 Arch.i386,
840 Arch.x86_64,
841 Arch.xcore,
842 Arch.nvptx,
843 Arch.nvptx64,
844 Arch.le32,
845 Arch.le64,
846 Arch.amdil,
847 Arch.amdil64,
848 Arch.hsail,
849 Arch.hsail64,
850 Arch.spir,
851 Arch.spir64,
852 Arch.kalimbav3,
853 Arch.kalimbav4,
854 Arch.kalimbav5,
855 Arch.shave,
856 Arch.lanai,
857 Arch.wasm32,
858 Arch.wasm64,
859 Arch.renderscript32,
860 Arch.renderscript64,
861};
862
863const Environ = builtin.Environ;
864pub const environ_list = []const Environ {
865 Environ.unknown,
866 Environ.gnu,
867 Environ.gnuabi64,
868 Environ.gnueabi,
869 Environ.gnueabihf,
870 Environ.gnux32,
871 Environ.code16,
872 Environ.eabi,
873 Environ.eabihf,
874 Environ.android,
875 Environ.musl,
876 Environ.musleabi,
877 Environ.musleabihf,
878 Environ.msvc,
879 Environ.itanium,
880 Environ.cygnus,
881 Environ.amdopencl,
882 Environ.coreclr,
883 Environ.opencl,
884};
885
886fn cmdTargets(allocator: &Allocator, args: []const []const u8) !void {
887 try stdout.write("Architectures:\n");
888 for (arch_list) |arch_tag| {
889 const native_str = if (builtin.arch == arch_tag) " (native) " else "";
890 try stdout.print(" {}{}\n", @tagName(arch_tag), native_str);
761891 }
892 try stdout.write("\n");
893
894 try stdout.write("Operating Systems:\n");
895 for (os_list) |os_tag| {
896 const native_str = if (builtin.os == os_tag) " (native) " else "";
897 try stdout.print(" {}{}\n", @tagName(os_tag), native_str);
898 }
899 try stdout.write("\n");
900
901 try stdout.write("Environments:\n");
902 for (environ_list) |environ_tag| {
903 const native_str = if (builtin.environ == environ_tag) " (native) " else "";
904 try stdout.print(" {}{}\n", @tagName(environ_tag), native_str);
905 }
906}
907
908// cmd:version /////////////////////////////////////////////////////////////////////////////////////
909
910fn cmdVersion(allocator: &Allocator, args: []const []const u8) !void {
911 try stdout.print("{}\n", std.cstr.toSliceConst(c.ZIG_VERSION_STRING));
762912}
763913
764/// Caller must free result
765fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) ![]u8 {
766 const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig");
767 errdefer allocator.free(test_zig_dir);
914// cmd:test ////////////////////////////////////////////////////////////////////////////////////////
915
916const usage_test =
917 \\usage: zig test [file]...
918 \\
919 \\Options:
920 \\ --help Print this help and exit
921 \\
922 \\
923 ;
924
925const args_test_spec = []Flag {
926 Flag.Bool("--help"),
927};
768928
769 const test_index_file = try os.path.join(allocator, test_zig_dir, "std", "index.zig");
770 defer allocator.free(test_index_file);
771929
772 var file = try os.File.openRead(allocator, test_index_file);
773 file.close();
930fn cmdTest(allocator: &Allocator, args: []const []const u8) !void {
931 var flags = try Args.parse(allocator, args_build_spec, args);
932 defer flags.deinit();
774933
775 return test_zig_dir;
934 if (flags.present("help")) {
935 try stderr.write(usage_test);
936 os.exit(0);
937 }
938
939 if (flags.positionals.len != 1) {
940 try stderr.write("expected exactly one zig source file\n");
941 os.exit(1);
942 }
943
944 // compile the test program into the cache and run
945
946 // NOTE: May be overlap with buildOutput, take the shared part out.
947 try stderr.print("testing file {}\n", flags.positionals.at(0));
776948}
777949
778/// Caller must free result
779fn findZigLibDir(allocator: &mem.Allocator) ![]u8 {
780 const self_exe_path = try os.selfExeDirPath(allocator);
781 defer allocator.free(self_exe_path);
950// cmd:run /////////////////////////////////////////////////////////////////////////////////////////
951
952// Run should be simple and not expose the full set of arguments provided by build-exe. If specific
953// build requirements are need, the user should `build-exe` then `run` manually.
954const usage_run =
955 \\usage: zig run [file] -- <runtime args>
956 \\
957 \\Options:
958 \\ --help Print this help and exit
959 \\
960 \\
961 ;
962
963const args_run_spec = []Flag {
964 Flag.Bool("--help"),
965};
782966
783 var cur_path: []const u8 = self_exe_path;
784 while (true) {
785 const test_dir = os.path.dirname(cur_path);
786967
787 if (mem.eql(u8, test_dir, cur_path)) {
968fn cmdRun(allocator: &Allocator, args: []const []const u8) !void {
969 var compile_args = args;
970 var runtime_args: []const []const u8 = []const []const u8 {};
971
972 for (args) |argv, i| {
973 if (mem.eql(u8, argv, "--")) {
974 compile_args = args[0..i];
975 runtime_args = args[i+1..];
788976 break;
789977 }
978 }
790979
791 return testZigInstallPrefix(allocator, test_dir) catch |err| {
792 cur_path = test_dir;
793 continue;
794 };
980 var flags = try Args.parse(allocator, args_run_spec, compile_args);
981 defer flags.deinit();
982
983 if (flags.present("help")) {
984 try stderr.write(usage_run);
985 os.exit(0);
795986 }
796987
797 // TODO look in hard coded installation path from configuration
798 //if (ZIG_INSTALL_PREFIX != nullptr) {
799 // if (test_zig_install_prefix(buf_create_from_str(ZIG_INSTALL_PREFIX), out_path)) {
800 // return 0;
801 // }
802 //}
988 if (flags.positionals.len != 1) {
989 try stderr.write("expected exactly one zig source file\n");
990 os.exit(1);
991 }
992
993 try stderr.print("runtime args:\n");
994 for (runtime_args) |cargs| {
995 try stderr.print("{}\n", cargs);
996 }
997}
803998
804 return error.FileNotFound;
999// cmd:translate-c /////////////////////////////////////////////////////////////////////////////////
1000
1001const usage_translate_c =
1002 \\usage: zig translate-c [file]
1003 \\
1004 \\Options:
1005 \\ --help Print this help and exit
1006 \\ --enable-timing-info Print timing diagnostics
1007 \\ --output [path] Output file to write generated zig file (default: stdout)
1008 \\
1009 \\
1010 ;
1011
1012const args_translate_c_spec = []Flag {
1013 Flag.Bool("--help"),
1014 Flag.Bool("--enable-timing-info"),
1015 Flag.Arg1("--libc-include-dir"),
1016 Flag.Arg1("--output"),
1017};
1018
1019fn cmdTranslateC(allocator: &Allocator, args: []const []const u8) !void {
1020 var flags = try Args.parse(allocator, args_translate_c_spec, args);
1021 defer flags.deinit();
1022
1023 if (flags.present("help")) {
1024 try stderr.write(usage_translate_c);
1025 os.exit(0);
1026 }
1027
1028 if (flags.positionals.len != 1) {
1029 try stderr.write("expected exactly one c source file\n");
1030 os.exit(1);
1031 }
1032
1033 // set up codegen
1034
1035 const zig_root_source_file = null;
1036
1037 // NOTE: translate-c shouldn't require setting up the full codegen instance as it does in
1038 // the C++ compiler.
1039
1040 // codegen_create(g);
1041 // codegen_set_out_name(g, null);
1042 // codegen_translate_c(g, flags.positional.at(0))
1043
1044 var output_stream = stdout;
1045 if (flags.single("output")) |output_file| {
1046 var file = try os.File.openWrite(allocator, output_file);
1047 defer file.close();
1048
1049 var file_stream = io.FileOutStream.init(&file);
1050 // TODO: Not being set correctly, still stdout
1051 output_stream = &file_stream.stream;
1052 }
1053
1054 // ast_render(g, output_stream, g->root_import->root, 4);
1055 try output_stream.write("pub const example = 10;\n");
1056
1057 if (flags.present("enable-timing-info")) {
1058 // codegen_print_timing_info(g, stdout);
1059 try stderr.write("printing timing info for translate-c\n");
1060 }
1061}
1062
1063// cmd:help ////////////////////////////////////////////////////////////////////////////////////////
1064
1065fn cmdHelp(allocator: &Allocator, args: []const []const u8) !void {
1066 try stderr.write(usage);
1067}
1068
1069// cmd:zen /////////////////////////////////////////////////////////////////////////////////////////
1070
1071const info_zen =
1072 \\
1073 \\ * Communicate intent precisely.
1074 \\ * Edge cases matter.
1075 \\ * Favor reading code over writing code.
1076 \\ * Only one obvious way to do things.
1077 \\ * Runtime crashes are better than bugs.
1078 \\ * Compile errors are better than runtime crashes.
1079 \\ * Incremental improvements.
1080 \\ * Avoid local maximums.
1081 \\ * Reduce the amount one must remember.
1082 \\ * Minimize energy spent on coding style.
1083 \\ * Together we serve end users.
1084 \\
1085 \\
1086 ;
1087
1088fn cmdZen(allocator: &Allocator, args: []const []const u8) !void {
1089 try stdout.write(info_zen);
1090}
1091
1092// cmd:internal ////////////////////////////////////////////////////////////////////////////////////
1093
1094const usage_internal =
1095 \\usage: zig internal [subcommand]
1096 \\
1097 \\Sub-Commands:
1098 \\ build-info Print static compiler build-info
1099 \\
1100 \\
1101 ;
1102
1103fn cmdInternal(allocator: &Allocator, args: []const []const u8) !void {
1104 if (args.len == 0) {
1105 try stderr.write(usage_internal);
1106 os.exit(1);
1107 }
1108
1109 const sub_commands = []Command {
1110 Command { .name = "build-info", .exec = cmdInternalBuildInfo },
1111 };
1112
1113 for (sub_commands) |sub_command| {
1114 if (mem.eql(u8, sub_command.name, args[0])) {
1115 try sub_command.exec(allocator, args[1..]);
1116 return;
1117 }
1118 }
1119
1120 try stderr.print("unknown sub command: {}\n\n", args[0]);
1121 try stderr.write(usage_internal);
1122}
1123
1124fn cmdInternalBuildInfo(allocator: &Allocator, args: []const []const u8) !void {
1125 try stdout.print(
1126 \\ZIG_CMAKE_BINARY_DIR {}
1127 \\ZIG_CXX_COMPILER {}
1128 \\ZIG_LLVM_CONFIG_EXE {}
1129 \\ZIG_LLD_INCLUDE_PATH {}
1130 \\ZIG_LLD_LIBRARIES {}
1131 \\ZIG_STD_FILES {}
1132 \\ZIG_C_HEADER_FILES {}
1133 \\ZIG_DIA_GUIDS_LIB {}
1134 \\
1135 ,
1136 std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),
1137 std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),
1138 std.cstr.toSliceConst(c.ZIG_LLVM_CONFIG_EXE),
1139 std.cstr.toSliceConst(c.ZIG_LLD_INCLUDE_PATH),
1140 std.cstr.toSliceConst(c.ZIG_LLD_LIBRARIES),
1141 std.cstr.toSliceConst(c.ZIG_STD_FILES),
1142 std.cstr.toSliceConst(c.ZIG_C_HEADER_FILES),
1143 std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),
1144 );
8051145}
src-self-hosted/module.zig+23
......@@ -109,6 +109,29 @@ pub const Module = struct {
109109 LlvmIr,
110110 };
111111
112 pub const CliPkg = struct {
113 name: []const u8,
114 path: []const u8,
115 children: ArrayList(&CliPkg),
116 parent: ?&CliPkg,
117
118 pub fn init(allocator: &mem.Allocator, name: []const u8, path: []const u8, parent: ?&CliPkg) !&CliPkg {
119 var pkg = try allocator.create(CliPkg);
120 pkg.name = name;
121 pkg.path = path;
122 pkg.children = ArrayList(&CliPkg).init(allocator);
123 pkg.parent = parent;
124 return pkg;
125 }
126
127 pub fn deinit(self: &CliPkg) void {
128 for (self.children.toSliceConst()) |child| {
129 child.deinit();
130 }
131 self.children.deinit();
132 }
133 };
134
112135 pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target,
113136 kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) !&Module
114137 {
std/os/file.zig+8
......@@ -85,6 +85,14 @@ pub const File = struct {
8585 };
8686 }
8787
88 pub fn exists(allocator: &mem.Allocator, path: []const u8) bool {
89 if (openRead(allocator, path)) |*file| {
90 file.close();
91 return true;
92 } else |_| {
93 return false;
94 }
95 }
8896
8997 /// Upon success, the stream is in an uninitialized state. To continue using it,
9098 /// you must use the open() function.