diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2019-03-04 22:15:53 -0500 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2019-03-04 22:15:53 -0500 |
| commit | aeb16010f37df3c702481c9bd98b8cc838418ee1 (patch) | |
| tree | 92194b8c0d4576efede7f29b2fee8b1bed1b2654 /src/codegen.cpp | |
| parent | 9c5852aa8674320d2912627708f32fea37d7cd08 (diff) | |
| download | zig-aeb16010f37df3c702481c9bd98b8cc838418ee1.tar.gz zig-aeb16010f37df3c702481c9bd98b8cc838418ee1.zip | |
initial glibc support
Diffstat (limited to 'src/codegen.cpp')
| -rw-r--r-- | src/codegen.cpp | 458 |
1 files changed, 298 insertions, 160 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp index 9a8864b87a..2054663fc6 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(); @@ -7912,12 +7914,27 @@ static void detect_libc(CodeGen *g) { 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_dir = buf_alloc(); + os_path_join(g->zig_lib_dir, buf_create_from_str("libc"), libc_dir); + + g->libc_include_dir = buf_alloc(); + os_path_join(libc_dir, buf_create_from_str("glibc-include"), g->libc_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 +7942,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 +7963,7 @@ static void detect_libc(CodeGen *g) { exit(1); } } + g->libc_include_dir = &g->libc->include_dir; } else if ((g->out_type == OutTypeExe || (g->out_type == OutTypeLib && !g->is_static)) && !target_is_darwin(g->zig_target)) { @@ -8190,140 +8208,253 @@ 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; +} + 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_buf_opt(cache_hash, g->libc_include_dir); + if (g->libc != nullptr) { + cache_buf(cache_hash, &g->libc->sys_include_dir); + } + 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); + } + if (buf_len(&digest) == 0) { + // 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("-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)) { + if (g->libc_include_dir != nullptr) { args.append("-isystem"); - args.append(buf_ptr(&g->libc->sys_include_dir)); + args.append(buf_ptr(g->libc_include_dir)); + } + if (g->libc != nullptr) { + if (!buf_eql_buf(&g->libc->include_dir, &g->libc->sys_include_dir)) { + args.append("-isystem"); + args.append(buf_ptr(&g->libc->sys_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("-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("-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); + } + + if (g->enable_cache) { + cache_buf(&g->cache_hash, &digest); } + + g->link_objects.append(o_final_path); + g->caches_to_release.append(cache_hash); } static void gen_c_objects(CodeGen *g) { @@ -8338,6 +8469,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); @@ -8862,13 +8995,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { 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); @@ -8908,13 +9034,27 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_buf(ch, &g->libc->dynamic_linker_path); } + gen_c_objects(g); + 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 +9081,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 +9091,41 @@ 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 *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: + 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_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); } } @@ -8991,14 +9135,11 @@ void codegen_build_and_link(CodeGen *g) { detect_libc(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("build"), manifest_dir); if ((err = check_cache(g, manifest_dir, &digest))) { if (err == ErrorCacheUnavailable) { @@ -9009,7 +9150,10 @@ void codegen_build_and_link(CodeGen *g) { 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) { @@ -9022,7 +9166,6 @@ void codegen_build_and_link(CodeGen *g) { gen_global_asm(g); gen_root_source(g); - gen_c_objects(g); if (g->enable_cache) { if ((err = cache_final(&g->cache_hash, &digest))) { @@ -9031,7 +9174,7 @@ void codegen_build_and_link(CodeGen *g) { } 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)); @@ -9040,14 +9183,8 @@ 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)) { do_code_gen(g); codegen_add_time_event(g, "LLVM Emit Output"); zig_llvm_emit_output(g); @@ -9056,14 +9193,15 @@ 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 && !compilation_is_already_done(g)) { + 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"); } |
