diff options
Diffstat (limited to 'src/main.cpp')
| -rw-r--r-- | src/main.cpp | 877 |
1 files changed, 616 insertions, 261 deletions
diff --git a/src/main.cpp b/src/main.cpp index 077603b30..46364d8d6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,6 +10,10 @@ gb_global Timings global_timings = {0}; +#if defined(LLVM_BACKEND_SUPPORT) +#include "llvm-c/Types.h" +#endif + #include "parser.hpp" #include "checker.hpp" @@ -17,11 +21,18 @@ gb_global Timings global_timings = {0}; #include "parser.cpp" #include "docs.cpp" #include "checker.cpp" + + +#if defined(LLVM_BACKEND_SUPPORT) +#include "llvm_backend.cpp" +#endif + #include "ir.cpp" #include "ir_opt.cpp" #include "ir_print.cpp" #include "query_data.cpp" + #if defined(GB_SYSTEM_WINDOWS) // NOTE(IC): In order to find Visual C++ paths without relying on environment variables. #include "microsoft_craziness.h" @@ -121,6 +132,304 @@ i32 system_exec_command_line_app(char const *name, char const *fmt, ...) { + +#if defined(LLVM_BACKEND_SUPPORT) +i32 linker_stage(lbGenerator *gen) { + i32 exit_code = 0; + + Timings *timings = &global_timings; + + String output_base = gen->output_base; + + if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { +#ifdef GB_SYSTEM_UNIX + system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s", + LIT(output_base), LIT(output_base), LIT(build_context.link_flags)); +#else + gb_printf_err("Don't know how to cross compile to selected target.\n"); +#endif + } else { + #if defined(GB_SYSTEM_WINDOWS) + timings_start_section(timings, str_lit("msvc-link")); + + gbString lib_str = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(lib_str)); + char lib_str_buf[1024] = {0}; + + char const *output_ext = "exe"; + gbString link_settings = gb_string_make_reserve(heap_allocator(), 256); + defer (gb_string_free(link_settings)); + + + // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. + Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8(); + + if (find_result.windows_sdk_version == 0) { + gb_printf_err("Windows SDK not found.\n"); + return 1; + } + + // Add library search paths. + if (find_result.vs_library_path.len > 0) { + GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0); + GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); + + String path = {}; + auto add_path = [&](String path) { + if (path[path.len-1] == '\\') { + path.len -= 1; + } + link_settings = gb_string_append_fmt(link_settings, " /LIBPATH:\"%.*s\"", LIT(path)); + }; + add_path(find_result.windows_sdk_um_library_path); + add_path(find_result.windows_sdk_ucrt_library_path); + add_path(find_result.vs_library_path); + } + + for_array(i, gen->module.foreign_library_paths) { + String lib = gen->module.foreign_library_paths[i]; + GB_ASSERT(lib.len < gb_count_of(lib_str_buf)-1); + isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), + " \"%.*s\"", LIT(lib)); + lib_str = gb_string_appendc(lib_str, lib_str_buf); + } + + + + if (build_context.is_dll) { + output_ext = "dll"; + link_settings = gb_string_append_fmt(link_settings, "/DLL"); + } else { + link_settings = gb_string_append_fmt(link_settings, "/ENTRY:mainCRTStartup"); + } + + if (build_context.pdb_filepath != "") { + link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(build_context.pdb_filepath)); + } + + if (build_context.no_crt) { + link_settings = gb_string_append_fmt(link_settings, " /nodefaultlib"); + } else { + link_settings = gb_string_append_fmt(link_settings, " /defaultlib:libcmt"); + } + + if (build_context.ODIN_DEBUG) { + link_settings = gb_string_append_fmt(link_settings, " /DEBUG"); + } + + gbString object_files = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(object_files)); + for_array(i, gen->output_object_paths) { + String object_path = gen->output_object_paths[i]; + object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path)); + } + + char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE"; + if (!build_context.use_lld) { // msvc + if (build_context.has_resource) { + exit_code = system_exec_command_line_app("msvc-link", + "\"%.*src.exe\" /nologo /fo \"%.*s.res\" \"%.*s.rc\"", + LIT(find_result.vs_exe_path), + LIT(output_base), + LIT(build_context.resource_filepath) + ); + + if (exit_code != 0) { + return exit_code; + } + + exit_code = system_exec_command_line_app("msvc-link", + "\"%.*slink.exe\" %s \"%.*s.res\" -OUT:\"%.*s.%s\" %s " + "/nologo /incremental:no /opt:ref /subsystem:%s " + " %.*s " + " %s " + "", + LIT(find_result.vs_exe_path), object_files, LIT(output_base), LIT(output_base), output_ext, + link_settings, + subsystem_str, + LIT(build_context.link_flags), + lib_str + ); + } else { + exit_code = system_exec_command_line_app("msvc-link", + "\"%.*slink.exe\" %s -OUT:\"%.*s.%s\" %s " + "/nologo /incremental:no /opt:ref /subsystem:%s " + " %.*s " + " %s " + "", + LIT(find_result.vs_exe_path), object_files, LIT(output_base), output_ext, + link_settings, + subsystem_str, + LIT(build_context.link_flags), + lib_str + ); + } + } else { // lld + exit_code = system_exec_command_line_app("msvc-link", + "\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s.%s\" %s " + "/nologo /incremental:no /opt:ref /subsystem:%s " + " %.*s " + " %s " + "", + LIT(build_context.ODIN_ROOT), + LIT(output_base), object_files, output_ext, + link_settings, + subsystem_str, + LIT(build_context.link_flags), + lib_str + ); + } + #else + timings_start_section(timings, str_lit("ld-link")); + + // NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe + char cwd[256]; + getcwd(&cwd[0], 256); + //printf("%s\n", cwd); + + // NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library + // files can be passed with -l: + gbString lib_str = gb_string_make(heap_allocator(), "-L/"); + defer (gb_string_free(lib_str)); + + for_array(i, ir_gen.module.foreign_library_paths) { + String lib = ir_gen.module.foreign_library_paths[i]; + + // NOTE(zangent): Sometimes, you have to use -framework on MacOS. + // This allows you to specify '-f' in a #foreign_system_library, + // without having to implement any new syntax specifically for MacOS. + #if defined(GB_SYSTEM_OSX) + if (string_ends_with(lib, str_lit(".framework"))) { + // framework thingie + String lib_name = lib; + lib_name = remove_extension_from_path(lib_name); + lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name)); + } else if (string_ends_with(lib, str_lit(".a"))) { + // static libs, absolute full path relative to the file in which the lib was imported from + lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); + } else if (string_ends_with(lib, str_lit(".dylib"))) { + // dynamic lib + lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); + } else { + // dynamic or static system lib, just link regularly searching system library paths + lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); + } + #else + // NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path, + // since those are statically linked to at link time. shared libraries (.so) has to be + // available at runtime wherever the executable is run, so we make require those to be + // local to the executable (unless the system collection is used, in which case we search + // the system library paths for the library file). + if (string_ends_with(lib, str_lit(".a"))) { + // static libs, absolute full path relative to the file in which the lib was imported from + lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib)); + } else if (string_ends_with(lib, str_lit(".so"))) { + // dynamic lib, relative path to executable + // NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible + // at runtimeto the executable + lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib)); + } else { + // dynamic or static system lib, just link regularly searching system library paths + lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); + } + #endif + } + + gbString object_files = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(object_files)); + for_array(i, gen->output_object_paths) { + String object_path = gen->output_object_paths[i]; + object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path)); + } + + // Unlike the Win32 linker code, the output_ext includes the dot, because + // typically executable files on *NIX systems don't have extensions. + String output_ext = {}; + char const *link_settings = ""; + char const *linker; + if (build_context.is_dll) { + // Shared libraries are .dylib on MacOS and .so on Linux. + #if defined(GB_SYSTEM_OSX) + output_ext = STR_LIT(".dylib"); + link_settings = "-dylib -dynamic"; + #else + output_ext = STR_LIT(".so"); + link_settings = "-shared"; + #endif + } else { + // TODO: Do I need anything here? + link_settings = ""; + } + + if (build_context.out_filepath.len > 0) { + //NOTE(thebirk): We have a custom -out arguments, so we should use the extension from that + isize pos = string_extension_position(build_context.out_filepath); + if (pos > 0) { + output_ext = substring(build_context.out_filepath, pos, build_context.out_filepath.len); + } + } + + #if defined(GB_SYSTEM_OSX) + linker = "ld"; + #else + // TODO(zangent): Figure out how to make ld work on Linux. + // It probably has to do with including the entire CRT, but + // that's quite a complicated issue to solve while remaining distro-agnostic. + // Clang can figure out linker flags for us, and that's good enough _for now_. + linker = "clang -Wno-unused-command-line-argument"; + #endif + + exit_code = system_exec_command_line_app("ld-link", + "%s %s -o \"%.*s%.*s\" %s " + " %s " + " %.*s " + " %s " + #if defined(GB_SYSTEM_OSX) + // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit. + // NOTE: If you change this (although this minimum is as low as you can go with Odin working) + // make sure to also change the 'mtriple' param passed to 'opt' + " -macosx_version_min 10.8.0 " + // This points the linker to where the entry point is + " -e _main " + #endif + , linker, object_files, LIT(output_base), LIT(output_ext), + lib_str, + "-lc -lm", + LIT(build_context.link_flags), + link_settings); + if (exit_code != 0) { + return exit_code; + } + + #if defined(GB_SYSTEM_OSX) + if (build_context.ODIN_DEBUG) { + // NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe + // to the symbols in the object file + exit_code = system_exec_command_line_app("dsymutil", + "dsymutil %.*s%.*s", LIT(output_base), LIT(output_ext) + ); + + if (exit_code != 0) { + return exit_code; + } + } + #endif + + + if (build_context.show_timings) { + show_timings(&checker, timings); + } + + remove_temp_files(output_base); + + + #endif + } + + return exit_code; +} +#endif + Array<String> setup_args(int argc, char const **argv) { gbAllocator a = heap_allocator(); @@ -234,6 +543,7 @@ enum BuildFlagKind { BuildFlag_NoCRT, BuildFlag_UseLLD, BuildFlag_Vet, + BuildFlag_UseLLVMApi, BuildFlag_IgnoreUnknownAttributes, BuildFlag_Compact, @@ -325,6 +635,7 @@ bool parse_build_flags(Array<String> args) { add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None); + add_flag(&build_flags, BuildFlag_UseLLVMApi, str_lit("llvm-api"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_Compact, str_lit("compact"), BuildFlagParam_None); @@ -349,6 +660,7 @@ bool parse_build_flags(Array<String> args) { gb_printf_err("Invalid flag: %.*s\n", LIT(flag)); continue; } + String name = substring(flag, 1, flag.len); isize end = 0; for (; end < name.len; end++) { @@ -694,6 +1006,10 @@ bool parse_build_flags(Array<String> args) { build_context.vet = true; break; + case BuildFlag_UseLLVMApi: + build_context.use_llvm_api = true; + break; + case BuildFlag_IgnoreUnknownAttributes: build_context.ignore_unknown_attributes = true; break; @@ -1277,331 +1593,370 @@ int main(int arg_count, char const **arg_ptr) { return 1; } - irGen ir_gen = {0}; - if (!ir_gen_init(&ir_gen, &checker)) { - return 1; - } - // defer (ir_gen_destroy(&ir_gen)); + if (build_context.use_llvm_api) { +#if defined(LLVM_BACKEND_SUPPORT) + timings_start_section(timings, str_lit("LLVM API Code Gen")); + lbGenerator gen = {}; + if (!lb_init_generator(&gen, &checker)) { + return 1; + } + lb_generate_code(&gen); - timings_start_section(timings, str_lit("llvm ir gen")); - ir_gen_tree(&ir_gen); + i32 linker_stage_exit_count = linker_stage(&gen); + if (linker_stage_exit_count != 0) { + return linker_stage_exit_count; + } - timings_start_section(timings, str_lit("llvm ir opt tree")); - ir_opt_tree(&ir_gen); + if (build_context.show_timings) { + show_timings(&checker, timings); + } - timings_start_section(timings, str_lit("llvm ir print")); - print_llvm_ir(&ir_gen); + remove_temp_files(gen.output_base); + if (run_output) { + #if defined(GB_SYSTEM_WINDOWS) + return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(gen.output_base), LIT(run_args_string)); + #else + //NOTE(thebirk): This whole thing is a little leaky + String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext); + complete_path = path_to_full_path(heap_allocator(), complete_path); + return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string)); + #endif + } - String output_name = ir_gen.output_name; - String output_base = ir_gen.output_base; + return 0; +#else + gb_printf_err("LLVM C API backend is not supported on this platform yet\n"); + return 1; +#endif + } else { + irGen ir_gen = {0}; + if (!ir_gen_init(&ir_gen, &checker)) { + return 1; + } + // defer (ir_gen_destroy(&ir_gen)); - build_context.optimization_level = gb_clamp(build_context.optimization_level, 0, 3); - i32 exit_code = 0; + timings_start_section(timings, str_lit("llvm ir gen")); + ir_gen_tree(&ir_gen); - timings_start_section(timings, str_lit("llvm-opt")); - exit_code = exec_llvm_opt(output_base); - if (exit_code != 0) { - return exit_code; - } + timings_start_section(timings, str_lit("llvm ir opt tree")); + ir_opt_tree(&ir_gen); - timings_start_section(timings, str_lit("llvm-llc")); - exit_code = exec_llvm_llc(output_base); - if (exit_code != 0) { - return exit_code; - } + timings_start_section(timings, str_lit("llvm ir print")); + print_llvm_ir(&ir_gen); - if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { -#ifdef GB_SYSTEM_UNIX - system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s", - LIT(output_base), LIT(output_base), LIT(build_context.link_flags)); -#else - gb_printf_err("Don't know how to cross compile to selected target.\n"); -#endif - } else { - #if defined(GB_SYSTEM_WINDOWS) - timings_start_section(timings, str_lit("msvc-link")); - gbString lib_str = gb_string_make(heap_allocator(), ""); - defer (gb_string_free(lib_str)); - char lib_str_buf[1024] = {0}; + String output_name = ir_gen.output_name; + String output_base = ir_gen.output_base; - char const *output_ext = "exe"; - gbString link_settings = gb_string_make_reserve(heap_allocator(), 256); - defer (gb_string_free(link_settings)); + build_context.optimization_level = gb_clamp(build_context.optimization_level, 0, 3); + i32 exit_code = 0; - // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. - Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8(); + timings_start_section(timings, str_lit("llvm-opt")); + exit_code = exec_llvm_opt(output_base); + if (exit_code != 0) { + return exit_code; + } - if (find_result.windows_sdk_version == 0) { - gb_printf_err("Windows SDK not found.\n"); - return 1; + timings_start_section(timings, str_lit("llvm-llc")); + exit_code = exec_llvm_llc(output_base); + if (exit_code != 0) { + return exit_code; } - // Add library search paths. - if (find_result.vs_library_path.len > 0) { - GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0); - GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); + if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { + #ifdef GB_SYSTEM_UNIX + system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s", + LIT(output_base), LIT(output_base), LIT(build_context.link_flags)); + #else + gb_printf_err("Don't know how to cross compile to selected target.\n"); + #endif + } else { + #if defined(GB_SYSTEM_WINDOWS) + timings_start_section(timings, str_lit("msvc-link")); - String path = {}; - auto add_path = [&](String path) { - if (path[path.len-1] == '\\') { - path.len -= 1; - } - link_settings = gb_string_append_fmt(link_settings, " /LIBPATH:\"%.*s\"", LIT(path)); - }; - add_path(find_result.windows_sdk_um_library_path); - add_path(find_result.windows_sdk_ucrt_library_path); - add_path(find_result.vs_library_path); - } + gbString lib_str = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(lib_str)); + char lib_str_buf[1024] = {0}; - for_array(i, ir_gen.module.foreign_library_paths) { - String lib = ir_gen.module.foreign_library_paths[i]; - GB_ASSERT(lib.len < gb_count_of(lib_str_buf)-1); - isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), - " \"%.*s\"", LIT(lib)); - lib_str = gb_string_appendc(lib_str, lib_str_buf); - } + char const *output_ext = "exe"; + gbString link_settings = gb_string_make_reserve(heap_allocator(), 256); + defer (gb_string_free(link_settings)); + // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. + Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8(); - if (build_context.is_dll) { - output_ext = "dll"; - link_settings = gb_string_append_fmt(link_settings, "/DLL"); - } else { - link_settings = gb_string_append_fmt(link_settings, "/ENTRY:mainCRTStartup"); - } + if (find_result.windows_sdk_version == 0) { + gb_printf_err("Windows SDK not found.\n"); + return 1; + } - if (build_context.pdb_filepath != "") { - link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(build_context.pdb_filepath)); - } + // Add library search paths. + if (find_result.vs_library_path.len > 0) { + GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0); + GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); - if (build_context.no_crt) { - link_settings = gb_string_append_fmt(link_settings, " /nodefaultlib"); - } else { - link_settings = gb_string_append_fmt(link_settings, " /defaultlib:libcmt"); - } + String path = {}; + auto add_path = [&](String path) { + if (path[path.len-1] == '\\') { + path.len -= 1; + } + link_settings = gb_string_append_fmt(link_settings, " /LIBPATH:\"%.*s\"", LIT(path)); + }; + add_path(find_result.windows_sdk_um_library_path); + add_path(find_result.windows_sdk_ucrt_library_path); + add_path(find_result.vs_library_path); + } - if (ir_gen.module.generate_debug_info) { - link_settings = gb_string_append_fmt(link_settings, " /DEBUG"); - } + for_array(i, ir_gen.module.foreign_library_paths) { + String lib = ir_gen.module.foreign_library_paths[i]; + GB_ASSERT(lib.len < gb_count_of(lib_str_buf)-1); + isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), + " \"%.*s\"", LIT(lib)); + lib_str = gb_string_appendc(lib_str, lib_str_buf); + } - char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE"; - if (!build_context.use_lld) { // msvc - if (build_context.has_resource) { - exit_code = system_exec_command_line_app("msvc-link", - "\"%.*src.exe\" /nologo /fo \"%.*s.res\" \"%.*s.rc\"", - LIT(find_result.vs_exe_path), - LIT(output_base), - LIT(build_context.resource_filepath) - ); - if (exit_code != 0) { - return exit_code; - } + if (build_context.is_dll) { + output_ext = "dll"; + link_settings = gb_string_append_fmt(link_settings, "/DLL"); + } else { + link_settings = gb_string_append_fmt(link_settings, "/ENTRY:mainCRTStartup"); + } - exit_code = system_exec_command_line_app("msvc-link", - "\"%.*slink.exe\" \"%.*s.obj\" \"%.*s.res\" -OUT:\"%.*s.%s\" %s " - "/nologo /incremental:no /opt:ref /subsystem:%s " - " %.*s " - " %s " - "", - LIT(find_result.vs_exe_path), LIT(output_base), LIT(output_base), LIT(output_base), output_ext, - link_settings, - subsystem_str, - LIT(build_context.link_flags), - lib_str - ); + if (build_context.pdb_filepath != "") { + link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(build_context.pdb_filepath)); + } + + if (build_context.no_crt) { + link_settings = gb_string_append_fmt(link_settings, " /nodefaultlib"); } else { + link_settings = gb_string_append_fmt(link_settings, " /defaultlib:libcmt"); + } + + if (ir_gen.module.generate_debug_info) { + link_settings = gb_string_append_fmt(link_settings, " /DEBUG"); + } + + + char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE"; + if (!build_context.use_lld) { // msvc + if (build_context.has_resource) { + exit_code = system_exec_command_line_app("msvc-link", + "\"%.*src.exe\" /nologo /fo \"%.*s.res\" \"%.*s.rc\"", + LIT(find_result.vs_exe_path), + LIT(output_base), + LIT(build_context.resource_filepath) + ); + + if (exit_code != 0) { + return exit_code; + } + + exit_code = system_exec_command_line_app("msvc-link", + "\"%.*slink.exe\" \"%.*s.obj\" \"%.*s.res\" -OUT:\"%.*s.%s\" %s " + "/nologo /incremental:no /opt:ref /subsystem:%s " + " %.*s " + " %s " + "", + LIT(find_result.vs_exe_path), LIT(output_base), LIT(output_base), LIT(output_base), output_ext, + link_settings, + subsystem_str, + LIT(build_context.link_flags), + lib_str + ); + } else { + exit_code = system_exec_command_line_app("msvc-link", + "\"%.*slink.exe\" \"%.*s.obj\" -OUT:\"%.*s.%s\" %s " + "/nologo /incremental:no /opt:ref /subsystem:%s " + " %.*s " + " %s " + "", + LIT(find_result.vs_exe_path), LIT(output_base), LIT(output_base), output_ext, + link_settings, + subsystem_str, + LIT(build_context.link_flags), + lib_str + ); + } + } else { // lld exit_code = system_exec_command_line_app("msvc-link", - "\"%.*slink.exe\" \"%.*s.obj\" -OUT:\"%.*s.%s\" %s " + "\"%.*s\\bin\\lld-link\" \"%.*s.obj\" -OUT:\"%.*s.%s\" %s " "/nologo /incremental:no /opt:ref /subsystem:%s " " %.*s " " %s " "", - LIT(find_result.vs_exe_path), LIT(output_base), LIT(output_base), output_ext, + LIT(build_context.ODIN_ROOT), + LIT(output_base), LIT(output_base), output_ext, link_settings, subsystem_str, LIT(build_context.link_flags), lib_str ); } - } else { // lld - exit_code = system_exec_command_line_app("msvc-link", - "\"%.*s\\bin\\lld-link\" \"%.*s.obj\" -OUT:\"%.*s.%s\" %s " - "/nologo /incremental:no /opt:ref /subsystem:%s " - " %.*s " - " %s " - "", - LIT(build_context.ODIN_ROOT), - LIT(output_base), LIT(output_base), output_ext, - link_settings, - subsystem_str, - LIT(build_context.link_flags), - lib_str - ); - } - - if (exit_code != 0) { - return exit_code; - } - - if (build_context.show_timings) { - show_timings(&checker, timings); - } - remove_temp_files(output_base); + if (exit_code != 0) { + return exit_code; + } - if (run_output) { - return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string)); - } - #else - timings_start_section(timings, str_lit("ld-link")); + if (build_context.show_timings) { + show_timings(&checker, timings); + } - // NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe - char cwd[256]; - getcwd(&cwd[0], 256); - //printf("%s\n", cwd); + remove_temp_files(output_base); - // NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library - // files can be passed with -l: - gbString lib_str = gb_string_make(heap_allocator(), "-L/"); - defer (gb_string_free(lib_str)); + if (run_output) { + return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string)); + } + #else + timings_start_section(timings, str_lit("ld-link")); + + // NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe + char cwd[256]; + getcwd(&cwd[0], 256); + //printf("%s\n", cwd); + + // NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library + // files can be passed with -l: + gbString lib_str = gb_string_make(heap_allocator(), "-L/"); + defer (gb_string_free(lib_str)); + + for_array(i, ir_gen.module.foreign_library_paths) { + String lib = ir_gen.module.foreign_library_paths[i]; + + // NOTE(zangent): Sometimes, you have to use -framework on MacOS. + // This allows you to specify '-f' in a #foreign_system_library, + // without having to implement any new syntax specifically for MacOS. + #if defined(GB_SYSTEM_OSX) + if (string_ends_with(lib, str_lit(".framework"))) { + // framework thingie + String lib_name = lib; + lib_name = remove_extension_from_path(lib_name); + lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name)); + } else if (string_ends_with(lib, str_lit(".a"))) { + // static libs, absolute full path relative to the file in which the lib was imported from + lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); + } else if (string_ends_with(lib, str_lit(".dylib"))) { + // dynamic lib + lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); + } else { + // dynamic or static system lib, just link regularly searching system library paths + lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); + } + #else + // NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path, + // since those are statically linked to at link time. shared libraries (.so) has to be + // available at runtime wherever the executable is run, so we make require those to be + // local to the executable (unless the system collection is used, in which case we search + // the system library paths for the library file). + if (string_ends_with(lib, str_lit(".a"))) { + // static libs, absolute full path relative to the file in which the lib was imported from + lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib)); + } else if (string_ends_with(lib, str_lit(".so"))) { + // dynamic lib, relative path to executable + // NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible + // at runtimeto the executable + lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib)); + } else { + // dynamic or static system lib, just link regularly searching system library paths + lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); + } + #endif + } - for_array(i, ir_gen.module.foreign_library_paths) { - String lib = ir_gen.module.foreign_library_paths[i]; + // Unlike the Win32 linker code, the output_ext includes the dot, because + // typically executable files on *NIX systems don't have extensions. + String output_ext = {}; + char const *link_settings = ""; + char const *linker; + if (build_context.is_dll) { + // Shared libraries are .dylib on MacOS and .so on Linux. + #if defined(GB_SYSTEM_OSX) + output_ext = STR_LIT(".dylib"); + link_settings = "-dylib -dynamic"; + #else + output_ext = STR_LIT(".so"); + link_settings = "-shared"; + #endif + } else { + // TODO: Do I need anything here? + link_settings = ""; + } - // NOTE(zangent): Sometimes, you have to use -framework on MacOS. - // This allows you to specify '-f' in a #foreign_system_library, - // without having to implement any new syntax specifically for MacOS. - #if defined(GB_SYSTEM_OSX) - if (string_ends_with(lib, str_lit(".framework"))) { - // framework thingie - String lib_name = lib; - lib_name = remove_extension_from_path(lib_name); - lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name)); - } else if (string_ends_with(lib, str_lit(".a"))) { - // static libs, absolute full path relative to the file in which the lib was imported from - lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); - } else if (string_ends_with(lib, str_lit(".dylib"))) { - // dynamic lib - lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); - } else { - // dynamic or static system lib, just link regularly searching system library paths - lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); + if (build_context.out_filepath.len > 0) { + //NOTE(thebirk): We have a custom -out arguments, so we should use the extension from that + isize pos = string_extension_position(build_context.out_filepath); + if (pos > 0) { + output_ext = substring(build_context.out_filepath, pos, build_context.out_filepath.len); } - #else - // NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path, - // since those are statically linked to at link time. shared libraries (.so) has to be - // available at runtime wherever the executable is run, so we make require those to be - // local to the executable (unless the system collection is used, in which case we search - // the system library paths for the library file). - if (string_ends_with(lib, str_lit(".a"))) { - // static libs, absolute full path relative to the file in which the lib was imported from - lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib)); - } else if (string_ends_with(lib, str_lit(".so"))) { - // dynamic lib, relative path to executable - // NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible - // at runtimeto the executable - lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib)); - } else { - // dynamic or static system lib, just link regularly searching system library paths - lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); - } - #endif - } + } - // Unlike the Win32 linker code, the output_ext includes the dot, because - // typically executable files on *NIX systems don't have extensions. - String output_ext = {}; - char const *link_settings = ""; - char const *linker; - if (build_context.is_dll) { - // Shared libraries are .dylib on MacOS and .so on Linux. #if defined(GB_SYSTEM_OSX) - output_ext = STR_LIT(".dylib"); - link_settings = "-dylib -dynamic"; + linker = "ld"; #else - output_ext = STR_LIT(".so"); - link_settings = "-shared"; + // TODO(zangent): Figure out how to make ld work on Linux. + // It probably has to do with including the entire CRT, but + // that's quite a complicated issue to solve while remaining distro-agnostic. + // Clang can figure out linker flags for us, and that's good enough _for now_. + linker = "clang -Wno-unused-command-line-argument"; #endif - } else { - // TODO: Do I need anything here? - link_settings = ""; - } - if (build_context.out_filepath.len > 0) { - //NOTE(thebirk): We have a custom -out arguments, so we should use the extension from that - isize pos = string_extension_position(build_context.out_filepath); - if (pos > 0) { - output_ext = substring(build_context.out_filepath, pos, build_context.out_filepath.len); + exit_code = system_exec_command_line_app("ld-link", + "%s \"%.*s.o\" -o \"%.*s%.*s\" %s " + " %s " + " %.*s " + " %s " + #if defined(GB_SYSTEM_OSX) + // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit. + // NOTE: If you change this (although this minimum is as low as you can go with Odin working) + // make sure to also change the 'mtriple' param passed to 'opt' + " -macosx_version_min 10.8.0 " + // This points the linker to where the entry point is + " -e _main " + #endif + , linker, LIT(output_base), LIT(output_base), LIT(output_ext), + lib_str, + "-lc -lm", + LIT(build_context.link_flags), + link_settings); + if (exit_code != 0) { + return exit_code; } - } #if defined(GB_SYSTEM_OSX) - linker = "ld"; - #else - // TODO(zangent): Figure out how to make ld work on Linux. - // It probably has to do with including the entire CRT, but - // that's quite a complicated issue to solve while remaining distro-agnostic. - // Clang can figure out linker flags for us, and that's good enough _for now_. - linker = "clang -Wno-unused-command-line-argument"; - #endif - - exit_code = system_exec_command_line_app("ld-link", - "%s \"%.*s.o\" -o \"%.*s%.*s\" %s " - " %s " - " %.*s " - " %s " - #if defined(GB_SYSTEM_OSX) - // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit. - // NOTE: If you change this (although this minimum is as low as you can go with Odin working) - // make sure to also change the 'mtriple' param passed to 'opt' - " -macosx_version_min 10.8.0 " - // This points the linker to where the entry point is - " -e _main " - #endif - , linker, LIT(output_base), LIT(output_base), LIT(output_ext), - lib_str, - "-lc -lm", - LIT(build_context.link_flags), - link_settings); - if (exit_code != 0) { - return exit_code; - } - - #if defined(GB_SYSTEM_OSX) - if (build_context.ODIN_DEBUG) { - // NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe - // to the symbols in the object file - exit_code = system_exec_command_line_app("dsymutil", - "dsymutil %.*s%.*s", LIT(output_base), LIT(output_ext) - ); + if (build_context.ODIN_DEBUG) { + // NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe + // to the symbols in the object file + exit_code = system_exec_command_line_app("dsymutil", + "dsymutil %.*s%.*s", LIT(output_base), LIT(output_ext) + ); - if (exit_code != 0) { - return exit_code; + if (exit_code != 0) { + return exit_code; + } } - } - #endif + #endif - if (build_context.show_timings) { - show_timings(&checker, timings); - } + if (build_context.show_timings) { + show_timings(&checker, timings); + } - remove_temp_files(output_base); + remove_temp_files(output_base); - if (run_output) { - //NOTE(thebirk): This whole thing is a little leaky - String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext); - complete_path = path_to_full_path(heap_allocator(), complete_path); - return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string)); + if (run_output) { + //NOTE(thebirk): This whole thing is a little leaky + String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext); + complete_path = path_to_full_path(heap_allocator(), complete_path); + return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string)); + } + #endif } - #endif } return 0; |