From 2bf6c28bc3e535deb651d5b37e332226e0d38930 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 11 Feb 2016 01:33:27 -0700 Subject: ability to cross compile hello_libc.zig can produce a windows build --- src/codegen.cpp | 333 ++++++++++---------------------------------------------- 1 file changed, 56 insertions(+), 277 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 1074d24200..c6fd87fa5d 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"); - } -} -- cgit v1.2.3