From a147f065850af8f9422d19d14aec0476b641cb07 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 28 Apr 2017 02:22:12 -0400 Subject: [PATCH] zig puts temporary object files in zig-cache folder See #298 --- src/all_types.hpp | 2 ++ src/codegen.cpp | 18 +++++++++++--- src/codegen.hpp | 1 + src/error.cpp | 2 ++ src/error.hpp | 4 ++- src/link.cpp | 10 +++++--- src/main.cpp | 26 ++++++++++++++++--- src/os.cpp | 48 ++++++++++++++++++++++++++++++++++++ src/os.hpp | 3 +++ std/build.zig | 12 ++++++--- std/special/build_runner.zig | 13 +++++++++- test/tests.zig | 2 +- 12 files changed, 124 insertions(+), 17 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 6c3351ac9b..23282a4a28 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1486,6 +1486,8 @@ struct CodeGen { Buf *test_name_prefix; ZigList timing_events; + + Buf *cache_dir; }; enum VarLinkage { diff --git a/src/codegen.cpp b/src/codegen.cpp index 2b48450711..a57ff40be3 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -204,6 +204,10 @@ void codegen_set_out_name(CodeGen *g, Buf *out_name) { g->root_out_name = out_name; } +void codegen_set_cache_dir(CodeGen *g, Buf *cache_dir) { + g->cache_dir = cache_dir; +} + void codegen_set_libc_lib_dir(CodeGen *g, Buf *libc_lib_dir) { g->libc_lib_dir = libc_lib_dir; } @@ -3910,16 +3914,22 @@ static void do_code_gen(CodeGen *g) { codegen_add_time_event(g, "LLVM Emit Object"); char *err_msg = nullptr; - Buf *out_file_o = buf_create_from_buf(g->root_out_name); + Buf *o_basename = buf_create_from_buf(g->root_out_name); const char *o_ext = target_o_file_ext(&g->zig_target); - buf_append_str(out_file_o, o_ext); - if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(out_file_o), + buf_append_str(o_basename, o_ext); + Buf *output_path = buf_alloc(); + os_path_join(g->cache_dir, o_basename, output_path); + int err; + if ((err = os_make_path(g->cache_dir))) { + zig_panic("unable to make cache dir: %s", err_str(err)); + } + if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), LLVMObjectFile, &err_msg, !g->is_release_build)) { zig_panic("unable to write object file: %s", err_msg); } - g->link_objects.append(out_file_o); + g->link_objects.append(output_path); } static const uint8_t int_sizes_in_bits[] = { diff --git a/src/codegen.hpp b/src/codegen.hpp index 0eac029a06..22818c33df 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -47,6 +47,7 @@ void codegen_set_omit_zigrt(CodeGen *g, bool omit_zigrt); 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_add_time_event(CodeGen *g, const char *name); void codegen_print_timing_report(CodeGen *g, FILE *f); void codegen_build(CodeGen *g); diff --git a/src/error.cpp b/src/error.cpp index baa883aeb1..bc4f9feba2 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -21,6 +21,8 @@ const char *err_str(int err) { case ErrorFileTooBig: return "file too big"; case ErrorDivByZero: return "division by zero"; case ErrorOverflow: return "overflow"; + case ErrorPathAlreadyExists: return "path already exists"; + case ErrorUnexpected: return "unexpected error"; } return "(invalid error)"; } diff --git a/src/error.hpp b/src/error.hpp index 7fea3ccfbb..7619f1c856 100644 --- a/src/error.hpp +++ b/src/error.hpp @@ -20,7 +20,9 @@ enum Error { ErrorFileSystem, ErrorFileTooBig, ErrorDivByZero, - ErrorOverflow + ErrorOverflow, + ErrorPathAlreadyExists, + ErrorUnexpected, }; const char *err_str(int err); diff --git a/src/link.cpp b/src/link.cpp index a771b5c6aa..e3179680f9 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -48,6 +48,8 @@ static Buf *build_o(CodeGen *parent_gen, const char *oname) { codegen_set_omit_zigrt(child_gen, true); child_gen->want_h_file = false; + codegen_set_cache_dir(child_gen, parent_gen->cache_dir); + codegen_set_is_release(child_gen, parent_gen->is_release_build); codegen_set_strip(child_gen, parent_gen->strip_debug_symbols); @@ -64,10 +66,12 @@ static Buf *build_o(CodeGen *parent_gen, const char *oname) { codegen_build(child_gen); const char *o_ext = target_o_file_ext(&child_gen->zig_target); - Buf *o_out = buf_sprintf("%s%s", oname, o_ext); - codegen_link(child_gen, buf_ptr(o_out)); + Buf *o_out_name = buf_sprintf("%s%s", oname, o_ext); + Buf *output_path = buf_alloc(); + os_path_join(parent_gen->cache_dir, o_out_name, output_path); + codegen_link(child_gen, buf_ptr(output_path)); - return o_out; + return output_path; } static const char *get_exe_file_extension(CodeGen *g) { diff --git a/src/main.cpp b/src/main.cpp index 4df56066d2..27fb9a494d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,6 +29,7 @@ static int usage(const char *arg0) { " version print version number and exit\n" "Compile Options:\n" " --assembly [source] add assembly file to build\n" + " --cache-dir [path] override the cache directory\n" " --color [auto|off|on] enable or disable colored error messages\n" " --enable-timing-info print timing diagnostics\n" " --libc-include-dir [path] directory where libc stdlib.h resides\n" @@ -162,6 +163,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"; if (argc >= 2 && strcmp(argv[1], "build") == 0) { const char *zig_exe_path = arg0; @@ -180,6 +182,7 @@ int main(int argc, char **argv) { ZigList args = {0}; args.append(zig_exe_path); args.append(NULL); // placeholder + args.append(NULL); // placeholder for (int i = 2; i < argc; i += 1) { if (strcmp(argv[i], "--debug-build-verbose") == 0) { verbose = true; @@ -189,6 +192,9 @@ int main(int argc, char **argv) { } else if (i + 1 < argc && strcmp(argv[i], "--build-file") == 0) { build_file = argv[i + 1]; i += 1; + } else if (i + 1 < argc && strcmp(argv[i], "--cache-dir") == 0) { + cache_dir = argv[i + 1]; + i += 1; } else { args.append(argv[i]); } @@ -205,7 +211,14 @@ int main(int argc, char **argv) { Buf build_file_dirname = BUF_INIT; 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); + 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); + args.items[1] = buf_ptr(&build_file_dirname); + args.items[2] = buf_ptr(full_cache_dir); bool build_file_exists; if ((err = os_file_exists(&build_file_abs, &build_file_exists))) { @@ -221,6 +234,7 @@ int main(int argc, char **argv) { "General Options:\n" " --help Print this help and exit\n" " --build-file [file] Override path to build.zig\n" + " --cache-dir [path] Override path to cache directory\n" " --verbose Print commands before executing them\n" " --debug-build-verbose Print verbose debugging information for the build system itself\n" " --prefix [prefix] Override default install prefix\n" @@ -245,13 +259,13 @@ int main(int argc, char **argv) { build_pkg->package_table.put(buf_create_from_str("std"), g->std_package); g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg); codegen_build(g); - codegen_link(g, "build"); + codegen_link(g, buf_ptr(path_to_build_exe)); Termination term; - os_spawn_process("./build", args, &term); + os_spawn_process(buf_ptr(path_to_build_exe), args, &term); if (term.how != TerminationIdClean || term.code != 0) { fprintf(stderr, "\nBuild failed. Use the following command to reproduce the failure:\n"); - fprintf(stderr, "./build"); + fprintf(stderr, "%s", buf_ptr(path_to_build_exe)); for (size_t i = 0; i < args.length; i += 1) { fprintf(stderr, " %s", args.at(i)); } @@ -331,6 +345,8 @@ int main(int argc, char **argv) { objects.append(argv[i]); } else if (strcmp(arg, "--assembly") == 0) { asm_files.append(argv[i]); + } else if (strcmp(arg, "--cache-dir") == 0) { + cache_dir = argv[i]; } else if (strcmp(arg, "--target-arch") == 0) { target_arch = argv[i]; } else if (strcmp(arg, "--target-os") == 0) { @@ -478,12 +494,16 @@ 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); + CodeGen *g = codegen_create(zig_root_source_file, target); 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); codegen_set_is_test(g, cmd == CmdTest); codegen_set_linker_script(g, linker_script); + codegen_set_cache_dir(g, full_cache_dir); if (each_lib_rpath) codegen_set_each_lib_rpath(g, each_lib_rpath); diff --git a/src/os.cpp b/src/os.cpp index adf723c445..8ad4d6639d 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -723,3 +723,51 @@ double os_get_time(void) { return seconds; #endif } + +int os_make_path(Buf *path) { + Buf *resolved_path = buf_alloc(); + os_path_resolve(buf_create_from_str("."), path, resolved_path); + + size_t end_index = buf_len(resolved_path); + int err; + while (true) { + if ((err = os_make_dir(buf_slice(resolved_path, 0, end_index)))) { + if (err == ErrorPathAlreadyExists) { + if (end_index == buf_len(resolved_path)) + return 0; + } else if (err == ErrorFileNotFound) { + // march end_index backward until next path component + while (true) { + end_index -= 1; + if (buf_ptr(resolved_path)[end_index] == '/') + break; + } + continue; + } else { + return err; + } + } + if (end_index == buf_len(resolved_path)) + return 0; + // march end_index forward until next path component + while (true) { + end_index += 1; + if (end_index == buf_len(resolved_path) || buf_ptr(resolved_path)[end_index] == '/') + break; + } + } + return 0; +} + +int os_make_dir(Buf *path) { + if (mkdir(buf_ptr(path), 0755) == -1) { + if (errno == EEXIST) + return ErrorPathAlreadyExists; + if (errno == ENOENT) + return ErrorFileNotFound; + if (errno == EACCES) + return ErrorAccess; + return ErrorUnexpected; + } + return 0; +} diff --git a/src/os.hpp b/src/os.hpp index 6187d0aca0..6e2ed6bf96 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -40,6 +40,9 @@ int os_path_real(Buf *rel_path, Buf *out_abs_path); void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path); bool os_path_is_absolute(Buf *path); +int os_make_path(Buf *path); +int os_make_dir(Buf *path); + void os_write_file(Buf *full_path, Buf *contents); int os_copy_file(Buf *src_path, Buf *dest_path); diff --git a/std/build.zig b/std/build.zig index c4657671ee..fa22d53044 100644 --- a/std/build.zig +++ b/std/build.zig @@ -37,9 +37,10 @@ pub const Builder = struct { top_level_steps: List(&TopLevelStep), prefix: []const u8, lib_dir: []const u8, - out_dir: []u8, + out_dir: []u8, // TODO get rid of this installed_files: List([]const u8), build_root: []const u8, + cache_root: []const u8, const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8); const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8); @@ -75,10 +76,13 @@ pub const Builder = struct { description: []const u8, }; - pub fn init(allocator: &Allocator, zig_exe: []const u8, build_root: []const u8) -> Builder { + pub fn init(allocator: &Allocator, zig_exe: []const u8, build_root: []const u8, + cache_root: []const u8) -> Builder + { var self = Builder { .zig_exe = zig_exe, .build_root = build_root, + .cache_root = cache_root, .verbose = false, .invalid_user_input = false, .allocator = allocator, @@ -768,7 +772,7 @@ pub const LibExeObjStep = struct { explicit_out_path } else { // TODO make it so we always know where this will be - %%os.path.join(self.builder.allocator, self.builder.out_dir, + %%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); @@ -1217,7 +1221,7 @@ 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.out_dir, + %%self.object_files.append(%%os.path.join(self.builder.allocator, self.builder.cache_root, self.builder.fmt("{}{}", obj.name, obj.target.oFileExt()))); // TODO should be some kind of isolated directory that only has this header in it diff --git a/std/special/build_runner.zig b/std/special/build_runner.zig index 5b412d83d6..a374194fe3 100644 --- a/std/special/build_runner.zig +++ b/std/special/build_runner.zig @@ -32,13 +32,23 @@ pub fn main() -> %void { result }; + const cache_root = { + if (arg_i >= os.args.count()) { + %%io.stderr.printf("Expected third argument to be cache root directory path\n"); + return error.InvalidArgs; + } + const result = os.args.at(arg_i); + arg_i += 1; + result + }; + // TODO use a more general purpose allocator here var inc_allocator = %%mem.IncrementingAllocator.init(10 * 1024 * 1024); defer inc_allocator.deinit(); const allocator = &inc_allocator.allocator; - var builder = Builder.init(allocator, zig_exe, build_root); + var builder = Builder.init(allocator, zig_exe, build_root, cache_root); defer builder.deinit(); var targets = List([]const u8).init(allocator); @@ -113,6 +123,7 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) \\General Options: \\ --help Print this help and exit \\ --build-file [file] Override path to build.zig + \\ --cache-dir [path] Override path to cache directory \\ --verbose Print commands before executing them \\ --debug-build-verbose Print verbose debugging information for the build system itself \\ --prefix [prefix] Override default install prefix diff --git a/test/tests.zig b/test/tests.zig index b89a47eff7..c532db71b8 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -675,7 +675,7 @@ pub const BuildExamplesContext = struct { %%zig_args.append("--verbose"); } - const run_cmd = b.addCommand(b.out_dir, b.env_map, b.zig_exe, zig_args.toSliceConst()); + const run_cmd = b.addCommand(b.cache_root, 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);