aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-11-10 13:50:44 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-12-06 12:15:04 -0700
commitd5312d53a066092ba9efd687e25b29a87eb6290c (patch)
treeb94a89b89f333cf381046982afe6a86c72c8122e /src
parent0a2fdfbdb934faae7fcf63e9b3ab760c00f47918 (diff)
downloadzig-d5312d53a066092ba9efd687e25b29a87eb6290c.tar.gz
zig-d5312d53a066092ba9efd687e25b29a87eb6290c.zip
WASI: remove absolute path emulation from std lib
Instead of checking for absolute paths and current working directories in various file system operations, there is one simple solution: allow overriding `std.fs.cwd` on WASI. os.realpath is back to causing a compile error when used on WASI. This caused a compile error in the Sema handling of `@src()`. The compiler should never call realpath, so the commit that made this change is reverted (95ab942184427e7c9b840d71f4d093931e3e48fb). If this breaks debug info, a different strategy is needed to solve it other than using realpath. I also removed the preopens code and replaced it with something much simpler. There is no longer any global state in the standard library. Additionally- * os.openat no longer does an unnecessary fstat on WASI when O.WRONLY is not provided. * os.chdir is back to causing a compile error on WASI.
Diffstat (limited to 'src')
-rw-r--r--src/Sema.zig11
-rw-r--r--src/introspect.zig44
-rw-r--r--src/main.zig85
3 files changed, 69 insertions, 71 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index a85c80826e..cb6165f2f6 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -15082,14 +15082,11 @@ fn zirBuiltinSrc(
const file_name_val = blk: {
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
- const relative_path = try fn_owner_decl.getFileScope().fullPath(sema.arena);
- const absolute_path = std.fs.realpathAlloc(sema.arena, relative_path) catch |err| {
- return sema.fail(block, src, "failed to get absolute path of file '{s}': {s}", .{ relative_path, @errorName(err) });
- };
- const aboslute_duped = try anon_decl.arena().dupeZ(u8, absolute_path);
+ // The compiler must not call realpath anywhere.
+ const name = try fn_owner_decl.getFileScope().fullPathZ(anon_decl.arena());
const new_decl = try anon_decl.finish(
- try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), aboslute_duped.len),
- try Value.Tag.bytes.create(anon_decl.arena(), aboslute_duped[0 .. aboslute_duped.len + 1]),
+ try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), name.len),
+ try Value.Tag.bytes.create(anon_decl.arena(), name[0 .. name.len + 1]),
0, // default alignment
);
break :blk try Value.Tag.decl_ref.create(sema.arena, new_decl);
diff --git a/src/introspect.zig b/src/introspect.zig
index 27925ab667..2eeae956ec 100644
--- a/src/introspect.zig
+++ b/src/introspect.zig
@@ -37,34 +37,7 @@ fn testZigInstallPrefix(base_dir: fs.Dir) ?Compilation.Directory {
/// based on a hard-coded Preopen directory ("/zig")
pub fn findZigExePath(allocator: mem.Allocator) ![]u8 {
if (builtin.os.tag == .wasi) {
- var args = try std.process.argsWithAllocator(allocator);
- defer args.deinit();
- // On WASI, argv[0] is always just the basename of the current executable
- const argv0 = args.next() orelse return error.FileNotFound;
-
- // Check these paths:
- // 1. "/zig/{exe_name}"
- // 2. "/zig/bin/{exe_name}"
- const base_paths_to_check = &[_][]const u8{ "/zig", "/zig/bin" };
- const exe_names_to_check = &[_][]const u8{ fs.path.basename(argv0), "zig.wasm" };
-
- for (base_paths_to_check) |base_path| {
- for (exe_names_to_check) |exe_name| {
- const test_path = fs.path.join(allocator, &.{ base_path, exe_name }) catch continue;
- defer allocator.free(test_path);
-
- // Make sure it's a file we're pointing to
- const file = os.fstatat(os.wasi.AT.FDCWD, test_path, 0) catch continue;
- if (file.filetype != .REGULAR_FILE) continue;
-
- // Path seems to be valid, let's try to turn it into an absolute path
- var real_path_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
- if (os.realpath(test_path, &real_path_buf)) |real_path| {
- return allocator.dupe(u8, real_path); // Success: return absolute path
- } else |_| continue;
- }
- }
- return error.FileNotFound;
+ @compileError("this function is unsupported on WASI");
}
return fs.selfExePathAlloc(allocator);
@@ -107,6 +80,9 @@ pub fn findZigLibDirFromSelfExe(
/// Caller owns returned memory.
pub fn resolveGlobalCacheDir(allocator: mem.Allocator) ![]u8 {
+ if (builtin.os.tag == .wasi) {
+ @compileError("on WASI the global cache dir must be resolved with preopens");
+ }
if (std.process.getEnvVarOwned(allocator, "ZIG_GLOBAL_CACHE_DIR")) |value| {
if (value.len > 0) {
return value;
@@ -125,17 +101,7 @@ pub fn resolveGlobalCacheDir(allocator: mem.Allocator) ![]u8 {
}
}
- if (builtin.os.tag == .wasi) {
- // On WASI, we have no way to get an App data dir, so we try to use a fixed
- // Preopen path "/cache" as a last resort
- const path = "/cache";
-
- const file = os.fstatat(os.wasi.AT.FDCWD, path, 0) catch return error.CacheDirUnavailable;
- if (file.filetype != .DIRECTORY) return error.CacheDirUnavailable;
- return allocator.dupe(u8, path);
- } else {
- return fs.getAppDataDir(allocator, appname);
- }
+ return fs.getAppDataDir(allocator, appname);
}
/// Similar to std.fs.path.resolve, with a few important differences:
diff --git a/src/main.zig b/src/main.zig
index 5947ff773a..11eaff9058 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -27,6 +27,23 @@ const crash_report = @import("crash_report.zig");
// Crash report needs to override the panic handler and other root decls
pub usingnamespace crash_report.root_decls;
+var wasi_preopens: fs.wasi.Preopens = undefined;
+pub inline fn wasi_cwd() fs.Dir {
+ // Expect the first preopen to be current working directory.
+ const cwd_fd: std.os.fd_t = 3;
+ assert(mem.eql(u8, wasi_preopens.names[cwd_fd], "."));
+ return .{ .fd = cwd_fd };
+}
+
+pub fn getWasiPreopen(name: []const u8) Compilation.Directory {
+ return .{
+ .path = name,
+ .handle = .{
+ .fd = wasi_preopens.find(name) orelse fatal("WASI preopen not found: '{s}'", .{name}),
+ },
+ };
+}
+
pub fn fatal(comptime format: []const u8, args: anytype) noreturn {
std.log.err(format, args);
process.exit(1);
@@ -161,20 +178,14 @@ pub fn main() anyerror!void {
return mainArgs(gpa_tracy.allocator(), arena, args);
}
- // WASI: `--dir` instructs the WASM runtime to "preopen" a directory, making
- // it available to the us, the guest program. This is the only way for us to
- // access files/dirs on the host filesystem
if (builtin.os.tag == .wasi) {
- // This sets our CWD to "/preopens/cwd"
- // Dot-prefixed preopens like `--dir=.` are "mounted" at "/preopens/cwd"
- // Other preopens like `--dir=lib` are "mounted" at "/"
- try std.os.initPreopensWasi(arena, "/preopens/cwd");
+ wasi_preopens = try fs.wasi.preopensAlloc(arena);
}
// Short circuit some of the other logic for bootstrapping.
if (build_options.only_c) {
- assert(mem.eql(u8, args[1], "build-obj"));
- return buildOutputType(gpa, arena, args, .{ .build = .Obj });
+ assert(mem.eql(u8, args[1], "build-exe"));
+ return buildOutputType(gpa, arena, args, .{ .build = .Exe });
}
return mainArgs(gpa, arena, args);
@@ -2300,7 +2311,7 @@ fn buildOutputType(
},
}
- if (std.fs.path.isAbsolute(lib_name)) {
+ if (fs.path.isAbsolute(lib_name)) {
fatal("cannot use absolute path as a system library: {s}", .{lib_name});
}
@@ -2763,18 +2774,33 @@ fn buildOutputType(
}
}
- const self_exe_path = try introspect.findZigExePath(arena);
- var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |unresolved_lib_dir| l: {
- const lib_dir = try introspect.resolvePath(arena, unresolved_lib_dir);
- break :l .{
- .path = lib_dir,
- .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| {
- fatal("unable to open zig lib directory '{s}': {s}", .{ lib_dir, @errorName(err) });
- },
+ const self_exe_path: ?[]const u8 = if (!process.can_spawn)
+ null
+ else
+ introspect.findZigExePath(arena) catch |err| {
+ fatal("unable to find zig self exe path: {s}", .{@errorName(err)});
};
- } else introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
- fatal("unable to find zig installation directory: {s}\n", .{@errorName(err)});
+
+ var zig_lib_directory: Compilation.Directory = d: {
+ if (override_lib_dir) |unresolved_lib_dir| {
+ const lib_dir = try introspect.resolvePath(arena, unresolved_lib_dir);
+ break :d .{
+ .path = lib_dir,
+ .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| {
+ fatal("unable to open zig lib directory '{s}': {s}", .{ lib_dir, @errorName(err) });
+ },
+ };
+ } else if (builtin.os.tag == .wasi) {
+ break :d getWasiPreopen("/lib");
+ } else if (self_exe_path) |p| {
+ break :d introspect.findZigLibDirFromSelfExe(arena, p) catch |err| {
+ fatal("unable to find zig installation directory: {s}", .{@errorName(err)});
+ };
+ } else {
+ unreachable;
+ }
};
+
defer zig_lib_directory.handle.close();
var thread_pool: ThreadPool = undefined;
@@ -2791,7 +2817,16 @@ fn buildOutputType(
}
var global_cache_directory: Compilation.Directory = l: {
- const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);
+ if (override_global_cache_dir) |p| {
+ break :l .{
+ .handle = try fs.cwd().makeOpenPath(p, .{}),
+ .path = p,
+ };
+ }
+ if (builtin.os.tag == .wasi) {
+ break :l getWasiPreopen("/cache");
+ }
+ const p = try introspect.resolveGlobalCacheDir(arena);
break :l .{
.handle = try fs.cwd().makeOpenPath(p, .{}),
.path = p,
@@ -3082,7 +3117,7 @@ fn buildOutputType(
gpa,
arena,
test_exec_args.items,
- self_exe_path,
+ self_exe_path.?,
arg_mode,
target_info,
watch,
@@ -3154,7 +3189,7 @@ fn buildOutputType(
gpa,
arena,
test_exec_args.items,
- self_exe_path,
+ self_exe_path.?,
arg_mode,
target_info,
watch,
@@ -3179,7 +3214,7 @@ fn buildOutputType(
gpa,
arena,
test_exec_args.items,
- self_exe_path,
+ self_exe_path.?,
arg_mode,
target_info,
watch,
@@ -3523,7 +3558,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void
defer tree.deinit(comp.gpa);
if (out_dep_path) |dep_file_path| {
- const dep_basename = std.fs.path.basename(dep_file_path);
+ const dep_basename = fs.path.basename(dep_file_path);
// Add the files depended on to the cache system.
try man.addDepFilePost(zig_cache_tmp_dir, dep_basename);
// Just to save disk space, we delete the file because it is never needed again.