From 5d2edac12dc9eec626977a5bf9b0630504b28c15 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 13 Mar 2019 19:33:19 -0400 Subject: [PATCH] breaking: remove --static; add -dynamic `--static` is no longer an option. Instead, Zig makes things as static as possible by default. `-dynamic` can be used to choose a dynamic library rather than a static one. `--enable-pic` is a new option. Usually it will be enabled automatically, but in the case of build-exe with no dynamic libraries on Linux or freestanding, Zig chooses off by default. closes #1703 closes #1828 --- src/all_types.hpp | 12 ++++- src/codegen.cpp | 96 +++++++++++++++++++++++++++------------ src/ir.cpp | 15 ++++-- src/libc_installation.cpp | 2 +- src/link.cpp | 78 ++++++++++--------------------- src/main.cpp | 47 +++++++++++-------- src/target.cpp | 53 ++++++++++++++++++--- src/target.hpp | 8 +++- std/build.zig | 38 +++++++--------- 9 files changed, 212 insertions(+), 137 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index ec14382a2b..d1d63f1062 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1616,6 +1616,12 @@ enum ValgrindSupport { ValgrindSupportEnabled, }; +enum WantPIC { + WantPICAuto, + WantPICDisabled, + WantPICEnabled, +}; + struct CFile { ZigList args; const char *source_path; @@ -1791,6 +1797,8 @@ struct CodeGen { bool have_dllmain_crt_startup; bool have_pub_panic; bool have_err_ret_tracing; + bool have_pic; + bool have_dynamic_link; // this is whether the final thing will be dynamically linked. see also is_dynamic bool c_want_stdint; bool c_want_stdbool; bool verbose_tokenize; @@ -1834,13 +1842,13 @@ struct CodeGen { const ZigTarget *zig_target; TargetSubsystem subsystem; ValgrindSupport valgrind_support; - bool is_static; + WantPIC want_pic; + bool is_dynamic; // shared library rather than static library. dynamic musl rather than static musl. bool strip_debug_symbols; bool is_test_build; bool is_single_threaded; bool linker_rdynamic; bool each_lib_rpath; - bool disable_pic; bool is_dummy_so; bool disable_gen_h; diff --git a/src/codegen.cpp b/src/codegen.cpp index 9f7bef52cb..11a368cda6 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -182,13 +182,13 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget } else { g->each_lib_rpath = true; - if (target_is_darwin(g->zig_target)) { + if (target_os_is_darwin(g->zig_target->os)) { init_darwin_native(g); } } - if (target_requires_libc(g->zig_target)) { + if (target_os_requires_libc(g->zig_target->os)) { g->libc_link_lib = create_link_lib(buf_create_from_str("c")); g->link_libs_list.append(g->libc_link_lib); } @@ -3370,7 +3370,7 @@ static LLVMValueRef gen_valgrind_client_request(CodeGen *g, LLVMValueRef default bool asm_has_side_effects = true; bool asm_is_alignstack = false; if (g->zig_target->arch == ZigLLVM_x86_64) { - if (g->zig_target->os == OsLinux || target_is_darwin(g->zig_target) || g->zig_target->os == OsSolaris || + if (g->zig_target->os == OsLinux || target_os_is_darwin(g->zig_target->os) || g->zig_target->os == OsSolaris || (g->zig_target->os == OsWindows && g->zig_target->abi != ZigLLVM_MSVC)) { if (g->cur_fn->valgrind_client_request_array == nullptr) { @@ -7283,7 +7283,44 @@ static const char *build_mode_to_str(BuildMode build_mode) { zig_unreachable(); } +static bool detect_dynamic_link(CodeGen *g) { + if (g->is_dynamic) + return true; + if (g->zig_target->os == OsFreestanding) + return false; + if (target_requires_pic(g->zig_target)) + return true; + if (g->out_type == OutTypeExe) { + // If there are no dynamic libraries then we can disable PIC + for (size_t i = 0; i < g->link_libs_list.length; i += 1) { + LinkLib *link_lib = g->link_libs_list.at(i); + if (target_is_libc_lib_name(g->zig_target, buf_ptr(link_lib->name))) + continue; + return true; + } + return false; + } + return true; +} + +static bool detect_pic(CodeGen *g) { + if (target_requires_pic(g->zig_target)) + return true; + switch (g->want_pic) { + case WantPICDisabled: + return false; + case WantPICEnabled: + return true; + case WantPICAuto: + return g->have_dynamic_link; + } + zig_unreachable(); +} + Buf *codegen_generate_builtin_source(CodeGen *g) { + g->have_dynamic_link = detect_dynamic_link(g); + g->have_pic = detect_pic(g); + Buf *contents = buf_alloc(); // NOTE: when editing this file, you may need to make modifications to the @@ -7683,6 +7720,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->libc_link_lib != nullptr)); buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing)); buf_appendf(contents, "pub const valgrind_support = %s;\n", bool_to_str(want_valgrind_support(g))); + buf_appendf(contents, "pub const position_independent_code = %s;\n", bool_to_str(g->have_pic)); buf_appendf(contents, "pub const __zig_test_fn_slice = {}; // overwritten later\n"); @@ -7777,6 +7815,9 @@ static void init(CodeGen *g) { if (g->module) return; + g->have_dynamic_link = detect_dynamic_link(g); + g->have_pic = detect_pic(g); + if (g->is_test_build) { g->subsystem = TargetSubsystemConsole; } @@ -7807,10 +7848,7 @@ static void init(CodeGen *g) { bool is_optimized = g->build_mode != BuildModeDebug; LLVMCodeGenOptLevel opt_level = is_optimized ? LLVMCodeGenLevelAggressive : LLVMCodeGenLevelNone; - if (g->out_type == OutTypeExe && g->is_static) { - g->disable_pic = true; - } - LLVMRelocMode reloc_mode = g->disable_pic ? LLVMRelocStatic : LLVMRelocPIC; + LLVMRelocMode reloc_mode = g->have_pic ? LLVMRelocPIC: LLVMRelocStatic; const char *target_specific_cpu_args; const char *target_specific_features; @@ -7892,8 +7930,13 @@ static void init(CodeGen *g) { } static void detect_dynamic_linker(CodeGen *g) { - if (g->dynamic_linker_path != nullptr || g->is_static) + if (g->dynamic_linker_path != nullptr) return; + if (!g->have_dynamic_link) + return; + if (g->out_type == OutTypeObj || (g->out_type == OutTypeLib && !g->is_dynamic)) + return; + const char *standard_ld_path = target_dynamic_linker(g->zig_target); if (standard_ld_path == nullptr) return; @@ -7944,13 +7987,6 @@ 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) && - g->is_static && g->out_type == OutTypeExe) - { - fprintf(stderr, "glibc does not support static linking\n"); - exit(1); - } - if (target_can_build_libc(g->zig_target)) { const char *generic_name = target_libc_generic_name(g->zig_target); @@ -8010,17 +8046,16 @@ static void detect_libc(CodeGen *g) { 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)) + } else if ((g->out_type == OutTypeExe || (g->out_type == OutTypeLib && g->is_dynamic)) && + !target_os_is_darwin(g->zig_target->os)) { + Buf triple_buf = BUF_INIT; + get_target_triple(&triple_buf, g->zig_target); fprintf(stderr, - "Zig is unable to provide a libc for the chosen target '%s-%s-%s'.\n" + "Zig is unable to provide a libc for the chosen target '%s'.\n" "The target is non-native, so Zig also cannot use the native libc installation.\n" "Choose a target which has a libc available, or provide a libc installation text file.\n" - "See `zig libc --help` for more details.\n", - target_arch_name(g->zig_target->arch), - target_os_name(g->zig_target->os), - target_abi_name(g->zig_target->abi)); + "See `zig libc --help` for more details.\n", buf_ptr(&triple_buf)); exit(1); } } @@ -8203,7 +8238,7 @@ static void gen_root_source(CodeGen *g) { g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap.zig"); } if (g->zig_target->os == OsWindows && !g->have_dllmain_crt_startup && - g->out_type == OutTypeLib && !g->is_static) + g->out_type == OutTypeLib && g->is_dynamic) { g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap_lib.zig"); } @@ -8297,7 +8332,8 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose cache_int(cache_hash, g->zig_target->abi); cache_bool(cache_hash, g->strip_debug_symbols); cache_int(cache_hash, g->build_mode); - cache_bool(cache_hash, g->disable_pic); + cache_bool(cache_hash, g->have_pic); + cache_bool(cache_hash, want_valgrind_support(g)); for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) { cache_str(cache_hash, g->clang_argv[arg_i]); } @@ -8451,7 +8487,7 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { args.append("-c"); args.append(buf_ptr(c_source_file)); - if (target_supports_fpic(g->zig_target) && !g->disable_pic) { + if (target_supports_fpic(g->zig_target) && g->have_pic) { args.append("-fPIC"); } @@ -9064,7 +9100,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_int(ch, g->zig_target->os); cache_int(ch, g->zig_target->abi); cache_int(ch, g->subsystem); - 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) { @@ -9074,9 +9109,10 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { 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->disable_gen_h); - cache_bool(ch, g->valgrind_support); + cache_bool(ch, want_valgrind_support(g)); + cache_bool(ch, g->have_pic); + cache_bool(ch, g->have_dynamic_link); cache_bool(ch, g->is_dummy_so); cache_buf_opt(ch, g->mmacosx_version_min); cache_buf_opt(ch, g->mios_version_min); @@ -9150,7 +9186,7 @@ static void resolve_out_paths(CodeGen *g) { buf_resize(out_basename, 0); buf_append_str(out_basename, target_lib_file_prefix(g->zig_target)); buf_append_buf(out_basename, g->root_out_name); - buf_append_str(out_basename, target_lib_file_ext(g->zig_target, g->is_static, + buf_append_str(out_basename, target_lib_file_ext(g->zig_target, !g->is_dynamic, g->version_major, g->version_minor, g->version_patch)); break; } @@ -9182,6 +9218,8 @@ void codegen_build_and_link(CodeGen *g) { g->output_dir = buf_create_from_str("."); } + g->have_dynamic_link = detect_dynamic_link(g); + g->have_pic = detect_pic(g); detect_libc(g); detect_dynamic_linker(g); diff --git a/src/ir.cpp b/src/ir.cpp index 26bc375003..f138080f00 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15543,9 +15543,8 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ } static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, AstNode *source_node) { - if (buf_eql_str(lib_name, "c") && ira->codegen->libc_link_lib == nullptr && - !ira->codegen->reported_bad_link_libc_error) - { + bool is_libc = target_is_libc_lib_name(ira->codegen->zig_target, buf_ptr(lib_name)); + if (is_libc && ira->codegen->libc_link_lib == nullptr && !ira->codegen->reported_bad_link_libc_error) { ir_add_error_node(ira, source_node, buf_sprintf("dependency on library c must be explicitly specified in the build command")); ira->codegen->reported_bad_link_libc_error = true; @@ -15558,6 +15557,16 @@ static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, return; } } + + if (!is_libc && !ira->codegen->have_pic && !ira->codegen->reported_bad_link_libc_error) { + ErrorMsg *msg = ir_add_error_node(ira, source_node, + buf_sprintf("dependency on dynamic library '%s' requires enabling Position Independent Code", + buf_ptr(lib_name))); + add_error_note(ira->codegen, msg, source_node, + buf_sprintf("fixed by `--library %s` or `--enable-pic`", buf_ptr(lib_name))); + ira->codegen->reported_bad_link_libc_error = true; + } + for (size_t i = 0; i < ira->codegen->forbidden_libs.length; i += 1) { Buf *forbidden_lib_name = ira->codegen->forbidden_libs.at(i); if (buf_eql_buf(lib_name, forbidden_lib_name)) { diff --git a/src/libc_installation.cpp b/src/libc_installation.cpp index 8a293af82a..14a9cd0b2d 100644 --- a/src/libc_installation.cpp +++ b/src/libc_installation.cpp @@ -102,7 +102,7 @@ Error zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file, const ZigTarget } if (buf_len(&libc->crt_dir) == 0) { - if (!target_is_darwin(target)) { + if (!target_os_is_darwin(target->os)) { if (verbose) { fprintf(stderr, "crt_dir may not be empty for %s\n", target_os_name(target->os)); } diff --git a/src/link.cpp b/src/link.cpp index b3aa94f0ee..e4f6fd3dd0 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -35,7 +35,7 @@ static CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, Ou child_gen->llvm_argv = parent_gen->llvm_argv; codegen_set_strip(child_gen, parent_gen->strip_debug_symbols); - child_gen->disable_pic = parent_gen->disable_pic; + child_gen->want_pic = parent_gen->have_pic ? WantPICEnabled : WantPICDisabled; child_gen->valgrind_support = ValgrindSupportDisabled; codegen_set_errmsg_color(child_gen, parent_gen->err_color); @@ -48,15 +48,6 @@ static CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, Ou return child_gen; } - -static bool target_is_glibc(CodeGen *g) { - return g->zig_target->os == OsLinux && target_abi_is_gnu(g->zig_target->abi); -} - -static bool target_is_musl(CodeGen *g) { - return g->zig_target->os == OsLinux && target_abi_is_musl(g->zig_target->abi); -} - static const char *build_libc_object(CodeGen *parent_gen, const char *name, CFile *c_file) { CodeGen *child_gen = create_child_codegen(parent_gen, nullptr, OutTypeObj, nullptr); codegen_set_out_name(child_gen, buf_create_from_str(name)); @@ -97,7 +88,7 @@ static const char *build_dummy_so(CodeGen *parent, const char *name, size_t majo CodeGen *child_gen = create_child_codegen(parent, glibc_dummy_root_src, OutTypeLib, nullptr); codegen_set_out_name(child_gen, buf_create_from_str(name)); codegen_set_lib_version(child_gen, major_version, 0, 0); - child_gen->is_static = false; + child_gen->is_dynamic = true; child_gen->is_dummy_so = true; codegen_build_and_link(child_gen); return buf_ptr(&child_gen->output_file_path); @@ -106,7 +97,6 @@ static const char *build_dummy_so(CodeGen *parent, const char *name, size_t majo static const char *build_libunwind(CodeGen *parent) { CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr); codegen_set_out_name(child_gen, buf_create_from_str("unwind")); - child_gen->is_static = true; LinkLib *new_link_lib = codegen_add_link_lib(child_gen, buf_create_from_str("c")); new_link_lib->provided_explicitly = false; enum SrcKind { @@ -490,7 +480,6 @@ static bool is_musl_arch_name(const char *name) { static const char *build_musl(CodeGen *parent) { CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr); codegen_set_out_name(child_gen, buf_create_from_str("c")); - child_gen->is_static = true; // When there is a src//foo.* then it should substitute for src/foo.* // Even a .s file can substitute for a .c file. @@ -608,7 +597,7 @@ static const char *build_musl(CodeGen *parent) { static const char *get_libc_crt_file(CodeGen *parent, const char *file) { - if (parent->libc == nullptr && target_is_glibc(parent)) { + if (parent->libc == nullptr && target_is_glibc(parent->zig_target)) { if (strcmp(file, "crti.o") == 0) { CFile *c_file = allocate(1); c_file->source_path = glibc_start_asm_path(parent, "crti.S"); @@ -677,7 +666,6 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file) { } else if (strcmp(file, "libc_nonshared.a") == 0) { CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr); codegen_set_out_name(child_gen, buf_create_from_str("c_nonshared")); - child_gen->is_static = true; { CFile *c_file = allocate(1); c_file->source_path = path_from_libc(parent, "glibc" OS_SEP "csu" OS_SEP "elf-init.c"); @@ -755,7 +743,7 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file) { } else { zig_unreachable(); } - } else if (parent->libc == nullptr && target_is_musl(parent)) { + } else if (parent->libc == nullptr && target_is_musl(parent->zig_target)) { if (strcmp(file, "crti.o") == 0) { return build_asm_object(parent, "crti", musl_start_asm_path(parent, "crti.s")); } else if (strcmp(file, "crtn.o") == 0) { @@ -799,7 +787,6 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path) CodeGen *child_gen = create_child_codegen(parent_gen, full_path, child_out_type, parent_gen->libc); - child_gen->is_static = true; codegen_set_out_name(child_gen, buf_create_from_str(aname)); // This is so that compiler_rt and builtin libraries know whether they @@ -924,9 +911,9 @@ static void construct_linker_job_elf(LinkJob *lj) { lj->args.append(getLDMOption(g->zig_target)); bool is_lib = g->out_type == OutTypeLib; - bool is_dyn_lib = !g->is_static && is_lib; + bool is_dyn_lib = g->is_dynamic && is_lib; Buf *soname = nullptr; - if (g->is_static) { + if (!g->have_dynamic_link) { if (g->zig_target->arch == ZigLLVM_arm || g->zig_target->arch == ZigLLVM_armeb || g->zig_target->arch == ZigLLVM_thumb || g->zig_target->arch == ZigLLVM_thumbeb) { @@ -948,7 +935,7 @@ static void construct_linker_job_elf(LinkJob *lj) { const char *crt1o; if (g->zig_target->os == OsNetBSD) { crt1o = "crt0.o"; - } else if (g->is_static) { + } else if (!g->have_dynamic_link) { crt1o = "crt1.o"; } else { crt1o = "Scrt1.o"; @@ -994,12 +981,11 @@ static void construct_linker_job_elf(LinkJob *lj) { lj->args.append(buf_ptr(&g->libc->crt_dir)); } - if (!g->is_static) { + if (g->have_dynamic_link && (is_dyn_lib || g->out_type == OutTypeExe)) { assert(g->dynamic_linker_path != nullptr); lj->args.append("-dynamic-linker"); lj->args.append(buf_ptr(g->dynamic_linker_path)); } - } if (is_dyn_lib) { @@ -1012,16 +998,14 @@ static void construct_linker_job_elf(LinkJob *lj) { lj->args.append((const char *)buf_ptr(g->link_objects.at(i))); } - if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && !g->is_static)) { - if (g->libc_link_lib == nullptr && !g->is_dummy_so) { + if (!g->is_dummy_so && (g->out_type == OutTypeExe || is_dyn_lib)) { + if (g->libc_link_lib == nullptr) { Buf *builtin_a_path = build_a(g, "builtin"); lj->args.append(buf_ptr(builtin_a_path)); } - if (!g->is_dummy_so) { - Buf *compiler_rt_o_path = build_compiler_rt(g); - lj->args.append(buf_ptr(compiler_rt_o_path)); - } + Buf *compiler_rt_o_path = build_compiler_rt(g); + lj->args.append(buf_ptr(compiler_rt_o_path)); } for (size_t i = 0; i < g->link_libs_list.length; i += 1) { @@ -1030,17 +1014,9 @@ static void construct_linker_job_elf(LinkJob *lj) { // libc is linked specially continue; } - if (g->libc == nullptr && (target_is_glibc(g) || target_is_musl(g))) { + if (g->libc == nullptr && target_is_libc_lib_name(g->zig_target, buf_ptr(link_lib->name))) { // these libraries are always linked below when targeting glibc - if (buf_eql_str(link_lib->name, "m")) { - continue; - } else if (buf_eql_str(link_lib->name, "pthread")) { - continue; - } else if (buf_eql_str(link_lib->name, "dl")) { - continue; - } else if (buf_eql_str(link_lib->name, "rt")) { - continue; - } + continue; } Buf *arg; if (buf_starts_with_str(link_lib->name, "/") || buf_ends_with_str(link_lib->name, ".a") || @@ -1057,7 +1033,7 @@ static void construct_linker_job_elf(LinkJob *lj) { // libc dep if (g->libc_link_lib != nullptr) { if (g->libc != nullptr) { - if (g->is_static) { + if (!g->have_dynamic_link) { lj->args.append("--start-group"); lj->args.append("-lgcc"); lj->args.append("-lgcc_eh"); @@ -1076,7 +1052,7 @@ static void construct_linker_job_elf(LinkJob *lj) { lj->args.append("-lgcc_s"); lj->args.append("--no-as-needed"); } - } else if (target_is_glibc(g)) { + } else if (target_is_glibc(g->zig_target)) { lj->args.append(build_libunwind(g)); lj->args.append(build_dummy_so(g, "c", 6)); lj->args.append(build_dummy_so(g, "m", 6)); @@ -1084,7 +1060,7 @@ static void construct_linker_job_elf(LinkJob *lj) { lj->args.append(build_dummy_so(g, "dl", 2)); lj->args.append(build_dummy_so(g, "rt", 1)); lj->args.append(get_libc_crt_file(g, "libc_nonshared.a")); - } else if (target_is_musl(g)) { + } else if (target_is_musl(g->zig_target)) { lj->args.append(build_libunwind(g)); lj->args.append(build_musl(g)); } else { @@ -1158,10 +1134,10 @@ static void add_nt_link_args(LinkJob *lj, bool is_library) { CodeGen *g = lj->codegen; if (lj->link_in_crt) { - const char *lib_str = g->is_static ? "lib" : ""; + const char *lib_str = g->is_dynamic ? "" : "lib"; const char *d_str = (g->build_mode == BuildModeDebug) ? "d" : ""; - if (g->is_static) { + if (!g->is_dynamic) { Buf *cmt_lib_name = buf_sprintf("libcmt%s.lib", d_str); lj->args.append(buf_ptr(cmt_lib_name)); } else { @@ -1265,7 +1241,7 @@ static void construct_linker_job_coff(LinkJob *lj) { lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->crt_dir)))); } - if (is_library && !g->is_static) { + if (is_library && g->is_dynamic) { lj->args.append("-DLL"); } @@ -1278,7 +1254,7 @@ static void construct_linker_job_coff(LinkJob *lj) { lj->args.append((const char *)buf_ptr(g->link_objects.at(i))); } - if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && !g->is_static)) { + if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && g->is_dynamic)) { if (g->libc_link_lib == nullptr && !g->is_dummy_so) { Buf *builtin_a_path = build_a(g, "builtin"); lj->args.append(buf_ptr(builtin_a_path)); @@ -1457,8 +1433,8 @@ static void construct_linker_job_macho(LinkJob *lj) { } bool is_lib = g->out_type == OutTypeLib; - bool is_dyn_lib = !g->is_static && is_lib; - if (g->is_static) { + bool is_dyn_lib = g->is_dynamic && is_lib; + if (!g->is_dynamic) { lj->args.append("-static"); } else { lj->args.append("-dynamic"); @@ -1509,11 +1485,7 @@ static void construct_linker_job_macho(LinkJob *lj) { if (g->out_type == OutTypeExe) { - if (g->is_static) { - lj->args.append("-no_pie"); - } else { - lj->args.append("-pie"); - } + lj->args.append("-pie"); } lj->args.append("-o"); @@ -1629,7 +1601,7 @@ void codegen_link(CodeGen *g) { lj.args.append("-r"); } - if (g->out_type == OutTypeLib && g->is_static) { + if (g->out_type == OutTypeLib && !g->is_dynamic) { ZigList file_names = {}; for (size_t i = 0; i < g->link_objects.length; i += 1) { file_names.append((const char *)buf_ptr(g->link_objects.at(i))); diff --git a/src/main.cpp b/src/main.cpp index bf05bb281d..81aaaaa368 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -52,7 +52,8 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " --cache [auto|off|on] build in cache, print output path to stdout\n" " --color [auto|off|on] enable or disable colored error messages\n" " --disable-gen-h do not generate a C header file (.h)\n" - " --disable-pic disable Position Independent Code for libraries\n" + " --disable-pic disable Position Independent Code\n" + " --enable-pic enable Position Independent Code\n" " --disable-valgrind omit valgrind client requests in debug builds\n" " --enable-valgrind include valgrind client requests release builds\n" " --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n" @@ -67,7 +68,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " --release-safe build with optimizations on and safety on\n" " --release-small build with size optimizations on and safety off\n" " --single-threaded source may assume it is only used single-threaded\n" - " --static output will be statically linked\n" + " -dynamic create a shared library (.so; .dll; .dylib)\n" " --strip exclude debug symbols\n" " -target [name] -- see the targets command\n" " --verbose-tokenize enable compiler debug output for tokenization\n" @@ -397,7 +398,7 @@ int main(int argc, char **argv) { const char *in_file = nullptr; Buf *output_dir = nullptr; bool strip = false; - bool is_static = false; + bool is_dynamic = false; OutType out_type = OutTypeUnknown; const char *out_name = nullptr; bool verbose_tokenize = false; @@ -432,7 +433,6 @@ int main(int argc, char **argv) { size_t ver_minor = 0; size_t ver_patch = 0; bool timing_info = false; - bool disable_pic = false; const char *cache_dir = nullptr; CliPkg *cur_pkg = allocate(1); BuildMode build_mode = BuildModeDebug; @@ -445,6 +445,7 @@ int main(int argc, char **argv) { Buf *override_std_dir = nullptr; Buf *main_pkg_path = nullptr; ValgrindSupport valgrind_support = ValgrindSupportAuto; + WantPIC want_pic = WantPICAuto; ZigList llvm_argv = {0}; llvm_argv.append("zig (LLVM option parsing)"); @@ -620,8 +621,8 @@ int main(int argc, char **argv) { } } else if (strcmp(arg, "--strip") == 0) { strip = true; - } else if (strcmp(arg, "--static") == 0) { - is_static = true; + } else if (strcmp(arg, "-dynamic") == 0) { + is_dynamic = true; } else if (strcmp(arg, "--verbose-tokenize") == 0) { verbose_tokenize = true; } else if (strcmp(arg, "--verbose-ast") == 0) { @@ -642,12 +643,14 @@ int main(int argc, char **argv) { each_lib_rpath = true; } else if (strcmp(arg, "-ftime-report") == 0) { timing_info = true; - } else if (strcmp(arg, "--disable-pic") == 0) { - disable_pic = true; } else if (strcmp(arg, "--enable-valgrind") == 0) { valgrind_support = ValgrindSupportEnabled; } else if (strcmp(arg, "--disable-valgrind") == 0) { valgrind_support = ValgrindSupportDisabled; + } else if (strcmp(arg, "--enable-pic") == 0) { + want_pic = WantPICEnabled; + } else if (strcmp(arg, "--disable-pic") == 0) { + want_pic = WantPICDisabled; } else if (strcmp(arg, "--system-linker-hack") == 0) { system_linker_hack = true; } else if (strcmp(arg, "--single-threaded") == 0) { @@ -904,12 +907,24 @@ int main(int argc, char **argv) { } if (output_dir != nullptr && enable_cache == CacheOptOn) { - fprintf(stderr, "The --output-dir argument is incompatible with --cache on.\n"); + fprintf(stderr, "`--output-dir` is incompatible with --cache on.\n"); + return print_error_usage(arg0); + } + + if (target_requires_pic(&target) && want_pic == WantPICDisabled) { + Buf triple_buf = BUF_INIT; + get_target_triple(&triple_buf, &target); + fprintf(stderr, "`--disable-pic` is incompatible with target '%s'\n", buf_ptr(&triple_buf)); return print_error_usage(arg0); } if (emit_file_type != EmitFileTypeBinary && in_file == nullptr) { - fprintf(stderr, "A root source file is required when using --emit asm or --emit llvm-ir"); + fprintf(stderr, "A root source file is required when using `--emit asm` or `--emit llvm-ir`\n"); + return print_error_usage(arg0); + } + + if (out_type != OutTypeLib && is_dynamic) { + fprintf(stderr, "`-dynamic` may only be specified with `build-lib`.\n"); return print_error_usage(arg0); } @@ -936,6 +951,7 @@ int main(int argc, char **argv) { CodeGen *g = codegen_create(main_pkg_path, nullptr, &target, out_type, build_mode, get_zig_lib_dir(), override_std_dir, nullptr, nullptr); g->valgrind_support = valgrind_support; + g->want_pic = want_pic; g->is_single_threaded = is_single_threaded; Buf *builtin_source = codegen_generate_builtin_source(g); if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) { @@ -1027,16 +1043,9 @@ int main(int argc, char **argv) { get_zig_lib_dir(), override_std_dir, libc, cache_dir_buf); if (llvm_argv.length >= 2) codegen_set_llvm_argv(g, llvm_argv.items + 1, llvm_argv.length - 2); g->valgrind_support = valgrind_support; + g->want_pic = want_pic; g->subsystem = subsystem; - if (disable_pic) { - if (out_type != OutTypeLib || !is_static) { - fprintf(stderr, "--disable-pic only applies to static libraries"); - return EXIT_FAILURE; - } - g->disable_pic = true; - } - g->enable_time_report = timing_info; codegen_set_out_name(g, buf_out_name); codegen_set_lib_version(g, ver_major, ver_minor, ver_patch); @@ -1049,7 +1058,7 @@ int main(int argc, char **argv) { codegen_set_clang_argv(g, clang_argv.items, clang_argv.length); codegen_set_strip(g, strip); - g->is_static = is_static; + g->is_dynamic = is_dynamic; g->dynamic_linker_path = dynamic_linker; g->verbose_tokenize = verbose_tokenize; g->verbose_ast = verbose_ast; diff --git a/src/target.cpp b/src/target.cpp index 440f0babe3..22d8dd2357 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -693,8 +693,8 @@ void get_target_triple(Buf *triple, const ZigTarget *target) { ZigLLVMGetEnvironmentTypeName(target->abi)); } -bool target_is_darwin(const ZigTarget *target) { - switch (target->os) { +bool target_os_is_darwin(Os os) { + switch (os) { case OsMacOSX: case OsIOS: case OsWatchOS: @@ -708,7 +708,7 @@ bool target_is_darwin(const ZigTarget *target) { ZigLLVM_ObjectFormatType target_object_format(const ZigTarget *target) { if (target->os == OsUefi || target->os == OsWindows) { return ZigLLVM_COFF; - } else if (target_is_darwin(target)) { + } else if (target_os_is_darwin(target->os)) { return ZigLLVM_MachO; } if (target->arch == ZigLLVM_wasm32 || @@ -942,7 +942,7 @@ const char *target_lib_file_ext(const ZigTarget *target, bool is_static, } else { if (is_static) { return ".a"; - } else if (target_is_darwin(target)) { + } else if (target_os_is_darwin(target->os)) { return buf_ptr(buf_sprintf(".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".dylib", version_major, version_minor, version_patch)); } else { @@ -1279,7 +1279,7 @@ bool target_has_valgrind_support(const ZigTarget *target) { case ZigLLVM_UnknownArch: zig_unreachable(); case ZigLLVM_x86_64: - return (target->os == OsLinux || target_is_darwin(target) || target->os == OsSolaris || + return (target->os == OsLinux || target_os_is_darwin(target->os) || target->os == OsSolaris || (target->os == OsWindows && target->abi != ZigLLVM_MSVC)); default: return false; @@ -1287,11 +1287,11 @@ bool target_has_valgrind_support(const ZigTarget *target) { zig_unreachable(); } -bool target_requires_libc(const ZigTarget *target) { +bool target_os_requires_libc(Os os) { // On Darwin, we always link libSystem which contains libc. // Similarly on FreeBSD and NetBSD we always link system libc // since this is the stable syscall interface. - return (target_is_darwin(target) || target->os == OsFreeBSD || target->os == OsNetBSD); + return (target_os_is_darwin(os) || os == OsFreeBSD || os == OsNetBSD); } bool target_supports_fpic(const ZigTarget *target) { @@ -1300,6 +1300,19 @@ bool target_supports_fpic(const ZigTarget *target) { return target->os != OsWindows; } +bool target_requires_pic(const ZigTarget *target) { + // This function returns whether non-pic code is completely invalid on the given target. + return target->os == OsWindows || target_os_requires_libc(target->os) || target_is_glibc(target); +} + +bool target_is_glibc(const ZigTarget *target) { + return target->os == OsLinux && target_abi_is_gnu(target->abi); +} + +bool target_is_musl(const ZigTarget *target) { + return target->os == OsLinux && target_abi_is_musl(target->abi); +} + ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) { switch (os) { case OsFreestanding: @@ -1458,3 +1471,29 @@ const char *target_libc_generic_name(const ZigTarget *target) { } zig_unreachable(); } + +bool target_is_libc_lib_name(const ZigTarget *target, const char *name) { + if (strcmp(name, "c") == 0) + return true; + + if (target_abi_is_gnu(target->abi) || target_abi_is_musl(target->abi)) { + if (strcmp(name, "m") == 0) + return true; + if (strcmp(name, "rt") == 0) + return true; + if (strcmp(name, "pthread") == 0) + return true; + if (strcmp(name, "crypt") == 0) + return true; + if (strcmp(name, "util") == 0) + return true; + if (strcmp(name, "xnet") == 0) + return true; + if (strcmp(name, "resolv") == 0) + return true; + if (strcmp(name, "dl") == 0) + return true; + } + + return false; +} diff --git a/src/target.hpp b/src/target.hpp index b79d95a530..072bfc184c 100644 --- a/src/target.hpp +++ b/src/target.hpp @@ -155,13 +155,17 @@ ZigLLVM_OSType get_llvm_os_type(Os os_type); bool target_is_arm(const ZigTarget *target); bool target_allows_addr_zero(const ZigTarget *target); bool target_has_valgrind_support(const ZigTarget *target); -bool target_is_darwin(const ZigTarget *target); -bool target_requires_libc(const ZigTarget *target); +bool target_os_is_darwin(Os os); +bool target_os_requires_libc(Os os); bool target_can_build_libc(const ZigTarget *target); const char *target_libc_generic_name(const ZigTarget *target); +bool target_is_libc_lib_name(const ZigTarget *target, const char *name); bool target_supports_fpic(const ZigTarget *target); +bool target_requires_pic(const ZigTarget *target); bool target_abi_is_gnu(ZigLLVM_EnvironmentType abi); bool target_abi_is_musl(ZigLLVM_EnvironmentType abi); +bool target_is_glibc(const ZigTarget *target); +bool target_is_musl(const ZigTarget *target); uint32_t target_arch_pointer_bit_width(ZigLLVM_ArchType arch); diff --git a/std/build.zig b/std/build.zig index 6d1749eca9..38be979da6 100644 --- a/std/build.zig +++ b/std/build.zig @@ -157,10 +157,6 @@ pub const Builder = struct { return LibExeObjStep.createExecutable(self, name, root_src, false); } - pub fn addStaticExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - return LibExeObjStep.createExecutable(self, name, root_src, true); - } - pub fn addObject(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { return LibExeObjStep.createObject(self, name, root_src); } @@ -920,7 +916,7 @@ pub const LibExeObjStep = struct { target: Target, linker_script: ?[]const u8, out_filename: []const u8, - static: bool, + is_dynamic: bool, version: Version, build_mode: builtin.Mode, kind: Kind, @@ -975,13 +971,13 @@ pub const LibExeObjStep = struct { pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep { const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, ver); + self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, ver); return self; } pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0)); + self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, builder.version(0, 0, 0)); return self; } @@ -991,9 +987,9 @@ pub const LibExeObjStep = struct { return self; } - pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, static: bool) *LibExeObjStep { + pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, is_dynamic: bool) *LibExeObjStep { const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0)); + self.* = initExtraArgs(builder, name, root_src, Kind.Exe, is_dynamic, builder.version(0, 0, 0)); return self; } @@ -1003,14 +999,14 @@ pub const LibExeObjStep = struct { return self; } - fn initExtraArgs(builder: *Builder, name: []const u8, root_src: ?[]const u8, kind: Kind, static: bool, ver: Version) LibExeObjStep { + fn initExtraArgs(builder: *Builder, name: []const u8, root_src: ?[]const u8, kind: Kind, is_dynamic: bool, ver: Version) LibExeObjStep { var self = LibExeObjStep{ .strip = false, .builder = builder, .verbose_link = false, .verbose_cc = false, .build_mode = builtin.Mode.Debug, - .static = static, + .is_dynamic = is_dynamic, .kind = kind, .root_src = root_src, .name = name, @@ -1057,7 +1053,7 @@ pub const LibExeObjStep = struct { self.out_filename = self.builder.fmt("test{}", self.target.exeFileExt()); }, Kind.Lib => { - if (self.static) { + if (!self.is_dynamic) { switch (self.target.getOs()) { builtin.Os.windows => { self.out_filename = self.builder.fmt("{}.lib", self.name); @@ -1147,7 +1143,7 @@ pub const LibExeObjStep = struct { } pub fn isDynamicLibrary(self: *LibExeObjStep) bool { - return self.kind == Kind.Lib and !self.static; + return self.kind == Kind.Lib and self.is_dynamic; } pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void { @@ -1333,7 +1329,7 @@ pub const LibExeObjStep = struct { try zig_args.append(other.getOutputPath()); }, LibExeObjStep.Kind.Lib => { - if (other.static or self.target.isWindows()) { + if (!other.is_dynamic or self.target.isWindows()) { try zig_args.append("--object"); try zig_args.append(other.getOutputLibPath()); } else { @@ -1413,7 +1409,7 @@ pub const LibExeObjStep = struct { zig_args.append("--name") catch unreachable; zig_args.append(self.name) catch unreachable; - if (self.kind == Kind.Lib and !self.static) { + if (self.kind == Kind.Lib and self.is_dynamic) { zig_args.append("--ver-major") catch unreachable; zig_args.append(builder.fmt("{}", self.version.major)) catch unreachable; @@ -1423,8 +1419,8 @@ pub const LibExeObjStep = struct { zig_args.append("--ver-patch") catch unreachable; zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable; } - if (self.static) { - zig_args.append("--static") catch unreachable; + if (self.is_dynamic) { + try zig_args.append("-dynamic"); } switch (self.target) { @@ -1531,7 +1527,7 @@ pub const LibExeObjStep = struct { self.output_dir = os.path.dirname(output_path).?; } - if (self.kind == Kind.Lib and !self.static and self.target.wantSharedLibSymLinks()) { + if (self.kind == Kind.Lib and self.is_dynamic and self.target.wantSharedLibSymLinks()) { try doAtomicSymLinks(builder.allocator, self.getOutputPath(), self.major_only_filename, self.name_only_filename); } } @@ -1677,7 +1673,7 @@ const InstallArtifactStep = struct { }; self.step.dependOn(&artifact.step); builder.pushInstalledFile(self.dest_file); - if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) { + if (self.artifact.kind == LibExeObjStep.Kind.Lib and self.artifact.is_dynamic) { builder.pushInstalledFile(os.path.join( builder.allocator, [][]const u8{ builder.lib_dir, artifact.major_only_filename }, @@ -1700,11 +1696,11 @@ const InstallArtifactStep = struct { LibExeObjStep.Kind.Obj => unreachable, LibExeObjStep.Kind.Test => unreachable, LibExeObjStep.Kind.Exe => u32(0o755), - LibExeObjStep.Kind.Lib => if (self.artifact.static) u32(0o666) else u32(0o755), + LibExeObjStep.Kind.Lib => if (!self.artifact.is_dynamic) u32(0o666) else u32(0o755), }, }; try builder.copyFileMode(self.artifact.getOutputPath(), self.dest_file, mode); - if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) { + if (self.artifact.isDynamicLibrary()) { try doAtomicSymLinks(builder.allocator, self.dest_file, self.artifact.major_only_filename, self.artifact.name_only_filename); } }