| author | |
| committer | |
| log | 3ae4931dc1a3b1b338d2fd3a49a5a79b445bebf6 |
| tree | 8c6f031412192a2024f17506a8f9d10e0fd13343 |
| parent | 7411be3c9e6d169108456f03b3cbb9b476ee7498 |
In general, we prefer compiler code to use relative paths based on open
directory handles because this is the most portable. However, sometimes
absolute paths are used, and sometimes relative paths are used that go
up a directory.
The recent improvements in 81d2135ca6ebd71b8c121a19957c8fbf7f87125b
regressed the use case when an absolute path is used for the zig lib
directory mixed with a relative path used for the root source file. This
could happen when, for example, running the standard library tests, like
this:
stage3/bin/zig test ../lib/std/std.zig
This happened because the zig lib dir was inferred to be an absolute
directory based on the zig executable directory, while the root source
file was detected as a relative path. There was no common prefix and so
it was not determined that the std.zig file was inside the lib
directory.
This commit adds a function for resolving paths that preserves relative
path names while allowing absolute paths, and converting relative
upwards paths (e.g. "../foo") to absolute paths. This restores the
previous functionality while remaining compatible with systems such as
WASI that cannot deal with absolute paths.6 files changed, 131 insertions(+), 58 deletions(-)
build.zig+1-1| ... | @@ -41,9 +41,9 @@ pub fn build(b: *Builder) !void { | ... | @@ -41,9 +41,9 @@ pub fn build(b: *Builder) !void { |
| 41 | docs_step.dependOn(&docgen_cmd.step); | 41 | docs_step.dependOn(&docgen_cmd.step); |
| 42 | 42 | ||
| 43 | const test_cases = b.addTest("src/test.zig"); | 43 | const test_cases = b.addTest("src/test.zig"); |
| 44 | test_cases.main_pkg_path = "."; | ||
| 44 | test_cases.stack_size = stack_size; | 45 | test_cases.stack_size = stack_size; |
| 45 | test_cases.setBuildMode(mode); | 46 | test_cases.setBuildMode(mode); |
| 46 | test_cases.addPackagePath("test_cases", "test/cases.zig"); | ||
| 47 | test_cases.single_threaded = single_threaded; | 47 | test_cases.single_threaded = single_threaded; |
| 48 | 48 | ||
| 49 | const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"}); | 49 | const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"}); |
lib/std/fs/path.zig+26-25| ... | @@ -462,7 +462,6 @@ pub fn resolve(allocator: Allocator, paths: []const []const u8) ![]u8 { | ... | @@ -462,7 +462,6 @@ pub fn resolve(allocator: Allocator, paths: []const []const u8) ![]u8 { |
| 462 | /// This function is like a series of `cd` statements executed one after another. | 462 | /// This function is like a series of `cd` statements executed one after another. |
| 463 | /// It resolves "." and "..". | 463 | /// It resolves "." and "..". |
| 464 | /// The result does not have a trailing path separator. | 464 | /// The result does not have a trailing path separator. |
| 465 | /// If all paths are relative it uses the current working directory as a starting point. | ||
| 466 | /// Each drive has its own current working directory. | 465 | /// Each drive has its own current working directory. |
| 467 | /// Path separators are canonicalized to '\\' and drives are canonicalized to capital letters. | 466 | /// Path separators are canonicalized to '\\' and drives are canonicalized to capital letters. |
| 468 | /// Note: all usage of this function should be audited due to the existence of symlinks. | 467 | /// Note: all usage of this function should be audited due to the existence of symlinks. |
| ... | @@ -572,15 +571,15 @@ pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) ![]u8 { | ... | @@ -572,15 +571,15 @@ pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) ![]u8 { |
| 572 | continue; | 571 | continue; |
| 573 | } | 572 | } |
| 574 | var it = mem.tokenize(u8, p[parsed.disk_designator.len..], "/\\"); | 573 | var it = mem.tokenize(u8, p[parsed.disk_designator.len..], "/\\"); |
| 575 | component: while (it.next()) |component| { | 574 | while (it.next()) |component| { |
| 576 | if (mem.eql(u8, component, ".")) { | 575 | if (mem.eql(u8, component, ".")) { |
| 577 | continue; | 576 | continue; |
| 578 | } else if (mem.eql(u8, component, "..")) { | 577 | } else if (mem.eql(u8, component, "..")) { |
| 578 | if (result.items.len == 0) { | ||
| 579 | negative_count += 1; | ||
| 580 | continue; | ||
| 581 | } | ||
| 579 | while (true) { | 582 | while (true) { |
| 580 | if (result.items.len == 0) { | ||
| 581 | negative_count += 1; | ||
| 582 | continue :component; | ||
| 583 | } | ||
| 584 | if (result.items.len == disk_designator_len) { | 583 | if (result.items.len == disk_designator_len) { |
| 585 | break; | 584 | break; |
| 586 | } | 585 | } |
| ... | @@ -589,7 +588,7 @@ pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) ![]u8 { | ... | @@ -589,7 +588,7 @@ pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) ![]u8 { |
| 589 | else => false, | 588 | else => false, |
| 590 | }; | 589 | }; |
| 591 | result.items.len -= 1; | 590 | result.items.len -= 1; |
| 592 | if (end_with_sep) break; | 591 | if (end_with_sep or result.items.len == 0) break; |
| 593 | } | 592 | } |
| 594 | } else if (!have_abs_path and result.items.len == 0) { | 593 | } else if (!have_abs_path and result.items.len == 0) { |
| 595 | try result.appendSlice(component); | 594 | try result.appendSlice(component); |
| ... | @@ -659,18 +658,18 @@ pub fn resolvePosix(allocator: Allocator, paths: []const []const u8) Allocator.E | ... | @@ -659,18 +658,18 @@ pub fn resolvePosix(allocator: Allocator, paths: []const []const u8) Allocator.E |
| 659 | result.clearRetainingCapacity(); | 658 | result.clearRetainingCapacity(); |
| 660 | } | 659 | } |
| 661 | var it = mem.tokenize(u8, p, "/"); | 660 | var it = mem.tokenize(u8, p, "/"); |
| 662 | component: while (it.next()) |component| { | 661 | while (it.next()) |component| { |
| 663 | if (mem.eql(u8, component, ".")) { | 662 | if (mem.eql(u8, component, ".")) { |
| 664 | continue; | 663 | continue; |
| 665 | } else if (mem.eql(u8, component, "..")) { | 664 | } else if (mem.eql(u8, component, "..")) { |
| 665 | if (result.items.len == 0) { | ||
| 666 | negative_count += @boolToInt(!is_abs); | ||
| 667 | continue; | ||
| 668 | } | ||
| 666 | while (true) { | 669 | while (true) { |
| 667 | if (result.items.len == 0) { | ||
| 668 | negative_count += @boolToInt(!is_abs); | ||
| 669 | continue :component; | ||
| 670 | } | ||
| 671 | const ends_with_slash = result.items[result.items.len - 1] == '/'; | 670 | const ends_with_slash = result.items[result.items.len - 1] == '/'; |
| 672 | result.items.len -= 1; | 671 | result.items.len -= 1; |
| 673 | if (ends_with_slash) break; | 672 | if (ends_with_slash or result.items.len == 0) break; |
| 674 | } | 673 | } |
| 675 | } else if (result.items.len > 0 or is_abs) { | 674 | } else if (result.items.len > 0 or is_abs) { |
| 676 | try result.ensureUnusedCapacity(1 + component.len); | 675 | try result.ensureUnusedCapacity(1 + component.len); |
| ... | @@ -717,10 +716,10 @@ pub fn resolvePosix(allocator: Allocator, paths: []const []const u8) Allocator.E | ... | @@ -717,10 +716,10 @@ pub fn resolvePosix(allocator: Allocator, paths: []const []const u8) Allocator.E |
| 717 | } | 716 | } |
| 718 | 717 | ||
| 719 | test "resolve" { | 718 | test "resolve" { |
| 720 | try testResolveWindows(&[_][]const u8{ "a\\b\\c\\", "..\\..\\.." }, ".."); | 719 | try testResolveWindows(&[_][]const u8{ "a\\b\\c\\", "..\\..\\.." }, "."); |
| 721 | try testResolveWindows(&[_][]const u8{"."}, "."); | 720 | try testResolveWindows(&[_][]const u8{"."}, "."); |
| 722 | 721 | ||
| 723 | try testResolvePosix(&[_][]const u8{ "a/b/c/", "../../.." }, ".."); | 722 | try testResolvePosix(&[_][]const u8{ "a/b/c/", "../../.." }, "."); |
| 724 | try testResolvePosix(&[_][]const u8{"."}, "."); | 723 | try testResolvePosix(&[_][]const u8{"."}, "."); |
| 725 | } | 724 | } |
| 726 | 725 | ||
| ... | @@ -753,19 +752,21 @@ test "resolveWindows" { | ... | @@ -753,19 +752,21 @@ test "resolveWindows" { |
| 753 | } | 752 | } |
| 754 | 753 | ||
| 755 | test "resolvePosix" { | 754 | test "resolvePosix" { |
| 756 | try testResolvePosix(&[_][]const u8{ "/a/b", "c" }, "/a/b/c"); | 755 | try testResolvePosix(&.{ "/a/b", "c" }, "/a/b/c"); |
| 757 | try testResolvePosix(&[_][]const u8{ "/a/b", "c", "//d", "e///" }, "/d/e"); | 756 | try testResolvePosix(&.{ "/a/b", "c", "//d", "e///" }, "/d/e"); |
| 758 | try testResolvePosix(&[_][]const u8{ "/a/b/c", "..", "../" }, "/a"); | 757 | try testResolvePosix(&.{ "/a/b/c", "..", "../" }, "/a"); |
| 759 | try testResolvePosix(&[_][]const u8{ "/", "..", ".." }, "/"); | 758 | try testResolvePosix(&.{ "/", "..", ".." }, "/"); |
| 760 | try testResolvePosix(&[_][]const u8{"/a/b/c/"}, "/a/b/c"); | 759 | try testResolvePosix(&.{"/a/b/c/"}, "/a/b/c"); |
| 761 | 760 | ||
| 762 | try testResolvePosix(&[_][]const u8{ "/var/lib", "../", "file/" }, "/var/file"); | 761 | try testResolvePosix(&.{ "/var/lib", "../", "file/" }, "/var/file"); |
| 763 | try testResolvePosix(&[_][]const u8{ "/var/lib", "/../", "file/" }, "/file"); | 762 | try testResolvePosix(&.{ "/var/lib", "/../", "file/" }, "/file"); |
| 764 | try testResolvePosix(&[_][]const u8{ "/some/dir", ".", "/absolute/" }, "/absolute"); | 763 | try testResolvePosix(&.{ "/some/dir", ".", "/absolute/" }, "/absolute"); |
| 765 | try testResolvePosix(&[_][]const u8{ "/foo/tmp.3/", "../tmp.3/cycles/root.js" }, "/foo/tmp.3/cycles/root.js"); | 764 | try testResolvePosix(&.{ "/foo/tmp.3/", "../tmp.3/cycles/root.js" }, "/foo/tmp.3/cycles/root.js"); |
| 766 | 765 | ||
| 767 | // Keep relative paths relative. | 766 | // Keep relative paths relative. |
| 768 | try testResolvePosix(&[_][]const u8{"a/b"}, "a/b"); | 767 | try testResolvePosix(&.{"a/b"}, "a/b"); |
| 768 | try testResolvePosix(&.{"."}, "."); | ||
| 769 | try testResolvePosix(&.{ ".", "src/test.zig", "..", "../test/cases.zig" }, "test/cases.zig"); | ||
| 769 | } | 770 | } |
| 770 | 771 | ||
| 771 | fn testResolveWindows(paths: []const []const u8, expected: []const u8) !void { | 772 | fn testResolveWindows(paths: []const []const u8, expected: []const u8) !void { |
src/Module.zig+25-12| ... | @@ -30,6 +30,7 @@ const Sema = @import("Sema.zig"); | ... | @@ -30,6 +30,7 @@ const Sema = @import("Sema.zig"); |
| 30 | const target_util = @import("target.zig"); | 30 | const target_util = @import("target.zig"); |
| 31 | const build_options = @import("build_options"); | 31 | const build_options = @import("build_options"); |
| 32 | const Liveness = @import("Liveness.zig"); | 32 | const Liveness = @import("Liveness.zig"); |
| 33 | const isUpDir = @import("introspect.zig").isUpDir; | ||
| 33 | 34 | ||
| 34 | /// General-purpose allocator. Used for both temporary and long-term storage. | 35 | /// General-purpose allocator. Used for both temporary and long-term storage. |
| 35 | gpa: Allocator, | 36 | gpa: Allocator, |
| ... | @@ -4957,15 +4958,19 @@ pub fn importFile( | ... | @@ -4957,15 +4958,19 @@ pub fn importFile( |
| 4957 | const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path}); | 4958 | const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path}); |
| 4958 | defer gpa.free(resolved_root_path); | 4959 | defer gpa.free(resolved_root_path); |
| 4959 | 4960 | ||
| 4960 | if (!mem.startsWith(u8, resolved_path, resolved_root_path) or | 4961 | const sub_file_path = p: { |
| 4961 | // This prevents this check from triggering when the name of the | 4962 | if (mem.startsWith(u8, resolved_path, resolved_root_path)) { |
| 4962 | // imported file starts with the root path's directory name. | 4963 | // +1 for the directory separator here. |
| 4963 | !std.fs.path.isSep(resolved_path[resolved_root_path.len])) | 4964 | break :p try gpa.dupe(u8, resolved_path[resolved_root_path.len + 1 ..]); |
| 4964 | { | 4965 | } |
| 4966 | if (mem.eql(u8, resolved_root_path, ".") and | ||
| 4967 | !isUpDir(resolved_path) and | ||
| 4968 | !std.fs.path.isAbsolute(resolved_path)) | ||
| 4969 | { | ||
| 4970 | break :p try gpa.dupe(u8, resolved_path); | ||
| 4971 | } | ||
| 4965 | return error.ImportOutsidePkgPath; | 4972 | return error.ImportOutsidePkgPath; |
| 4966 | } | 4973 | }; |
| 4967 | // +1 for the directory separator here. | ||
| 4968 | const sub_file_path = try gpa.dupe(u8, resolved_path[resolved_root_path.len + 1 ..]); | ||
| 4969 | errdefer gpa.free(sub_file_path); | 4974 | errdefer gpa.free(sub_file_path); |
| 4970 | 4975 | ||
| 4971 | log.debug("new importFile. resolved_root_path={s}, resolved_path={s}, sub_file_path={s}, import_string={s}", .{ | 4976 | log.debug("new importFile. resolved_root_path={s}, resolved_path={s}, sub_file_path={s}, import_string={s}", .{ |
| ... | @@ -5015,11 +5020,19 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb | ... | @@ -5015,11 +5020,19 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb |
| 5015 | const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path}); | 5020 | const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path}); |
| 5016 | defer gpa.free(resolved_root_path); | 5021 | defer gpa.free(resolved_root_path); |
| 5017 | 5022 | ||
| 5018 | if (!mem.startsWith(u8, resolved_path, resolved_root_path)) { | 5023 | const sub_file_path = p: { |
| 5024 | if (mem.startsWith(u8, resolved_path, resolved_root_path)) { | ||
| 5025 | // +1 for the directory separator here. | ||
| 5026 | break :p try gpa.dupe(u8, resolved_path[resolved_root_path.len + 1 ..]); | ||
| 5027 | } | ||
| 5028 | if (mem.eql(u8, resolved_root_path, ".") and | ||
| 5029 | !isUpDir(resolved_path) and | ||
| 5030 | !std.fs.path.isAbsolute(resolved_path)) | ||
| 5031 | { | ||
| 5032 | break :p try gpa.dupe(u8, resolved_path); | ||
| 5033 | } | ||
| 5019 | return error.ImportOutsidePkgPath; | 5034 | return error.ImportOutsidePkgPath; |
| 5020 | } | 5035 | }; |
| 5021 | // +1 for the directory separator here. | ||
| 5022 | const sub_file_path = try gpa.dupe(u8, resolved_path[resolved_root_path.len + 1 ..]); | ||
| 5023 | errdefer gpa.free(sub_file_path); | 5036 | errdefer gpa.free(sub_file_path); |
| 5024 | 5037 | ||
| 5025 | var file = try cur_file.pkg.root_src_directory.handle.openFile(sub_file_path, .{}); | 5038 | var file = try cur_file.pkg.root_src_directory.handle.openFile(sub_file_path, .{}); |
src/introspect.zig+52-2| ... | @@ -82,7 +82,12 @@ pub fn findZigLibDir(gpa: mem.Allocator) !Compilation.Directory { | ... | @@ -82,7 +82,12 @@ pub fn findZigLibDir(gpa: mem.Allocator) !Compilation.Directory { |
| 82 | pub fn findZigLibDirFromSelfExe( | 82 | pub fn findZigLibDirFromSelfExe( |
| 83 | allocator: mem.Allocator, | 83 | allocator: mem.Allocator, |
| 84 | self_exe_path: []const u8, | 84 | self_exe_path: []const u8, |
| 85 | ) error{ OutOfMemory, FileNotFound }!Compilation.Directory { | 85 | ) error{ |
| 86 | OutOfMemory, | ||
| 87 | FileNotFound, | ||
| 88 | CurrentWorkingDirectoryUnlinked, | ||
| 89 | Unexpected, | ||
| 90 | }!Compilation.Directory { | ||
| 86 | const cwd = fs.cwd(); | 91 | const cwd = fs.cwd(); |
| 87 | var cur_path: []const u8 = self_exe_path; | 92 | var cur_path: []const u8 = self_exe_path; |
| 88 | while (fs.path.dirname(cur_path)) |dirname| : (cur_path = dirname) { | 93 | while (fs.path.dirname(cur_path)) |dirname| : (cur_path = dirname) { |
| ... | @@ -90,9 +95,11 @@ pub fn findZigLibDirFromSelfExe( | ... | @@ -90,9 +95,11 @@ pub fn findZigLibDirFromSelfExe( |
| 90 | defer base_dir.close(); | 95 | defer base_dir.close(); |
| 91 | 96 | ||
| 92 | const sub_directory = testZigInstallPrefix(base_dir) orelse continue; | 97 | const sub_directory = testZigInstallPrefix(base_dir) orelse continue; |
| 98 | const p = try fs.path.join(allocator, &[_][]const u8{ dirname, sub_directory.path.? }); | ||
| 99 | defer allocator.free(p); | ||
| 93 | return Compilation.Directory{ | 100 | return Compilation.Directory{ |
| 94 | .handle = sub_directory.handle, | 101 | .handle = sub_directory.handle, |
| 95 | .path = try fs.path.join(allocator, &[_][]const u8{ dirname, sub_directory.path.? }), | 102 | .path = try resolvePath(allocator, p), |
| 96 | }; | 103 | }; |
| 97 | } | 104 | } |
| 98 | return error.FileNotFound; | 105 | return error.FileNotFound; |
| ... | @@ -130,3 +137,46 @@ pub fn resolveGlobalCacheDir(allocator: mem.Allocator) ![]u8 { | ... | @@ -130,3 +137,46 @@ pub fn resolveGlobalCacheDir(allocator: mem.Allocator) ![]u8 { |
| 130 | return fs.getAppDataDir(allocator, appname); | 137 | return fs.getAppDataDir(allocator, appname); |
| 131 | } | 138 | } |
| 132 | } | 139 | } |
| 140 | |||
| 141 | /// Similar to std.fs.path.resolve, with a few important differences: | ||
| 142 | /// * If the input is an absolute path, check it against the cwd and try to | ||
| 143 | /// convert it to a relative path. | ||
| 144 | /// * If the resulting path would start with a relative up-dir ("../"), instead | ||
| 145 | /// return an absolute path based on the cwd. | ||
| 146 | /// * When targeting WASI, fail with an error message if an absolute path is | ||
| 147 | /// used. | ||
| 148 | pub fn resolvePath( | ||
| 149 | ally: mem.Allocator, | ||
| 150 | p: []const u8, | ||
| 151 | ) error{ | ||
| 152 | OutOfMemory, | ||
| 153 | CurrentWorkingDirectoryUnlinked, | ||
| 154 | Unexpected, | ||
| 155 | }![]u8 { | ||
| 156 | if (fs.path.isAbsolute(p)) { | ||
| 157 | const cwd_path = try std.process.getCwdAlloc(ally); | ||
| 158 | defer ally.free(cwd_path); | ||
| 159 | const relative = try fs.path.relative(ally, cwd_path, p); | ||
| 160 | if (isUpDir(relative)) { | ||
| 161 | ally.free(relative); | ||
| 162 | return ally.dupe(u8, p); | ||
| 163 | } else { | ||
| 164 | return relative; | ||
| 165 | } | ||
| 166 | } else { | ||
| 167 | const resolved = try fs.path.resolve(ally, &.{p}); | ||
| 168 | if (isUpDir(resolved)) { | ||
| 169 | ally.free(resolved); | ||
| 170 | const cwd_path = try std.process.getCwdAlloc(ally); | ||
| 171 | defer ally.free(cwd_path); | ||
| 172 | return fs.path.resolve(ally, &.{ cwd_path, p }); | ||
| 173 | } else { | ||
| 174 | return resolved; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | /// TODO move this to std.fs.path | ||
| 180 | pub fn isUpDir(p: []const u8) bool { | ||
| 181 | return mem.startsWith(u8, p, "..") and (p.len == 2 or p[2] == fs.path.sep); | ||
| 182 | } |
src/main.zig+26-17| ... | @@ -885,24 +885,28 @@ fn buildOutputType( | ... | @@ -885,24 +885,28 @@ fn buildOutputType( |
| 885 | fatal("unexpected end-of-parameter mark: --", .{}); | 885 | fatal("unexpected end-of-parameter mark: --", .{}); |
| 886 | } | 886 | } |
| 887 | } else if (mem.eql(u8, arg, "--pkg-begin")) { | 887 | } else if (mem.eql(u8, arg, "--pkg-begin")) { |
| 888 | const pkg_name = args_iter.next(); | 888 | const opt_pkg_name = args_iter.next(); |
| 889 | const pkg_path = args_iter.next(); | 889 | const opt_pkg_path = args_iter.next(); |
| 890 | if (pkg_name == null or pkg_path == null) fatal("Expected 2 arguments after {s}", .{arg}); | 890 | if (opt_pkg_name == null or opt_pkg_path == null) |
| 891 | fatal("Expected 2 arguments after {s}", .{arg}); | ||
| 892 | |||
| 893 | const pkg_name = opt_pkg_name.?; | ||
| 894 | const pkg_path = try introspect.resolvePath(arena, opt_pkg_path.?); | ||
| 891 | 895 | ||
| 892 | const new_cur_pkg = Package.create( | 896 | const new_cur_pkg = Package.create( |
| 893 | gpa, | 897 | gpa, |
| 894 | fs.path.dirname(pkg_path.?), | 898 | fs.path.dirname(pkg_path), |
| 895 | fs.path.basename(pkg_path.?), | 899 | fs.path.basename(pkg_path), |
| 896 | ) catch |err| { | 900 | ) catch |err| { |
| 897 | fatal("Failed to add package at path {s}: {s}", .{ pkg_path.?, @errorName(err) }); | 901 | fatal("Failed to add package at path {s}: {s}", .{ pkg_path, @errorName(err) }); |
| 898 | }; | 902 | }; |
| 899 | 903 | ||
| 900 | if (mem.eql(u8, pkg_name.?, "std") or mem.eql(u8, pkg_name.?, "root") or mem.eql(u8, pkg_name.?, "builtin")) { | 904 | if (mem.eql(u8, pkg_name, "std") or mem.eql(u8, pkg_name, "root") or mem.eql(u8, pkg_name, "builtin")) { |
| 901 | fatal("unable to add package '{s}' -> '{s}': conflicts with builtin package", .{ pkg_name.?, pkg_path.? }); | 905 | fatal("unable to add package '{s}' -> '{s}': conflicts with builtin package", .{ pkg_name, pkg_path }); |
| 902 | } else if (cur_pkg.table.get(pkg_name.?)) |prev| { | 906 | } else if (cur_pkg.table.get(pkg_name)) |prev| { |
| 903 | fatal("unable to add package '{s}' -> '{s}': already exists as '{s}", .{ pkg_name.?, pkg_path.?, prev.root_src_path }); | 907 | fatal("unable to add package '{s}' -> '{s}': already exists as '{s}", .{ pkg_name, pkg_path, prev.root_src_path }); |
| 904 | } | 908 | } |
| 905 | try cur_pkg.addAndAdopt(gpa, pkg_name.?, new_cur_pkg); | 909 | try cur_pkg.addAndAdopt(gpa, pkg_name, new_cur_pkg); |
| 906 | cur_pkg = new_cur_pkg; | 910 | cur_pkg = new_cur_pkg; |
| 907 | } else if (mem.eql(u8, arg, "--pkg-end")) { | 911 | } else if (mem.eql(u8, arg, "--pkg-end")) { |
| 908 | cur_pkg = cur_pkg.parent orelse | 912 | cur_pkg = cur_pkg.parent orelse |
| ... | @@ -2705,11 +2709,16 @@ fn buildOutputType( | ... | @@ -2705,11 +2709,16 @@ fn buildOutputType( |
| 2705 | }; | 2709 | }; |
| 2706 | defer emit_implib_resolved.deinit(); | 2710 | defer emit_implib_resolved.deinit(); |
| 2707 | 2711 | ||
| 2708 | const main_pkg: ?*Package = if (root_src_file) |src_path| blk: { | 2712 | const main_pkg: ?*Package = if (root_src_file) |unresolved_src_path| blk: { |
| 2709 | if (main_pkg_path) |p| { | 2713 | const src_path = try introspect.resolvePath(arena, unresolved_src_path); |
| 2710 | const rel_src_path = try fs.path.relative(gpa, p, src_path); | 2714 | if (main_pkg_path) |unresolved_main_pkg_path| { |
| 2711 | defer gpa.free(rel_src_path); | 2715 | const p = try introspect.resolvePath(arena, unresolved_main_pkg_path); |
| 2712 | break :blk try Package.create(gpa, p, rel_src_path); | 2716 | if (p.len == 0) { |
| 2717 | break :blk try Package.create(gpa, null, src_path); | ||
| 2718 | } else { | ||
| 2719 | const rel_src_path = try fs.path.relative(arena, p, src_path); | ||
| 2720 | break :blk try Package.create(gpa, p, rel_src_path); | ||
| 2721 | } | ||
| 2713 | } else { | 2722 | } else { |
| 2714 | const root_src_dir_path = fs.path.dirname(src_path); | 2723 | const root_src_dir_path = fs.path.dirname(src_path); |
| 2715 | break :blk Package.create(gpa, root_src_dir_path, fs.path.basename(src_path)) catch |err| { | 2724 | break :blk Package.create(gpa, root_src_dir_path, fs.path.basename(src_path)) catch |err| { |
| ... | @@ -2745,7 +2754,7 @@ fn buildOutputType( | ... | @@ -2745,7 +2754,7 @@ fn buildOutputType( |
| 2745 | 2754 | ||
| 2746 | const self_exe_path = try introspect.findZigExePath(arena); | 2755 | const self_exe_path = try introspect.findZigExePath(arena); |
| 2747 | var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |unresolved_lib_dir| l: { | 2756 | var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |unresolved_lib_dir| l: { |
| 2748 | const lib_dir = try fs.path.resolve(arena, &.{unresolved_lib_dir}); | 2757 | const lib_dir = try introspect.resolvePath(arena, unresolved_lib_dir); |
| 2749 | break :l .{ | 2758 | break :l .{ |
| 2750 | .path = lib_dir, | 2759 | .path = lib_dir, |
| 2751 | .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| { | 2760 | .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| { |
src/test.zig+1-1| ... | @@ -60,7 +60,7 @@ test { | ... | @@ -60,7 +60,7 @@ test { |
| 60 | ctx.addTestCasesFromDir(dir); | 60 | ctx.addTestCasesFromDir(dir); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | try @import("test_cases").addCases(&ctx); | 63 | try @import("../test/cases.zig").addCases(&ctx); |
| 64 | 64 | ||
| 65 | try ctx.run(); | 65 | try ctx.run(); |
| 66 | } | 66 | } |