diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-11-10 13:50:44 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-12-06 12:15:04 -0700 |
| commit | d5312d53a066092ba9efd687e25b29a87eb6290c (patch) | |
| tree | b94a89b89f333cf381046982afe6a86c72c8122e /src | |
| parent | 0a2fdfbdb934faae7fcf63e9b3ab760c00f47918 (diff) | |
| download | zig-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.zig | 11 | ||||
| -rw-r--r-- | src/introspect.zig | 44 | ||||
| -rw-r--r-- | src/main.zig | 85 |
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. |
