diff --git a/CMakeLists.txt b/CMakeLists.txt index 4679185573..ceaecf5552 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -326,10 +326,15 @@ set(LIBUNWIND_FILES_DEST "${ZIG_LIB_DIR}/libunwind") set(LIBCXX_FILES_DEST "${ZIG_LIB_DIR}/libcxx") set(ZIG_STD_DEST "${ZIG_LIB_DIR}/std") set(ZIG_CONFIG_H_OUT "${CMAKE_BINARY_DIR}/config.h") +set(ZIG_CONFIG_ZIG_OUT "${CMAKE_BINARY_DIR}/config.zig") configure_file ( "${CMAKE_SOURCE_DIR}/src/config.h.in" "${ZIG_CONFIG_H_OUT}" ) +configure_file ( + "${CMAKE_SOURCE_DIR}/src/config.zig.in" + "${ZIG_CONFIG_ZIG_OUT}" +) include_directories( ${CMAKE_SOURCE_DIR} @@ -472,6 +477,8 @@ set(BUILD_LIBSTAGE2_ARGS "build-lib" --bundle-compiler-rt -fPIC -lc + --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}" + --pkg-end ) if("${ZIG_TARGET_TRIPLE}" STREQUAL "native") diff --git a/lib/std/cache_hash.zig b/lib/std/cache_hash.zig index acaa5edc8d..e89c165d23 100644 --- a/lib/std/cache_hash.zig +++ b/lib/std/cache_hash.zig @@ -193,7 +193,7 @@ pub const CacheHash = struct { const digest_str = iter.next() orelse return error.InvalidFormat; const file_path = iter.rest(); - cache_hash_file.stat.inode = fmt.parseInt(fs.File.INode, mtime_nsec_str, 10) catch return error.InvalidFormat; + cache_hash_file.stat.inode = fmt.parseInt(fs.File.INode, inode, 10) catch return error.InvalidFormat; cache_hash_file.stat.mtime = fmt.parseInt(i64, mtime_nsec_str, 10) catch return error.InvalidFormat; base64_decoder.decode(&cache_hash_file.bin_digest, digest_str) catch return error.InvalidFormat; diff --git a/src-self-hosted/introspect.zig b/src-self-hosted/introspect.zig index 0d4c14a9ae..8e99c93c60 100644 --- a/src-self-hosted/introspect.zig +++ b/src-self-hosted/introspect.zig @@ -3,8 +3,7 @@ const std = @import("std"); const mem = std.mem; const fs = std.fs; - -const warn = std.debug.warn; +const CacheHash = std.cache_hash.CacheHash; /// Caller must free result pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 { @@ -63,7 +62,7 @@ pub fn findZigLibDir(allocator: *mem.Allocator) ![]u8 { pub fn resolveZigLibDir(allocator: *mem.Allocator) ![]u8 { return findZigLibDir(allocator) catch |err| { - warn( + std.debug.print( \\Unable to find zig lib directory: {}. \\Reinstall Zig or use --zig-install-prefix. \\ @@ -73,7 +72,64 @@ pub fn resolveZigLibDir(allocator: *mem.Allocator) ![]u8 { }; } -/// Caller must free result -pub fn resolveZigCacheDir(allocator: *mem.Allocator) ![]u8 { - return std.mem.dupe(allocator, u8, "zig-cache"); +/// Caller owns returned memory. +pub fn resolveGlobalCacheDir(allocator: *mem.Allocator) ![]u8 { + const appname = "zig"; + + if (std.Target.current.os.tag != .windows) { + if (std.os.getenv("XDG_CACHE_HOME")) |cache_root| { + return fs.path.join(allocator, &[_][]const u8{ cache_root, appname }); + } else if (std.os.getenv("HOME")) |home| { + return fs.path.join(allocator, &[_][]const u8{ home, ".cache", appname }); + } + } + + return fs.getAppDataDir(allocator, appname); +} + +var compiler_id_mutex = std.Mutex{}; +var compiler_id: [16]u8 = undefined; +var compiler_id_computed = false; + +pub fn resolveCompilerId(gpa: *mem.Allocator) ![16]u8 { + const held = compiler_id_mutex.acquire(); + defer held.release(); + + if (compiler_id_computed) + return compiler_id; + compiler_id_computed = true; + + const global_cache_dir = try resolveGlobalCacheDir(gpa); + defer gpa.free(global_cache_dir); + + // TODO Introduce openGlobalCacheDir which returns a dir handle rather than a string. + var cache_dir = try fs.cwd().openDir(global_cache_dir, .{}); + defer cache_dir.close(); + + var ch = try CacheHash.init(gpa, cache_dir, "exe"); + defer ch.release(); + + const self_exe_path = try fs.selfExePathAlloc(gpa); + defer gpa.free(self_exe_path); + + _ = try ch.addFile(self_exe_path, null); + + if (try ch.hit()) |digest| { + compiler_id = digest[0..16].*; + return compiler_id; + } + + const libs = try std.process.getSelfExeSharedLibPaths(gpa); + defer { + for (libs) |lib| gpa.free(lib); + gpa.free(libs); + } + + for (libs) |lib| { + try ch.addFilePost(lib); + } + + const digest = ch.final(); + compiler_id = digest[0..16].*; + return compiler_id; } diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index d63ea3a757..d44a7f5305 100644 --- a/src-self-hosted/main.zig +++ b/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 + \\ env 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, "env")) { + try @import("print_env.zig").cmdEnv(arena, cmd_args, io.getStdOut().outStream()); } else if (mem.eql(u8, cmd, "zen")) { try io.getStdOut().writeAll(info_zen); } else if (mem.eql(u8, cmd, "help")) { diff --git a/src-self-hosted/print_env.zig b/src-self-hosted/print_env.zig new file mode 100644 index 0000000000..9b68633d3e --- /dev/null +++ b/src-self-hosted/print_env.zig @@ -0,0 +1,47 @@ +const std = @import("std"); +const build_options = @import("build_options"); +const introspect = @import("introspect.zig"); +const Allocator = std.mem.Allocator; + +pub fn cmdEnv(gpa: *Allocator, args: []const []const u8, stdout: anytype) !void { + const zig_lib_dir = introspect.resolveZigLibDir(gpa) catch |err| { + std.debug.print("unable to find zig installation directory: {}\n", .{@errorName(err)}); + std.process.exit(1); + }; + defer gpa.free(zig_lib_dir); + + const zig_std_dir = try std.fs.path.join(gpa, &[_][]const u8{ zig_lib_dir, "std" }); + defer gpa.free(zig_std_dir); + + const global_cache_dir = try introspect.resolveGlobalCacheDir(gpa); + defer gpa.free(global_cache_dir); + + const compiler_id_digest = try introspect.resolveCompilerId(gpa); + var compiler_id_buf: [compiler_id_digest.len * 2]u8 = undefined; + const compiler_id = std.fmt.bufPrint(&compiler_id_buf, "{x}", .{compiler_id_digest}) catch unreachable; + + var bos = std.io.bufferedOutStream(stdout); + const bos_stream = bos.outStream(); + + var jws = std.json.WriteStream(@TypeOf(bos_stream), 6).init(bos_stream); + try jws.beginObject(); + + try jws.objectField("lib_dir"); + try jws.emitString(zig_lib_dir); + + try jws.objectField("std_dir"); + try jws.emitString(zig_std_dir); + + try jws.objectField("id"); + try jws.emitString(compiler_id); + + try jws.objectField("global_cache_dir"); + try jws.emitString(global_cache_dir); + + try jws.objectField("version"); + try jws.emitString(build_options.version); + + try jws.endObject(); + try bos_stream.writeByte('\n'); + try bos.flush(); +} diff --git a/src-self-hosted/print_targets.zig b/src-self-hosted/print_targets.zig index 34eda71ccf..0fe755ffb4 100644 --- a/src-self-hosted/print_targets.zig +++ b/src-self-hosted/print_targets.zig @@ -67,7 +67,7 @@ pub fn cmdTargets( ) !void { const available_glibcs = blk: { const zig_lib_dir = introspect.resolveZigLibDir(allocator) catch |err| { - std.debug.warn("unable to find zig installation directory: {}\n", .{@errorName(err)}); + std.debug.print("unable to find zig installation directory: {}\n", .{@errorName(err)}); std.process.exit(1); }; defer allocator.free(zig_lib_dir); diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index d96f27a84b..3e1e80892c 100644 --- a/src-self-hosted/stage2.zig +++ b/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_env(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.print("unable to parse arguments: {}\n", .{@errorName(err)}); + return -1; + }; + defer args_list.deinit(); + + const args = args_list.span()[2..]; + + @import("print_env.zig").cmdEnv(allocator, args, std.io.getStdOut().outStream()) catch |err| { + std.debug.print("unable to print info: {}\n", .{@errorName(err)}); + return -1; + }; + + return 0; +} + // ABI warning export fn stage2_cmd_targets( zig_triple: ?[*:0]const u8, diff --git a/src/config.zig.in b/src/config.zig.in new file mode 100644 index 0000000000..ccb618df2d --- /dev/null +++ b/src/config.zig.in @@ -0,0 +1,3 @@ +pub const version: []const u8 = "@ZIG_VERSION@"; +pub const log_scopes: []const []const u8 = &[_][]const u8{}; +pub const enable_tracy = false; diff --git a/src/main.cpp b/src/main.cpp index 6d5f1f3f76..e2f6a82a12 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,6 +38,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " builtin show the source code of @import(\"builtin\")\n" " cc use Zig as a drop-in C compiler\n" " c++ use Zig as a drop-in C++ compiler\n" + " env print lib path, std path, compiler id and version\n" " fmt parse files and render in canonical zig format\n" " id print the base64-encoded compiler id\n" " init-exe initialize a `zig build` application in the cwd\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], "env") == 0) { + return stage2_env(argc, argv); } else if (argc >= 2 && (strcmp(argv[1], "cc") == 0 || strcmp(argv[1], "c++") == 0)) { emit_h = false; strip = true; diff --git a/src/stage2.cpp b/src/stage2.cpp index 887ad461bc..6c010de84f 100644 --- a/src/stage2.cpp +++ b/src/stage2.cpp @@ -27,6 +27,11 @@ void stage2_zen(const char **ptr, size_t *len) { stage2_panic(msg, strlen(msg)); } +int stage2_env(int argc, char** argv) { + const char *msg = "stage0 called stage2_env"; + stage2_panic(msg, strlen(msg)); +} + void stage2_attach_segfault_handler(void) { } void stage2_panic(const char *ptr, size_t len) { diff --git a/src/stage2.h b/src/stage2.h index 7875ef26c3..38a1f77d46 100644 --- a/src/stage2.h +++ b/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_env(int argc, char **argv); + // ABI warning ZIG_EXTERN_C void stage2_attach_segfault_handler(void);