zig/src-self-hosted/introspect.zig

139 lines
4.0 KiB
Zig

//! Introspection and determination of system libraries needed by zig.
const std = @import("std");
const mem = std.mem;
const fs = std.fs;
const CacheHash = std.cache_hash.CacheHash;
/// Caller must free result
pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 {
{
const test_zig_dir = try fs.path.join(allocator, &[_][]const u8{ test_path, "lib", "zig" });
errdefer allocator.free(test_zig_dir);
const test_index_file = try fs.path.join(allocator, &[_][]const u8{ test_zig_dir, "std", "std.zig" });
defer allocator.free(test_index_file);
if (fs.cwd().openFile(test_index_file, .{})) |file| {
file.close();
return test_zig_dir;
} else |err| switch (err) {
error.FileNotFound => {
allocator.free(test_zig_dir);
},
else => |e| return e,
}
}
// Also try without "zig"
const test_zig_dir = try fs.path.join(allocator, &[_][]const u8{ test_path, "lib" });
errdefer allocator.free(test_zig_dir);
const test_index_file = try fs.path.join(allocator, &[_][]const u8{ test_zig_dir, "std", "std.zig" });
defer allocator.free(test_index_file);
const file = try fs.cwd().openFile(test_index_file, .{});
file.close();
return test_zig_dir;
}
/// Caller must free result
pub fn findZigLibDir(allocator: *mem.Allocator) ![]u8 {
const self_exe_path = try fs.selfExePathAlloc(allocator);
defer allocator.free(self_exe_path);
var cur_path: []const u8 = self_exe_path;
while (true) {
const test_dir = fs.path.dirname(cur_path) orelse ".";
if (mem.eql(u8, test_dir, cur_path)) {
break;
}
return testZigInstallPrefix(allocator, test_dir) catch |err| {
cur_path = test_dir;
continue;
};
}
return error.FileNotFound;
}
pub fn resolveZigLibDir(allocator: *mem.Allocator) ![]u8 {
return findZigLibDir(allocator) catch |err| {
std.debug.print(
\\Unable to find zig lib directory: {}.
\\Reinstall Zig or use --zig-install-prefix.
\\
, .{@errorName(err)});
return error.ZigLibDirNotFound;
};
}
/// 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);
}
pub fn openGlobalCacheDir() !fs.Dir {
var buf: [fs.MAX_PATH_BYTES]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buf);
const path_name = try resolveGlobalCacheDir(&fba.allocator);
return fs.cwd().makeOpenPath(path_name, .{});
}
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;
var cache_dir = try openGlobalCacheDir();
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;
}