diff --git a/CMakeLists.txt b/CMakeLists.txt index 027842c49..6feb456fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,14 @@ set(ZIG_VERSION_PATCH 0) set(ZIG_VERSION "${ZIG_VERSION_MAJOR}.${ZIG_VERSION_MINOR}.${ZIG_VERSION_PATCH}") 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_DYNAMIC_LINKER "" CACHE STRING "Override dynamic linker for native target") + + + find_package(llvm) include_directories(${LLVM_INCLUDE_DIRS}) link_directories(${LLVM_LIBDIRS}) @@ -27,6 +35,7 @@ include_directories( ) set(ZIG_SOURCES + "${CMAKE_SOURCE_DIR}/src/link.cpp" "${CMAKE_SOURCE_DIR}/src/target.cpp" "${CMAKE_SOURCE_DIR}/src/ast_render.cpp" "${CMAKE_SOURCE_DIR}/src/bignum.cpp" diff --git a/src/all_types.hpp b/src/all_types.hpp index bded9207e..492a0e059 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -14,6 +14,7 @@ #include "hash_map.hpp" #include "errmsg.hpp" #include "bignum.hpp" +#include "target.hpp" struct AstNode; struct ImportTableEntry; @@ -1109,6 +1110,7 @@ struct CodeGen { TypeTableEntry *entry_pure_error; } builtin_types; + ZigTarget zig_target; LLVMTargetDataRef target_data_ref; unsigned pointer_size_bytes; bool is_big_endian; @@ -1120,12 +1122,18 @@ struct CodeGen { Buf *libc_static_lib_dir; Buf *libc_include_dir; Buf *dynamic_linker; + Buf *linker_path; + Buf triple_str; bool is_release_build; bool is_test_build; LLVMTargetMachineRef target_machine; LLVMZigDIFile *dummy_di_file; + bool is_native_target; Buf *root_source_dir; Buf *root_out_name; + bool windows_subsystem_windows; + bool windows_subsystem_console; + bool windows_linker_unicode; // The function definitions this module includes. There must be a corresponding // fn_protos entry. diff --git a/src/analyze.cpp b/src/analyze.cpp index 4093b04ea..287a8667e 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -5929,13 +5929,13 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { void find_libc_path(CodeGen *g) { // later we can handle this better by reporting an error via the normal mechanism if (!g->libc_lib_dir || buf_len(g->libc_lib_dir) == 0) { - zig_panic("Unable to determine libc lib path. probably need to reconfigure"); + zig_panic("Unable to determine libc lib path."); } 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"); + zig_panic("Unable to determine libc static lib path."); } if (!g->libc_include_dir || buf_len(g->libc_include_dir) == 0) { - zig_panic("Unable to determine libc include path. probably need to reconfigure"); + zig_panic("Unable to determine libc include path."); } } diff --git a/src/codegen.cpp b/src/codegen.cpp index 1074d2420..c6fd87fa5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -15,12 +15,14 @@ #include "errmsg.hpp" #include "parseh.hpp" #include "ast_render.hpp" +#include "target.hpp" +#include "link.hpp" #include #include -CodeGen *codegen_create(Buf *root_source_dir) { +CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) { CodeGen *g = allocate(1); g->link_table.init(32); g->import_table.init(32); @@ -33,11 +35,29 @@ CodeGen *codegen_create(Buf *root_source_dir) { g->is_test_build = false; g->root_source_dir = root_source_dir; g->error_value_count = 1; - g->dynamic_linker = buf_create_from_str(ZIG_DYNAMIC_LINKER); - 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); + if (target) { + // cross compiling, so we can't rely on all the configured stuff since + // that's for native compilation + g->zig_target = *target; + resolve_target_object_format(&g->zig_target); + + g->dynamic_linker = buf_create_from_str(""); + 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(""); + } else { + // native compilation, we can rely on the configuration stuff + g->is_native_target = true; + get_native_target(&g->zig_target); + + g->dynamic_linker = buf_create_from_str(ZIG_DYNAMIC_LINKER); + 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); + } return g; } @@ -95,10 +115,23 @@ 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_add_lib_dir(CodeGen *g, const char *dir) { g->lib_dirs.append(dir); } +void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole) { + g->windows_subsystem_windows = mwindows; + g->windows_subsystem_console = mconsole; +} + +void codegen_set_windows_unicode(CodeGen *g, bool municode) { + g->windows_linker_unicode = municode; +} + static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node); static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, TypeTableEntry **out_type_entry); static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue); @@ -3502,34 +3535,35 @@ static void init(CodeGen *g, Buf *source_path) { g->lib_search_paths.append(g->root_source_dir); g->lib_search_paths.append(buf_create_from_str(ZIG_STD_DIR)); - LLVMInitializeAllTargets(); - LLVMInitializeAllTargetMCs(); - LLVMInitializeAllAsmPrinters(); - LLVMInitializeAllAsmParsers(); - LLVMInitializeNativeTarget(); - - char *native_triple = LLVMGetDefaultTargetTriple(); - g->module = LLVMModuleCreateWithName(buf_ptr(source_path)); - LLVMSetTarget(g->module, native_triple); + get_target_triple(&g->triple_str, &g->zig_target); + + LLVMSetTarget(g->module, buf_ptr(&g->triple_str)); LLVMTargetRef target_ref; char *err_msg = nullptr; - if (LLVMGetTargetFromTriple(native_triple, &target_ref, &err_msg)) { - zig_panic("unable to get target from triple: %s", err_msg); + if (LLVMGetTargetFromTriple(buf_ptr(&g->triple_str), &target_ref, &err_msg)) { + zig_panic("unable to create target based on: %s", buf_ptr(&g->triple_str)); } - char *native_cpu = LLVMZigGetHostCPUName(); - char *native_features = LLVMZigGetNativeFeatures(); - LLVMCodeGenOptLevel opt_level = g->is_release_build ? LLVMCodeGenLevelAggressive : LLVMCodeGenLevelNone; LLVMRelocMode reloc_mode = g->is_static ? LLVMRelocStatic : LLVMRelocPIC; - g->target_machine = LLVMCreateTargetMachine(target_ref, native_triple, - native_cpu, native_features, opt_level, reloc_mode, LLVMCodeModelDefault); + const char *target_specific_cpu_args; + const char *target_specific_features; + if (g->is_native_target) { + target_specific_cpu_args = LLVMZigGetHostCPUName(); + target_specific_features = LLVMZigGetNativeFeatures(); + } else { + target_specific_cpu_args = ""; + target_specific_features = ""; + } + + g->target_machine = LLVMCreateTargetMachine(target_ref, buf_ptr(&g->triple_str), + target_specific_cpu_args, target_specific_features, opt_level, reloc_mode, LLVMCodeModelDefault); g->target_data_ref = LLVMGetTargetMachineData(g->target_machine); @@ -3902,7 +3936,7 @@ static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) { } } -static void generate_h_file(CodeGen *g) { +void codegen_generate_h_file(CodeGen *g) { assert(!g->is_test_build); Buf *h_file_out_path = buf_sprintf("%s.h", buf_ptr(g->root_out_name)); @@ -3989,258 +4023,3 @@ static void generate_h_file(CodeGen *g) { if (fclose(out_h)) zig_panic("unable to close h file: %s", strerror(errno)); } - -static const char *get_libc_file(CodeGen *g, const char *file) { - Buf *out_buf = buf_alloc(); - os_path_join(g->libc_lib_dir, buf_create_from_str(file), out_buf); - 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); - - CodeGen *child_gen = codegen_create(std_dir_path); - child_gen->link_libc = parent_gen->link_libc; - - codegen_set_is_release(child_gen, parent_gen->is_release_build); - - codegen_set_strip(child_gen, parent_gen->strip_debug_symbols); - codegen_set_is_static(child_gen, parent_gen->is_static); - - codegen_set_out_type(child_gen, OutTypeObj); - codegen_set_out_name(child_gen, buf_create_from_str(oname)); - - codegen_set_verbose(child_gen, parent_gen->verbose); - codegen_set_errmsg_color(child_gen, parent_gen->err_color); - - Buf *full_path = buf_alloc(); - os_path_join(std_dir_path, source_basename, full_path); - Buf source_code = BUF_INIT; - if (os_fetch_file_path(full_path, &source_code)) { - zig_panic("unable to fetch file: %s\n", buf_ptr(full_path)); - } - - codegen_add_root_code(child_gen, std_dir_path, source_basename, &source_code); - Buf *o_out = buf_sprintf("%s.o", oname); - codegen_link(child_gen, buf_ptr(o_out)); - - return o_out; -} - -void codegen_link(CodeGen *g, const char *out_file) { - bool is_optimized = g->is_release_build; - if (is_optimized) { - if (g->verbose) { - fprintf(stderr, "\nOptimization:\n"); - fprintf(stderr, "---------------\n"); - } - - LLVMZigOptimizeModule(g->target_machine, g->module); - - if (g->verbose) { - LLVMDumpModule(g->module); - } - } - if (g->verbose) { - fprintf(stderr, "\nLink:\n"); - fprintf(stderr, "-------\n"); - } - - if (!out_file) { - assert(g->root_out_name); - out_file = buf_ptr(g->root_out_name); - } - - Buf out_file_o = BUF_INIT; - buf_init_from_str(&out_file_o, out_file); - - if (g->out_type != OutTypeObj) { - buf_append_str(&out_file_o, ".o"); - } - - char *err_msg = nullptr; - if (LLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(&out_file_o), - LLVMObjectFile, &err_msg)) - { - zig_panic("unable to write object file: %s", err_msg); - } - - if (g->out_type == OutTypeObj) { - if (g->verbose) { - fprintf(stderr, "OK\n"); - } - return; - } - - if (g->out_type == OutTypeLib && g->is_static) { - // invoke `ar` - // example: - // # static link into libfoo.a - // ar rcs libfoo.a foo1.o foo2.o - zig_panic("TODO invoke ar"); - 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}; - - // TODO make this target dependent - args.append("-m"); - args.append("elf_x86_64"); - - if (g->is_static) { - args.append("-static"); - } - - 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)); - } - - if (g->dynamic_linker && buf_len(g->dynamic_linker) > 0) { - args.append("-dynamic-linker"); - args.append(buf_ptr(g->dynamic_linker)); - } else { - args.append("-dynamic-linker"); - args.append(buf_ptr(get_dynamic_linker(g->target_machine))); - } - - if (g->out_type == OutTypeLib) { - Buf *out_lib_so = buf_sprintf("lib%s.so.%d.%d.%d", - buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch); - Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->root_out_name), g->version_major); - args.append("-shared"); - args.append("-soname"); - args.append(buf_ptr(soname)); - out_file = buf_ptr(out_lib_so); - } - - // .o files - args.append((const char *)buf_ptr(&out_file_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); - args.append(buf_ptr(test_runner_o_path)); - } - - if (!g->link_libc && (g->out_type == OutTypeExe || g->out_type == OutTypeLib)) { - Buf *builtin_o_path = build_o(g, "builtin"); - args.append(buf_ptr(builtin_o_path)); - } - - auto it = g->link_table.entry_iterator(); - for (;;) { - auto *entry = it.next(); - if (!entry) - break; - - // 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) { - fprintf(stderr, "ld"); - for (int i = 0; i < args.length; i += 1) { - fprintf(stderr, " %s", args.at(i)); - } - fprintf(stderr, "\n"); - } - - int return_code; - Buf ld_stderr = BUF_INIT; - Buf ld_stdout = BUF_INIT; - os_exec_process("ld", args, &return_code, &ld_stderr, &ld_stdout); - - if (return_code != 0) { - fprintf(stderr, "ld failed with return code %d\n", return_code); - fprintf(stderr, "ld "); - for (int i = 0; i < args.length; i += 1) { - fprintf(stderr, "%s ", args.at(i)); - } - fprintf(stderr, "\n%s\n", buf_ptr(&ld_stderr)); - exit(1); - } else if (buf_len(&ld_stderr)) { - fprintf(stderr, "%s\n", buf_ptr(&ld_stderr)); - } - - if (g->out_type == OutTypeLib) { - generate_h_file(g); - } - - if (g->verbose) { - fprintf(stderr, "OK\n"); - } -} diff --git a/src/codegen.hpp b/src/codegen.hpp index 64053e04c..06fe7dd8a 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -10,10 +10,11 @@ #include "parser.hpp" #include "errmsg.hpp" +#include "target.hpp" #include -CodeGen *codegen_create(Buf *root_source_dir); +CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target); void codegen_set_clang_argv(CodeGen *codegen, const char **args, int len); void codegen_set_is_release(CodeGen *codegen, bool is_release); @@ -29,13 +30,16 @@ 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_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker); +void codegen_set_linker_path(CodeGen *g, Buf *linker_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_root_code(CodeGen *g, Buf *source_dir, Buf *source_basename, Buf *source_code); -void codegen_link(CodeGen *g, const char *out_file); - void codegen_parseh(CodeGen *g, Buf *src_dirname, Buf *src_basename, Buf *source_code); void codegen_render_ast(CodeGen *g, FILE *f, int indent_size); +void codegen_generate_h_file(CodeGen *g); + #endif diff --git a/src/config.h.in b/src/config.h.in index 43952815d..77e563a99 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -11,6 +11,7 @@ #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_DYNAMIC_LINKER "@ZIG_DYNAMIC_LINKER@" #cmakedefine ZIG_LLVM_OLD_CXX_ABI diff --git a/src/link.cpp b/src/link.cpp new file mode 100644 index 000000000..753e30d05 --- /dev/null +++ b/src/link.cpp @@ -0,0 +1,518 @@ +/* + * Copyright (c) 2015 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + +#include "link.hpp" +#include "os.hpp" +#include "config.h" +#include "codegen.hpp" +#include "analyze.hpp" + +struct LinkJob { + CodeGen *codegen; + Buf out_file; + ZigList args; + bool link_in_crt; + Buf out_file_o; +}; + +static const char *get_libc_file(CodeGen *g, const char *file) { + Buf *out_buf = buf_alloc(); + os_path_join(g->libc_lib_dir, buf_create_from_str(file), out_buf); + 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); + + ZigTarget *child_target = parent_gen->is_native_target ? nullptr : &parent_gen->zig_target; + CodeGen *child_gen = codegen_create(std_dir_path, child_target); + child_gen->link_libc = parent_gen->link_libc; + + codegen_set_is_release(child_gen, parent_gen->is_release_build); + + codegen_set_strip(child_gen, parent_gen->strip_debug_symbols); + codegen_set_is_static(child_gen, parent_gen->is_static); + + codegen_set_out_type(child_gen, OutTypeObj); + codegen_set_out_name(child_gen, buf_create_from_str(oname)); + + codegen_set_verbose(child_gen, parent_gen->verbose); + codegen_set_errmsg_color(child_gen, parent_gen->err_color); + + Buf *full_path = buf_alloc(); + os_path_join(std_dir_path, source_basename, full_path); + Buf source_code = BUF_INIT; + if (os_fetch_file_path(full_path, &source_code)) { + zig_panic("unable to fetch file: %s\n", buf_ptr(full_path)); + } + + codegen_add_root_code(child_gen, std_dir_path, source_basename, &source_code); + Buf *o_out = buf_sprintf("%s.o", oname); + codegen_link(child_gen, buf_ptr(o_out)); + + return o_out; +} + +static const char *get_o_file_extension(CodeGen *g) { + if (g->zig_target.environ == ZigLLVM_MSVC) { + return ".obj"; + } else { + return ".o"; + } +} + +static const char *get_exe_file_extension(CodeGen *g) { + if (g->zig_target.os == ZigLLVM_Win32) { + return ".exe"; + } else { + return ""; + } +} + +static void construct_linker_job_linux(LinkJob *lj) { + CodeGen *g = lj->codegen; + + lj->args.append("-m"); + lj->args.append("elf_x86_64"); + + if (g->is_static) { + lj->args.append("-static"); + } + + lj->args.append("-o"); + lj->args.append(buf_ptr(&lj->out_file)); + + if (lj->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"; + } + lj->args.append(get_libc_file(g, crt1o)); + lj->args.append(get_libc_file(g, "crti.o")); + lj->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); + lj->args.append("-L"); + lj->args.append(lib_dir); + } + + if (g->link_libc) { + lj->args.append("-L"); + lj->args.append(buf_ptr(g->libc_lib_dir)); + + lj->args.append("-L"); + lj->args.append(buf_ptr(g->libc_static_lib_dir)); + } + + if (g->dynamic_linker && buf_len(g->dynamic_linker) > 0) { + lj->args.append("-dynamic-linker"); + lj->args.append(buf_ptr(g->dynamic_linker)); + } else { + lj->args.append("-dynamic-linker"); + lj->args.append(buf_ptr(get_dynamic_linker(g->target_machine))); + } + + if (g->out_type == OutTypeLib) { + buf_resize(&lj->out_file, 0); + buf_appendf(&lj->out_file, "lib%s.so.%d.%d.%d", + buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch); + Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->root_out_name), g->version_major); + lj->args.append("-shared"); + lj->args.append("-soname"); + lj->args.append(buf_ptr(soname)); + } + + // .o files + lj->args.append((const char *)buf_ptr(&lj->out_file_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); + lj->args.append(buf_ptr(test_runner_o_path)); + } + + if (!g->link_libc && (g->out_type == OutTypeExe || g->out_type == OutTypeLib)) { + Buf *builtin_o_path = build_o(g, "builtin"); + lj->args.append(buf_ptr(builtin_o_path)); + } + + auto it = g->link_table.entry_iterator(); + for (;;) { + auto *entry = it.next(); + if (!entry) + break; + + // 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)); + lj->args.append(buf_ptr(arg)); + } + } + + + // libc dep + if (g->link_libc) { + if (g->is_static) { + lj->args.append("--start-group"); + lj->args.append("-lgcc"); + lj->args.append("-lgcc_eh"); + lj->args.append("-lc"); + lj->args.append("--end-group"); + } else { + lj->args.append("-lgcc"); + lj->args.append("--as-needed"); + lj->args.append("-lgcc_s"); + lj->args.append("--no-as-needed"); + lj->args.append("-lc"); + lj->args.append("-lgcc"); + lj->args.append("--as-needed"); + lj->args.append("-lgcc_s"); + lj->args.append("--no-as-needed"); + } + } + + // crt end + if (lj->link_in_crt) { + lj->args.append(get_libc_static_file(g, "crtend.o")); + lj->args.append(get_libc_file(g, "crtn.o")); + } +} + +static bool is_target_cyg_mingw(const ZigTarget *target) { + return (target->os == ZigLLVM_Win32 && target->environ == ZigLLVM_Cygnus) || + (target->os == ZigLLVM_Win32 && target->environ == ZigLLVM_GNU); +} + +static void construct_linker_job_mingw(LinkJob *lj) { + CodeGen *g = lj->codegen; + + if (g->zig_target.arch.arch == ZigLLVM_x86) { + lj->args.append("-m"); + lj->args.append("i386pe"); + } else if (g->zig_target.arch.arch == ZigLLVM_x86_64) { + lj->args.append("-m"); + lj->args.append("i386pep"); + } else if (g->zig_target.arch.arch == ZigLLVM_arm) { + lj->args.append("-m"); + lj->args.append("thumb2pe"); + } + + if (g->windows_subsystem_windows) { + lj->args.append("--subsystem"); + lj->args.append("windows"); + } else if (g->windows_subsystem_console) { + lj->args.append("--subsystem"); + lj->args.append("console"); + } + + bool dll = g->out_type == OutTypeLib; + bool shared = !g->is_static && dll; + if (g->is_static) { + lj->args.append("-Bstatic"); + } else { + if (dll) { + lj->args.append("--dll"); + } else if (shared) { + lj->args.append("--shared"); + } + lj->args.append("-Bdynamic"); + if (dll || shared) { + lj->args.append("-e"); + if (g->zig_target.arch.arch == ZigLLVM_x86) { + lj->args.append("_DllMainCRTStartup@12"); + } else { + lj->args.append("DllMainCRTStartup"); + } + lj->args.append("--enable-auto-image-base"); + } + } + + lj->args.append("-o"); + lj->args.append(buf_ptr(&lj->out_file)); + + if (lj->link_in_crt) { + if (shared || dll) { + lj->args.append(get_libc_file(g, "dllcrt2.o")); + } else { + if (g->windows_linker_unicode) { + lj->args.append(get_libc_file(g, "crt2u.o")); + } else { + lj->args.append(get_libc_file(g, "crt2.o")); + } + } + lj->args.append(get_libc_static_file(g, "crtbegin.o")); + } + + for (int i = 0; i < g->lib_dirs.length; i += 1) { + const char *lib_dir = g->lib_dirs.at(i); + lj->args.append("-L"); + lj->args.append(lib_dir); + } + + if (g->link_libc) { + lj->args.append("-L"); + lj->args.append(buf_ptr(g->libc_lib_dir)); + + lj->args.append("-L"); + lj->args.append(buf_ptr(g->libc_static_lib_dir)); + } + + lj->args.append((const char *)buf_ptr(&lj->out_file_o)); + + if (g->link_libc) { + if (g->is_static) { + lj->args.append("--start-group"); + } + + lj->args.append("-lmingw32"); + + lj->args.append("-lgcc"); + bool is_android = (g->zig_target.environ == ZigLLVM_Android); + bool is_cyg_ming = is_target_cyg_mingw(&g->zig_target); + if (!g->is_static && !is_android) { + if (!is_cyg_ming) { + lj->args.append("--as-needed"); + } + //lj->args.append("-lgcc_s"); + if (!is_cyg_ming) { + lj->args.append("--no-as-needed"); + } + } + if (g->is_static && !is_android) { + //lj->args.append("-lgcc_eh"); + } + if (is_android && !g->is_static) { + lj->args.append("-ldl"); + } + + lj->args.append("-lmoldname"); + lj->args.append("-lmingwex"); + lj->args.append("-lmsvcrt"); + + + if (g->windows_subsystem_windows) { + lj->args.append("-lgdi32"); + lj->args.append("-lcomdlg32"); + } + lj->args.append("-ladvapi32"); + lj->args.append("-lshell32"); + lj->args.append("-luser32"); + lj->args.append("-lkernel32"); + + if (g->is_static) { + lj->args.append("--end-group"); + } + + if (lj->link_in_crt) { + lj->args.append(get_libc_static_file(g, "crtend.o")); + } + } +} + +static void construct_linker_job(LinkJob *lj) { + switch (lj->codegen->zig_target.os) { + case ZigLLVM_UnknownOS: + zig_unreachable(); + 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: + zig_panic("TODO construct DarwinClang linker job"); + 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.environ) { + 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"); + } + + } +} + +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"); + } +} + +void codegen_link(CodeGen *g, const char *out_file) { + LinkJob lj = {0}; + lj.codegen = g; + if (out_file) { + buf_init_from_str(&lj.out_file, out_file); + } else { + buf_resize(&lj.out_file, 0); + } + + bool is_optimized = g->is_release_build; + if (is_optimized) { + if (g->verbose) { + fprintf(stderr, "\nOptimization:\n"); + fprintf(stderr, "---------------\n"); + } + + LLVMZigOptimizeModule(g->target_machine, g->module); + + if (g->verbose) { + LLVMDumpModule(g->module); + } + } + if (g->verbose) { + fprintf(stderr, "\nLink:\n"); + fprintf(stderr, "-------\n"); + } + + if (buf_len(&lj.out_file) == 0) { + assert(g->root_out_name); + buf_init_from_buf(&lj.out_file, g->root_out_name); + buf_append_str(&lj.out_file, get_exe_file_extension(g)); + } + + buf_init_from_buf(&lj.out_file_o, &lj.out_file); + + if (g->out_type != OutTypeObj) { + const char *o_ext = get_o_file_extension(g); + buf_append_str(&lj.out_file_o, o_ext); + } + + char *err_msg = nullptr; + if (LLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(&lj.out_file_o), + LLVMObjectFile, &err_msg)) + { + zig_panic("unable to write object file: %s", err_msg); + } + + if (g->out_type == OutTypeObj) { + if (g->verbose) { + fprintf(stderr, "OK\n"); + } + return; + } + + if (g->out_type == OutTypeLib && g->is_static) { + // invoke `ar` + // example: + // # static link into libfoo.a + // ar rcs libfoo.a foo1.o foo2.o + zig_panic("TODO invoke ar"); + return; + } + + lj.link_in_crt = (g->link_libc && g->out_type == OutTypeExe); + if (lj.link_in_crt) { + find_libc_path(g); + } + + + + // invoke `ld` + ensure_we_have_linker_path(g); + + construct_linker_job(&lj); + + + if (g->verbose) { + fprintf(stderr, "%s", buf_ptr(g->linker_path)); + for (int i = 0; i < lj.args.length; i += 1) { + fprintf(stderr, " %s", lj.args.at(i)); + } + fprintf(stderr, "\n"); + } + + int return_code; + Buf ld_stderr = BUF_INIT; + Buf ld_stdout = BUF_INIT; + os_exec_process(buf_ptr(g->linker_path), lj.args, &return_code, &ld_stderr, &ld_stdout); + + if (return_code != 0) { + fprintf(stderr, "linker failed with return code %d\n", return_code); + fprintf(stderr, "%s ", buf_ptr(g->linker_path)); + for (int i = 0; i < lj.args.length; i += 1) { + fprintf(stderr, "%s ", lj.args.at(i)); + } + fprintf(stderr, "\n%s\n", buf_ptr(&ld_stderr)); + exit(1); + } else if (buf_len(&ld_stderr)) { + fprintf(stderr, "%s\n", buf_ptr(&ld_stderr)); + } + + if (g->out_type == OutTypeLib) { + codegen_generate_h_file(g); + } + + if (g->verbose) { + fprintf(stderr, "OK\n"); + } +} diff --git a/src/link.hpp b/src/link.hpp new file mode 100644 index 000000000..9f978c28d --- /dev/null +++ b/src/link.hpp @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2015 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + +#ifndef ZIG_LINK_HPP +#define ZIG_LINK_HPP + +#include "all_types.hpp" + +void codegen_link(CodeGen *g, const char *out_file); + + +#endif + diff --git a/src/main.cpp b/src/main.cpp index 0d1145809..3cc7fdd9d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,6 +11,7 @@ #include "os.hpp" #include "error.hpp" #include "target.hpp" +#include "link.hpp" #include @@ -31,26 +32,27 @@ static int usage(const char *arg0) { " --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" + " --libc-lib-dir [path] directory where libc crt1.o resides\n" + " --libc-static-lib-dir [path] directory where libc crtbeginT.o resides\n" + " --libc-include-dir [path] directory where libc stdlib.h resides\n" " --dynamic-linker [path] set the path to ld.so\n" + " --ld-path [path] set the path to the linker\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" + " --target-arch [name] specify target architecture\n" + " --target-os [name] specify target operating system\n" + " --target-environ [name] specify target environment\n" + " -mwindows (windows only) --subsystem windows to the linker\n" + " -mconsole (windows only) --subsystem console to the linker\n" + " -municode (windows only) link with unicode\n" , arg0); return EXIT_FAILURE; } static int print_target_list(FILE *f) { - ZigLLVM_ArchType native_arch_type; - ZigLLVM_SubArchType native_sub_arch_type; - ZigLLVM_VendorType native_vendor_type; - ZigLLVM_OSType native_os_type; - ZigLLVM_EnvironmentType native_environ_type; - - ZigLLVMGetNativeTarget(&native_arch_type, &native_sub_arch_type, &native_vendor_type, - &native_os_type, &native_environ_type); + ZigTarget native; + get_native_target(&native); fprintf(f, "Architectures:\n"); int arch_count = target_arch_count(); @@ -58,7 +60,7 @@ static int print_target_list(FILE *f) { const ArchType *arch = get_target_arch(arch_i); const char *sub_arch_str = (arch->sub_arch == ZigLLVM_NoSubArch) ? "" : ZigLLVMGetSubArchTypeName(arch->sub_arch); - const char *native_str = (native_arch_type == arch->arch && native_sub_arch_type == arch->sub_arch) ? + const char *native_str = (native.arch.arch == arch->arch && native.arch.sub_arch == arch->sub_arch) ? " (native)" : ""; fprintf(f, " %s%s%s\n", ZigLLVMGetArchTypeName(arch->arch), sub_arch_str, native_str); } @@ -67,15 +69,15 @@ static int print_target_list(FILE *f) { int os_count = target_os_count(); for (int i = 0; i < os_count; i += 1) { ZigLLVM_OSType os_type = get_target_os(i); - const char *native_str = (native_os_type == os_type) ? " (native)" : ""; + const char *native_str = (native.os == os_type) ? " (native)" : ""; fprintf(f, " %s%s\n", get_target_os_name(os_type), native_str); } - fprintf(f, "\nABIs:\n"); + fprintf(f, "\nEnvironments:\n"); int environ_count = target_environ_count(); for (int i = 0; i < environ_count; i += 1) { ZigLLVM_EnvironmentType environ_type = get_target_environ(i); - const char *native_str = (native_environ_type == environ_type) ? " (native)" : ""; + const char *native_str = (native.environ == environ_type) ? " (native)" : ""; fprintf(f, " %s%s\n", ZigLLVMGetEnvironmentTypeName(environ_type), native_str); } @@ -107,9 +109,16 @@ int main(int argc, char **argv) { const char *libc_static_lib_dir = nullptr; const char *libc_include_dir = nullptr; const char *dynamic_linker = nullptr; + const char *linker_path = nullptr; ZigList clang_argv = {0}; ZigList lib_dirs = {0}; int err; + const char *target_arch = nullptr; + const char *target_os = nullptr; + const char *target_environ = nullptr; + bool mwindows = false; + bool mconsole = false; + bool municode = false; for (int i = 1; i < argc; i += 1) { char *arg = argv[i]; @@ -123,6 +132,12 @@ int main(int argc, char **argv) { is_static = true; } else if (strcmp(arg, "--verbose") == 0) { verbose = true; + } else if (strcmp(arg, "-mwindows") == 0) { + mwindows = true; + } else if (strcmp(arg, "-mconsole") == 0) { + mconsole = true; + } else if (strcmp(arg, "-municode") == 0) { + municode = true; } else if (i + 1 >= argc) { return usage(arg0); } else { @@ -161,6 +176,8 @@ int main(int argc, char **argv) { libc_include_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, "-isystem") == 0) { clang_argv.append("-isystem"); clang_argv.append(argv[i]); @@ -169,7 +186,14 @@ int main(int argc, char **argv) { clang_argv.append(argv[i]); } else if (strcmp(arg, "--library-path") == 0) { lib_dirs.append(argv[i]); + } else if (strcmp(arg, "--target-arch") == 0) { + target_arch = argv[i]; + } else if (strcmp(arg, "--target-os") == 0) { + target_os = argv[i]; + } else if (strcmp(arg, "--target-environ") == 0) { + target_environ = argv[i]; } else { + fprintf(stderr, "Invalid argument: %s\n", arg); return usage(arg0); } } @@ -216,6 +240,36 @@ int main(int argc, char **argv) { if (!in_file) return usage(arg0); + init_all_targets(); + + ZigTarget alloc_target; + ZigTarget *target; + if (!target_arch && !target_os && !target_environ) { + target = nullptr; + } else { + target = &alloc_target; + get_unknown_target(target); + if (target_arch) { + if (parse_target_arch(target_arch, &target->arch)) { + fprintf(stderr, "invalid --target-arch argument\n"); + return usage(arg0); + } + } + if (target_os) { + if (parse_target_os(target_os, &target->os)) { + fprintf(stderr, "invalid --target-os argument\n"); + return usage(arg0); + } + } + if (target_environ) { + if (parse_target_environ(target_environ, &target->environ)) { + fprintf(stderr, "invalid --target-environ argument\n"); + return usage(arg0); + } + } + } + + Buf in_file_buf = BUF_INIT; buf_init_from_str(&in_file_buf, in_file); @@ -237,7 +291,7 @@ int main(int argc, char **argv) { } } - CodeGen *g = codegen_create(&root_source_dir); + CodeGen *g = codegen_create(&root_source_dir, target); codegen_set_is_release(g, is_release_build); codegen_set_is_test(g, cmd == CmdTest); @@ -262,6 +316,8 @@ int main(int argc, char **argv) { codegen_set_libc_include_dir(g, buf_create_from_str(libc_include_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)); codegen_set_verbose(g, verbose); codegen_set_errmsg_color(g, color); @@ -269,6 +325,9 @@ int main(int argc, char **argv) { codegen_add_lib_dir(g, lib_dirs.at(i)); } + codegen_set_windows_subsystem(g, mwindows, mconsole); + codegen_set_windows_unicode(g, municode); + if (cmd == CmdBuild) { codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code); codegen_link(g, out_file); diff --git a/src/parseh.cpp b/src/parseh.cpp index ebe2c2f24..d77f155e3 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -1540,6 +1540,11 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch clang_argv.append("-Xclang"); clang_argv.append("-detailed-preprocessing-record"); + if (!c->codegen->is_native_target) { + clang_argv.append("-target"); + clang_argv.append(buf_ptr(&c->codegen->triple_str)); + } + clang_argv.append(target_file); // to make the [start...end] argument work diff --git a/src/target.cpp b/src/target.cpp index 04a073493..67f30f13c 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -7,6 +7,9 @@ #include "target.hpp" #include "util.hpp" +#include "error.hpp" + +#include static const ArchType arch_list[] = { {ZigLLVM_arm, ZigLLVM_ARMSubArch_v8_1a}, @@ -158,3 +161,127 @@ int target_environ_count(void) { ZigLLVM_EnvironmentType get_target_environ(int index) { return environ_list[index]; } + +void get_native_target(ZigTarget *target) { + ZigLLVMGetNativeTarget( + &target->arch.arch, + &target->arch.sub_arch, + &target->vendor, + &target->os, + &target->environ, + &target->oformat); +} + +void get_unknown_target(ZigTarget *target) { + target->arch.arch = ZigLLVM_UnknownArch; + target->arch.sub_arch = ZigLLVM_NoSubArch; + target->vendor = ZigLLVM_UnknownVendor; + target->os = ZigLLVM_UnknownOS; + target->environ = ZigLLVM_UnknownEnvironment; + target->oformat = ZigLLVM_UnknownObjectFormat; +} + +int parse_target_arch(const char *str, ArchType *out_arch) { + for (int i = 0; i < array_length(arch_list); i += 1) { + const ArchType *arch = &arch_list[i]; + char arch_name[50]; + const char *sub_str = (arch->sub_arch == ZigLLVM_NoSubArch) ? + "" : ZigLLVMGetSubArchTypeName(arch->sub_arch); + sprintf(arch_name, "%s%s", ZigLLVMGetArchTypeName(arch->arch), sub_str); + if (strcmp(arch_name, str) == 0) { + *out_arch = *arch; + return 0; + } + } + return ErrorFileNotFound; +} + +int parse_target_os(const char *str, ZigLLVM_OSType *out_os) { + for (int i = 0; i < array_length(os_list); i += 1) { + ZigLLVM_OSType os = os_list[i]; + const char *os_name = get_target_os_name(os); + if (strcmp(os_name, str) == 0) { + *out_os = os; + return 0; + } + } + return ErrorFileNotFound; +} + +int parse_target_environ(const char *str, ZigLLVM_EnvironmentType *out_environ) { + for (int i = 0; i < array_length(environ_list); i += 1) { + ZigLLVM_EnvironmentType environ = environ_list[i]; + const char *environ_name = ZigLLVMGetEnvironmentTypeName(environ); + if (strcmp(environ_name, str) == 0) { + *out_environ = environ; + return 0; + } + } + return ErrorFileNotFound; +} + +void init_all_targets(void) { + LLVMInitializeAllTargets(); + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllAsmPrinters(); + LLVMInitializeAllAsmParsers(); +} + +void get_target_triple(Buf *triple, const ZigTarget *target) { + ZigLLVMGetTargetTriple(triple, target->arch.arch, target->arch.sub_arch, + target->vendor, target->os, target->environ, target->oformat); +} + +static bool is_os_darwin(ZigTarget *target) { + switch (target->os) { + case ZigLLVM_Darwin: + case ZigLLVM_IOS: + case ZigLLVM_MacOSX: + return true; + default: + return false; + } +} + +void resolve_target_object_format(ZigTarget *target) { + if (target->oformat != ZigLLVM_UnknownObjectFormat) { + return; + } + switch (target->arch.arch) { + default: + break; + case ZigLLVM_hexagon: + case ZigLLVM_mips: + case ZigLLVM_mipsel: + case ZigLLVM_mips64: + case ZigLLVM_mips64el: + case ZigLLVM_r600: + case ZigLLVM_amdgcn: + case ZigLLVM_sparc: + case ZigLLVM_sparcv9: + case ZigLLVM_systemz: + case ZigLLVM_xcore: + case ZigLLVM_ppc64le: + target->oformat = ZigLLVM_ELF; + return; + + case ZigLLVM_ppc: + case ZigLLVM_ppc64: + if (is_os_darwin(target)) { + target->oformat = ZigLLVM_MachO; + return; + } + target->oformat = ZigLLVM_ELF; + return; + } + + if (is_os_darwin(target)) { + target->oformat = ZigLLVM_MachO; + return; + } else if (target->os == ZigLLVM_Win32) { + target->oformat = ZigLLVM_COFF; + return; + } + target->oformat = ZigLLVM_ELF; +} diff --git a/src/target.hpp b/src/target.hpp index 2366c426d..f858bfb2a 100644 --- a/src/target.hpp +++ b/src/target.hpp @@ -10,11 +10,21 @@ #include +struct Buf; + struct ArchType { ZigLLVM_ArchType arch; ZigLLVM_SubArchType sub_arch; }; +struct ZigTarget { + ArchType arch; + ZigLLVM_VendorType vendor; + ZigLLVM_OSType os; + ZigLLVM_EnvironmentType environ; + ZigLLVM_ObjectFormatType oformat; +}; + int target_arch_count(void); const ArchType *get_target_arch(int index); @@ -28,4 +38,18 @@ const char *get_target_os_name(ZigLLVM_OSType os_type); int target_environ_count(void); ZigLLVM_EnvironmentType get_target_environ(int index); +void get_native_target(ZigTarget *target); +void get_unknown_target(ZigTarget *target); + +int parse_target_arch(const char *str, ArchType *arch); +int parse_target_os(const char *str, ZigLLVM_OSType *os); +int parse_target_environ(const char *str, ZigLLVM_EnvironmentType *environ); + +void init_all_targets(void); + +void get_target_triple(Buf *triple, const ZigTarget *target); + +void resolve_target_object_format(ZigTarget *target); + + #endif diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index 072b5c011..e3a26ddac 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -14,6 +14,7 @@ #include "zig_llvm.hpp" + /* * The point of this file is to contain all the LLVM C++ API interaction so that: * 1. The compile time of other files is kept under control. @@ -520,6 +521,11 @@ static_assert((Triple::VendorType)ZigLLVM_LastVendorType == Triple::LastVendorTy static_assert((Triple::OSType)ZigLLVM_LastOSType == Triple::LastOSType, ""); static_assert((Triple::EnvironmentType)ZigLLVM_LastEnvironmentType == Triple::LastEnvironmentType, ""); +static_assert((Triple::ObjectFormatType)ZigLLVM_UnknownObjectFormat == Triple::UnknownObjectFormat, ""); +static_assert((Triple::ObjectFormatType)ZigLLVM_COFF == Triple::COFF, ""); +static_assert((Triple::ObjectFormatType)ZigLLVM_ELF == Triple::ELF, ""); +static_assert((Triple::ObjectFormatType)ZigLLVM_MachO == Triple::MachO, ""); + const char *ZigLLVMGetArchTypeName(ZigLLVM_ArchType arch) { return Triple::getArchTypeName((Triple::ArchType)arch); } @@ -537,7 +543,8 @@ const char *ZigLLVMGetEnvironmentTypeName(ZigLLVM_EnvironmentType environ) { } void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type, ZigLLVM_SubArchType *sub_arch_type, - ZigLLVM_VendorType *vendor_type, ZigLLVM_OSType *os_type, ZigLLVM_EnvironmentType *environ_type) + ZigLLVM_VendorType *vendor_type, ZigLLVM_OSType *os_type, ZigLLVM_EnvironmentType *environ_type, + ZigLLVM_ObjectFormatType *oformat) { char *native_triple = LLVMGetDefaultTargetTriple(); Triple triple(native_triple); @@ -547,6 +554,7 @@ void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type, ZigLLVM_SubArchType *su *vendor_type = (ZigLLVM_VendorType)triple.getVendor(); *os_type = (ZigLLVM_OSType)triple.getOS(); *environ_type = (ZigLLVM_EnvironmentType)triple.getEnvironment(); + *oformat = (ZigLLVM_ObjectFormatType)triple.getObjectFormat(); free(native_triple); } @@ -594,6 +602,23 @@ const char *ZigLLVMGetSubArchTypeName(ZigLLVM_SubArchType sub_arch) { #include "buffer.hpp" +void ZigLLVMGetTargetTriple(Buf *out_buf, ZigLLVM_ArchType arch_type, ZigLLVM_SubArchType sub_arch_type, + ZigLLVM_VendorType vendor_type, ZigLLVM_OSType os_type, ZigLLVM_EnvironmentType environ_type, + ZigLLVM_ObjectFormatType oformat) +{ + Triple triple; + + triple.setArch((Triple::ArchType)arch_type); + // TODO how to set the sub arch? + triple.setVendor((Triple::VendorType)vendor_type); + triple.setOS((Triple::OSType)os_type); + triple.setEnvironment((Triple::EnvironmentType)environ_type); + triple.setObjectFormat((Triple::ObjectFormatType)oformat); + + const std::string &str = triple.str(); + buf_init_from_mem(out_buf, str.c_str(), str.size()); +} + enum FloatAbi { FloatAbiHard, FloatAbiSoft, diff --git a/src/zig_llvm.hpp b/src/zig_llvm.hpp index fbed42d29..dd6e40cb0 100644 --- a/src/zig_llvm.hpp +++ b/src/zig_llvm.hpp @@ -189,6 +189,7 @@ enum ZigLLVM_ArchType { ZigLLVM_shave, // SHAVE: Movidius vector VLIW processors ZigLLVM_wasm32, // WebAssembly with 32-bit pointers ZigLLVM_wasm64, // WebAssembly with 64-bit pointers + ZigLLVM_LastArchType = ZigLLVM_wasm64 }; @@ -227,6 +228,7 @@ enum ZigLLVM_VendorType { ZigLLVM_MipsTechnologies, ZigLLVM_NVIDIA, ZigLLVM_CSR, + ZigLLVM_LastVendorType = ZigLLVM_CSR }; enum ZigLLVM_OSType { @@ -256,6 +258,7 @@ enum ZigLLVM_OSType { ZigLLVM_NVCL, // NVIDIA OpenCL ZigLLVM_AMDHSA, // AMD HSA Runtime ZigLLVM_PS4, + ZigLLVM_LastOSType = ZigLLVM_PS4 }; enum ZigLLVM_EnvironmentType { @@ -273,14 +276,15 @@ enum ZigLLVM_EnvironmentType { ZigLLVM_MSVC, ZigLLVM_Itanium, ZigLLVM_Cygnus, - ZigLLVM_LastEnvironmentType = ZigLLVM_Cygnus + + ZigLLVM_LastEnvironmentType = ZigLLVM_Cygnus, }; enum ZigLLVM_ObjectFormatType { - ZigLLVM_UnknownObjectFormat, + ZigLLVM_UnknownObjectFormat, - ZigLLVM_COFF, - ZigLLVM_ELF, - ZigLLVM_MachO, + ZigLLVM_COFF, + ZigLLVM_ELF, + ZigLLVM_MachO, }; const char *ZigLLVMGetArchTypeName(ZigLLVM_ArchType arch); @@ -289,14 +293,18 @@ const char *ZigLLVMGetVendorTypeName(ZigLLVM_VendorType vendor); const char *ZigLLVMGetOSTypeName(ZigLLVM_OSType os); const char *ZigLLVMGetEnvironmentTypeName(ZigLLVM_EnvironmentType environ); -void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type, ZigLLVM_SubArchType *sub_arch_type, - ZigLLVM_VendorType *vendor_type, ZigLLVM_OSType *os_type, ZigLLVM_EnvironmentType *environ_type); - - /* * This stuff is not LLVM API but it depends on the LLVM C++ API so we put it here. */ struct Buf; +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); +void ZigLLVMGetTargetTriple(Buf *out_buf, ZigLLVM_ArchType arch_type, ZigLLVM_SubArchType sub_arch_type, + ZigLLVM_VendorType vendor_type, ZigLLVM_OSType os_type, ZigLLVM_EnvironmentType environ_type, + ZigLLVM_ObjectFormatType oformat); + + Buf *get_dynamic_linker(LLVMTargetMachineRef target_machine); #endif