From 430d0dfcb24178fd079be5d6988298bffec8beab Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 8 Feb 2016 00:50:51 -0700 Subject: [PATCH] support static linking against libc --- README.md | 9 ++-- src/all_types.hpp | 1 + src/analyze.cpp | 3 ++ src/codegen.cpp | 127 +++++++++++++++++++++++++++++++++------------- src/codegen.hpp | 1 + src/config.h.in | 2 + src/main.cpp | 40 ++++++++------- 7 files changed, 127 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index feab377d8a..e694f3485d 100644 --- a/README.md +++ b/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 ``` diff --git a/src/all_types.hpp b/src/all_types.hpp index 709ae528f5..c247e82669 100644 --- a/src/all_types.hpp +++ b/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; diff --git a/src/analyze.cpp b/src/analyze.cpp index bbda180b7f..7e71ac2db3 100644 --- a/src/analyze.cpp +++ b/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"); } diff --git a/src/codegen.cpp b/src/codegen.cpp index fea85a8bc6..97c528bc81 100644 --- a/src/codegen.cpp +++ b/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 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"; + } + + 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"; + } + 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 - 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); - } - } else { + 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) { diff --git a/src/codegen.hpp b/src/codegen.hpp index b1bd981939..6fffaf06bd 100644 --- a/src/codegen.hpp +++ b/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); diff --git a/src/config.h.in b/src/config.h.in index ffe76ffa23..43952815df 100644 --- a/src/config.h.in +++ b/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 diff --git a/src/main.cpp b/src/main.cpp index 7f288ba4ec..2d10cbb6f5 100644 --- a/src/main.cpp +++ b/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 clang_argv = {0}; ZigList 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);