authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-07 00:42:41-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-07 00:42:41-05:00
log36bade5c562bf0b2479b6dfdd465a1a312890835
tree5ecb89cb50e08dc7032e31c84128f5d32d20d315
parentc804ae2d6b1f62d9cb45db2613d36ef14ac539a0
signaturelock-open Commit is signed but in an unrecognized format.

fixups, and modify std.mem.join and std.os.path.resolve API

* zig fmt * std.mem.join takes a slice of slices instead of var args * std.mem.join takes a separator slice rather than byte, and always inserts it. Previously it would not insert the separator if there already was one, violating the documented behavior. * std.mem.join calculates exactly the correct amount to allocate and has no call to allocator.shrink() * bring back joinWindows and joinPosix and the corresponding tests. it is intended to be able to call these functions from any OS. * rename std.os.path.resolveSlice to resolve (now resolve takes a slice of slices instead of var args)

13 files changed, 291 insertions(+), 147 deletions(-)

build.zig+27-8
...@@ -16,7 +16,10 @@ pub fn build(b: *Builder) !void {...@@ -16,7 +16,10 @@ pub fn build(b: *Builder) !void {
16 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");16 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
1717
18 const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe);18 const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe);
19 const langref_out_path = os.path.join(b.allocator, [][]const u8{ b.cache_root, "langref.html" }) catch unreachable;19 const langref_out_path = os.path.join(
20 b.allocator,
21 [][]const u8{ b.cache_root, "langref.html" },
22 ) catch unreachable;
20 var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{23 var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{
21 docgen_exe.getOutputPath(),24 docgen_exe.getOutputPath(),
22 rel_zig_exe,25 rel_zig_exe,
...@@ -125,13 +128,19 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void {...@@ -125,13 +128,19 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void {
125 for (dep.libdirs.toSliceConst()) |lib_dir| {128 for (dep.libdirs.toSliceConst()) |lib_dir| {
126 lib_exe_obj.addLibPath(lib_dir);129 lib_exe_obj.addLibPath(lib_dir);
127 }130 }
128 const lib_dir = os.path.join(b.allocator, [][]const u8{dep.prefix, "lib"}) catch unreachable;131 const lib_dir = os.path.join(
132 b.allocator,
133 [][]const u8{ dep.prefix, "lib" },
134 ) catch unreachable;
129 for (dep.system_libs.toSliceConst()) |lib| {135 for (dep.system_libs.toSliceConst()) |lib| {
130 const static_bare_name = if (mem.eql(u8, lib, "curses"))136 const static_bare_name = if (mem.eql(u8, lib, "curses"))
131 ([]const u8)("libncurses.a")137 ([]const u8)("libncurses.a")
132 else138 else
133 b.fmt("lib{}.a", lib);139 b.fmt("lib{}.a", lib);
134 const static_lib_name = os.path.join(b.allocator, [][]const u8{lib_dir, static_bare_name}) catch unreachable;140 const static_lib_name = os.path.join(
141 b.allocator,
142 [][]const u8{ lib_dir, static_bare_name },
143 ) catch unreachable;
135 const have_static = fileExists(static_lib_name) catch unreachable;144 const have_static = fileExists(static_lib_name) catch unreachable;
136 if (have_static) {145 if (have_static) {
137 lib_exe_obj.addObjectFile(static_lib_name);146 lib_exe_obj.addObjectFile(static_lib_name);
...@@ -159,7 +168,11 @@ fn fileExists(filename: []const u8) !bool {...@@ -159,7 +168,11 @@ fn fileExists(filename: []const u8) !bool {
159168
160fn addCppLib(b: *Builder, lib_exe_obj: var, cmake_binary_dir: []const u8, lib_name: []const u8) void {169fn addCppLib(b: *Builder, lib_exe_obj: var, cmake_binary_dir: []const u8, lib_name: []const u8) void {
161 const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib";170 const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib";
162 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);171 lib_exe_obj.addObjectFile(os.path.join(b.allocator, [][]const u8{
172 cmake_binary_dir,
173 "zig_cpp",
174 b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt()),
175 }) catch unreachable);
163}176}
164177
165const LibraryDep = struct {178const LibraryDep = struct {
...@@ -235,8 +248,11 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {...@@ -235,8 +248,11 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
235pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {248pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {
236 var it = mem.tokenize(stdlib_files, ";");249 var it = mem.tokenize(stdlib_files, ";");
237 while (it.next()) |stdlib_file| {250 while (it.next()) |stdlib_file| {
238 const src_path = os.path.join(b.allocator, [][]const u8{"std", stdlib_file}) catch unreachable;251 const src_path = os.path.join(b.allocator, [][]const u8{ "std", stdlib_file }) catch unreachable;
239 const dest_path = os.path.join(b.allocator, [][]const u8{"lib", "zig", "std", stdlib_file}) catch unreachable;252 const dest_path = os.path.join(
253 b.allocator,
254 [][]const u8{ "lib", "zig", "std", stdlib_file },
255 ) catch unreachable;
240 b.installFile(src_path, dest_path);256 b.installFile(src_path, dest_path);
241 }257 }
242}258}
...@@ -244,8 +260,11 @@ pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {...@@ -244,8 +260,11 @@ pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {
244pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void {260pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void {
245 var it = mem.tokenize(c_header_files, ";");261 var it = mem.tokenize(c_header_files, ";");
246 while (it.next()) |c_header_file| {262 while (it.next()) |c_header_file| {
247 const src_path = os.path.join(b.allocator, [][]const u8{"c_headers", c_header_file}) catch unreachable;263 const src_path = os.path.join(b.allocator, [][]const u8{ "c_headers", c_header_file }) catch unreachable;
248 const dest_path = os.path.join(b.allocator, [][]const u8{"lib", "zig", "include", c_header_file}) catch unreachable;264 const dest_path = os.path.join(
265 b.allocator,
266 [][]const u8{ "lib", "zig", "include", c_header_file },
267 ) catch unreachable;
249 b.installFile(src_path, dest_path);268 b.installFile(src_path, dest_path);
250 }269 }
251}270}
doc/docgen.zig+20-5
...@@ -990,13 +990,19 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -990,13 +990,19 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
990 try tokenizeAndPrint(tokenizer, out, code.source_token);990 try tokenizeAndPrint(tokenizer, out, code.source_token);
991 try out.write("</pre>");991 try out.write("</pre>");
992 const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name);992 const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name);
993 const tmp_source_file_name = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_plus_ext });993 const tmp_source_file_name = try os.path.join(
994 allocator,
995 [][]const u8{ tmp_dir_name, name_plus_ext },
996 );
994 try io.writeFile(tmp_source_file_name, trimmed_raw_source);997 try io.writeFile(tmp_source_file_name, trimmed_raw_source);
995998
996 switch (code.id) {999 switch (code.id) {
997 Code.Id.Exe => |expected_outcome| {1000 Code.Id.Exe => |expected_outcome| {
998 const name_plus_bin_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, exe_ext);1001 const name_plus_bin_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, exe_ext);
999 const tmp_bin_file_name = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_plus_bin_ext });1002 const tmp_bin_file_name = try os.path.join(
1003 allocator,
1004 [][]const u8{ tmp_dir_name, name_plus_bin_ext },
1005 );
1000 var build_args = std.ArrayList([]const u8).init(allocator);1006 var build_args = std.ArrayList([]const u8).init(allocator);
1001 defer build_args.deinit();1007 defer build_args.deinit();
1002 try build_args.appendSlice([][]const u8{1008 try build_args.appendSlice([][]const u8{
...@@ -1024,7 +1030,10 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1024,7 +1030,10 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1024 }1030 }
1025 for (code.link_objects) |link_object| {1031 for (code.link_objects) |link_object| {
1026 const name_with_ext = try std.fmt.allocPrint(allocator, "{}{}", link_object, obj_ext);1032 const name_with_ext = try std.fmt.allocPrint(allocator, "{}{}", link_object, obj_ext);
1027 const full_path_object = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_with_ext });1033 const full_path_object = try os.path.join(
1034 allocator,
1035 [][]const u8{ tmp_dir_name, name_with_ext },
1036 );
1028 try build_args.append("--object");1037 try build_args.append("--object");
1029 try build_args.append(full_path_object);1038 try build_args.append(full_path_object);
1030 try out.print(" --object {}", name_with_ext);1039 try out.print(" --object {}", name_with_ext);
...@@ -1216,12 +1225,18 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1216,12 +1225,18 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1216 },1225 },
1217 Code.Id.Obj => |maybe_error_match| {1226 Code.Id.Obj => |maybe_error_match| {
1218 const name_plus_obj_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, obj_ext);1227 const name_plus_obj_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, obj_ext);
1219 const tmp_obj_file_name = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_plus_obj_ext });1228 const tmp_obj_file_name = try os.path.join(
1229 allocator,
1230 [][]const u8{ tmp_dir_name, name_plus_obj_ext },
1231 );
1220 var build_args = std.ArrayList([]const u8).init(allocator);1232 var build_args = std.ArrayList([]const u8).init(allocator);
1221 defer build_args.deinit();1233 defer build_args.deinit();
12221234
1223 const name_plus_h_ext = try std.fmt.allocPrint(allocator, "{}.h", code.name);1235 const name_plus_h_ext = try std.fmt.allocPrint(allocator, "{}.h", code.name);
1224 const output_h_file_name = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_plus_h_ext });1236 const output_h_file_name = try os.path.join(
1237 allocator,
1238 [][]const u8{ tmp_dir_name, name_plus_h_ext },
1239 );
12251240
1226 try build_args.appendSlice([][]const u8{1241 try build_args.appendSlice([][]const u8{
1227 zig_exe,1242 zig_exe,
src-self-hosted/libc_installation.zig+12-3
...@@ -254,7 +254,10 @@ pub const LibCInstallation = struct {...@@ -254,7 +254,10 @@ pub const LibCInstallation = struct {
254 const stream = &std.io.BufferOutStream.init(&result_buf).stream;254 const stream = &std.io.BufferOutStream.init(&result_buf).stream;
255 try stream.print("{}\\Include\\{}\\ucrt", search.path, search.version);255 try stream.print("{}\\Include\\{}\\ucrt", search.path, search.version);
256256
257 const stdlib_path = try std.os.path.join(loop.allocator, [][]const u8{ result_buf.toSliceConst(), "stdlib.h" });257 const stdlib_path = try std.os.path.join(
258 loop.allocator,
259 [][]const u8{ result_buf.toSliceConst(), "stdlib.h" },
260 );
258 defer loop.allocator.free(stdlib_path);261 defer loop.allocator.free(stdlib_path);
259262
260 if (try fileExists(stdlib_path)) {263 if (try fileExists(stdlib_path)) {
...@@ -283,7 +286,10 @@ pub const LibCInstallation = struct {...@@ -283,7 +286,10 @@ pub const LibCInstallation = struct {
283 builtin.Arch.aarch64v8 => try stream.write("arm"),286 builtin.Arch.aarch64v8 => try stream.write("arm"),
284 else => return error.UnsupportedArchitecture,287 else => return error.UnsupportedArchitecture,
285 }288 }
286 const ucrt_lib_path = try std.os.path.join(loop.allocator, [][]const u8{ result_buf.toSliceConst(), "ucrt.lib" });289 const ucrt_lib_path = try std.os.path.join(
290 loop.allocator,
291 [][]const u8{ result_buf.toSliceConst(), "ucrt.lib" },
292 );
287 defer loop.allocator.free(ucrt_lib_path);293 defer loop.allocator.free(ucrt_lib_path);
288 if (try fileExists(ucrt_lib_path)) {294 if (try fileExists(ucrt_lib_path)) {
289 self.lib_dir = result_buf.toOwnedSlice();295 self.lib_dir = result_buf.toOwnedSlice();
...@@ -358,7 +364,10 @@ pub const LibCInstallation = struct {...@@ -358,7 +364,10 @@ pub const LibCInstallation = struct {
358 builtin.Arch.aarch64v8 => try stream.write("arm\\"),364 builtin.Arch.aarch64v8 => try stream.write("arm\\"),
359 else => return error.UnsupportedArchitecture,365 else => return error.UnsupportedArchitecture,
360 }366 }
361 const kernel32_path = try std.os.path.join(loop.allocator, [][]const u8{ result_buf.toSliceConst(), "kernel32.lib" });367 const kernel32_path = try std.os.path.join(
368 loop.allocator,
369 [][]const u8{ result_buf.toSliceConst(), "kernel32.lib" },
370 );
362 defer loop.allocator.free(kernel32_path);371 defer loop.allocator.free(kernel32_path);
363 if (try fileExists(kernel32_path)) {372 if (try fileExists(kernel32_path)) {
364 self.kernel32_lib_dir = result_buf.toOwnedSlice();373 self.kernel32_lib_dir = result_buf.toOwnedSlice();
std/build.zig+59-20
...@@ -145,8 +145,8 @@ pub const Builder = struct {...@@ -145,8 +145,8 @@ pub const Builder = struct {
145145
146 pub fn setInstallPrefix(self: *Builder, maybe_prefix: ?[]const u8) void {146 pub fn setInstallPrefix(self: *Builder, maybe_prefix: ?[]const u8) void {
147 self.prefix = maybe_prefix orelse "/usr/local"; // TODO better default147 self.prefix = maybe_prefix orelse "/usr/local"; // TODO better default
148 self.lib_dir = os.path.join(self.allocator, [][]const u8{self.prefix, "lib"}) catch unreachable;148 self.lib_dir = os.path.join(self.allocator, [][]const u8{ self.prefix, "lib" }) catch unreachable;
149 self.exe_dir = os.path.join(self.allocator, [][]const u8{self.prefix, "bin"}) catch unreachable;149 self.exe_dir = os.path.join(self.allocator, [][]const u8{ self.prefix, "bin" }) catch unreachable;
150 }150 }
151151
152 pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {152 pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
...@@ -618,7 +618,10 @@ pub const Builder = struct {...@@ -618,7 +618,10 @@ pub const Builder = struct {
618618
619 ///::dest_rel_path is relative to prefix path or it can be an absolute path619 ///::dest_rel_path is relative to prefix path or it can be an absolute path
620 pub fn addInstallFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep {620 pub fn addInstallFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep {
621 const full_dest_path = os.path.resolve(self.allocator, self.prefix, dest_rel_path) catch unreachable;621 const full_dest_path = os.path.resolve(
622 self.allocator,
623 [][]const u8{ self.prefix, dest_rel_path },
624 ) catch unreachable;
622 self.pushInstalledFile(full_dest_path);625 self.pushInstalledFile(full_dest_path);
623626
624 const install_step = self.allocator.create(InstallFileStep) catch unreachable;627 const install_step = self.allocator.create(InstallFileStep) catch unreachable;
...@@ -653,7 +656,7 @@ pub const Builder = struct {...@@ -653,7 +656,7 @@ pub const Builder = struct {
653 }656 }
654657
655 fn pathFromRoot(self: *Builder, rel_path: []const u8) []u8 {658 fn pathFromRoot(self: *Builder, rel_path: []const u8) []u8 {
656 return os.path.resolve(self.allocator, self.build_root, rel_path) catch unreachable;659 return os.path.resolve(self.allocator, [][]const u8{ self.build_root, rel_path }) catch unreachable;
657 }660 }
658661
659 pub fn fmt(self: *Builder, comptime format: []const u8, args: ...) []u8 {662 pub fn fmt(self: *Builder, comptime format: []const u8, args: ...) []u8 {
...@@ -676,7 +679,7 @@ pub const Builder = struct {...@@ -676,7 +679,7 @@ pub const Builder = struct {
676 if (os.path.isAbsolute(name)) {679 if (os.path.isAbsolute(name)) {
677 return name;680 return name;
678 }681 }
679 const full_path = try os.path.join(self.allocator, [][]const u8{search_prefix, "bin", self.fmt("{}{}", name, exe_extension)});682 const full_path = try os.path.join(self.allocator, [][]const u8{ search_prefix, "bin", self.fmt("{}{}", name, exe_extension) });
680 if (os.path.real(self.allocator, full_path)) |real_path| {683 if (os.path.real(self.allocator, full_path)) |real_path| {
681 return real_path;684 return real_path;
682 } else |_| {685 } else |_| {
...@@ -691,7 +694,7 @@ pub const Builder = struct {...@@ -691,7 +694,7 @@ pub const Builder = struct {
691 }694 }
692 var it = mem.tokenize(PATH, []u8{os.path.delimiter});695 var it = mem.tokenize(PATH, []u8{os.path.delimiter});
693 while (it.next()) |path| {696 while (it.next()) |path| {
694 const full_path = try os.path.join(self.allocator, [][]const u8{path, self.fmt("{}{}", name, exe_extension)});697 const full_path = try os.path.join(self.allocator, [][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
695 if (os.path.real(self.allocator, full_path)) |real_path| {698 if (os.path.real(self.allocator, full_path)) |real_path| {
696 return real_path;699 return real_path;
697 } else |_| {700 } else |_| {
...@@ -705,7 +708,7 @@ pub const Builder = struct {...@@ -705,7 +708,7 @@ pub const Builder = struct {
705 return name;708 return name;
706 }709 }
707 for (paths) |path| {710 for (paths) |path| {
708 const full_path = try os.path.join(self.allocator, [][]const u8{path, self.fmt("{}{}", name, exe_extension)});711 const full_path = try os.path.join(self.allocator, [][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
709 if (os.path.real(self.allocator, full_path)) |real_path| {712 if (os.path.real(self.allocator, full_path)) |real_path| {
710 return real_path;713 return real_path;
711 } else |_| {714 } else |_| {
...@@ -1113,7 +1116,10 @@ pub const LibExeObjStep = struct {...@@ -1113,7 +1116,10 @@ pub const LibExeObjStep = struct {
1113 }1116 }
11141117
1115 pub fn getOutputPath(self: *LibExeObjStep) []const u8 {1118 pub fn getOutputPath(self: *LibExeObjStep) []const u8 {
1116 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;1119 return if (self.output_path) |output_path| output_path else os.path.join(
1120 self.builder.allocator,
1121 [][]const u8{ self.builder.cache_root, self.out_filename },
1122 ) catch unreachable;
1117 }1123 }
11181124
1119 pub fn setOutputHPath(self: *LibExeObjStep, file_path: []const u8) void {1125 pub fn setOutputHPath(self: *LibExeObjStep, file_path: []const u8) void {
...@@ -1126,7 +1132,10 @@ pub const LibExeObjStep = struct {...@@ -1126,7 +1132,10 @@ pub const LibExeObjStep = struct {
1126 }1132 }
11271133
1128 pub fn getOutputHPath(self: *LibExeObjStep) []const u8 {1134 pub fn getOutputHPath(self: *LibExeObjStep) []const u8 {
1129 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;1135 return if (self.output_h_path) |output_h_path| output_h_path else os.path.join(
1136 self.builder.allocator,
1137 [][]const u8{ self.builder.cache_root, self.out_h_filename },
1138 ) catch unreachable;
1130 }1139 }
11311140
1132 pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void {1141 pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void {
...@@ -1226,7 +1235,10 @@ pub const LibExeObjStep = struct {...@@ -1226,7 +1235,10 @@ pub const LibExeObjStep = struct {
1226 }1235 }
12271236
1228 if (self.build_options_contents.len() > 0) {1237 if (self.build_options_contents.len() > 0) {
1229 const build_options_file = try os.path.join(builder.allocator, [][]const u8{builder.cache_root, builder.fmt("{}_build_options.zig", self.name)});1238 const build_options_file = try os.path.join(
1239 builder.allocator,
1240 [][]const u8{ builder.cache_root, builder.fmt("{}_build_options.zig", self.name) },
1241 );
1230 try std.io.writeFile(build_options_file, self.build_options_contents.toSliceConst());1242 try std.io.writeFile(build_options_file, self.build_options_contents.toSliceConst());
1231 try zig_args.append("--pkg-begin");1243 try zig_args.append("--pkg-begin");
1232 try zig_args.append("build_options");1244 try zig_args.append("build_options");
...@@ -1476,7 +1488,10 @@ pub const LibExeObjStep = struct {...@@ -1476,7 +1488,10 @@ pub const LibExeObjStep = struct {
1476 cc_args.append("-c") catch unreachable;1488 cc_args.append("-c") catch unreachable;
1477 cc_args.append(abs_source_file) catch unreachable;1489 cc_args.append(abs_source_file) catch unreachable;
14781490
1479 const cache_o_src = os.path.join(builder.allocator, [][]const u8{builder.cache_root, source_file}) catch unreachable;1491 const cache_o_src = os.path.join(
1492 builder.allocator,
1493 [][]const u8{ builder.cache_root, source_file },
1494 ) catch unreachable;
1480 if (os.path.dirname(cache_o_src)) |cache_o_dir| {1495 if (os.path.dirname(cache_o_src)) |cache_o_dir| {
1481 try builder.makePath(cache_o_dir);1496 try builder.makePath(cache_o_dir);
1482 }1497 }
...@@ -1528,7 +1543,10 @@ pub const LibExeObjStep = struct {...@@ -1528,7 +1543,10 @@ pub const LibExeObjStep = struct {
1528 cc_args.append("-current_version") catch unreachable;1543 cc_args.append("-current_version") catch unreachable;
1529 cc_args.append(builder.fmt("{}.{}.{}", self.version.major, self.version.minor, self.version.patch)) catch unreachable;1544 cc_args.append(builder.fmt("{}.{}.{}", self.version.major, self.version.minor, self.version.patch)) catch unreachable;
15301545
1531 const install_name = builder.pathFromRoot(os.path.join(builder.allocator, [][]const u8{builder.cache_root, self.major_only_filename}) catch unreachable);1546 const install_name = builder.pathFromRoot(os.path.join(
1547 builder.allocator,
1548 [][]const u8{ builder.cache_root, self.major_only_filename },
1549 ) catch unreachable);
1532 cc_args.append("-install_name") catch unreachable;1550 cc_args.append("-install_name") catch unreachable;
1533 cc_args.append(install_name) catch unreachable;1551 cc_args.append(install_name) catch unreachable;
1534 } else {1552 } else {
...@@ -1594,7 +1612,10 @@ pub const LibExeObjStep = struct {...@@ -1594,7 +1612,10 @@ pub const LibExeObjStep = struct {
1594 cc_args.append("-c") catch unreachable;1612 cc_args.append("-c") catch unreachable;
1595 cc_args.append(abs_source_file) catch unreachable;1613 cc_args.append(abs_source_file) catch unreachable;
15961614
1597 const cache_o_src = os.path.join(builder.allocator, [][]const u8{builder.cache_root, source_file}) catch unreachable;1615 const cache_o_src = os.path.join(
1616 builder.allocator,
1617 [][]const u8{ builder.cache_root, source_file },
1618 ) catch unreachable;
1598 if (os.path.dirname(cache_o_src)) |cache_o_dir| {1619 if (os.path.dirname(cache_o_src)) |cache_o_dir| {
1599 try builder.makePath(cache_o_dir);1620 try builder.makePath(cache_o_dir);
1600 }1621 }
...@@ -1757,7 +1778,10 @@ pub const TestStep = struct {...@@ -1757,7 +1778,10 @@ pub const TestStep = struct {
1757 return output_path;1778 return output_path;
1758 } else {1779 } else {
1759 const basename = self.builder.fmt("test{}", self.target.exeFileExt());1780 const basename = self.builder.fmt("test{}", self.target.exeFileExt());
1760 return os.path.join(self.builder.allocator, [][]const u8{self.builder.cache_root, basename}) catch unreachable;1781 return os.path.join(
1782 self.builder.allocator,
1783 [][]const u8{ self.builder.cache_root, basename },
1784 ) catch unreachable;
1761 }1785 }
1762 }1786 }
17631787
...@@ -1979,13 +2003,22 @@ const InstallArtifactStep = struct {...@@ -1979,13 +2003,22 @@ const InstallArtifactStep = struct {
1979 .builder = builder,2003 .builder = builder,
1980 .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),2004 .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),
1981 .artifact = artifact,2005 .artifact = artifact,
1982 .dest_file = os.path.join(builder.allocator, dest_dir, artifact.out_filename) catch unreachable,2006 .dest_file = os.path.join(
1983 }) catch unreachable;2007 builder.allocator,
2008 [][]const u8{ dest_dir, artifact.out_filename },
2009 ) catch unreachable,
2010 };
1984 self.step.dependOn(&artifact.step);2011 self.step.dependOn(&artifact.step);
1985 builder.pushInstalledFile(self.dest_file);2012 builder.pushInstalledFile(self.dest_file);
1986 if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {2013 if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {
1987 builder.pushInstalledFile(os.path.join(builder.allocator, [][]const u8{builder.lib_dir, artifact.major_only_filename}) catch unreachable);2014 builder.pushInstalledFile(os.path.join(
1988 builder.pushInstalledFile(os.path.join(builder.allocator, [][]const u8{builder.lib_dir, artifact.name_only_filename}) catch unreachable);2015 builder.allocator,
2016 [][]const u8{ builder.lib_dir, artifact.major_only_filename },
2017 ) catch unreachable);
2018 builder.pushInstalledFile(os.path.join(
2019 builder.allocator,
2020 [][]const u8{ builder.lib_dir, artifact.name_only_filename },
2021 ) catch unreachable);
1989 }2022 }
1990 return self;2023 return self;
1991 }2024 }
...@@ -2141,13 +2174,19 @@ fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_maj...@@ -2141,13 +2174,19 @@ fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_maj
2141 const out_dir = os.path.dirname(output_path) orelse ".";2174 const out_dir = os.path.dirname(output_path) orelse ".";
2142 const out_basename = os.path.basename(output_path);2175 const out_basename = os.path.basename(output_path);
2143 // sym link for libfoo.so.1 to libfoo.so.1.2.32176 // sym link for libfoo.so.1 to libfoo.so.1.2.3
2144 const major_only_path = os.path.join(allocator, [][]const u8{out_dir, filename_major_only}) catch unreachable;2177 const major_only_path = os.path.join(
2178 allocator,
2179 [][]const u8{ out_dir, filename_major_only },
2180 ) catch unreachable;
2145 os.atomicSymLink(allocator, out_basename, major_only_path) catch |err| {2181 os.atomicSymLink(allocator, out_basename, major_only_path) catch |err| {
2146 warn("Unable to symlink {} -> {}\n", major_only_path, out_basename);2182 warn("Unable to symlink {} -> {}\n", major_only_path, out_basename);
2147 return err;2183 return err;
2148 };2184 };
2149 // sym link for libfoo.so to libfoo.so.12185 // sym link for libfoo.so to libfoo.so.1
2150 const name_only_path = os.path.join(allocator, [][]const u8{out_dir, filename_name_only}) catch unreachable;2186 const name_only_path = os.path.join(
2187 allocator,
2188 [][]const u8{ out_dir, filename_name_only },
2189 ) catch unreachable;
2151 os.atomicSymLink(allocator, filename_major_only, name_only_path) catch |err| {2190 os.atomicSymLink(allocator, filename_major_only, name_only_path) catch |err| {
2152 warn("Unable to symlink {} -> {}\n", name_only_path, filename_major_only);2191 warn("Unable to symlink {} -> {}\n", name_only_path, filename_major_only);
2153 return err;2192 return err;
std/debug/index.zig+2-2
...@@ -774,7 +774,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {...@@ -774,7 +774,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
774 const len = try di.coff.getPdbPath(path_buf[0..]);774 const len = try di.coff.getPdbPath(path_buf[0..]);
775 const raw_path = path_buf[0..len];775 const raw_path = path_buf[0..len];
776776
777 const path = try os.path.resolve(allocator, raw_path);777 const path = try os.path.resolve(allocator, [][]const u8{raw_path});
778778
779 try di.pdb.openFile(di.coff, path);779 try di.pdb.openFile(di.coff, path);
780780
...@@ -1352,7 +1352,7 @@ const LineNumberProgram = struct {...@@ -1352,7 +1352,7 @@ const LineNumberProgram = struct {
1352 return error.InvalidDebugInfo;1352 return error.InvalidDebugInfo;
1353 } else1353 } else
1354 self.include_dirs[file_entry.dir_index];1354 self.include_dirs[file_entry.dir_index];
1355 const file_name = try os.path.join(self.file_entries.allocator, [][]const u8{dir_name, file_entry.file_name});1355 const file_name = try os.path.join(self.file_entries.allocator, [][]const u8{ dir_name, file_entry.file_name });
1356 errdefer self.file_entries.allocator.free(file_name);1356 errdefer self.file_entries.allocator.free(file_name);
1357 return LineInfo{1357 return LineInfo{
1358 .line = if (self.prev_line >= 0) @intCast(usize, self.prev_line) else 0,1358 .line = if (self.prev_line >= 0) @intCast(usize, self.prev_line) else 0,
std/event/fs.zig+2-2
...@@ -871,7 +871,7 @@ pub fn Watch(comptime V: type) type {...@@ -871,7 +871,7 @@ pub fn Watch(comptime V: type) type {
871 }871 }
872872
873 async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {873 async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {
874 const resolved_path = try os.path.resolve(self.channel.loop.allocator, file_path);874 const resolved_path = try os.path.resolve(self.channel.loop.allocator, [][]const u8{file_path});
875 var resolved_path_consumed = false;875 var resolved_path_consumed = false;
876 defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);876 defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);
877877
...@@ -1336,7 +1336,7 @@ async fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void {...@@ -1336,7 +1336,7 @@ async fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void {
1336}1336}
13371337
1338async fn testFsWatch(loop: *Loop) !void {1338async fn testFsWatch(loop: *Loop) !void {
1339 const file_path = try os.path.join(loop.allocator, [][]const u8{test_tmp_dir, "file.txt"});1339 const file_path = try os.path.join(loop.allocator, [][]const u8{ test_tmp_dir, "file.txt" });
1340 defer loop.allocator.free(file_path);1340 defer loop.allocator.free(file_path);
13411341
1342 const contents =1342 const contents =
std/mem.zig+22-27
...@@ -882,42 +882,37 @@ pub const SplitIterator = struct {...@@ -882,42 +882,37 @@ pub const SplitIterator = struct {
882 }882 }
883};883};
884884
885/// Naively combines a series of strings with a separator.885/// Naively combines a series of slices with a separator.
886/// Allocates memory for the result, which must be freed by the caller.886/// Allocates memory for the result, which must be freed by the caller.
887pub fn join(allocator: *Allocator, sep: u8, strings: ...) ![]u8 {887pub fn join(allocator: *Allocator, separator: []const u8, slices: []const []const u8) ![]u8 {
888 comptime assert(strings.len >= 1);888 if (slices.len == 0) return (([*]u8)(undefined))[0..0];
889 var total_strings_len: usize = strings.len; // 1 sep per string889
890 {890 const total_len = blk: {
891 comptime var string_i = 0;891 var sum: usize = separator.len * (slices.len - 1);
892 inline while (string_i < strings.len) : (string_i += 1) {892 for (slices) |slice|
893 const arg = ([]const u8)(strings[string_i]);893 sum += slice.len;
894 total_strings_len += arg.len;894 break :blk sum;
895 }895 };
896 }
897896
898 const buf = try allocator.alloc(u8, total_strings_len);897 const buf = try allocator.alloc(u8, total_len);
899 errdefer allocator.free(buf);898 errdefer allocator.free(buf);
900899
901 var buf_index: usize = 0;900 copy(u8, buf, slices[0]);
902 comptime var string_i = 0;901 var buf_index: usize = slices[0].len;
903 inline while (true) {902 for (slices[1..]) |slice| {
904 const arg = ([]const u8)(strings[string_i]);903 copy(u8, buf[buf_index..], separator);
905 string_i += 1;904 buf_index += separator.len;
906 copy(u8, buf[buf_index..], arg);905 copy(u8, buf[buf_index..], slice);
907 buf_index += arg.len;906 buf_index += slice.len;
908 if (string_i >= strings.len) break;
909 if (buf[buf_index - 1] != sep) {
910 buf[buf_index] = sep;
911 buf_index += 1;
912 }
913 }907 }
914908
915 return allocator.shrink(u8, buf, buf_index);909 // No need for shrink since buf is exactly the correct size.
910 return buf;
916}911}
917912
918test "mem.join" {913test "mem.join" {
919 assert(eql(u8, try join(debug.global_allocator, ',', "a", "b", "c"), "a,b,c"));914 assert(eql(u8, try join(debug.global_allocator, ",", [][]const u8{ "a", "b", "c" }), "a,b,c"));
920 assert(eql(u8, try join(debug.global_allocator, ',', "a"), "a"));915 assert(eql(u8, try join(debug.global_allocator, ",", [][]const u8{"a"}), "a"));
921}916}
922917
923test "testStringEquality" {918test "testStringEquality" {
std/os/child_process.zig+1-1
...@@ -574,7 +574,7 @@ pub const ChildProcess = struct {...@@ -574,7 +574,7 @@ pub const ChildProcess = struct {
574 // to match posix semantics574 // to match posix semantics
575 const app_name = x: {575 const app_name = x: {
576 if (self.cwd) |cwd| {576 if (self.cwd) |cwd| {
577 const resolved = try os.path.resolve(self.allocator, cwd, self.argv[0]);577 const resolved = try os.path.resolve(self.allocator, [][]const u8{ cwd, self.argv[0] });
578 defer self.allocator.free(resolved);578 defer self.allocator.free(resolved);
579 break :x try cstr.addNullByte(self.allocator, resolved);579 break :x try cstr.addNullByte(self.allocator, resolved);
580 } else {580 } else {
std/os/get_app_data_dir.zig+3-4
...@@ -30,7 +30,7 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD...@@ -30,7 +30,7 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD
30 error.OutOfMemory => return error.OutOfMemory,30 error.OutOfMemory => return error.OutOfMemory,
31 };31 };
32 defer allocator.free(global_dir);32 defer allocator.free(global_dir);
33 return os.path.join(allocator, [][]const u8{global_dir, appname});33 return os.path.join(allocator, [][]const u8{ global_dir, appname });
34 },34 },
35 os.windows.E_OUTOFMEMORY => return error.OutOfMemory,35 os.windows.E_OUTOFMEMORY => return error.OutOfMemory,
36 else => return error.AppDataDirUnavailable,36 else => return error.AppDataDirUnavailable,
...@@ -41,14 +41,14 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD...@@ -41,14 +41,14 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD
41 // TODO look in /etc/passwd41 // TODO look in /etc/passwd
42 return error.AppDataDirUnavailable;42 return error.AppDataDirUnavailable;
43 };43 };
44 return os.path.join(allocator, [][]const u8{home_dir, "Library", "Application Support", appname});44 return os.path.join(allocator, [][]const u8{ home_dir, "Library", "Application Support", appname });
45 },45 },
46 builtin.Os.linux, builtin.Os.freebsd => {46 builtin.Os.linux, builtin.Os.freebsd => {
47 const home_dir = os.getEnvPosix("HOME") orelse {47 const home_dir = os.getEnvPosix("HOME") orelse {
48 // TODO look in /etc/passwd48 // TODO look in /etc/passwd
49 return error.AppDataDirUnavailable;49 return error.AppDataDirUnavailable;
50 };50 };
51 return os.path.join(allocator, [][]const u8{home_dir, ".local", "share", appname});51 return os.path.join(allocator, [][]const u8{ home_dir, ".local", "share", appname });
52 },52 },
53 else => @compileError("Unsupported OS"),53 else => @compileError("Unsupported OS"),
54 }54 }
...@@ -67,4 +67,3 @@ test "std.os.getAppDataDir" {...@@ -67,4 +67,3 @@ test "std.os.getAppDataDir" {
67 // We can't actually validate the result67 // We can't actually validate the result
68 _ = getAppDataDir(allocator, "zig") catch return;68 _ = getAppDataDir(allocator, "zig") catch return;
69}69}
70
std/os/index.zig+3-4
...@@ -1284,7 +1284,7 @@ pub fn makeDirPosix(dir_path: []const u8) !void {...@@ -1284,7 +1284,7 @@ pub fn makeDirPosix(dir_path: []const u8) !void {
1284/// already exists and is a directory.1284/// already exists and is a directory.
1285/// TODO determine if we can remove the allocator requirement from this function1285/// TODO determine if we can remove the allocator requirement from this function
1286pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {1286pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {
1287 const resolved_path = try path.resolve(allocator, full_path);1287 const resolved_path = try path.resolve(allocator, [][]const u8{full_path});
1288 defer allocator.free(resolved_path);1288 defer allocator.free(resolved_path);
12891289
1290 var end_index: usize = resolved_path.len;1290 var end_index: usize = resolved_path.len;
...@@ -2304,18 +2304,17 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {...@@ -2304,18 +2304,17 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
2304 switch (builtin.os) {2304 switch (builtin.os) {
2305 Os.linux => return readLink(out_buffer, "/proc/self/exe"),2305 Os.linux => return readLink(out_buffer, "/proc/self/exe"),
2306 Os.freebsd => {2306 Os.freebsd => {
2307 var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC, posix.KERN_PROC_PATHNAME, -1};2307 var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC, posix.KERN_PROC_PATHNAME, -1 };
2308 var out_len: usize = out_buffer.len;2308 var out_len: usize = out_buffer.len;
2309 const err = posix.getErrno(posix.sysctl(&mib, 4, out_buffer, &out_len, null, 0));2309 const err = posix.getErrno(posix.sysctl(&mib, 4, out_buffer, &out_len, null, 0));
23102310
2311 if (err == 0 ) return mem.toSlice(u8, out_buffer);2311 if (err == 0) return mem.toSlice(u8, out_buffer);
23122312
2313 return switch (err) {2313 return switch (err) {
2314 posix.EFAULT => error.BadAdress,2314 posix.EFAULT => error.BadAdress,
2315 posix.EPERM => error.PermissionDenied,2315 posix.EPERM => error.PermissionDenied,
2316 else => unexpectedErrorPosix(err),2316 else => unexpectedErrorPosix(err),
2317 };2317 };
2318
2319 },2318 },
2320 Os.windows => {2319 Os.windows => {
2321 var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;2320 var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
std/os/path.zig+95-59
...@@ -33,63 +33,103 @@ pub fn isSep(byte: u8) bool {...@@ -33,63 +33,103 @@ pub fn isSep(byte: u8) bool {
33 }33 }
34}34}
3535
36/// Naively combines a series of paths with the native path seperator.36/// This is different from mem.join in that the separator will not be repeated if
37/// Allocates memory for the result, which must be freed by the caller.37/// it is found at the end or beginning of a pair of consecutive paths.
3838fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u8 {
39pub fn join(allocator: *Allocator, paths: []const []const u8) ![]u8 {39 if (paths.len == 0) return (([*]u8)(undefined))[0..0];
40 assert(paths.len >= 1);40
41 var total_paths_len: usize = paths.len; // 1 sep per path41 const total_len = blk: {
42 {42 var sum: usize = paths[0].len;
43 var path_i: usize = 0;43 var i: usize = 1;
44 while (path_i < paths.len) : (path_i += 1) {44 while (i < paths.len) : (i += 1) {
45 const arg = ([]const u8)(paths[path_i]);45 const prev_path = paths[i - 1];
46 total_paths_len += arg.len;46 const this_path = paths[i];
47 const prev_sep = (prev_path.len != 0 and prev_path[prev_path.len - 1] == separator);
48 const this_sep = (this_path.len != 0 and this_path[0] == separator);
49 sum += @boolToInt(!prev_sep and !this_sep);
50 sum += if (prev_sep and this_sep) this_path.len - 1 else this_path.len;
47 }51 }
48 }52 break :blk sum;
53 };
4954
50 const buf = try allocator.alloc(u8, total_paths_len);55 const buf = try allocator.alloc(u8, total_len);
51 errdefer allocator.free(buf);56 errdefer allocator.free(buf);
5257
53 var buf_index: usize = 0;58 mem.copy(u8, buf, paths[0]);
54 var path_i: usize = 0;59 var buf_index: usize = paths[0].len;
55 while (true) {60 var i: usize = 1;
56 const arg = ([]const u8)(paths[path_i]);61 while (i < paths.len) : (i += 1) {
57 path_i += 1;62 const prev_path = paths[i - 1];
58 mem.copy(u8, buf[buf_index..], arg);63 const this_path = paths[i];
59 buf_index += arg.len;64 const prev_sep = (prev_path.len != 0 and prev_path[prev_path.len - 1] == separator);
60 if (path_i >= paths.len) break;65 const this_sep = (this_path.len != 0 and this_path[0] == separator);
61 if (buf_index > 0 and buf[buf_index - 1] != sep) {66 if (!prev_sep and !this_sep) {
62 buf[buf_index] = sep;67 buf[buf_index] = separator;
63 buf_index += 1;68 buf_index += 1;
64 }69 }
70 const adjusted_path = if (prev_sep and this_sep) this_path[1..] else this_path;
71 mem.copy(u8, buf[buf_index..], adjusted_path);
72 buf_index += adjusted_path.len;
65 }73 }
6674
67 return allocator.shrink(u8, buf, buf_index);75 // No need for shrink since buf is exactly the correct size.
76 return buf;
77}
78
79pub const join = if (is_windows) joinWindows else joinPosix;
80
81/// Naively combines a series of paths with the native path seperator.
82/// Allocates memory for the result, which must be freed by the caller.
83pub fn joinWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
84 return joinSep(allocator, sep_windows, paths);
85}
86
87/// Naively combines a series of paths with the native path seperator.
88/// Allocates memory for the result, which must be freed by the caller.
89pub fn joinPosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
90 return joinSep(allocator, sep_posix, paths);
91}
92
93fn testJoinWindows(paths: []const []const u8, expected: []const u8) void {
94 var buf: [1024]u8 = undefined;
95 const a = &std.heap.FixedBufferAllocator.init(&buf).allocator;
96 const actual = joinWindows(a, paths) catch @panic("fail");
97 debug.assertOrPanic(mem.eql(u8, actual, expected));
98}
99
100fn testJoinPosix(paths: []const []const u8, expected: []const u8) void {
101 var buf: [1024]u8 = undefined;
102 const a = &std.heap.FixedBufferAllocator.init(&buf).allocator;
103 const actual = joinPosix(a, paths) catch @panic("fail");
104 debug.assertOrPanic(mem.eql(u8, actual, expected));
68}105}
69106
70test "os.path.join" {107test "os.path.join" {
71 switch (builtin.os) {108 testJoinWindows([][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c");
72 Os.windows => {109 testJoinWindows([][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c");
73 assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"c:\\a\\b", "c"}), "c:\\a\\b\\c"));110 testJoinWindows([][]const u8{ "c:\\a\\b\\", "c" }, "c:\\a\\b\\c");
74 assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"c:\\a\\b\\", "c"}), "c:\\a\\b\\c"));111
75 assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"c:\\", "a", "b\\", "c"}), "c:\\a\\b\\c"));112 testJoinWindows([][]const u8{ "c:\\", "a", "b\\", "c" }, "c:\\a\\b\\c");
76 assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"c:\\a\\", "b\\", "c"}), "c:\\a\\b\\c"));113 testJoinWindows([][]const u8{ "c:\\a\\", "b\\", "c" }, "c:\\a\\b\\c");
77 assert(mem.eql(u8, try join( debug.global_allocator114
78 , [][]const u8{ "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std"115 testJoinWindows(
79 , "io.zig"})116 [][]const u8{ "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig" },
80 , "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig"));117 "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig",
81 },118 );
82 else => {119
83 assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"/a/b", "c"}), "/a/b/c"));120 testJoinPosix([][]const u8{ "/a/b", "c" }, "/a/b/c");
84 assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"/a/b/", "c"}), "/a/b/c"));121 testJoinPosix([][]const u8{ "/a/b/", "c" }, "/a/b/c");
85 assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"/", "a", "b/", "c"}), "/a/b/c"));122
86 assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"/a/", "b/", "c"}), "/a/b/c"));123 testJoinPosix([][]const u8{ "/", "a", "b/", "c" }, "/a/b/c");
87 assert(mem.eql(u8, try join( debug.global_allocator124 testJoinPosix([][]const u8{ "/a/", "b/", "c" }, "/a/b/c");
88 , [][]const u8{ "/home/andy/dev/zig/build/lib/zig/std"125
89 , "io.zig"})126 testJoinPosix(
90 , "/home/andy/dev/zig/build/lib/zig/std/io.zig"));127 [][]const u8{ "/home/andy/dev/zig/build/lib/zig/std", "io.zig" },
91 }128 "/home/andy/dev/zig/build/lib/zig/std/io.zig",
92 }129 );
130
131 testJoinPosix([][]const u8{ "a", "/c" }, "a/c");
132 testJoinPosix([][]const u8{ "a/", "/c" }, "a/c");
93}133}
94134
95pub fn isAbsolute(path: []const u8) bool {135pub fn isAbsolute(path: []const u8) bool {
...@@ -335,18 +375,8 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool {...@@ -335,18 +375,8 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool {
335 return true;375 return true;
336}376}
337377
338/// Converts the command line arguments into a slice and calls `resolveSlice`.
339pub fn resolve(allocator: *Allocator, args: ...) ![]u8 {
340 var paths: [args.len][]const u8 = undefined;
341 comptime var arg_i = 0;
342 inline while (arg_i < args.len) : (arg_i += 1) {
343 paths[arg_i] = args[arg_i];
344 }
345 return resolveSlice(allocator, paths);
346}
347
348/// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`.378/// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`.
349pub fn resolveSlice(allocator: *Allocator, paths: []const []const u8) ![]u8 {379pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 {
350 if (is_windows) {380 if (is_windows) {
351 return resolveWindows(allocator, paths);381 return resolveWindows(allocator, paths);
352 } else {382 } else {
...@@ -625,7 +655,10 @@ test "os.path.resolveWindows" {...@@ -625,7 +655,10 @@ test "os.path.resolveWindows" {
625 const parsed_cwd = windowsParsePath(cwd);655 const parsed_cwd = windowsParsePath(cwd);
626 {656 {
627 const result = testResolveWindows([][]const u8{ "/usr/local", "lib\\zig\\std\\array_list.zig" });657 const result = testResolveWindows([][]const u8{ "/usr/local", "lib\\zig\\std\\array_list.zig" });
628 const expected = try join(debug.global_allocator, [][]const u8{ parsed_cwd.disk_designator, "usr\\local\\lib\\zig\\std\\array_list.zig"});658 const expected = try join(debug.global_allocator, [][]const u8{
659 parsed_cwd.disk_designator,
660 "usr\\local\\lib\\zig\\std\\array_list.zig",
661 });
629 if (parsed_cwd.kind == WindowsPath.Kind.Drive) {662 if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
630 expected[0] = asciiUpper(parsed_cwd.disk_designator[0]);663 expected[0] = asciiUpper(parsed_cwd.disk_designator[0]);
631 }664 }
...@@ -633,7 +666,10 @@ test "os.path.resolveWindows" {...@@ -633,7 +666,10 @@ test "os.path.resolveWindows" {
633 }666 }
634 {667 {
635 const result = testResolveWindows([][]const u8{ "usr/local", "lib\\zig" });668 const result = testResolveWindows([][]const u8{ "usr/local", "lib\\zig" });
636 const expected = try join(debug.global_allocator, [][]const u8{ cwd, "usr\\local\\lib\\zig" });669 const expected = try join(debug.global_allocator, [][]const u8{
670 cwd,
671 "usr\\local\\lib\\zig",
672 });
637 if (parsed_cwd.kind == WindowsPath.Kind.Drive) {673 if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
638 expected[0] = asciiUpper(parsed_cwd.disk_designator[0]);674 expected[0] = asciiUpper(parsed_cwd.disk_designator[0]);
639 }675 }
test/cli.zig+1-1
...@@ -27,7 +27,7 @@ pub fn main() !void {...@@ -27,7 +27,7 @@ pub fn main() !void {
27 std.debug.warn("Expected second argument to be cache root directory path\n");27 std.debug.warn("Expected second argument to be cache root directory path\n");
28 return error.InvalidArgs;28 return error.InvalidArgs;
29 });29 });
30 const zig_exe = try os.path.resolve(a, zig_exe_rel);30 const zig_exe = try os.path.resolve(a, [][]const u8{zig_exe_rel});
3131
32 const dir_path = try os.path.join(a, [][]const u8{ cache_root, "clitest" });32 const dir_path = try os.path.join(a, [][]const u8{ cache_root, "clitest" });
33 const TestFn = fn ([]const u8, []const u8) anyerror!void;33 const TestFn = fn ([]const u8, []const u8) anyerror!void;
test/tests.zig+44-11
...@@ -439,7 +439,10 @@ pub const CompareOutputContext = struct {...@@ -439,7 +439,10 @@ pub const CompareOutputContext = struct {
439 pub fn addCase(self: *CompareOutputContext, case: TestCase) void {439 pub fn addCase(self: *CompareOutputContext, case: TestCase) void {
440 const b = self.b;440 const b = self.b;
441441
442 const root_src = os.path.join(b.allocator, [][]const u8{b.cache_root, case.sources.items[0].filename}) catch unreachable;442 const root_src = os.path.join(
443 b.allocator,
444 [][]const u8{ b.cache_root, case.sources.items[0].filename },
445 ) catch unreachable;
443446
444 switch (case.special) {447 switch (case.special) {
445 Special.Asm => {448 Special.Asm => {
...@@ -452,7 +455,10 @@ pub const CompareOutputContext = struct {...@@ -452,7 +455,10 @@ pub const CompareOutputContext = struct {
452 exe.addAssemblyFile(root_src);455 exe.addAssemblyFile(root_src);
453456
454 for (case.sources.toSliceConst()) |src_file| {457 for (case.sources.toSliceConst()) |src_file| {
455 const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable;458 const expanded_src_path = os.path.join(
459 b.allocator,
460 [][]const u8{ b.cache_root, src_file.filename },
461 ) catch unreachable;
456 const write_src = b.addWriteFile(expanded_src_path, src_file.source);462 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
457 exe.step.dependOn(&write_src.step);463 exe.step.dependOn(&write_src.step);
458 }464 }
...@@ -476,7 +482,10 @@ pub const CompareOutputContext = struct {...@@ -476,7 +482,10 @@ pub const CompareOutputContext = struct {
476 }482 }
477483
478 for (case.sources.toSliceConst()) |src_file| {484 for (case.sources.toSliceConst()) |src_file| {
479 const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable;485 const expanded_src_path = os.path.join(
486 b.allocator,
487 [][]const u8{ b.cache_root, src_file.filename },
488 ) catch unreachable;
480 const write_src = b.addWriteFile(expanded_src_path, src_file.source);489 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
481 exe.step.dependOn(&write_src.step);490 exe.step.dependOn(&write_src.step);
482 }491 }
...@@ -499,7 +508,10 @@ pub const CompareOutputContext = struct {...@@ -499,7 +508,10 @@ pub const CompareOutputContext = struct {
499 }508 }
500509
501 for (case.sources.toSliceConst()) |src_file| {510 for (case.sources.toSliceConst()) |src_file| {
502 const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable;511 const expanded_src_path = os.path.join(
512 b.allocator,
513 [][]const u8{ b.cache_root, src_file.filename },
514 ) catch unreachable;
503 const write_src = b.addWriteFile(expanded_src_path, src_file.source);515 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
504 exe.step.dependOn(&write_src.step);516 exe.step.dependOn(&write_src.step);
505 }517 }
...@@ -572,8 +584,14 @@ pub const CompileErrorContext = struct {...@@ -572,8 +584,14 @@ pub const CompileErrorContext = struct {
572 const self = @fieldParentPtr(CompileCmpOutputStep, "step", step);584 const self = @fieldParentPtr(CompileCmpOutputStep, "step", step);
573 const b = self.context.b;585 const b = self.context.b;
574586
575 const root_src = os.path.join(b.allocator, [][]const u8{b.cache_root, self.case.sources.items[0].filename}) catch unreachable;587 const root_src = os.path.join(
576 const obj_path = os.path.join(b.allocator, [][]const u8{b.cache_root, "test.o"}) catch unreachable;588 b.allocator,
589 [][]const u8{ b.cache_root, self.case.sources.items[0].filename },
590 ) catch unreachable;
591 const obj_path = os.path.join(
592 b.allocator,
593 [][]const u8{ b.cache_root, "test.o" },
594 ) catch unreachable;
577595
578 var zig_args = ArrayList([]const u8).init(b.allocator);596 var zig_args = ArrayList([]const u8).init(b.allocator);
579 zig_args.append(b.zig_exe) catch unreachable;597 zig_args.append(b.zig_exe) catch unreachable;
...@@ -721,7 +739,10 @@ pub const CompileErrorContext = struct {...@@ -721,7 +739,10 @@ pub const CompileErrorContext = struct {
721 self.step.dependOn(&compile_and_cmp_errors.step);739 self.step.dependOn(&compile_and_cmp_errors.step);
722740
723 for (case.sources.toSliceConst()) |src_file| {741 for (case.sources.toSliceConst()) |src_file| {
724 const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable;742 const expanded_src_path = os.path.join(
743 b.allocator,
744 [][]const u8{ b.cache_root, src_file.filename },
745 ) catch unreachable;
725 const write_src = b.addWriteFile(expanded_src_path, src_file.source);746 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
726 compile_and_cmp_errors.step.dependOn(&write_src.step);747 compile_and_cmp_errors.step.dependOn(&write_src.step);
727 }748 }
...@@ -852,7 +873,10 @@ pub const TranslateCContext = struct {...@@ -852,7 +873,10 @@ pub const TranslateCContext = struct {
852 const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step);873 const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step);
853 const b = self.context.b;874 const b = self.context.b;
854875
855 const root_src = os.path.join(b.allocator, [][]const u8{b.cache_root, self.case.sources.items[0].filename}) catch unreachable;876 const root_src = os.path.join(
877 b.allocator,
878 [][]const u8{ b.cache_root, self.case.sources.items[0].filename },
879 ) catch unreachable;
856880
857 var zig_args = ArrayList([]const u8).init(b.allocator);881 var zig_args = ArrayList([]const u8).init(b.allocator);
858 zig_args.append(b.zig_exe) catch unreachable;882 zig_args.append(b.zig_exe) catch unreachable;
...@@ -986,7 +1010,10 @@ pub const TranslateCContext = struct {...@@ -986,7 +1010,10 @@ pub const TranslateCContext = struct {
986 self.step.dependOn(&translate_c_and_cmp.step);1010 self.step.dependOn(&translate_c_and_cmp.step);
9871011
988 for (case.sources.toSliceConst()) |src_file| {1012 for (case.sources.toSliceConst()) |src_file| {
989 const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable;1013 const expanded_src_path = os.path.join(
1014 b.allocator,
1015 [][]const u8{ b.cache_root, src_file.filename },
1016 ) catch unreachable;
990 const write_src = b.addWriteFile(expanded_src_path, src_file.source);1017 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
991 translate_c_and_cmp.step.dependOn(&write_src.step);1018 translate_c_and_cmp.step.dependOn(&write_src.step);
992 }1019 }
...@@ -1101,7 +1128,10 @@ pub const GenHContext = struct {...@@ -1101,7 +1128,10 @@ pub const GenHContext = struct {
11011128
1102 pub fn addCase(self: *GenHContext, case: *const TestCase) void {1129 pub fn addCase(self: *GenHContext, case: *const TestCase) void {
1103 const b = self.b;1130 const b = self.b;
1104 const root_src = os.path.join(b.allocator, [][]const u8{b.cache_root, case.sources.items[0].filename}) catch unreachable;1131 const root_src = os.path.join(
1132 b.allocator,
1133 [][]const u8{ b.cache_root, case.sources.items[0].filename },
1134 ) catch unreachable;
11051135
1106 const mode = builtin.Mode.Debug;1136 const mode = builtin.Mode.Debug;
1107 const annotated_case_name = fmt.allocPrint(self.b.allocator, "gen-h {} ({})", case.name, @tagName(mode)) catch unreachable;1137 const annotated_case_name = fmt.allocPrint(self.b.allocator, "gen-h {} ({})", case.name, @tagName(mode)) catch unreachable;
...@@ -1113,7 +1143,10 @@ pub const GenHContext = struct {...@@ -1113,7 +1143,10 @@ pub const GenHContext = struct {
1113 obj.setBuildMode(mode);1143 obj.setBuildMode(mode);
11141144
1115 for (case.sources.toSliceConst()) |src_file| {1145 for (case.sources.toSliceConst()) |src_file| {
1116 const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable;1146 const expanded_src_path = os.path.join(
1147 b.allocator,
1148 [][]const u8{ b.cache_root, src_file.filename },
1149 ) catch unreachable;
1117 const write_src = b.addWriteFile(expanded_src_path, src_file.source);1150 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
1118 obj.step.dependOn(&write_src.step);1151 obj.step.dependOn(&write_src.step);
1119 }1152 }