From ba78ae0ae73ac38a2bb32c618cd145b4d2f9602e Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Sun, 30 Sep 2018 22:59:45 +0200 Subject: Fixes --emit asm on windows and makes C header file generation explicit. (#1612) * build: only do codegen_link when emitting an actual binary. Fixes #1371 * build: only output C header file when explicitely asked to --- src/link.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/link.cpp') diff --git a/src/link.cpp b/src/link.cpp index aa0edde61b..a280c31f74 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -34,7 +34,7 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path) CodeGen *child_gen = codegen_create(full_path, child_target, OutTypeObj, parent_gen->build_mode, parent_gen->zig_lib_dir); - child_gen->want_h_file = false; + child_gen->out_h_path = nullptr; child_gen->verbose_tokenize = parent_gen->verbose_tokenize; child_gen->verbose_ast = parent_gen->verbose_ast; child_gen->verbose_link = parent_gen->verbose_link; -- cgit v1.2.3 From d4d22df1d90d9d78f2960e807c3dad061ed1c71a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 1 Oct 2018 14:10:18 -0400 Subject: increase stack size on windows for all executables fixes test failures See #157 --- src/link.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/link.cpp') diff --git a/src/link.cpp b/src/link.cpp index a280c31f74..2b58f14266 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -434,6 +434,11 @@ static void construct_linker_job_coff(LinkJob *lj) { lj->args.append("-DEBUG"); } + if (g->out_type == OutTypeExe) { + // TODO compile time stack upper bound detection + lj->args.append("/STACK:16777216"); + } + coff_append_machine_arg(g, &lj->args); if (g->windows_subsystem_windows) { -- cgit v1.2.3 From 24bbade217ed814bd6c4d94ed93442824b7153a4 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 2 Oct 2018 12:31:21 +0200 Subject: fix build-exe for --target-arch wasm32 (#1570) Pass --no-entry instead of --relocatable to lld. Both stop a reference to the _start() entry point from being emitted but --relocatable also prevents public symbols from being exported when creating an executable. --- src/link.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/link.cpp') diff --git a/src/link.cpp b/src/link.cpp index 2b58f14266..e3753bff24 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -386,7 +386,7 @@ static void construct_linker_job_elf(LinkJob *lj) { static void construct_linker_job_wasm(LinkJob *lj) { CodeGen *g = lj->codegen; - lj->args.append("--relocatable"); // So lld doesn't look for _start. + lj->args.append("--no-entry"); // So lld doesn't look for _start. lj->args.append("-o"); lj->args.append(buf_ptr(&g->output_file_path)); -- cgit v1.2.3 From 4640853d1b49ec17e1e997901c58c2294aca30d6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 5 Oct 2018 18:31:25 -0400 Subject: on linux, link statically if not linking any shared libs --- src/link.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src/link.cpp') diff --git a/src/link.cpp b/src/link.cpp index e3753bff24..8b75f0e783 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -215,9 +215,10 @@ static void construct_linker_job_elf(LinkJob *lj) { lj->args.append(getLDMOption(&g->zig_target)); bool is_lib = g->out_type == OutTypeLib; - bool shared = !g->is_static && is_lib; + bool is_static = g->is_static || (!is_lib && g->link_libs_list.length == 0); + bool shared = !is_static && is_lib; Buf *soname = nullptr; - if (g->is_static) { + if (is_static) { if (g->zig_target.arch.arch == ZigLLVM_arm || g->zig_target.arch.arch == ZigLLVM_armeb || g->zig_target.arch.arch == ZigLLVM_thumb || g->zig_target.arch.arch == ZigLLVM_thumbeb) { @@ -241,7 +242,7 @@ static void construct_linker_job_elf(LinkJob *lj) { if (lj->link_in_crt) { const char *crt1o; const char *crtbegino; - if (g->is_static) { + if (is_static) { crt1o = "crt1.o"; crtbegino = "crtbeginT.o"; } else { @@ -292,7 +293,7 @@ static void construct_linker_job_elf(LinkJob *lj) { lj->args.append(buf_ptr(g->libc_static_lib_dir)); } - if (!g->is_static) { + if (!is_static) { if (g->dynamic_linker != nullptr) { assert(buf_len(g->dynamic_linker) != 0); lj->args.append("-dynamic-linker"); @@ -344,7 +345,7 @@ static void construct_linker_job_elf(LinkJob *lj) { // libc dep if (g->libc_link_lib != nullptr) { - if (g->is_static) { + if (is_static) { lj->args.append("--start-group"); lj->args.append("-lgcc"); lj->args.append("-lgcc_eh"); -- cgit v1.2.3 From 5a3c02137e6a15d3b8c1fb3595d55003ea44139a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 8 Oct 2018 13:24:39 -0400 Subject: support building static libraries closes #1493 closes #54 --- src/codegen.cpp | 4 +++- src/link.cpp | 43 +++++++++++++++++++++++-------------------- src/target.cpp | 2 +- src/target.hpp | 2 +- src/zig_llvm.cpp | 40 +++++++++++++++++++++++++++++++++++++++- src/zig_llvm.h | 3 +++ std/special/bootstrap_lib.zig | 2 +- 7 files changed, 71 insertions(+), 25 deletions(-) (limited to 'src/link.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index e792fd77aa..fd7a386078 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7487,7 +7487,9 @@ 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) { + if (g->zig_target.os == OsWindows && !g->have_dllmain_crt_startup && + g->out_type == OutTypeLib && !g->is_static) + { g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap_lib.zig"); } diff --git a/src/link.cpp b/src/link.cpp index 8b75f0e783..c961042324 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -29,9 +29,9 @@ static const char *get_libc_static_file(CodeGen *g, const char *file) { return buf_ptr(out_buf); } -static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path) { +static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path) { ZigTarget *child_target = parent_gen->is_native_target ? nullptr : &parent_gen->zig_target; - CodeGen *child_gen = codegen_create(full_path, child_target, OutTypeObj, parent_gen->build_mode, + CodeGen *child_gen = codegen_create(full_path, child_target, OutTypeLib, parent_gen->build_mode, parent_gen->zig_lib_dir); child_gen->out_h_path = nullptr; @@ -43,32 +43,26 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path) child_gen->verbose_cimport = parent_gen->verbose_cimport; codegen_set_strip(child_gen, parent_gen->strip_debug_symbols); - codegen_set_is_static(child_gen, parent_gen->is_static); + codegen_set_is_static(child_gen, true); - codegen_set_out_name(child_gen, buf_create_from_str(oname)); + codegen_set_out_name(child_gen, buf_create_from_str(aname)); codegen_set_errmsg_color(child_gen, parent_gen->err_color); codegen_set_mmacosx_version_min(child_gen, parent_gen->mmacosx_version_min); codegen_set_mios_version_min(child_gen, parent_gen->mios_version_min); - for (size_t i = 0; i < parent_gen->link_libs_list.length; i += 1) { - LinkLib *link_lib = parent_gen->link_libs_list.at(i); - LinkLib *new_link_lib = codegen_add_link_lib(child_gen, link_lib->name); - new_link_lib->provided_explicitly = link_lib->provided_explicitly; - } - child_gen->enable_cache = true; codegen_build_and_link(child_gen); return &child_gen->output_file_path; } -static Buf *build_o(CodeGen *parent_gen, const char *oname) { - Buf *source_basename = buf_sprintf("%s.zig", oname); +static Buf *build_a(CodeGen *parent_gen, const char *aname) { + Buf *source_basename = buf_sprintf("%s.zig", aname); Buf *full_path = buf_alloc(); os_path_join(parent_gen->zig_std_special_dir, source_basename, full_path); - return build_o_raw(parent_gen, oname, full_path); + return build_a_raw(parent_gen, aname, full_path); } static Buf *build_compiler_rt(CodeGen *parent_gen) { @@ -77,7 +71,7 @@ static Buf *build_compiler_rt(CodeGen *parent_gen) { Buf *full_path = buf_alloc(); os_path_join(dir_path, buf_create_from_str("index.zig"), full_path); - return build_o_raw(parent_gen, "compiler_rt", full_path); + return build_a_raw(parent_gen, "compiler_rt", full_path); } static const char *get_darwin_arch_string(const ZigTarget *t) { @@ -317,8 +311,8 @@ static void construct_linker_job_elf(LinkJob *lj) { if (g->out_type == OutTypeExe || g->out_type == OutTypeLib) { if (g->libc_link_lib == nullptr) { - Buf *builtin_o_path = build_o(g, "builtin"); - lj->args.append(buf_ptr(builtin_o_path)); + Buf *builtin_a_path = build_a(g, "builtin"); + lj->args.append(buf_ptr(builtin_a_path)); } // sometimes libgcc is missing stuff, so we still build compiler_rt and rely on weak linkage @@ -548,8 +542,8 @@ static void construct_linker_job_coff(LinkJob *lj) { if (g->out_type == OutTypeExe || g->out_type == OutTypeLib) { if (g->libc_link_lib == nullptr) { - Buf *builtin_o_path = build_o(g, "builtin"); - lj->args.append(buf_ptr(builtin_o_path)); + Buf *builtin_a_path = build_a(g, "builtin"); + lj->args.append(buf_ptr(builtin_a_path)); } // msvc compiler_rt is missing some stuff, so we still build it and rely on weak linkage @@ -960,8 +954,17 @@ void codegen_link(CodeGen *g) { } if (g->out_type == OutTypeLib && g->is_static) { - fprintf(stderr, "Zig does not yet support creating static libraries\nSee https://github.com/ziglang/zig/issues/1493\n"); - exit(1); + 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))); + } + ZigLLVM_OSType os_type = get_llvm_os_type(g->zig_target.os); + codegen_add_time_event(g, "LLVM Link"); + if (ZigLLVMWriteArchive(buf_ptr(&g->output_file_path), file_names.items, file_names.length, os_type)) { + fprintf(stderr, "Unable to write archive '%s'\n", buf_ptr(&g->output_file_path)); + exit(1); + } + return; } lj.link_in_crt = (g->libc_link_lib != nullptr && g->out_type == OutTypeExe); diff --git a/src/target.cpp b/src/target.cpp index 525935310a..25dfa9d3cb 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -250,7 +250,7 @@ Os get_target_os(size_t index) { return os_list[index]; } -static ZigLLVM_OSType get_llvm_os_type(Os os_type) { +ZigLLVM_OSType get_llvm_os_type(Os os_type) { switch (os_type) { case OsFreestanding: case OsZen: diff --git a/src/target.hpp b/src/target.hpp index 0e0b1f2dc5..a4685fc09e 100644 --- a/src/target.hpp +++ b/src/target.hpp @@ -119,6 +119,6 @@ const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t versio Buf *target_dynamic_linker(ZigTarget *target); bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target); - +ZigLLVM_OSType get_llvm_os_type(Os os_type); #endif diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index ea270bcb5a..00023f6232 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include #include @@ -40,8 +42,8 @@ #include #include #include -#include #include +#include #include #include @@ -854,6 +856,42 @@ class MyOStream: public raw_ostream { size_t pos; }; +bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count, + ZigLLVM_OSType os_type) +{ + object::Archive::Kind kind; + switch (os_type) { + case ZigLLVM_Win32: + // For some reason llvm-lib passes K_GNU on windows. + // See lib/ToolDrivers/llvm-lib/LibDriver.cpp:168 in libDriverMain + kind = object::Archive::K_GNU; + break; + case ZigLLVM_Linux: + kind = object::Archive::K_GNU; + break; + case ZigLLVM_Darwin: + case ZigLLVM_IOS: + kind = object::Archive::K_DARWIN; + break; + case ZigLLVM_OpenBSD: + case ZigLLVM_FreeBSD: + kind = object::Archive::K_BSD; + break; + default: + kind = object::Archive::K_GNU; + } + SmallVector new_members; + for (size_t i = 0; i < file_name_count; i += 1) { + Expected new_member = NewArchiveMember::getFile(file_names[i], true); + Error err = new_member.takeError(); + if (err) return true; + new_members.push_back(std::move(*new_member)); + } + Error err = writeArchive(archive_name, new_members, true, kind, true, false, nullptr); + if (err) return true; + return false; +} + bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, void (*append_diagnostic)(void *, const char *, size_t), void *context) diff --git a/src/zig_llvm.h b/src/zig_llvm.h index a005b3157e..551a4a7448 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -406,6 +406,9 @@ ZIG_EXTERN_C const char *ZigLLVMGetEnvironmentTypeName(enum ZigLLVM_EnvironmentT ZIG_EXTERN_C bool ZigLLDLink(enum ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, void (*append_diagnostic)(void *, const char *, size_t), void *context); +ZIG_EXTERN_C bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count, + enum ZigLLVM_OSType os_type); + ZIG_EXTERN_C void ZigLLVMGetNativeTarget(enum ZigLLVM_ArchType *arch_type, enum ZigLLVM_SubArchType *sub_arch_type, enum ZigLLVM_VendorType *vendor_type, enum ZigLLVM_OSType *os_type, enum ZigLLVM_EnvironmentType *environ_type, enum ZigLLVM_ObjectFormatType *oformat); diff --git a/std/special/bootstrap_lib.zig b/std/special/bootstrap_lib.zig index f029495cb0..701eee389d 100644 --- a/std/special/bootstrap_lib.zig +++ b/std/special/bootstrap_lib.zig @@ -1,4 +1,4 @@ -// This file is included in the compilation unit when exporting a library on windows. +// This file is included in the compilation unit when exporting a DLL on windows. const std = @import("std"); const builtin = @import("builtin"); -- cgit v1.2.3 From 6b93495792678bd00a6205967bb2704a9a35e9c7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 9 Oct 2018 12:18:09 -0400 Subject: more efficient builtin library code generation * introduce --disable-pic option which can generally be allowed to be the default. compiler_rt.a and builtin.a get this option when you build a static executable. * compiler_rt and builtin libraries are not built for build-lib --static * posix_spawn instead of fork/execv * disable the error limit on LLD. Fixes the blank lines printed --- src/all_types.hpp | 1 + src/codegen.cpp | 6 +++++- src/link.cpp | 19 ++++++++++--------- src/main.cpp | 12 ++++++++++++ src/os.cpp | 34 ++++++++++++++++------------------ 5 files changed, 44 insertions(+), 28 deletions(-) (limited to 'src/link.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index d7071590d8..a144013947 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1763,6 +1763,7 @@ struct CodeGen { bool linker_rdynamic; bool no_rosegment_workaround; bool each_lib_rpath; + bool disable_pic; Buf *mmacosx_version_min; Buf *mios_version_min; diff --git a/src/codegen.cpp b/src/codegen.cpp index fd7a386078..02105b4d2a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7228,7 +7228,10 @@ static void init(CodeGen *g) { bool is_optimized = g->build_mode != BuildModeDebug; LLVMCodeGenOptLevel opt_level = is_optimized ? LLVMCodeGenLevelAggressive : LLVMCodeGenLevelNone; - LLVMRelocMode reloc_mode = g->is_static ? LLVMRelocStatic : LLVMRelocPIC; + if (g->out_type == OutTypeExe && g->is_static) { + g->disable_pic = true; + } + LLVMRelocMode reloc_mode = g->disable_pic ? LLVMRelocStatic : LLVMRelocPIC; const char *target_specific_cpu_args; const char *target_specific_features; @@ -8047,6 +8050,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_bool(ch, g->linker_rdynamic); cache_bool(ch, g->no_rosegment_workaround); cache_bool(ch, g->each_lib_rpath); + cache_bool(ch, g->disable_pic); cache_buf_opt(ch, g->mmacosx_version_min); cache_buf_opt(ch, g->mios_version_min); cache_usize(ch, g->version_major); diff --git a/src/link.cpp b/src/link.cpp index c961042324..095d3d79d7 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -44,6 +44,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path) codegen_set_strip(child_gen, parent_gen->strip_debug_symbols); codegen_set_is_static(child_gen, true); + child_gen->disable_pic = parent_gen->disable_pic; codegen_set_out_name(child_gen, buf_create_from_str(aname)); @@ -209,10 +210,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_static = g->is_static || (!is_lib && g->link_libs_list.length == 0); - bool shared = !is_static && is_lib; + bool shared = !g->is_static && is_lib; Buf *soname = nullptr; - if (is_static) { + if (g->is_static) { if (g->zig_target.arch.arch == ZigLLVM_arm || g->zig_target.arch.arch == ZigLLVM_armeb || g->zig_target.arch.arch == ZigLLVM_thumb || g->zig_target.arch.arch == ZigLLVM_thumbeb) { @@ -236,7 +236,7 @@ static void construct_linker_job_elf(LinkJob *lj) { if (lj->link_in_crt) { const char *crt1o; const char *crtbegino; - if (is_static) { + if (g->is_static) { crt1o = "crt1.o"; crtbegino = "crtbeginT.o"; } else { @@ -287,7 +287,7 @@ static void construct_linker_job_elf(LinkJob *lj) { lj->args.append(buf_ptr(g->libc_static_lib_dir)); } - if (!is_static) { + if (!g->is_static) { if (g->dynamic_linker != nullptr) { assert(buf_len(g->dynamic_linker) != 0); lj->args.append("-dynamic-linker"); @@ -309,7 +309,7 @@ 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) { + if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && !g->is_static)) { if (g->libc_link_lib == nullptr) { Buf *builtin_a_path = build_a(g, "builtin"); lj->args.append(buf_ptr(builtin_a_path)); @@ -339,7 +339,7 @@ static void construct_linker_job_elf(LinkJob *lj) { // libc dep if (g->libc_link_lib != nullptr) { - if (is_static) { + if (g->is_static) { lj->args.append("--start-group"); lj->args.append("-lgcc"); lj->args.append("-lgcc_eh"); @@ -540,7 +540,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) { + if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && !g->is_static)) { if (g->libc_link_lib == nullptr) { Buf *builtin_a_path = build_a(g, "builtin"); lj->args.append(buf_ptr(builtin_a_path)); @@ -872,7 +872,7 @@ static void construct_linker_job_macho(LinkJob *lj) { } // compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce - if (g->out_type == OutTypeExe || g->out_type == OutTypeLib) { + if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && !g->is_static)) { Buf *compiler_rt_o_path = build_compiler_rt(g); lj->args.append(buf_ptr(compiler_rt_o_path)); } @@ -969,6 +969,7 @@ void codegen_link(CodeGen *g) { lj.link_in_crt = (g->libc_link_lib != nullptr && g->out_type == OutTypeExe); + lj.args.append("-error-limit=0"); construct_linker_job(&lj); diff --git a/src/main.cpp b/src/main.cpp index f9df802cb3..5e827b5ba6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -47,6 +47,7 @@ static int print_full_usage(const char *arg0) { " --cache-dir [path] override the cache directory\n" " --cache [auto|off|on] build in global cache, print out paths to stdout\n" " --color [auto|off|on] enable or disable colored error messages\n" + " --disable-pic disable Position Independent Code for libraries\n" " --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n" " -ftime-report print timing diagnostics\n" " --libc-include-dir [path] directory where libc stdlib.h resides\n" @@ -386,6 +387,7 @@ 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; @@ -556,6 +558,8 @@ 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, "--test-cmd-bin") == 0) { test_exec_args.append(nullptr); } else if (arg[1] == 'L' && arg[2] != 0) { @@ -849,6 +853,14 @@ int main(int argc, char **argv) { buf_out_name = buf_create_from_str("run"); } CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir()); + 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; buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name); codegen_set_out_name(g, buf_out_name); diff --git a/src/os.cpp b/src/os.cpp index ed069b2ff8..e1bd6bd479 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -46,6 +46,7 @@ typedef SSIZE_T ssize_t; #include #include #include +#include #endif @@ -88,25 +89,22 @@ static void populate_termination(Termination *term, int status) { } static void os_spawn_process_posix(const char *exe, ZigList &args, Termination *term) { - pid_t pid = fork(); - if (pid == -1) - zig_panic("fork failed: %s", strerror(errno)); - if (pid == 0) { - // child - const char **argv = allocate(args.length + 2); - argv[0] = exe; - argv[args.length + 1] = nullptr; - for (size_t i = 0; i < args.length; i += 1) { - argv[i + 1] = args.at(i); - } - execvp(exe, const_cast(argv)); - zig_panic("execvp failed: %s", strerror(errno)); - } else { - // parent - int status; - waitpid(pid, &status, 0); - populate_termination(term, status); + const char **argv = allocate(args.length + 2); + argv[0] = exe; + argv[args.length + 1] = nullptr; + for (size_t i = 0; i < args.length; i += 1) { + argv[i + 1] = args.at(i); } + + pid_t pid; + int rc = posix_spawn(&pid, exe, nullptr, nullptr, const_cast(argv), environ); + if (rc != 0) { + zig_panic("posix_spawn failed: %s", strerror(rc)); + } + + int status; + waitpid(pid, &status, 0); + populate_termination(term, status); } #endif -- cgit v1.2.3 From e0a94db65e24c756e5e91ac1dfafa5c85035eaee Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 9 Oct 2018 12:46:22 -0400 Subject: fix error limit linker arg on windows --- src/link.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/link.cpp') diff --git a/src/link.cpp b/src/link.cpp index 095d3d79d7..6166584353 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -192,6 +192,8 @@ static Buf *get_dynamic_linker_path(CodeGen *g) { static void construct_linker_job_elf(LinkJob *lj) { CodeGen *g = lj->codegen; + lj->args.append("-error-limit=0"); + if (g->libc_link_lib != nullptr) { find_libc_lib_path(g); } @@ -381,6 +383,7 @@ static void construct_linker_job_elf(LinkJob *lj) { static void construct_linker_job_wasm(LinkJob *lj) { CodeGen *g = lj->codegen; + lj->args.append("-error-limit=0"); lj->args.append("--no-entry"); // So lld doesn't look for _start. lj->args.append("-o"); lj->args.append(buf_ptr(&g->output_file_path)); @@ -419,6 +422,8 @@ static bool zig_lld_link(ZigLLVM_ObjectFormatType oformat, const char **args, si static void construct_linker_job_coff(LinkJob *lj) { CodeGen *g = lj->codegen; + lj->args.append("/ERRORLIMIT:0"); + if (g->libc_link_lib != nullptr) { find_libc_lib_path(g); } @@ -755,6 +760,7 @@ static bool darwin_version_lt(DarwinPlatform *platform, int major, int minor) { static void construct_linker_job_macho(LinkJob *lj) { CodeGen *g = lj->codegen; + lj->args.append("-error-limit=0"); lj->args.append("-demangle"); if (g->linker_rdynamic) { @@ -969,7 +975,6 @@ void codegen_link(CodeGen *g) { lj.link_in_crt = (g->libc_link_lib != nullptr && g->out_type == OutTypeExe); - lj.args.append("-error-limit=0"); construct_linker_job(&lj); -- cgit v1.2.3 From e29a3b1d2a74732c6e6e4a1f10a02b45797fe4e2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 9 Oct 2018 13:02:01 -0400 Subject: stage1 link: compiler_rt and builtin libs know ... ...whether they will be linked with libc --- src/link.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/link.cpp') diff --git a/src/link.cpp b/src/link.cpp index 6166584353..ad3e0ef8d0 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -53,6 +53,14 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path) codegen_set_mmacosx_version_min(child_gen, parent_gen->mmacosx_version_min); codegen_set_mios_version_min(child_gen, parent_gen->mios_version_min); + // This is so that compiler_rt and builtin libraries know whether they + // will eventually be linked with libc. They make different decisions + // about what to export depending on whether libc is linked. + if (parent_gen->libc_link_lib != nullptr) { + LinkLib *new_link_lib = codegen_add_link_lib(child_gen, parent_gen->libc_link_lib->name); + new_link_lib->provided_explicitly = parent_gen->libc_link_lib->provided_explicitly; + } + child_gen->enable_cache = true; codegen_build_and_link(child_gen); return &child_gen->output_file_path; -- cgit v1.2.3 From 81c6f087241b6b7a1c12de72a2061cb02df0f93f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 9 Oct 2018 13:12:50 -0400 Subject: add workaround for bad LLD macos code --- src/link.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src/link.cpp') diff --git a/src/link.cpp b/src/link.cpp index ad3e0ef8d0..424b06169e 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -31,8 +31,18 @@ static const char *get_libc_static_file(CodeGen *g, const char *file) { static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path) { ZigTarget *child_target = parent_gen->is_native_target ? nullptr : &parent_gen->zig_target; - CodeGen *child_gen = codegen_create(full_path, child_target, OutTypeLib, parent_gen->build_mode, - parent_gen->zig_lib_dir); + + // The Mach-O LLD code is not well maintained, and trips an assertion + // when we link compiler_rt and builtin as libraries rather than objects. + // Here we workaround this by having compiler_rt and builtin be objects. + // TODO write our own linker. https://github.com/ziglang/zig/issues/1535 + OutType child_out_type = OutTypeLib; + if (parent_gen->zig_target.os == OsMacOSX) { + child_out_type = OutTypeObj; + } + + CodeGen *child_gen = codegen_create(full_path, child_target, child_out_type, + parent_gen->build_mode, parent_gen->zig_lib_dir); child_gen->out_h_path = nullptr; child_gen->verbose_tokenize = parent_gen->verbose_tokenize; -- cgit v1.2.3 From 1554dd9697b77b4fe4a309247982c3e29048f124 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 2 Nov 2018 00:07:43 -0400 Subject: support building static self hosted compiler on macos * add a --system-linker-hack command line parameter to work around poor LLD macho code. See #1535 * build.zig correctly handles static as well as dynamic dependencies when building the self hosted compiler. - no more unnecessary libxml2 dependency - a static build on macos produces a completely static self-hosted compiler for macos (except for libSystem as intended). --- build.zig | 122 +++++++++++++++++++++++++++++++++++++----------------- src/all_types.hpp | 1 + src/link.cpp | 15 ++++++- src/main.cpp | 4 ++ src/os.cpp | 2 +- std/build.zig | 19 +++++++++ 6 files changed, 122 insertions(+), 41 deletions(-) (limited to 'src/link.cpp') diff --git a/build.zig b/build.zig index c2a20015a7..c4a95bb0a9 100644 --- a/build.zig +++ b/build.zig @@ -121,12 +121,23 @@ pub fn build(b: *Builder) !void { test_step.dependOn(docs_step); } -fn dependOnLib(lib_exe_obj: var, dep: LibraryDep) void { +fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void { for (dep.libdirs.toSliceConst()) |lib_dir| { lib_exe_obj.addLibPath(lib_dir); } + const lib_dir = os.path.join(b.allocator, dep.prefix, "lib") catch unreachable; for (dep.system_libs.toSliceConst()) |lib| { - lib_exe_obj.linkSystemLibrary(lib); + const static_bare_name = if (mem.eql(u8, lib, "curses")) + ([]const u8)("libncurses.a") + else + b.fmt("lib{}.a", lib); + const static_lib_name = os.path.join(b.allocator, lib_dir, static_bare_name) catch unreachable; + const have_static = fileExists(static_lib_name) catch unreachable; + if (have_static) { + lib_exe_obj.addObjectFile(static_lib_name); + } else { + lib_exe_obj.linkSystemLibrary(lib); + } } for (dep.libs.toSliceConst()) |lib| { lib_exe_obj.addObjectFile(lib); @@ -136,12 +147,23 @@ fn dependOnLib(lib_exe_obj: var, dep: LibraryDep) void { } } +fn fileExists(filename: []const u8) !bool { + os.File.access(filename) catch |err| switch (err) { + error.PermissionDenied, + error.FileNotFound, + => return false, + else => return err, + }; + return true; +} + fn addCppLib(b: *Builder, lib_exe_obj: var, cmake_binary_dir: []const u8, lib_name: []const u8) void { const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib"; lib_exe_obj.addObjectFile(os.path.join(b.allocator, cmake_binary_dir, "zig_cpp", b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt())) catch unreachable); } const LibraryDep = struct.{ + prefix: []const u8, libdirs: ArrayList([]const u8), libs: ArrayList([]const u8), system_libs: ArrayList([]const u8), @@ -149,21 +171,25 @@ const LibraryDep = struct.{ }; fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { - const libs_output = try b.exec([][]const u8.{ - llvm_config_exe, - "--libs", - "--system-libs", - }); - const includes_output = try b.exec([][]const u8.{ - llvm_config_exe, - "--includedir", - }); - const libdir_output = try b.exec([][]const u8.{ - llvm_config_exe, - "--libdir", - }); + const shared_mode = try b.exec([][]const u8.{ llvm_config_exe, "--shared-mode" }); + const is_static = mem.startsWith(u8, shared_mode, "static"); + const libs_output = if (is_static) + try b.exec([][]const u8.{ + llvm_config_exe, + "--libfiles", + "--system-libs", + }) + else + try b.exec([][]const u8.{ + llvm_config_exe, + "--libs", + }); + const includes_output = try b.exec([][]const u8.{ llvm_config_exe, "--includedir" }); + const libdir_output = try b.exec([][]const u8.{ llvm_config_exe, "--libdir" }); + const prefix_output = try b.exec([][]const u8.{ llvm_config_exe, "--prefix" }); var result = LibraryDep.{ + .prefix = mem.split(prefix_output, " \r\n").next().?, .libs = ArrayList([]const u8).init(b.allocator), .system_libs = ArrayList([]const u8).init(b.allocator), .includes = ArrayList([]const u8).init(b.allocator), @@ -244,10 +270,6 @@ fn nextValue(index: *usize, build_info: []const u8) []const u8 { } fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { - // This is for finding /lib/libz.a on alpine linux. - // TODO turn this into -Dextra-lib-path=/lib option - exe.addLibPath("/lib"); - exe.setNoRoSegment(ctx.no_rosegment); exe.addIncludeDir("src"); @@ -265,39 +287,63 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_coff"); addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_lib"); } - dependOnLib(exe, ctx.llvm); + dependOnLib(b, exe, ctx.llvm); if (exe.target.getOs() == builtin.Os.linux) { - const libstdcxx_path_padded = try b.exec([][]const u8.{ - ctx.cxx_compiler, - "-print-file-name=libstdc++.a", - }); - const libstdcxx_path = mem.split(libstdcxx_path_padded, "\r\n").next().?; - if (mem.eql(u8, libstdcxx_path, "libstdc++.a")) { - warn( - \\Unable to determine path to libstdc++.a - \\On Fedora, install libstdc++-static and try again. - \\ - ); - return error.RequiredLibraryNotFound; - } - exe.addObjectFile(libstdcxx_path); + try addCxxKnownPath(b, ctx, exe, "libstdc++.a", + \\Unable to determine path to libstdc++.a + \\On Fedora, install libstdc++-static and try again. + \\ + ); exe.linkSystemLibrary("pthread"); } else if (exe.target.isDarwin()) { - exe.linkSystemLibrary("c++"); + if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) { + // Compiler is GCC. + try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null); + exe.linkSystemLibrary("pthread"); + // TODO LLD cannot perform this link. + // See https://github.com/ziglang/zig/issues/1535 + exe.enableSystemLinkerHack(); + } else |err| switch (err) { + error.RequiredLibraryNotFound => { + // System compiler, not gcc. + exe.linkSystemLibrary("c++"); + }, + else => return err, + } } if (ctx.dia_guids_lib.len != 0) { exe.addObjectFile(ctx.dia_guids_lib); } - if (exe.target.getOs() != builtin.Os.windows) { - exe.linkSystemLibrary("xml2"); - } exe.linkSystemLibrary("c"); } +fn addCxxKnownPath( + b: *Builder, + ctx: Context, + exe: var, + objname: []const u8, + errtxt: ?[]const u8, +) !void { + const path_padded = try b.exec([][]const u8.{ + ctx.cxx_compiler, + b.fmt("-print-file-name={}", objname), + }); + const path_unpadded = mem.split(path_padded, "\r\n").next().?; + if (mem.eql(u8, path_unpadded, objname)) { + if (errtxt) |msg| { + warn("{}", msg); + } else { + warn("Unable to determine path to {}\n", objname); + } + return error.RequiredLibraryNotFound; + } + exe.addObjectFile(path_unpadded); +} + const Context = struct.{ cmake_binary_dir: []const u8, cxx_compiler: []const u8, diff --git a/src/all_types.hpp b/src/all_types.hpp index c490999a2b..0276d6212e 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1731,6 +1731,7 @@ struct CodeGen { bool generate_error_name_table; bool enable_cache; bool enable_time_report; + bool system_linker_hack; //////////////////////////// Participates in Input Parameter Cache Hash ZigList link_libs_list; diff --git a/src/link.cpp b/src/link.cpp index 424b06169e..0e729fa918 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -778,7 +778,8 @@ static bool darwin_version_lt(DarwinPlatform *platform, int major, int minor) { static void construct_linker_job_macho(LinkJob *lj) { CodeGen *g = lj->codegen; - lj->args.append("-error-limit=0"); + // LLD MACH-O has no error limit option. + //lj->args.append("-error-limit=0"); lj->args.append("-demangle"); if (g->linker_rdynamic) { @@ -1007,7 +1008,17 @@ void codegen_link(CodeGen *g) { Buf diag = BUF_INIT; codegen_add_time_event(g, "LLVM Link"); - if (!zig_lld_link(g->zig_target.oformat, lj.args.items, lj.args.length, &diag)) { + if (g->system_linker_hack && g->zig_target.os == OsMacOSX) { + Termination term; + ZigList args = {}; + for (size_t i = 1; i < lj.args.length; i += 1) { + args.append(lj.args.at(i)); + } + os_spawn_process("ld", args, &term); + if (term.how != TerminationIdClean || term.code != 0) { + exit(1); + } + } else if (!zig_lld_link(g->zig_target.oformat, lj.args.items, lj.args.length, &diag)) { fprintf(stderr, "%s\n", buf_ptr(&diag)); exit(1); } diff --git a/src/main.cpp b/src/main.cpp index 5e827b5ba6..84ff2fb4b2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -394,6 +394,7 @@ int main(int argc, char **argv) { ZigList test_exec_args = {0}; int runtime_args_start = -1; bool no_rosegment_workaround = false; + bool system_linker_hack = false; if (argc >= 2 && strcmp(argv[1], "build") == 0) { Buf zig_exe_path_buf = BUF_INIT; @@ -560,6 +561,8 @@ int main(int argc, char **argv) { timing_info = true; } else if (strcmp(arg, "--disable-pic") == 0) { disable_pic = true; + } else if (strcmp(arg, "--system-linker-hack") == 0) { + system_linker_hack = true; } else if (strcmp(arg, "--test-cmd-bin") == 0) { test_exec_args.append(nullptr); } else if (arg[1] == 'L' && arg[2] != 0) { @@ -893,6 +896,7 @@ int main(int argc, char **argv) { g->verbose_llvm_ir = verbose_llvm_ir; g->verbose_cimport = verbose_cimport; codegen_set_errmsg_color(g, color); + g->system_linker_hack = system_linker_hack; for (size_t i = 0; i < lib_dirs.length; i += 1) { codegen_add_lib_dir(g, lib_dirs.at(i)); diff --git a/src/os.cpp b/src/os.cpp index 6df463d8a5..f01a99fc23 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -103,7 +103,7 @@ static void os_spawn_process_posix(const char *exe, ZigList &args, } pid_t pid; - int rc = posix_spawn(&pid, exe, nullptr, nullptr, const_cast(argv), environ); + int rc = posix_spawnp(&pid, exe, nullptr, nullptr, const_cast(argv), environ); if (rc != 0) { zig_panic("posix_spawn failed: %s", strerror(rc)); } diff --git a/std/build.zig b/std/build.zig index a80580a383..1d90aa90e6 100644 --- a/std/build.zig +++ b/std/build.zig @@ -836,6 +836,7 @@ pub const LibExeObjStep = struct.{ assembly_files: ArrayList([]const u8), packages: ArrayList(Pkg), build_options_contents: std.Buffer, + system_linker_hack: bool, // C only stuff source_files: ArrayList([]const u8), @@ -930,6 +931,7 @@ pub const LibExeObjStep = struct.{ .disable_libc = true, .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable, .c_std = Builder.CStd.C99, + .system_linker_hack = false, }; self.computeOutFileNames(); return self; @@ -965,6 +967,7 @@ pub const LibExeObjStep = struct.{ .is_zig = false, .linker_script = null, .c_std = Builder.CStd.C99, + .system_linker_hack = false, .root_src = undefined, .verbose_link = false, @@ -1162,6 +1165,10 @@ pub const LibExeObjStep = struct.{ self.disable_libc = disable; } + pub fn enableSystemLinkerHack(self: *LibExeObjStep) void { + self.system_linker_hack = true; + } + fn make(step: *Step) !void { const self = @fieldParentPtr(LibExeObjStep, "step", step); return if (self.is_zig) self.makeZig() else self.makeC(); @@ -1338,6 +1345,9 @@ pub const LibExeObjStep = struct.{ if (self.no_rosegment) { try zig_args.append("--no-rosegment"); } + if (self.system_linker_hack) { + try zig_args.append("--system-linker-hack"); + } try builder.spawnChild(zig_args.toSliceConst()); @@ -1646,6 +1656,7 @@ pub const TestStep = struct.{ object_files: ArrayList([]const u8), no_rosegment: bool, output_path: ?[]const u8, + system_linker_hack: bool, pub fn init(builder: *Builder, root_src: []const u8) TestStep { const step_name = builder.fmt("test {}", root_src); @@ -1665,6 +1676,7 @@ pub const TestStep = struct.{ .object_files = ArrayList([]const u8).init(builder.allocator), .no_rosegment = false, .output_path = null, + .system_linker_hack = false, }; } @@ -1747,6 +1759,10 @@ pub const TestStep = struct.{ self.exec_cmd_args = args; } + pub fn enableSystemLinkerHack(self: *TestStep) void { + self.system_linker_hack = true; + } + fn make(step: *Step) !void { const self = @fieldParentPtr(TestStep, "step", step); const builder = self.builder; @@ -1851,6 +1867,9 @@ pub const TestStep = struct.{ if (self.no_rosegment) { try zig_args.append("--no-rosegment"); } + if (self.system_linker_hack) { + try zig_args.append("--system-linker-hack"); + } try builder.spawnChild(zig_args.toSliceConst()); } -- cgit v1.2.3