Commit 2b78a90424

kristopher tate <kris.tate+github@gmail.com>
2018-11-29 16:37:01
std.os.path: remove dependance on std.mem.join;
std/os/child_process.zig: windows test/cli.zig: godbolt; doc/docgen.zig
1 parent 53766e7
doc/docgen.zig
@@ -990,13 +990,13 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
                 try tokenizeAndPrint(tokenizer, out, code.source_token);
                 try out.write("</pre>");
                 const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name);
-                const tmp_source_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_ext);
+                const tmp_source_file_name = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_plus_ext });
                 try io.writeFile(tmp_source_file_name, trimmed_raw_source);
 
                 switch (code.id) {
                     Code.Id.Exe => |expected_outcome| {
                         const name_plus_bin_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, exe_ext);
-                        const tmp_bin_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_bin_ext);
+                        const tmp_bin_file_name = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_plus_bin_ext });
                         var build_args = std.ArrayList([]const u8).init(allocator);
                         defer build_args.deinit();
                         try build_args.appendSlice([][]const u8{
@@ -1024,7 +1024,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
                         }
                         for (code.link_objects) |link_object| {
                             const name_with_ext = try std.fmt.allocPrint(allocator, "{}{}", link_object, obj_ext);
-                            const full_path_object = try os.path.join(allocator, tmp_dir_name, name_with_ext);
+                            const full_path_object = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_with_ext });
                             try build_args.append("--object");
                             try build_args.append(full_path_object);
                             try out.print(" --object {}", name_with_ext);
@@ -1216,12 +1216,12 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
                     },
                     Code.Id.Obj => |maybe_error_match| {
                         const name_plus_obj_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, obj_ext);
-                        const tmp_obj_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_obj_ext);
+                        const tmp_obj_file_name = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_plus_obj_ext });
                         var build_args = std.ArrayList([]const u8).init(allocator);
                         defer build_args.deinit();
 
                         const name_plus_h_ext = try std.fmt.allocPrint(allocator, "{}.h", code.name);
-                        const output_h_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_h_ext);
+                        const output_h_file_name = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_plus_h_ext });
 
                         try build_args.appendSlice([][]const u8{
                             zig_exe,
std/debug/index.zig
@@ -1290,7 +1290,7 @@ const LineNumberProgram = struct {
                 return error.InvalidDebugInfo;
             } else
                 self.include_dirs[file_entry.dir_index];
-            const file_name = try os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
+            const file_name = try os.path.join(self.file_entries.allocator, [][]const u8{dir_name, file_entry.file_name});
             errdefer self.file_entries.allocator.free(file_name);
             return LineInfo{
                 .line = if (self.prev_line >= 0) @intCast(usize, self.prev_line) else 0,
std/event/fs.zig
@@ -1339,7 +1339,7 @@ async fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void {
 }
 
 async fn testFsWatch(loop: *Loop) !void {
-    const file_path = try os.path.join(loop.allocator, test_tmp_dir, "file.txt");
+    const file_path = try os.path.join(loop.allocator, [][]const u8{test_tmp_dir, "file.txt"});
     defer loop.allocator.free(file_path);
 
     const contents =
std/os/child_process.zig
@@ -596,7 +596,7 @@ pub const ChildProcess = struct {
 
             var it = mem.split(PATH, ";");
             while (it.next()) |search_path| {
-                const joined_path = try os.path.join(self.allocator, search_path, app_name);
+                const joined_path = try os.path.join(self.allocator, [][]const u8{ search_path, app_name });
                 defer self.allocator.free(joined_path);
 
                 const joined_path_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, app_name);
std/os/get_app_data_dir.zig
@@ -30,7 +30,7 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD
                         error.OutOfMemory => return error.OutOfMemory,
                     };
                     defer allocator.free(global_dir);
-                    return os.path.join(allocator, global_dir, appname);
+                    return os.path.join(allocator, [][]const u8{global_dir, appname});
                 },
                 os.windows.E_OUTOFMEMORY => return error.OutOfMemory,
                 else => return error.AppDataDirUnavailable,
@@ -41,14 +41,14 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD
                 // TODO look in /etc/passwd
                 return error.AppDataDirUnavailable;
             };
-            return os.path.join(allocator, home_dir, "Library", "Application Support", appname);
+            return os.path.join(allocator, [][]const u8{home_dir, "Library", "Application Support", appname});
         },
         builtin.Os.linux, builtin.Os.freebsd => {
             const home_dir = os.getEnvPosix("HOME") orelse {
                 // TODO look in /etc/passwd
                 return error.AppDataDirUnavailable;
             };
-            return os.path.join(allocator, home_dir, ".local", "share", appname);
+            return os.path.join(allocator, [][]const u8{home_dir, ".local", "share", appname});
         },
         else => @compileError("Unsupported OS"),
     }
