123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491 |
- #if defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD)
- #include <sys/types.h>
- #include <sys/sysctl.h>
- #endif
- // #if defined(GB_SYSTEM_WINDOWS)
- // #define DEFAULT_TO_THREADED_CHECKER
- // #endif
- enum TargetOsKind : u16 {
- TargetOs_Invalid,
- TargetOs_windows,
- TargetOs_darwin,
- TargetOs_linux,
- TargetOs_essence,
- TargetOs_freebsd,
- TargetOs_openbsd,
-
- TargetOs_wasi,
- TargetOs_js,
- TargetOs_freestanding,
- TargetOs_COUNT,
- };
- enum TargetArchKind : u16 {
- TargetArch_Invalid,
- TargetArch_amd64,
- TargetArch_i386,
- TargetArch_arm32,
- TargetArch_arm64,
- TargetArch_wasm32,
- TargetArch_wasm64,
- TargetArch_COUNT,
- };
- enum TargetEndianKind : u8 {
- TargetEndian_Invalid,
- TargetEndian_Little,
- TargetEndian_Big,
- TargetEndian_COUNT,
- };
- enum TargetABIKind : u16 {
- TargetABI_Default,
- TargetABI_Win64,
- TargetABI_SysV,
- TargetABI_COUNT,
- };
- String target_os_names[TargetOs_COUNT] = {
- str_lit(""),
- str_lit("windows"),
- str_lit("darwin"),
- str_lit("linux"),
- str_lit("essence"),
- str_lit("freebsd"),
- str_lit("openbsd"),
-
- str_lit("wasi"),
- str_lit("js"),
- str_lit("freestanding"),
- };
- String target_arch_names[TargetArch_COUNT] = {
- str_lit(""),
- str_lit("amd64"),
- str_lit("i386"),
- str_lit("arm32"),
- str_lit("arm64"),
- str_lit("wasm32"),
- str_lit("wasm64"),
- };
- String target_endian_names[TargetEndian_COUNT] = {
- str_lit(""),
- str_lit("little"),
- str_lit("big"),
- };
- String target_abi_names[TargetABI_COUNT] = {
- str_lit(""),
- str_lit("win64"),
- str_lit("sysv"),
- };
- TargetEndianKind target_endians[TargetArch_COUNT] = {
- TargetEndian_Invalid,
- TargetEndian_Little,
- TargetEndian_Little,
- TargetEndian_Little,
- TargetEndian_Little,
- TargetEndian_Little,
- };
- #ifndef ODIN_VERSION_RAW
- #define ODIN_VERSION_RAW "dev-unknown-unknown"
- #endif
- String const ODIN_VERSION = str_lit(ODIN_VERSION_RAW);
- struct TargetMetrics {
- TargetOsKind os;
- TargetArchKind arch;
- isize word_size;
- isize max_align;
- String target_triplet;
- String target_data_layout;
- TargetABIKind abi;
- };
- enum QueryDataSetKind {
- QueryDataSet_Invalid,
- QueryDataSet_GlobalDefinitions,
- QueryDataSet_GoToDefinitions,
- };
- struct QueryDataSetSettings {
- QueryDataSetKind kind;
- bool ok;
- bool compact;
- };
- enum BuildModeKind {
- BuildMode_Executable,
- BuildMode_DynamicLibrary,
- BuildMode_Object,
- BuildMode_Assembly,
- BuildMode_LLVM_IR,
- BuildMode_COUNT,
- };
- enum CommandKind : u32 {
- Command_run = 1<<0,
- Command_build = 1<<1,
- Command_check = 1<<3,
- Command_query = 1<<4,
- Command_doc = 1<<5,
- Command_version = 1<<6,
- Command_test = 1<<7,
-
- Command_strip_semicolon = 1<<8,
- Command_bug_report = 1<<9,
- Command__does_check = Command_run|Command_build|Command_check|Command_query|Command_doc|Command_test|Command_strip_semicolon,
- Command__does_build = Command_run|Command_build|Command_test,
- Command_all = ~(u32)0,
- };
- char const *odin_command_strings[32] = {
- "run",
- "build",
- "check",
- "query",
- "doc",
- "version",
- "test",
- "strip-semicolon",
- };
- enum CmdDocFlag : u32 {
- CmdDocFlag_Short = 1<<0,
- CmdDocFlag_AllPackages = 1<<1,
- CmdDocFlag_DocFormat = 1<<2,
- };
- enum TimingsExportFormat : i32 {
- TimingsExportUnspecified = 0,
- TimingsExportJson = 1,
- TimingsExportCSV = 2,
- };
- enum ErrorPosStyle {
- ErrorPosStyle_Default, // path(line:column) msg
- ErrorPosStyle_Unix, // path:line:column: msg
- ErrorPosStyle_COUNT
- };
- enum RelocMode : u8 {
- RelocMode_Default,
- RelocMode_Static,
- RelocMode_PIC,
- RelocMode_DynamicNoPIC,
- };
- enum BuildPath : u8 {
- BuildPath_Main_Package, // Input Path to the package directory (or file) we're building.
- BuildPath_RC, // Input Path for .rc file, can be set with `-resource:`.
- BuildPath_RES, // Output Path for .res file, generated from previous.
- BuildPath_Win_SDK_Root, // windows_sdk_root
- BuildPath_Win_SDK_UM_Lib, // windows_sdk_um_library_path
- BuildPath_Win_SDK_UCRT_Lib, // windows_sdk_ucrt_library_path
- BuildPath_VS_EXE, // vs_exe_path
- BuildPath_VS_LIB, // vs_library_path
- BuildPath_Output, // Output Path for .exe, .dll, .so, etc. Can be overridden with `-out:`.
- BuildPath_PDB, // Output Path for .pdb file, can be overridden with `-pdb-name:`.
- BuildPathCOUNT,
- };
- // 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_VENDOR; // compiler vendor
- String ODIN_VERSION; // compiler version
- String ODIN_ROOT; // Odin ROOT
- bool ODIN_DEBUG; // Odin in debug mode
- bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not
- bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing)
- bool ODIN_FOREIGN_ERROR_PROCEDURES;
- ErrorPosStyle ODIN_ERROR_POS_STYLE;
- 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)
- CommandKind command_kind;
- String command;
- TargetMetrics metrics;
- bool show_help;
- Array<Path> build_paths; // Contains `Path` objects to output filename, pdb, resource and intermediate files.
- // BuildPath enum contains the indices of paths we know *before* the work starts.
- String out_filepath;
- String resource_filepath;
- String pdb_filepath;
- bool has_resource;
- String link_flags;
- String extra_linker_flags;
- String extra_assembler_flags;
- String microarch;
- BuildModeKind build_mode;
- bool generate_docs;
- i32 optimization_level;
- bool show_timings;
- TimingsExportFormat export_timings_format;
- String export_timings_file;
- bool show_unused;
- bool show_unused_with_location;
- bool show_more_timings;
- bool show_system_calls;
- bool keep_temp_files;
- bool ignore_unknown_attributes;
- bool no_bounds_check;
- bool no_dynamic_literals;
- bool no_output_files;
- bool no_crt;
- bool no_entry_point;
- bool use_lld;
- bool vet;
- bool vet_extra;
- bool cross_compiling;
- bool different_os;
- bool keep_object_files;
- bool disallow_do;
- bool strict_style;
- bool strict_style_init_only;
- bool ignore_warnings;
- bool warnings_as_errors;
- bool show_error_line;
- bool ignore_lazy;
- bool use_subsystem_windows;
- bool ignore_microsoft_magic;
- bool linker_map_file;
- bool use_separate_modules;
- bool threaded_checker;
- bool show_debug_messages;
-
- bool copy_file_contents;
- bool disallow_rtti;
- RelocMode reloc_mode;
- bool disable_red_zone;
- u32 cmd_doc_flags;
- Array<String> extra_packages;
- QueryDataSetSettings query_data_set_settings;
- StringSet test_names;
- gbAffinity affinity;
- isize thread_count;
- PtrMap<char const *, ExactValue> defined_values;
- BlockingMutex target_features_mutex;
- StringSet target_features_set;
- String target_features_string;
- };
- gb_global BuildContext build_context = {0};
- bool global_warnings_as_errors(void) {
- return build_context.warnings_as_errors;
- }
- bool global_ignore_warnings(void) {
- return build_context.ignore_warnings;
- }
- gb_global TargetMetrics target_windows_i386 = {
- TargetOs_windows,
- TargetArch_i386,
- 4,
- 8,
- str_lit("i386-pc-windows-msvc"),
- };
- gb_global TargetMetrics target_windows_amd64 = {
- TargetOs_windows,
- TargetArch_amd64,
- 8,
- 16,
- str_lit("x86_64-pc-windows-msvc"),
- str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
- };
- gb_global TargetMetrics target_linux_i386 = {
- TargetOs_linux,
- TargetArch_i386,
- 4,
- 8,
- str_lit("i386-pc-linux-gnu"),
- };
- gb_global TargetMetrics target_linux_amd64 = {
- TargetOs_linux,
- TargetArch_amd64,
- 8,
- 16,
- str_lit("x86_64-pc-linux-gnu"),
- str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
- };
- gb_global TargetMetrics target_linux_arm64 = {
- TargetOs_linux,
- TargetArch_arm64,
- 8,
- 16,
- str_lit("aarch64-linux-elf"),
- str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"),
- };
- gb_global TargetMetrics target_linux_arm32 = {
- TargetOs_linux,
- TargetArch_arm32,
- 4,
- 8,
- str_lit("arm-linux-gnu"),
- str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"),
- };
- gb_global TargetMetrics target_darwin_amd64 = {
- TargetOs_darwin,
- TargetArch_amd64,
- 8,
- 16,
- str_lit("x86_64-apple-darwin"),
- str_lit("e-m:o-i64:64-f80:128-n8:16:32:64-S128"),
- };
- gb_global TargetMetrics target_darwin_arm64 = {
- TargetOs_darwin,
- TargetArch_arm64,
- 8,
- 16,
- str_lit("arm64-apple-macosx11.0.0"),
- str_lit("e-m:o-i64:64-i128:128-n32:64-S128"), // TODO(bill): Is this correct?
- };
- gb_global TargetMetrics target_freebsd_i386 = {
- TargetOs_freebsd,
- TargetArch_i386,
- 4,
- 8,
- str_lit("i386-unknown-freebsd-elf"),
- };
- gb_global TargetMetrics target_freebsd_amd64 = {
- TargetOs_freebsd,
- TargetArch_amd64,
- 8,
- 16,
- str_lit("x86_64-unknown-freebsd-elf"),
- str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
- };
- gb_global TargetMetrics target_openbsd_amd64 = {
- TargetOs_openbsd,
- TargetArch_amd64,
- 8,
- 16,
- str_lit("x86_64-unknown-openbsd-elf"),
- str_lit("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"),
- };
- gb_global TargetMetrics target_essence_amd64 = {
- TargetOs_essence,
- TargetArch_amd64,
- 8,
- 16,
- str_lit("x86_64-pc-none-elf"),
- };
- gb_global TargetMetrics target_freestanding_wasm32 = {
- TargetOs_freestanding,
- TargetArch_wasm32,
- 4,
- 8,
- str_lit("wasm32-freestanding-js"),
- str_lit(""),
- };
- gb_global TargetMetrics target_js_wasm32 = {
- TargetOs_js,
- TargetArch_wasm32,
- 4,
- 8,
- str_lit("wasm32-js-js"),
- str_lit(""),
- };
- gb_global TargetMetrics target_js_wasm64 = {
- TargetOs_js,
- TargetArch_wasm64,
- 8,
- 16,
- str_lit("wasm64-js-js"),
- str_lit(""),
- };
- gb_global TargetMetrics target_wasi_wasm32 = {
- TargetOs_wasi,
- TargetArch_wasm32,
- 4,
- 8,
- str_lit("wasm32-wasi-js"),
- str_lit(""),
- };
- // gb_global TargetMetrics target_freestanding_wasm64 = {
- // TargetOs_freestanding,
- // TargetArch_wasm64,
- // 8,
- // 16,
- // str_lit("wasm64-freestanding-js"),
- // str_lit(""),
- // };
- gb_global TargetMetrics target_freestanding_amd64_sysv = {
- TargetOs_freestanding,
- TargetArch_amd64,
- 8,
- 16,
- str_lit("x86_64-pc-none-gnu"),
- str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
- TargetABI_SysV,
- };
- struct NamedTargetMetrics {
- String name;
- TargetMetrics *metrics;
- };
- gb_global NamedTargetMetrics named_targets[] = {
- { str_lit("darwin_amd64"), &target_darwin_amd64 },
- { str_lit("darwin_arm64"), &target_darwin_arm64 },
- { str_lit("essence_amd64"), &target_essence_amd64 },
- { str_lit("linux_i386"), &target_linux_i386 },
- { str_lit("linux_amd64"), &target_linux_amd64 },
- { str_lit("linux_arm64"), &target_linux_arm64 },
- { str_lit("linux_arm32"), &target_linux_arm32 },
- { str_lit("windows_i386"), &target_windows_i386 },
- { str_lit("windows_amd64"), &target_windows_amd64 },
- { str_lit("freebsd_i386"), &target_freebsd_i386 },
- { str_lit("freebsd_amd64"), &target_freebsd_amd64 },
- { str_lit("openbsd_amd64"), &target_openbsd_amd64 },
- { str_lit("freestanding_wasm32"), &target_freestanding_wasm32 },
- { str_lit("wasi_wasm32"), &target_wasi_wasm32 },
- { str_lit("js_wasm32"), &target_js_wasm32 },
- { str_lit("js_wasm64"), &target_js_wasm64 },
- { str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
- };
- NamedTargetMetrics *selected_target_metrics;
- 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 original_name = name;
- name = remove_extension_from_path(name);
- if (string_starts_with(name, str_lit("."))) {
- // Ignore .*.odin files
- return true;
- }
- if (build_context.command_kind != Command_test) {
- String test_suffix = str_lit("_test");
- if (string_ends_with(name, test_suffix) && name != test_suffix) {
- // Ignore *_test.odin files
- return true;
- }
- }
- 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;
- }
- bool is_arch_wasm(void) {
- switch (build_context.metrics.arch) {
- case TargetArch_wasm32:
- case TargetArch_wasm64:
- return true;
- }
- return false;
- }
- bool is_arch_x86(void) {
- switch (build_context.metrics.arch) {
- case TargetArch_i386:
- case TargetArch_amd64:
- return true;
- }
- return false;
- }
- bool allow_check_foreign_filepath(void) {
- switch (build_context.metrics.arch) {
- case TargetArch_wasm32:
- case TargetArch_wasm64:
- return false;
- }
- return true;
- }
- // 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};
- String const WASM_MODULE_NAME_SEPARATOR = str_lit("..");
- String internal_odin_root_dir(void);
- String odin_root_dir(void) {
- if (global_module_path_set) {
- return global_module_path;
- }
- gbAllocator a = permanent_allocator();
- char const *found = gb_get_env("ODIN_ROOT", a);
- if (found) {
- String path = path_to_full_path(a, make_string_c(found));
- if (path[path.len-1] != '/' && path[path.len-1] != '\\') {
- #if defined(GB_SYSTEM_WINDOWS)
- path = concatenate_strings(a, path, WIN32_SEPARATOR_STRING);
- #else
- path = concatenate_strings(a, path, NIX_SEPARATOR_STRING);
- #endif
- }
- global_module_path = path;
- global_module_path_set = true;
- return global_module_path;
- }
- return internal_odin_root_dir();
- }
- #if defined(GB_SYSTEM_WINDOWS)
- String internal_odin_root_dir(void) {
- String path = global_module_path;
- isize len, i;
- 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
- mutex_lock(&string_buffer_mutex);
- defer (mutex_unlock(&string_buffer_mutex));
- text = gb_alloc_array(permanent_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 path_to_fullpath(gbAllocator a, String s);
- String internal_odin_root_dir(void) {
- String path = global_module_path;
- isize len, i;
- 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);
- }
- }
- mutex_lock(&string_buffer_mutex);
- defer (mutex_unlock(&string_buffer_mutex));
- text = gb_alloc_array(permanent_allocator(), u8, len + 1);
- gb_memmove(text, &path_buf[0], len);
- path = path_to_fullpath(heap_allocator(), 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 path_to_fullpath(gbAllocator a, String s);
- String internal_odin_root_dir(void) {
- String path = global_module_path;
- isize len, i;
- 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.
- #if defined(GB_SYSTEM_FREEBSD)
- int mib[4];
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC;
- mib[2] = KERN_PROC_PATHNAME;
- mib[3] = -1;
- len = path_buf.count;
- sysctl(mib, 4, &path_buf[0], (size_t *) &len, NULL, 0);
- #elif defined(GB_SYSTEM_NETBSD)
- len = readlink("/proc/curproc/exe", &path_buf[0], path_buf.count);
- #elif defined(GB_SYSTEM_DRAGONFLYBSD)
- len = readlink("/proc/curproc/file", &path_buf[0], path_buf.count);
- #elif defined(GB_SYSTEM_LINUX)
- len = readlink("/proc/self/exe", &path_buf[0], path_buf.count);
- #elif defined(GB_SYSTEM_OPENBSD)
- int error;
- int mib[] = {
- CTL_KERN,
- KERN_PROC_ARGS,
- getpid(),
- KERN_PROC_ARGV,
- };
- // get argv size
- error = sysctl(mib, 4, NULL, (size_t *) &len, NULL, 0);
- if (error == -1) {
- // sysctl error
- return make_string(nullptr, 0);
- }
- // get argv
- char **argv = (char **)gb_malloc(len);
- error = sysctl(mib, 4, argv, (size_t *) &len, NULL, 0);
- if (error == -1) {
- // sysctl error
- gb_mfree(argv);
- return make_string(nullptr, 0);
- }
- // copy argv[0] to path_buf
- len = gb_strlen(argv[0]);
- if(len < path_buf.count) {
- gb_memmove(&path_buf[0], argv[0], len);
- }
- gb_mfree(argv);
- #endif
- if(len == 0 || len == -1) {
- return make_string(nullptr, 0);
- }
- if (len < path_buf.count) {
- break;
- }
- array_resize(&path_buf, 2*path_buf.count + 300);
- }
- mutex_lock(&string_buffer_mutex);
- defer (mutex_unlock(&string_buffer_mutex));
- text = gb_alloc_array(permanent_allocator(), u8, len + 1);
- gb_memmove(text, &path_buf[0], len);
- path = path_to_fullpath(heap_allocator(), 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
- gb_global BlockingMutex fullpath_mutex;
- #if defined(GB_SYSTEM_WINDOWS)
- String path_to_fullpath(gbAllocator a, String s) {
- String result = {};
- mutex_lock(&fullpath_mutex);
- defer (mutex_unlock(&fullpath_mutex));
- String16 string16 = string_to_string16(heap_allocator(), s);
- defer (gb_free(heap_allocator(), string16.text));
- DWORD len = GetFullPathNameW(&string16[0], 0, nullptr, nullptr);
- if (len != 0) {
- wchar_t *text = gb_alloc_array(permanent_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.text[i] == '\\') {
- result.text[i] = '/';
- }
- }
- }
- return result;
- }
- #elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
- String path_to_fullpath(gbAllocator a, String s) {
- char *p;
- mutex_lock(&fullpath_mutex);
- p = realpath(cast(char *)s.text, 0);
- mutex_unlock(&fullpath_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);
- }
- bool show_error_line(void) {
- return build_context.show_error_line;
- }
- bool has_asm_extension(String const &path) {
- String ext = path_extension(path);
- if (ext == ".asm") {
- return true;
- } else if (ext == ".s") {
- return true;
- } else if (ext == ".S") {
- return true;
- }
- return false;
- }
- // temporary
- char *token_pos_to_string(TokenPos const &pos) {
- gbString s = gb_string_make_reserve(temporary_allocator(), 128);
- String file = get_file_path_string(pos.file_id);
- switch (build_context.ODIN_ERROR_POS_STYLE) {
- default: /*fallthrough*/
- case ErrorPosStyle_Default:
- s = gb_string_append_fmt(s, "%.*s(%d:%d)", LIT(file), pos.line, pos.column);
- break;
- case ErrorPosStyle_Unix:
- s = gb_string_append_fmt(s, "%.*s:%d:%d:", LIT(file), pos.line, pos.column);
- break;
- }
- return s;
- }
- void init_build_context(TargetMetrics *cross_target) {
- 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();
- {
- char const *found = gb_get_env("ODIN_ERROR_POS_STYLE", permanent_allocator());
- if (found) {
- ErrorPosStyle kind = ErrorPosStyle_Default;
- String style = make_string_c(found);
- style = string_trim_whitespace(style);
- if (style == "" || style == "default" || style == "odin") {
- kind = ErrorPosStyle_Default;
- } else if (style == "unix" || style == "gcc" || style == "clang" || style == "llvm") {
- kind = ErrorPosStyle_Unix;
- } else {
- gb_printf_err("Invalid ODIN_ERROR_POS_STYLE: got %.*s\n", LIT(style));
- gb_printf_err("Valid formats:\n");
- gb_printf_err("\t\"default\" or \"odin\"\n");
- gb_printf_err("\t\tpath(line:column) message\n");
- gb_printf_err("\t\"unix\"\n");
- gb_printf_err("\t\tpath:line:column: message\n");
- gb_exit(1);
- }
- build_context.ODIN_ERROR_POS_STYLE = kind;
- }
- }
- bc->copy_file_contents = true;
- TargetMetrics *metrics = nullptr;
- #if defined(GB_ARCH_64_BIT)
- #if defined(GB_SYSTEM_WINDOWS)
- metrics = &target_windows_amd64;
- #elif defined(GB_SYSTEM_OSX)
- #if defined(GB_CPU_ARM)
- metrics = &target_darwin_arm64;
- #else
- metrics = &target_darwin_amd64;
- #endif
- #elif defined(GB_SYSTEM_FREEBSD)
- metrics = &target_freebsd_amd64;
- #elif defined(GB_SYSTEM_OPENBSD)
- metrics = &target_openbsd_amd64;
- #elif defined(GB_CPU_ARM)
- metrics = &target_linux_arm64;
- #else
- metrics = &target_linux_amd64;
- #endif
- #else
- #if defined(GB_SYSTEM_WINDOWS)
- metrics = &target_windows_i386;
- #elif defined(GB_SYSTEM_OSX)
- #error "Build Error: Unsupported architecture"
- #elif defined(GB_SYSTEM_FREEBSD)
- metrics = &target_freebsd_i386;
- #else
- metrics = &target_linux_i386;
- #endif
- #endif
- if (cross_target != nullptr && metrics != cross_target) {
- bc->different_os = cross_target->os != metrics->os;
- bc->cross_compiling = true;
- metrics = cross_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->endian_kind = target_endians[metrics->arch];
- bc->word_size = metrics->word_size;
- bc->max_align = metrics->max_align;
- bc->link_flags = str_lit(" ");
- #if defined(DEFAULT_TO_THREADED_CHECKER)
- bc->threaded_checker = true;
- #endif
- if (bc->disable_red_zone) {
- if (is_arch_wasm() && bc->metrics.os == TargetOs_freestanding) {
- gb_printf_err("-disable-red-zone is not support for this target");
- gb_exit(1);
- }
- }
- if (bc->metrics.os == TargetOs_freestanding) {
- bc->no_entry_point = true;
- } else {
- if (bc->disallow_rtti) {
- gb_printf_err("-disallow-rtti is only allowed on freestanding targets\n");
- gb_exit(1);
- }
- }
- // 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) {
- switch (bc->metrics.os) {
- case TargetOs_windows:
- bc->link_flags = str_lit("/machine:x64 ");
- break;
- case TargetOs_darwin:
- break;
- case TargetOs_linux:
- bc->link_flags = str_lit("-arch x86-64 ");
- break;
- case TargetOs_freebsd:
- bc->link_flags = str_lit("-arch x86-64 ");
- break;
- case TargetOs_openbsd:
- bc->link_flags = str_lit("-arch x86-64 ");
- break;
- }
- } else if (bc->metrics.arch == TargetArch_i386) {
- switch (bc->metrics.os) {
- case TargetOs_windows:
- bc->link_flags = str_lit("/machine:x86 ");
- break;
- case TargetOs_darwin:
- gb_printf_err("Unsupported architecture\n");
- gb_exit(1);
- break;
- case TargetOs_linux:
- bc->link_flags = str_lit("-arch x86 ");
- break;
- case TargetOs_freebsd:
- bc->link_flags = str_lit("-arch x86 ");
- break;
- }
- } else if (bc->metrics.arch == TargetArch_arm32) {
- switch (bc->metrics.os) {
- case TargetOs_linux:
- bc->link_flags = str_lit("-arch arm ");
- break;
- default:
- gb_printf_err("Compiler Error: Unsupported architecture\n");
- gb_exit(1);
- }
- } else if (bc->metrics.arch == TargetArch_arm64) {
- switch (bc->metrics.os) {
- case TargetOs_darwin:
- bc->link_flags = str_lit("-arch arm64 ");
- break;
- case TargetOs_linux:
- bc->link_flags = str_lit("-arch aarch64 ");
- break;
- }
- } else if (is_arch_wasm()) {
- gbString link_flags = gb_string_make(heap_allocator(), " ");
- // link_flags = gb_string_appendc(link_flags, "--export-all ");
- // link_flags = gb_string_appendc(link_flags, "--export-table ");
- link_flags = gb_string_appendc(link_flags, "--allow-undefined ");
- if (bc->metrics.arch == TargetArch_wasm64) {
- link_flags = gb_string_appendc(link_flags, "-mwasm64 ");
- }
- if (bc->no_entry_point) {
- link_flags = gb_string_appendc(link_flags, "--no-entry ");
- }
-
- bc->link_flags = make_string_c(link_flags);
-
- // Disallow on wasm
- bc->use_separate_modules = false;
- } else {
- gb_printf_err("Compiler Error: Unsupported architecture\n");
- gb_exit(1);
- }
- bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3);
- #undef LINK_FLAG_X64
- #undef LINK_FLAG_386
- }
- #if defined(GB_SYSTEM_WINDOWS)
- // NOTE(IC): In order to find Visual C++ paths without relying on environment variables.
- // NOTE(Jeroen): No longer needed in `main.cpp -> linker_stage`. We now resolve those paths in `init_build_paths`.
- #include "microsoft_craziness.h"
- #endif
- Array<String> split_by_comma(String const &list) {
- isize n = 1;
- for (isize i = 0; i < list.len; i++) {
- if (list.text[i] == ',') {
- n++;
- }
- }
- auto res = array_make<String>(heap_allocator(), n);
- String s = list;
- for (isize i = 0; i < n; i++) {
- isize m = string_index_byte(s, ',');
- if (m < 0) {
- res[i] = s;
- break;
- }
- res[i] = substring(s, 0, m);
- s = substring(s, m+1, s.len);
- }
- return res;
- }
- bool check_target_feature_is_valid(TokenPos pos, String const &feature) {
- // TODO(bill): check_target_feature_is_valid
- return true;
- }
- bool check_target_feature_is_enabled(TokenPos pos, String const &target_feature_list) {
- BuildContext *bc = &build_context;
- mutex_lock(&bc->target_features_mutex);
- defer (mutex_unlock(&bc->target_features_mutex));
- auto items = split_by_comma(target_feature_list);
- array_free(&items);
- for_array(i, items) {
- String const &item = items.data[i];
- if (!check_target_feature_is_valid(pos, item)) {
- error(pos, "Target feature '%.*s' is not valid", LIT(item));
- return false;
- }
- if (!string_set_exists(&bc->target_features_set, item)) {
- error(pos, "Target feature '%.*s' is not enabled", LIT(item));
- return false;
- }
- }
- return true;
- }
- void enable_target_feature(TokenPos pos, String const &target_feature_list) {
- BuildContext *bc = &build_context;
- mutex_lock(&bc->target_features_mutex);
- defer (mutex_unlock(&bc->target_features_mutex));
- auto items = split_by_comma(target_feature_list);
- array_free(&items);
- for_array(i, items) {
- String const &item = items.data[i];
- if (!check_target_feature_is_valid(pos, item)) {
- error(pos, "Target feature '%.*s' is not valid", LIT(item));
- }
- }
- }
- char const *target_features_set_to_cstring(gbAllocator allocator, bool with_quotes) {
- isize len = 0;
- for_array(i, build_context.target_features_set.entries) {
- if (i != 0) {
- len += 1;
- }
- String feature = build_context.target_features_set.entries[i].value;
- len += feature.len;
- if (with_quotes) len += 2;
- }
- char *features = gb_alloc_array(allocator, char, len+1);
- len = 0;
- for_array(i, build_context.target_features_set.entries) {
- if (i != 0) {
- features[len++] = ',';
- }
- if (with_quotes) features[len++] = '"';
- String feature = build_context.target_features_set.entries[i].value;
- gb_memmove(features, feature.text, feature.len);
- len += feature.len;
- if (with_quotes) features[len++] = '"';
- }
- features[len++] = 0;
- return features;
- }
- // NOTE(Jeroen): Set/create the output and other paths and report an error as appropriate.
- // We've previously called `parse_build_flags`, so `out_filepath` should be set.
- bool init_build_paths(String init_filename) {
- gbAllocator ha = heap_allocator();
- BuildContext *bc = &build_context;
- // NOTE(Jeroen): We're pre-allocating BuildPathCOUNT slots so that certain paths are always at the same enumerated index.
- array_init(&bc->build_paths, permanent_allocator(), BuildPathCOUNT);
- string_set_init(&bc->target_features_set, heap_allocator(), 1024);
- mutex_init(&bc->target_features_mutex);
- // [BuildPathMainPackage] Turn given init path into a `Path`, which includes normalizing it into a full path.
- bc->build_paths[BuildPath_Main_Package] = path_from_string(ha, init_filename);
- bool produces_output_file = false;
- if (bc->command_kind == Command_doc && bc->cmd_doc_flags & CmdDocFlag_DocFormat) {
- produces_output_file = true;
- } else if (bc->command_kind & Command__does_build) {
- produces_output_file = true;
- }
- if (!produces_output_file) {
- // Command doesn't produce output files. We're done.
- return true;
- }
- #if defined(GB_SYSTEM_WINDOWS)
- if (bc->resource_filepath.len > 0) {
- bc->build_paths[BuildPath_RC] = path_from_string(ha, bc->resource_filepath);
- bc->build_paths[BuildPath_RES] = path_from_string(ha, bc->resource_filepath);
- bc->build_paths[BuildPath_RC].ext = copy_string(ha, STR_LIT("rc"));
- bc->build_paths[BuildPath_RES].ext = copy_string(ha, STR_LIT("res"));
- }
- if (bc->pdb_filepath.len > 0) {
- bc->build_paths[BuildPath_PDB] = path_from_string(ha, bc->pdb_filepath);
- }
- if ((bc->command_kind & Command__does_build) && (!bc->ignore_microsoft_magic)) {
- // 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 false;
- }
- if (find_result.windows_sdk_um_library_path.len > 0) {
- GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0);
- if (find_result.windows_sdk_root.len > 0) {
- bc->build_paths[BuildPath_Win_SDK_Root] = path_from_string(ha, find_result.windows_sdk_root);
- }
- if (find_result.windows_sdk_um_library_path.len > 0) {
- bc->build_paths[BuildPath_Win_SDK_UM_Lib] = path_from_string(ha, find_result.windows_sdk_um_library_path);
- }
- if (find_result.windows_sdk_ucrt_library_path.len > 0) {
- bc->build_paths[BuildPath_Win_SDK_UCRT_Lib] = path_from_string(ha, find_result.windows_sdk_ucrt_library_path);
- }
- if (find_result.vs_exe_path.len > 0) {
- bc->build_paths[BuildPath_VS_EXE] = path_from_string(ha, find_result.vs_exe_path);
- }
- if (find_result.vs_library_path.len > 0) {
- bc->build_paths[BuildPath_VS_LIB] = path_from_string(ha, find_result.vs_library_path);
- }
- }
- gb_free(ha, find_result.windows_sdk_root.text);
- gb_free(ha, find_result.windows_sdk_um_library_path.text);
- gb_free(ha, find_result.windows_sdk_ucrt_library_path.text);
- gb_free(ha, find_result.vs_exe_path.text);
- gb_free(ha, find_result.vs_library_path.text);
- }
- #endif
- // All the build targets and OSes.
- String output_extension;
- if (bc->command_kind == Command_doc && bc->cmd_doc_flags & CmdDocFlag_DocFormat) {
- output_extension = STR_LIT("odin-doc");
- } else if (is_arch_wasm()) {
- output_extension = STR_LIT("wasm");
- } else if (build_context.build_mode == BuildMode_Executable) {
- // By default use a .bin executable extension.
- output_extension = STR_LIT("bin");
- if (build_context.metrics.os == TargetOs_windows) {
- output_extension = STR_LIT("exe");
- } else if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) {
- output_extension = make_string(nullptr, 0);
- }
- } else if (build_context.build_mode == BuildMode_DynamicLibrary) {
- // By default use a .so shared library extension.
- output_extension = STR_LIT("so");
- if (build_context.metrics.os == TargetOs_windows) {
- output_extension = STR_LIT("dll");
- } else if (build_context.metrics.os == TargetOs_darwin) {
- output_extension = STR_LIT("dylib");
- }
- } else if (build_context.build_mode == BuildMode_Object) {
- // By default use a .o object extension.
- output_extension = STR_LIT("o");
- if (build_context.metrics.os == TargetOs_windows) {
- output_extension = STR_LIT("obj");
- }
- } else if (build_context.build_mode == BuildMode_Assembly) {
- // By default use a .S asm extension.
- output_extension = STR_LIT("S");
- } else if (build_context.build_mode == BuildMode_LLVM_IR) {
- output_extension = STR_LIT("ll");
- } else {
- GB_PANIC("Unhandled build mode/target combination.\n");
- }
- if (bc->out_filepath.len > 0) {
- bc->build_paths[BuildPath_Output] = path_from_string(ha, bc->out_filepath);
- if (build_context.metrics.os == TargetOs_windows) {
- String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]);
- defer (gb_free(ha, output_file.text));
- if (path_is_directory(bc->build_paths[BuildPath_Output])) {
- gb_printf_err("Output path %.*s is a directory.\n", LIT(output_file));
- return false;
- } else if (bc->build_paths[BuildPath_Output].ext.len == 0) {
- gb_printf_err("Output path %.*s must have an appropriate extension.\n", LIT(output_file));
- return false;
- }
- }
- } else {
- Path output_path;
- if (str_eq(init_filename, str_lit("."))) {
- // We must name the output file after the current directory.
- debugf("Output name will be created from current base name %.*s.\n", LIT(bc->build_paths[BuildPath_Main_Package].basename));
- String last_element = last_path_element(bc->build_paths[BuildPath_Main_Package].basename);
- if (last_element.len == 0) {
- gb_printf_err("The output name is created from the last path element. `%.*s` has none. Use `-out:output_name.ext` to set it.\n", LIT(bc->build_paths[BuildPath_Main_Package].basename));
- return false;
- }
- output_path.basename = copy_string(ha, bc->build_paths[BuildPath_Main_Package].basename);
- output_path.name = copy_string(ha, last_element);
- } else {
- // Init filename was not 'current path'.
- // Contruct the output name from the path elements as usual.
- String output_name = init_filename;
- // If it ends with a trailing (back)slash, strip it before continuing.
- while (output_name.len > 0 && (output_name[output_name.len-1] == '/' || output_name[output_name.len-1] == '\\')) {
- output_name.len -= 1;
- }
- output_name = remove_directory_from_path(output_name);
- output_name = remove_extension_from_path(output_name);
- output_name = copy_string(ha, string_trim_whitespace(output_name));
- output_path = path_from_string(ha, output_name);
- // Replace extension.
- if (output_path.ext.len > 0) {
- gb_free(ha, output_path.ext.text);
- }
- }
- output_path.ext = copy_string(ha, output_extension);
- bc->build_paths[BuildPath_Output] = output_path;
- }
- // Do we have an extension? We might not if the output filename was supplied.
- if (bc->build_paths[BuildPath_Output].ext.len == 0) {
- if (build_context.metrics.os == TargetOs_windows || build_context.build_mode != BuildMode_Executable) {
- bc->build_paths[BuildPath_Output].ext = copy_string(ha, output_extension);
- }
- }
- // Check if output path is a directory.
- if (path_is_directory(bc->build_paths[BuildPath_Output])) {
- String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]);
- defer (gb_free(ha, output_file.text));
- gb_printf_err("Output path %.*s is a directory.\n", LIT(output_file));
- return false;
- }
- if (bc->target_features_string.len != 0) {
- enable_target_feature({}, bc->target_features_string);
- }
- return true;
- }
|