Commit 80e70735fb
Changed files (6)
src-self-hosted
src/main.cpp
@@ -47,6 +47,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
" translate-c [source] convert c code to zig code\n"
" targets list available compilation targets\n"
" test [source] create and run a test build\n"
+ " info print lib path, std path, compiler id and version\n"
" version print version number and exit\n"
" zen print zen of zig and exit\n"
"\n"
@@ -582,6 +583,8 @@ static int main0(int argc, char **argv) {
return (term.how == TerminationIdClean) ? term.code : -1;
} else if (argc >= 2 && strcmp(argv[1], "fmt") == 0) {
return stage2_fmt(argc, argv);
+ } else if (argc >= 2 && strcmp(argv[1], "info") == 0) {
+ return stage2_info(argc, argv);
} else if (argc >= 2 && (strcmp(argv[1], "cc") == 0 || strcmp(argv[1], "c++") == 0)) {
emit_h = false;
strip = true;
src/stage2.cpp
@@ -27,6 +27,11 @@ void stage2_zen(const char **ptr, size_t *len) {
stage2_panic(msg, strlen(msg));
}
+int stage2_info(int argc, char** argv) {
+ const char *msg = "stage0 called stage2_info";
+ stage2_panic(msg, strlen(msg));
+}
+
void stage2_attach_segfault_handler(void) { }
void stage2_panic(const char *ptr, size_t len) {
src/stage2.h
@@ -141,6 +141,9 @@ ZIG_EXTERN_C void stage2_render_ast(struct Stage2Ast *ast, FILE *output_file);
// ABI warning
ZIG_EXTERN_C void stage2_zen(const char **ptr, size_t *len);
+// ABI warning
+ZIG_EXTERN_C int stage2_info(int argc, char **argv);
+
// ABI warning
ZIG_EXTERN_C void stage2_attach_segfault_handler(void);
src-self-hosted/main.zig
@@ -30,6 +30,7 @@ const usage =
\\ build-obj [source] Create object from source or assembly
\\ fmt [source] Parse file and render in canonical zig format
\\ targets List available compilation targets
+ \\ info Print lib path, std path, compiler id and version
\\ version Print version number and exit
\\ zen Print zen of zig and exit
\\
@@ -95,8 +96,9 @@ pub fn main() !void {
const stdout = io.getStdOut().outStream();
return @import("print_targets.zig").cmdTargets(arena, cmd_args, stdout, info.target);
} else if (mem.eql(u8, cmd, "version")) {
- std.io.getStdOut().writeAll(build_options.version ++ "\n") catch process.exit(1);
- return;
+ try std.io.getStdOut().writeAll(build_options.version ++ "\n");
+ } else if (mem.eql(u8, cmd, "info")) {
+ try @import("print_info.zig").cmdInfo(arena, cmd_args, .SelfHosted, io.getStdOut().outStream());
} else if (mem.eql(u8, cmd, "zen")) {
try io.getStdOut().writeAll(info_zen);
} else if (mem.eql(u8, cmd, "help")) {
src-self-hosted/print_info.zig
@@ -0,0 +1,192 @@
+const builtin = @import("builtin");
+const std = @import("std");
+const process = std.process;
+const mem = std.mem;
+const unicode = std.unicode;
+const io = std.io;
+const fs = std.fs;
+const os = std.os;
+const json = std.json;
+const StringifyOptions = json.StringifyOptions;
+const Allocator = std.mem.Allocator;
+const introspect = @import("introspect.zig");
+
+const usage_info =
+ \\Usage: zig info [options]
+ \\
+ \\ Outputs path to zig lib dir, std dir and the global cache dir.
+ \\
+ \\Options:
+ \\ --help Print this help and exit
+ \\ --format [text|json] Choose output format (defaults to text)
+ \\
+;
+
+pub const CompilerInfo = struct {
+ // TODO: port compiler id hash from cpp
+ // /// Compiler id hash
+ // id: []const u8,
+
+ // /// Compiler version
+ // version: []const u8,
+ /// Path to lib/
+ lib_dir: []const u8,
+
+ /// Path to lib/zig/std
+ std_dir: []const u8,
+
+ /// Path to the global cache dir
+ global_cache_dir: []const u8,
+
+ const CompilerType = enum {
+ Stage1,
+ SelfHosted,
+ };
+
+ pub fn getVersionString() []const u8 {
+ // TODO: get this from build.zig somehow
+ return "0.6.0";
+ }
+
+ pub fn getCacheDir(allocator: *Allocator, compiler_type: CompilerType) ![]u8 {
+ const global_cache_dir = try getAppCacheDir(allocator, "zig");
+ defer allocator.free(global_cache_dir);
+
+ const postfix = switch (compiler_type) {
+ .SelfHosted => "self_hosted",
+ .Stage1 => "stage1",
+ };
+ return try fs.path.join(allocator, &[_][]const u8{ global_cache_dir, postfix }); // stage1 compiler uses $cache_dir/zig/stage1
+ }
+
+ // TODO: add CacheType argument here to make it return correct cache dir for stage1
+ pub fn init(allocator: *Allocator, compiler_type: CompilerType) !CompilerInfo {
+ const zig_lib_dir = try introspect.resolveZigLibDir(allocator);
+ errdefer allocator.free(zig_lib_dir);
+
+ const zig_std_dir = try fs.path.join(allocator, &[_][]const u8{ zig_lib_dir, "std" });
+ errdefer allocator.free(zig_std_dir);
+
+ const cache_dir = try CompilerInfo.getCacheDir(allocator, compiler_type);
+ errdefer allocator.free(cache_dir);
+
+ return CompilerInfo{
+ .lib_dir = zig_lib_dir,
+ .std_dir = zig_std_dir,
+ .global_cache_dir = cache_dir,
+ };
+ }
+
+ pub fn toString(self: *CompilerInfo, out_stream: var) !void {
+ inline for (@typeInfo(CompilerInfo).Struct.fields) |field| {
+ try std.fmt.format(out_stream, "{: <16}\t{: <}\n", .{ field.name, @field(self, field.name) });
+ }
+ }
+
+ pub fn deinit(self: *CompilerInfo, allocator: *Allocator) void {
+ allocator.free(self.lib_dir);
+ allocator.free(self.std_dir);
+ allocator.free(self.global_cache_dir);
+ }
+};
+
+pub fn cmdInfo(allocator: *Allocator, cmd_args: []const []const u8, compiler_type: CompilerInfo.CompilerType, stdout: var) !void {
+ var info = try CompilerInfo.init(allocator, compiler_type);
+ defer info.deinit(allocator);
+
+ var bos = io.bufferedOutStream(stdout);
+ const bos_stream = bos.outStream();
+
+ var json_format = false;
+
+ var i: usize = 0;
+ while (i < cmd_args.len) : (i += 1) {
+ const arg = cmd_args[i];
+ if (mem.eql(u8, arg, "--format")) {
+ if (cmd_args.len <= i + 1) {
+ std.debug.warn("expected [text|json] after --format\n", .{});
+ process.exit(1);
+ }
+ const format = cmd_args[i + 1];
+ i += 1;
+ if (mem.eql(u8, format, "text")) {
+ json_format = false;
+ } else if (mem.eql(u8, format, "json")) {
+ json_format = true;
+ } else {
+ std.debug.warn("expected [text|json] after --format, found '{}'\n", .{format});
+ process.exit(1);
+ }
+ } else if (mem.eql(u8, arg, "--help")) {
+ try stdout.writeAll(usage_info);
+ return;
+ } else {
+ std.debug.warn("unrecognized parameter: '{}'\n", .{arg});
+ process.exit(1);
+ }
+ }
+
+ if (json_format) {
+ try json.stringify(info, StringifyOptions{
+ .whitespace = StringifyOptions.Whitespace{ .indent = .{ .Space = 2 } },
+ }, bos_stream);
+ try bos_stream.writeByte('\n');
+ } else {
+ try info.toString(bos_stream);
+ }
+
+ try bos.flush();
+}
+
+pub const GetAppCacheDirError = error{
+ OutOfMemory,
+ AppCacheDirUnavailable,
+};
+
+// Copied from fs.getAppDataDir, but changed it to return .cache/ dir on linux.
+// This is the same behavior as the current zig compiler global cache resolution.
+fn getAppCacheDir(allocator: *Allocator, appname: []const u8) GetAppCacheDirError![]u8 {
+ switch (builtin.os.tag) {
+ .windows => {
+ var dir_path_ptr: [*:0]u16 = undefined;
+ switch (os.windows.shell32.SHGetKnownFolderPath(
+ &os.windows.FOLDERID_LocalAppData,
+ os.windows.KF_FLAG_CREATE,
+ null,
+ &dir_path_ptr,
+ )) {
+ os.windows.S_OK => {
+ defer os.windows.ole32.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr));
+ const global_dir = unicode.utf16leToUtf8Alloc(allocator, mem.spanZ(dir_path_ptr)) catch |err| switch (err) {
+ error.UnexpectedSecondSurrogateHalf => return error.AppCacheDirUnavailable,
+ error.ExpectedSecondSurrogateHalf => return error.AppCacheDirUnavailable,
+ error.DanglingSurrogateHalf => return error.AppCacheDirUnavailable,
+ error.OutOfMemory => return error.OutOfMemory,
+ };
+ defer allocator.free(global_dir);
+ return fs.path.join(allocator, &[_][]const u8{ global_dir, appname });
+ },
+ os.windows.E_OUTOFMEMORY => return error.OutOfMemory,
+ else => return error.AppCacheDirUnavailable,
+ }
+ },
+ .macosx => {
+ const home_dir = os.getenv("HOME") orelse {
+ // TODO look in /etc/passwd
+ return error.AppCacheDirUnavailable;
+ };
+ return fs.path.join(allocator, &[_][]const u8{ home_dir, "Library", "Application Support", appname });
+ },
+ .linux, .freebsd, .netbsd, .dragonfly => {
+ if (os.getenv("XDG_CACHE_HOME")) |cache_home| {
+ return fs.path.join(allocator, &[_][]const u8{ cache_home, appname });
+ }
+
+ const home_dir = os.getenv("HOME") orelse {
+ return error.AppCacheDirUnavailable;
+ };
+ return fs.path.join(allocator, &[_][]const u8{ home_dir, ".cache", appname });
+ },
+ else => @compileError("Unsupported OS"),
+ }
+}
src-self-hosted/stage2.zig
@@ -179,8 +179,7 @@ export fn stage2_fmt(argc: c_int, argv: [*]const [*:0]const u8) c_int {
return 0;
}
-fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
- const allocator = std.heap.c_allocator;
+fn argvToArrayList(allocator: *Allocator, argc: c_int, argv: [*]const [*:0]const u8) !ArrayList([]const u8) {
var args_list = std.ArrayList([]const u8).init(allocator);
const argc_usize = @intCast(usize, argc);
var arg_i: usize = 0;
@@ -188,8 +187,16 @@ fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
try args_list.append(mem.spanZ(argv[arg_i]));
}
- const args = args_list.span()[2..];
+ return args_list;
+}
+fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
+ const allocator = std.heap.c_allocator;
+
+ var args_list = try argvToArrayList(allocator, argc, argv);
+ defer args_list.deinit();
+
+ const args = args_list.span()[2..];
return self_hosted_main.cmdFmt(allocator, args);
}
@@ -387,6 +394,25 @@ fn detectNativeCpuWithLLVM(
return result;
}
+export fn stage2_info(argc: c_int, argv: [*]const [*:0]const u8) c_int {
+ const allocator = std.heap.c_allocator;
+
+ var args_list = argvToArrayList(allocator, argc, argv) catch |err| {
+ std.debug.warn("unable to parse arguments: {}\n", .{@errorName(err)});
+ return -1;
+ };
+ defer args_list.deinit();
+
+ const args = args_list.span()[2..];
+
+ @import("print_info.zig").cmdInfo(allocator, args, .Stage1, std.io.getStdOut().outStream()) catch |err| {
+ std.debug.warn("unable to print info: {}\n", .{@errorName(err)});
+ return -1;
+ };
+
+ return 0;
+}
+
// ABI warning
export fn stage2_cmd_targets(
zig_triple: ?[*:0]const u8,