main.cpp 101 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901
  1. // #define NO_ARRAY_BOUNDS_CHECK
  2. #include "common.cpp"
  3. #include "timings.cpp"
  4. #include "tokenizer.cpp"
  5. #if defined(GB_SYSTEM_WINDOWS)
  6. #pragma warning(push)
  7. #pragma warning(disable: 4505)
  8. #endif
  9. #include "big_int.cpp"
  10. #if defined(GB_SYSTEM_WINDOWS)
  11. #pragma warning(pop)
  12. #endif
  13. #include "exact_value.cpp"
  14. #include "build_settings.cpp"
  15. gb_global ThreadPool global_thread_pool;
  16. gb_internal void init_global_thread_pool(void) {
  17. isize thread_count = gb_max(build_context.thread_count, 1);
  18. isize worker_count = thread_count; // +1
  19. thread_pool_init(&global_thread_pool, worker_count, "ThreadPoolWorker");
  20. }
  21. gb_internal bool thread_pool_add_task(WorkerTaskProc *proc, void *data) {
  22. return thread_pool_add_task(&global_thread_pool, proc, data);
  23. }
  24. gb_internal void thread_pool_wait(void) {
  25. thread_pool_wait(&global_thread_pool);
  26. }
  27. gb_internal i64 PRINT_PEAK_USAGE(void) {
  28. if (build_context.show_more_timings) {
  29. #if defined(GB_SYSTEM_WINDOWS)
  30. PROCESS_MEMORY_COUNTERS p = {sizeof(p)};
  31. if (GetProcessMemoryInfo(GetCurrentProcess(), &p, sizeof(p))) {
  32. gb_printf("\n");
  33. gb_printf("Peak Memory Size: %.3f MiB\n", (cast(f64)p.PeakWorkingSetSize) / cast(f64)(1024ull * 1024ull));
  34. return cast(i64)p.PeakWorkingSetSize;
  35. }
  36. #endif
  37. }
  38. return 0;
  39. }
  40. gb_global BlockingMutex debugf_mutex;
  41. gb_internal void debugf(char const *fmt, ...) {
  42. if (build_context.show_debug_messages) {
  43. mutex_lock(&debugf_mutex);
  44. gb_printf_err("[DEBUG] ");
  45. va_list va;
  46. va_start(va, fmt);
  47. (void)gb_printf_err_va(fmt, va);
  48. va_end(va);
  49. mutex_unlock(&debugf_mutex);
  50. }
  51. }
  52. gb_global Timings global_timings = {0};
  53. #if defined(GB_SYSTEM_WINDOWS)
  54. #include "llvm-c/Types.h"
  55. #else
  56. #include <llvm-c/Types.h>
  57. #endif
  58. #include "parser.hpp"
  59. #include "checker.hpp"
  60. #include "parser.cpp"
  61. #include "checker.cpp"
  62. #include "docs.cpp"
  63. #include "llvm_backend.cpp"
  64. #if defined(GB_SYSTEM_OSX)
  65. #include <llvm/Config/llvm-config.h>
  66. #if LLVM_VERSION_MAJOR < 11
  67. #error LLVM Version 11+ is required => "brew install llvm@11"
  68. #endif
  69. #if LLVM_VERSION_MAJOR > 14
  70. #error LLVM Version 11..=14 is required => "brew install llvm@14"
  71. #endif
  72. #endif
  73. #include "bug_report.cpp"
  74. // NOTE(bill): 'name' is used in debugging and profiling modes
  75. gb_internal i32 system_exec_command_line_app(char const *name, char const *fmt, ...) {
  76. isize const cmd_cap = 64<<20; // 64 MiB should be more than enough
  77. char *cmd_line = gb_alloc_array(gb_heap_allocator(), char, cmd_cap);
  78. isize cmd_len = 0;
  79. va_list va;
  80. i32 exit_code = 0;
  81. va_start(va, fmt);
  82. cmd_len = gb_snprintf_va(cmd_line, cmd_cap-1, fmt, va);
  83. va_end(va);
  84. #if defined(GB_SYSTEM_WINDOWS)
  85. STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
  86. PROCESS_INFORMATION pi = {0};
  87. String16 wcmd = {};
  88. start_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
  89. start_info.wShowWindow = SW_SHOW;
  90. start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
  91. start_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  92. start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
  93. if (build_context.show_system_calls) {
  94. gb_printf_err("[SYSTEM CALL] %s\n", name);
  95. gb_printf_err("%.*s\n\n", cast(int)(cmd_len-1), cmd_line);
  96. }
  97. wcmd = string_to_string16(permanent_allocator(), make_string(cast(u8 *)cmd_line, cmd_len-1));
  98. if (CreateProcessW(nullptr, wcmd.text,
  99. nullptr, nullptr, true, 0, nullptr, nullptr,
  100. &start_info, &pi)) {
  101. WaitForSingleObject(pi.hProcess, INFINITE);
  102. GetExitCodeProcess(pi.hProcess, cast(DWORD *)&exit_code);
  103. CloseHandle(pi.hProcess);
  104. CloseHandle(pi.hThread);
  105. } else {
  106. // NOTE(bill): failed to create process
  107. gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);
  108. exit_code = -1;
  109. }
  110. #elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
  111. if (build_context.show_system_calls) {
  112. gb_printf_err("[SYSTEM CALL] %s\n", name);
  113. gb_printf_err("%s\n\n", cmd_line);
  114. }
  115. exit_code = system(cmd_line);
  116. if (WIFEXITED(exit_code)) {
  117. exit_code = WEXITSTATUS(exit_code);
  118. }
  119. #endif
  120. if (exit_code) {
  121. exit(exit_code);
  122. }
  123. return exit_code;
  124. }
  125. gb_internal i32 linker_stage(lbGenerator *gen) {
  126. i32 result = 0;
  127. Timings *timings = &global_timings;
  128. String output_filename = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]);
  129. debugf("Linking %.*s\n", LIT(output_filename));
  130. // TOOD(Jeroen): Make a `build_paths[BuildPath_Object] to avoid `%.*s.o`.
  131. if (is_arch_wasm()) {
  132. timings_start_section(timings, str_lit("wasm-ld"));
  133. #if defined(GB_SYSTEM_WINDOWS)
  134. result = system_exec_command_line_app("wasm-ld",
  135. "\"%.*s\\bin\\wasm-ld\" \"%.*s.o\" -o \"%.*s\" %.*s %.*s",
  136. LIT(build_context.ODIN_ROOT),
  137. LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags));
  138. #else
  139. result = system_exec_command_line_app("wasm-ld",
  140. "wasm-ld \"%.*s.o\" -o \"%.*s\" %.*s %.*s",
  141. LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags));
  142. #endif
  143. return result;
  144. }
  145. if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) {
  146. #if defined(GB_SYSTEM_UNIX)
  147. result = system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s %.*s",
  148. LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags));
  149. #else
  150. gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n",
  151. LIT(target_os_names[build_context.metrics.os]),
  152. LIT(target_arch_names[build_context.metrics.arch])
  153. );
  154. #endif
  155. } else if (build_context.cross_compiling && build_context.different_os) {
  156. gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n",
  157. LIT(target_os_names[build_context.metrics.os]),
  158. LIT(target_arch_names[build_context.metrics.arch])
  159. );
  160. build_context.keep_object_files = true;
  161. } else {
  162. #if defined(GB_SYSTEM_WINDOWS)
  163. bool is_windows = true;
  164. #else
  165. bool is_windows = false;
  166. #endif
  167. #if defined(GB_SYSTEM_OSX)
  168. bool is_osx = true;
  169. #else
  170. bool is_osx = false;
  171. #endif
  172. if (is_windows) {
  173. String section_name = str_lit("msvc-link");
  174. if (build_context.use_lld) {
  175. section_name = str_lit("lld-link");
  176. }
  177. timings_start_section(timings, section_name);
  178. gbString lib_str = gb_string_make(heap_allocator(), "");
  179. defer (gb_string_free(lib_str));
  180. gbString link_settings = gb_string_make_reserve(heap_allocator(), 256);
  181. defer (gb_string_free(link_settings));
  182. // Add library search paths.
  183. if (build_context.build_paths[BuildPath_VS_LIB].basename.len > 0) {
  184. String path = {};
  185. auto add_path = [&](String path) {
  186. if (path[path.len-1] == '\\') {
  187. path.len -= 1;
  188. }
  189. link_settings = gb_string_append_fmt(link_settings, " /LIBPATH:\"%.*s\"", LIT(path));
  190. };
  191. add_path(build_context.build_paths[BuildPath_Win_SDK_UM_Lib].basename);
  192. add_path(build_context.build_paths[BuildPath_Win_SDK_UCRT_Lib].basename);
  193. add_path(build_context.build_paths[BuildPath_VS_LIB].basename);
  194. }
  195. StringSet libs = {};
  196. string_set_init(&libs, 64);
  197. defer (string_set_destroy(&libs));
  198. StringSet asm_files = {};
  199. string_set_init(&asm_files, 64);
  200. defer (string_set_destroy(&asm_files));
  201. for (Entity *e : gen->foreign_libraries) {
  202. GB_ASSERT(e->kind == Entity_LibraryName);
  203. for_array(i, e->LibraryName.paths) {
  204. String lib = string_trim_whitespace(e->LibraryName.paths[i]);
  205. // IMPORTANT NOTE(bill): calling `string_to_lower` here is not an issue because
  206. // we will never uses these strings afterwards
  207. string_to_lower(&lib);
  208. if (lib.len == 0) {
  209. continue;
  210. }
  211. if (has_asm_extension(lib)) {
  212. if (!string_set_update(&asm_files, lib)) {
  213. String asm_file = asm_files.entries[i].value;
  214. String obj_file = concatenate_strings(permanent_allocator(), asm_file, str_lit(".obj"));
  215. result = system_exec_command_line_app("nasm",
  216. "\"%.*s\\bin\\nasm\\windows\\nasm.exe\" \"%.*s\" "
  217. "-f win64 "
  218. "-o \"%.*s\" "
  219. "%.*s "
  220. "",
  221. LIT(build_context.ODIN_ROOT), LIT(asm_file),
  222. LIT(obj_file),
  223. LIT(build_context.extra_assembler_flags)
  224. );
  225. if (result) {
  226. return result;
  227. }
  228. array_add(&gen->output_object_paths, obj_file);
  229. }
  230. } else {
  231. if (!string_set_update(&libs, lib)) {
  232. lib_str = gb_string_append_fmt(lib_str, " \"%.*s\"", LIT(lib));
  233. }
  234. }
  235. }
  236. }
  237. for (Entity *e : gen->foreign_libraries) {
  238. GB_ASSERT(e->kind == Entity_LibraryName);
  239. if (e->LibraryName.extra_linker_flags.len != 0) {
  240. lib_str = gb_string_append_fmt(lib_str, " %.*s", LIT(e->LibraryName.extra_linker_flags));
  241. }
  242. }
  243. if (build_context.build_mode == BuildMode_DynamicLibrary) {
  244. link_settings = gb_string_append_fmt(link_settings, " /DLL");
  245. } else {
  246. link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup");
  247. }
  248. if (build_context.pdb_filepath != "") {
  249. String pdb_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_PDB]);
  250. link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(pdb_path));
  251. }
  252. if (build_context.no_crt) {
  253. link_settings = gb_string_append_fmt(link_settings, " /nodefaultlib");
  254. } else {
  255. link_settings = gb_string_append_fmt(link_settings, " /defaultlib:libcmt");
  256. }
  257. if (build_context.ODIN_DEBUG) {
  258. link_settings = gb_string_append_fmt(link_settings, " /DEBUG");
  259. }
  260. gbString object_files = gb_string_make(heap_allocator(), "");
  261. defer (gb_string_free(object_files));
  262. for (String const &object_path : gen->output_object_paths) {
  263. object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path));
  264. }
  265. String vs_exe_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_VS_EXE]);
  266. defer (gb_free(heap_allocator(), vs_exe_path.text));
  267. String windows_sdk_bin_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Win_SDK_Bin_Path]);
  268. defer (gb_free(heap_allocator(), windows_sdk_bin_path.text));
  269. char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE";
  270. if (!build_context.use_lld) { // msvc
  271. String res_path = {};
  272. defer (gb_free(heap_allocator(), res_path.text));
  273. if (build_context.has_resource) {
  274. String temp_res_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RES]);
  275. res_path = concatenate3_strings(heap_allocator(), str_lit("\""), temp_res_path, str_lit("\""));
  276. gb_free(heap_allocator(), temp_res_path.text);
  277. String rc_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RC]);
  278. defer (gb_free(heap_allocator(), rc_path.text));
  279. result = system_exec_command_line_app("msvc-link",
  280. "\"%.*src.exe\" /nologo /fo \"%.*s\" \"%.*s\"",
  281. LIT(windows_sdk_bin_path),
  282. LIT(res_path),
  283. LIT(rc_path)
  284. );
  285. if (result) {
  286. return result;
  287. }
  288. }
  289. switch (build_context.build_mode) {
  290. case BuildMode_Executable:
  291. link_settings = gb_string_append_fmt(link_settings, " /NOIMPLIB /NOEXP");
  292. break;
  293. }
  294. result = system_exec_command_line_app("msvc-link",
  295. "\"%.*slink.exe\" %s %.*s -OUT:\"%.*s\" %s "
  296. "/nologo /incremental:no /opt:ref /subsystem:%s "
  297. "%.*s "
  298. "%.*s "
  299. "%s "
  300. "",
  301. LIT(vs_exe_path), object_files, LIT(res_path), LIT(output_filename),
  302. link_settings,
  303. subsystem_str,
  304. LIT(build_context.link_flags),
  305. LIT(build_context.extra_linker_flags),
  306. lib_str
  307. );
  308. if (result) {
  309. return result;
  310. }
  311. } else { // lld
  312. result = system_exec_command_line_app("msvc-lld-link",
  313. "\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s\" %s "
  314. "/nologo /incremental:no /opt:ref /subsystem:%s "
  315. "%.*s "
  316. "%.*s "
  317. "%s "
  318. "",
  319. LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename),
  320. link_settings,
  321. subsystem_str,
  322. LIT(build_context.link_flags),
  323. LIT(build_context.extra_linker_flags),
  324. lib_str
  325. );
  326. if (result) {
  327. return result;
  328. }
  329. }
  330. } else {
  331. timings_start_section(timings, str_lit("ld-link"));
  332. // NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe
  333. char cwd[256];
  334. #if !defined(GB_SYSTEM_WINDOWS)
  335. getcwd(&cwd[0], 256);
  336. #endif
  337. //printf("%s\n", cwd);
  338. // NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library
  339. // files can be passed with -l:
  340. gbString lib_str = gb_string_make(heap_allocator(), "-L/");
  341. defer (gb_string_free(lib_str));
  342. StringSet libs = {};
  343. string_set_init(&libs, 64);
  344. defer (string_set_destroy(&libs));
  345. for (Entity *e : gen->foreign_libraries) {
  346. GB_ASSERT(e->kind == Entity_LibraryName);
  347. for (String lib : e->LibraryName.paths) {
  348. lib = string_trim_whitespace(lib);
  349. if (lib.len == 0) {
  350. continue;
  351. }
  352. if (string_set_update(&libs, lib)) {
  353. continue;
  354. }
  355. // NOTE(zangent): Sometimes, you have to use -framework on MacOS.
  356. // This allows you to specify '-f' in a #foreign_system_library,
  357. // without having to implement any new syntax specifically for MacOS.
  358. if (build_context.metrics.os == TargetOs_darwin) {
  359. if (string_ends_with(lib, str_lit(".framework"))) {
  360. // framework thingie
  361. String lib_name = lib;
  362. lib_name = remove_extension_from_path(lib_name);
  363. lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name));
  364. } else if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o")) || string_ends_with(lib, str_lit(".dylib"))) {
  365. // For:
  366. // object
  367. // dynamic lib
  368. // static libs, absolute full path relative to the file in which the lib was imported from
  369. lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
  370. } else {
  371. // dynamic or static system lib, just link regularly searching system library paths
  372. lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
  373. }
  374. } else {
  375. // NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path,
  376. // since those are statically linked to at link time. shared libraries (.so) has to be
  377. // available at runtime wherever the executable is run, so we make require those to be
  378. // local to the executable (unless the system collection is used, in which case we search
  379. // the system library paths for the library file).
  380. if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o"))) {
  381. // static libs and object files, absolute full path relative to the file in which the lib was imported from
  382. lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib));
  383. } else if (string_ends_with(lib, str_lit(".so"))) {
  384. // dynamic lib, relative path to executable
  385. // NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible
  386. // at runtime to the executable
  387. lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib));
  388. } else {
  389. // dynamic or static system lib, just link regularly searching system library paths
  390. lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
  391. }
  392. }
  393. }
  394. }
  395. for (Entity *e : gen->foreign_libraries) {
  396. GB_ASSERT(e->kind == Entity_LibraryName);
  397. if (e->LibraryName.extra_linker_flags.len != 0) {
  398. lib_str = gb_string_append_fmt(lib_str, " %.*s", LIT(e->LibraryName.extra_linker_flags));
  399. }
  400. }
  401. gbString object_files = gb_string_make(heap_allocator(), "");
  402. defer (gb_string_free(object_files));
  403. for (String object_path : gen->output_object_paths) {
  404. object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path));
  405. }
  406. gbString link_settings = gb_string_make_reserve(heap_allocator(), 32);
  407. if (build_context.no_crt) {
  408. link_settings = gb_string_append_fmt(link_settings, "-nostdlib ");
  409. }
  410. // NOTE(dweiler): We use clang as a frontend for the linker as there are
  411. // other runtime and compiler support libraries that need to be linked in
  412. // very specific orders such as libgcc_s, ld-linux-so, unwind, etc.
  413. // These are not always typically inside /lib, /lib64, or /usr versions
  414. // of that, e.g libgcc.a is in /usr/lib/gcc/{version}, and can vary on
  415. // the distribution of Linux even. The gcc or clang specs is the only
  416. // reliable way to query this information to call ld directly.
  417. if (build_context.build_mode == BuildMode_DynamicLibrary) {
  418. // NOTE(dweiler): Let the frontend know we're building a shared library
  419. // so it doesn't generate symbols which cannot be relocated.
  420. link_settings = gb_string_appendc(link_settings, "-shared ");
  421. // NOTE(dweiler): _odin_entry_point must be called at initialization
  422. // time of the shared object, similarly, _odin_exit_point must be called
  423. // at deinitialization. We can pass both -init and -fini to the linker by
  424. // using a comma separated list of arguments to -Wl.
  425. //
  426. // This previously used ld but ld cannot actually build a shared library
  427. // correctly this way since all the other dependencies provided implicitly
  428. // by the compiler frontend are still needed and most of the command
  429. // line arguments prepared previously are incompatible with ld.
  430. if (build_context.metrics.os == TargetOs_darwin) {
  431. link_settings = gb_string_appendc(link_settings, "-Wl,-init,'__odin_entry_point' ");
  432. // NOTE(weshardee): __odin_exit_point should also be added, but -fini
  433. // does not exist on MacOS
  434. } else {
  435. link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' ");
  436. link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' ");
  437. }
  438. } else if (build_context.metrics.os != TargetOs_openbsd) {
  439. // OpenBSD defaults to PIE executable. do not pass -no-pie for it.
  440. link_settings = gb_string_appendc(link_settings, "-no-pie ");
  441. }
  442. gbString platform_lib_str = gb_string_make(heap_allocator(), "");
  443. defer (gb_string_free(platform_lib_str));
  444. if (build_context.metrics.os == TargetOs_darwin) {
  445. platform_lib_str = gb_string_appendc(platform_lib_str, "-lSystem -lm -Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib");
  446. } else {
  447. platform_lib_str = gb_string_appendc(platform_lib_str, "-lc -lm");
  448. }
  449. if (build_context.metrics.os == TargetOs_darwin) {
  450. // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
  451. if (build_context.minimum_os_version_string.len) {
  452. link_settings = gb_string_append_fmt(link_settings, " -mmacosx-version-min=%.*s ", LIT(build_context.minimum_os_version_string));
  453. } else if (build_context.metrics.arch == TargetArch_arm64) {
  454. link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=12.0.0 ");
  455. } else {
  456. link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=10.12.0 ");
  457. }
  458. // This points the linker to where the entry point is
  459. link_settings = gb_string_appendc(link_settings, " -e _main ");
  460. }
  461. gbString link_command_line = gb_string_make(heap_allocator(), "clang -Wno-unused-command-line-argument ");
  462. defer (gb_string_free(link_command_line));
  463. link_command_line = gb_string_appendc(link_command_line, object_files);
  464. link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s\" ", LIT(output_filename));
  465. link_command_line = gb_string_append_fmt(link_command_line, " %s ", platform_lib_str);
  466. link_command_line = gb_string_append_fmt(link_command_line, " %s ", lib_str);
  467. link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.link_flags));
  468. link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.extra_linker_flags));
  469. link_command_line = gb_string_append_fmt(link_command_line, " %s ", link_settings);
  470. result = system_exec_command_line_app("ld-link", link_command_line);
  471. if (result) {
  472. return result;
  473. }
  474. if (is_osx && build_context.ODIN_DEBUG) {
  475. // NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe
  476. // to the symbols in the object file
  477. result = system_exec_command_line_app("dsymutil", "dsymutil %.*s", LIT(output_filename));
  478. if (result) {
  479. return result;
  480. }
  481. }
  482. }
  483. }
  484. return result;
  485. }
  486. gb_internal Array<String> setup_args(int argc, char const **argv) {
  487. gbAllocator a = heap_allocator();
  488. #if defined(GB_SYSTEM_WINDOWS)
  489. int wargc = 0;
  490. wchar_t **wargv = command_line_to_wargv(GetCommandLineW(), &wargc);
  491. auto args = array_make<String>(a, 0, wargc);
  492. for (isize i = 0; i < wargc; i++) {
  493. wchar_t *warg = wargv[i];
  494. isize wlen = string16_len(warg);
  495. String16 wstr = make_string16(warg, wlen);
  496. String arg = string16_to_string(a, wstr);
  497. if (arg.len > 0) {
  498. array_add(&args, arg);
  499. }
  500. }
  501. return args;
  502. #else
  503. auto args = array_make<String>(a, 0, argc);
  504. for (isize i = 0; i < argc; i++) {
  505. String arg = make_string_c(argv[i]);
  506. if (arg.len > 0) {
  507. array_add(&args, arg);
  508. }
  509. }
  510. return args;
  511. #endif
  512. }
  513. gb_internal void print_usage_line(i32 indent, char const *fmt, ...) {
  514. while (indent --> 0) {
  515. gb_printf("\t");
  516. }
  517. va_list va;
  518. va_start(va, fmt);
  519. gb_printf_va(fmt, va);
  520. va_end(va);
  521. gb_printf("\n");
  522. }
  523. gb_internal void usage(String argv0) {
  524. print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(argv0));
  525. print_usage_line(0, "Usage:");
  526. print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
  527. print_usage_line(0, "Commands:");
  528. print_usage_line(1, "build compile directory of .odin files, as an executable.");
  529. print_usage_line(1, " one must contain the program's entry point, all must be in the same package.");
  530. print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable.");
  531. print_usage_line(1, "check parse, and type check a directory of .odin files");
  532. print_usage_line(1, "strip-semicolon parse, type check, and remove unneeded semicolons from the entire program");
  533. print_usage_line(1, "test build and runs procedures with the attribute @(test) in the initial package");
  534. print_usage_line(1, "doc generate documentation on a directory of .odin files");
  535. print_usage_line(1, "version print version");
  536. print_usage_line(1, "report print information useful to reporting a bug");
  537. print_usage_line(0, "");
  538. print_usage_line(0, "For further details on a command, invoke command help:");
  539. print_usage_line(1, "e.g. `odin build -help` or `odin help build`");
  540. }
  541. enum BuildFlagKind {
  542. BuildFlag_Invalid,
  543. BuildFlag_Help,
  544. BuildFlag_SingleFile,
  545. BuildFlag_OutFile,
  546. BuildFlag_OptimizationMode,
  547. BuildFlag_ShowTimings,
  548. BuildFlag_ShowUnused,
  549. BuildFlag_ShowUnusedWithLocation,
  550. BuildFlag_ShowMoreTimings,
  551. BuildFlag_ExportTimings,
  552. BuildFlag_ExportTimingsFile,
  553. BuildFlag_ShowSystemCalls,
  554. BuildFlag_ThreadCount,
  555. BuildFlag_KeepTempFiles,
  556. BuildFlag_Collection,
  557. BuildFlag_Define,
  558. BuildFlag_BuildMode,
  559. BuildFlag_Target,
  560. BuildFlag_Debug,
  561. BuildFlag_DisableAssert,
  562. BuildFlag_NoBoundsCheck,
  563. BuildFlag_NoDynamicLiterals,
  564. BuildFlag_NoCRT,
  565. BuildFlag_NoEntryPoint,
  566. BuildFlag_UseLLD,
  567. BuildFlag_UseSeparateModules,
  568. BuildFlag_NoThreadedChecker,
  569. BuildFlag_ShowDebugMessages,
  570. BuildFlag_Vet,
  571. BuildFlag_VetExtra,
  572. BuildFlag_UseLLVMApi,
  573. BuildFlag_IgnoreUnknownAttributes,
  574. BuildFlag_ExtraLinkerFlags,
  575. BuildFlag_ExtraAssemblerFlags,
  576. BuildFlag_Microarch,
  577. BuildFlag_TargetFeatures,
  578. BuildFlag_MinimumOSVersion,
  579. BuildFlag_NoThreadLocal,
  580. BuildFlag_RelocMode,
  581. BuildFlag_DisableRedZone,
  582. BuildFlag_TestName,
  583. BuildFlag_DisallowDo,
  584. BuildFlag_DefaultToNilAllocator,
  585. BuildFlag_InsertSemicolon,
  586. BuildFlag_StrictStyle,
  587. BuildFlag_StrictStyleInitOnly,
  588. BuildFlag_ForeignErrorProcedures,
  589. BuildFlag_DisallowRTTI,
  590. BuildFlag_DynamicMapCalls,
  591. BuildFlag_Compact,
  592. BuildFlag_GlobalDefinitions,
  593. BuildFlag_GoToDefinitions,
  594. BuildFlag_Short,
  595. BuildFlag_AllPackages,
  596. BuildFlag_DocFormat,
  597. BuildFlag_IgnoreWarnings,
  598. BuildFlag_WarningsAsErrors,
  599. BuildFlag_TerseErrors,
  600. BuildFlag_VerboseErrors,
  601. BuildFlag_ErrorPosStyle,
  602. BuildFlag_MaxErrorCount,
  603. // internal use only
  604. BuildFlag_InternalIgnoreLazy,
  605. BuildFlag_InternalIgnoreLLVMBuild,
  606. #if defined(GB_SYSTEM_WINDOWS)
  607. BuildFlag_IgnoreVsSearch,
  608. BuildFlag_ResourceFile,
  609. BuildFlag_WindowsPdbName,
  610. BuildFlag_Subsystem,
  611. #endif
  612. BuildFlag_COUNT,
  613. };
  614. enum BuildFlagParamKind {
  615. BuildFlagParam_None,
  616. BuildFlagParam_Boolean,
  617. BuildFlagParam_Integer,
  618. BuildFlagParam_Float,
  619. BuildFlagParam_String,
  620. BuildFlagParam_COUNT,
  621. };
  622. struct BuildFlag {
  623. BuildFlagKind kind;
  624. String name;
  625. BuildFlagParamKind param_kind;
  626. u32 command_support;
  627. bool allow_mulitple;
  628. };
  629. gb_internal void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind, u32 command_support, bool allow_mulitple=false) {
  630. BuildFlag flag = {kind, name, param_kind, command_support, allow_mulitple};
  631. array_add(build_flags, flag);
  632. }
  633. gb_internal ExactValue build_param_to_exact_value(String name, String param) {
  634. ExactValue value = {};
  635. /*
  636. Bail out on an empty param string
  637. */
  638. if (param.len == 0) {
  639. gb_printf_err("Invalid flag parameter for '%.*s' = '%.*s'\n", LIT(name), LIT(param));
  640. return value;
  641. }
  642. /*
  643. Attempt to parse as bool first.
  644. */
  645. if (str_eq_ignore_case(param, str_lit("t")) || str_eq_ignore_case(param, str_lit("true"))) {
  646. return exact_value_bool(true);
  647. }
  648. if (str_eq_ignore_case(param, str_lit("f")) || str_eq_ignore_case(param, str_lit("false"))) {
  649. return exact_value_bool(false);
  650. }
  651. /*
  652. Try to parse as an integer or float
  653. */
  654. if (param[0] == '-' || param[0] == '+' || gb_is_between(param[0], '0', '9')) {
  655. if (string_contains_char(param, '.')) {
  656. value = exact_value_float_from_string(param);
  657. } else {
  658. value = exact_value_integer_from_string(param);
  659. }
  660. if (value.kind != ExactValue_Invalid) {
  661. return value;
  662. }
  663. }
  664. /*
  665. Treat the param as a string literal,
  666. optionally be quoted in '' to avoid being parsed as a bool, integer or float.
  667. */
  668. value = exact_value_string(param);
  669. if (param[0] == '\'' && value.kind == ExactValue_String) {
  670. String s = value.value_string;
  671. if (s.len > 1 && s[0] == '\'' && s[s.len-1] == '\'') {
  672. value.value_string = substring(s, 1, s.len-1);
  673. }
  674. }
  675. if (value.kind != ExactValue_String) {
  676. gb_printf_err("Invalid flag parameter for '%.*s' = '%.*s'\n", LIT(name), LIT(param));
  677. }
  678. return value;
  679. }
  680. // Writes a did-you-mean message for formerly deprecated flags.
  681. gb_internal void did_you_mean_flag(String flag) {
  682. gbAllocator a = heap_allocator();
  683. String name = copy_string(a, flag);
  684. defer (gb_free(a, name.text));
  685. string_to_lower(&name);
  686. if (name == "opt") {
  687. gb_printf_err("`-opt` is an unrecognized option. Did you mean `-o`?\n");
  688. return;
  689. }
  690. gb_printf_err("Unknown flag: '%.*s'\n", LIT(flag));
  691. }
  692. gb_internal bool parse_build_flags(Array<String> args) {
  693. auto build_flags = array_make<BuildFlag>(heap_allocator(), 0, BuildFlag_COUNT);
  694. add_flag(&build_flags, BuildFlag_Help, str_lit("help"), BuildFlagParam_None, Command_all);
  695. add_flag(&build_flags, BuildFlag_SingleFile, str_lit("file"), BuildFlagParam_None, Command__does_build | Command__does_check);
  696. add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String, Command__does_build | Command_test);
  697. add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("o"), BuildFlagParam_String, Command__does_build);
  698. add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("O"), BuildFlagParam_String, Command__does_build);
  699. add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None, Command__does_check);
  700. add_flag(&build_flags, BuildFlag_ShowMoreTimings, str_lit("show-more-timings"), BuildFlagParam_None, Command__does_check);
  701. add_flag(&build_flags, BuildFlag_ExportTimings, str_lit("export-timings"), BuildFlagParam_String, Command__does_check);
  702. add_flag(&build_flags, BuildFlag_ExportTimingsFile, str_lit("export-timings-file"), BuildFlagParam_String, Command__does_check);
  703. add_flag(&build_flags, BuildFlag_ShowUnused, str_lit("show-unused"), BuildFlagParam_None, Command_check);
  704. add_flag(&build_flags, BuildFlag_ShowUnusedWithLocation, str_lit("show-unused-with-location"), BuildFlagParam_None, Command_check);
  705. add_flag(&build_flags, BuildFlag_ShowSystemCalls, str_lit("show-system-calls"), BuildFlagParam_None, Command_all);
  706. add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer, Command_all);
  707. add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None, Command__does_build | Command_strip_semicolon);
  708. add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String, Command__does_check);
  709. add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String, Command__does_check, true);
  710. add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String, Command__does_build); // Commands_build is not used to allow for a better error message
  711. add_flag(&build_flags, BuildFlag_Target, str_lit("target"), BuildFlagParam_String, Command__does_check);
  712. add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None, Command__does_check);
  713. add_flag(&build_flags, BuildFlag_DisableAssert, str_lit("disable-assert"), BuildFlagParam_None, Command__does_check);
  714. add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None, Command__does_check);
  715. add_flag(&build_flags, BuildFlag_NoThreadLocal, str_lit("no-thread-local"), BuildFlagParam_None, Command__does_check);
  716. add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None, Command__does_check);
  717. add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None, Command__does_build);
  718. add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check &~ Command_test);
  719. add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None, Command__does_build);
  720. add_flag(&build_flags, BuildFlag_UseSeparateModules, str_lit("use-separate-modules"), BuildFlagParam_None, Command__does_build);
  721. add_flag(&build_flags, BuildFlag_NoThreadedChecker, str_lit("no-threaded-checker"), BuildFlagParam_None, Command__does_check);
  722. add_flag(&build_flags, BuildFlag_ShowDebugMessages, str_lit("show-debug-messages"), BuildFlagParam_None, Command_all);
  723. add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check);
  724. add_flag(&build_flags, BuildFlag_VetExtra, str_lit("vet-extra"), BuildFlagParam_None, Command__does_check);
  725. add_flag(&build_flags, BuildFlag_UseLLVMApi, str_lit("llvm-api"), BuildFlagParam_None, Command__does_build);
  726. add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check);
  727. add_flag(&build_flags, BuildFlag_ExtraLinkerFlags, str_lit("extra-linker-flags"), BuildFlagParam_String, Command__does_build);
  728. add_flag(&build_flags, BuildFlag_ExtraAssemblerFlags, str_lit("extra-assembler-flags"), BuildFlagParam_String, Command__does_build);
  729. add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build);
  730. add_flag(&build_flags, BuildFlag_TargetFeatures, str_lit("target-features"), BuildFlagParam_String, Command__does_build);
  731. add_flag(&build_flags, BuildFlag_MinimumOSVersion, str_lit("minimum-os-version"), BuildFlagParam_String, Command__does_build);
  732. add_flag(&build_flags, BuildFlag_RelocMode, str_lit("reloc-mode"), BuildFlagParam_String, Command__does_build);
  733. add_flag(&build_flags, BuildFlag_DisableRedZone, str_lit("disable-red-zone"), BuildFlagParam_None, Command__does_build);
  734. add_flag(&build_flags, BuildFlag_TestName, str_lit("test-name"), BuildFlagParam_String, Command_test);
  735. add_flag(&build_flags, BuildFlag_DisallowDo, str_lit("disallow-do"), BuildFlagParam_None, Command__does_check);
  736. add_flag(&build_flags, BuildFlag_DefaultToNilAllocator, str_lit("default-to-nil-allocator"), BuildFlagParam_None, Command__does_check);
  737. add_flag(&build_flags, BuildFlag_InsertSemicolon, str_lit("insert-semicolon"), BuildFlagParam_None, Command__does_check);
  738. add_flag(&build_flags, BuildFlag_StrictStyle, str_lit("strict-style"), BuildFlagParam_None, Command__does_check);
  739. add_flag(&build_flags, BuildFlag_StrictStyleInitOnly, str_lit("strict-style-init-only"), BuildFlagParam_None, Command__does_check);
  740. add_flag(&build_flags, BuildFlag_ForeignErrorProcedures, str_lit("foreign-error-procedures"), BuildFlagParam_None, Command__does_check);
  741. add_flag(&build_flags, BuildFlag_DisallowRTTI, str_lit("disallow-rtti"), BuildFlagParam_None, Command__does_check);
  742. add_flag(&build_flags, BuildFlag_DynamicMapCalls, str_lit("dynamic-map-calls"), BuildFlagParam_None, Command__does_check);
  743. add_flag(&build_flags, BuildFlag_Short, str_lit("short"), BuildFlagParam_None, Command_doc);
  744. add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc);
  745. add_flag(&build_flags, BuildFlag_DocFormat, str_lit("doc-format"), BuildFlagParam_None, Command_doc);
  746. add_flag(&build_flags, BuildFlag_IgnoreWarnings, str_lit("ignore-warnings"), BuildFlagParam_None, Command_all);
  747. add_flag(&build_flags, BuildFlag_WarningsAsErrors, str_lit("warnings-as-errors"), BuildFlagParam_None, Command_all);
  748. add_flag(&build_flags, BuildFlag_TerseErrors, str_lit("terse-errors"), BuildFlagParam_None, Command_all);
  749. add_flag(&build_flags, BuildFlag_VerboseErrors, str_lit("verbose-errors"), BuildFlagParam_None, Command_all);
  750. add_flag(&build_flags, BuildFlag_ErrorPosStyle, str_lit("error-pos-style"), BuildFlagParam_String, Command_all);
  751. add_flag(&build_flags, BuildFlag_MaxErrorCount, str_lit("max-error-count"), BuildFlagParam_Integer, Command_all);
  752. add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all);
  753. add_flag(&build_flags, BuildFlag_InternalIgnoreLLVMBuild, str_lit("internal-ignore-llvm-build"),BuildFlagParam_None, Command_all);
  754. #if defined(GB_SYSTEM_WINDOWS)
  755. add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"), BuildFlagParam_None, Command__does_build);
  756. add_flag(&build_flags, BuildFlag_ResourceFile, str_lit("resource"), BuildFlagParam_String, Command__does_build);
  757. add_flag(&build_flags, BuildFlag_WindowsPdbName, str_lit("pdb-name"), BuildFlagParam_String, Command__does_build);
  758. add_flag(&build_flags, BuildFlag_Subsystem, str_lit("subsystem"), BuildFlagParam_String, Command__does_build);
  759. #endif
  760. GB_ASSERT(args.count >= 3);
  761. Array<String> flag_args = array_slice(args, 3, args.count);
  762. bool set_flags[BuildFlag_COUNT] = {};
  763. bool bad_flags = false;
  764. for (String flag : flag_args) {
  765. if (flag[0] != '-') {
  766. gb_printf_err("Invalid flag: %.*s\n", LIT(flag));
  767. continue;
  768. }
  769. if (string_starts_with(flag, str_lit("--"))) {
  770. flag = substring(flag, 1, flag.len);
  771. }
  772. String name = substring(flag, 1, flag.len);
  773. isize end = 0;
  774. bool have_equals = false;
  775. for (; end < name.len; end++) {
  776. if (name[end] == ':') break;
  777. if (name[end] == '=') {
  778. have_equals = true;
  779. break;
  780. }
  781. }
  782. name = substring(name, 0, end);
  783. String param = {};
  784. if (end < flag.len-1) param = substring(flag, 2+end, flag.len);
  785. bool is_supported = true;
  786. bool found = false;
  787. BuildFlag found_bf = {};
  788. for (BuildFlag const &bf : build_flags) {
  789. if (bf.name == name) {
  790. found = true;
  791. found_bf = bf;
  792. if ((bf.command_support & build_context.command_kind) == 0) {
  793. is_supported = false;
  794. break;
  795. }
  796. if (set_flags[bf.kind]) {
  797. gb_printf_err("Previous flag set: '%.*s'\n", LIT(name));
  798. bad_flags = true;
  799. } else {
  800. ExactValue value = {};
  801. bool ok = false;
  802. if (bf.param_kind == BuildFlagParam_None) {
  803. if (param.len == 0) {
  804. ok = true;
  805. } else {
  806. gb_printf_err("Flag '%.*s' was not expecting a parameter '%.*s'\n", LIT(name), LIT(param));
  807. bad_flags = true;
  808. }
  809. } else if (param.len == 0) {
  810. gb_printf_err("Flag missing for '%.*s'\n", LIT(name));
  811. bad_flags = true;
  812. } else {
  813. ok = true;
  814. switch (bf.param_kind) {
  815. default: {
  816. ok = false;
  817. } break;
  818. case BuildFlagParam_Boolean: {
  819. if (str_eq_ignore_case(param, str_lit("t")) ||
  820. str_eq_ignore_case(param, str_lit("true")) ||
  821. param == "1") {
  822. value = exact_value_bool(true);
  823. } else if (str_eq_ignore_case(param, str_lit("f")) ||
  824. str_eq_ignore_case(param, str_lit("false")) ||
  825. param == "0") {
  826. value = exact_value_bool(false);
  827. } else {
  828. gb_printf_err("Invalid flag parameter for '%.*s' : '%.*s'\n", LIT(name), LIT(param));
  829. }
  830. } break;
  831. case BuildFlagParam_Integer: {
  832. value = exact_value_integer_from_string(param);
  833. } break;
  834. case BuildFlagParam_Float: {
  835. value = exact_value_float_from_string(param);
  836. } break;
  837. case BuildFlagParam_String: {
  838. value = exact_value_string(param);
  839. if (value.kind == ExactValue_String) {
  840. String s = value.value_string;
  841. if (s.len > 1 && s[0] == '"' && s[s.len-1] == '"') {
  842. value.value_string = substring(s, 1, s.len-1);
  843. }
  844. }
  845. break;
  846. }
  847. }
  848. }
  849. if (ok) {
  850. switch (bf.param_kind) {
  851. case BuildFlagParam_None:
  852. if (value.kind != ExactValue_Invalid) {
  853. gb_printf_err("%.*s expected no value, got %.*s\n", LIT(name), LIT(param));
  854. bad_flags = true;
  855. ok = false;
  856. }
  857. break;
  858. case BuildFlagParam_Boolean:
  859. if (value.kind != ExactValue_Bool) {
  860. gb_printf_err("%.*s expected a boolean, got %.*s\n", LIT(name), LIT(param));
  861. bad_flags = true;
  862. ok = false;
  863. }
  864. break;
  865. case BuildFlagParam_Integer:
  866. if (value.kind != ExactValue_Integer) {
  867. gb_printf_err("%.*s expected an integer, got %.*s\n", LIT(name), LIT(param));
  868. bad_flags = true;
  869. ok = false;
  870. }
  871. break;
  872. case BuildFlagParam_Float:
  873. if (value.kind != ExactValue_Float) {
  874. gb_printf_err("%.*s expected a floating pointer number, got %.*s\n", LIT(name), LIT(param));
  875. bad_flags = true;
  876. ok = false;
  877. }
  878. break;
  879. case BuildFlagParam_String:
  880. if (value.kind != ExactValue_String) {
  881. gb_printf_err("%.*s expected a string, got %.*s\n", LIT(name), LIT(param));
  882. bad_flags = true;
  883. ok = false;
  884. }
  885. break;
  886. }
  887. if (ok) switch (bf.kind) {
  888. case BuildFlag_Help:
  889. build_context.show_help = true;
  890. break;
  891. case BuildFlag_OutFile: {
  892. GB_ASSERT(value.kind == ExactValue_String);
  893. String path = value.value_string;
  894. path = string_trim_whitespace(path);
  895. if (is_build_flag_path_valid(path)) {
  896. build_context.out_filepath = path_to_full_path(heap_allocator(), path);
  897. } else {
  898. gb_printf_err("Invalid -out path, got %.*s\n", LIT(path));
  899. bad_flags = true;
  900. }
  901. break;
  902. }
  903. case BuildFlag_OptimizationMode: {
  904. GB_ASSERT(value.kind == ExactValue_String);
  905. if (value.value_string == "none") {
  906. build_context.optimization_level = -1;
  907. } else if (value.value_string == "minimal") {
  908. build_context.optimization_level = 0;
  909. } else if (value.value_string == "size") {
  910. build_context.optimization_level = 1;
  911. } else if (value.value_string == "speed") {
  912. build_context.optimization_level = 2;
  913. } else {
  914. gb_printf_err("Invalid optimization mode for -o:<string>, got %.*s\n", LIT(value.value_string));
  915. gb_printf_err("Valid optimization modes:\n");
  916. gb_printf_err("\tminimal\n");
  917. gb_printf_err("\tsize\n");
  918. gb_printf_err("\tspeed\n");
  919. gb_printf_err("\tnone (useful for -debug builds)\n");
  920. bad_flags = true;
  921. }
  922. break;
  923. }
  924. case BuildFlag_ShowTimings: {
  925. GB_ASSERT(value.kind == ExactValue_Invalid);
  926. build_context.show_timings = true;
  927. break;
  928. }
  929. case BuildFlag_ShowUnused: {
  930. GB_ASSERT(value.kind == ExactValue_Invalid);
  931. build_context.show_unused = true;
  932. break;
  933. }
  934. case BuildFlag_ShowUnusedWithLocation: {
  935. GB_ASSERT(value.kind == ExactValue_Invalid);
  936. build_context.show_unused = true;
  937. build_context.show_unused_with_location = true;
  938. break;
  939. }
  940. case BuildFlag_ShowMoreTimings:
  941. GB_ASSERT(value.kind == ExactValue_Invalid);
  942. build_context.show_timings = true;
  943. build_context.show_more_timings = true;
  944. break;
  945. case BuildFlag_ExportTimings: {
  946. GB_ASSERT(value.kind == ExactValue_String);
  947. /*
  948. NOTE(Jeroen): `build_context.export_timings_format == 0` means the option wasn't used.
  949. */
  950. if (value.value_string == "json") {
  951. build_context.export_timings_format = TimingsExportJson;
  952. } else if (value.value_string == "csv") {
  953. build_context.export_timings_format = TimingsExportCSV;
  954. } else {
  955. gb_printf_err("Invalid export format for -export-timings:<string>, got %.*s\n", LIT(value.value_string));
  956. gb_printf_err("Valid export formats:\n");
  957. gb_printf_err("\tjson\n");
  958. gb_printf_err("\tcsv\n");
  959. bad_flags = true;
  960. }
  961. break;
  962. }
  963. case BuildFlag_ExportTimingsFile: {
  964. GB_ASSERT(value.kind == ExactValue_String);
  965. String export_path = string_trim_whitespace(value.value_string);
  966. if (is_build_flag_path_valid(export_path)) {
  967. build_context.export_timings_file = path_to_full_path(heap_allocator(), export_path);
  968. } else {
  969. gb_printf_err("Invalid -export-timings-file path, got %.*s\n", LIT(export_path));
  970. bad_flags = true;
  971. }
  972. break;
  973. }
  974. case BuildFlag_ShowSystemCalls: {
  975. GB_ASSERT(value.kind == ExactValue_Invalid);
  976. build_context.show_system_calls = true;
  977. break;
  978. }
  979. case BuildFlag_ThreadCount: {
  980. GB_ASSERT(value.kind == ExactValue_Integer);
  981. isize count = cast(isize)big_int_to_i64(&value.value_integer);
  982. if (count <= 0) {
  983. gb_printf_err("%.*s expected a positive non-zero number, got %.*s\n", LIT(name), LIT(param));
  984. build_context.thread_count = 1;
  985. } else {
  986. build_context.thread_count = count;
  987. }
  988. break;
  989. }
  990. case BuildFlag_KeepTempFiles: {
  991. GB_ASSERT(value.kind == ExactValue_Invalid);
  992. build_context.keep_temp_files = true;
  993. break;
  994. }
  995. case BuildFlag_Collection: {
  996. GB_ASSERT(value.kind == ExactValue_String);
  997. String str = value.value_string;
  998. isize eq_pos = -1;
  999. for (isize i = 0; i < str.len; i++) {
  1000. if (str[i] == '=') {
  1001. eq_pos = i;
  1002. break;
  1003. }
  1004. }
  1005. if (eq_pos < 0) {
  1006. gb_printf_err("Expected 'name=path', got '%.*s'\n", LIT(param));
  1007. bad_flags = true;
  1008. break;
  1009. }
  1010. String name = substring(str, 0, eq_pos);
  1011. String path = substring(str, eq_pos+1, str.len);
  1012. if (name.len == 0 || path.len == 0) {
  1013. gb_printf_err("Expected 'name=path', got '%.*s'\n", LIT(param));
  1014. bad_flags = true;
  1015. break;
  1016. }
  1017. if (!string_is_valid_identifier(name)) {
  1018. gb_printf_err("Library collection name '%.*s' must be a valid identifier\n", LIT(name));
  1019. bad_flags = true;
  1020. break;
  1021. }
  1022. if (name == "_") {
  1023. gb_printf_err("Library collection name cannot be an underscore\n");
  1024. bad_flags = true;
  1025. break;
  1026. }
  1027. if (name == "system") {
  1028. gb_printf_err("Library collection name 'system' is reserved\n");
  1029. bad_flags = true;
  1030. break;
  1031. }
  1032. String prev_path = {};
  1033. bool found = find_library_collection_path(name, &prev_path);
  1034. if (found) {
  1035. gb_printf_err("Library collection '%.*s' already exists with path '%.*s'\n", LIT(name), LIT(prev_path));
  1036. bad_flags = true;
  1037. break;
  1038. }
  1039. gbAllocator a = heap_allocator();
  1040. String fullpath = path_to_fullpath(a, path);
  1041. if (!path_is_directory(fullpath)) {
  1042. gb_printf_err("Library collection '%.*s' path must be a directory, got '%.*s'\n", LIT(name), LIT(fullpath));
  1043. gb_free(a, fullpath.text);
  1044. bad_flags = true;
  1045. break;
  1046. }
  1047. add_library_collection(name, path);
  1048. // NOTE(bill): Allow for multiple library collections
  1049. continue;
  1050. }
  1051. case BuildFlag_Define: {
  1052. GB_ASSERT(value.kind == ExactValue_String);
  1053. String str = value.value_string;
  1054. isize eq_pos = -1;
  1055. for (isize i = 0; i < str.len; i++) {
  1056. if (str[i] == '=') {
  1057. eq_pos = i;
  1058. break;
  1059. }
  1060. }
  1061. if (eq_pos < 0) {
  1062. gb_printf_err("Expected 'name=value', got '%.*s'\n", LIT(param));
  1063. bad_flags = true;
  1064. break;
  1065. }
  1066. String name = substring(str, 0, eq_pos);
  1067. String value = substring(str, eq_pos+1, str.len);
  1068. if (name.len == 0 || value.len == 0) {
  1069. gb_printf_err("Expected 'name=value', got '%.*s'\n", LIT(param));
  1070. bad_flags = true;
  1071. break;
  1072. }
  1073. if (!string_is_valid_identifier(name)) {
  1074. gb_printf_err("Defined constant name '%.*s' must be a valid identifier\n", LIT(name));
  1075. bad_flags = true;
  1076. break;
  1077. }
  1078. if (name == "_") {
  1079. gb_printf_err("Defined constant name cannot be an underscore\n");
  1080. bad_flags = true;
  1081. break;
  1082. }
  1083. char const *key = string_intern(name);
  1084. if (map_get(&build_context.defined_values, key) != nullptr) {
  1085. gb_printf_err("Defined constant '%.*s' already exists\n", LIT(name));
  1086. bad_flags = true;
  1087. break;
  1088. }
  1089. ExactValue v = build_param_to_exact_value(name, value);
  1090. if (v.kind != ExactValue_Invalid) {
  1091. map_set(&build_context.defined_values, key, v);
  1092. } else {
  1093. gb_printf_err("Invalid define constant value: '%.*s'. Define constants must be a valid Odin literal.\n", LIT(value));
  1094. bad_flags = true;
  1095. }
  1096. break;
  1097. }
  1098. case BuildFlag_Target: {
  1099. GB_ASSERT(value.kind == ExactValue_String);
  1100. String str = value.value_string;
  1101. bool found = false;
  1102. for (isize i = 0; i < gb_count_of(named_targets); i++) {
  1103. if (str_eq_ignore_case(str, named_targets[i].name)) {
  1104. found = true;
  1105. selected_target_metrics = named_targets + i;
  1106. break;
  1107. }
  1108. }
  1109. if (!found) {
  1110. struct DistanceAndTargetIndex {
  1111. isize distance;
  1112. isize target_index;
  1113. };
  1114. DistanceAndTargetIndex distances[gb_count_of(named_targets)] = {};
  1115. for (isize i = 0; i < gb_count_of(named_targets); i++) {
  1116. distances[i].target_index = i;
  1117. distances[i].distance = levenstein_distance_case_insensitive(str, named_targets[i].name);
  1118. }
  1119. gb_sort_array(distances, gb_count_of(distances), gb_isize_cmp(gb_offset_of(DistanceAndTargetIndex, distance)));
  1120. gb_printf_err("Unknown target '%.*s'\n", LIT(str));
  1121. if (distances[0].distance <= MAX_SMALLEST_DID_YOU_MEAN_DISTANCE) {
  1122. gb_printf_err("Did you mean:\n");
  1123. for (isize i = 0; i < gb_count_of(named_targets); i++) {
  1124. if (distances[i].distance > MAX_SMALLEST_DID_YOU_MEAN_DISTANCE) {
  1125. break;
  1126. }
  1127. gb_printf_err("\t%.*s\n", LIT(named_targets[distances[i].target_index].name));
  1128. }
  1129. }
  1130. gb_printf_err("All supported targets:\n");
  1131. for (isize i = 0; i < gb_count_of(named_targets); i++) {
  1132. gb_printf_err("\t%.*s\n", LIT(named_targets[i].name));
  1133. }
  1134. bad_flags = true;
  1135. }
  1136. break;
  1137. }
  1138. case BuildFlag_BuildMode: {
  1139. GB_ASSERT(value.kind == ExactValue_String);
  1140. String str = value.value_string;
  1141. if (build_context.command != "build") {
  1142. gb_printf_err("'build-mode' can only be used with the 'build' command\n");
  1143. bad_flags = true;
  1144. break;
  1145. }
  1146. if (str == "dll" || str == "shared" || str == "dynamic") {
  1147. build_context.build_mode = BuildMode_DynamicLibrary;
  1148. } else if (str == "obj" || str == "object") {
  1149. build_context.build_mode = BuildMode_Object;
  1150. } else if (str == "exe") {
  1151. build_context.build_mode = BuildMode_Executable;
  1152. } else if (str == "asm" || str == "assembly" || str == "assembler") {
  1153. build_context.build_mode = BuildMode_Assembly;
  1154. } else if (str == "llvm" || str == "llvm-ir") {
  1155. build_context.build_mode = BuildMode_LLVM_IR;
  1156. } else {
  1157. gb_printf_err("Unknown build mode '%.*s'\n", LIT(str));
  1158. gb_printf_err("Valid build modes:\n");
  1159. gb_printf_err("\tdll, shared, dynamic\n");
  1160. gb_printf_err("\tobj, object\n");
  1161. gb_printf_err("\texe\n");
  1162. gb_printf_err("\tasm, assembly, assembler\n");
  1163. gb_printf_err("\tllvm, llvm-ir\n");
  1164. bad_flags = true;
  1165. break;
  1166. }
  1167. break;
  1168. }
  1169. case BuildFlag_Debug:
  1170. build_context.ODIN_DEBUG = true;
  1171. break;
  1172. case BuildFlag_DisableAssert:
  1173. build_context.ODIN_DISABLE_ASSERT = true;
  1174. break;
  1175. case BuildFlag_NoBoundsCheck:
  1176. build_context.no_bounds_check = true;
  1177. break;
  1178. case BuildFlag_NoDynamicLiterals:
  1179. build_context.no_dynamic_literals = true;
  1180. break;
  1181. case BuildFlag_NoCRT:
  1182. build_context.no_crt = true;
  1183. break;
  1184. case BuildFlag_NoEntryPoint:
  1185. build_context.no_entry_point = true;
  1186. break;
  1187. case BuildFlag_NoThreadLocal:
  1188. build_context.no_thread_local = true;
  1189. break;
  1190. case BuildFlag_UseLLD:
  1191. build_context.use_lld = true;
  1192. break;
  1193. case BuildFlag_UseSeparateModules:
  1194. build_context.use_separate_modules = true;
  1195. break;
  1196. case BuildFlag_NoThreadedChecker: {
  1197. build_context.no_threaded_checker = true;
  1198. break;
  1199. }
  1200. case BuildFlag_ShowDebugMessages:
  1201. build_context.show_debug_messages = true;
  1202. break;
  1203. case BuildFlag_Vet:
  1204. build_context.vet = true;
  1205. break;
  1206. case BuildFlag_VetExtra: {
  1207. build_context.vet = true;
  1208. build_context.vet_extra = true;
  1209. break;
  1210. }
  1211. case BuildFlag_UseLLVMApi: {
  1212. gb_printf_err("-llvm-api flag is not required any more\n");
  1213. bad_flags = true;
  1214. break;
  1215. }
  1216. case BuildFlag_IgnoreUnknownAttributes:
  1217. build_context.ignore_unknown_attributes = true;
  1218. break;
  1219. case BuildFlag_ExtraLinkerFlags:
  1220. GB_ASSERT(value.kind == ExactValue_String);
  1221. build_context.extra_linker_flags = value.value_string;
  1222. break;
  1223. case BuildFlag_ExtraAssemblerFlags:
  1224. GB_ASSERT(value.kind == ExactValue_String);
  1225. build_context.extra_assembler_flags = value.value_string;
  1226. break;
  1227. case BuildFlag_Microarch: {
  1228. GB_ASSERT(value.kind == ExactValue_String);
  1229. build_context.microarch = value.value_string;
  1230. string_to_lower(&build_context.microarch);
  1231. break;
  1232. }
  1233. case BuildFlag_TargetFeatures: {
  1234. GB_ASSERT(value.kind == ExactValue_String);
  1235. build_context.target_features_string = value.value_string;
  1236. string_to_lower(&build_context.target_features_string);
  1237. break;
  1238. }
  1239. case BuildFlag_MinimumOSVersion: {
  1240. GB_ASSERT(value.kind == ExactValue_String);
  1241. build_context.minimum_os_version_string = value.value_string;
  1242. break;
  1243. }
  1244. case BuildFlag_RelocMode: {
  1245. GB_ASSERT(value.kind == ExactValue_String);
  1246. String v = value.value_string;
  1247. if (v == "default") {
  1248. build_context.reloc_mode = RelocMode_Default;
  1249. } else if (v == "static") {
  1250. build_context.reloc_mode = RelocMode_Static;
  1251. } else if (v == "pic") {
  1252. build_context.reloc_mode = RelocMode_PIC;
  1253. } else if (v == "dynamic-no-pic") {
  1254. build_context.reloc_mode = RelocMode_DynamicNoPIC;
  1255. } else {
  1256. gb_printf_err("-reloc-mode flag expected one of the following\n");
  1257. gb_printf_err("\tdefault\n");
  1258. gb_printf_err("\tstatic\n");
  1259. gb_printf_err("\tpic\n");
  1260. gb_printf_err("\tdynamic-no-pic\n");
  1261. bad_flags = true;
  1262. }
  1263. break;
  1264. }
  1265. case BuildFlag_DisableRedZone:
  1266. build_context.disable_red_zone = true;
  1267. break;
  1268. case BuildFlag_TestName: {
  1269. GB_ASSERT(value.kind == ExactValue_String);
  1270. {
  1271. String name = value.value_string;
  1272. if (!string_is_valid_identifier(name)) {
  1273. gb_printf_err("Test name '%.*s' must be a valid identifier\n", LIT(name));
  1274. bad_flags = true;
  1275. break;
  1276. }
  1277. string_set_add(&build_context.test_names, name);
  1278. // NOTE(bill): Allow for multiple -test-name
  1279. continue;
  1280. }
  1281. }
  1282. case BuildFlag_DisallowDo:
  1283. build_context.disallow_do = true;
  1284. break;
  1285. case BuildFlag_DisallowRTTI:
  1286. build_context.disallow_rtti = true;
  1287. break;
  1288. case BuildFlag_DynamicMapCalls:
  1289. build_context.dynamic_map_calls = true;
  1290. break;
  1291. case BuildFlag_DefaultToNilAllocator:
  1292. build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR = true;
  1293. break;
  1294. case BuildFlag_ForeignErrorProcedures:
  1295. build_context.ODIN_FOREIGN_ERROR_PROCEDURES = true;
  1296. break;
  1297. case BuildFlag_InsertSemicolon: {
  1298. gb_printf_err("-insert-semicolon flag is not required any more\n");
  1299. bad_flags = true;
  1300. break;
  1301. }
  1302. case BuildFlag_StrictStyle: {
  1303. if (build_context.strict_style_init_only) {
  1304. gb_printf_err("-strict-style and -strict-style-init-only cannot be used together\n");
  1305. }
  1306. build_context.strict_style = true;
  1307. break;
  1308. }
  1309. case BuildFlag_StrictStyleInitOnly: {
  1310. if (build_context.strict_style) {
  1311. gb_printf_err("-strict-style and -strict-style-init-only cannot be used together\n");
  1312. }
  1313. build_context.strict_style_init_only = true;
  1314. break;
  1315. }
  1316. case BuildFlag_Short:
  1317. build_context.cmd_doc_flags |= CmdDocFlag_Short;
  1318. break;
  1319. case BuildFlag_AllPackages:
  1320. build_context.cmd_doc_flags |= CmdDocFlag_AllPackages;
  1321. break;
  1322. case BuildFlag_DocFormat:
  1323. build_context.cmd_doc_flags |= CmdDocFlag_DocFormat;
  1324. break;
  1325. case BuildFlag_IgnoreWarnings: {
  1326. if (build_context.warnings_as_errors) {
  1327. gb_printf_err("-ignore-warnings cannot be used with -warnings-as-errors\n");
  1328. bad_flags = true;
  1329. } else {
  1330. build_context.ignore_warnings = true;
  1331. }
  1332. break;
  1333. }
  1334. case BuildFlag_WarningsAsErrors: {
  1335. if (build_context.ignore_warnings) {
  1336. gb_printf_err("-warnings-as-errors cannot be used with -ignore-warnings\n");
  1337. bad_flags = true;
  1338. } else {
  1339. build_context.warnings_as_errors = true;
  1340. }
  1341. break;
  1342. }
  1343. case BuildFlag_TerseErrors:
  1344. build_context.hide_error_line = true;
  1345. break;
  1346. case BuildFlag_VerboseErrors:
  1347. gb_printf_err("-verbose-errors is not the default, -terse-errors can now disable it\n");
  1348. build_context.hide_error_line = false;
  1349. break;
  1350. case BuildFlag_ErrorPosStyle:
  1351. GB_ASSERT(value.kind == ExactValue_String);
  1352. if (str_eq_ignore_case(value.value_string, str_lit("odin")) || str_eq_ignore_case(value.value_string, str_lit("default"))) {
  1353. build_context.ODIN_ERROR_POS_STYLE = ErrorPosStyle_Default;
  1354. } else if (str_eq_ignore_case(value.value_string, str_lit("unix"))) {
  1355. build_context.ODIN_ERROR_POS_STYLE = ErrorPosStyle_Unix;
  1356. } else {
  1357. gb_printf_err("-error-pos-style options are 'unix', 'odin' and 'default' (odin)\n");
  1358. bad_flags = true;
  1359. }
  1360. break;
  1361. case BuildFlag_MaxErrorCount: {
  1362. i64 count = big_int_to_i64(&value.value_integer);
  1363. if (count <= 0) {
  1364. gb_printf_err("-%.*s must be greater than 0", LIT(bf.name));
  1365. bad_flags = true;
  1366. } else {
  1367. build_context.max_error_count = cast(isize)count;
  1368. }
  1369. break;
  1370. }
  1371. case BuildFlag_InternalIgnoreLazy:
  1372. build_context.ignore_lazy = true;
  1373. break;
  1374. case BuildFlag_InternalIgnoreLLVMBuild:
  1375. build_context.ignore_llvm_build = true;
  1376. break;
  1377. #if defined(GB_SYSTEM_WINDOWS)
  1378. case BuildFlag_IgnoreVsSearch: {
  1379. GB_ASSERT(value.kind == ExactValue_Invalid);
  1380. build_context.ignore_microsoft_magic = true;
  1381. break;
  1382. }
  1383. case BuildFlag_ResourceFile: {
  1384. GB_ASSERT(value.kind == ExactValue_String);
  1385. String path = value.value_string;
  1386. path = string_trim_whitespace(path);
  1387. if (is_build_flag_path_valid(path)) {
  1388. if(!string_ends_with(path, str_lit(".rc"))) {
  1389. gb_printf_err("Invalid -resource path %.*s, missing .rc\n", LIT(path));
  1390. bad_flags = true;
  1391. break;
  1392. } else if (!gb_file_exists((const char *)path.text)) {
  1393. gb_printf_err("Invalid -resource path %.*s, file does not exist.\n", LIT(path));
  1394. bad_flags = true;
  1395. break;
  1396. }
  1397. build_context.resource_filepath = path;
  1398. build_context.has_resource = true;
  1399. } else {
  1400. gb_printf_err("Invalid -resource path, got %.*s\n", LIT(path));
  1401. bad_flags = true;
  1402. }
  1403. break;
  1404. }
  1405. case BuildFlag_WindowsPdbName: {
  1406. GB_ASSERT(value.kind == ExactValue_String);
  1407. String path = value.value_string;
  1408. path = string_trim_whitespace(path);
  1409. if (is_build_flag_path_valid(path)) {
  1410. if (path_is_directory(path)) {
  1411. gb_printf_err("Invalid -pdb-name path. %.*s, is a directory.\n", LIT(path));
  1412. bad_flags = true;
  1413. break;
  1414. }
  1415. // #if defined(GB_SYSTEM_WINDOWS)
  1416. // String ext = path_extension(path);
  1417. // if (ext != ".pdb") {
  1418. // path = substring(path, 0, string_extension_position(path));
  1419. // }
  1420. // #endif
  1421. build_context.pdb_filepath = path;
  1422. } else {
  1423. gb_printf_err("Invalid -pdb-name path, got %.*s\n", LIT(path));
  1424. bad_flags = true;
  1425. }
  1426. break;
  1427. }
  1428. case BuildFlag_Subsystem: {
  1429. GB_ASSERT(value.kind == ExactValue_String);
  1430. String subsystem = value.value_string;
  1431. if (str_eq_ignore_case(subsystem, str_lit("console"))) {
  1432. build_context.use_subsystem_windows = false;
  1433. } else if (str_eq_ignore_case(subsystem, str_lit("window"))) {
  1434. build_context.use_subsystem_windows = true;
  1435. } else if (str_eq_ignore_case(subsystem, str_lit("windows"))) {
  1436. build_context.use_subsystem_windows = true;
  1437. } else {
  1438. gb_printf_err("Invalid -subsystem string, got %.*s, expected either 'console' or 'windows'\n", LIT(subsystem));
  1439. bad_flags = true;
  1440. }
  1441. break;
  1442. }
  1443. #endif
  1444. }
  1445. }
  1446. if (!bf.allow_mulitple) {
  1447. set_flags[bf.kind] = ok;
  1448. }
  1449. }
  1450. break;
  1451. }
  1452. }
  1453. if (found && !is_supported) {
  1454. gb_printf_err("Unknown flag for 'odin %.*s': '%.*s'\n", LIT(build_context.command), LIT(name));
  1455. gb_printf_err("'%.*s' is supported with the following commands:\n", LIT(name));
  1456. gb_printf_err("\t");
  1457. i32 count = 0;
  1458. for (u32 i = 0; i < 32; i++) {
  1459. if (found_bf.command_support & (1<<i)) {
  1460. if (count > 0) {
  1461. gb_printf_err(", ");
  1462. }
  1463. gb_printf_err("%s", odin_command_strings[i]);
  1464. count += 1;
  1465. }
  1466. }
  1467. gb_printf_err("\n");
  1468. bad_flags = true;
  1469. } else if (!found) {
  1470. did_you_mean_flag(name);
  1471. bad_flags = true;
  1472. }
  1473. }
  1474. if ((!(build_context.export_timings_format == TimingsExportUnspecified)) && (build_context.export_timings_file.len == 0)) {
  1475. gb_printf_err("`-export-timings:<format>` requires `-export-timings-file:<filename>` to be specified as well\n");
  1476. bad_flags = true;
  1477. } else if ((build_context.export_timings_format == TimingsExportUnspecified) && (build_context.export_timings_file.len > 0)) {
  1478. gb_printf_err("`-export-timings-file:<filename>` requires `-export-timings:<format>` to be specified as well\n");
  1479. bad_flags = true;
  1480. }
  1481. if (build_context.export_timings_format && !(build_context.show_timings || build_context.show_more_timings)) {
  1482. gb_printf_err("`-export-timings:<format>` requires `-show-timings` or `-show-more-timings` to be present\n");
  1483. bad_flags = true;
  1484. }
  1485. return !bad_flags;
  1486. }
  1487. gb_internal void timings_export_all(Timings *t, Checker *c, bool timings_are_finalized = false) {
  1488. GB_ASSERT((!(build_context.export_timings_format == TimingsExportUnspecified) && build_context.export_timings_file.len > 0));
  1489. /*
  1490. NOTE(Jeroen): Whether we call `timings_print_all()`, then `timings_export_all()`, the other way around,
  1491. or just one of them, we only need to stop the clock once.
  1492. */
  1493. if (!timings_are_finalized) {
  1494. timings__stop_current_section(t);
  1495. t->total.finish = time_stamp_time_now();
  1496. }
  1497. TimingUnit unit = TimingUnit_Millisecond;
  1498. /*
  1499. Prepare file for export.
  1500. */
  1501. gbFile f = {};
  1502. char * fileName = (char *)build_context.export_timings_file.text;
  1503. gbFileError err = gb_file_open_mode(&f, gbFileMode_Write, fileName);
  1504. if (err != gbFileError_None) {
  1505. gb_printf_err("Failed to export timings to: %s\n", fileName);
  1506. gb_exit(1);
  1507. return;
  1508. } else {
  1509. gb_printf("\nExporting timings to '%s'... ", fileName);
  1510. }
  1511. defer (gb_file_close(&f));
  1512. if (build_context.export_timings_format == TimingsExportJson) {
  1513. /*
  1514. JSON export
  1515. */
  1516. Parser *p = c->parser;
  1517. isize lines = p->total_line_count;
  1518. isize tokens = p->total_token_count;
  1519. isize files = 0;
  1520. isize packages = p->packages.count;
  1521. isize total_file_size = 0;
  1522. for (AstPackage *pkg : p->packages) {
  1523. files += pkg->files.count;
  1524. for (AstFile *file : pkg->files) {
  1525. total_file_size += file->tokenizer.end - file->tokenizer.start;
  1526. }
  1527. }
  1528. gb_fprintf(&f, "{\n");
  1529. gb_fprintf(&f, "\t\"totals\": [\n");
  1530. gb_fprintf(&f, "\t\t{\"name\": \"total_packages\", \"count\": %td},\n", packages);
  1531. gb_fprintf(&f, "\t\t{\"name\": \"total_files\", \"count\": %td},\n", files);
  1532. gb_fprintf(&f, "\t\t{\"name\": \"total_lines\", \"count\": %td},\n", lines);
  1533. gb_fprintf(&f, "\t\t{\"name\": \"total_tokens\", \"count\": %td},\n", tokens);
  1534. gb_fprintf(&f, "\t\t{\"name\": \"total_file_size\", \"count\": %td},\n", total_file_size);
  1535. gb_fprintf(&f, "\t],\n");
  1536. gb_fprintf(&f, "\t\"timings\": [\n");
  1537. t->total_time_seconds = time_stamp_as_s(t->total, t->freq);
  1538. f64 total_time = time_stamp(t->total, t->freq, unit);
  1539. gb_fprintf(&f, "\t\t{\"name\": \"%.*s\", \"millis\": %.3f},\n",
  1540. LIT(t->total.label), total_time);
  1541. for (TimeStamp const &ts : t->sections) {
  1542. f64 section_time = time_stamp(ts, t->freq, unit);
  1543. gb_fprintf(&f, "\t\t{\"name\": \"%.*s\", \"millis\": %.3f},\n",
  1544. LIT(ts.label), section_time);
  1545. }
  1546. gb_fprintf(&f, "\t],\n");
  1547. gb_fprintf(&f, "}\n");
  1548. } else if (build_context.export_timings_format == TimingsExportCSV) {
  1549. /*
  1550. CSV export
  1551. */
  1552. t->total_time_seconds = time_stamp_as_s(t->total, t->freq);
  1553. f64 total_time = time_stamp(t->total, t->freq, unit);
  1554. /*
  1555. CSV doesn't really like floating point values. Cast to `int`.
  1556. */
  1557. gb_fprintf(&f, "\"%.*s\", %d\n", LIT(t->total.label), int(total_time));
  1558. for (TimeStamp const &ts : t->sections) {
  1559. f64 section_time = time_stamp(ts, t->freq, unit);
  1560. gb_fprintf(&f, "\"%.*s\", %d\n", LIT(ts.label), int(section_time));
  1561. }
  1562. }
  1563. gb_printf("Done.\n");
  1564. }
  1565. gb_internal void show_timings(Checker *c, Timings *t) {
  1566. Parser *p = c->parser;
  1567. isize lines = p->total_line_count;
  1568. isize tokens = p->total_token_count;
  1569. isize files = 0;
  1570. isize packages = p->packages.count;
  1571. isize total_file_size = 0;
  1572. f64 total_tokenizing_time = 0;
  1573. f64 total_parsing_time = 0;
  1574. for (AstPackage *pkg : p->packages) {
  1575. files += pkg->files.count;
  1576. for (AstFile *file : pkg->files) {
  1577. total_tokenizing_time += file->time_to_tokenize;
  1578. total_parsing_time += file->time_to_parse;
  1579. total_file_size += file->tokenizer.end - file->tokenizer.start;
  1580. }
  1581. }
  1582. timings_print_all(t);
  1583. PRINT_PEAK_USAGE();
  1584. if (!(build_context.export_timings_format == TimingsExportUnspecified)) {
  1585. timings_export_all(t, c, true);
  1586. }
  1587. if (build_context.show_debug_messages && build_context.show_more_timings) {
  1588. {
  1589. gb_printf("\n");
  1590. gb_printf("Total Lines - %td\n", lines);
  1591. gb_printf("Total Tokens - %td\n", tokens);
  1592. gb_printf("Total Files - %td\n", files);
  1593. gb_printf("Total Packages - %td\n", packages);
  1594. gb_printf("Total File Size - %td\n", total_file_size);
  1595. gb_printf("\n");
  1596. }
  1597. {
  1598. f64 time = total_tokenizing_time;
  1599. gb_printf("Tokenization Only\n");
  1600. gb_printf("LOC/s - %.3f\n", cast(f64)lines/time);
  1601. gb_printf("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines);
  1602. gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/time);
  1603. gb_printf("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens);
  1604. gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/time);
  1605. gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024));
  1606. gb_printf("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size);
  1607. gb_printf("\n");
  1608. }
  1609. {
  1610. f64 time = total_parsing_time;
  1611. gb_printf("Parsing Only\n");
  1612. gb_printf("LOC/s - %.3f\n", cast(f64)lines/time);
  1613. gb_printf("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines);
  1614. gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/time);
  1615. gb_printf("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens);
  1616. gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/time);
  1617. gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024));
  1618. gb_printf("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size);
  1619. gb_printf("\n");
  1620. }
  1621. {
  1622. TimeStamp ts = {};
  1623. for (TimeStamp const &s : t->sections) {
  1624. if (s.label == "parse files") {
  1625. ts = s;
  1626. break;
  1627. }
  1628. }
  1629. GB_ASSERT(ts.label == "parse files");
  1630. f64 parse_time = time_stamp_as_s(ts, t->freq);
  1631. gb_printf("Parse pass\n");
  1632. gb_printf("LOC/s - %.3f\n", cast(f64)lines/parse_time);
  1633. gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
  1634. gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
  1635. gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
  1636. gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
  1637. gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/parse_time)/(1024*1024));
  1638. gb_printf("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
  1639. gb_printf("\n");
  1640. }
  1641. {
  1642. TimeStamp ts = {};
  1643. TimeStamp ts_end = {};
  1644. for (TimeStamp const &s : t->sections) {
  1645. if (s.label == "type check") {
  1646. ts = s;
  1647. }
  1648. if (s.label == "type check finish") {
  1649. GB_ASSERT(ts.label != "");
  1650. ts_end = s;
  1651. break;
  1652. }
  1653. }
  1654. GB_ASSERT(ts.label != "");
  1655. GB_ASSERT(ts_end.label != "");
  1656. ts.finish = ts_end.finish;
  1657. f64 parse_time = time_stamp_as_s(ts, t->freq);
  1658. gb_printf("Checker pass\n");
  1659. gb_printf("LOC/s - %.3f\n", cast(f64)lines/parse_time);
  1660. gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
  1661. gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
  1662. gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
  1663. gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
  1664. gb_printf("MiB/s - %.3f\n", (cast(f64)total_file_size/parse_time)/(1024*1024));
  1665. gb_printf("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
  1666. gb_printf("\n");
  1667. }
  1668. {
  1669. f64 total_time = t->total_time_seconds;
  1670. gb_printf("Total pass\n");
  1671. gb_printf("LOC/s - %.3f\n", cast(f64)lines/total_time);
  1672. gb_printf("us/LOC - %.3f\n", 1.0e6*total_time/cast(f64)lines);
  1673. gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/total_time);
  1674. gb_printf("us/Token - %.3f\n", 1.0e6*total_time/cast(f64)tokens);
  1675. gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/total_time);
  1676. gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/total_time)/(1024*1024));
  1677. gb_printf("us/bytes - %.3f\n", 1.0e6*total_time/cast(f64)total_file_size);
  1678. gb_printf("\n");
  1679. }
  1680. }
  1681. }
  1682. gb_internal void remove_temp_files(lbGenerator *gen) {
  1683. if (build_context.keep_temp_files) return;
  1684. switch (build_context.build_mode) {
  1685. case BuildMode_Executable:
  1686. case BuildMode_DynamicLibrary:
  1687. break;
  1688. case BuildMode_Object:
  1689. case BuildMode_Assembly:
  1690. case BuildMode_LLVM_IR:
  1691. return;
  1692. }
  1693. TIME_SECTION("remove keep temp files");
  1694. for (String const &path : gen->output_temp_paths) {
  1695. gb_file_remove(cast(char const *)path.text);
  1696. }
  1697. if (!build_context.keep_object_files) {
  1698. switch (build_context.build_mode) {
  1699. case BuildMode_Executable:
  1700. case BuildMode_DynamicLibrary:
  1701. for (String const &path : gen->output_object_paths) {
  1702. gb_file_remove(cast(char const *)path.text);
  1703. }
  1704. break;
  1705. }
  1706. }
  1707. }
  1708. gb_internal void print_show_help(String const arg0, String const &command) {
  1709. print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(arg0));
  1710. print_usage_line(0, "Usage:");
  1711. print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command));
  1712. print_usage_line(0, "");
  1713. if (command == "build") {
  1714. print_usage_line(1, "build Compile directory of .odin files as an executable.");
  1715. print_usage_line(2, "One must contain the program's entry point, all must be in the same package.");
  1716. print_usage_line(2, "Use `-file` to build a single file instead.");
  1717. print_usage_line(2, "Examples:");
  1718. print_usage_line(3, "odin build . # Build package in current directory");
  1719. print_usage_line(3, "odin build <dir> # Build package in <dir>");
  1720. print_usage_line(3, "odin build filename.odin -file # Build single-file package, must contain entry point.");
  1721. } else if (command == "run") {
  1722. print_usage_line(1, "run Same as 'build', but also then runs the newly compiled executable.");
  1723. print_usage_line(2, "Append an empty flag and then the args, '-- <args>', to specify args for the output.");
  1724. print_usage_line(2, "Examples:");
  1725. print_usage_line(3, "odin run . # Build and run package in current directory");
  1726. print_usage_line(3, "odin run <dir> # Build and run package in <dir>");
  1727. print_usage_line(3, "odin run filename.odin -file # Build and run single-file package, must contain entry point.");
  1728. } else if (command == "check") {
  1729. print_usage_line(1, "check Parse and type check directory of .odin files");
  1730. print_usage_line(2, "Examples:");
  1731. print_usage_line(3, "odin check . # Type check package in current directory");
  1732. print_usage_line(3, "odin check <dir> # Type check package in <dir>");
  1733. print_usage_line(3, "odin check filename.odin -file # Type check single-file package, must contain entry point.");
  1734. } else if (command == "test") {
  1735. print_usage_line(1, "test Build and runs procedures with the attribute @(test) in the initial package");
  1736. } else if (command == "doc") {
  1737. print_usage_line(1, "doc generate documentation from a directory of .odin files");
  1738. print_usage_line(2, "Examples:");
  1739. print_usage_line(3, "odin doc . # Generate documentation on package in current directory");
  1740. print_usage_line(3, "odin doc <dir> # Generate documentation on package in <dir>");
  1741. print_usage_line(3, "odin doc filename.odin -file # Generate documentation on single-file package.");
  1742. } else if (command == "version") {
  1743. print_usage_line(1, "version print version");
  1744. } else if (command == "strip-semicolon") {
  1745. print_usage_line(1, "strip-semicolon");
  1746. print_usage_line(2, "Parse and type check .odin file(s) and then remove unneeded semicolons from the entire project");
  1747. }
  1748. bool doc = command == "doc";
  1749. bool build = command == "build";
  1750. bool run_or_build = command == "run" || command == "build" || command == "test";
  1751. bool test_only = command == "test";
  1752. bool strip_semicolon = command == "strip-semicolon";
  1753. bool check_only = command == "check" || strip_semicolon;
  1754. bool check = run_or_build || check_only;
  1755. print_usage_line(0, "");
  1756. print_usage_line(1, "Flags");
  1757. print_usage_line(0, "");
  1758. if (check) {
  1759. print_usage_line(1, "-file");
  1760. print_usage_line(2, "Tells `%.*s %.*s` to treat the given file as a self-contained package.", LIT(arg0), LIT(command));
  1761. print_usage_line(2, "This means that `<dir>/a.odin` won't have access to `<dir>/b.odin`'s contents.");
  1762. print_usage_line(0, "");
  1763. }
  1764. if (doc) {
  1765. print_usage_line(1, "-short");
  1766. print_usage_line(2, "Show shortened documentation for the packages");
  1767. print_usage_line(0, "");
  1768. print_usage_line(1, "-all-packages");
  1769. print_usage_line(2, "Generates documentation for all packages used in the current project");
  1770. print_usage_line(0, "");
  1771. print_usage_line(1, "-doc-format");
  1772. print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling)");
  1773. print_usage_line(0, "");
  1774. }
  1775. if (run_or_build) {
  1776. print_usage_line(1, "-out:<filepath>");
  1777. print_usage_line(2, "Set the file name of the outputted executable");
  1778. print_usage_line(2, "Example: -out:foo.exe");
  1779. print_usage_line(0, "");
  1780. print_usage_line(1, "-o:<string>");
  1781. print_usage_line(2, "Set the optimization mode for compilation");
  1782. print_usage_line(2, "Accepted values: minimal, size, speed, none");
  1783. print_usage_line(2, "Example: -o:speed");
  1784. print_usage_line(0, "");
  1785. }
  1786. if (check) {
  1787. print_usage_line(1, "-show-timings");
  1788. print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds");
  1789. print_usage_line(0, "");
  1790. print_usage_line(1, "-show-more-timings");
  1791. print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds");
  1792. print_usage_line(0, "");
  1793. print_usage_line(1, "-export-timings:<format>");
  1794. print_usage_line(2, "Export timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`");
  1795. print_usage_line(2, "Available options:");
  1796. print_usage_line(3, "-export-timings:json Export compile time stats to JSON");
  1797. print_usage_line(3, "-export-timings:csv Export compile time stats to CSV");
  1798. print_usage_line(0, "");
  1799. print_usage_line(1, "-export-timings-file:<filename>");
  1800. print_usage_line(2, "Specify the filename for `-export-timings`");
  1801. print_usage_line(2, "Example: -export-timings-file:timings.json");
  1802. print_usage_line(0, "");
  1803. print_usage_line(1, "-thread-count:<integer>");
  1804. print_usage_line(2, "Override the number of threads the compiler will use to compile with");
  1805. print_usage_line(2, "Example: -thread-count:2");
  1806. print_usage_line(0, "");
  1807. }
  1808. if (check_only) {
  1809. print_usage_line(1, "-show-unused");
  1810. print_usage_line(2, "Shows unused package declarations within the current project");
  1811. print_usage_line(0, "");
  1812. print_usage_line(1, "-show-unused-with-location");
  1813. print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location");
  1814. print_usage_line(0, "");
  1815. }
  1816. if (run_or_build) {
  1817. print_usage_line(1, "-keep-temp-files");
  1818. print_usage_line(2, "Keeps the temporary files generated during compilation");
  1819. print_usage_line(0, "");
  1820. } else if (strip_semicolon) {
  1821. print_usage_line(1, "-keep-temp-files");
  1822. print_usage_line(2, "Keeps the temporary files generated during stripping the unneeded semicolons from files");
  1823. print_usage_line(0, "");
  1824. }
  1825. if (check) {
  1826. print_usage_line(1, "-collection:<name>=<filepath>");
  1827. print_usage_line(2, "Defines a library collection used for imports");
  1828. print_usage_line(2, "Example: -collection:shared=dir/to/shared");
  1829. print_usage_line(2, "Usage in Code:");
  1830. print_usage_line(3, "import \"shared:foo\"");
  1831. print_usage_line(0, "");
  1832. print_usage_line(1, "-define:<name>=<value>");
  1833. print_usage_line(2, "Defines a scalar boolean, integer or string as global constant");
  1834. print_usage_line(2, "Example: -define:SPAM=123");
  1835. print_usage_line(2, "To use: #config(SPAM, default_value)");
  1836. print_usage_line(0, "");
  1837. }
  1838. if (build) {
  1839. print_usage_line(1, "-build-mode:<mode>");
  1840. print_usage_line(2, "Sets the build mode");
  1841. print_usage_line(2, "Available options:");
  1842. print_usage_line(3, "-build-mode:exe Build as an executable");
  1843. print_usage_line(3, "-build-mode:dll Build as a dynamically linked library");
  1844. print_usage_line(3, "-build-mode:shared Build as a dynamically linked library");
  1845. print_usage_line(3, "-build-mode:obj Build as an object file");
  1846. print_usage_line(3, "-build-mode:object Build as an object file");
  1847. print_usage_line(3, "-build-mode:assembly Build as an assembly file");
  1848. print_usage_line(3, "-build-mode:assembler Build as an assembly file");
  1849. print_usage_line(3, "-build-mode:asm Build as an assembly file");
  1850. print_usage_line(3, "-build-mode:llvm-ir Build as an LLVM IR file");
  1851. print_usage_line(3, "-build-mode:llvm Build as an LLVM IR file");
  1852. print_usage_line(0, "");
  1853. }
  1854. if (check) {
  1855. print_usage_line(1, "-target:<string>");
  1856. print_usage_line(2, "Sets the target for the executable to be built in");
  1857. print_usage_line(0, "");
  1858. }
  1859. if (run_or_build) {
  1860. print_usage_line(1, "-debug");
  1861. print_usage_line(2, "Enabled debug information, and defines the global constant ODIN_DEBUG to be 'true'");
  1862. print_usage_line(0, "");
  1863. print_usage_line(1, "-disable-assert");
  1864. print_usage_line(2, "Disable the code generation of the built-in run-time 'assert' procedure, and defines the global constant ODIN_DISABLE_ASSERT to be 'true'");
  1865. print_usage_line(0, "");
  1866. print_usage_line(1, "-no-bounds-check");
  1867. print_usage_line(2, "Disables bounds checking program wide");
  1868. print_usage_line(0, "");
  1869. print_usage_line(1, "-no-crt");
  1870. print_usage_line(2, "Disables automatic linking with the C Run Time");
  1871. print_usage_line(0, "");
  1872. print_usage_line(1, "-no-thread-local");
  1873. print_usage_line(2, "Ignore @thread_local attribute, effectively treating the program as if it is single-threaded");
  1874. print_usage_line(0, "");
  1875. print_usage_line(1, "-lld");
  1876. print_usage_line(2, "Use the LLD linker rather than the default");
  1877. print_usage_line(0, "");
  1878. print_usage_line(1, "-use-separate-modules");
  1879. print_usage_line(1, "[EXPERIMENTAL]");
  1880. print_usage_line(2, "The backend generates multiple build units which are then linked together");
  1881. print_usage_line(2, "Normally, a single build unit is generated for a standard project");
  1882. print_usage_line(0, "");
  1883. }
  1884. if (check) {
  1885. #if defined(GB_SYSTEM_WINDOWS)
  1886. print_usage_line(1, "-no-threaded-checker");
  1887. print_usage_line(2, "Disabled multithreading in the semantic checker stage");
  1888. print_usage_line(0, "");
  1889. #else
  1890. print_usage_line(1, "-threaded-checker");
  1891. print_usage_line(1, "[EXPERIMENTAL]");
  1892. print_usage_line(2, "Multithread the semantic checker stage");
  1893. print_usage_line(0, "");
  1894. #endif
  1895. print_usage_line(1, "-vet");
  1896. print_usage_line(2, "Do extra checks on the code");
  1897. print_usage_line(2, "Extra checks include:");
  1898. print_usage_line(3, "Variable shadowing within procedures");
  1899. print_usage_line(3, "Unused declarations");
  1900. print_usage_line(0, "");
  1901. print_usage_line(1, "-vet-extra");
  1902. print_usage_line(2, "Do even more checks than standard vet on the code");
  1903. print_usage_line(2, "To treat the extra warnings as errors, use -warnings-as-errors");
  1904. print_usage_line(0, "");
  1905. print_usage_line(1, "-ignore-unknown-attributes");
  1906. print_usage_line(2, "Ignores unknown attributes");
  1907. print_usage_line(2, "This can be used with metaprogramming tools");
  1908. print_usage_line(0, "");
  1909. if (command != "test") {
  1910. print_usage_line(1, "-no-entry-point");
  1911. print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure)");
  1912. print_usage_line(0, "");
  1913. }
  1914. }
  1915. if (test_only) {
  1916. print_usage_line(1, "-test-name:<string>");
  1917. print_usage_line(2, "Run specific test only by name");
  1918. print_usage_line(0, "");
  1919. }
  1920. if (run_or_build) {
  1921. print_usage_line(1, "-minimum-os-version:<string>");
  1922. print_usage_line(2, "Sets the minimum OS version targeted by the application");
  1923. print_usage_line(2, "e.g. -minimum-os-version:12.0.0");
  1924. print_usage_line(2, "(Only used when target is Darwin)");
  1925. print_usage_line(0, "");
  1926. print_usage_line(1, "-extra-linker-flags:<string>");
  1927. print_usage_line(2, "Adds extra linker specific flags in a string");
  1928. print_usage_line(0, "");
  1929. print_usage_line(1, "-extra-assembler-flags:<string>");
  1930. print_usage_line(2, "Adds extra assembler specific flags in a string");
  1931. print_usage_line(0, "");
  1932. print_usage_line(1, "-microarch:<string>");
  1933. print_usage_line(2, "Specifies the specific micro-architecture for the build in a string");
  1934. print_usage_line(2, "Examples:");
  1935. print_usage_line(3, "-microarch:sandybridge");
  1936. print_usage_line(3, "-microarch:native");
  1937. print_usage_line(0, "");
  1938. print_usage_line(1, "-reloc-mode:<string>");
  1939. print_usage_line(2, "Specifies the reloc mode");
  1940. print_usage_line(2, "Options:");
  1941. print_usage_line(3, "default");
  1942. print_usage_line(3, "static");
  1943. print_usage_line(3, "pic");
  1944. print_usage_line(3, "dynamic-no-pic");
  1945. print_usage_line(0, "");
  1946. print_usage_line(1, "-disable-red-zone");
  1947. print_usage_line(2, "Disable red zone on a supported freestanding target");
  1948. print_usage_line(0, "");
  1949. print_usage_line(1, "-dynamic-map-calls");
  1950. print_usage_line(2, "Use dynamic map calls to minimize code generation at the cost of runtime execution");
  1951. print_usage_line(0, "");
  1952. }
  1953. if (check) {
  1954. print_usage_line(1, "-disallow-do");
  1955. print_usage_line(2, "Disallows the 'do' keyword in the project");
  1956. print_usage_line(0, "");
  1957. print_usage_line(1, "-default-to-nil-allocator");
  1958. print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing");
  1959. print_usage_line(0, "");
  1960. print_usage_line(1, "-strict-style");
  1961. print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons");
  1962. print_usage_line(0, "");
  1963. print_usage_line(1, "-strict-style-init-only");
  1964. print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons, only on the initial project");
  1965. print_usage_line(0, "");
  1966. print_usage_line(1, "-ignore-warnings");
  1967. print_usage_line(2, "Ignores warning messages");
  1968. print_usage_line(0, "");
  1969. print_usage_line(1, "-warnings-as-errors");
  1970. print_usage_line(2, "Treats warning messages as error messages");
  1971. print_usage_line(0, "");
  1972. print_usage_line(1, "-terse-errors");
  1973. print_usage_line(2, "Prints a terse error message without showing the code on that line and the location in that line");
  1974. print_usage_line(0, "");
  1975. print_usage_line(1, "-error-pos-style:<string>");
  1976. print_usage_line(2, "Options are 'unix', 'odin' and 'default' (odin)");
  1977. print_usage_line(2, "'odin' file/path(45:3)");
  1978. print_usage_line(2, "'unix' file/path:45:3:");
  1979. print_usage_line(0, "");
  1980. print_usage_line(1, "-max-error-count:<integer>");
  1981. print_usage_line(2, "Set the maximum number of errors that can be displayed before the compiler terminates");
  1982. print_usage_line(2, "Must be an integer >0");
  1983. print_usage_line(2, "If not set, the default max error count is %d", DEFAULT_MAX_ERROR_COLLECTOR_COUNT);
  1984. print_usage_line(0, "");
  1985. print_usage_line(1, "-foreign-error-procedures");
  1986. print_usage_line(2, "States that the error procedues used in the runtime are defined in a separate translation unit");
  1987. print_usage_line(0, "");
  1988. }
  1989. if (run_or_build) {
  1990. #if defined(GB_SYSTEM_WINDOWS)
  1991. print_usage_line(1, "-ignore-vs-search");
  1992. print_usage_line(2, "[Windows only]");
  1993. print_usage_line(2, "Ignores the Visual Studio search for library paths");
  1994. print_usage_line(0, "");
  1995. print_usage_line(1, "-resource:<filepath>");
  1996. print_usage_line(2, "[Windows only]");
  1997. print_usage_line(2, "Defines the resource file for the executable");
  1998. print_usage_line(2, "Example: -resource:path/to/file.rc");
  1999. print_usage_line(0, "");
  2000. print_usage_line(1, "-pdb-name:<filepath>");
  2001. print_usage_line(2, "[Windows only]");
  2002. print_usage_line(2, "Defines the generated PDB name when -debug is enabled");
  2003. print_usage_line(2, "Example: -pdb-name:different.pdb");
  2004. print_usage_line(0, "");
  2005. print_usage_line(1, "-subsystem:<option>");
  2006. print_usage_line(2, "[Windows only]");
  2007. print_usage_line(2, "Defines the subsystem for the application");
  2008. print_usage_line(2, "Available options:");
  2009. print_usage_line(3, "console");
  2010. print_usage_line(3, "windows");
  2011. print_usage_line(0, "");
  2012. #endif
  2013. }
  2014. }
  2015. gb_internal void print_show_unused(Checker *c) {
  2016. CheckerInfo *info = &c->info;
  2017. auto unused = array_make<Entity *>(permanent_allocator(), 0, info->entities.count);
  2018. for (Entity *e : info->entities) {
  2019. if (e == nullptr) {
  2020. continue;
  2021. }
  2022. if (e->pkg == nullptr || e->pkg->scope == nullptr) {
  2023. continue;
  2024. }
  2025. if (e->pkg->scope->flags & ScopeFlag_Builtin) {
  2026. continue;
  2027. }
  2028. switch (e->kind) {
  2029. case Entity_Invalid:
  2030. case Entity_Builtin:
  2031. case Entity_Nil:
  2032. case Entity_Label:
  2033. continue;
  2034. case Entity_Constant:
  2035. case Entity_Variable:
  2036. case Entity_TypeName:
  2037. case Entity_Procedure:
  2038. case Entity_ProcGroup:
  2039. case Entity_ImportName:
  2040. case Entity_LibraryName:
  2041. // Fine
  2042. break;
  2043. }
  2044. if ((e->scope->flags & (ScopeFlag_Pkg|ScopeFlag_File)) == 0) {
  2045. continue;
  2046. }
  2047. if (e->token.string.len == 0) {
  2048. continue;
  2049. }
  2050. if (e->token.string == "_") {
  2051. continue;
  2052. }
  2053. if (ptr_set_exists(&info->minimum_dependency_set, e)) {
  2054. continue;
  2055. }
  2056. array_add(&unused, e);
  2057. }
  2058. gb_sort_array(unused.data, unused.count, cmp_entities_for_printing);
  2059. print_usage_line(0, "Unused Package Declarations");
  2060. AstPackage *curr_pkg = nullptr;
  2061. EntityKind curr_entity_kind = Entity_Invalid;
  2062. for (Entity *e : unused) {
  2063. if (curr_pkg != e->pkg) {
  2064. curr_pkg = e->pkg;
  2065. curr_entity_kind = Entity_Invalid;
  2066. print_usage_line(0, "");
  2067. print_usage_line(0, "package %.*s", LIT(curr_pkg->name));
  2068. }
  2069. if (curr_entity_kind != e->kind) {
  2070. curr_entity_kind = e->kind;
  2071. print_usage_line(1, "%s", print_entity_names[e->kind]);
  2072. }
  2073. if (build_context.show_unused_with_location) {
  2074. TokenPos pos = e->token.pos;
  2075. print_usage_line(2, "%s %.*s", token_pos_to_string(pos), LIT(e->token.string));
  2076. } else {
  2077. print_usage_line(2, "%.*s", LIT(e->token.string));
  2078. }
  2079. }
  2080. print_usage_line(0, "");
  2081. }
  2082. gb_internal bool check_env(void) {
  2083. gbAllocator a = heap_allocator();
  2084. char const *odin_root = gb_get_env("ODIN_ROOT", a);
  2085. defer (gb_free(a, cast(void *)odin_root));
  2086. if (odin_root) {
  2087. if (!gb_file_exists(odin_root)) {
  2088. gb_printf_err("Invalid ODIN_ROOT, directory does not exist, got %s\n", odin_root);
  2089. return false;
  2090. }
  2091. String path = make_string_c(odin_root);
  2092. if (!path_is_directory(path)) {
  2093. gb_printf_err("Invalid ODIN_ROOT, expected a directory, got %s\n", odin_root);
  2094. return false;
  2095. }
  2096. }
  2097. return true;
  2098. }
  2099. struct StripSemicolonFile {
  2100. String old_fullpath;
  2101. String old_fullpath_backup;
  2102. String new_fullpath;
  2103. AstFile *file;
  2104. i64 written;
  2105. };
  2106. gb_internal gbFileError write_file_with_stripped_tokens(gbFile *f, AstFile *file, i64 *written_) {
  2107. i64 written = 0;
  2108. gbFileError err = gbFileError_None;
  2109. u8 const *file_data = file->tokenizer.start;
  2110. i32 prev_offset = 0;
  2111. i32 const end_offset = cast(i32)(file->tokenizer.end - file->tokenizer.start);
  2112. for (Token const &token : file->tokens) {
  2113. if (token.flags & (TokenFlag_Remove|TokenFlag_Replace)) {
  2114. i32 offset = token.pos.offset;
  2115. i32 to_write = offset-prev_offset;
  2116. if (!gb_file_write(f, file_data+prev_offset, to_write)) {
  2117. return gbFileError_Invalid;
  2118. }
  2119. written += to_write;
  2120. prev_offset = token_pos_end(token).offset;
  2121. }
  2122. if (token.flags & TokenFlag_Replace) {
  2123. if (token.kind == Token_Ellipsis) {
  2124. if (!gb_file_write(f, "..=", 3)) {
  2125. return gbFileError_Invalid;
  2126. }
  2127. written += 3;
  2128. } else {
  2129. return gbFileError_Invalid;
  2130. }
  2131. }
  2132. }
  2133. if (end_offset > prev_offset) {
  2134. i32 to_write = end_offset-prev_offset;
  2135. if (!gb_file_write(f, file_data+prev_offset, end_offset-prev_offset)) {
  2136. return gbFileError_Invalid;
  2137. }
  2138. written += to_write;
  2139. }
  2140. if (written_) *written_ = written;
  2141. return err;
  2142. }
  2143. gb_internal int strip_semicolons(Parser *parser) {
  2144. isize file_count = 0;
  2145. for (AstPackage *pkg : parser->packages) {
  2146. file_count += pkg->files.count;
  2147. }
  2148. auto generated_files = array_make<StripSemicolonFile>(permanent_allocator(), 0, file_count);
  2149. for (AstPackage *pkg : parser->packages) {
  2150. for (AstFile *file : pkg->files) {
  2151. bool nothing_to_change = true;
  2152. for (Token const &token : file->tokens) {
  2153. if (token.flags) {
  2154. nothing_to_change = false;
  2155. break;
  2156. }
  2157. }
  2158. if (nothing_to_change) {
  2159. continue;
  2160. }
  2161. String old_fullpath = copy_string(permanent_allocator(), file->fullpath);
  2162. // assumes .odin extension
  2163. String fullpath_base = substring(old_fullpath, 0, old_fullpath.len-5);
  2164. String old_fullpath_backup = concatenate_strings(permanent_allocator(), fullpath_base, str_lit("~backup.odin-temp"));
  2165. String new_fullpath = concatenate_strings(permanent_allocator(), fullpath_base, str_lit("~temp.odin-temp"));
  2166. array_add(&generated_files, StripSemicolonFile{old_fullpath, old_fullpath_backup, new_fullpath, file});
  2167. }
  2168. }
  2169. gb_printf_err("File count to be stripped of unneeded tokens: %td\n", generated_files.count);
  2170. isize generated_count = 0;
  2171. bool failed = false;
  2172. for (StripSemicolonFile &file : generated_files) {
  2173. char const *filename = cast(char const *)file.new_fullpath.text;
  2174. gbFileError err = gbFileError_None;
  2175. defer (if (err != gbFileError_None) {
  2176. failed = true;
  2177. });
  2178. gbFile f = {};
  2179. err = gb_file_create(&f, filename);
  2180. if (err) {
  2181. break;
  2182. }
  2183. defer (err = gb_file_close(&f));
  2184. generated_count += 1;
  2185. i64 written = 0;
  2186. defer (err = gb_file_truncate(&f, written));
  2187. debugf("Write file with stripped tokens: %s\n", filename);
  2188. err = write_file_with_stripped_tokens(&f, file.file, &written);
  2189. if (err) {
  2190. break;
  2191. }
  2192. file.written = written;
  2193. }
  2194. if (failed) {
  2195. for (isize i = 0; i < generated_count; i++) {
  2196. auto *file = &generated_files[i];
  2197. char const *filename = nullptr;
  2198. filename = cast(char const *)file->new_fullpath.text;
  2199. GB_ASSERT_MSG(gb_file_remove(filename), "unable to delete file %s", filename);
  2200. }
  2201. return 1;
  2202. }
  2203. isize overwritten_files = 0;
  2204. for (StripSemicolonFile const &file : generated_files) {
  2205. char const *old_fullpath = cast(char const *)file.old_fullpath.text;
  2206. char const *old_fullpath_backup = cast(char const *)file.old_fullpath_backup.text;
  2207. char const *new_fullpath = cast(char const *)file.new_fullpath.text;
  2208. debugf("Copy '%s' to '%s'\n", old_fullpath, old_fullpath_backup);
  2209. if (!gb_file_copy(old_fullpath, old_fullpath_backup, false)) {
  2210. gb_printf_err("failed to copy '%s' to '%s'\n", old_fullpath, old_fullpath_backup);
  2211. failed = true;
  2212. break;
  2213. }
  2214. debugf("Copy '%s' to '%s'\n", new_fullpath, old_fullpath);
  2215. if (!gb_file_copy(new_fullpath, old_fullpath, false)) {
  2216. gb_printf_err("failed to copy '%s' to '%s'\n", old_fullpath, new_fullpath);
  2217. debugf("Copy '%s' to '%s'\n", old_fullpath_backup, old_fullpath);
  2218. if (!gb_file_copy(old_fullpath_backup, old_fullpath, false)) {
  2219. gb_printf_err("failed to restore '%s' from '%s'\n", old_fullpath, old_fullpath_backup);
  2220. }
  2221. failed = true;
  2222. break;
  2223. }
  2224. debugf("Remove '%s'\n", old_fullpath_backup);
  2225. if (!gb_file_remove(old_fullpath_backup)) {
  2226. gb_printf_err("failed to remove '%s'\n", old_fullpath_backup);
  2227. }
  2228. overwritten_files++;
  2229. }
  2230. if (!build_context.keep_temp_files) {
  2231. for_array(i, generated_files) {
  2232. auto *file = &generated_files[i];
  2233. char const *filename = nullptr;
  2234. filename = cast(char const *)file->new_fullpath.text;
  2235. debugf("Remove '%s'\n", filename);
  2236. GB_ASSERT_MSG(gb_file_remove(filename), "unable to delete file %s", filename);
  2237. filename = cast(char const *)file->old_fullpath_backup.text;
  2238. debugf("Remove '%s'\n", filename);
  2239. if (gb_file_exists(filename) && !gb_file_remove(filename)) {
  2240. if (i < overwritten_files) {
  2241. gb_printf_err("unable to delete file %s", filename);
  2242. failed = true;
  2243. }
  2244. }
  2245. }
  2246. }
  2247. gb_printf_err("Files stripped of unneeded token: %td\n", generated_files.count);
  2248. return cast(int)failed;
  2249. }
  2250. gb_internal void init_terminal(void) {
  2251. build_context.has_ansi_terminal_colours = false;
  2252. #if defined(GB_SYSTEM_WINDOWS)
  2253. HANDLE hnd = GetStdHandle(STD_ERROR_HANDLE);
  2254. DWORD mode = 0;
  2255. if (GetConsoleMode(hnd, &mode)) {
  2256. enum {FLAG_ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004};
  2257. if (SetConsoleMode(hnd, mode|FLAG_ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
  2258. build_context.has_ansi_terminal_colours = true;
  2259. }
  2260. }
  2261. #endif
  2262. if (!build_context.has_ansi_terminal_colours) {
  2263. gbAllocator a = heap_allocator();
  2264. char const *odin_terminal_ = gb_get_env("ODIN_TERMINAL", a);
  2265. defer (gb_free(a, cast(void *)odin_terminal_));
  2266. String odin_terminal = make_string_c(odin_terminal_);
  2267. if (str_eq_ignore_case(odin_terminal, str_lit("ansi"))) {
  2268. build_context.has_ansi_terminal_colours = true;
  2269. }
  2270. }
  2271. }
  2272. int main(int arg_count, char const **arg_ptr) {
  2273. if (arg_count < 2) {
  2274. usage(make_string_c(arg_ptr[0]));
  2275. return 1;
  2276. }
  2277. virtual_memory_init();
  2278. timings_init(&global_timings, str_lit("Total Time"), 2048);
  2279. defer (timings_destroy(&global_timings));
  2280. MAIN_TIME_SECTION("initialization");
  2281. init_string_interner();
  2282. init_global_error_collector();
  2283. init_keyword_hash_table();
  2284. init_terminal();
  2285. if (!check_env()) {
  2286. return 1;
  2287. }
  2288. array_init(&library_collections, heap_allocator());
  2289. // NOTE(bill): 'core' cannot be (re)defined by the user
  2290. add_library_collection(str_lit("core"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("core")));
  2291. add_library_collection(str_lit("vendor"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("vendor")));
  2292. map_init(&build_context.defined_values);
  2293. build_context.extra_packages.allocator = heap_allocator();
  2294. string_set_init(&build_context.test_names);
  2295. Array<String> args = setup_args(arg_count, arg_ptr);
  2296. String command = args[1];
  2297. String init_filename = {};
  2298. String run_args_string = {};
  2299. isize last_non_run_arg = args.count;
  2300. bool run_output = false;
  2301. if (command == "run" || command == "test") {
  2302. if (args.count < 3) {
  2303. usage(args[0]);
  2304. return 1;
  2305. }
  2306. build_context.command_kind = Command_run;
  2307. if (command == "test") {
  2308. build_context.command_kind = Command_test;
  2309. }
  2310. Array<String> run_args = array_make<String>(heap_allocator(), 0, arg_count);
  2311. defer (array_free(&run_args));
  2312. for_array(i, args) {
  2313. if (args[i] == "--") {
  2314. last_non_run_arg = i;
  2315. }
  2316. if (i <= last_non_run_arg) {
  2317. continue;
  2318. }
  2319. array_add(&run_args, args[i]);
  2320. }
  2321. args = array_slice(args, 0, last_non_run_arg);
  2322. run_args_string = string_join_and_quote(heap_allocator(), run_args);
  2323. init_filename = args[2];
  2324. run_output = true;
  2325. } else if (command == "build") {
  2326. if (args.count < 3) {
  2327. usage(args[0]);
  2328. return 1;
  2329. }
  2330. build_context.command_kind = Command_build;
  2331. init_filename = args[2];
  2332. } else if (command == "check") {
  2333. if (args.count < 3) {
  2334. usage(args[0]);
  2335. return 1;
  2336. }
  2337. build_context.command_kind = Command_check;
  2338. build_context.no_output_files = true;
  2339. init_filename = args[2];
  2340. } else if (command == "strip-semicolon") {
  2341. if (args.count < 3) {
  2342. usage(args[0]);
  2343. return 1;
  2344. }
  2345. build_context.command_kind = Command_strip_semicolon;
  2346. build_context.no_output_files = true;
  2347. init_filename = args[2];
  2348. } else if (command == "doc") {
  2349. if (args.count < 3) {
  2350. usage(args[0]);
  2351. return 1;
  2352. }
  2353. build_context.command_kind = Command_doc;
  2354. init_filename = args[2];
  2355. for (isize i = 3; i < args.count; i++) {
  2356. auto arg = args[i];
  2357. if (string_starts_with(arg, str_lit("-"))) {
  2358. break;
  2359. }
  2360. array_add(&build_context.extra_packages, arg);
  2361. }
  2362. isize extra_count = build_context.extra_packages.count;
  2363. if (extra_count > 0) {
  2364. gb_memmove(args.data + 3, args.data + 3 + extra_count, extra_count * gb_size_of(*args.data));
  2365. args.count -= extra_count;
  2366. }
  2367. build_context.no_output_files = true;
  2368. build_context.generate_docs = true;
  2369. build_context.no_entry_point = true; // ignore entry point
  2370. #if 0
  2371. print_usage_line(0, "Documentation generation is not yet supported");
  2372. return 1;
  2373. #endif
  2374. } else if (command == "version") {
  2375. build_context.command_kind = Command_version;
  2376. gb_printf("%.*s version %.*s", LIT(args[0]), LIT(ODIN_VERSION));
  2377. #ifdef NIGHTLY
  2378. gb_printf("-nightly");
  2379. #endif
  2380. #ifdef GIT_SHA
  2381. gb_printf(":%s", GIT_SHA);
  2382. #endif
  2383. gb_printf("\n");
  2384. return 0;
  2385. } else if (command == "report") {
  2386. build_context.command_kind = Command_bug_report;
  2387. print_bug_report_help();
  2388. return 0;
  2389. } else if (command == "help") {
  2390. if (args.count <= 2) {
  2391. usage(args[0]);
  2392. return 1;
  2393. } else {
  2394. print_show_help(args[0], args[2]);
  2395. return 0;
  2396. }
  2397. } else {
  2398. usage(args[0]);
  2399. return 1;
  2400. }
  2401. init_filename = copy_string(permanent_allocator(), init_filename);
  2402. if (init_filename == "-help" ||
  2403. init_filename == "--help") {
  2404. build_context.show_help = true;
  2405. }
  2406. if (init_filename.len > 0 && !build_context.show_help) {
  2407. // The command must be build, run, test, check, or another that takes a directory or filename.
  2408. if (!path_is_directory(init_filename)) {
  2409. // Input package is a filename. We allow this only if `-file` was given, otherwise we exit with an error message.
  2410. bool single_file_package = false;
  2411. for_array(i, args) {
  2412. if (i >= 3 && i <= last_non_run_arg && args[i] == "-file") {
  2413. single_file_package = true;
  2414. break;
  2415. }
  2416. }
  2417. if (!single_file_package) {
  2418. gb_printf_err("ERROR: `%.*s %.*s` takes a package as its first argument.\n", LIT(args[0]), LIT(command));
  2419. if (init_filename == "-file") {
  2420. gb_printf_err("Did you mean `%.*s %.*s <filename.odin> -file`?\n", LIT(args[0]), LIT(command));
  2421. } else {
  2422. gb_printf_err("Did you mean `%.*s %.*s %.*s -file`?\n", LIT(args[0]), LIT(command), LIT(init_filename));
  2423. }
  2424. gb_printf_err("The `-file` flag tells it to treat a file as a self-contained package.\n");
  2425. return 1;
  2426. } else {
  2427. String const ext = str_lit(".odin");
  2428. if (!string_ends_with(init_filename, ext)) {
  2429. gb_printf_err("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename));
  2430. return 1;
  2431. }
  2432. }
  2433. }
  2434. }
  2435. build_context.command = command;
  2436. if (!parse_build_flags(args)) {
  2437. return 1;
  2438. }
  2439. if (build_context.show_help) {
  2440. print_show_help(args[0], command);
  2441. return 0;
  2442. }
  2443. // NOTE(bill): add 'shared' directory if it is not already set
  2444. if (!find_library_collection_path(str_lit("shared"), nullptr)) {
  2445. add_library_collection(str_lit("shared"),
  2446. get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("shared")));
  2447. }
  2448. init_build_context(selected_target_metrics ? selected_target_metrics->metrics : nullptr);
  2449. // if (build_context.word_size == 4 && build_context.metrics.os != TargetOs_js) {
  2450. // print_usage_line(0, "%.*s 32-bit is not yet supported for this platform", LIT(args[0]));
  2451. // return 1;
  2452. // }
  2453. // Set and check build paths...
  2454. if (!init_build_paths(init_filename)) {
  2455. return 1;
  2456. }
  2457. if (build_context.show_debug_messages) {
  2458. for_array(i, build_context.build_paths) {
  2459. String build_path = path_to_string(heap_allocator(), build_context.build_paths[i]);
  2460. debugf("build_paths[%ld]: %.*s\n", i, LIT(build_path));
  2461. }
  2462. }
  2463. init_global_thread_pool();
  2464. defer (thread_pool_destroy(&global_thread_pool));
  2465. init_universal();
  2466. // TODO(bill): prevent compiling without a linker
  2467. Parser *parser = gb_alloc_item(permanent_allocator(), Parser);
  2468. Checker *checker = gb_alloc_item(permanent_allocator(), Checker);
  2469. MAIN_TIME_SECTION("parse files");
  2470. if (!init_parser(parser)) {
  2471. return 1;
  2472. }
  2473. defer (destroy_parser(parser));
  2474. // TODO(jeroen): Remove the `init_filename` param.
  2475. // Let's put that on `build_context.build_paths[0]` instead.
  2476. if (parse_packages(parser, init_filename) != ParseFile_None) {
  2477. return 1;
  2478. }
  2479. if (any_errors()) {
  2480. return 1;
  2481. }
  2482. MAIN_TIME_SECTION("type check");
  2483. checker->parser = parser;
  2484. init_checker(checker);
  2485. defer (destroy_checker(checker));
  2486. check_parsed_files(checker);
  2487. if (any_errors()) {
  2488. return 1;
  2489. }
  2490. if (build_context.command_kind == Command_strip_semicolon) {
  2491. return strip_semicolons(parser);
  2492. }
  2493. if (build_context.generate_docs) {
  2494. if (global_error_collector.count != 0) {
  2495. return 1;
  2496. }
  2497. generate_documentation(checker);
  2498. return 0;
  2499. }
  2500. if (build_context.no_output_files) {
  2501. if (build_context.show_unused) {
  2502. print_show_unused(checker);
  2503. }
  2504. if (build_context.show_timings) {
  2505. show_timings(checker, &global_timings);
  2506. }
  2507. if (global_error_collector.count != 0) {
  2508. return 1;
  2509. }
  2510. return 0;
  2511. }
  2512. MAIN_TIME_SECTION("LLVM API Code Gen");
  2513. lbGenerator *gen = gb_alloc_item(permanent_allocator(), lbGenerator);
  2514. if (!lb_init_generator(gen, checker)) {
  2515. return 1;
  2516. }
  2517. if (lb_generate_code(gen)) {
  2518. switch (build_context.build_mode) {
  2519. case BuildMode_Executable:
  2520. case BuildMode_DynamicLibrary:
  2521. i32 result = linker_stage(gen);
  2522. if (result) {
  2523. if (build_context.show_timings) {
  2524. show_timings(checker, &global_timings);
  2525. }
  2526. return result;
  2527. }
  2528. break;
  2529. }
  2530. }
  2531. remove_temp_files(gen);
  2532. if (build_context.show_timings) {
  2533. show_timings(checker, &global_timings);
  2534. }
  2535. if (run_output) {
  2536. String exe_name = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]);
  2537. defer (gb_free(heap_allocator(), exe_name.text));
  2538. return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(exe_name), LIT(run_args_string));
  2539. }
  2540. return 0;
  2541. }