diff --git a/CMakeLists.txt b/CMakeLists.txt index d9cf7873b..b65b234fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,8 +17,6 @@ message("Configuring zig version ${ZIG_VERSION}") set(ZIG_LIBC_LIB_DIR "" CACHE STRING "Default native target libc directory where crt1.o can be found") set(ZIG_LIBC_STATIC_LIB_DIR "" CACHE STRING "Default native target libc directory where crtbeginT.o can be found") set(ZIG_LIBC_INCLUDE_DIR "/usr/include" CACHE STRING "Default native target libc include directory") -set(ZIG_LD_PATH "ld" CACHE STRING "Path to ld for the native target") -set(ZIG_AR_PATH "ar" CACHE STRING "Path to ar for the native target") set(ZIG_DYNAMIC_LINKER "" CACHE STRING "Override dynamic linker for native target") option(ZIG_TEST_COVERAGE "Build Zig with test coverage instrumentation" OFF) @@ -32,6 +30,9 @@ link_directories(${LLVM_LIBDIRS}) find_package(clang) include_directories(${CLANG_INCLUDE_DIRS}) +find_package(lld) +include_directories(${LLD_INCLUDE_DIRS}) + include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} @@ -192,6 +193,7 @@ set_target_properties(zig PROPERTIES ) target_link_libraries(zig LINK_PUBLIC ${CLANG_LIBRARIES} + ${LLD_LIBRARIES} ${LLVM_LIBRARIES} ) install(TARGETS zig DESTINATION bin) diff --git a/cmake/Findclang.cmake b/cmake/Findclang.cmake index 27f1b6df6..f72f10f81 100644 --- a/cmake/Findclang.cmake +++ b/cmake/Findclang.cmake @@ -11,7 +11,7 @@ find_path(CLANG_INCLUDE_DIRS NAMES clang/Frontend/ASTUnit.h /usr/lib/llvm-4/include /mingw64/include) -macro(FIND_AND_ADD_CLANG_LIB _libname_) + macro(FIND_AND_ADD_CLANG_LIB _libname_) string(TOUPPER ${_libname_} _prettylibname_) find_library(CLANG_${_prettylibname_}_LIB NAMES ${_libname_} PATHS diff --git a/cmake/Findlld.cmake b/cmake/Findlld.cmake new file mode 100644 index 000000000..e74e8acf6 --- /dev/null +++ b/cmake/Findlld.cmake @@ -0,0 +1,38 @@ +# Copyright (c) 2017 Andrew Kelley +# This file is MIT licensed. +# See http://opensource.org/licenses/MIT + +# LLD_FOUND +# LLD_INCLUDE_DIRS +# LLD_LIBRARIES + +find_path(LLD_INCLUDE_DIRS NAMES lld/Driver/Driver.h + PATHS + /usr/lib/llvm-4/include + /mingw64/include) + + macro(FIND_AND_ADD_LLD_LIB _libname_) + string(TOUPPER ${_libname_} _prettylibname_) + find_library(LLD_${_prettylibname_}_LIB NAMES ${_libname_} + PATHS + /usr/lib/llvm-4/lib + /mingw64/lib) + if(LLD_${_prettylibname_}_LIB) + set(LLD_LIBRARIES ${LLD_LIBRARIES} ${LLD_${_prettylibname_}_LIB}) + endif() +endmacro(FIND_AND_ADD_LLD_LIB) + +FIND_AND_ADD_LLD_LIB(lldDriver) +FIND_AND_ADD_LLD_LIB(lldELF) +FIND_AND_ADD_LLD_LIB(lldCOFF) +FIND_AND_ADD_LLD_LIB(lldMachO) +FIND_AND_ADD_LLD_LIB(lldReaderWriter) +FIND_AND_ADD_LLD_LIB(lldCore) +FIND_AND_ADD_LLD_LIB(lldYAML) +FIND_AND_ADD_LLD_LIB(lldConfig) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LLD DEFAULT_MSG LLD_LIBRARIES LLD_INCLUDE_DIRS) + +mark_as_advanced(LLD_INCLUDE_DIRS LLD_LIBRARIES) + diff --git a/example/hello_world/hello_libc.zig b/example/hello_world/hello_libc.zig index 97174fe01..ea8a9df38 100644 --- a/example/hello_world/hello_libc.zig +++ b/example/hello_world/hello_libc.zig @@ -1,6 +1,6 @@ const c = @cImport(@cInclude("stdio.h")); export fn main(argc: c_int, argv: &&u8) -> c_int { - c.printf(c"Hello, world!\n"); + _ = c.printf(c"Hello, world!\n"); return 0; } diff --git a/src/all_types.hpp b/src/all_types.hpp index 6ef0156bd..2315b28c4 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1268,6 +1268,9 @@ struct CodeGen { ZigList link_libs; // non-libc link libs // add -framework [name] args to linker ZigList darwin_frameworks; + // add -rpath [name] args to linker + ZigList rpath_list; + // reminder: hash tables must be initialized before use HashMap import_table; @@ -1342,7 +1345,6 @@ struct CodeGen { Buf *libc_include_dir; Buf *zig_std_dir; Buf *dynamic_linker; - Buf *linker_path; Buf *ar_path; Buf triple_str; bool is_release_build; diff --git a/src/codegen.cpp b/src/codegen.cpp index 28dd4f219..3fbf0ff68 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -89,8 +89,6 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) { g->libc_lib_dir = buf_create_from_str(""); g->libc_static_lib_dir = buf_create_from_str(""); g->libc_include_dir = buf_create_from_str(""); - g->linker_path = buf_create_from_str(""); - g->ar_path = buf_create_from_str(""); g->darwin_linker_version = buf_create_from_str(""); } else { // native compilation, we can rely on the configuration stuff @@ -101,8 +99,6 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) { 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); - g->linker_path = buf_create_from_str(ZIG_LD_PATH); - g->ar_path = buf_create_from_str(ZIG_AR_PATH); g->darwin_linker_version = buf_create_from_str(ZIG_HOST_LINK_VERSION); if (g->zig_target.os == ZigLLVM_Darwin || @@ -180,18 +176,14 @@ void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker) { g->dynamic_linker = dynamic_linker; } -void codegen_set_linker_path(CodeGen *g, Buf *linker_path) { - g->linker_path = linker_path; -} - -void codegen_set_ar_path(CodeGen *g, Buf *ar_path) { - g->ar_path = ar_path; -} - void codegen_add_lib_dir(CodeGen *g, const char *dir) { g->lib_dirs.append(dir); } +void codegen_add_rpath(CodeGen *g, const char *name) { + g->rpath_list.append(buf_create_from_str(name)); +} + void codegen_add_link_lib(CodeGen *g, const char *lib) { if (strcmp(lib, "c") == 0) { g->link_libc = true; diff --git a/src/codegen.hpp b/src/codegen.hpp index cf8929f1f..21e840654 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -32,13 +32,12 @@ 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_set_zig_std_dir(CodeGen *codegen, Buf *zig_std_dir); void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker); -void codegen_set_linker_path(CodeGen *g, Buf *linker_path); -void codegen_set_ar_path(CodeGen *g, Buf *ar_path); void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole); void codegen_set_windows_unicode(CodeGen *g, bool municode); void codegen_add_lib_dir(CodeGen *codegen, const char *dir); void codegen_add_link_lib(CodeGen *codegen, const char *lib); void codegen_add_framework(CodeGen *codegen, const char *name); +void codegen_add_rpath(CodeGen *codegen, const char *name); void codegen_set_mlinker_version(CodeGen *g, Buf *darwin_linker_version); void codegen_set_rdynamic(CodeGen *g, bool rdynamic); void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min); diff --git a/src/config.h.in b/src/config.h.in index 95d3a6f7f..32c53add8 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -18,8 +18,6 @@ #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_LD_PATH "@ZIG_LD_PATH@" -#define ZIG_AR_PATH "@ZIG_AR_PATH@" #define ZIG_DYNAMIC_LINKER "@ZIG_DYNAMIC_LINKER@" #define ZIG_HOST_LINK_VERSION "@ZIG_HOST_LINK_VERSION@" diff --git a/src/link.cpp b/src/link.cpp index 6c12f0ef4..9d1cb0574 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -103,6 +103,7 @@ static const char *get_darwin_arch_string(const ZigTarget *t) { } } + static const char *getLDMOption(const ZigTarget *t) { switch (t->arch.arch) { case ZigLLVM_x86: @@ -147,7 +148,7 @@ static const char *getLDMOption(const ZigTarget *t) { } } -static void construct_linker_job_linux(LinkJob *lj) { +static void construct_linker_job_elf(LinkJob *lj) { CodeGen *g = lj->codegen; if (lj->link_in_crt) { @@ -202,6 +203,12 @@ static void construct_linker_job_linux(LinkJob *lj) { lj->args.append(get_libc_static_file(g, crtbegino)); } + for (size_t i = 0; i < g->rpath_list.length; i += 1) { + Buf *rpath = g->rpath_list.at(i); + lj->args.append("-rpath"); + lj->args.append(buf_ptr(rpath)); + } + for (size_t i = 0; i < g->lib_dirs.length; i += 1) { const char *lib_dir = g->lib_dirs.at(i); lj->args.append("-L"); @@ -293,7 +300,7 @@ static bool is_target_cyg_mingw(const ZigTarget *target) { (target->os == ZigLLVM_Win32 && target->env_type == ZigLLVM_GNU); } -static void construct_linker_job_mingw(LinkJob *lj) { +static void construct_linker_job_coff(LinkJob *lj) { CodeGen *g = lj->codegen; if (lj->link_in_crt) { @@ -546,7 +553,7 @@ static bool darwin_version_lt(DarwinPlatform *platform, int major, int minor) { return false; } -static void construct_linker_job_darwin(LinkJob *lj) { +static void construct_linker_job_macho(LinkJob *lj) { CodeGen *g = lj->codegen; int ver_major; @@ -686,85 +693,16 @@ static void construct_linker_job_darwin(LinkJob *lj) { } static void construct_linker_job(LinkJob *lj) { - switch (lj->codegen->zig_target.os) { - case ZigLLVM_UnknownOS: // freestanding - // TODO we want to solve this problem with LLD, but for now let's - // assume gnu binutils - // http://lists.llvm.org/pipermail/llvm-dev/2017-February/109835.html - return construct_linker_job_linux(lj); - case ZigLLVM_Linux: - if (lj->codegen->zig_target.arch.arch == ZigLLVM_hexagon) { - zig_panic("TODO construct hexagon_TC linker job"); - } else { - return construct_linker_job_linux(lj); - } - case ZigLLVM_CloudABI: - zig_panic("TODO construct CloudABI linker job"); - case ZigLLVM_Darwin: - case ZigLLVM_MacOSX: - case ZigLLVM_IOS: - return construct_linker_job_darwin(lj); - case ZigLLVM_DragonFly: - zig_panic("TODO construct DragonFly linker job"); - case ZigLLVM_OpenBSD: - zig_panic("TODO construct OpenBSD linker job"); - case ZigLLVM_Bitrig: - zig_panic("TODO construct Bitrig linker job"); - case ZigLLVM_NetBSD: - zig_panic("TODO construct NetBSD linker job"); - case ZigLLVM_FreeBSD: - zig_panic("TODO construct FreeBSD linker job"); - case ZigLLVM_Minix: - zig_panic("TODO construct Minix linker job"); - case ZigLLVM_NaCl: - zig_panic("TODO construct NaCl_TC linker job"); - case ZigLLVM_Solaris: - zig_panic("TODO construct Solaris linker job"); - case ZigLLVM_Win32: - switch (lj->codegen->zig_target.env_type) { - default: - if (lj->codegen->zig_target.oformat == ZigLLVM_ELF) { - zig_panic("TODO construct Generic_ELF linker job"); - } else if (lj->codegen->zig_target.oformat == ZigLLVM_MachO) { - zig_panic("TODO construct MachO linker job"); - } else { - zig_panic("TODO construct Generic_GCC linker job"); - } - case ZigLLVM_GNU: - return construct_linker_job_mingw(lj); - case ZigLLVM_Itanium: - zig_panic("TODO construct CrossWindowsToolChain linker job"); - case ZigLLVM_MSVC: - case ZigLLVM_UnknownEnvironment: - zig_panic("TODO construct MSVC linker job"); - } - case ZigLLVM_CUDA: - zig_panic("TODO construct Cuda linker job"); - default: - // Of these targets, Hexagon is the only one that might have - // an OS of Linux, in which case it got handled above already. - if (lj->codegen->zig_target.arch.arch == ZigLLVM_tce) { - zig_panic("TODO construct TCE linker job"); - } else if (lj->codegen->zig_target.arch.arch == ZigLLVM_hexagon) { - zig_panic("TODO construct Hexagon_TC linker job"); - } else if (lj->codegen->zig_target.arch.arch == ZigLLVM_xcore) { - zig_panic("TODO construct XCore linker job"); - } else if (lj->codegen->zig_target.arch.arch == ZigLLVM_shave) { - zig_panic("TODO construct SHAVE linker job"); - } else if (lj->codegen->zig_target.oformat == ZigLLVM_ELF) { - zig_panic("TODO construct Generic_ELF linker job"); - } else if (lj->codegen->zig_target.oformat == ZigLLVM_MachO) { - zig_panic("TODO construct MachO linker job"); - } else { - zig_panic("TODO construct Generic_GCC linker job"); - } + switch (lj->codegen->zig_target.oformat) { + case ZigLLVM_UnknownObjectFormat: + zig_unreachable(); - } -} - -static void ensure_we_have_linker_path(CodeGen *g) { - if (!g->linker_path || buf_len(g->linker_path) == 0) { - zig_panic("zig does not know the path to the linker"); + case ZigLLVM_COFF: + return construct_linker_job_coff(lj); + case ZigLLVM_ELF: + return construct_linker_job_elf(lj); + case ZigLLVM_MachO: + return construct_linker_job_macho(lj); } } @@ -838,44 +776,23 @@ void codegen_link(CodeGen *g, const char *out_file) { } lj.link_in_crt = (g->link_libc && g->out_type == OutTypeExe); - ensure_we_have_linker_path(g); construct_linker_job(&lj); if (g->verbose) { - fprintf(stderr, "%s", buf_ptr(g->linker_path)); + fprintf(stderr, "link"); for (size_t i = 0; i < lj.args.length; i += 1) { fprintf(stderr, " %s", lj.args.at(i)); } fprintf(stderr, "\n"); } - Buf ld_stderr = BUF_INIT; - Buf ld_stdout = BUF_INIT; - Termination term; - int err = os_exec_process(buf_ptr(g->linker_path), lj.args, &term, &ld_stderr, &ld_stdout); - if (err) { - fprintf(stderr, "linker not found: '%s'\n", buf_ptr(g->linker_path)); - exit(1); - } + Buf diag = BUF_INIT; - if (term.how != TerminationIdClean || term.code != 0) { - if (term.how == TerminationIdClean) { - fprintf(stderr, "linker failed with return code %d\n", term.code); - } else if (term.how == TerminationIdSignaled) { - fprintf(stderr, "linker failed with signal %d\n", term.code); - } else { - fprintf(stderr, "linker failed\n"); - } - fprintf(stderr, "%s ", buf_ptr(g->linker_path)); - for (size_t i = 0; i < lj.args.length; i += 1) { - fprintf(stderr, "%s ", lj.args.at(i)); - } - fprintf(stderr, "\n%s\n", buf_ptr(&ld_stderr)); + if (!ZigLLDLink(g->zig_target.oformat, lj.args.items, lj.args.length, &diag)) { + fprintf(stderr, "%s\n", buf_ptr(&diag)); exit(1); - } else if (buf_len(&ld_stderr)) { - fprintf(stderr, "%s\n", buf_ptr(&ld_stderr)); } if (g->out_type == OutTypeLib || diff --git a/src/main.cpp b/src/main.cpp index c57a35fc9..bee0c1e4c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -43,6 +43,7 @@ static int usage(const char *arg0) { " -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" + " -L[dir] alias for --library-path\n" " --library [lib] link against lib\n" " --target-arch [name] specify target architecture\n" " --target-os [name] specify target operating system\n" @@ -57,6 +58,7 @@ static int usage(const char *arg0) { " -framework [name] (darwin only) link against framework\n" " --check-unused perform semantic analysis on unused declarations\n" " --linker-script [path] use a custom linker script\n" + " -rpath [path] add a directory to the runtime library search path\n" , arg0); return EXIT_FAILURE; } @@ -123,8 +125,6 @@ int main(int argc, char **argv) { const char *libc_include_dir = nullptr; const char *zig_std_dir = nullptr; const char *dynamic_linker = nullptr; - const char *linker_path = nullptr; - const char *ar_path = nullptr; ZigList clang_argv = {0}; ZigList lib_dirs = {0}; ZigList link_libs = {0}; @@ -142,6 +142,7 @@ int main(int argc, char **argv) { const char *mios_version_min = nullptr; bool check_unused = false; const char *linker_script = nullptr; + ZigList rpath_list = {0}; for (int i = 1; i < argc; i += 1) { char *arg = argv[i]; @@ -165,6 +166,9 @@ int main(int argc, char **argv) { rdynamic = true; } else if (strcmp(arg, "--check-unused") == 0) { check_unused = true; + } else if (arg[1] == 'L' && arg[2] != 0) { + // alias for --library-path + lib_dirs.append(&arg[2]); } else if (i + 1 >= argc) { return usage(arg0); } else { @@ -205,17 +209,13 @@ int main(int argc, char **argv) { zig_std_dir = argv[i]; } else if (strcmp(arg, "--dynamic-linker") == 0) { dynamic_linker = argv[i]; - } else if (strcmp(arg, "--ld-path") == 0) { - linker_path = argv[i]; - } else if (strcmp(arg, "--ar-path") == 0) { - ar_path = argv[i]; } else if (strcmp(arg, "-isystem") == 0) { clang_argv.append("-isystem"); clang_argv.append(argv[i]); } else if (strcmp(arg, "-dirafter") == 0) { clang_argv.append("-dirafter"); clang_argv.append(argv[i]); - } else if (strcmp(arg, "--library-path") == 0) { + } else if (strcmp(arg, "--library-path") == 0 || strcmp(arg, "-L") == 0) { lib_dirs.append(argv[i]); } else if (strcmp(arg, "--library") == 0) { link_libs.append(argv[i]); @@ -235,6 +235,8 @@ int main(int argc, char **argv) { frameworks.append(argv[i]); } else if (strcmp(arg, "--linker-script") == 0) { linker_script = argv[i]; + } else if (strcmp(arg, "-rpath") == 0) { + rpath_list.append(argv[i]); } else { fprintf(stderr, "Invalid argument: %s\n", arg); return usage(arg0); @@ -373,10 +375,6 @@ int main(int argc, char **argv) { codegen_set_zig_std_dir(g, buf_create_from_str(zig_std_dir)); if (dynamic_linker) codegen_set_dynamic_linker(g, buf_create_from_str(dynamic_linker)); - if (linker_path) - codegen_set_linker_path(g, buf_create_from_str(linker_path)); - if (ar_path) - codegen_set_ar_path(g, buf_create_from_str(ar_path)); codegen_set_verbose(g, verbose); codegen_set_errmsg_color(g, color); @@ -389,6 +387,9 @@ int main(int argc, char **argv) { for (size_t i = 0; i < frameworks.length; i += 1) { codegen_add_framework(g, frameworks.at(i)); } + for (size_t i = 0; i < rpath_list.length; i += 1) { + codegen_add_rpath(g, rpath_list.at(i)); + } codegen_set_windows_subsystem(g, mwindows, mconsole); codegen_set_windows_unicode(g, municode); diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index 21ea54b79..a837c896c 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -42,6 +42,8 @@ #include #include +#include + using namespace llvm; void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R) { @@ -790,3 +792,36 @@ Buf *get_dynamic_linker(LLVMTargetMachineRef target_machine_ref) { } } +bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, Buf *diag_buf) { + ArrayRef array_ref_args(args, arg_count); + + buf_resize(diag_buf, 0); + class MyOStream: public raw_ostream { + public: + MyOStream(Buf *_diag_buf) : raw_ostream(true), diag_buf(_diag_buf) { + + } + void write_impl(const char *ptr, size_t len) override { + buf_append_mem(diag_buf, ptr, len); + } + uint64_t current_pos() const override { + return buf_len(diag_buf); + } + Buf *diag_buf; + } diag(diag_buf); + + switch (oformat) { + case ZigLLVM_UnknownObjectFormat: + zig_unreachable(); + + case ZigLLVM_COFF: + return lld::coff::link(array_ref_args); + + case ZigLLVM_ELF: + return lld::elf::link(array_ref_args, false, diag); + + case ZigLLVM_MachO: + return lld::mach_o::link(array_ref_args, diag); + } + zig_unreachable(); +} diff --git a/src/zig_llvm.hpp b/src/zig_llvm.hpp index 8e73fffc9..b242cfac3 100644 --- a/src/zig_llvm.hpp +++ b/src/zig_llvm.hpp @@ -351,6 +351,9 @@ const char *ZigLLVMGetEnvironmentTypeName(ZigLLVM_EnvironmentType env_type); * This stuff is not LLVM API but it depends on the LLVM C++ API so we put it here. */ struct Buf; + +bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, Buf *diag); + void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type, ZigLLVM_SubArchType *sub_arch_type, ZigLLVM_VendorType *vendor_type, ZigLLVM_OSType *os_type, ZigLLVM_EnvironmentType *environ_type, ZigLLVM_ObjectFormatType *oformat);