| author | |
| committer | |
| log | bb9cd6db1cab40d5d5fba7c2ea4fc979efdefa44 |
| tree | cd567d917137ffb0a1138f95e71f673b608e2c7b |
| parent | edb4a07d4ddf01c7f4d589b0f427ba6b9e03134b |
4 files changed, 42 insertions(+), 51 deletions(-)
lib/std/fs.zig-46| ... | ... | @@ -2547,15 +2547,6 @@ pub const SelfExePathError = os.ReadLinkError || os.SysCtlError || os.RealPathEr |
| 2547 | 2547 | /// `selfExePath` except allocates the result on the heap. |
| 2548 | 2548 | /// Caller owns returned memory. |
| 2549 | 2549 | pub fn selfExePathAlloc(allocator: Allocator) ![]u8 { |
| 2550 | if (builtin.os.tag == .wasi) { | |
| 2551 | var args = try std.process.argsWithAllocator(allocator); | |
| 2552 | defer args.deinit(); | |
| 2553 | // On WASI, argv[0] is always just the basename of the current executable | |
| 2554 | const exe_name = args.next() orelse return error.FileNotFound; | |
| 2555 | ||
| 2556 | var buf: [MAX_PATH_BYTES]u8 = undefined; | |
| 2557 | return allocator.dupe(u8, try selfExePathWasi(&buf, exe_name)); | |
| 2558 | } | |
| 2559 | 2550 | // Use of MAX_PATH_BYTES here is justified as, at least on one tested Linux |
| 2560 | 2551 | // system, readlink will completely fail to return a result larger than |
| 2561 | 2552 | // PATH_MAX even if given a sufficiently large buffer. This makes it |
| ... | ... | @@ -2657,43 +2648,6 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { |
| 2657 | 2648 | } |
| 2658 | 2649 | } |
| 2659 | 2650 | |
| 2660 | /// WASI-specific implementation of selfExePath | |
| 2661 | /// | |
| 2662 | /// On WASI argv0 is always just the executable basename, so this function relies | |
| 2663 | /// using a fixed executable directory path: "/zig" | |
| 2664 | /// | |
| 2665 | /// This path can be configured in wasmtime using `--mapdir=/zig::/path/to/zig/dir/` | |
| 2666 | fn selfExePathWasi(out_buffer: []u8, argv0: []const u8) SelfExePathError![]const u8 { | |
| 2667 | var allocator = std.heap.FixedBufferAllocator.init(out_buffer); | |
| 2668 | var alloc = allocator.allocator(); | |
| 2669 | ||
| 2670 | // Check these paths: | |
| 2671 | // 1. "/zig/{exe_name}" | |
| 2672 | // 2. "/zig/bin/{exe_name}" | |
| 2673 | const base_paths_to_check = &[_][]const u8{ "/zig", "/zig/bin" }; | |
| 2674 | const exe_names_to_check = &[_][]const u8{ path.basename(argv0), "zig.wasm" }; | |
| 2675 | ||
| 2676 | for (base_paths_to_check) |base_path| { | |
| 2677 | for (exe_names_to_check) |exe_name| { | |
| 2678 | const test_path = path.join(alloc, &.{ base_path, exe_name }) catch continue; | |
| 2679 | ||
| 2680 | // Make sure it's a file we're pointing to | |
| 2681 | const file = os.fstatat(os.wasi.AT.FDCWD, test_path, 0) catch continue; | |
| 2682 | if (file.filetype != .REGULAR_FILE) continue; | |
| 2683 | ||
| 2684 | // Path seems to be valid, let's try to turn it into an absolute path | |
| 2685 | var real_path_buf: [MAX_PATH_BYTES]u8 = undefined; | |
| 2686 | if (os.realpath(test_path, &real_path_buf)) |real_path| { | |
| 2687 | if (real_path.len > out_buffer.len) | |
| 2688 | return error.NameTooLong; | |
| 2689 | mem.copy(u8, out_buffer, real_path); | |
| 2690 | return out_buffer[0..real_path.len]; | |
| 2691 | } else |_| continue; | |
| 2692 | } | |
| 2693 | } | |
| 2694 | return error.FileNotFound; | |
| 2695 | } | |
| 2696 | ||
| 2697 | 2651 | /// The result is UTF16LE-encoded. |
| 2698 | 2652 | pub fn selfExePathW() [:0]const u16 { |
| 2699 | 2653 | const image_path_name = &os.windows.peb().ProcessParameters.ImagePathName; |
src/introspect.zig+38-1| ... | ... | @@ -33,9 +33,46 @@ fn testZigInstallPrefix(base_dir: fs.Dir) ?Compilation.Directory { |
| 33 | 33 | return Compilation.Directory{ .handle = test_zig_dir, .path = "lib" }; |
| 34 | 34 | } |
| 35 | 35 | |
| 36 | /// This is a small wrapper around selfExePathAlloc that adds support for WASI | |
| 37 | /// based on a hard-coded Preopen directory ("/zig") | |
| 38 | pub fn findZigExePath(allocator: mem.Allocator) ![]u8 { | |
| 39 | if (builtin.os.tag == .wasi) { | |
| 40 | var args = try std.process.argsWithAllocator(allocator); | |
| 41 | defer args.deinit(); | |
| 42 | // On WASI, argv[0] is always just the basename of the current executable | |
| 43 | const argv0 = args.next() orelse return error.FileNotFound; | |
| 44 | ||
| 45 | // Check these paths: | |
| 46 | // 1. "/zig/{exe_name}" | |
| 47 | // 2. "/zig/bin/{exe_name}" | |
| 48 | const base_paths_to_check = &[_][]const u8{ "/zig", "/zig/bin" }; | |
| 49 | const exe_names_to_check = &[_][]const u8{ fs.path.basename(argv0), "zig.wasm" }; | |
| 50 | ||
| 51 | for (base_paths_to_check) |base_path| { | |
| 52 | for (exe_names_to_check) |exe_name| { | |
| 53 | const test_path = fs.path.join(allocator, &.{ base_path, exe_name }) catch continue; | |
| 54 | defer allocator.free(test_path); | |
| 55 | ||
| 56 | // Make sure it's a file we're pointing to | |
| 57 | const file = os.fstatat(os.wasi.AT.FDCWD, test_path, 0) catch continue; | |
| 58 | if (file.filetype != .REGULAR_FILE) continue; | |
| 59 | ||
| 60 | // Path seems to be valid, let's try to turn it into an absolute path | |
| 61 | var real_path_buf: [fs.MAX_PATH_BYTES]u8 = undefined; | |
| 62 | if (os.realpath(test_path, &real_path_buf)) |real_path| { | |
| 63 | return allocator.dupe(u8, real_path); // Success: return absolute path | |
| 64 | } else |_| continue; | |
| 65 | } | |
| 66 | } | |
| 67 | return error.FileNotFound; | |
| 68 | } | |
| 69 | ||
| 70 | return fs.selfExePathAlloc(allocator); | |
| 71 | } | |
| 72 | ||
| 36 | 73 | /// Both the directory handle and the path are newly allocated resources which the caller now owns. |
| 37 | 74 | pub fn findZigLibDir(gpa: mem.Allocator) !Compilation.Directory { |
| 38 | const self_exe_path = try fs.selfExePathAlloc(gpa); | |
| 75 | const self_exe_path = try findZigExePath(gpa); | |
| 39 | 76 | defer gpa.free(self_exe_path); |
| 40 | 77 | |
| 41 | 78 | return findZigLibDirFromSelfExe(gpa, self_exe_path); |
src/main.zig+3-3| ... | ... | @@ -2526,7 +2526,7 @@ fn buildOutputType( |
| 2526 | 2526 | pkg_tree_root.table = .{}; |
| 2527 | 2527 | } |
| 2528 | 2528 | |
| 2529 | const self_exe_path = try fs.selfExePathAlloc(arena); | |
| 2529 | const self_exe_path = try introspect.findZigExePath(arena); | |
| 2530 | 2530 | var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir| .{ |
| 2531 | 2531 | .path = lib_dir, |
| 2532 | 2532 | .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| { |
| ... | ... | @@ -3395,7 +3395,7 @@ pub fn cmdInit( |
| 3395 | 3395 | } |
| 3396 | 3396 | } |
| 3397 | 3397 | } |
| 3398 | const self_exe_path = try fs.selfExePathAlloc(arena); | |
| 3398 | const self_exe_path = try introspect.findZigExePath(arena); | |
| 3399 | 3399 | var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| { |
| 3400 | 3400 | fatal("unable to find zig installation directory: {s}\n", .{@errorName(err)}); |
| 3401 | 3401 | }; |
| ... | ... | @@ -3475,7 +3475,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi |
| 3475 | 3475 | // We want to release all the locks before executing the child process, so we make a nice |
| 3476 | 3476 | // big block here to ensure the cleanup gets run when we extract out our argv. |
| 3477 | 3477 | const child_argv = argv: { |
| 3478 | const self_exe_path = try fs.selfExePathAlloc(arena); | |
| 3478 | const self_exe_path = try introspect.findZigExePath(arena); | |
| 3479 | 3479 | |
| 3480 | 3480 | var build_file: ?[]const u8 = null; |
| 3481 | 3481 | var override_lib_dir: ?[]const u8 = null; |
src/print_env.zig+1-1| ... | ... | @@ -6,7 +6,7 @@ const fatal = @import("main.zig").fatal; |
| 6 | 6 | |
| 7 | 7 | pub fn cmdEnv(gpa: Allocator, args: []const []const u8, stdout: std.fs.File.Writer) !void { |
| 8 | 8 | _ = args; |
| 9 | const self_exe_path = try std.fs.selfExePathAlloc(gpa); | |
| 9 | const self_exe_path = try introspect.findZigExePath(gpa); | |
| 10 | 10 | defer gpa.free(self_exe_path); |
| 11 | 11 | |
| 12 | 12 | var zig_lib_directory = introspect.findZigLibDirFromSelfExe(gpa, self_exe_path) catch |err| { |