authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-30 18:56:24-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-30 18:56:24-04:00
log363d9038c9b52878054505e905e133310b53086e
tree643a613f7502dab37a743049e1b28ee8cfe5b06a
parent38a04a267c11fdedc62102ab8e5989cafa3073ef

zig build: organize build artifacts

closes #328

16 files changed, 357 insertions(+), 146 deletions(-)

.gitignore+1-1
......@@ -1,6 +1,6 @@
1zig-cache/
12build/
23build-release/
34/.cproject
45/.project
56/.settings/
6/test_artifacts/
build.zig+8-11
......@@ -5,19 +5,16 @@ pub fn build(b: &Builder) {
55 const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter");
66 const test_step = b.step("test", "Run all the tests");
77
8 const cleanup = b.addRemoveDirTree("test_artifacts");
9 test_step.dependOn(&cleanup.step);
10
11 cleanup.step.dependOn(tests.addPkgTests(b, test_filter,
8 test_step.dependOn(tests.addPkgTests(b, test_filter,
129 "test/behavior.zig", "behavior", "Run the behavior tests"));
1310
14 cleanup.step.dependOn(tests.addPkgTests(b, test_filter,
11 test_step.dependOn(tests.addPkgTests(b, test_filter,
1512 "std/index.zig", "std", "Run the standard library tests"));
1613
17 cleanup.step.dependOn(tests.addCompareOutputTests(b, test_filter));
18 cleanup.step.dependOn(tests.addBuildExampleTests(b, test_filter));
19 cleanup.step.dependOn(tests.addCompileErrorTests(b, test_filter));
20 cleanup.step.dependOn(tests.addAssembleAndLinkTests(b, test_filter));
21 cleanup.step.dependOn(tests.addDebugSafetyTests(b, test_filter));
22 cleanup.step.dependOn(tests.addParseHTests(b, test_filter));
14 test_step.dependOn(tests.addCompareOutputTests(b, test_filter));
15 test_step.dependOn(tests.addBuildExampleTests(b, test_filter));
16 test_step.dependOn(tests.addCompileErrorTests(b, test_filter));
17 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter));
18 test_step.dependOn(tests.addDebugSafetyTests(b, test_filter));
19 test_step.dependOn(tests.addParseHTests(b, test_filter));
2320}
example/mix_o_files/build.zig+1-1
......@@ -12,7 +12,7 @@ pub fn build(b: &Builder) {
1212
1313 b.default_step.dependOn(&exe.step);
1414
15 const run_cmd = b.addCommand(b.out_dir, b.env_map, "./test", [][]const u8{});
15 const run_cmd = b.addCommand(b.cache_root, b.env_map, "./test", [][]const u8{});
1616 run_cmd.step.dependOn(&exe.step);
1717
1818 const test_step = b.step("test", "Test the program");
example/shared_library/build.zig+1-1
......@@ -12,7 +12,7 @@ pub fn build(b: &Builder) {
1212
1313 b.default_step.dependOn(&exe.step);
1414
15 const run_cmd = b.addCommand(b.out_dir, b.env_map, "./test", [][]const u8{});
15 const run_cmd = b.addCommand(b.cache_root, b.env_map, "./test", [][]const u8{});
1616 run_cmd.step.dependOn(&exe.step);
1717
1818 const test_step = b.step("test", "Test the program");
src/all_types.hpp+1
......@@ -1488,6 +1488,7 @@ struct CodeGen {
14881488 ZigList<TimeEvent> timing_events;
14891489
14901490 Buf *cache_dir;
1491 Buf *out_h_path;
14911492};
14921493
14931494enum VarLinkage {
src/codegen.cpp+29-19
......@@ -55,11 +55,12 @@ PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_pa
5555 return entry;
5656}
5757
58CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target) {
58CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type) {
5959 CodeGen *g = allocate<CodeGen>(1);
6060
6161 codegen_add_time_event(g, "Initialize");
6262
63 g->out_type = out_type;
6364 g->import_table.init(32);
6465 g->builtin_fn_table.init(32);
6566 g->primitive_type_table.init(32);
......@@ -74,7 +75,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target) {
7475 g->external_prototypes.init(8);
7576 g->is_release_build = false;
7677 g->is_test_build = false;
77 g->want_h_file = true;
78 g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib);
7879
7980 buf_resize(&g->global_asm, 0);
8081
......@@ -145,6 +146,10 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target) {
145146 return g;
146147}
147148
149void codegen_set_output_h_path(CodeGen *g, Buf *h_path) {
150 g->out_h_path = h_path;
151}
152
148153void codegen_set_clang_argv(CodeGen *g, const char **args, size_t len) {
149154 g->clang_argv = args;
150155 g->clang_argv_len = len;
......@@ -196,10 +201,6 @@ void codegen_set_strip(CodeGen *g, bool strip) {
196201 g->strip_debug_symbols = strip;
197202}
198203
199void codegen_set_out_type(CodeGen *g, OutType out_type) {
200 g->out_type = out_type;
201}
202
203204void codegen_set_out_name(CodeGen *g, Buf *out_name) {
204205 g->root_out_name = out_name;
205206}
......@@ -4808,15 +4809,6 @@ static void gen_global_asm(CodeGen *g) {
48084809 }
48094810}
48104811
4811void codegen_build(CodeGen *g) {
4812 assert(g->out_type != OutTypeUnknown);
4813 init(g);
4814
4815 gen_global_asm(g);
4816 gen_root_source(g);
4817 do_code_gen(g);
4818}
4819
48204812void codegen_add_object(CodeGen *g, Buf *object_path) {
48214813 g->link_objects.append(object_path);
48224814}
......@@ -4946,13 +4938,21 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
49464938 }
49474939}
49484940
4949void codegen_generate_h_file(CodeGen *g) {
4941static void gen_h_file(CodeGen *g) {
4942 if (!g->want_h_file)
4943 return;
4944
4945 codegen_add_time_event(g, "Generate .h");
4946
49504947 assert(!g->is_test_build);
49514948
4952 Buf *h_file_out_path = buf_sprintf("%s.h", buf_ptr(g->root_out_name));
4953 FILE *out_h = fopen(buf_ptr(h_file_out_path), "wb");
4949 if (!g->out_h_path) {
4950 g->out_h_path = buf_sprintf("%s.h", buf_ptr(g->root_out_name));
4951 }
4952
4953 FILE *out_h = fopen(buf_ptr(g->out_h_path), "wb");
49544954 if (!out_h)
4955 zig_panic("unable to open %s: %s", buf_ptr(h_file_out_path), strerror(errno));
4955 zig_panic("unable to open %s: %s", buf_ptr(g->out_h_path), strerror(errno));
49564956
49574957 Buf *export_macro = buf_sprintf("%s_EXPORT", buf_ptr(g->root_out_name));
49584958 buf_upcase(export_macro);
......@@ -5056,3 +5056,13 @@ void codegen_print_timing_report(CodeGen *g, FILE *f) {
50565056void codegen_add_time_event(CodeGen *g, const char *name) {
50575057 g->timing_events.append({os_get_time(), name});
50585058}
5059
5060void codegen_build(CodeGen *g) {
5061 assert(g->out_type != OutTypeUnknown);
5062 init(g);
5063
5064 gen_global_asm(g);
5065 gen_root_source(g);
5066 do_code_gen(g);
5067 gen_h_file(g);
5068}
src/codegen.hpp+2-3
......@@ -14,7 +14,7 @@
1414
1515#include <stdio.h>
1616
17CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target);
17CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type);
1818
1919void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
2020void codegen_set_is_release(CodeGen *codegen, bool is_release);
......@@ -25,7 +25,6 @@ void codegen_set_is_static(CodeGen *codegen, bool is_static);
2525void codegen_set_strip(CodeGen *codegen, bool strip);
2626void codegen_set_verbose(CodeGen *codegen, bool verbose);
2727void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color);
28void codegen_set_out_type(CodeGen *codegen, OutType out_type);
2928void codegen_set_out_name(CodeGen *codegen, Buf *out_name);
3029void codegen_set_libc_lib_dir(CodeGen *codegen, Buf *libc_lib_dir);
3130void codegen_set_libc_static_lib_dir(CodeGen *g, Buf *libc_static_lib_dir);
......@@ -48,6 +47,7 @@ void codegen_set_test_filter(CodeGen *g, Buf *filter);
4847void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
4948void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch);
5049void codegen_set_cache_dir(CodeGen *g, Buf *cache_dir);
50void codegen_set_output_h_path(CodeGen *g, Buf *h_path);
5151void codegen_add_time_event(CodeGen *g, const char *name);
5252void codegen_print_timing_report(CodeGen *g, FILE *f);
5353void codegen_build(CodeGen *g);
......@@ -59,6 +59,5 @@ void codegen_add_object(CodeGen *g, Buf *object_path);
5959void codegen_parseh(CodeGen *g, Buf *path);
6060void codegen_render_ast(CodeGen *g, FILE *f, int indent_size);
6161
62void codegen_generate_h_file(CodeGen *g);
6362
6463#endif
src/link.cpp+5-15
......@@ -37,7 +37,7 @@ static Buf *build_o(CodeGen *parent_gen, const char *oname) {
3737 os_path_join(parent_gen->zig_std_special_dir, source_basename, full_path);
3838
3939 ZigTarget *child_target = parent_gen->is_native_target ? nullptr : &parent_gen->zig_target;
40 CodeGen *child_gen = codegen_create(full_path, child_target);
40 CodeGen *child_gen = codegen_create(full_path, child_target, OutTypeObj);
4141 child_gen->link_libc = parent_gen->link_libc;
4242
4343 child_gen->link_libs.resize(parent_gen->link_libs.length);
......@@ -55,7 +55,6 @@ static Buf *build_o(CodeGen *parent_gen, const char *oname) {
5555 codegen_set_strip(child_gen, parent_gen->strip_debug_symbols);
5656 codegen_set_is_static(child_gen, parent_gen->is_static);
5757
58 codegen_set_out_type(child_gen, OutTypeObj);
5958 codegen_set_out_name(child_gen, buf_create_from_str(oname));
6059
6160 codegen_set_verbose(child_gen, parent_gen->verbose);
......@@ -186,9 +185,10 @@ static void construct_linker_job_elf(LinkJob *lj) {
186185 } else if (shared) {
187186 lj->args.append("-shared");
188187
189 buf_resize(&lj->out_file, 0);
190 buf_appendf(&lj->out_file, "lib%s.so.%zu.%zu.%zu",
191 buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch);
188 if (buf_len(&lj->out_file) == 0) {
189 buf_appendf(&lj->out_file, "lib%s.so.%zu.%zu.%zu",
190 buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch);
191 }
192192 soname = buf_sprintf("lib%s.so.%zu", buf_ptr(g->root_out_name), g->version_major);
193193 }
194194
......@@ -752,9 +752,6 @@ void codegen_link(CodeGen *g, const char *out_file) {
752752 }
753753
754754 if (g->out_type == OutTypeObj) {
755 if (g->want_h_file) {
756 codegen_generate_h_file(g);
757 }
758755 if (override_out_file) {
759756 assert(g->link_objects.length == 1);
760757 Buf *o_file_path = g->link_objects.at(0);
......@@ -798,13 +795,6 @@ void codegen_link(CodeGen *g, const char *out_file) {
798795 fprintf(stderr, "%s\n", buf_ptr(&diag));
799796 exit(1);
800797 }
801 codegen_add_time_event(g, "Generate .h");
802
803 if (g->out_type == OutTypeLib ||
804 g->out_type == OutTypeObj)
805 {
806 codegen_generate_h_file(g);
807 }
808798
809799 codegen_add_time_event(g, "Done");
810800
src/main.cpp+22-11
......@@ -35,6 +35,7 @@ static int usage(const char *arg0) {
3535 " --libc-include-dir [path] directory where libc stdlib.h resides\n"
3636 " --name [name] override output name\n"
3737 " --output [file] override destination path\n"
38 " --output-h [file] override generated header file path\n"
3839 " --release build with optimizations on and debug protection off\n"
3940 " --static output will be statically linked\n"
4041 " --strip exclude debug symbols\n"
......@@ -118,6 +119,8 @@ enum Cmd {
118119 CmdTargets,
119120};
120121
122static const char *default_zig_cache_name = "zig-cache";
123
121124int main(int argc, char **argv) {
122125 os_init();
123126
......@@ -125,6 +128,7 @@ int main(int argc, char **argv) {
125128 Cmd cmd = CmdInvalid;
126129 const char *in_file = nullptr;
127130 const char *out_file = nullptr;
131 const char *out_file_h = nullptr;
128132 bool is_release_build = false;
129133 bool strip = false;
130134 bool is_static = false;
......@@ -163,7 +167,7 @@ int main(int argc, char **argv) {
163167 size_t ver_minor = 0;
164168 size_t ver_patch = 0;
165169 bool timing_info = false;
166 const char *cache_dir = "zig-cache";
170 const char *cache_dir = nullptr;
167171
168172 if (argc >= 2 && strcmp(argv[1], "build") == 0) {
169173 const char *zig_exe_path = arg0;
......@@ -200,9 +204,8 @@ int main(int argc, char **argv) {
200204 }
201205 }
202206
203 CodeGen *g = codegen_create(build_runner_path, nullptr);
207 CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe);
204208 codegen_set_out_name(g, buf_create_from_str("build"));
205 codegen_set_out_type(g, OutTypeExe);
206209 codegen_set_verbose(g, verbose);
207210
208211 Buf build_file_abs = BUF_INIT;
......@@ -212,7 +215,12 @@ int main(int argc, char **argv) {
212215 os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename);
213216
214217 Buf *full_cache_dir = buf_alloc();
215 os_path_resolve(buf_create_from_str("."), buf_create_from_str(cache_dir), full_cache_dir);
218 if (cache_dir == nullptr) {
219 os_path_join(&build_file_dirname, buf_create_from_str(default_zig_cache_name), full_cache_dir);
220 } else {
221 os_path_resolve(buf_create_from_str("."), buf_create_from_str(cache_dir), full_cache_dir);
222 }
223
216224 Buf *path_to_build_exe = buf_alloc();
217225 os_path_join(full_cache_dir, buf_create_from_str("build"), path_to_build_exe);
218226 codegen_set_cache_dir(g, full_cache_dir);
......@@ -309,6 +317,8 @@ int main(int argc, char **argv) {
309317 return usage(arg0);
310318 } else if (strcmp(arg, "--output") == 0) {
311319 out_file = argv[i];
320 } else if (strcmp(arg, "--output-h") == 0) {
321 out_file_h = argv[i];
312322 } else if (strcmp(arg, "--color") == 0) {
313323 if (strcmp(argv[i], "auto") == 0) {
314324 color = ErrColorAuto;
......@@ -396,6 +406,7 @@ int main(int argc, char **argv) {
396406 cmd = CmdParseH;
397407 } else if (strcmp(arg, "test") == 0) {
398408 cmd = CmdTest;
409 out_type = OutTypeExe;
399410 } else if (strcmp(arg, "targets") == 0) {
400411 cmd = CmdTargets;
401412 } else {
......@@ -495,9 +506,11 @@ int main(int argc, char **argv) {
495506 Buf *zig_root_source_file = (cmd == CmdParseH) ? nullptr : in_file_buf;
496507
497508 Buf *full_cache_dir = buf_alloc();
498 os_path_resolve(buf_create_from_str("."), buf_create_from_str(cache_dir), full_cache_dir);
509 os_path_resolve(buf_create_from_str("."),
510 buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir),
511 full_cache_dir);
499512
500 CodeGen *g = codegen_create(zig_root_source_file, target);
513 CodeGen *g = codegen_create(zig_root_source_file, target, out_type);
501514 codegen_set_out_name(g, buf_out_name);
502515 codegen_set_lib_version(g, ver_major, ver_minor, ver_patch);
503516 codegen_set_is_release(g, is_release_build);
......@@ -510,11 +523,6 @@ int main(int argc, char **argv) {
510523 codegen_set_clang_argv(g, clang_argv.items, clang_argv.length);
511524 codegen_set_strip(g, strip);
512525 codegen_set_is_static(g, is_static);
513 if (out_type != OutTypeUnknown) {
514 codegen_set_out_type(g, out_type);
515 } else if (cmd == CmdTest) {
516 codegen_set_out_type(g, OutTypeExe);
517 }
518526 if (libc_lib_dir)
519527 codegen_set_libc_lib_dir(g, buf_create_from_str(libc_lib_dir));
520528 if (libc_static_lib_dir)
......@@ -568,6 +576,9 @@ int main(int argc, char **argv) {
568576 codegen_set_test_name_prefix(g, buf_create_from_str(test_name_prefix));
569577 }
570578
579 if (out_file_h)
580 codegen_set_output_h_path(g, buf_create_from_str(out_file_h));
581
571582 if (cmd == CmdBuild) {
572583 for (size_t i = 0; i < objects.length; i += 1) {
573584 codegen_add_object(g, buf_create_from_str(objects.at(i)));
std/build.zig+138-62
......@@ -37,7 +37,6 @@ pub const Builder = struct {
3737 top_level_steps: List(&TopLevelStep),
3838 prefix: []const u8,
3939 lib_dir: []const u8,
40 out_dir: []u8, // TODO get rid of this
4140 installed_files: List([]const u8),
4241 build_root: []const u8,
4342 cache_root: []const u8,
......@@ -97,7 +96,6 @@ pub const Builder = struct {
9796 .env_map = %%os.getEnvMap(allocator),
9897 .prefix = undefined,
9998 .lib_dir = undefined,
100 .out_dir = %%os.getCwd(allocator),
10199 .installed_files = List([]const u8).init(allocator),
102100 .uninstall_tls = TopLevelStep {
103101 .step = Step.init("uninstall", allocator, makeUninstall),
......@@ -111,7 +109,6 @@ pub const Builder = struct {
111109 }
112110
113111 pub fn deinit(self: &Builder) {
114 self.allocator.free(self.out_dir);
115112 self.lib_paths.deinit();
116113 self.include_paths.deinit();
117114 self.rpaths.deinit();
......@@ -172,12 +169,10 @@ pub const Builder = struct {
172169 return exe;
173170 }
174171
175 pub fn addCommand(self: &Builder, cwd: []const u8, env_map: &const BufMap,
172 pub fn addCommand(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
176173 path: []const u8, args: []const []const u8) -> &CommandStep
177174 {
178 const cmd = %%self.allocator.create(CommandStep);
179 *cmd = CommandStep.init(self, cwd, env_map, path, args);
180 return cmd;
175 return CommandStep.create(self, cwd, env_map, path, args);
181176 }
182177
183178 pub fn addWriteFile(self: &Builder, file_path: []const u8, data: []const u8) -> &WriteFileStep {
......@@ -489,21 +484,22 @@ pub const Builder = struct {
489484 }
490485
491486 fn spawnChild(self: &Builder, exe_path: []const u8, args: []const []const u8) -> %void {
492 return self.spawnChildEnvMap(&self.env_map, exe_path, args);
487 return self.spawnChildEnvMap(null, &self.env_map, exe_path, args);
493488 }
494489
495 fn spawnChildEnvMap(self: &Builder, env_map: &const BufMap, exe_path: []const u8,
496 args: []const []const u8) -> %void
490 fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
491 exe_path: []const u8, args: []const []const u8) -> %void
497492 {
498493 if (self.verbose) {
499 %%io.stderr.printf("{}", exe_path);
494 test (cwd) |yes_cwd| %%io.stderr.print("cd {}; ", yes_cwd);
495 %%io.stderr.print("{}", exe_path);
500496 for (args) |arg| {
501 %%io.stderr.printf(" {}", arg);
497 %%io.stderr.print(" {}", arg);
502498 }
503499 %%io.stderr.printf("\n");
504500 }
505501
506 var child = os.ChildProcess.spawn(exe_path, args, env_map,
502 var child = os.ChildProcess.spawn(exe_path, args, cwd, env_map,
507503 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator) %% |err|
508504 {
509505 %%io.stderr.printf("Unable to spawn {}: {}\n", exe_path, @errorName(err));
......@@ -511,6 +507,7 @@ pub const Builder = struct {
511507 };
512508
513509 const term = child.wait() %% |err| {
510 test (cwd) |yes_cwd| %%io.stderr.printf("cwd: {}\n", yes_cwd);
514511 %%io.stderr.printf("Unable to spawn {}: {}\n", exe_path, @errorName(err));
515512 return err;
516513 };
......@@ -560,11 +557,12 @@ pub const Builder = struct {
560557
561558 fn copyFile(self: &Builder, source_path: []const u8, dest_path: []const u8) {
562559 const dirname = os.path.dirname(dest_path);
560 const abs_source_path = self.pathFromRoot(source_path);
563561 os.makePath(self.allocator, dirname) %% |err| {
564562 debug.panic("Unable to create path {}: {}", dirname, @errorName(err));
565563 };
566 os.copyFile(self.allocator, source_path, dest_path) %% |err| {
567 debug.panic("Unable to copy {} to {}: {}", source_path, dest_path, @errorName(err));
564 os.copyFile(self.allocator, abs_source_path, dest_path) %% |err| {
565 debug.panic("Unable to copy {} to {}: {}", abs_source_path, dest_path, @errorName(err));
568566 };
569567 }
570568
......@@ -628,8 +626,10 @@ pub const LibExeObjStep = struct {
628626 release: bool,
629627 static: bool,
630628 output_path: ?[]const u8,
629 output_h_path: ?[]const u8,
631630 kind: Kind,
632631 version: Version,
632 out_h_filename: []const u8,
633633 out_filename: []const u8,
634634 out_filename_major_only: []const u8,
635635 out_filename_name_only: []const u8,
......@@ -684,8 +684,10 @@ pub const LibExeObjStep = struct {
684684 .link_libs = BufSet.init(builder.allocator),
685685 .step = Step.init(name, builder.allocator, make),
686686 .output_path = null,
687 .output_h_path = null,
687688 .version = *ver,
688689 .out_filename = undefined,
690 .out_h_filename = builder.fmt("{}.h", name),
689691 .out_filename_major_only = undefined,
690692 .out_filename_name_only = undefined,
691693 .object_files = List([]const u8).init(builder.allocator),
......@@ -747,6 +749,27 @@ pub const LibExeObjStep = struct {
747749 self.output_path = value;
748750 }
749751
752 pub fn getOutputPath(self: &LibExeObjStep) -> []const u8 {
753 test (self.output_path) |output_path| {
754 output_path
755 } else {
756 const wanted_path = %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename);
757 %%os.path.relative(self.builder.allocator, self.builder.build_root, wanted_path)
758 }
759 }
760
761 pub fn setOutputHPath(self: &LibExeObjStep, value: []const u8) {
762 self.output_h_path = value;
763 }
764
765 pub fn getOutputHPath(self: &LibExeObjStep) -> []const u8 {
766 test (self.output_h_path) |output_h_path| {
767 output_h_path
768 } else {
769 %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_h_filename)
770 }
771 }
772
750773 pub fn addAssemblyFile(self: &LibExeObjStep, path: []const u8) {
751774 %%self.assembly_files.append(path);
752775 }
......@@ -763,14 +786,7 @@ pub const LibExeObjStep = struct {
763786
764787 self.step.dependOn(&obj.step);
765788
766 const path_to_obj = test (obj.output_path) |explicit_out_path| {
767 explicit_out_path
768 } else {
769 // TODO make it so we always know where this will be
770 %%os.path.join(self.builder.allocator, self.builder.cache_root,
771 self.builder.fmt("{}{}", obj.name, obj.target.oFileExt()))
772 };
773 %%self.object_files.append(path_to_obj);
789 %%self.object_files.append(obj.getOutputPath());
774790 }
775791
776792 fn make(step: &Step) -> %void {
......@@ -814,10 +830,16 @@ pub const LibExeObjStep = struct {
814830 %%zig_args.append("--release");
815831 }
816832
817 test (self.output_path) |output_path| {
818 %%zig_args.append("--output");
819 %%zig_args.append(builder.pathFromRoot(output_path));
820 }
833 %%zig_args.append("--cache-dir");
834 %%zig_args.append(builder.cache_root);
835
836 const output_path = builder.pathFromRoot(self.getOutputPath());
837 %%zig_args.append("--output");
838 %%zig_args.append(output_path);
839
840 const output_h_path = self.getOutputHPath();
841 %%zig_args.append("--output-h");
842 %%zig_args.append(builder.pathFromRoot(output_h_path));
821843
822844 %%zig_args.append("--name");
823845 %%zig_args.append(self.name);
......@@ -879,10 +901,8 @@ pub const LibExeObjStep = struct {
879901 %return builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
880902
881903 if (self.kind == Kind.Lib and !self.static) {
882 // sym link for libfoo.so.1 to libfoo.so.1.2.3
883 %%os.atomicSymLink(builder.allocator, self.out_filename, self.out_filename_major_only);
884 // sym link for libfoo.so to libfoo.so.1
885 %%os.atomicSymLink(builder.allocator, self.out_filename_major_only, self.out_filename_name_only);
904 %return doAtomicSymLinks(builder.allocator, output_path, self.out_filename_major_only,
905 self.out_filename_name_only);
886906 }
887907 }
888908};
......@@ -987,10 +1007,12 @@ pub const TestStep = struct {
9871007 }
9881008};
9891009
1010// TODO merge with CExecutable
9901011pub const CLibrary = struct {
9911012 step: Step,
9921013 name: []const u8,
9931014 out_filename: []const u8,
1015 output_path: ?[]const u8,
9941016 static: bool,
9951017 version: Version,
9961018 cflags: List([]const u8),
......@@ -1024,6 +1046,7 @@ pub const CLibrary = struct {
10241046 .step = Step.init(name, builder.allocator, make),
10251047 .link_libs = BufSet.init(builder.allocator),
10261048 .include_dirs = List([]const u8).init(builder.allocator),
1049 .output_path = null,
10271050 .out_filename = undefined,
10281051 .major_only_filename = undefined,
10291052 .name_only_filename = undefined,
......@@ -1043,6 +1066,19 @@ pub const CLibrary = struct {
10431066 }
10441067 }
10451068
1069 pub fn setOutputPath(self: &CLibrary, value: []const u8) {
1070 self.output_path = value;
1071 }
1072
1073 pub fn getOutputPath(self: &CLibrary) -> []const u8 {
1074 test (self.output_path) |output_path| {
1075 output_path
1076 } else {
1077 const wanted_path = %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename);
1078 %%os.path.relative(self.builder.allocator, self.builder.build_root, wanted_path)
1079 }
1080 }
1081
10461082 pub fn linkSystemLibrary(self: &CLibrary, name: []const u8) {
10471083 %%self.link_libs.put(name);
10481084 }
......@@ -1131,8 +1167,9 @@ pub const CLibrary = struct {
11311167 defer builder.allocator.free(soname_arg);
11321168 %%cc_args.append(soname_arg);
11331169
1170 const output_path = builder.pathFromRoot(self.getOutputPath());
11341171 %%cc_args.append("-o");
1135 %%cc_args.append(self.out_filename);
1172 %%cc_args.append(output_path);
11361173
11371174 for (self.object_files.toSliceConst()) |object_file| {
11381175 %%cc_args.append(builder.pathFromRoot(object_file));
......@@ -1140,10 +1177,8 @@ pub const CLibrary = struct {
11401177
11411178 %return builder.spawnChild(cc, cc_args.toSliceConst());
11421179
1143 // sym link for libfoo.so.1 to libfoo.so.1.2.3
1144 %%os.atomicSymLink(builder.allocator, self.out_filename, self.major_only_filename);
1145 // sym link for libfoo.so to libfoo.so.1
1146 %%os.atomicSymLink(builder.allocator, self.major_only_filename, self.name_only_filename);
1180 %return doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename,
1181 self.name_only_filename);
11471182 }
11481183 }
11491184
......@@ -1169,9 +1204,11 @@ pub const CExecutable = struct {
11691204 link_libs: BufSet,
11701205 target: Target,
11711206 include_dirs: List([]const u8),
1207 output_path: ?[]const u8,
1208 out_filename: []const u8,
11721209
11731210 pub fn init(builder: &Builder, name: []const u8) -> CExecutable {
1174 CExecutable {
1211 var self = CExecutable {
11751212 .builder = builder,
11761213 .name = name,
11771214 .target = Target.Native,
......@@ -1182,6 +1219,27 @@ pub const CExecutable = struct {
11821219 .step = Step.init(name, builder.allocator, make),
11831220 .link_libs = BufSet.init(builder.allocator),
11841221 .include_dirs = List([]const u8).init(builder.allocator),
1222 .output_path = null,
1223 .out_filename = undefined,
1224 };
1225 self.computeOutFileName();
1226 return self;
1227 }
1228
1229 fn computeOutFileName(self: &CExecutable) {
1230 self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt());
1231 }
1232
1233 pub fn setOutputPath(self: &CExecutable, value: []const u8) {
1234 self.output_path = value;
1235 }
1236
1237 pub fn getOutputPath(self: &CExecutable) -> []const u8 {
1238 test (self.output_path) |output_path| {
1239 self.builder.pathFromRoot(output_path)
1240 } else {
1241 const wanted_path = %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename);
1242 %%os.path.relative(self.builder.allocator, self.builder.build_root, wanted_path)
11851243 }
11861244 }
11871245
......@@ -1191,15 +1249,15 @@ pub const CExecutable = struct {
11911249
11921250 pub fn linkCLibrary(self: &CExecutable, clib: &CLibrary) {
11931251 self.step.dependOn(&clib.step);
1194 %%self.full_path_libs.append(clib.out_filename);
1252 %%self.full_path_libs.append(clib.getOutputPath());
11951253 }
11961254
11971255 pub fn linkLibrary(self: &CExecutable, lib: &LibExeObjStep) {
11981256 assert(lib.kind == LibExeObjStep.Kind.Lib);
11991257 self.step.dependOn(&lib.step);
1200 %%self.full_path_libs.append(lib.out_filename);
1258 %%self.full_path_libs.append(lib.getOutputPath());
12011259 // TODO should be some kind of isolated directory that only has this header in it
1202 %%self.include_dirs.append(self.builder.out_dir);
1260 %%self.include_dirs.append(self.builder.cache_root);
12031261 }
12041262
12051263 pub fn addObject(self: &CExecutable, obj: &LibExeObjStep) {
......@@ -1207,12 +1265,10 @@ pub const CExecutable = struct {
12071265
12081266 self.step.dependOn(&obj.step);
12091267
1210 // TODO make it so we always know where this will be
1211 %%self.object_files.append(%%os.path.join(self.builder.allocator, self.builder.cache_root,
1212 self.builder.fmt("{}{}", obj.name, obj.target.oFileExt())));
1268 %%self.object_files.append(obj.getOutputPath());
12131269
12141270 // TODO should be some kind of isolated directory that only has this header in it
1215 %%self.include_dirs.append(self.builder.out_dir);
1271 %%self.include_dirs.append(self.builder.cache_root);
12161272 }
12171273
12181274 pub fn addSourceFile(self: &CExecutable, file: []const u8) {
......@@ -1256,7 +1312,6 @@ pub const CExecutable = struct {
12561312 %%cc_args.append("-c");
12571313 %%cc_args.append(builder.pathFromRoot(source_file));
12581314
1259 // TODO don't dump the .o file in the same place as the source file
12601315 const rel_src_path = %%os.path.relative(builder.allocator, builder.build_root, source_file);
12611316 const cache_o_src = %%os.path.join(builder.allocator, builder.cache_root, rel_src_path);
12621317 const cache_o_dir = os.path.dirname(cache_o_src);
......@@ -1276,26 +1331,28 @@ pub const CExecutable = struct {
12761331
12771332 %return builder.spawnChild(cc, cc_args.toSliceConst());
12781333
1279 %%self.object_files.append(cache_o_file);
1334 %%self.object_files.append(%%os.path.relative(builder.allocator, builder.build_root, cache_o_file));
12801335 }
12811336
12821337 %%cc_args.resize(0);
12831338
12841339 for (self.object_files.toSliceConst()) |object_file| {
1285 %%cc_args.append(object_file);
1340 %%cc_args.append(builder.pathFromRoot(object_file));
12861341 }
12871342
1343 const output_path = builder.pathFromRoot(self.getOutputPath());
12881344 %%cc_args.append("-o");
1289 %%cc_args.append(self.name);
1345 %%cc_args.append(output_path);
12901346
1291 const rpath_arg = builder.fmt("-Wl,-rpath,{}", builder.out_dir);
1347 const rpath_arg = builder.fmt("-Wl,-rpath,{}",
1348 %%os.path.real(builder.allocator, builder.cache_root));
12921349 defer builder.allocator.free(rpath_arg);
12931350 %%cc_args.append(rpath_arg);
12941351
12951352 %%cc_args.append("-rdynamic");
12961353
12971354 for (self.full_path_libs.toSliceConst()) |full_path_lib| {
1298 %%cc_args.append(full_path_lib);
1355 %%cc_args.append(builder.pathFromRoot(full_path_lib));
12991356 }
13001357
13011358 %return builder.spawnChild(cc, cc_args.toSliceConst());
......@@ -1317,27 +1374,29 @@ pub const CommandStep = struct {
13171374 builder: &Builder,
13181375 exe_path: []const u8,
13191376 args: []const []const u8,
1320 cwd: []const u8,
1377 cwd: ?[]const u8,
13211378 env_map: &const BufMap,
13221379
1323 pub fn init(builder: &Builder, cwd: []const u8, env_map: &const BufMap,
1324 exe_path: []const u8, args: []const []const u8) -> CommandStep
1380 pub fn create(builder: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
1381 exe_path: []const u8, args: []const []const u8) -> &CommandStep
13251382 {
1326 CommandStep {
1383 const self = %%builder.allocator.create(CommandStep);
1384 *self = CommandStep {
13271385 .builder = builder,
13281386 .step = Step.init(exe_path, builder.allocator, make),
13291387 .exe_path = exe_path,
13301388 .args = args,
13311389 .cwd = cwd,
13321390 .env_map = env_map,
1333 }
1391 };
1392 return self;
13341393 }
13351394
13361395 fn make(step: &Step) -> %void {
13371396 const self = @fieldParentPtr(CommandStep, "step", step);
13381397
1339 // TODO set cwd
1340 return self.builder.spawnChildEnvMap(self.env_map, self.exe_path, self.args);
1398 const cwd = test (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else null;
1399 return self.builder.spawnChildEnvMap(cwd, self.env_map, self.exe_path, self.args);
13411400 }
13421401};
13431402
......@@ -1367,12 +1426,10 @@ pub const InstallCLibraryStep = struct {
13671426 const self = @fieldParentPtr(InstallCLibraryStep, "step", step);
13681427 const builder = self.builder;
13691428
1370 self.builder.copyFile(self.lib.out_filename, self.dest_file);
1429 self.builder.copyFile(self.lib.getOutputPath(), self.dest_file);
13711430 if (!self.lib.static) {
1372 const dest_major_only = %%os.path.join(builder.allocator, builder.lib_dir, self.lib.major_only_filename);
1373 const dest_name_only = %%os.path.join(builder.allocator, builder.lib_dir, self.lib.name_only_filename);
1374 %%os.atomicSymLink(self.builder.allocator, self.lib.out_filename, dest_major_only);
1375 %%os.atomicSymLink(self.builder.allocator, self.lib.major_only_filename, dest_name_only);
1431 %return doAtomicSymLinks(self.builder.allocator, self.dest_file, self.lib.major_only_filename,
1432 self.lib.name_only_filename);
13761433 }
13771434 }
13781435};
......@@ -1506,3 +1563,22 @@ pub const Step = struct {
15061563
15071564 fn makeNoOp(self: &Step) -> %void {}
15081565};
1566
1567fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_major_only: []const u8,
1568 filename_name_only: []const u8) -> %void
1569{
1570 const out_dir = os.path.dirname(output_path);
1571 const out_basename = os.path.basename(output_path);
1572 // sym link for libfoo.so.1 to libfoo.so.1.2.3
1573 const major_only_path = %%os.path.join(allocator, out_dir, filename_major_only);
1574 os.atomicSymLink(allocator, out_basename, major_only_path) %% |err| {
1575 %%io.stderr.printf("Unable to symlink {} -> {}\n", major_only_path, out_basename);
1576 return err;
1577 };
1578 // sym link for libfoo.so to libfoo.so.1
1579 const name_only_path = %%os.path.join(allocator, out_dir, filename_name_only);
1580 os.atomicSymLink(allocator, filename_major_only, name_only_path) %% |err| {
1581 %%io.stderr.printf("Unable to symlink {} -> {}\n", name_only_path, filename_major_only);
1582 return err;
1583 };
1584}
std/fmt.zig+3-3
......@@ -345,17 +345,17 @@ fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) -> bool {
345345 return true;
346346}
347347
348pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) {
348pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) -> []u8 {
349349 var context = BufPrintContext { .remaining = buf, };
350350 _ = format(&context, bufPrintWrite, fmt, args);
351 return buf[0...buf.len - context.remaining.len];
351352}
352353
353354pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...) -> %[]u8 {
354355 var size: usize = 0;
355356 _ = format(&size, countSize, fmt, args);
356357 const buf = %return allocator.alloc(u8, size);
357 bufPrint(buf, fmt, args);
358 return buf;
358 return bufPrint(buf, fmt, args);
359359}
360360
361361fn countSize(size: &usize, bytes: []const u8) -> bool {
std/os/child_process.zig+10-3
......@@ -30,12 +30,13 @@ pub const ChildProcess = struct {
3030 Close,
3131 };
3232
33 pub fn spawn(exe_path: []const u8, args: []const []const u8, env_map: &const BufMap,
33 pub fn spawn(exe_path: []const u8, args: []const []const u8,
34 cwd: ?[]const u8, env_map: &const BufMap,
3435 stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
3536 {
3637 switch (@compileVar("os")) {
3738 Os.linux, Os.macosx, Os.ios, Os.darwin => {
38 return spawnPosix(exe_path, args, env_map, stdin, stdout, stderr, allocator);
39 return spawnPosix(exe_path, args, cwd, env_map, stdin, stdout, stderr, allocator);
3940 },
4041 else => @compileError("Unsupported OS"),
4142 }
......@@ -98,7 +99,8 @@ pub const ChildProcess = struct {
9899 };
99100 }
100101
101 fn spawnPosix(exe_path: []const u8, args: []const []const u8, env_map: &const BufMap,
102 fn spawnPosix(exe_path: []const u8, args: []const []const u8,
103 maybe_cwd: ?[]const u8, env_map: &const BufMap,
102104 stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
103105 {
104106 // TODO issue #295
......@@ -155,6 +157,11 @@ pub const ChildProcess = struct {
155157 setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %%
156158 |err| forkChildErrReport(err_pipe[1], err);
157159
160 test (maybe_cwd) |cwd| {
161 os.changeCurDir(allocator, cwd) %%
162 |err| forkChildErrReport(err_pipe[1], err);
163 }
164
158165 os.posixExecve(exe_path, args, env_map, allocator) %%
159166 |err| forkChildErrReport(err_pipe[1], err);
160167 }
std/os/index.zig+57
......@@ -780,3 +780,60 @@ pub const Dir = struct {
780780 };
781781 }
782782};
783
784pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) -> %void {
785 const path_buf = %return allocator.alloc(u8, dir_path.len + 1);
786 defer allocator.free(path_buf);
787
788 mem.copy(u8, path_buf, dir_path);
789 path_buf[dir_path.len] = 0;
790
791 const err = posix.getErrno(posix.chdir(path_buf.ptr));
792 if (err > 0) {
793 return switch (err) {
794 errno.EACCES => error.AccessDenied,
795 errno.EFAULT => unreachable,
796 errno.EIO => error.FileSystem,
797 errno.ELOOP => error.SymLinkLoop,
798 errno.ENAMETOOLONG => error.NameTooLong,
799 errno.ENOENT => error.FileNotFound,
800 errno.ENOMEM => error.SystemResources,
801 errno.ENOTDIR => error.NotDir,
802 else => error.Unexpected,
803 };
804 }
805}
806
807/// Read value of a symbolic link.
808pub fn readLink(allocator: &Allocator, pathname: []const u8) -> %[]u8 {
809 const path_buf = %return allocator.alloc(u8, pathname.len + 1);
810 defer allocator.free(path_buf);
811
812 mem.copy(u8, path_buf, pathname);
813 path_buf[pathname.len] = 0;
814
815 var result_buf = %return allocator.alloc(u8, 1024);
816 %defer allocator.free(result_buf);
817 while (true) {
818 const ret_val = posix.readlink(path_buf.ptr, result_buf.ptr, result_buf.len);
819 const err = posix.getErrno(ret_val);
820 if (err > 0) {
821 return switch (err) {
822 errno.EACCES => error.AccessDenied,
823 errno.EFAULT, errno.EINVAL => unreachable,
824 errno.EIO => error.FileSystem,
825 errno.ELOOP => error.SymLinkLoop,
826 errno.ENAMETOOLONG => error.NameTooLong,
827 errno.ENOENT => error.FileNotFound,
828 errno.ENOMEM => error.SystemResources,
829 errno.ENOTDIR => error.NotDir,
830 else => error.Unexpected,
831 };
832 }
833 if (ret_val == result_buf.len) {
834 result_buf = %return allocator.realloc(u8, result_buf, result_buf.len * 2);
835 continue;
836 }
837 return result_buf[0...ret_val];
838 }
839}
std/os/linux.zig+8
......@@ -335,6 +335,10 @@ pub fn dup2(old: i32, new: i32) -> usize {
335335 arch.syscall2(arch.SYS_dup2, usize(old), usize(new))
336336}
337337
338pub fn chdir(path: &const u8) -> usize {
339 arch.syscall1(arch.SYS_chdir, usize(path))
340}
341
338342pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) -> usize {
339343 arch.syscall3(arch.SYS_execve, usize(path), usize(argv), usize(envp))
340344}
......@@ -356,6 +360,10 @@ pub fn isatty(fd: i32) -> bool {
356360 return arch.syscall3(arch.SYS_ioctl, usize(fd), TIOCGWINSZ, usize(&wsz)) == 0;
357361}
358362
363pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) -> usize {
364 arch.syscall3(arch.SYS_readlink, usize(path), usize(buf_ptr), buf_len)
365}
366
359367pub fn mkdir(path: &const u8, mode: usize) -> usize {
360368 arch.syscall2(arch.SYS_mkdir, usize(path), mode)
361369}
std/os/path.zig+55
......@@ -1,9 +1,11 @@
11const debug = @import("../debug.zig");
22const assert = debug.assert;
33const mem = @import("../mem.zig");
4const fmt = @import("../fmt.zig");
45const Allocator = mem.Allocator;
56const os = @import("index.zig");
67const math = @import("../math.zig");
8const posix = os.posix;
79
810pub const sep = switch (@compileVar("os")) {
911 Os.windows => '\\',
......@@ -185,6 +187,45 @@ fn testDirname(input: []const u8, expected_output: []const u8) {
185187 assert(mem.eql(u8, dirname(input), expected_output));
186188}
187189
190pub fn basename(path: []const u8) -> []const u8 {
191 if (path.len == 0)
192 return []u8{};
193
194 var end_index: usize = path.len - 1;
195 while (path[end_index] == '/') {
196 if (end_index == 0)
197 return []u8{};
198 end_index -= 1;
199 }
200 var start_index: usize = end_index;
201 end_index += 1;
202 while (path[start_index] != '/') {
203 if (start_index == 0)
204 return path[0...end_index];
205 start_index -= 1;
206 }
207
208 return path[start_index + 1...end_index];
209}
210
211test "os.path.basename" {
212 testBasename("", "");
213 testBasename("/", "");
214 testBasename("/dir/basename.ext", "basename.ext");
215 testBasename("/basename.ext", "basename.ext");
216 testBasename("basename.ext", "basename.ext");
217 testBasename("basename.ext/", "basename.ext");
218 testBasename("basename.ext//", "basename.ext");
219 testBasename("/aaa/bbb", "bbb");
220 testBasename("/aaa/", "aaa");
221 testBasename("/aaa/b", "b");
222 testBasename("/a/b", "b");
223 testBasename("//a", "a");
224}
225fn testBasename(input: []const u8, expected_output: []const u8) {
226 assert(mem.eql(u8, basename(input), expected_output));
227}
228
188229/// Returns the relative path from ::from to ::to. If ::from and ::to each
189230/// resolve to the same path (after calling ::resolve on each), a zero-length
190231/// string is returned.
......@@ -252,3 +293,17 @@ fn testRelative(from: []const u8, to: []const u8, expected_output: []const u8) {
252293 const result = %%relative(&debug.global_allocator, from, to);
253294 assert(mem.eql(u8, result, expected_output));
254295}
296
297/// Return the canonicalized absolute pathname.
298/// Expands all symbolic links and resolves references to `.`, `..`, and
299/// extra `/` characters in ::pathname.
300/// Caller must deallocate result.
301pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 {
302 const fd = %return os.posixOpen(pathname, posix.O_PATH|posix.O_NONBLOCK|posix.O_CLOEXEC, 0, allocator);
303 defer os.posixClose(fd);
304
305 var buf: ["/proc/self/fd/-2147483648".len]u8 = undefined;
306 const proc_path = fmt.bufPrint(buf[0...], "/proc/self/fd/{}", fd);
307
308 return os.readLink(allocator, proc_path);
309}
test/tests.zig+16-16
......@@ -189,7 +189,7 @@ pub const CompareOutputContext = struct {
189189
190190 %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
191191
192 var child = os.ChildProcess.spawn(full_exe_path, [][]u8{}, &b.env_map,
192 var child = os.ChildProcess.spawn(full_exe_path, [][]u8{}, null, &b.env_map,
193193 StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, b.allocator) %% |err|
194194 {
195195 debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
......@@ -264,7 +264,7 @@ pub const CompareOutputContext = struct {
264264
265265 %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
266266
267 var child = os.ChildProcess.spawn(full_exe_path, [][]u8{}, &b.env_map,
267 var child = os.ChildProcess.spawn(full_exe_path, [][]u8{}, null, &b.env_map,
268268 StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, b.allocator) %% |err|
269269 {
270270 debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
......@@ -344,8 +344,8 @@ pub const CompareOutputContext = struct {
344344 pub fn addCase(self: &CompareOutputContext, case: &const TestCase) {
345345 const b = self.b;
346346
347 const root_src = %%os.path.join(b.allocator, "test_artifacts", case.sources.items[0].filename);
348 const exe_path = %%os.path.join(b.allocator, "test_artifacts", "test");
347 const root_src = %%os.path.join(b.allocator, b.cache_root, case.sources.items[0].filename);
348 const exe_path = %%os.path.join(b.allocator, b.cache_root, "test");
349349
350350 switch (case.special) {
351351 Special.Asm => {
......@@ -360,7 +360,7 @@ pub const CompareOutputContext = struct {
360360 exe.setOutputPath(exe_path);
361361
362362 for (case.sources.toSliceConst()) |src_file| {
363 const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename);
363 const expanded_src_path = %%os.path.join(b.allocator, b.cache_root, src_file.filename);
364364 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
365365 exe.step.dependOn(&write_src.step);
366366 }
......@@ -388,7 +388,7 @@ pub const CompareOutputContext = struct {
388388 }
389389
390390 for (case.sources.toSliceConst()) |src_file| {
391 const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename);
391 const expanded_src_path = %%os.path.join(b.allocator, b.cache_root, src_file.filename);
392392 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
393393 exe.step.dependOn(&write_src.step);
394394 }
......@@ -401,7 +401,7 @@ pub const CompareOutputContext = struct {
401401 }
402402 },
403403 Special.DebugSafety => {
404 const obj_path = %%os.path.join(b.allocator, "test_artifacts", "test.o");
404 const obj_path = %%os.path.join(b.allocator, b.cache_root, "test.o");
405405 const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "debug-safety {}", case.name);
406406 test (self.test_filter) |filter| {
407407 if (mem.indexOf(u8, annotated_case_name, filter) == null)
......@@ -415,7 +415,7 @@ pub const CompareOutputContext = struct {
415415 }
416416
417417 for (case.sources.toSliceConst()) |src_file| {
418 const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename);
418 const expanded_src_path = %%os.path.join(b.allocator, b.cache_root, src_file.filename);
419419 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
420420 exe.step.dependOn(&write_src.step);
421421 }
......@@ -488,8 +488,8 @@ pub const CompileErrorContext = struct {
488488 const self = @fieldParentPtr(CompileCmpOutputStep, "step", step);
489489 const b = self.context.b;
490490
491 const root_src = %%os.path.join(b.allocator, "test_artifacts", self.case.sources.items[0].filename);
492 const obj_path = %%os.path.join(b.allocator, "test_artifacts", "test.o");
491 const root_src = %%os.path.join(b.allocator, b.cache_root, self.case.sources.items[0].filename);
492 const obj_path = %%os.path.join(b.allocator, b.cache_root, "test.o");
493493
494494 var zig_args = List([]const u8).init(b.allocator);
495495 %%zig_args.append(if (self.case.is_exe) "build_exe" else "build_obj");
......@@ -511,7 +511,7 @@ pub const CompileErrorContext = struct {
511511 printInvocation(b.zig_exe, zig_args.toSliceConst());
512512 }
513513
514 var child = os.ChildProcess.spawn(b.zig_exe, zig_args.toSliceConst(), &b.env_map,
514 var child = os.ChildProcess.spawn(b.zig_exe, zig_args.toSliceConst(), null, &b.env_map,
515515 StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, b.allocator) %% |err|
516516 {
517517 debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err));
......@@ -632,7 +632,7 @@ pub const CompileErrorContext = struct {
632632 self.step.dependOn(&compile_and_cmp_errors.step);
633633
634634 for (case.sources.toSliceConst()) |src_file| {
635 const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename);
635 const expanded_src_path = %%os.path.join(b.allocator, b.cache_root, src_file.filename);
636636 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
637637 compile_and_cmp_errors.step.dependOn(&write_src.step);
638638 }
......@@ -675,7 +675,7 @@ pub const BuildExamplesContext = struct {
675675 %%zig_args.append("--verbose");
676676 }
677677
678 const run_cmd = b.addCommand(b.cache_root, b.env_map, b.zig_exe, zig_args.toSliceConst());
678 const run_cmd = b.addCommand(null, b.env_map, b.zig_exe, zig_args.toSliceConst());
679679
680680 const log_step = b.addLog("PASS {}\n", annotated_case_name);
681681 log_step.step.dependOn(&run_cmd.step);
......@@ -762,7 +762,7 @@ pub const ParseHContext = struct {
762762 const self = @fieldParentPtr(ParseHCmpOutputStep, "step", step);
763763 const b = self.context.b;
764764
765 const root_src = %%os.path.join(b.allocator, "test_artifacts", self.case.sources.items[0].filename);
765 const root_src = %%os.path.join(b.allocator, b.cache_root, self.case.sources.items[0].filename);
766766
767767 var zig_args = List([]const u8).init(b.allocator);
768768 %%zig_args.append("parseh");
......@@ -774,7 +774,7 @@ pub const ParseHContext = struct {
774774 printInvocation(b.zig_exe, zig_args.toSliceConst());
775775 }
776776
777 var child = os.ChildProcess.spawn(b.zig_exe, zig_args.toSliceConst(), &b.env_map,
777 var child = os.ChildProcess.spawn(b.zig_exe, zig_args.toSliceConst(), null, &b.env_map,
778778 StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, b.allocator) %% |err|
779779 {
780780 debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err));
......@@ -886,7 +886,7 @@ pub const ParseHContext = struct {
886886 self.step.dependOn(&parseh_and_cmp.step);
887887
888888 for (case.sources.toSliceConst()) |src_file| {
889 const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename);
889 const expanded_src_path = %%os.path.join(b.allocator, b.cache_root, src_file.filename);
890890 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
891891 parseh_and_cmp.step.dependOn(&write_src.step);
892892 }