diff options
Diffstat (limited to 'src/codegen.cpp')
| -rw-r--r-- | src/codegen.cpp | 589 |
1 files changed, 396 insertions, 193 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp index 9a8864b87a..87974b7778 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -89,7 +89,8 @@ static const char *symbols_that_llvm_depends_on[] = { }; CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, - OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, Buf *override_std_dir, ZigLibCInstallation *libc) + OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, Buf *override_std_dir, + ZigLibCInstallation *libc, Buf *cache_dir) { CodeGen *g = allocate<CodeGen>(1); @@ -98,6 +99,7 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget g->libc = libc; g->zig_lib_dir = zig_lib_dir; g->zig_target = target; + g->cache_dir = cache_dir; if (override_std_dir == nullptr) { g->zig_std_dir = buf_alloc(); @@ -188,6 +190,9 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget g->link_libs_list.append(g->libc_link_lib); } + get_target_triple(&g->triple_str, g->zig_target); + g->pointer_size_bytes = target_arch_pointer_bit_width(g->zig_target->arch) / 8; + return g; } @@ -235,10 +240,6 @@ void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type) { g->emit_file_type = emit_file_type; } -void codegen_set_is_static(CodeGen *g, bool is_static) { - g->is_static = is_static; -} - void codegen_set_each_lib_rpath(CodeGen *g, bool each_lib_rpath) { g->each_lib_rpath = each_lib_rpath; } @@ -255,6 +256,10 @@ void codegen_set_out_name(CodeGen *g, Buf *out_name) { g->root_out_name = out_name; } +void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker_path) { + g->dynamic_linker_path = dynamic_linker_path; +} + void codegen_add_lib_dir(CodeGen *g, const char *dir) { g->lib_dirs.append(dir); } @@ -7780,16 +7785,6 @@ static void init(CodeGen *g) { if (g->module) return; - if (g->llvm_argv_len > 0) { - const char **args = allocate_nonzero<const char *>(g->llvm_argv_len + 2); - args[0] = "zig (LLVM option parsing)"; - for (size_t i = 0; i < g->llvm_argv_len; i += 1) { - args[i + 1] = g->llvm_argv[i]; - } - args[g->llvm_argv_len + 1] = nullptr; - ZigLLVMParseCommandLineOptions(g->llvm_argv_len + 1, args); - } - if (g->is_test_build) { g->subsystem = TargetSubsystemConsole; } @@ -7797,8 +7792,6 @@ static void init(CodeGen *g) { assert(g->root_out_name); g->module = LLVMModuleCreateWithName(buf_ptr(g->root_out_name)); - get_target_triple(&g->triple_str, g->zig_target); - LLVMSetTarget(g->module, buf_ptr(&g->triple_str)); if (target_object_format(g->zig_target) == ZigLLVM_COFF) { @@ -7854,7 +7847,7 @@ static void init(CodeGen *g) { LLVMSetDataLayout(g->module, layout_str); - g->pointer_size_bytes = LLVMPointerSize(g->target_data_ref); + assert(g->pointer_size_bytes == LLVMPointerSize(g->target_data_ref)); g->is_big_endian = (LLVMByteOrder(g->target_data_ref) == LLVMBigEndian); g->builder = LLVMCreateBuilder(); @@ -7906,18 +7899,89 @@ static void init(CodeGen *g) { } } +static void detect_dynamic_linker(CodeGen *g) { + if (g->dynamic_linker_path != nullptr) + return; + const char *standard_ld_path = target_dynamic_linker(g->zig_target); + if (standard_ld_path == nullptr) + return; + + if (g->zig_target->is_native) { + // target_dynamic_linker is usually correct. However on some systems, such as NixOS + // it will be incorrect. See if we can do better by looking at what zig's own + // dynamic linker path is. + g->dynamic_linker_path = get_self_dynamic_linker_path(); + if (g->dynamic_linker_path != nullptr) + return; + + // If Zig is statically linked, such as via distributed binary static builds, the above + // trick won't work. What are we left with? Try to run the system C compiler and get + // it to tell us the dynamic linker path +#if defined(ZIG_OS_LINUX) + { + Error err; + static const char *dyn_tests[] = { +#if defined(ZIG_ARCH_X86_64) + "ld-linux-x86-64.so.2", + "ld-musl-x86_64.so.1", +#endif + }; + Buf *result = buf_alloc(); + for (size_t i = 0; i < array_length(dyn_tests); i += 1) { + const char *lib_name = dyn_tests[i]; + if ((err = zig_libc_cc_print_file_name(lib_name, result, false, true))) { + if (err != ErrorCCompilerCannotFindFile) { + fprintf(stderr, "Unable to detect native dynamic linker: %s\n", err_str(err)); + exit(1); + } + continue; + } + g->dynamic_linker_path = result; + return; + } + } +#endif + } + + g->dynamic_linker_path = buf_create_from_str(standard_ld_path); +} + static void detect_libc(CodeGen *g) { Error err; if (g->libc != nullptr || g->libc_link_lib == nullptr) return; + if (g->zig_target->os == OsLinux && target_abi_is_gnu(g->zig_target->abi)) { + // we have glibc headers and can build glibc start files from source + if (g->is_static && g->out_type == OutTypeExe) { + fprintf(stderr, "glibc does not support static linking\n"); + exit(1); + } + + Buf libc_include_dir = BUF_INIT; + os_path_join(g->zig_lib_dir, buf_create_from_str("libc" OS_SEP "include"), &libc_include_dir); + + Buf *arch_include_dir = buf_sprintf("%s" OS_SEP "libc" OS_SEP "include" OS_SEP "%s-%s-%s", + buf_ptr(g->zig_lib_dir), target_arch_name(g->zig_target->arch), + target_os_name(g->zig_target->os), target_abi_name(g->zig_target->abi)); + + Buf *generic_include_dir = buf_sprintf("%s" OS_SEP "libc" OS_SEP "include" OS_SEP "generic-glibc", + buf_ptr(g->zig_lib_dir)); + + g->libc_include_dir_len = 2; + g->libc_include_dir_list = allocate<Buf*>(2); + g->libc_include_dir_list[0] = arch_include_dir; + g->libc_include_dir_list[1] = generic_include_dir; + return; + } + if (g->zig_target->is_native) { g->libc = allocate<ZigLibCInstallation>(1); // Look for zig-cache/native_libc.txt Buf *native_libc_txt = buf_alloc(); - os_path_join(&g->cache_dir, buf_create_from_str("native_libc.txt"), native_libc_txt); + os_path_join(g->cache_dir, buf_create_from_str("native_libc.txt"), native_libc_txt); if ((err = zig_libc_parse(g->libc, native_libc_txt, g->zig_target, false))) { if ((err = zig_libc_find_native(g->libc, true))) { fprintf(stderr, @@ -7925,9 +7989,9 @@ static void detect_libc(CodeGen *g) { "See `zig libc --help` for more details.\n", err_str(err)); exit(1); } - if ((err = os_make_path(&g->cache_dir))) { + if ((err = os_make_path(g->cache_dir))) { fprintf(stderr, "Unable to create %s directory: %s\n", - buf_ptr(&g->cache_dir), err_str(err)); + buf_ptr(g->cache_dir), err_str(err)); exit(1); } Buf *native_libc_tmp = buf_sprintf("%s.tmp", buf_ptr(native_libc_txt)); @@ -7946,6 +8010,14 @@ static void detect_libc(CodeGen *g) { exit(1); } } + bool want_sys_dir = !buf_eql_buf(&g->libc->include_dir, &g->libc->sys_include_dir); + size_t dir_count = 1 + want_sys_dir; + g->libc_include_dir_len = dir_count; + g->libc_include_dir_list = allocate<Buf*>(dir_count); + g->libc_include_dir_list[0] = &g->libc->include_dir; + if (want_sys_dir) { + g->libc_include_dir_list[1] = &g->libc->sys_include_dir; + } } else if ((g->out_type == OutTypeExe || (g->out_type == OutTypeLib && !g->is_static)) && !target_is_darwin(g->zig_target)) { @@ -8113,7 +8185,7 @@ static void gen_root_source(CodeGen *g) { assert(g->root_out_name); assert(g->out_type != OutTypeUnknown); - { + if (!g->is_dummy_so) { // Zig has lazy top level definitions. Here we semantically analyze the panic function. ZigType *import_with_panic; if (g->have_pub_panic) { @@ -8158,7 +8230,9 @@ static void gen_root_source(CodeGen *g) { } } - typecheck_panic_fn(g, g->panic_tld_fn, g->panic_fn); + if (!g->is_dummy_so) { + typecheck_panic_fn(g, g->panic_tld_fn, g->panic_fn); + } report_errors_and_maybe_exit(g); @@ -8190,142 +8264,248 @@ static void print_zig_cc_cmd(const char *zig_exe, ZigList<const char *> *args) { fprintf(stderr, "\n"); } +// Caller should delete the file when done or rename it into a better location. +static Error get_tmp_filename(CodeGen *g, Buf *out, Buf *suffix) { + Error err; + buf_resize(out, 0); + os_path_join(g->cache_dir, buf_create_from_str("tmp" OS_SEP), out); + if ((err = os_make_path(out))) { + return err; + } + const char base64[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"; + assert(array_length(base64) == 64 + 1); + for (size_t i = 0; i < 12; i += 1) { + buf_append_char(out, base64[rand() % 64]); + } + buf_append_char(out, '-'); + buf_append_buf(out, suffix); + return ErrorNone; +} + +// returns true if it was a cache miss static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { Error err; + Buf *artifact_dir; + Buf *o_final_path; + + Buf *o_dir = buf_alloc(); + os_path_join(g->cache_dir, buf_create_from_str("o"), o_dir); + Buf *c_source_file = buf_create_from_str(c_file->source_path); Buf *c_source_basename = buf_alloc(); os_path_split(c_source_file, nullptr, c_source_basename); - Buf *out_obj_name = buf_sprintf("%s%s", buf_ptr(c_source_basename), target_o_file_ext(g->zig_target)); - Buf *out_obj_path = buf_alloc(); - os_path_join(&g->cache_dir, out_obj_name, out_obj_path); - Buf *out_dep_name = buf_sprintf("%s.d", buf_ptr(c_source_file)); - Buf *out_dep_path = buf_alloc(); - os_path_join(&g->cache_dir, out_dep_name, out_dep_path); + Buf *final_o_basename = buf_alloc(); + os_path_extname(c_source_basename, final_o_basename, nullptr); + buf_append_str(final_o_basename, target_o_file_ext(g->zig_target)); - Termination term; - ZigList<const char *> args = {}; - args.append("cc"); + CacheHash *cache_hash = allocate<CacheHash>(1); + Buf *manifest_dir = buf_alloc(); + os_path_join(g->cache_dir, buf_create_from_str("c"), manifest_dir); + cache_init(cache_hash, manifest_dir); - if (g->enable_cache) { + Buf *compiler_id; + if ((err = get_compiler_id(&compiler_id))) { + fprintf(stderr, "unable to get compiler id: %s\n", err_str(err)); + exit(1); + } + cache_buf(cache_hash, compiler_id); + cache_int(cache_hash, g->err_color); + cache_buf(cache_hash, g->zig_c_headers_dir); + cache_list_of_buf(cache_hash, g->libc_include_dir_list, g->libc_include_dir_len); + cache_int(cache_hash, g->zig_target->is_native); + cache_int(cache_hash, g->zig_target->arch); + cache_int(cache_hash, g->zig_target->sub_arch); + cache_int(cache_hash, g->zig_target->vendor); + cache_int(cache_hash, g->zig_target->os); + cache_int(cache_hash, g->zig_target->abi); + cache_bool(cache_hash, g->strip_debug_symbols); + cache_int(cache_hash, g->build_mode); + cache_file(cache_hash, c_source_file); + cache_bool(cache_hash, g->disable_pic); + for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) { + cache_str(cache_hash, g->clang_argv[arg_i]); + } + // Note: not directory args, just args that always have a file next + static const char *file_args[] = { + "-include", + }; + for (size_t arg_i = 0; arg_i < c_file->args.length; arg_i += 1) { + const char *arg = c_file->args.at(arg_i); + cache_str(cache_hash, arg); + for (size_t file_arg_i = 0; file_arg_i < array_length(file_args); file_arg_i += 1) { + if (strcmp(arg, file_args[file_arg_i]) == 0 && arg_i + 1 < c_file->args.length) { + arg_i += 1; + cache_file(cache_hash, buf_create_from_str(c_file->args.at(arg_i))); + } + } + } + + Buf digest = BUF_INIT; + buf_resize(&digest, 0); + if ((err = cache_hit(cache_hash, &digest))) { + if (err == ErrorCacheUnavailable) { + // already printed error + } else { + fprintf(stderr, "unable to check cache when compiling C object: %s\n", err_str(err)); + } + exit(1); + } + bool is_cache_miss = (buf_len(&digest) == 0); + if (is_cache_miss) { + // we can't know the digest until we do the C compiler invocation, so we + // need a tmp filename. + Buf *out_obj_path = buf_alloc(); + if ((err = get_tmp_filename(g, out_obj_path, final_o_basename))) { + fprintf(stderr, "unable to create tmp dir: %s\n", err_str(err)); + exit(1); + } + + Termination term; + ZigList<const char *> args = {}; + args.append("cc"); + + Buf *out_dep_path = buf_sprintf("%s.d", buf_ptr(out_obj_path)); args.append("-MD"); + args.append("-MV"); args.append("-MF"); args.append(buf_ptr(out_dep_path)); - } - - args.append("-nostdinc"); - args.append("-fno-spell-checking"); - switch (g->err_color) { - case ErrColorAuto: - break; - case ErrColorOff: - args.append("-fno-color-diagnostics"); - args.append("-fno-caret-diagnostics"); - break; - case ErrColorOn: - args.append("-fcolor-diagnostics"); - args.append("-fcaret-diagnostics"); - break; - } + args.append("-nostdinc"); + args.append("-fno-spell-checking"); - args.append("-isystem"); - args.append(buf_ptr(g->zig_c_headers_dir)); + switch (g->err_color) { + case ErrColorAuto: + break; + case ErrColorOff: + args.append("-fno-color-diagnostics"); + args.append("-fno-caret-diagnostics"); + break; + case ErrColorOn: + args.append("-fcolor-diagnostics"); + args.append("-fcaret-diagnostics"); + break; + } - if (g->libc != nullptr) { args.append("-isystem"); - args.append(buf_ptr(&g->libc->include_dir)); + args.append(buf_ptr(g->zig_c_headers_dir)); - if (!buf_eql_buf(&g->libc->include_dir, &g->libc->sys_include_dir)) { + for (size_t i = 0; i < g->libc_include_dir_len; i += 1) { + Buf *include_dir = g->libc_include_dir_list[i]; args.append("-isystem"); - args.append(buf_ptr(&g->libc->sys_include_dir)); + args.append(buf_ptr(include_dir)); } - } - if (g->zig_target->is_native) { - args.append("-march=native"); - } else { - args.append("-target"); - args.append(buf_ptr(&g->triple_str)); - } + if (g->zig_target->is_native) { + args.append("-march=native"); + } else { + args.append("-target"); + args.append(buf_ptr(&g->triple_str)); + } - if (!g->strip_debug_symbols) { - args.append("-g"); - } - switch (g->build_mode) { - case BuildModeDebug: - if (g->libc_link_lib != nullptr) { - args.append("-fstack-protector-strong"); - args.append("--param"); - args.append("ssp-buffer-size=4"); - } else { + if (!g->strip_debug_symbols) { + args.append("-g"); + } + + switch (g->build_mode) { + case BuildModeDebug: + if (g->libc_link_lib != nullptr) { + args.append("-fstack-protector-strong"); + args.append("--param"); + args.append("ssp-buffer-size=4"); + } else { + args.append("-fno-stack-protector"); + } + break; + case BuildModeSafeRelease: + args.append("-O2"); + if (g->libc_link_lib != nullptr) { + args.append("-D_FORTIFY_SOURCE=2"); + args.append("-fstack-protector-strong"); + args.append("--param"); + args.append("ssp-buffer-size=4"); + } else { + args.append("-fno-stack-protector"); + } + break; + case BuildModeFastRelease: + args.append("-DNDEBUG"); + args.append("-O2"); args.append("-fno-stack-protector"); - } - break; - case BuildModeSafeRelease: - args.append("-O2"); - if (g->libc_link_lib != nullptr) { - args.append("-D_FORTIFY_SOURCE=2"); - args.append("-fstack-protector-strong"); - args.append("--param"); - args.append("ssp-buffer-size=4"); - } else { + break; + case BuildModeSmallRelease: + args.append("-DNDEBUG"); + args.append("-Os"); args.append("-fno-stack-protector"); - } - break; - case BuildModeFastRelease: - args.append("-O2"); - args.append("-fno-stack-protector"); - break; - case BuildModeSmallRelease: - args.append("-Os"); - args.append("-fno-stack-protector"); - break; - } + break; + } - args.append("-o"); - args.append(buf_ptr(out_obj_path)); + args.append("-o"); + args.append(buf_ptr(out_obj_path)); - args.append("-c"); - args.append(buf_ptr(c_source_file)); + args.append("-c"); + args.append(buf_ptr(c_source_file)); - if (!g->disable_pic && target_supports_fpic(g->zig_target)) { - args.append("-fPIC"); - } + if (target_supports_fpic(g->zig_target) && !g->disable_pic) { + args.append("-fPIC"); + } - for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) { - args.append(g->clang_argv[arg_i]); - } + for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) { + args.append(g->clang_argv[arg_i]); + } - for (size_t arg_i = 0; arg_i < c_file->args.length; arg_i += 1) { - args.append(c_file->args.at(arg_i)); - } + for (size_t arg_i = 0; arg_i < c_file->args.length; arg_i += 1) { + args.append(c_file->args.at(arg_i)); + } - if (g->verbose_cc) { - print_zig_cc_cmd("zig", &args); - } - os_spawn_process(buf_ptr(self_exe_path), args, &term); - if (term.how != TerminationIdClean || term.code != 0) { - fprintf(stderr, "\nThe following command failed:\n"); - print_zig_cc_cmd(buf_ptr(self_exe_path), &args); - exit(1); - } - g->link_objects.append(out_obj_path); + if (g->verbose_cc) { + print_zig_cc_cmd("zig", &args); + } + os_spawn_process(buf_ptr(self_exe_path), args, &term); + if (term.how != TerminationIdClean || term.code != 0) { + fprintf(stderr, "\nThe following command failed:\n"); + print_zig_cc_cmd(buf_ptr(self_exe_path), &args); + exit(1); + } - if (g->enable_cache) { // add the files depended on to the cache system - if ((err = cache_add_file(&g->cache_hash, c_source_file))) { - fprintf(stderr, "unable to add %s to cache: %s\n", buf_ptr(c_source_file), err_str(err)); + if ((err = cache_add_dep_file(cache_hash, out_dep_path, true))) { + fprintf(stderr, "Failed to add C source dependencies to cache: %s\n", err_str(err)); + exit(1); + } + os_delete_file(out_dep_path); + + if ((err = cache_final(cache_hash, &digest))) { + fprintf(stderr, "Unable to finalize cache hash: %s\n", err_str(err)); + exit(1); + } + artifact_dir = buf_alloc(); + os_path_join(o_dir, &digest, artifact_dir); + if ((err = os_make_path(artifact_dir))) { + fprintf(stderr, "Unable to create output directory '%s': %s", + buf_ptr(artifact_dir), err_str(err)); exit(1); } - if ((err = cache_add_dep_file(&g->cache_hash, out_dep_path, true))) { - fprintf(stderr, "failed to add C source dependencies to cache: %s\n", err_str(err)); + o_final_path = buf_alloc(); + os_path_join(artifact_dir, final_o_basename, o_final_path); + if ((err = os_rename(out_obj_path, o_final_path))) { + fprintf(stderr, "Unable to rename object: %s\n", err_str(err)); exit(1); } + } else { + // cache hit + artifact_dir = buf_alloc(); + os_path_join(o_dir, &digest, artifact_dir); + o_final_path = buf_alloc(); + os_path_join(artifact_dir, final_o_basename, o_final_path); } + + g->link_objects.append(o_final_path); + g->caches_to_release.append(cache_hash); } +// returns true if we had any cache misses static void gen_c_objects(CodeGen *g) { Error err; @@ -8338,6 +8518,8 @@ static void gen_c_objects(CodeGen *g) { exit(1); } + codegen_add_time_event(g, "Compile C Code"); + for (size_t c_file_i = 0; c_file_i < g->c_source_files.length; c_file_i += 1) { CFile *c_file = g->c_source_files.at(c_file_i); gen_c_object(g, self_exe_path, c_file); @@ -8838,6 +9020,7 @@ static void add_cache_pkg(CodeGen *g, CacheHash *ch, ZigPackage *pkg) { } // Called before init() +// is_cache_hit takes into account gen_c_objects static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { Error err; @@ -8860,15 +9043,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_list_of_buf(ch, g->darwin_frameworks.items, g->darwin_frameworks.length); cache_list_of_buf(ch, g->rpath_list.items, g->rpath_list.length); cache_list_of_buf(ch, g->forbidden_libs.items, g->forbidden_libs.length); - cache_list_of_file(ch, g->link_objects.items, g->link_objects.length); cache_list_of_file(ch, g->assembly_files.items, g->assembly_files.length); - for (size_t c_file_i = 0; c_file_i < g->c_source_files.length; c_file_i += 1) { - CFile *c_file = g->c_source_files.at(c_file_i); - cache_file(ch, buf_create_from_str(c_file->source_path)); - for (size_t opt_i = 0; opt_i < c_file->args.length; opt_i += 1) { - cache_buf(ch, buf_create_from_str(c_file->args.at(opt_i))); - } - } cache_int(ch, g->emit_file_type); cache_int(ch, g->build_mode); cache_int(ch, g->out_type); @@ -8882,18 +9057,21 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_bool(ch, g->is_static); cache_bool(ch, g->strip_debug_symbols); cache_bool(ch, g->is_test_build); + if (g->is_test_build) { + cache_buf_opt(ch, g->test_filter); + cache_buf_opt(ch, g->test_name_prefix); + } cache_bool(ch, g->is_single_threaded); cache_bool(ch, g->linker_rdynamic); cache_bool(ch, g->each_lib_rpath); cache_bool(ch, g->disable_pic); cache_bool(ch, g->valgrind_support); + cache_bool(ch, g->is_dummy_so); cache_buf_opt(ch, g->mmacosx_version_min); cache_buf_opt(ch, g->mios_version_min); cache_usize(ch, g->version_major); cache_usize(ch, g->version_minor); cache_usize(ch, g->version_patch); - cache_buf_opt(ch, g->test_filter); - cache_buf_opt(ch, g->test_name_prefix); cache_list_of_str(ch, g->llvm_argv, g->llvm_argv_len); cache_list_of_str(ch, g->clang_argv, g->clang_argv_len); cache_list_of_str(ch, g->lib_dirs.items, g->lib_dirs.length); @@ -8901,20 +9079,34 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_buf(ch, &g->libc->include_dir); cache_buf(ch, &g->libc->sys_include_dir); cache_buf(ch, &g->libc->crt_dir); - cache_buf(ch, &g->libc->lib_dir); - cache_buf(ch, &g->libc->static_lib_dir); cache_buf(ch, &g->libc->msvc_lib_dir); cache_buf(ch, &g->libc->kernel32_lib_dir); - cache_buf(ch, &g->libc->dynamic_linker_path); } + cache_buf_opt(ch, g->dynamic_linker_path); + + // gen_c_objects appends objects to g->link_objects which we want to include in the hash + gen_c_objects(g); + cache_list_of_file(ch, g->link_objects.items, g->link_objects.length); buf_resize(digest, 0); if ((err = cache_hit(ch, digest))) return err; + if (ch->manifest_file_path != nullptr) { + g->caches_to_release.append(ch); + } + return ErrorNone; } +static bool need_llvm_module(CodeGen *g) { + return g->assembly_files.length != 0 || buf_len(&g->root_package->root_src_path) != 0; +} + +static bool compilation_is_already_done(CodeGen *g) { + return !need_llvm_module(g) && g->link_objects.length == 1 && g->out_type == OutTypeObj; +} + static void resolve_out_paths(CodeGen *g) { Buf *o_basename = buf_create_from_buf(g->root_out_name); @@ -8941,7 +9133,9 @@ static void resolve_out_paths(CodeGen *g) { zig_unreachable(); } - if (g->enable_cache || g->out_type != OutTypeObj) { + if (compilation_is_already_done(g)) { + buf_init_from_str(&g->o_file_output_path, buf_ptr(g->link_objects.at(0))); + } else if (g->enable_cache || g->out_type != OutTypeObj) { os_path_join(&g->artifact_dir, o_basename, &g->o_file_output_path); } else if (g->wanted_output_file_path != nullptr && g->out_type == OutTypeObj) { buf_init_from_buf(&g->o_file_output_path, g->wanted_output_file_path); @@ -8949,39 +9143,44 @@ static void resolve_out_paths(CodeGen *g) { buf_init_from_buf(&g->o_file_output_path, o_basename); } - if (g->out_type == OutTypeObj) { + if (!g->enable_cache && g->wanted_output_file_path != nullptr) { + buf_init_from_buf(&g->output_file_path, g->wanted_output_file_path); + return; + } + + if (compilation_is_already_done(g)) { buf_init_from_buf(&g->output_file_path, &g->o_file_output_path); - } else if (g->out_type == OutTypeExe) { - if (!g->enable_cache && g->wanted_output_file_path != nullptr) { - buf_init_from_buf(&g->output_file_path, g->wanted_output_file_path); - } else { - assert(g->root_out_name); + return; + } - Buf basename = BUF_INIT; - buf_init_from_buf(&basename, g->root_out_name); - buf_append_str(&basename, target_exe_file_ext(g->zig_target)); - if (g->enable_cache || g->is_test_build) { - os_path_join(&g->artifact_dir, &basename, &g->output_file_path); - } else { - buf_init_from_buf(&g->output_file_path, &basename); - } - } - } else if (g->out_type == OutTypeLib) { - if (!g->enable_cache && g->wanted_output_file_path != nullptr) { - buf_init_from_buf(&g->output_file_path, g->wanted_output_file_path); - } else { - Buf basename = BUF_INIT; - buf_init_from_buf(&basename, g->root_out_name); - buf_append_str(&basename, target_lib_file_ext(g->zig_target, g->is_static, - g->version_major, g->version_minor, g->version_patch)); - if (g->enable_cache) { - os_path_join(&g->artifact_dir, &basename, &g->output_file_path); - } else { - buf_init_from_buf(&g->output_file_path, &basename); - } - } + const char *prefix = ""; + const char *extname; + switch (g->out_type) { + case OutTypeUnknown: + zig_unreachable(); + case OutTypeObj: + extname = target_o_file_ext(g->zig_target); + break; + case OutTypeExe: + extname = target_exe_file_ext(g->zig_target); + break; + case OutTypeLib: + prefix = target_lib_file_prefix(g->zig_target); + extname = target_lib_file_ext(g->zig_target, g->is_static, + g->version_major, g->version_minor, g->version_patch); + break; + } + + assert(g->root_out_name); + + Buf basename = BUF_INIT; + buf_init_from_str(&basename, prefix); + buf_append_buf(&basename, g->root_out_name); + buf_append_str(&basename, extname); + if (g->enable_cache || g->is_test_build) { + os_path_join(&g->artifact_dir, &basename, &g->output_file_path); } else { - zig_unreachable(); + buf_init_from_buf(&g->output_file_path, &basename); } } @@ -8990,48 +9189,55 @@ void codegen_build_and_link(CodeGen *g) { assert(g->out_type != OutTypeUnknown); detect_libc(g); + detect_dynamic_linker(g); - Buf *stage1_dir = get_stage1_cache_path(); Buf *artifact_dir = buf_alloc(); Buf digest = BUF_INIT; if (g->enable_cache) { - codegen_add_time_event(g, "Check Cache"); - Buf *manifest_dir = buf_alloc(); - os_path_join(stage1_dir, buf_create_from_str("build"), manifest_dir); + os_path_join(g->cache_dir, buf_create_from_str("h"), manifest_dir); if ((err = check_cache(g, manifest_dir, &digest))) { if (err == ErrorCacheUnavailable) { // message already printed + } else if (err == ErrorNotDir) { + fprintf(stderr, "Unable to check cache: %s is not a directory\n", + buf_ptr(manifest_dir)); } else { fprintf(stderr, "Unable to check cache: %s\n", err_str(err)); } exit(1); } - os_path_join(stage1_dir, buf_create_from_str("artifact"), artifact_dir); + os_path_join(g->cache_dir, buf_create_from_str("artifact"), artifact_dir); + } else { + // There is a call to this in check_cache + gen_c_objects(g); } if (g->enable_cache && buf_len(&digest) != 0) { os_path_join(artifact_dir, &digest, &g->artifact_dir); resolve_out_paths(g); } else { - init(g); + if (need_llvm_module(g)) { + init(g); - codegen_add_time_event(g, "Semantic Analysis"); + codegen_add_time_event(g, "Semantic Analysis"); - gen_global_asm(g); - gen_root_source(g); - gen_c_objects(g); + gen_global_asm(g); + gen_root_source(g); + } if (g->enable_cache) { - if ((err = cache_final(&g->cache_hash, &digest))) { - fprintf(stderr, "Unable to finalize cache hash: %s\n", err_str(err)); - exit(1); + if (buf_len(&digest) == 0) { + if ((err = cache_final(&g->cache_hash, &digest))) { + fprintf(stderr, "Unable to finalize cache hash: %s\n", err_str(err)); + exit(1); + } } os_path_join(artifact_dir, &digest, &g->artifact_dir); } else { - buf_init_from_buf(&g->artifact_dir, &g->cache_dir); + buf_init_from_buf(&g->artifact_dir, g->cache_dir); } if ((err = os_make_path(&g->artifact_dir))) { fprintf(stderr, "Unable to create artifact directory: %s\n", err_str(err)); @@ -9039,15 +9245,9 @@ void codegen_build_and_link(CodeGen *g) { } resolve_out_paths(g); - codegen_add_time_event(g, "Code Generation"); - if (g->out_type == OutTypeObj && g->c_source_files.length == 1) { - assert(g->link_objects.length == 1); - if ((err = os_rename(g->link_objects.pop(), &g->o_file_output_path))) { - fprintf(stderr, "unable to move object to '%s': %s\n", - buf_ptr(&g->o_file_output_path), err_str(err)); - exit(1); - } - } else { + if (need_llvm_module(g)) { + codegen_add_time_event(g, "Code Generation"); + do_code_gen(g); codegen_add_time_event(g, "LLVM Emit Output"); zig_llvm_emit_output(g); @@ -9056,14 +9256,17 @@ void codegen_build_and_link(CodeGen *g) { codegen_add_time_event(g, "Generate .h"); gen_h_file(g); } - if (g->out_type != OutTypeObj && g->emit_file_type == EmitFileTypeBinary) { - codegen_link(g); - } + } + + if (g->emit_file_type == EmitFileTypeBinary && + (g->link_objects.length > 1 || g->out_type != OutTypeObj)) + { + codegen_link(g); } } - if (g->enable_cache) { - cache_release(&g->cache_hash); + while (g->caches_to_release.length != 0) { + cache_release(g->caches_to_release.pop()); } codegen_add_time_event(g, "Done"); } |
