Commit 430d0dfcb2

Andrew Kelley <superjoe30@gmail.com>
2016-02-08 08:50:51
support static linking against libc
1 parent ea3bd58
src/all_types.hpp
@@ -1104,6 +1104,7 @@ struct CodeGen {
     bool have_exported_main;
     bool link_libc;
     Buf *libc_lib_dir;
+    Buf *libc_static_lib_dir;
     Buf *libc_include_dir;
     bool is_release_build;
     bool is_test_build;
src/analyze.cpp
@@ -5852,6 +5852,9 @@ void find_libc_path(CodeGen *g) {
     if (!g->libc_lib_dir || buf_len(g->libc_lib_dir) == 0) {
         zig_panic("Unable to determine libc lib path. probably need to reconfigure");
     }
+    if (!g->libc_static_lib_dir || buf_len(g->libc_static_lib_dir) == 0) {
+        zig_panic("Unable to determine libc static lib path. probably need to reconfigure");
+    }
     if (!g->libc_include_dir || buf_len(g->libc_include_dir) == 0) {
         zig_panic("Unable to determine libc include path. probably need to reconfigure");
     }
src/codegen.cpp
@@ -35,6 +35,7 @@ CodeGen *codegen_create(Buf *root_source_dir) {
     g->error_value_count = 1;
 
     g->libc_lib_dir = buf_create_from_str(ZIG_LIBC_LIB_DIR);
+    g->libc_static_lib_dir = buf_create_from_str(ZIG_LIBC_STATIC_LIB_DIR);
     g->libc_include_dir = buf_create_from_str(ZIG_LIBC_INCLUDE_DIR);
 
     return g;
@@ -81,6 +82,10 @@ void codegen_set_libc_lib_dir(CodeGen *g, Buf *libc_lib_dir) {
     g->libc_lib_dir = libc_lib_dir;
 }
 
+void codegen_set_libc_static_lib_dir(CodeGen *g, Buf *libc_static_lib_dir) {
+    g->libc_static_lib_dir = libc_static_lib_dir;
+}
+
 void codegen_set_libc_include_dir(CodeGen *g, Buf *libc_include_dir) {
     g->libc_include_dir = libc_include_dir;
 }
@@ -4010,6 +4015,12 @@ static const char *get_libc_file(CodeGen *g, const char *file) {
     return buf_ptr(out_buf);
 }
 
+static const char *get_libc_static_file(CodeGen *g, const char *file) {
+    Buf *out_buf = buf_alloc();
+    os_path_join(g->libc_static_lib_dir, buf_create_from_str(file), out_buf);
+    return buf_ptr(out_buf);
+}
+
 static Buf *build_o(CodeGen *parent_gen, const char *oname) {
     Buf *source_basename = buf_sprintf("%s.zig", oname);
     Buf *std_dir_path = buf_create_from_str(ZIG_STD_DIR);
@@ -4096,27 +4107,63 @@ void codegen_link(CodeGen *g, const char *out_file) {
         return;
     }
 
+    bool link_in_crt = (g->link_libc && g->out_type == OutTypeExe);
+    if (link_in_crt) {
+        find_libc_path(g);
+    }
+
+
 
     // invoke `ld`
     ZigList<const char *> args = {0};
-    const char *crt1o;
+
+    // TODO make this target dependent
+    args.append("-m");
+    args.append("elf_x86_64");
+
     if (g->is_static) {
         args.append("-static");
-        crt1o = "crt1.o";
-    } else {
-        crt1o = "Scrt1.o";
     }
 
-    // TODO don't pass this parameter unless linking with libc
-    char *ZIG_NATIVE_DYNAMIC_LINKER = getenv("ZIG_NATIVE_DYNAMIC_LINKER");
-    if (g->is_native_target && ZIG_NATIVE_DYNAMIC_LINKER) {
-        if (ZIG_NATIVE_DYNAMIC_LINKER[0] != 0) {
-            args.append("-dynamic-linker");
-            args.append(ZIG_NATIVE_DYNAMIC_LINKER);
+    args.append("-o");
+    args.append(out_file);
+
+    if (link_in_crt) {
+        const char *crt1o;
+        const char *crtbegino;
+        if (g->is_static) {
+            crt1o = "crt1.o";
+            crtbegino = "crtbeginT.o";
+        } else {
+            crt1o = "Scrt1.o";
+            crtbegino = "crtbegin.o";
         }
-    } else {
+        args.append(get_libc_file(g, crt1o));
+        args.append(get_libc_file(g, "crti.o"));
+        args.append(get_libc_static_file(g, crtbegino));
+    }
+
+    for (int i = 0; i < g->lib_dirs.length; i += 1) {
+        const char *lib_dir = g->lib_dirs.at(i);
+        args.append("-L");
+        args.append(lib_dir);
+    }
+
+    if (g->link_libc) {
+        args.append("-L");
+        args.append(buf_ptr(g->libc_lib_dir));
+
+        args.append("-L");
+        args.append(buf_ptr(g->libc_static_lib_dir));
+    }
+
+    // TODO don't pass this parameter unless linking with libc
+    if (ZIG_DYNAMIC_LINKER[0] == 0) {
         args.append("-dynamic-linker");
         args.append(buf_ptr(get_dynamic_linker(g->target_machine)));
+    } else {
+        args.append("-dynamic-linker");
+        args.append(ZIG_DYNAMIC_LINKER);
     }
 
     if (g->out_type == OutTypeLib) {
@@ -4129,24 +4176,9 @@ void codegen_link(CodeGen *g, const char *out_file) {
         out_file = buf_ptr(out_lib_so);
     }
 
-    args.append("-o");
-    args.append(out_file);
-
-    bool link_in_crt = (g->link_libc && g->out_type == OutTypeExe);
-
-    if (link_in_crt) {
-        find_libc_path(g);
-
-        args.append(get_libc_file(g, crt1o));
-        args.append(get_libc_file(g, "crti.o"));
-    }
-
+    // .o files
     args.append((const char *)buf_ptr(&out_file_o));
 
-    if (link_in_crt) {
-        args.append(get_libc_file(g, "crtn.o"));
-    }
-
     if (g->is_test_build) {
         const char *test_runner_name = g->link_libc ? "test_runner_libc" : "test_runner_nolibc";
         Buf *test_runner_o_path = build_o(g, test_runner_name);
@@ -4158,20 +4190,45 @@ void codegen_link(CodeGen *g, const char *out_file) {
         args.append(buf_ptr(builtin_o_path));
     }
 
-    for (int i = 0; i < g->lib_dirs.length; i += 1) {
-        const char *lib_dir = g->lib_dirs.at(i);
-        args.append("-L");
-        args.append(lib_dir);
-    }
-
     auto it = g->link_table.entry_iterator();
     for (;;) {
         auto *entry = it.next();
         if (!entry)
             break;
 
-        Buf *arg = buf_sprintf("-l%s", buf_ptr(entry->key));
-        args.append(buf_ptr(arg));
+        // we handle libc explicitly, don't do it here
+        if (!buf_eql_str(entry->key, "c")) {
+            Buf *arg = buf_sprintf("-l%s", buf_ptr(entry->key));
+            args.append(buf_ptr(arg));
+        }
+    }
+
+
+    // libc dep
+    if (g->link_libc) {
+        if (g->is_static) {
+            args.append("--start-group");
+            args.append("-lgcc");
+            args.append("-lgcc_eh");
+            args.append("-lc");
+            args.append("--end-group");
+        } else {
+            args.append("-lgcc");
+            args.append("--as-needed");
+            args.append("-lgcc_s");
+            args.append("--no-as-needed");
+            args.append("-lc");
+            args.append("-lgcc");
+            args.append("--as-needed");
+            args.append("-lgcc_s");
+            args.append("--no-as-needed");
+        }
+    }
+
+    // crt end
+    if (link_in_crt) {
+        args.append(get_libc_static_file(g, "crtend.o"));
+        args.append(get_libc_file(g, "crtn.o"));
     }
 
     if (g->verbose) {
src/codegen.hpp
@@ -26,6 +26,7 @@ void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color);
 void codegen_set_out_type(CodeGen *codegen, OutType out_type);
 void codegen_set_out_name(CodeGen *codegen, Buf *out_name);
 void codegen_set_libc_lib_dir(CodeGen *codegen, Buf *libc_lib_dir);
+void codegen_set_libc_static_lib_dir(CodeGen *g, Buf *libc_static_lib_dir);
 void codegen_set_libc_include_dir(CodeGen *codegen, Buf *libc_include_dir);
 void codegen_add_lib_dir(CodeGen *codegen, const char *dir);
 
src/config.h.in
@@ -10,6 +10,8 @@
 #define ZIG_STD_DIR "@CMAKE_INSTALL_PREFIX@/@ZIG_STD_DEST@"
 #define ZIG_LIBC_INCLUDE_DIR "@ZIG_LIBC_INCLUDE_DIR@"
 #define ZIG_LIBC_LIB_DIR "@ZIG_LIBC_LIB_DIR@"
+#define ZIG_LIBC_STATIC_LIB_DIR "@ZIG_LIBC_STATIC_LIB_DIR@"
+#define ZIG_DYNAMIC_LINKER "@ZIG_DYNAMIC_LINKER@"
 
 #cmakedefine ZIG_LLVM_OLD_CXX_ABI
 
src/main.cpp
@@ -16,24 +16,25 @@
 static int usage(const char *arg0) {
     fprintf(stderr, "Usage: %s [command] [options]\n"
         "Commands:\n"
-        "  build                     create executable, object, or library from target\n"
-        "  test                      create and run a test build\n"
-        "  version                   print version number and exit\n"
-        "  parseh                    convert a c header file to zig extern declarations\n"
+        "  build                        create executable, object, or library from target\n"
+        "  test                         create and run a test build\n"
+        "  version                      print version number and exit\n"
+        "  parseh                       convert a c header file to zig extern declarations\n"
         "Options:\n"
-        "  --release                 build with optimizations on and debug protection off\n"
-        "  --static                  output will be statically linked\n"
-        "  --strip                   exclude debug symbols\n"
-        "  --export [exe|lib|obj]    override output type\n"
-        "  --name [name]             override output name\n"
-        "  --output [file]           override destination path\n"
-        "  --verbose                 turn on compiler debug output\n"
-        "  --color [auto|off|on]     enable or disable colored error messages\n"
-        "  --libc-lib-dir [path]     set the C compiler data path\n"
-        "  --libc-include-dir [path] set the C compiler data path\n"
-        "  -isystem [dir]            add additional search path for other .h files\n"
-        "  -dirafter [dir]           same as -isystem but do it last\n"
-        "  --library-path [dir]      add a directory to the library search path\n"
+        "  --release                    build with optimizations on and debug protection off\n"
+        "  --static                     output will be statically linked\n"
+        "  --strip                      exclude debug symbols\n"
+        "  --export [exe|lib|obj]       override output type\n"
+        "  --name [name]                override output name\n"
+        "  --output [file]              override destination path\n"
+        "  --verbose                    turn on compiler debug output\n"
+        "  --color [auto|off|on]        enable or disable colored error messages\n"
+        "  --libc-lib-dir [path]        set the C compiler data path\n"
+        "  --libc-static-lib-dir [path] set the C compiler data path\n"
+        "  --libc-include-dir [path]    set the C compiler data path\n"
+        "  -isystem [dir]               add additional search path for other .h files\n"
+        "  -dirafter [dir]              same as -isystem but do it last\n"
+        "  --library-path [dir]         add a directory to the library search path\n"
     , arg0);
     return EXIT_FAILURE;
 }
@@ -59,6 +60,7 @@ int main(int argc, char **argv) {
     bool verbose = false;
     ErrColor color = ErrColorAuto;
     const char *libc_lib_dir = nullptr;
+    const char *libc_static_lib_dir = nullptr;
     const char *libc_include_dir = nullptr;
     ZigList<const char *> clang_argv = {0};
     ZigList<const char *> lib_dirs = {0};
@@ -108,6 +110,8 @@ int main(int argc, char **argv) {
                     out_name = argv[i];
                 } else if (strcmp(arg, "--libc-lib-dir") == 0) {
                     libc_lib_dir = argv[i];
+                } else if (strcmp(arg, "--libc-static-lib-dir") == 0) {
+                    libc_static_lib_dir = argv[i];
                 } else if (strcmp(arg, "--libc-include-dir") == 0) {
                     libc_include_dir = argv[i];
                 } else if (strcmp(arg, "-isystem") == 0) {
@@ -202,6 +206,8 @@ int main(int argc, char **argv) {
             }
             if (libc_lib_dir)
                 codegen_set_libc_lib_dir(g, buf_create_from_str(libc_lib_dir));
+            if (libc_static_lib_dir)
+                codegen_set_libc_static_lib_dir(g, buf_create_from_str(libc_static_lib_dir));
             if (libc_include_dir)
                 codegen_set_libc_include_dir(g, buf_create_from_str(libc_include_dir));
             codegen_set_verbose(g, verbose);
README.md
@@ -70,13 +70,14 @@ compromises backward compatibility.
 
 ### Debug / Development Build
 
-If you have gcc or clang installed, you can find out what `ZIG_LIBC_LIB_DIR` should
-be set to (example below). `ZIG_LIBC_INCLUDE_DIR` likely can be set to `/usr/include`.
+If you have gcc or clang installed, you can find out what `ZIG_LIBC_LIB_DIR`
+and `ZIG_LIBC_STATIC_LIB_DIR` should be set to (example below).
+`ZIG_LIBC_INCLUDE_DIR` likely can be set to `/usr/include`.
 
 ```
 mkdir build
 cd build
-cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_LIB_DIR=$(dirname $(cc -print-file-name=crt1.o)) -DZIG_LIBC_INCLUDE_DIR=/usr/include
+cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_LIB_DIR=$(dirname $(cc -print-file-name=crt1.o)) -DZIG_LIBC_INCLUDE_DIR=/usr/include -DZIG_LIBC_STATIC_LIB_DIR=$(dirname $(cc -print-file-name=crtbeginT.o))
 make
 make install
 ./run_tests
@@ -90,7 +91,7 @@ by the `--libc-lib-dir` and `--libc-include-dir` parameters to the zig binary.
 ```
 mkdir build
 cd build
-cmake .. -DCMAKE_BUILD_TYPE=Release -DZIG_LIBC_LIB_DIR=/some/path -DZIG_LIBC_INCLUDE_DIR=/some/path
+cmake .. -DCMAKE_BUILD_TYPE=Release -DZIG_LIBC_LIB_DIR=/some/path -DZIG_LIBC_INCLUDE_DIR=/some/path -DZIG_LIBC_STATIC_INCLUDE_DIR=/some/path
 make
 sudo make install
 ```