use lld instead of system linker

master
Andrew Kelley 2017-03-13 11:54:56 -04:00
parent 7bc0145b80
commit d10bbd28e9
12 changed files with 125 additions and 138 deletions

View File

@ -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)

View File

@ -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

38
cmake/Findlld.cmake Normal file
View File

@ -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)

View File

@ -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;
}

View File

@ -1268,6 +1268,9 @@ struct CodeGen {
ZigList<Buf *> link_libs; // non-libc link libs
// add -framework [name] args to linker
ZigList<Buf *> darwin_frameworks;
// add -rpath [name] args to linker
ZigList<Buf *> rpath_list;
// reminder: hash tables must be initialized before use
HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> 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;

View File

@ -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;

View File

@ -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);

View File

@ -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@"

View File

@ -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 ||

View File

@ -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<const char *> clang_argv = {0};
ZigList<const char *> lib_dirs = {0};
ZigList<const char *> 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<const char *> 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);

View File

@ -42,6 +42,8 @@
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
#include <llvm/Transforms/Scalar.h>
#include <lld/Driver/Driver.h>
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<const char *> 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();
}

View File

@ -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);