Commit 6b93495792

Andrew Kelley <superjoe30@gmail.com>
2018-10-09 18:18:09
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
1 parent 5a3c021
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;
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);
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);
 
 
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<CliPkg>(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);
src/os.cpp
@@ -46,6 +46,7 @@ typedef SSIZE_T ssize_t;
 #include <sys/wait.h>
 #include <fcntl.h>
 #include <limits.h>
+#include <spawn.h>
 
 #endif
 
@@ -88,25 +89,22 @@ static void populate_termination(Termination *term, int status) {
 }
 
 static void os_spawn_process_posix(const char *exe, ZigList<const char *> &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<const char *>(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<char * const *>(argv));
-        zig_panic("execvp failed: %s", strerror(errno));
-    } else {
-        // parent
-        int status;
-        waitpid(pid, &status, 0);
-        populate_termination(term, status);
+    const char **argv = allocate<const char *>(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<char *const*>(argv), environ);
+    if (rc != 0) {
+        zig_panic("posix_spawn failed: %s", strerror(rc));
+    }
+
+    int status;
+    waitpid(pid, &status, 0);
+    populate_termination(term, status);
 }
 #endif