diff --git a/.gitignore b/.gitignore index b0b6e7cb61..c52f5c5568 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ +zig-cache/ build/ build-release/ /.cproject /.project /.settings/ -/test_artifacts/ diff --git a/build.zig b/build.zig index 378ea66c86..cbd1732bc0 100644 --- a/build.zig +++ b/build.zig @@ -5,19 +5,16 @@ pub fn build(b: &Builder) { const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter"); const test_step = b.step("test", "Run all the tests"); - const cleanup = b.addRemoveDirTree("test_artifacts"); - test_step.dependOn(&cleanup.step); - - cleanup.step.dependOn(tests.addPkgTests(b, test_filter, + test_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests")); - cleanup.step.dependOn(tests.addPkgTests(b, test_filter, + test_step.dependOn(tests.addPkgTests(b, test_filter, "std/index.zig", "std", "Run the standard library tests")); - cleanup.step.dependOn(tests.addCompareOutputTests(b, test_filter)); - cleanup.step.dependOn(tests.addBuildExampleTests(b, test_filter)); - cleanup.step.dependOn(tests.addCompileErrorTests(b, test_filter)); - cleanup.step.dependOn(tests.addAssembleAndLinkTests(b, test_filter)); - cleanup.step.dependOn(tests.addDebugSafetyTests(b, test_filter)); - cleanup.step.dependOn(tests.addParseHTests(b, test_filter)); + test_step.dependOn(tests.addCompareOutputTests(b, test_filter)); + test_step.dependOn(tests.addBuildExampleTests(b, test_filter)); + test_step.dependOn(tests.addCompileErrorTests(b, test_filter)); + test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter)); + test_step.dependOn(tests.addDebugSafetyTests(b, test_filter)); + test_step.dependOn(tests.addParseHTests(b, test_filter)); } diff --git a/example/mix_o_files/build.zig b/example/mix_o_files/build.zig index d653d7ae7d..262b412f1c 100644 --- a/example/mix_o_files/build.zig +++ b/example/mix_o_files/build.zig @@ -12,7 +12,7 @@ pub fn build(b: &Builder) { b.default_step.dependOn(&exe.step); - const run_cmd = b.addCommand(b.out_dir, b.env_map, "./test", [][]const u8{}); + const run_cmd = b.addCommand(b.cache_root, b.env_map, "./test", [][]const u8{}); run_cmd.step.dependOn(&exe.step); const test_step = b.step("test", "Test the program"); diff --git a/example/shared_library/build.zig b/example/shared_library/build.zig index 1212c58ab8..cfa3340e17 100644 --- a/example/shared_library/build.zig +++ b/example/shared_library/build.zig @@ -12,7 +12,7 @@ pub fn build(b: &Builder) { b.default_step.dependOn(&exe.step); - const run_cmd = b.addCommand(b.out_dir, b.env_map, "./test", [][]const u8{}); + const run_cmd = b.addCommand(b.cache_root, b.env_map, "./test", [][]const u8{}); run_cmd.step.dependOn(&exe.step); const test_step = b.step("test", "Test the program"); diff --git a/src/all_types.hpp b/src/all_types.hpp index 23282a4a28..fea5fefad3 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1488,6 +1488,7 @@ struct CodeGen { ZigList timing_events; Buf *cache_dir; + Buf *out_h_path; }; enum VarLinkage { diff --git a/src/codegen.cpp b/src/codegen.cpp index 63a03fc496..31c7038a7e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -55,11 +55,12 @@ PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_pa return entry; } -CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target) { +CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type) { CodeGen *g = allocate(1); codegen_add_time_event(g, "Initialize"); + g->out_type = out_type; g->import_table.init(32); g->builtin_fn_table.init(32); g->primitive_type_table.init(32); @@ -74,7 +75,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target) { g->external_prototypes.init(8); g->is_release_build = false; g->is_test_build = false; - g->want_h_file = true; + g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib); buf_resize(&g->global_asm, 0); @@ -145,6 +146,10 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target) { return g; } +void codegen_set_output_h_path(CodeGen *g, Buf *h_path) { + g->out_h_path = h_path; +} + void codegen_set_clang_argv(CodeGen *g, const char **args, size_t len) { g->clang_argv = args; g->clang_argv_len = len; @@ -196,10 +201,6 @@ void codegen_set_strip(CodeGen *g, bool strip) { g->strip_debug_symbols = strip; } -void codegen_set_out_type(CodeGen *g, OutType out_type) { - g->out_type = out_type; -} - void codegen_set_out_name(CodeGen *g, Buf *out_name) { g->root_out_name = out_name; } @@ -4808,15 +4809,6 @@ static void gen_global_asm(CodeGen *g) { } } -void codegen_build(CodeGen *g) { - assert(g->out_type != OutTypeUnknown); - init(g); - - gen_global_asm(g); - gen_root_source(g); - do_code_gen(g); -} - void codegen_add_object(CodeGen *g, Buf *object_path) { g->link_objects.append(object_path); } @@ -4946,13 +4938,21 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) { } } -void codegen_generate_h_file(CodeGen *g) { +static void gen_h_file(CodeGen *g) { + if (!g->want_h_file) + return; + + codegen_add_time_event(g, "Generate .h"); + assert(!g->is_test_build); - Buf *h_file_out_path = buf_sprintf("%s.h", buf_ptr(g->root_out_name)); - FILE *out_h = fopen(buf_ptr(h_file_out_path), "wb"); + if (!g->out_h_path) { + g->out_h_path = buf_sprintf("%s.h", buf_ptr(g->root_out_name)); + } + + FILE *out_h = fopen(buf_ptr(g->out_h_path), "wb"); if (!out_h) - zig_panic("unable to open %s: %s", buf_ptr(h_file_out_path), strerror(errno)); + zig_panic("unable to open %s: %s", buf_ptr(g->out_h_path), strerror(errno)); Buf *export_macro = buf_sprintf("%s_EXPORT", buf_ptr(g->root_out_name)); buf_upcase(export_macro); @@ -5056,3 +5056,13 @@ void codegen_print_timing_report(CodeGen *g, FILE *f) { void codegen_add_time_event(CodeGen *g, const char *name) { g->timing_events.append({os_get_time(), name}); } + +void codegen_build(CodeGen *g) { + assert(g->out_type != OutTypeUnknown); + init(g); + + gen_global_asm(g); + gen_root_source(g); + do_code_gen(g); + gen_h_file(g); +} diff --git a/src/codegen.hpp b/src/codegen.hpp index 22818c33df..599217cf14 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -14,7 +14,7 @@ #include -CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target); +CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type); void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len); void codegen_set_is_release(CodeGen *codegen, bool is_release); @@ -25,7 +25,6 @@ void codegen_set_is_static(CodeGen *codegen, bool is_static); void codegen_set_strip(CodeGen *codegen, bool strip); void codegen_set_verbose(CodeGen *codegen, bool verbose); void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color); -void codegen_set_out_type(CodeGen *codegen, OutType out_type); void codegen_set_out_name(CodeGen *codegen, Buf *out_name); void codegen_set_libc_lib_dir(CodeGen *codegen, Buf *libc_lib_dir); void 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); void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix); void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch); void codegen_set_cache_dir(CodeGen *g, Buf *cache_dir); +void codegen_set_output_h_path(CodeGen *g, Buf *h_path); void codegen_add_time_event(CodeGen *g, const char *name); void codegen_print_timing_report(CodeGen *g, FILE *f); void codegen_build(CodeGen *g); @@ -59,6 +59,5 @@ void codegen_add_object(CodeGen *g, Buf *object_path); void codegen_parseh(CodeGen *g, Buf *path); void codegen_render_ast(CodeGen *g, FILE *f, int indent_size); -void codegen_generate_h_file(CodeGen *g); #endif diff --git a/src/link.cpp b/src/link.cpp index e3179680f9..5e1d2cce3a 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -37,7 +37,7 @@ static Buf *build_o(CodeGen *parent_gen, const char *oname) { os_path_join(parent_gen->zig_std_special_dir, source_basename, full_path); ZigTarget *child_target = parent_gen->is_native_target ? nullptr : &parent_gen->zig_target; - CodeGen *child_gen = codegen_create(full_path, child_target); + CodeGen *child_gen = codegen_create(full_path, child_target, OutTypeObj); child_gen->link_libc = parent_gen->link_libc; child_gen->link_libs.resize(parent_gen->link_libs.length); @@ -55,7 +55,6 @@ static Buf *build_o(CodeGen *parent_gen, const char *oname) { codegen_set_strip(child_gen, parent_gen->strip_debug_symbols); codegen_set_is_static(child_gen, parent_gen->is_static); - codegen_set_out_type(child_gen, OutTypeObj); codegen_set_out_name(child_gen, buf_create_from_str(oname)); codegen_set_verbose(child_gen, parent_gen->verbose); @@ -186,9 +185,10 @@ static void construct_linker_job_elf(LinkJob *lj) { } else if (shared) { lj->args.append("-shared"); - buf_resize(&lj->out_file, 0); - buf_appendf(&lj->out_file, "lib%s.so.%zu.%zu.%zu", - buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch); + if (buf_len(&lj->out_file) == 0) { + buf_appendf(&lj->out_file, "lib%s.so.%zu.%zu.%zu", + buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch); + } soname = buf_sprintf("lib%s.so.%zu", buf_ptr(g->root_out_name), g->version_major); } @@ -752,9 +752,6 @@ void codegen_link(CodeGen *g, const char *out_file) { } if (g->out_type == OutTypeObj) { - if (g->want_h_file) { - codegen_generate_h_file(g); - } if (override_out_file) { assert(g->link_objects.length == 1); Buf *o_file_path = g->link_objects.at(0); @@ -798,13 +795,6 @@ void codegen_link(CodeGen *g, const char *out_file) { fprintf(stderr, "%s\n", buf_ptr(&diag)); exit(1); } - codegen_add_time_event(g, "Generate .h"); - - if (g->out_type == OutTypeLib || - g->out_type == OutTypeObj) - { - codegen_generate_h_file(g); - } codegen_add_time_event(g, "Done"); diff --git a/src/main.cpp b/src/main.cpp index 27fb9a494d..89fa07cf56 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,6 +35,7 @@ static int usage(const char *arg0) { " --libc-include-dir [path] directory where libc stdlib.h resides\n" " --name [name] override output name\n" " --output [file] override destination path\n" + " --output-h [file] override generated header file path\n" " --release build with optimizations on and debug protection off\n" " --static output will be statically linked\n" " --strip exclude debug symbols\n" @@ -118,6 +119,8 @@ enum Cmd { CmdTargets, }; +static const char *default_zig_cache_name = "zig-cache"; + int main(int argc, char **argv) { os_init(); @@ -125,6 +128,7 @@ int main(int argc, char **argv) { Cmd cmd = CmdInvalid; const char *in_file = nullptr; const char *out_file = nullptr; + const char *out_file_h = nullptr; bool is_release_build = false; bool strip = false; bool is_static = false; @@ -163,7 +167,7 @@ int main(int argc, char **argv) { size_t ver_minor = 0; size_t ver_patch = 0; bool timing_info = false; - const char *cache_dir = "zig-cache"; + const char *cache_dir = nullptr; if (argc >= 2 && strcmp(argv[1], "build") == 0) { const char *zig_exe_path = arg0; @@ -200,9 +204,8 @@ int main(int argc, char **argv) { } } - CodeGen *g = codegen_create(build_runner_path, nullptr); + CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe); codegen_set_out_name(g, buf_create_from_str("build")); - codegen_set_out_type(g, OutTypeExe); codegen_set_verbose(g, verbose); Buf build_file_abs = BUF_INIT; @@ -212,7 +215,12 @@ int main(int argc, char **argv) { os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename); Buf *full_cache_dir = buf_alloc(); - os_path_resolve(buf_create_from_str("."), buf_create_from_str(cache_dir), full_cache_dir); + if (cache_dir == nullptr) { + os_path_join(&build_file_dirname, buf_create_from_str(default_zig_cache_name), full_cache_dir); + } else { + os_path_resolve(buf_create_from_str("."), buf_create_from_str(cache_dir), full_cache_dir); + } + Buf *path_to_build_exe = buf_alloc(); os_path_join(full_cache_dir, buf_create_from_str("build"), path_to_build_exe); codegen_set_cache_dir(g, full_cache_dir); @@ -309,6 +317,8 @@ int main(int argc, char **argv) { return usage(arg0); } else if (strcmp(arg, "--output") == 0) { out_file = argv[i]; + } else if (strcmp(arg, "--output-h") == 0) { + out_file_h = argv[i]; } else if (strcmp(arg, "--color") == 0) { if (strcmp(argv[i], "auto") == 0) { color = ErrColorAuto; @@ -396,6 +406,7 @@ int main(int argc, char **argv) { cmd = CmdParseH; } else if (strcmp(arg, "test") == 0) { cmd = CmdTest; + out_type = OutTypeExe; } else if (strcmp(arg, "targets") == 0) { cmd = CmdTargets; } else { @@ -495,9 +506,11 @@ int main(int argc, char **argv) { Buf *zig_root_source_file = (cmd == CmdParseH) ? nullptr : in_file_buf; Buf *full_cache_dir = buf_alloc(); - os_path_resolve(buf_create_from_str("."), buf_create_from_str(cache_dir), full_cache_dir); + os_path_resolve(buf_create_from_str("."), + buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir), + full_cache_dir); - CodeGen *g = codegen_create(zig_root_source_file, target); + CodeGen *g = codegen_create(zig_root_source_file, target, out_type); codegen_set_out_name(g, buf_out_name); codegen_set_lib_version(g, ver_major, ver_minor, ver_patch); codegen_set_is_release(g, is_release_build); @@ -510,11 +523,6 @@ int main(int argc, char **argv) { codegen_set_clang_argv(g, clang_argv.items, clang_argv.length); codegen_set_strip(g, strip); codegen_set_is_static(g, is_static); - if (out_type != OutTypeUnknown) { - codegen_set_out_type(g, out_type); - } else if (cmd == CmdTest) { - codegen_set_out_type(g, OutTypeExe); - } if (libc_lib_dir) codegen_set_libc_lib_dir(g, buf_create_from_str(libc_lib_dir)); if (libc_static_lib_dir) @@ -568,6 +576,9 @@ int main(int argc, char **argv) { codegen_set_test_name_prefix(g, buf_create_from_str(test_name_prefix)); } + if (out_file_h) + codegen_set_output_h_path(g, buf_create_from_str(out_file_h)); + if (cmd == CmdBuild) { for (size_t i = 0; i < objects.length; i += 1) { codegen_add_object(g, buf_create_from_str(objects.at(i))); diff --git a/std/build.zig b/std/build.zig index 60600b5ac0..5d001c0ac3 100644 --- a/std/build.zig +++ b/std/build.zig @@ -37,7 +37,6 @@ pub const Builder = struct { top_level_steps: List(&TopLevelStep), prefix: []const u8, lib_dir: []const u8, - out_dir: []u8, // TODO get rid of this installed_files: List([]const u8), build_root: []const u8, cache_root: []const u8, @@ -97,7 +96,6 @@ pub const Builder = struct { .env_map = %%os.getEnvMap(allocator), .prefix = undefined, .lib_dir = undefined, - .out_dir = %%os.getCwd(allocator), .installed_files = List([]const u8).init(allocator), .uninstall_tls = TopLevelStep { .step = Step.init("uninstall", allocator, makeUninstall), @@ -111,7 +109,6 @@ pub const Builder = struct { } pub fn deinit(self: &Builder) { - self.allocator.free(self.out_dir); self.lib_paths.deinit(); self.include_paths.deinit(); self.rpaths.deinit(); @@ -172,12 +169,10 @@ pub const Builder = struct { return exe; } - pub fn addCommand(self: &Builder, cwd: []const u8, env_map: &const BufMap, + pub fn addCommand(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap, path: []const u8, args: []const []const u8) -> &CommandStep { - const cmd = %%self.allocator.create(CommandStep); - *cmd = CommandStep.init(self, cwd, env_map, path, args); - return cmd; + return CommandStep.create(self, cwd, env_map, path, args); } pub fn addWriteFile(self: &Builder, file_path: []const u8, data: []const u8) -> &WriteFileStep { @@ -489,21 +484,22 @@ pub const Builder = struct { } fn spawnChild(self: &Builder, exe_path: []const u8, args: []const []const u8) -> %void { - return self.spawnChildEnvMap(&self.env_map, exe_path, args); + return self.spawnChildEnvMap(null, &self.env_map, exe_path, args); } - fn spawnChildEnvMap(self: &Builder, env_map: &const BufMap, exe_path: []const u8, - args: []const []const u8) -> %void + fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap, + exe_path: []const u8, args: []const []const u8) -> %void { if (self.verbose) { - %%io.stderr.printf("{}", exe_path); + test (cwd) |yes_cwd| %%io.stderr.print("cd {}; ", yes_cwd); + %%io.stderr.print("{}", exe_path); for (args) |arg| { - %%io.stderr.printf(" {}", arg); + %%io.stderr.print(" {}", arg); } %%io.stderr.printf("\n"); } - var child = os.ChildProcess.spawn(exe_path, args, env_map, + var child = os.ChildProcess.spawn(exe_path, args, cwd, env_map, StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator) %% |err| { %%io.stderr.printf("Unable to spawn {}: {}\n", exe_path, @errorName(err)); @@ -511,6 +507,7 @@ pub const Builder = struct { }; const term = child.wait() %% |err| { + test (cwd) |yes_cwd| %%io.stderr.printf("cwd: {}\n", yes_cwd); %%io.stderr.printf("Unable to spawn {}: {}\n", exe_path, @errorName(err)); return err; }; @@ -560,11 +557,12 @@ pub const Builder = struct { fn copyFile(self: &Builder, source_path: []const u8, dest_path: []const u8) { const dirname = os.path.dirname(dest_path); + const abs_source_path = self.pathFromRoot(source_path); os.makePath(self.allocator, dirname) %% |err| { debug.panic("Unable to create path {}: {}", dirname, @errorName(err)); }; - os.copyFile(self.allocator, source_path, dest_path) %% |err| { - debug.panic("Unable to copy {} to {}: {}", source_path, dest_path, @errorName(err)); + os.copyFile(self.allocator, abs_source_path, dest_path) %% |err| { + debug.panic("Unable to copy {} to {}: {}", abs_source_path, dest_path, @errorName(err)); }; } @@ -628,8 +626,10 @@ pub const LibExeObjStep = struct { release: bool, static: bool, output_path: ?[]const u8, + output_h_path: ?[]const u8, kind: Kind, version: Version, + out_h_filename: []const u8, out_filename: []const u8, out_filename_major_only: []const u8, out_filename_name_only: []const u8, @@ -684,8 +684,10 @@ pub const LibExeObjStep = struct { .link_libs = BufSet.init(builder.allocator), .step = Step.init(name, builder.allocator, make), .output_path = null, + .output_h_path = null, .version = *ver, .out_filename = undefined, + .out_h_filename = builder.fmt("{}.h", name), .out_filename_major_only = undefined, .out_filename_name_only = undefined, .object_files = List([]const u8).init(builder.allocator), @@ -747,6 +749,27 @@ pub const LibExeObjStep = struct { self.output_path = value; } + pub fn getOutputPath(self: &LibExeObjStep) -> []const u8 { + test (self.output_path) |output_path| { + output_path + } else { + const wanted_path = %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename); + %%os.path.relative(self.builder.allocator, self.builder.build_root, wanted_path) + } + } + + pub fn setOutputHPath(self: &LibExeObjStep, value: []const u8) { + self.output_h_path = value; + } + + pub fn getOutputHPath(self: &LibExeObjStep) -> []const u8 { + test (self.output_h_path) |output_h_path| { + output_h_path + } else { + %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_h_filename) + } + } + pub fn addAssemblyFile(self: &LibExeObjStep, path: []const u8) { %%self.assembly_files.append(path); } @@ -763,14 +786,7 @@ pub const LibExeObjStep = struct { self.step.dependOn(&obj.step); - const path_to_obj = test (obj.output_path) |explicit_out_path| { - explicit_out_path - } else { - // TODO make it so we always know where this will be - %%os.path.join(self.builder.allocator, self.builder.cache_root, - self.builder.fmt("{}{}", obj.name, obj.target.oFileExt())) - }; - %%self.object_files.append(path_to_obj); + %%self.object_files.append(obj.getOutputPath()); } fn make(step: &Step) -> %void { @@ -814,10 +830,16 @@ pub const LibExeObjStep = struct { %%zig_args.append("--release"); } - test (self.output_path) |output_path| { - %%zig_args.append("--output"); - %%zig_args.append(builder.pathFromRoot(output_path)); - } + %%zig_args.append("--cache-dir"); + %%zig_args.append(builder.cache_root); + + const output_path = builder.pathFromRoot(self.getOutputPath()); + %%zig_args.append("--output"); + %%zig_args.append(output_path); + + const output_h_path = self.getOutputHPath(); + %%zig_args.append("--output-h"); + %%zig_args.append(builder.pathFromRoot(output_h_path)); %%zig_args.append("--name"); %%zig_args.append(self.name); @@ -879,10 +901,8 @@ pub const LibExeObjStep = struct { %return builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); if (self.kind == Kind.Lib and !self.static) { - // sym link for libfoo.so.1 to libfoo.so.1.2.3 - %%os.atomicSymLink(builder.allocator, self.out_filename, self.out_filename_major_only); - // sym link for libfoo.so to libfoo.so.1 - %%os.atomicSymLink(builder.allocator, self.out_filename_major_only, self.out_filename_name_only); + %return doAtomicSymLinks(builder.allocator, output_path, self.out_filename_major_only, + self.out_filename_name_only); } } }; @@ -987,10 +1007,12 @@ pub const TestStep = struct { } }; +// TODO merge with CExecutable pub const CLibrary = struct { step: Step, name: []const u8, out_filename: []const u8, + output_path: ?[]const u8, static: bool, version: Version, cflags: List([]const u8), @@ -1024,6 +1046,7 @@ pub const CLibrary = struct { .step = Step.init(name, builder.allocator, make), .link_libs = BufSet.init(builder.allocator), .include_dirs = List([]const u8).init(builder.allocator), + .output_path = null, .out_filename = undefined, .major_only_filename = undefined, .name_only_filename = undefined, @@ -1043,6 +1066,19 @@ pub const CLibrary = struct { } } + pub fn setOutputPath(self: &CLibrary, value: []const u8) { + self.output_path = value; + } + + pub fn getOutputPath(self: &CLibrary) -> []const u8 { + test (self.output_path) |output_path| { + output_path + } else { + const wanted_path = %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename); + %%os.path.relative(self.builder.allocator, self.builder.build_root, wanted_path) + } + } + pub fn linkSystemLibrary(self: &CLibrary, name: []const u8) { %%self.link_libs.put(name); } @@ -1131,8 +1167,9 @@ pub const CLibrary = struct { defer builder.allocator.free(soname_arg); %%cc_args.append(soname_arg); + const output_path = builder.pathFromRoot(self.getOutputPath()); %%cc_args.append("-o"); - %%cc_args.append(self.out_filename); + %%cc_args.append(output_path); for (self.object_files.toSliceConst()) |object_file| { %%cc_args.append(builder.pathFromRoot(object_file)); @@ -1140,10 +1177,8 @@ pub const CLibrary = struct { %return builder.spawnChild(cc, cc_args.toSliceConst()); - // sym link for libfoo.so.1 to libfoo.so.1.2.3 - %%os.atomicSymLink(builder.allocator, self.out_filename, self.major_only_filename); - // sym link for libfoo.so to libfoo.so.1 - %%os.atomicSymLink(builder.allocator, self.major_only_filename, self.name_only_filename); + %return doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, + self.name_only_filename); } } @@ -1169,9 +1204,11 @@ pub const CExecutable = struct { link_libs: BufSet, target: Target, include_dirs: List([]const u8), + output_path: ?[]const u8, + out_filename: []const u8, pub fn init(builder: &Builder, name: []const u8) -> CExecutable { - CExecutable { + var self = CExecutable { .builder = builder, .name = name, .target = Target.Native, @@ -1182,6 +1219,27 @@ pub const CExecutable = struct { .step = Step.init(name, builder.allocator, make), .link_libs = BufSet.init(builder.allocator), .include_dirs = List([]const u8).init(builder.allocator), + .output_path = null, + .out_filename = undefined, + }; + self.computeOutFileName(); + return self; + } + + fn computeOutFileName(self: &CExecutable) { + self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt()); + } + + pub fn setOutputPath(self: &CExecutable, value: []const u8) { + self.output_path = value; + } + + pub fn getOutputPath(self: &CExecutable) -> []const u8 { + test (self.output_path) |output_path| { + self.builder.pathFromRoot(output_path) + } else { + const wanted_path = %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename); + %%os.path.relative(self.builder.allocator, self.builder.build_root, wanted_path) } } @@ -1191,15 +1249,15 @@ pub const CExecutable = struct { pub fn linkCLibrary(self: &CExecutable, clib: &CLibrary) { self.step.dependOn(&clib.step); - %%self.full_path_libs.append(clib.out_filename); + %%self.full_path_libs.append(clib.getOutputPath()); } pub fn linkLibrary(self: &CExecutable, lib: &LibExeObjStep) { assert(lib.kind == LibExeObjStep.Kind.Lib); self.step.dependOn(&lib.step); - %%self.full_path_libs.append(lib.out_filename); + %%self.full_path_libs.append(lib.getOutputPath()); // TODO should be some kind of isolated directory that only has this header in it - %%self.include_dirs.append(self.builder.out_dir); + %%self.include_dirs.append(self.builder.cache_root); } pub fn addObject(self: &CExecutable, obj: &LibExeObjStep) { @@ -1207,12 +1265,10 @@ pub const CExecutable = struct { self.step.dependOn(&obj.step); - // TODO make it so we always know where this will be - %%self.object_files.append(%%os.path.join(self.builder.allocator, self.builder.cache_root, - self.builder.fmt("{}{}", obj.name, obj.target.oFileExt()))); + %%self.object_files.append(obj.getOutputPath()); // TODO should be some kind of isolated directory that only has this header in it - %%self.include_dirs.append(self.builder.out_dir); + %%self.include_dirs.append(self.builder.cache_root); } pub fn addSourceFile(self: &CExecutable, file: []const u8) { @@ -1256,7 +1312,6 @@ pub const CExecutable = struct { %%cc_args.append("-c"); %%cc_args.append(builder.pathFromRoot(source_file)); - // TODO don't dump the .o file in the same place as the source file const rel_src_path = %%os.path.relative(builder.allocator, builder.build_root, source_file); const cache_o_src = %%os.path.join(builder.allocator, builder.cache_root, rel_src_path); const cache_o_dir = os.path.dirname(cache_o_src); @@ -1276,26 +1331,28 @@ pub const CExecutable = struct { %return builder.spawnChild(cc, cc_args.toSliceConst()); - %%self.object_files.append(cache_o_file); + %%self.object_files.append(%%os.path.relative(builder.allocator, builder.build_root, cache_o_file)); } %%cc_args.resize(0); for (self.object_files.toSliceConst()) |object_file| { - %%cc_args.append(object_file); + %%cc_args.append(builder.pathFromRoot(object_file)); } + const output_path = builder.pathFromRoot(self.getOutputPath()); %%cc_args.append("-o"); - %%cc_args.append(self.name); + %%cc_args.append(output_path); - const rpath_arg = builder.fmt("-Wl,-rpath,{}", builder.out_dir); + const rpath_arg = builder.fmt("-Wl,-rpath,{}", + %%os.path.real(builder.allocator, builder.cache_root)); defer builder.allocator.free(rpath_arg); %%cc_args.append(rpath_arg); %%cc_args.append("-rdynamic"); for (self.full_path_libs.toSliceConst()) |full_path_lib| { - %%cc_args.append(full_path_lib); + %%cc_args.append(builder.pathFromRoot(full_path_lib)); } %return builder.spawnChild(cc, cc_args.toSliceConst()); @@ -1317,27 +1374,29 @@ pub const CommandStep = struct { builder: &Builder, exe_path: []const u8, args: []const []const u8, - cwd: []const u8, + cwd: ?[]const u8, env_map: &const BufMap, - pub fn init(builder: &Builder, cwd: []const u8, env_map: &const BufMap, - exe_path: []const u8, args: []const []const u8) -> CommandStep + pub fn create(builder: &Builder, cwd: ?[]const u8, env_map: &const BufMap, + exe_path: []const u8, args: []const []const u8) -> &CommandStep { - CommandStep { + const self = %%builder.allocator.create(CommandStep); + *self = CommandStep { .builder = builder, .step = Step.init(exe_path, builder.allocator, make), .exe_path = exe_path, .args = args, .cwd = cwd, .env_map = env_map, - } + }; + return self; } fn make(step: &Step) -> %void { const self = @fieldParentPtr(CommandStep, "step", step); - // TODO set cwd - return self.builder.spawnChildEnvMap(self.env_map, self.exe_path, self.args); + const cwd = test (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else null; + return self.builder.spawnChildEnvMap(cwd, self.env_map, self.exe_path, self.args); } }; @@ -1367,12 +1426,10 @@ pub const InstallCLibraryStep = struct { const self = @fieldParentPtr(InstallCLibraryStep, "step", step); const builder = self.builder; - self.builder.copyFile(self.lib.out_filename, self.dest_file); + self.builder.copyFile(self.lib.getOutputPath(), self.dest_file); if (!self.lib.static) { - const dest_major_only = %%os.path.join(builder.allocator, builder.lib_dir, self.lib.major_only_filename); - const dest_name_only = %%os.path.join(builder.allocator, builder.lib_dir, self.lib.name_only_filename); - %%os.atomicSymLink(self.builder.allocator, self.lib.out_filename, dest_major_only); - %%os.atomicSymLink(self.builder.allocator, self.lib.major_only_filename, dest_name_only); + %return doAtomicSymLinks(self.builder.allocator, self.dest_file, self.lib.major_only_filename, + self.lib.name_only_filename); } } }; @@ -1506,3 +1563,22 @@ pub const Step = struct { fn makeNoOp(self: &Step) -> %void {} }; + +fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_major_only: []const u8, + filename_name_only: []const u8) -> %void +{ + const out_dir = os.path.dirname(output_path); + const out_basename = os.path.basename(output_path); + // sym link for libfoo.so.1 to libfoo.so.1.2.3 + const major_only_path = %%os.path.join(allocator, out_dir, filename_major_only); + os.atomicSymLink(allocator, out_basename, major_only_path) %% |err| { + %%io.stderr.printf("Unable to symlink {} -> {}\n", major_only_path, out_basename); + return err; + }; + // sym link for libfoo.so to libfoo.so.1 + const name_only_path = %%os.path.join(allocator, out_dir, filename_name_only); + os.atomicSymLink(allocator, filename_major_only, name_only_path) %% |err| { + %%io.stderr.printf("Unable to symlink {} -> {}\n", name_only_path, filename_major_only); + return err; + }; +} diff --git a/std/fmt.zig b/std/fmt.zig index 0a5a97a3f1..fa01f936c2 100644 --- a/std/fmt.zig +++ b/std/fmt.zig @@ -345,17 +345,17 @@ fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) -> bool { return true; } -pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) { +pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) -> []u8 { var context = BufPrintContext { .remaining = buf, }; _ = format(&context, bufPrintWrite, fmt, args); + return buf[0...buf.len - context.remaining.len]; } pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...) -> %[]u8 { var size: usize = 0; _ = format(&size, countSize, fmt, args); const buf = %return allocator.alloc(u8, size); - bufPrint(buf, fmt, args); - return buf; + return bufPrint(buf, fmt, args); } fn countSize(size: &usize, bytes: []const u8) -> bool { diff --git a/std/os/child_process.zig b/std/os/child_process.zig index bb5b2eb187..cfd09f2b7b 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -30,12 +30,13 @@ pub const ChildProcess = struct { Close, }; - pub fn spawn(exe_path: []const u8, args: []const []const u8, env_map: &const BufMap, + pub fn spawn(exe_path: []const u8, args: []const []const u8, + cwd: ?[]const u8, env_map: &const BufMap, stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess { switch (@compileVar("os")) { Os.linux, Os.macosx, Os.ios, Os.darwin => { - return spawnPosix(exe_path, args, env_map, stdin, stdout, stderr, allocator); + return spawnPosix(exe_path, args, cwd, env_map, stdin, stdout, stderr, allocator); }, else => @compileError("Unsupported OS"), } @@ -98,7 +99,8 @@ pub const ChildProcess = struct { }; } - fn spawnPosix(exe_path: []const u8, args: []const []const u8, env_map: &const BufMap, + fn spawnPosix(exe_path: []const u8, args: []const []const u8, + maybe_cwd: ?[]const u8, env_map: &const BufMap, stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess { // TODO issue #295 @@ -155,6 +157,11 @@ pub const ChildProcess = struct { setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %% |err| forkChildErrReport(err_pipe[1], err); + test (maybe_cwd) |cwd| { + os.changeCurDir(allocator, cwd) %% + |err| forkChildErrReport(err_pipe[1], err); + } + os.posixExecve(exe_path, args, env_map, allocator) %% |err| forkChildErrReport(err_pipe[1], err); } diff --git a/std/os/index.zig b/std/os/index.zig index ec32b60d84..209bf1b863 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -780,3 +780,60 @@ pub const Dir = struct { }; } }; + +pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) -> %void { + const path_buf = %return allocator.alloc(u8, dir_path.len + 1); + defer allocator.free(path_buf); + + mem.copy(u8, path_buf, dir_path); + path_buf[dir_path.len] = 0; + + const err = posix.getErrno(posix.chdir(path_buf.ptr)); + if (err > 0) { + return switch (err) { + errno.EACCES => error.AccessDenied, + errno.EFAULT => unreachable, + errno.EIO => error.FileSystem, + errno.ELOOP => error.SymLinkLoop, + errno.ENAMETOOLONG => error.NameTooLong, + errno.ENOENT => error.FileNotFound, + errno.ENOMEM => error.SystemResources, + errno.ENOTDIR => error.NotDir, + else => error.Unexpected, + }; + } +} + +/// Read value of a symbolic link. +pub fn readLink(allocator: &Allocator, pathname: []const u8) -> %[]u8 { + const path_buf = %return allocator.alloc(u8, pathname.len + 1); + defer allocator.free(path_buf); + + mem.copy(u8, path_buf, pathname); + path_buf[pathname.len] = 0; + + var result_buf = %return allocator.alloc(u8, 1024); + %defer allocator.free(result_buf); + while (true) { + const ret_val = posix.readlink(path_buf.ptr, result_buf.ptr, result_buf.len); + const err = posix.getErrno(ret_val); + if (err > 0) { + return switch (err) { + errno.EACCES => error.AccessDenied, + errno.EFAULT, errno.EINVAL => unreachable, + errno.EIO => error.FileSystem, + errno.ELOOP => error.SymLinkLoop, + errno.ENAMETOOLONG => error.NameTooLong, + errno.ENOENT => error.FileNotFound, + errno.ENOMEM => error.SystemResources, + errno.ENOTDIR => error.NotDir, + else => error.Unexpected, + }; + } + if (ret_val == result_buf.len) { + result_buf = %return allocator.realloc(u8, result_buf, result_buf.len * 2); + continue; + } + return result_buf[0...ret_val]; + } +} diff --git a/std/os/linux.zig b/std/os/linux.zig index 6db552e640..662ebed4be 100644 --- a/std/os/linux.zig +++ b/std/os/linux.zig @@ -335,6 +335,10 @@ pub fn dup2(old: i32, new: i32) -> usize { arch.syscall2(arch.SYS_dup2, usize(old), usize(new)) } +pub fn chdir(path: &const u8) -> usize { + arch.syscall1(arch.SYS_chdir, usize(path)) +} + pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) -> usize { arch.syscall3(arch.SYS_execve, usize(path), usize(argv), usize(envp)) } @@ -356,6 +360,10 @@ pub fn isatty(fd: i32) -> bool { return arch.syscall3(arch.SYS_ioctl, usize(fd), TIOCGWINSZ, usize(&wsz)) == 0; } +pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) -> usize { + arch.syscall3(arch.SYS_readlink, usize(path), usize(buf_ptr), buf_len) +} + pub fn mkdir(path: &const u8, mode: usize) -> usize { arch.syscall2(arch.SYS_mkdir, usize(path), mode) } diff --git a/std/os/path.zig b/std/os/path.zig index b3de010d43..604d8f5073 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -1,9 +1,11 @@ const debug = @import("../debug.zig"); const assert = debug.assert; const mem = @import("../mem.zig"); +const fmt = @import("../fmt.zig"); const Allocator = mem.Allocator; const os = @import("index.zig"); const math = @import("../math.zig"); +const posix = os.posix; pub const sep = switch (@compileVar("os")) { Os.windows => '\\', @@ -185,6 +187,45 @@ fn testDirname(input: []const u8, expected_output: []const u8) { assert(mem.eql(u8, dirname(input), expected_output)); } +pub fn basename(path: []const u8) -> []const u8 { + if (path.len == 0) + return []u8{}; + + var end_index: usize = path.len - 1; + while (path[end_index] == '/') { + if (end_index == 0) + return []u8{}; + end_index -= 1; + } + var start_index: usize = end_index; + end_index += 1; + while (path[start_index] != '/') { + if (start_index == 0) + return path[0...end_index]; + start_index -= 1; + } + + return path[start_index + 1...end_index]; +} + +test "os.path.basename" { + testBasename("", ""); + testBasename("/", ""); + testBasename("/dir/basename.ext", "basename.ext"); + testBasename("/basename.ext", "basename.ext"); + testBasename("basename.ext", "basename.ext"); + testBasename("basename.ext/", "basename.ext"); + testBasename("basename.ext//", "basename.ext"); + testBasename("/aaa/bbb", "bbb"); + testBasename("/aaa/", "aaa"); + testBasename("/aaa/b", "b"); + testBasename("/a/b", "b"); + testBasename("//a", "a"); +} +fn testBasename(input: []const u8, expected_output: []const u8) { + assert(mem.eql(u8, basename(input), expected_output)); +} + /// Returns the relative path from ::from to ::to. If ::from and ::to each /// resolve to the same path (after calling ::resolve on each), a zero-length /// string is returned. @@ -252,3 +293,17 @@ fn testRelative(from: []const u8, to: []const u8, expected_output: []const u8) { const result = %%relative(&debug.global_allocator, from, to); assert(mem.eql(u8, result, expected_output)); } + +/// Return the canonicalized absolute pathname. +/// Expands all symbolic links and resolves references to `.`, `..`, and +/// extra `/` characters in ::pathname. +/// Caller must deallocate result. +pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 { + const fd = %return os.posixOpen(pathname, posix.O_PATH|posix.O_NONBLOCK|posix.O_CLOEXEC, 0, allocator); + defer os.posixClose(fd); + + var buf: ["/proc/self/fd/-2147483648".len]u8 = undefined; + const proc_path = fmt.bufPrint(buf[0...], "/proc/self/fd/{}", fd); + + return os.readLink(allocator, proc_path); +} diff --git a/test/tests.zig b/test/tests.zig index c532db71b8..837dcac08e 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -189,7 +189,7 @@ pub const CompareOutputContext = struct { %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name); - var child = os.ChildProcess.spawn(full_exe_path, [][]u8{}, &b.env_map, + var child = os.ChildProcess.spawn(full_exe_path, [][]u8{}, null, &b.env_map, StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, b.allocator) %% |err| { debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); @@ -264,7 +264,7 @@ pub const CompareOutputContext = struct { %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name); - var child = os.ChildProcess.spawn(full_exe_path, [][]u8{}, &b.env_map, + var child = os.ChildProcess.spawn(full_exe_path, [][]u8{}, null, &b.env_map, StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, b.allocator) %% |err| { debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); @@ -344,8 +344,8 @@ pub const CompareOutputContext = struct { pub fn addCase(self: &CompareOutputContext, case: &const TestCase) { const b = self.b; - const root_src = %%os.path.join(b.allocator, "test_artifacts", case.sources.items[0].filename); - const exe_path = %%os.path.join(b.allocator, "test_artifacts", "test"); + const root_src = %%os.path.join(b.allocator, b.cache_root, case.sources.items[0].filename); + const exe_path = %%os.path.join(b.allocator, b.cache_root, "test"); switch (case.special) { Special.Asm => { @@ -360,7 +360,7 @@ pub const CompareOutputContext = struct { exe.setOutputPath(exe_path); for (case.sources.toSliceConst()) |src_file| { - const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename); + const expanded_src_path = %%os.path.join(b.allocator, b.cache_root, src_file.filename); const write_src = b.addWriteFile(expanded_src_path, src_file.source); exe.step.dependOn(&write_src.step); } @@ -388,7 +388,7 @@ pub const CompareOutputContext = struct { } for (case.sources.toSliceConst()) |src_file| { - const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename); + const expanded_src_path = %%os.path.join(b.allocator, b.cache_root, src_file.filename); const write_src = b.addWriteFile(expanded_src_path, src_file.source); exe.step.dependOn(&write_src.step); } @@ -401,7 +401,7 @@ pub const CompareOutputContext = struct { } }, Special.DebugSafety => { - const obj_path = %%os.path.join(b.allocator, "test_artifacts", "test.o"); + const obj_path = %%os.path.join(b.allocator, b.cache_root, "test.o"); const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "debug-safety {}", case.name); test (self.test_filter) |filter| { if (mem.indexOf(u8, annotated_case_name, filter) == null) @@ -415,7 +415,7 @@ pub const CompareOutputContext = struct { } for (case.sources.toSliceConst()) |src_file| { - const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename); + const expanded_src_path = %%os.path.join(b.allocator, b.cache_root, src_file.filename); const write_src = b.addWriteFile(expanded_src_path, src_file.source); exe.step.dependOn(&write_src.step); } @@ -488,8 +488,8 @@ pub const CompileErrorContext = struct { const self = @fieldParentPtr(CompileCmpOutputStep, "step", step); const b = self.context.b; - const root_src = %%os.path.join(b.allocator, "test_artifacts", self.case.sources.items[0].filename); - const obj_path = %%os.path.join(b.allocator, "test_artifacts", "test.o"); + const root_src = %%os.path.join(b.allocator, b.cache_root, self.case.sources.items[0].filename); + const obj_path = %%os.path.join(b.allocator, b.cache_root, "test.o"); var zig_args = List([]const u8).init(b.allocator); %%zig_args.append(if (self.case.is_exe) "build_exe" else "build_obj"); @@ -511,7 +511,7 @@ pub const CompileErrorContext = struct { printInvocation(b.zig_exe, zig_args.toSliceConst()); } - var child = os.ChildProcess.spawn(b.zig_exe, zig_args.toSliceConst(), &b.env_map, + var child = os.ChildProcess.spawn(b.zig_exe, zig_args.toSliceConst(), null, &b.env_map, StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, b.allocator) %% |err| { debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err)); @@ -632,7 +632,7 @@ pub const CompileErrorContext = struct { self.step.dependOn(&compile_and_cmp_errors.step); for (case.sources.toSliceConst()) |src_file| { - const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename); + const expanded_src_path = %%os.path.join(b.allocator, b.cache_root, src_file.filename); const write_src = b.addWriteFile(expanded_src_path, src_file.source); compile_and_cmp_errors.step.dependOn(&write_src.step); } @@ -675,7 +675,7 @@ pub const BuildExamplesContext = struct { %%zig_args.append("--verbose"); } - const run_cmd = b.addCommand(b.cache_root, b.env_map, b.zig_exe, zig_args.toSliceConst()); + const run_cmd = b.addCommand(null, b.env_map, b.zig_exe, zig_args.toSliceConst()); const log_step = b.addLog("PASS {}\n", annotated_case_name); log_step.step.dependOn(&run_cmd.step); @@ -762,7 +762,7 @@ pub const ParseHContext = struct { const self = @fieldParentPtr(ParseHCmpOutputStep, "step", step); const b = self.context.b; - const root_src = %%os.path.join(b.allocator, "test_artifacts", self.case.sources.items[0].filename); + const root_src = %%os.path.join(b.allocator, b.cache_root, self.case.sources.items[0].filename); var zig_args = List([]const u8).init(b.allocator); %%zig_args.append("parseh"); @@ -774,7 +774,7 @@ pub const ParseHContext = struct { printInvocation(b.zig_exe, zig_args.toSliceConst()); } - var child = os.ChildProcess.spawn(b.zig_exe, zig_args.toSliceConst(), &b.env_map, + var child = os.ChildProcess.spawn(b.zig_exe, zig_args.toSliceConst(), null, &b.env_map, StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, b.allocator) %% |err| { debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err)); @@ -886,7 +886,7 @@ pub const ParseHContext = struct { self.step.dependOn(&parseh_and_cmp.step); for (case.sources.toSliceConst()) |src_file| { - const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename); + const expanded_src_path = %%os.path.join(b.allocator, b.cache_root, src_file.filename); const write_src = b.addWriteFile(expanded_src_path, src_file.source); parseh_and_cmp.step.dependOn(&write_src.step); }