authorgravatar for Sergeeeekg@gmail.comSergey Poznyak <Sergeeeekg@gmail.com> 2020-05-20 07:04:22+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-17 16:35:32-07:00
log80e70735fb9a56279ec990bba17f044a770b339a
treee8146b77c8ec05cc3a34c1ffdf2203eff0de432f
parent044e3ca59222f26ae0a63be24510007c3e2cda82

add `zig info` command


6 files changed, 236 insertions(+), 5 deletions(-)

src-self-hosted/main.zig+4-2
......@@ -30,6 +30,7 @@ const usage =
3030 \\ build-obj [source] Create object from source or assembly
3131 \\ fmt [source] Parse file and render in canonical zig format
3232 \\ targets List available compilation targets
33 \\ info Print lib path, std path, compiler id and version
3334 \\ version Print version number and exit
3435 \\ zen Print zen of zig and exit
3536 \\
......@@ -95,8 +96,9 @@ pub fn main() !void {
9596 const stdout = io.getStdOut().outStream();
9697 return @import("print_targets.zig").cmdTargets(arena, cmd_args, stdout, info.target);
9798 } else if (mem.eql(u8, cmd, "version")) {
98 std.io.getStdOut().writeAll(build_options.version ++ "\n") catch process.exit(1);
99 return;
99 try std.io.getStdOut().writeAll(build_options.version ++ "\n");
100 } else if (mem.eql(u8, cmd, "info")) {
101 try @import("print_info.zig").cmdInfo(arena, cmd_args, .SelfHosted, io.getStdOut().outStream());
100102 } else if (mem.eql(u8, cmd, "zen")) {
101103 try io.getStdOut().writeAll(info_zen);
102104 } else if (mem.eql(u8, cmd, "help")) {
src-self-hosted/print_info.zig created+192
......@@ -0,0 +1,192 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const process = std.process;
4const mem = std.mem;
5const unicode = std.unicode;
6const io = std.io;
7const fs = std.fs;
8const os = std.os;
9const json = std.json;
10const StringifyOptions = json.StringifyOptions;
11const Allocator = std.mem.Allocator;
12const introspect = @import("introspect.zig");
13
14const usage_info =
15 \\Usage: zig info [options]
16 \\
17 \\ Outputs path to zig lib dir, std dir and the global cache dir.
18 \\
19 \\Options:
20 \\ --help Print this help and exit
21 \\ --format [text|json] Choose output format (defaults to text)
22 \\
23;
24
25pub const CompilerInfo = struct {
26 // TODO: port compiler id hash from cpp
27 // /// Compiler id hash
28 // id: []const u8,
29
30 // /// Compiler version
31 // version: []const u8,
32 /// Path to lib/
33 lib_dir: []const u8,
34
35 /// Path to lib/zig/std
36 std_dir: []const u8,
37
38 /// Path to the global cache dir
39 global_cache_dir: []const u8,
40
41 const CompilerType = enum {
42 Stage1,
43 SelfHosted,
44 };
45
46 pub fn getVersionString() []const u8 {
47 // TODO: get this from build.zig somehow
48 return "0.6.0";
49 }
50
51 pub fn getCacheDir(allocator: *Allocator, compiler_type: CompilerType) ![]u8 {
52 const global_cache_dir = try getAppCacheDir(allocator, "zig");
53 defer allocator.free(global_cache_dir);
54
55 const postfix = switch (compiler_type) {
56 .SelfHosted => "self_hosted",
57 .Stage1 => "stage1",
58 };
59 return try fs.path.join(allocator, &[_][]const u8{ global_cache_dir, postfix }); // stage1 compiler uses $cache_dir/zig/stage1
60 }
61
62 // TODO: add CacheType argument here to make it return correct cache dir for stage1
63 pub fn init(allocator: *Allocator, compiler_type: CompilerType) !CompilerInfo {
64 const zig_lib_dir = try introspect.resolveZigLibDir(allocator);
65 errdefer allocator.free(zig_lib_dir);
66
67 const zig_std_dir = try fs.path.join(allocator, &[_][]const u8{ zig_lib_dir, "std" });
68 errdefer allocator.free(zig_std_dir);
69
70 const cache_dir = try CompilerInfo.getCacheDir(allocator, compiler_type);
71 errdefer allocator.free(cache_dir);
72
73 return CompilerInfo{
74 .lib_dir = zig_lib_dir,
75 .std_dir = zig_std_dir,
76 .global_cache_dir = cache_dir,
77 };
78 }
79
80 pub fn toString(self: *CompilerInfo, out_stream: var) !void {
81 inline for (@typeInfo(CompilerInfo).Struct.fields) |field| {
82 try std.fmt.format(out_stream, "{: <16}\t{: <}\n", .{ field.name, @field(self, field.name) });
83 }
84 }
85
86 pub fn deinit(self: *CompilerInfo, allocator: *Allocator) void {
87 allocator.free(self.lib_dir);
88 allocator.free(self.std_dir);
89 allocator.free(self.global_cache_dir);
90 }
91};
92
93pub fn cmdInfo(allocator: *Allocator, cmd_args: []const []const u8, compiler_type: CompilerInfo.CompilerType, stdout: var) !void {
94 var info = try CompilerInfo.init(allocator, compiler_type);
95 defer info.deinit(allocator);
96
97 var bos = io.bufferedOutStream(stdout);
98 const bos_stream = bos.outStream();
99
100 var json_format = false;
101
102 var i: usize = 0;
103 while (i < cmd_args.len) : (i += 1) {
104 const arg = cmd_args[i];
105 if (mem.eql(u8, arg, "--format")) {
106 if (cmd_args.len <= i + 1) {
107 std.debug.warn("expected [text|json] after --format\n", .{});
108 process.exit(1);
109 }
110 const format = cmd_args[i + 1];
111 i += 1;
112 if (mem.eql(u8, format, "text")) {
113 json_format = false;
114 } else if (mem.eql(u8, format, "json")) {
115 json_format = true;
116 } else {
117 std.debug.warn("expected [text|json] after --format, found '{}'\n", .{format});
118 process.exit(1);
119 }
120 } else if (mem.eql(u8, arg, "--help")) {
121 try stdout.writeAll(usage_info);
122 return;
123 } else {
124 std.debug.warn("unrecognized parameter: '{}'\n", .{arg});
125 process.exit(1);
126 }
127 }
128
129 if (json_format) {
130 try json.stringify(info, StringifyOptions{
131 .whitespace = StringifyOptions.Whitespace{ .indent = .{ .Space = 2 } },
132 }, bos_stream);
133 try bos_stream.writeByte('\n');
134 } else {
135 try info.toString(bos_stream);
136 }
137
138 try bos.flush();
139}
140
141pub const GetAppCacheDirError = error{
142 OutOfMemory,
143 AppCacheDirUnavailable,
144};
145
146// Copied from fs.getAppDataDir, but changed it to return .cache/ dir on linux.
147// This is the same behavior as the current zig compiler global cache resolution.
148fn getAppCacheDir(allocator: *Allocator, appname: []const u8) GetAppCacheDirError![]u8 {
149 switch (builtin.os.tag) {
150 .windows => {
151 var dir_path_ptr: [*:0]u16 = undefined;
152 switch (os.windows.shell32.SHGetKnownFolderPath(
153 &os.windows.FOLDERID_LocalAppData,
154 os.windows.KF_FLAG_CREATE,
155 null,
156 &dir_path_ptr,
157 )) {
158 os.windows.S_OK => {
159 defer os.windows.ole32.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr));
160 const global_dir = unicode.utf16leToUtf8Alloc(allocator, mem.spanZ(dir_path_ptr)) catch |err| switch (err) {
161 error.UnexpectedSecondSurrogateHalf => return error.AppCacheDirUnavailable,
162 error.ExpectedSecondSurrogateHalf => return error.AppCacheDirUnavailable,
163 error.DanglingSurrogateHalf => return error.AppCacheDirUnavailable,
164 error.OutOfMemory => return error.OutOfMemory,
165 };
166 defer allocator.free(global_dir);
167 return fs.path.join(allocator, &[_][]const u8{ global_dir, appname });
168 },
169 os.windows.E_OUTOFMEMORY => return error.OutOfMemory,
170 else => return error.AppCacheDirUnavailable,
171 }
172 },
173 .macosx => {
174 const home_dir = os.getenv("HOME") orelse {
175 // TODO look in /etc/passwd
176 return error.AppCacheDirUnavailable;
177 };
178 return fs.path.join(allocator, &[_][]const u8{ home_dir, "Library", "Application Support", appname });
179 },
180 .linux, .freebsd, .netbsd, .dragonfly => {
181 if (os.getenv("XDG_CACHE_HOME")) |cache_home| {
182 return fs.path.join(allocator, &[_][]const u8{ cache_home, appname });
183 }
184
185 const home_dir = os.getenv("HOME") orelse {
186 return error.AppCacheDirUnavailable;
187 };
188 return fs.path.join(allocator, &[_][]const u8{ home_dir, ".cache", appname });
189 },
190 else => @compileError("Unsupported OS"),
191 }
192}
src-self-hosted/stage2.zig+29-3
......@@ -179,8 +179,7 @@ export fn stage2_fmt(argc: c_int, argv: [*]const [*:0]const u8) c_int {
179179 return 0;
180180}
181181
182fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
183 const allocator = std.heap.c_allocator;
182fn argvToArrayList(allocator: *Allocator, argc: c_int, argv: [*]const [*:0]const u8) !ArrayList([]const u8) {
184183 var args_list = std.ArrayList([]const u8).init(allocator);
185184 const argc_usize = @intCast(usize, argc);
186185 var arg_i: usize = 0;
......@@ -188,8 +187,16 @@ fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
188187 try args_list.append(mem.spanZ(argv[arg_i]));
189188 }
190189
191 const args = args_list.span()[2..];
190 return args_list;
191}
192192
193fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
194 const allocator = std.heap.c_allocator;
195
196 var args_list = try argvToArrayList(allocator, argc, argv);
197 defer args_list.deinit();
198
199 const args = args_list.span()[2..];
193200 return self_hosted_main.cmdFmt(allocator, args);
194201}
195202
......@@ -387,6 +394,25 @@ fn detectNativeCpuWithLLVM(
387394 return result;
388395}
389396
397export fn stage2_info(argc: c_int, argv: [*]const [*:0]const u8) c_int {
398 const allocator = std.heap.c_allocator;
399
400 var args_list = argvToArrayList(allocator, argc, argv) catch |err| {
401 std.debug.warn("unable to parse arguments: {}\n", .{@errorName(err)});
402 return -1;
403 };
404 defer args_list.deinit();
405
406 const args = args_list.span()[2..];
407
408 @import("print_info.zig").cmdInfo(allocator, args, .Stage1, std.io.getStdOut().outStream()) catch |err| {
409 std.debug.warn("unable to print info: {}\n", .{@errorName(err)});
410 return -1;
411 };
412
413 return 0;
414}
415
390416// ABI warning
391417export fn stage2_cmd_targets(
392418 zig_triple: ?[*:0]const u8,
src/main.cpp+3
......@@ -47,6 +47,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
4747 " translate-c [source] convert c code to zig code\n"
4848 " targets list available compilation targets\n"
4949 " test [source] create and run a test build\n"
50 " info print lib path, std path, compiler id and version\n"
5051 " version print version number and exit\n"
5152 " zen print zen of zig and exit\n"
5253 "\n"
......@@ -582,6 +583,8 @@ static int main0(int argc, char **argv) {
582583 return (term.how == TerminationIdClean) ? term.code : -1;
583584 } else if (argc >= 2 && strcmp(argv[1], "fmt") == 0) {
584585 return stage2_fmt(argc, argv);
586 } else if (argc >= 2 && strcmp(argv[1], "info") == 0) {
587 return stage2_info(argc, argv);
585588 } else if (argc >= 2 && (strcmp(argv[1], "cc") == 0 || strcmp(argv[1], "c++") == 0)) {
586589 emit_h = false;
587590 strip = true;
src/stage2.cpp+5
......@@ -27,6 +27,11 @@ void stage2_zen(const char **ptr, size_t *len) {
2727 stage2_panic(msg, strlen(msg));
2828}
2929
30int stage2_info(int argc, char** argv) {
31 const char *msg = "stage0 called stage2_info";
32 stage2_panic(msg, strlen(msg));
33}
34
3035void stage2_attach_segfault_handler(void) { }
3136
3237void stage2_panic(const char *ptr, size_t len) {
src/stage2.h+3
......@@ -141,6 +141,9 @@ ZIG_EXTERN_C void stage2_render_ast(struct Stage2Ast *ast, FILE *output_file);
141141// ABI warning
142142ZIG_EXTERN_C void stage2_zen(const char **ptr, size_t *len);
143143
144// ABI warning
145ZIG_EXTERN_C int stage2_info(int argc, char **argv);
146
144147// ABI warning
145148ZIG_EXTERN_C void stage2_attach_segfault_handler(void);
146149