123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633 |
- enum TargetOsKind {
- TargetOs_Invalid,
- TargetOs_windows,
- TargetOs_osx,
- TargetOs_linux,
- TargetOs_essence,
- TargetOs_COUNT,
- };
- enum TargetArchKind {
- TargetArch_Invalid,
- TargetArch_amd64,
- TargetArch_386,
- TargetArch_COUNT,
- };
- enum TargetEndianKind {
- TargetEndian_Invalid,
- TargetEndian_Little,
- TargetEndian_Big,
- TargetEndian_COUNT,
- };
- String target_os_names[TargetOs_COUNT] = {
- str_lit(""),
- str_lit("windows"),
- str_lit("osx"),
- str_lit("linux"),
- str_lit("essence"),
- };
- String target_arch_names[TargetArch_COUNT] = {
- str_lit(""),
- str_lit("amd64"),
- str_lit("386"),
- };
- String target_endian_names[TargetEndian_COUNT] = {
- str_lit(""),
- str_lit("little"),
- str_lit("big"),
- };
- TargetEndianKind target_endians[TargetArch_COUNT] = {
- TargetEndian_Invalid,
- TargetEndian_Little,
- TargetEndian_Little,
- };
- String const ODIN_VERSION = str_lit("0.9.2");
- String cross_compile_target = str_lit("");
- String cross_compile_lib_dir = str_lit("");
- struct TargetMetrics {
- TargetOsKind os;
- TargetArchKind arch;
- isize word_size;
- isize max_align;
- };
- // This stores the information for the specify architecture of this build
- struct BuildContext {
- // Constants
- String ODIN_OS; // target operating system
- String ODIN_ARCH; // target architecture
- String ODIN_ENDIAN; // target endian
- String ODIN_VENDOR; // compiler vendor
- String ODIN_VERSION; // compiler version
- String ODIN_ROOT; // Odin ROOT
- bool ODIN_DEBUG; // Odin in debug mode
- TargetEndianKind endian_kind;
- // In bytes
- i64 word_size; // Size of a pointer, must be >= 4
- i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
- String command;
- TargetMetrics metrics;
- String out_filepath;
- String resource_filepath;
- String pdb_filepath;
- bool has_resource;
- String opt_flags;
- String llc_flags;
- String link_flags;
- bool is_dll;
- bool generate_docs;
- i32 optimization_level;
- bool show_timings;
- bool keep_temp_files;
- bool ignore_unknown_attributes;
- bool no_bounds_check;
- bool no_output_files;
- bool print_query_data;
- bool no_crt;
- bool use_lld;
- bool vet;
- gbAffinity affinity;
- isize thread_count;
- Map<ExactValue> defined_values; // Key:
- };
- gb_global BuildContext build_context = {0};
- gb_global TargetMetrics target_windows_386 = {
- TargetOs_windows,
- TargetArch_386,
- 4,
- 8,
- };
- gb_global TargetMetrics target_windows_amd64 = {
- TargetOs_windows,
- TargetArch_amd64,
- 8,
- 16,
- };
- gb_global TargetMetrics target_linux_386 = {
- TargetOs_linux,
- TargetArch_386,
- 4,
- 8,
- };
- gb_global TargetMetrics target_linux_amd64 = {
- TargetOs_linux,
- TargetArch_amd64,
- 8,
- 16,
- };
- gb_global TargetMetrics target_osx_amd64 = {
- TargetOs_osx,
- TargetArch_amd64,
- 8,
- 16,
- };
- TargetOsKind get_target_os_from_string(String str) {
- for (isize i = 0; i < TargetOs_COUNT; i++) {
- if (str_eq_ignore_case(target_os_names[i], str)) {
- return cast(TargetOsKind)i;
- }
- }
- return TargetOs_Invalid;
- }
- TargetArchKind get_target_arch_from_string(String str) {
- for (isize i = 0; i < TargetArch_COUNT; i++) {
- if (str_eq_ignore_case(target_arch_names[i], str)) {
- return cast(TargetArchKind)i;
- }
- }
- return TargetArch_Invalid;
- }
- bool is_excluded_target_filename(String name) {
- String const ext = str_lit(".odin");
- String original_name = name;
- GB_ASSERT(string_ends_with(name, ext));
- name = substring(name, 0, name.len-ext.len);
- String str1 = {};
- String str2 = {};
- isize n = 0;
- str1 = name;
- n = str1.len;
- for (isize i = str1.len-1; i >= 0 && str1[i] != '_'; i--) {
- n -= 1;
- }
- str1 = substring(str1, n, str1.len);
- str2 = substring(name, 0, gb_max(n-1, 0));
- n = str2.len;
- for (isize i = str2.len-1; i >= 0 && str2[i] != '_'; i--) {
- n -= 1;
- }
- str2 = substring(str2, n, str2.len);
- if (str1 == name) {
- return false;
- }
- TargetOsKind os1 = get_target_os_from_string(str1);
- TargetArchKind arch1 = get_target_arch_from_string(str1);
- TargetOsKind os2 = get_target_os_from_string(str2);
- TargetArchKind arch2 = get_target_arch_from_string(str2);
- if (os1 != TargetOs_Invalid && arch2 != TargetArch_Invalid) {
- return os1 != build_context.metrics.os || arch2 != build_context.metrics.arch;
- } else if (arch1 != TargetArch_Invalid && os2 != TargetOs_Invalid) {
- return arch1 != build_context.metrics.arch || os2 != build_context.metrics.os;
- } else if (os1 != TargetOs_Invalid) {
- return os1 != build_context.metrics.os;
- } else if (arch1 != TargetArch_Invalid) {
- return arch1 != build_context.metrics.arch;
- }
- return false;
- }
- struct LibraryCollections {
- String name;
- String path;
- };
- gb_global Array<LibraryCollections> library_collections = {0};
- void add_library_collection(String name, String path) {
- // TODO(bill): Check the path is valid and a directory
- LibraryCollections lc = {name, string_trim_whitespace(path)};
- array_add(&library_collections, lc);
- }
- bool find_library_collection_path(String name, String *path) {
- for_array(i, library_collections) {
- if (library_collections[i].name == name) {
- if (path) *path = library_collections[i].path;
- return true;
- }
- }
- return false;
- }
- // TODO(bill): OS dependent versions for the BuildContext
- // join_path
- // is_dir
- // is_file
- // is_abs_path
- // has_subdir
- String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
- String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1};
- #if defined(GB_SYSTEM_WINDOWS)
- String odin_root_dir(void) {
- String path = global_module_path;
- isize len, i;
- gbTempArenaMemory tmp;
- wchar_t *text;
- if (global_module_path_set) {
- return global_module_path;
- }
- auto path_buf = array_make<wchar_t>(heap_allocator(), 300);
- len = 0;
- for (;;) {
- len = GetModuleFileNameW(nullptr, &path_buf[0], cast(int)path_buf.count);
- if (len == 0) {
- return make_string(nullptr, 0);
- }
- if (len < path_buf.count) {
- break;
- }
- array_resize(&path_buf, 2*path_buf.count + 300);
- }
- len += 1; // NOTE(bill): It needs an extra 1 for some reason
- gb_mutex_lock(&string_buffer_mutex);
- defer (gb_mutex_unlock(&string_buffer_mutex));
- tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
- defer (gb_temp_arena_memory_end(tmp));
- text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
- GetModuleFileNameW(nullptr, text, cast(int)len);
- path = string16_to_string(heap_allocator(), make_string16(text, len));
- for (i = path.len-1; i >= 0; i--) {
- u8 c = path[i];
- if (c == '/' || c == '\\') {
- break;
- }
- path.len--;
- }
- global_module_path = path;
- global_module_path_set = true;
- array_free(&path_buf);
- return path;
- }
- #elif defined(GB_SYSTEM_OSX)
- #include <mach-o/dyld.h>
- String odin_root_dir(void) {
- String path = global_module_path;
- isize len, i;
- gbTempArenaMemory tmp;
- u8 *text;
- if (global_module_path_set) {
- return global_module_path;
- }
- auto path_buf = array_make<char>(heap_allocator(), 300);
- len = 0;
- for (;;) {
- u32 sz = path_buf.count;
- int res = _NSGetExecutablePath(&path_buf[0], &sz);
- if(res == 0) {
- len = sz;
- break;
- } else {
- array_resize(&path_buf, sz + 1);
- }
- }
- gb_mutex_lock(&string_buffer_mutex);
- defer (gb_mutex_unlock(&string_buffer_mutex));
- tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
- defer (gb_temp_arena_memory_end(tmp));
- text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
- gb_memmove(text, &path_buf[0], len);
- path = make_string(text, len);
- for (i = path.len-1; i >= 0; i--) {
- u8 c = path[i];
- if (c == '/' || c == '\\') {
- break;
- }
- path.len--;
- }
- global_module_path = path;
- global_module_path_set = true;
- // array_free(&path_buf);
- return path;
- }
- #else
- // NOTE: Linux / Unix is unfinished and not tested very well.
- #include <sys/stat.h>
- String odin_root_dir(void) {
- String path = global_module_path;
- isize len, i;
- gbTempArenaMemory tmp;
- u8 *text;
- if (global_module_path_set) {
- return global_module_path;
- }
- auto path_buf = array_make<char>(heap_allocator(), 300);
- defer (array_free(&path_buf));
- len = 0;
- for (;;) {
- // This is not a 100% reliable system, but for the purposes
- // of this compiler, it should be _good enough_.
- // That said, there's no solid 100% method on Linux to get the program's
- // path without checking this link. Sorry.
- len = readlink("/proc/self/exe", &path_buf[0], path_buf.count);
- if(len == 0) {
- return make_string(nullptr, 0);
- }
- if (len < path_buf.count) {
- break;
- }
- array_resize(&path_buf, 2*path_buf.count + 300);
- }
- gb_mutex_lock(&string_buffer_mutex);
- defer (gb_mutex_unlock(&string_buffer_mutex));
- tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
- defer (gb_temp_arena_memory_end(tmp));
- text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
- gb_memmove(text, &path_buf[0], len);
- path = make_string(text, len);
- for (i = path.len-1; i >= 0; i--) {
- u8 c = path[i];
- if (c == '/' || c == '\\') {
- break;
- }
- path.len--;
- }
- global_module_path = path;
- global_module_path_set = true;
- return path;
- }
- #endif
- #if defined(GB_SYSTEM_WINDOWS)
- String path_to_fullpath(gbAllocator a, String s) {
- String result = {};
- gb_mutex_lock(&string_buffer_mutex);
- defer (gb_mutex_unlock(&string_buffer_mutex));
- gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
- defer (gb_temp_arena_memory_end(tmp));
- String16 string16 = string_to_string16(string_buffer_allocator, s);
- DWORD len = GetFullPathNameW(&string16[0], 0, nullptr, nullptr);
- if (len != 0) {
- wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
- GetFullPathNameW(&string16[0], len, text, nullptr);
- text[len] = 0;
- result = string16_to_string(a, make_string16(text, len));
- result = string_trim_whitespace(result);
- // Replace Windows style separators
- for (isize i = 0; i < result.len; i++) {
- if (result[i] == '\\') {
- result[i] = '/';
- }
- }
- }
- return result;
- }
- #elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
- String path_to_fullpath(gbAllocator a, String s) {
- char *p;
- gb_mutex_lock(&string_buffer_mutex);
- p = realpath(cast(char *)s.text, 0);
- gb_mutex_unlock(&string_buffer_mutex);
- if(p == nullptr) return String{};
- return make_string_c(p);
- }
- #else
- #error Implement system
- #endif
- String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
- u8 *str = gb_alloc_array(heap_allocator(), u8, base_dir.len+1+path.len+1);
- defer (gb_free(heap_allocator(), str));
- isize i = 0;
- gb_memmove(str+i, base_dir.text, base_dir.len); i += base_dir.len;
- gb_memmove(str+i, "/", 1); i += 1;
- gb_memmove(str+i, path.text, path.len); i += path.len;
- str[i] = 0;
- String res = make_string(str, i);
- res = string_trim_whitespace(res);
- return path_to_fullpath(a, res);
- }
- String get_fullpath_core(gbAllocator a, String path) {
- String module_dir = odin_root_dir();
- String core = str_lit("core/");
- isize str_len = module_dir.len + core.len + path.len;
- u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
- defer (gb_free(heap_allocator(), str));
- isize i = 0;
- gb_memmove(str+i, module_dir.text, module_dir.len); i += module_dir.len;
- gb_memmove(str+i, core.text, core.len); i += core.len;
- gb_memmove(str+i, path.text, path.len); i += path.len;
- str[i] = 0;
- String res = make_string(str, i);
- res = string_trim_whitespace(res);
- return path_to_fullpath(a, res);
- }
- void init_build_context(void) {
- BuildContext *bc = &build_context;
- gb_affinity_init(&bc->affinity);
- if (bc->thread_count == 0) {
- bc->thread_count = gb_max(bc->affinity.thread_count, 1);
- }
- bc->ODIN_VENDOR = str_lit("odin");
- bc->ODIN_VERSION = ODIN_VERSION;
- bc->ODIN_ROOT = odin_root_dir();
- TargetMetrics metrics = {};
- #if defined(GB_ARCH_64_BIT)
- #if defined(GB_SYSTEM_WINDOWS)
- metrics = target_windows_amd64;
- #elif defined(GB_SYSTEM_OSX)
- metrics = target_osx_amd64;
- #else
- metrics = target_linux_amd64;
- #endif
- #else
- #if defined(GB_SYSTEM_WINDOWS)
- metrics = target_windows_386;
- #elif defined(GB_SYSTEM_OSX)
- #error "Unsupported architecture"
- #else
- metrics = target_linux_386;
- #endif
- #endif
- if (cross_compile_target.len) {
- bc->ODIN_OS = cross_compile_target;
- }
- GB_ASSERT(metrics.os != TargetOs_Invalid);
- GB_ASSERT(metrics.arch != TargetArch_Invalid);
- GB_ASSERT(metrics.word_size > 1);
- GB_ASSERT(metrics.max_align > 1);
- bc->metrics = metrics;
- bc->ODIN_OS = target_os_names[metrics.os];
- bc->ODIN_ARCH = target_arch_names[metrics.arch];
- bc->ODIN_ENDIAN = target_endian_names[target_endians[metrics.arch]];
- bc->endian_kind = target_endians[metrics.arch];
- bc->word_size = metrics.word_size;
- bc->max_align = metrics.max_align;
- bc->link_flags = str_lit(" ");
- bc->opt_flags = str_lit(" ");
- gbString llc_flags = gb_string_make_reserve(heap_allocator(), 64);
- if (bc->ODIN_DEBUG) {
- // llc_flags = gb_string_appendc(llc_flags, "-debug-compile ");
- }
- // NOTE(zangent): The linker flags to set the build architecture are different
- // across OSs. It doesn't make sense to allocate extra data on the heap
- // here, so I just #defined the linker flags to keep things concise.
- if (bc->metrics.arch == TargetArch_amd64) {
- llc_flags = gb_string_appendc(llc_flags, "-march=x86-64 ");
- switch (bc->metrics.os) {
- case TargetOs_windows:
- bc->link_flags = str_lit("/machine:x64 ");
- break;
- case TargetOs_osx:
- break;
- case TargetOs_linux:
- bc->link_flags = str_lit("-arch x86-64 ");
- break;
- }
- } else if (bc->metrics.arch == TargetArch_386) {
- llc_flags = gb_string_appendc(llc_flags, "-march=x86 ");
- switch (bc->metrics.os) {
- case TargetOs_windows:
- bc->link_flags = str_lit("/machine:x86 ");
- break;
- case TargetOs_osx:
- gb_printf_err("Unsupported architecture\n");
- gb_exit(1);
- break;
- case TargetOs_linux:
- bc->link_flags = str_lit("-arch x86 ");
- break;
- }
- } else {
- gb_printf_err("Unsupported architecture\n");;
- gb_exit(1);
- }
- bc->llc_flags = make_string_c(llc_flags);
- bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3);
- gbString opt_flags = gb_string_make_reserve(heap_allocator(), 64);
- if (bc->optimization_level != 0) {
- opt_flags = gb_string_append_fmt(opt_flags, "-O%d ", bc->optimization_level);
- // NOTE(lachsinc): The following options were previously passed during call
- // to opt in main.cpp:exec_llvm_opt().
- // -die: Dead instruction elimination
- // -memcpyopt: MemCpy optimization
- }
- if (bc->ODIN_DEBUG == false) {
- opt_flags = gb_string_appendc(opt_flags, "-memcpyopt -die ");
- }
- // NOTE(lachsinc): This optimization option was previously required to get
- // around an issue in fmt.odin. Thank bp for tracking it down! Leaving for now until the issue
- // is resolved and confirmed by Bill. Maybe it should be readded in non-debug builds.
- // if (bc->ODIN_DEBUG == false) {
- // opt_flags = gb_string_appendc(opt_flags, "-mem2reg ");
- // }
- bc->opt_flags = make_string_c(opt_flags);
- #undef LINK_FLAG_X64
- #undef LINK_FLAG_386
- }
|