std/os/path.zig
@@ -35,38 +35,61 @@ pub fn isSep(byte: u8) bool {
 
 /// Naively combines a series of paths with the native path seperator.
 /// Allocates memory for the result, which must be freed by the caller.
-pub fn join(allocator: *Allocator, paths: ...) ![]u8 {
-    if (is_windows) {
-        return joinWindows(allocator, paths);
-    } else {
-        return joinPosix(allocator, paths);
+
+pub fn join(allocator: *Allocator, paths: []const []const u8) ![]u8 {
+    assert(paths.len >= 1);
+    var total_paths_len: usize = paths.len; // 1 sep per path
+    {
+        var path_i: usize = 0;
+        while (path_i < paths.len) : (path_i += 1) {
+            const arg = ([]const u8)(paths[path_i]);
+            total_paths_len += arg.len;
+        }
     }
-}
 
-pub fn joinWindows(allocator: *Allocator, paths: ...) ![]u8 {
-    return mem.join(allocator, sep_windows, paths);
-}
+    const buf = try allocator.alloc(u8, total_paths_len);
+    errdefer allocator.free(buf);
+
+    var buf_index: usize = 0;
+    var path_i: usize = 0;
+    while (true) {
+        const arg = ([]const u8)(paths[path_i]);
+        path_i += 1;
+        mem.copy(u8, buf[buf_index..], arg);
+        buf_index += arg.len;
+        if (path_i >= paths.len) break;
+        if (buf_index > 0 and buf[buf_index - 1] != sep) {
+            buf[buf_index] = sep;
+            buf_index += 1;
+        }
+    }
 
-pub fn joinPosix(allocator: *Allocator, paths: ...) ![]u8 {
-    return mem.join(allocator, sep_posix, paths);
+    return allocator.shrink(u8, buf, buf_index);
 }
 
 test "os.path.join" {
-    assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\a\\b", "c"), "c:\\a\\b\\c"));
-    assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\a\\b\\", "c"), "c:\\a\\b\\c"));
-
-    assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\", "a", "b\\", "c"), "c:\\a\\b\\c"));
-    assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\a\\", "b\\", "c"), "c:\\a\\b\\c"));
-
-    assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig"), "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig"));
-
-    assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/a/b", "c"), "/a/b/c"));
-    assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/a/b/", "c"), "/a/b/c"));
-
-    assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/", "a", "b/", "c"), "/a/b/c"));
-    assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/a/", "b/", "c"), "/a/b/c"));
-
-    assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/home/andy/dev/zig/build/lib/zig/std", "io.zig"), "/home/andy/dev/zig/build/lib/zig/std/io.zig"));
+    switch (builtin.os) {
+        Os.windows => {
+            assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"c:\\a\\b", "c"}), "c:\\a\\b\\c"));
+            assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"c:\\a\\b\\", "c"}), "c:\\a\\b\\c"));
+            assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"c:\\", "a", "b\\", "c"}), "c:\\a\\b\\c"));
+            assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"c:\\a\\", "b\\", "c"}), "c:\\a\\b\\c"));
+            assert(mem.eql(u8, try join( debug.global_allocator
+                                       , [][]const u8{ "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std"
+                                                     , "io.zig"})
+                                       , "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig"));
+        },
+        else => {
+            assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"/a/b", "c"}), "/a/b/c"));
+            assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"/a/b/", "c"}), "/a/b/c"));
+            assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"/", "a", "b/", "c"}), "/a/b/c"));
+            assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"/a/", "b/", "c"}), "/a/b/c"));
+            assert(mem.eql(u8, try join( debug.global_allocator
+                                       , [][]const u8{ "/home/andy/dev/zig/build/lib/zig/std"
+                                                     , "io.zig"})
+                                       , "/home/andy/dev/zig/build/lib/zig/std/io.zig"));
+        }
+    }
 }
 
 pub fn isAbsolute(path: []const u8) bool {
@@ -598,7 +621,7 @@ test "os.path.resolveWindows" {
         const parsed_cwd = windowsParsePath(cwd);
         {
             const result = testResolveWindows([][]const u8{ "/usr/local", "lib\\zig\\std\\array_list.zig" });
-            const expected = try join(debug.global_allocator, parsed_cwd.disk_designator, "usr\\local\\lib\\zig\\std\\array_list.zig");
+            const expected = try join(debug.global_allocator, [][]const u8{ parsed_cwd.disk_designator, "usr\\local\\lib\\zig\\std\\array_list.zig"});
             if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
                 expected[0] = asciiUpper(parsed_cwd.disk_designator[0]);
             }
@@ -606,7 +629,7 @@ test "os.path.resolveWindows" {
         }
         {
             const result = testResolveWindows([][]const u8{ "usr/local", "lib\\zig" });
-            const expected = try join(debug.global_allocator, cwd, "usr\\local\\lib\\zig");
+            const expected = try join(debug.global_allocator, [][]const u8{ cwd, "usr\\local\\lib\\zig" });
             if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
                 expected[0] = asciiUpper(parsed_cwd.disk_designator[0]);
             }
std/build.zig
@@ -145,8 +145,8 @@ pub const Builder = struct {
 
     pub fn setInstallPrefix(self: *Builder, maybe_prefix: ?[]const u8) void {
         self.prefix = maybe_prefix orelse "/usr/local"; // TODO better default
-        self.lib_dir = os.path.join(self.allocator, self.prefix, "lib") catch unreachable;
-        self.exe_dir = os.path.join(self.allocator, self.prefix, "bin") catch unreachable;
+        self.lib_dir = os.path.join(self.allocator, [][]const u8{self.prefix, "lib"}) catch unreachable;
+        self.exe_dir = os.path.join(self.allocator, [][]const u8{self.prefix, "bin"}) catch unreachable;
     }
 
     pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
@@ -666,7 +666,7 @@ pub const Builder = struct {
                 if (os.path.isAbsolute(name)) {
                     return name;
                 }
-                const full_path = try os.path.join(self.allocator, search_prefix, "bin", self.fmt("{}{}", name, exe_extension));
+                const full_path = try os.path.join(self.allocator, [][]const u8{search_prefix, "bin", self.fmt("{}{}", name, exe_extension)});
                 if (os.path.real(self.allocator, full_path)) |real_path| {
                     return real_path;
                 } else |_| {
@@ -681,7 +681,7 @@ pub const Builder = struct {
                 }
                 var it = mem.split(PATH, []u8{os.path.delimiter});
                 while (it.next()) |path| {
-                    const full_path = try os.path.join(self.allocator, path, self.fmt("{}{}", name, exe_extension));
+                    const full_path = try os.path.join(self.allocator, [][]const u8{path, self.fmt("{}{}", name, exe_extension)});
                     if (os.path.real(self.allocator, full_path)) |real_path| {
                         return real_path;
                     } else |_| {
@@ -695,7 +695,7 @@ pub const Builder = struct {
                 return name;
             }
             for (paths) |path| {
-                const full_path = try os.path.join(self.allocator, path, self.fmt("{}{}", name, exe_extension));
+                const full_path = try os.path.join(self.allocator, [][]const u8{path, self.fmt("{}{}", name, exe_extension)});
                 if (os.path.real(self.allocator, full_path)) |real_path| {
                     return real_path;
                 } else |_| {
@@ -1095,7 +1095,7 @@ pub const LibExeObjStep = struct {
     }
 
     pub fn getOutputPath(self: *LibExeObjStep) []const u8 {
-        return if (self.output_path) |output_path| output_path else os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename) catch unreachable;
+        return if (self.output_path) |output_path| output_path else os.path.join(self.builder.allocator, [][]const u8{self.builder.cache_root, self.out_filename}) catch unreachable;
     }
 
     pub fn setOutputHPath(self: *LibExeObjStep, file_path: []const u8) void {
@@ -1108,7 +1108,7 @@ pub const LibExeObjStep = struct {
     }
 
     pub fn getOutputHPath(self: *LibExeObjStep) []const u8 {
-        return if (self.output_h_path) |output_h_path| output_h_path else os.path.join(self.builder.allocator, self.builder.cache_root, self.out_h_filename) catch unreachable;
+        return if (self.output_h_path) |output_h_path| output_h_path else os.path.join(self.builder.allocator, [][]const u8{self.builder.cache_root, self.out_h_filename}) catch unreachable;
     }
 
     pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void {
@@ -1208,7 +1208,7 @@ pub const LibExeObjStep = struct {
         }
 
         if (self.build_options_contents.len() > 0) {
-            const build_options_file = try os.path.join(builder.allocator, builder.cache_root, builder.fmt("{}_build_options.zig", self.name));
+            const build_options_file = try os.path.join(builder.allocator, [][]const u8{builder.cache_root, builder.fmt("{}_build_options.zig", self.name)});
             try std.io.writeFile(build_options_file, self.build_options_contents.toSliceConst());
             try zig_args.append("--pkg-begin");
             try zig_args.append("build_options");
@@ -1455,7 +1455,7 @@ pub const LibExeObjStep = struct {
                     cc_args.append("-c") catch unreachable;
                     cc_args.append(abs_source_file) catch unreachable;
 
-                    const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;
+                    const cache_o_src = os.path.join(builder.allocator, [][]const u8{builder.cache_root, source_file}) catch unreachable;
                     if (os.path.dirname(cache_o_src)) |cache_o_dir| {
                         try builder.makePath(cache_o_dir);
                     }
@@ -1507,7 +1507,7 @@ pub const LibExeObjStep = struct {
                         cc_args.append("-current_version") catch unreachable;
                         cc_args.append(builder.fmt("{}.{}.{}", self.version.major, self.version.minor, self.version.patch)) catch unreachable;
 
-                        const install_name = builder.pathFromRoot(os.path.join(builder.allocator, builder.cache_root, self.major_only_filename) catch unreachable);
+                        const install_name = builder.pathFromRoot(os.path.join(builder.allocator, [][]const u8{builder.cache_root, self.major_only_filename}) catch unreachable);
                         cc_args.append("-install_name") catch unreachable;
                         cc_args.append(install_name) catch unreachable;
                     } else {
@@ -1573,7 +1573,7 @@ pub const LibExeObjStep = struct {
                     cc_args.append("-c") catch unreachable;
                     cc_args.append(abs_source_file) catch unreachable;
 
-                    const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;
+                    const cache_o_src = os.path.join(builder.allocator, [][]const u8{builder.cache_root, source_file}) catch unreachable;
                     if (os.path.dirname(cache_o_src)) |cache_o_dir| {
                         try builder.makePath(cache_o_dir);
                     }
@@ -1721,7 +1721,7 @@ pub const TestStep = struct {
             return output_path;
         } else {
             const basename = self.builder.fmt("test{}", self.target.exeFileExt());
-            return os.path.join(self.builder.allocator, self.builder.cache_root, basename) catch unreachable;
+            return os.path.join(self.builder.allocator, [][]const u8{self.builder.cache_root, basename}) catch unreachable;
         }
     }
 
@@ -1930,13 +1930,13 @@ const InstallArtifactStep = struct {
             .builder = builder,
             .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),
             .artifact = artifact,
-            .dest_file = os.path.join(builder.allocator, dest_dir, artifact.out_filename) catch unreachable,
+            .dest_file = os.path.join(builder.allocator, [][]const u8{dest_dir, artifact.out_filename}) catch unreachable,
         }) catch unreachable;
         self.step.dependOn(&artifact.step);
         builder.pushInstalledFile(self.dest_file);
         if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {
-            builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir, artifact.major_only_filename) catch unreachable);
-            builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir, artifact.name_only_filename) catch unreachable);
+            builder.pushInstalledFile(os.path.join(builder.allocator, [][]const u8{builder.lib_dir, artifact.major_only_filename}) catch unreachable);
+            builder.pushInstalledFile(os.path.join(builder.allocator, [][]const u8{builder.lib_dir, artifact.name_only_filename}) catch unreachable);
         }
         return self;
     }
@@ -2092,13 +2092,13 @@ fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_maj
     const out_dir = os.path.dirname(output_path) orelse ".";
     const out_basename = os.path.basename(output_path);
     // sym link for libfoo.so.1 to libfoo.so.1.2.3
-    const major_only_path = os.path.join(allocator, out_dir, filename_major_only) catch unreachable;
+    const major_only_path = os.path.join(allocator, [][]const u8{out_dir, filename_major_only}) catch unreachable;
     os.atomicSymLink(allocator, out_basename, major_only_path) catch |err| {
         warn("Unable to symlink {} -> {}\n", major_only_path, out_basename);
         return err;
     };
     // sym link for libfoo.so to libfoo.so.1
-    const name_only_path = os.path.join(allocator, out_dir, filename_name_only) catch unreachable;
+    const name_only_path = os.path.join(allocator, [][]const u8{out_dir, filename_name_only}) catch unreachable;
     os.atomicSymLink(allocator, filename_major_only, name_only_path) catch |err| {
         warn("Unable to symlink {} -> {}\n", name_only_path, filename_major_only);
         return err;
test/cli.zig
@@ -29,7 +29,7 @@ pub fn main() !void {
     });
     const zig_exe = try os.path.resolve(a, zig_exe_rel);
 
-    const dir_path = try os.path.join(a, cache_root, "clitest");
+    const dir_path = try os.path.join(a, [][]const u8{ cache_root, "clitest" });
     const TestFn = fn ([]const u8, []const u8) anyerror!void;
     const test_fns = []TestFn{
         testZigInitLib,
@@ -99,8 +99,8 @@ fn testZigInitExe(zig_exe: []const u8, dir_path: []const u8) !void {
 fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void {
     if (builtin.os != builtin.Os.linux or builtin.arch != builtin.Arch.x86_64) return;
 
-    const example_zig_path = try os.path.join(a, dir_path, "example.zig");
-    const example_s_path = try os.path.join(a, dir_path, "example.s");
+    const example_zig_path = try os.path.join(a, [][]const u8{ dir_path, "example.zig" });
+    const example_s_path = try os.path.join(a, [][]const u8{ dir_path, "example.s" });
 
     try std.io.writeFile(example_zig_path,
         \\// Type your code here, or load an example.
test/tests.zig
@@ -420,7 +420,7 @@ pub const CompareOutputContext = struct {
     pub fn addCase(self: *CompareOutputContext, case: TestCase) void {
         const b = self.b;
 
-        const root_src = os.path.join(b.allocator, b.cache_root, case.sources.items[0].filename) catch unreachable;
+        const root_src = os.path.join(b.allocator, [][]const u8{b.cache_root, case.sources.items[0].filename}) catch unreachable;
 
         switch (case.special) {
             Special.Asm => {
@@ -433,7 +433,7 @@ pub const CompareOutputContext = struct {
                 exe.addAssemblyFile(root_src);
 
                 for (case.sources.toSliceConst()) |src_file| {
-                    const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable;
+                    const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable;
                     const write_src = b.addWriteFile(expanded_src_path, src_file.source);
                     exe.step.dependOn(&write_src.step);
                 }
@@ -457,7 +457,7 @@ pub const CompareOutputContext = struct {
                     }
 
                     for (case.sources.toSliceConst()) |src_file| {
-                        const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable;
+                        const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable;
                         const write_src = b.addWriteFile(expanded_src_path, src_file.source);
                         exe.step.dependOn(&write_src.step);
                     }
@@ -480,7 +480,7 @@ pub const CompareOutputContext = struct {
                 }
 
                 for (case.sources.toSliceConst()) |src_file| {
-                    const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable;
+                    const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable;
                     const write_src = b.addWriteFile(expanded_src_path, src_file.source);
                     exe.step.dependOn(&write_src.step);
                 }
@@ -552,8 +552,8 @@ pub const CompileErrorContext = struct {
             const self = @fieldParentPtr(CompileCmpOutputStep, "step", step);
             const b = self.context.b;
 
-            const root_src = os.path.join(b.allocator, b.cache_root, self.case.sources.items[0].filename) catch unreachable;
-            const obj_path = os.path.join(b.allocator, b.cache_root, "test.o") catch unreachable;
+            const root_src = os.path.join(b.allocator, [][]const u8{b.cache_root, self.case.sources.items[0].filename}) catch unreachable;
+            const obj_path = os.path.join(b.allocator, [][]const u8{b.cache_root, "test.o"}) catch unreachable;
 
             var zig_args = ArrayList([]const u8).init(b.allocator);
             zig_args.append(b.zig_exe) catch unreachable;
@@ -700,7 +700,7 @@ pub const CompileErrorContext = struct {
             self.step.dependOn(&compile_and_cmp_errors.step);
 
             for (case.sources.toSliceConst()) |src_file| {
-                const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable;
+                const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable;
                 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
                 compile_and_cmp_errors.step.dependOn(&write_src.step);
             }
@@ -830,7 +830,7 @@ pub const TranslateCContext = struct {
             const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step);
             const b = self.context.b;
 
-            const root_src = os.path.join(b.allocator, b.cache_root, self.case.sources.items[0].filename) catch unreachable;
+            const root_src = os.path.join(b.allocator, [][]const u8{b.cache_root, self.case.sources.items[0].filename}) catch unreachable;
 
             var zig_args = ArrayList([]const u8).init(b.allocator);
             zig_args.append(b.zig_exe) catch unreachable;
@@ -963,7 +963,7 @@ pub const TranslateCContext = struct {
         self.step.dependOn(&translate_c_and_cmp.step);
 
         for (case.sources.toSliceConst()) |src_file| {
-            const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable;
+            const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable;
             const write_src = b.addWriteFile(expanded_src_path, src_file.source);
             translate_c_and_cmp.step.dependOn(&write_src.step);
         }
@@ -1076,7 +1076,7 @@ pub const GenHContext = struct {
 
     pub fn addCase(self: *GenHContext, case: *const TestCase) void {
         const b = self.b;
-        const root_src = os.path.join(b.allocator, b.cache_root, case.sources.items[0].filename) catch unreachable;
+        const root_src = os.path.join(b.allocator, [][]const u8{b.cache_root, case.sources.items[0].filename}) catch unreachable;
 
         const mode = builtin.Mode.Debug;
         const annotated_case_name = fmt.allocPrint(self.b.allocator, "gen-h {} ({})", case.name, @tagName(mode)) catch unreachable;
@@ -1088,7 +1088,7 @@ pub const GenHContext = struct {
         obj.setBuildMode(mode);
 
         for (case.sources.toSliceConst()) |src_file| {
-            const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable;
+            const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable;
             const write_src = b.addWriteFile(expanded_src_path, src_file.source);
             obj.step.dependOn(&write_src.step);
         }
build.zig
@@ -16,7 +16,7 @@ pub fn build(b: *Builder) !void {
     var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
 
     const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe);
-    const langref_out_path = os.path.join(b.allocator, b.cache_root, "langref.html") catch unreachable;
+    const langref_out_path = os.path.join(b.allocator, [][]const u8{ b.cache_root, "langref.html" }) catch unreachable;
     var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{
         docgen_exe.getOutputPath(),
         rel_zig_exe,
@@ -125,13 +125,13 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void {
     for (dep.libdirs.toSliceConst()) |lib_dir| {
         lib_exe_obj.addLibPath(lib_dir);
     }
-    const lib_dir = os.path.join(b.allocator, dep.prefix, "lib") catch unreachable;
+    const lib_dir = os.path.join(b.allocator, [][]const u8{dep.prefix, "lib"}) catch unreachable;
     for (dep.system_libs.toSliceConst()) |lib| {
         const static_bare_name = if (mem.eql(u8, lib, "curses"))
             ([]const u8)("libncurses.a")
         else
             b.fmt("lib{}.a", lib);
-        const static_lib_name = os.path.join(b.allocator, lib_dir, static_bare_name) catch unreachable;
+        const static_lib_name = os.path.join(b.allocator, [][]const u8{lib_dir, static_bare_name}) catch unreachable;
         const have_static = fileExists(static_lib_name) catch unreachable;
         if (have_static) {
             lib_exe_obj.addObjectFile(static_lib_name);
@@ -159,7 +159,7 @@ fn fileExists(filename: []const u8) !bool {
 
 fn addCppLib(b: *Builder, lib_exe_obj: var, cmake_binary_dir: []const u8, lib_name: []const u8) void {
     const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib";
-    lib_exe_obj.addObjectFile(os.path.join(b.allocator, cmake_binary_dir, "zig_cpp", b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt())) catch unreachable);
+    lib_exe_obj.addObjectFile(os.path.join(b.allocator, [][]const u8{ cmake_binary_dir, "zig_cpp", b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt()) }) catch unreachable);
 }
 
 const LibraryDep = struct {
@@ -235,8 +235,8 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
 pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {
     var it = mem.split(stdlib_files, ";");
     while (it.next()) |stdlib_file| {
-        const src_path = os.path.join(b.allocator, "std", stdlib_file) catch unreachable;
-        const dest_path = os.path.join(b.allocator, "lib", "zig", "std", stdlib_file) catch unreachable;
+        const src_path = os.path.join(b.allocator, [][]const u8{"std", stdlib_file}) catch unreachable;
+        const dest_path = os.path.join(b.allocator, [][]const u8{"lib", "zig", "std", stdlib_file}) catch unreachable;
         b.installFile(src_path, dest_path);
     }
 }
@@ -244,8 +244,8 @@ pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {
 pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void {
     var it = mem.split(c_header_files, ";");
     while (it.next()) |c_header_file| {
-        const src_path = os.path.join(b.allocator, "c_headers", c_header_file) catch unreachable;
-        const dest_path = os.path.join(b.allocator, "lib", "zig", "include", c_header_file) catch unreachable;
+        const src_path = os.path.join(b.allocator, [][]const u8{"c_headers", c_header_file}) catch unreachable;
+        const dest_path = os.path.join(b.allocator, [][]const u8{"lib", "zig", "include", c_header_file}) catch unreachable;
         b.installFile(src_path, dest_path);
     }
 }