main.cpp 88 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637
  1. // #define NO_ARRAY_BOUNDS_CHECK
  2. #include "common.cpp"
  3. #include "timings.cpp"
  4. #include "tokenizer.cpp"
  5. #include "big_int.cpp"
  6. #include "exact_value.cpp"
  7. #include "build_settings.cpp"
  8. gb_global Timings global_timings = {0};
  9. #if defined(LLVM_BACKEND_SUPPORT)
  10. #if defined(GB_SYSTEM_WINDOWS)
  11. #include "llvm-c/Types.h"
  12. #else
  13. #include <llvm-c/Types.h>
  14. #endif
  15. #endif
  16. #include "parser.hpp"
  17. #include "checker.hpp"
  18. #include "parser.cpp"
  19. #include "checker.cpp"
  20. #include "docs.cpp"
  21. #if defined(LLVM_BACKEND_SUPPORT)
  22. #include "llvm_backend.cpp"
  23. #if defined(GB_SYSTEM_OSX)
  24. #include <llvm/Config/llvm-config.h>
  25. #if LLVM_VERSION_MAJOR < 11
  26. #error LLVM Version 11+ is required => "brew install llvm@11"
  27. #endif
  28. #endif
  29. #endif
  30. #include "ir.cpp"
  31. #include "ir_opt.cpp"
  32. #include "ir_print.cpp"
  33. #include "query_data.cpp"
  34. #if defined(GB_SYSTEM_WINDOWS)
  35. // NOTE(IC): In order to find Visual C++ paths without relying on environment variables.
  36. #include "microsoft_craziness.h"
  37. #endif
  38. // NOTE(bill): 'name' is used in debugging and profiling modes
  39. i32 system_exec_command_line_app(char const *name, char const *fmt, ...) {
  40. #if defined(GB_SYSTEM_WINDOWS)
  41. STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
  42. PROCESS_INFORMATION pi = {0};
  43. isize cmd_len = 0;
  44. isize const cmd_cap = 4096;
  45. char cmd_line[cmd_cap] = {};
  46. va_list va;
  47. gbTempArenaMemory tmp;
  48. String16 cmd;
  49. i32 exit_code = 0;
  50. start_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
  51. start_info.wShowWindow = SW_SHOW;
  52. start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
  53. start_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  54. start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
  55. va_start(va, fmt);
  56. cmd_len = gb_snprintf_va(cmd_line, cmd_cap-1, fmt, va);
  57. va_end(va);
  58. if (build_context.show_system_calls) {
  59. gb_printf_err("[SYSTEM CALL] %s\n", name);
  60. gb_printf_err("%.*s\n\n", cast(int)(cmd_len-1), cmd_line);
  61. }
  62. tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
  63. defer (gb_temp_arena_memory_end(tmp));
  64. cmd = string_to_string16(string_buffer_allocator, make_string(cast(u8 *)cmd_line, cmd_len-1));
  65. if (CreateProcessW(nullptr, cmd.text,
  66. nullptr, nullptr, true, 0, nullptr, nullptr,
  67. &start_info, &pi)) {
  68. WaitForSingleObject(pi.hProcess, INFINITE);
  69. GetExitCodeProcess(pi.hProcess, cast(DWORD *)&exit_code);
  70. CloseHandle(pi.hProcess);
  71. CloseHandle(pi.hThread);
  72. } else {
  73. // NOTE(bill): failed to create process
  74. gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);
  75. exit_code = -1;
  76. }
  77. if (exit_code) {
  78. exit(exit_code);
  79. }
  80. return exit_code;
  81. #elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
  82. char cmd_line[4096] = {0};
  83. isize cmd_len;
  84. va_list va;
  85. String cmd;
  86. i32 exit_code = 0;
  87. va_start(va, fmt);
  88. cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
  89. va_end(va);
  90. cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1);
  91. if (build_context.show_system_calls) {
  92. gb_printf_err("[SYSTEM CALL] %s\n", name);
  93. gb_printf_err("%s\n\n", cmd_line);
  94. }
  95. exit_code = system(cmd_line);
  96. // pid_t pid = fork();
  97. // int status = 0;
  98. // if(pid == 0) {
  99. // // in child, pid == 0.
  100. // int ret = execvp(cmd.text, (char* const*) cmd.text);
  101. // if(ret == -1) {
  102. // gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);
  103. // // we're in the child, so returning won't do us any good -- just quit.
  104. // exit(-1);
  105. // }
  106. // // unreachable
  107. // abort();
  108. // } else {
  109. // // wait for child to finish, then we can continue cleanup
  110. // int s = 0;
  111. // waitpid(pid, &s, 0);
  112. // status = WEXITSTATUS(s);
  113. // }
  114. // exit_code = status
  115. return exit_code;
  116. #endif
  117. }
  118. #if defined(LLVM_BACKEND_SUPPORT)
  119. i32 linker_stage(lbGenerator *gen) {
  120. i32 result = 0;
  121. Timings *timings = &global_timings;
  122. String output_base = gen->output_base;
  123. if (build_context.metrics.os == TargetOs_js) {
  124. timings_start_section(timings, str_lit("wasm-ld"));
  125. system_exec_command_line_app("wasm-ld",
  126. "\"%.*s\\bin\\wasm-ld\" \"%.*s.wasm-obj\" -o \"%.*s.wasm\" %.*s %.*s",
  127. LIT(build_context.ODIN_ROOT),
  128. LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags));
  129. }
  130. if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) {
  131. #ifdef GB_SYSTEM_UNIX
  132. result = system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s %.*s",
  133. LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags));
  134. #else
  135. gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n",
  136. LIT(target_os_names[build_context.metrics.os]),
  137. LIT(target_arch_names[build_context.metrics.arch])
  138. );
  139. #endif
  140. } else if (build_context.cross_compiling && build_context.different_os) {
  141. gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n",
  142. LIT(target_os_names[build_context.metrics.os]),
  143. LIT(target_arch_names[build_context.metrics.arch])
  144. );
  145. build_context.keep_object_files = true;
  146. } else {
  147. #if defined(GB_SYSTEM_WINDOWS)
  148. timings_start_section(timings, str_lit("msvc-link"));
  149. gbString lib_str = gb_string_make(heap_allocator(), "");
  150. defer (gb_string_free(lib_str));
  151. char lib_str_buf[1024] = {0};
  152. char const *output_ext = "exe";
  153. gbString link_settings = gb_string_make_reserve(heap_allocator(), 256);
  154. defer (gb_string_free(link_settings));
  155. // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest.
  156. Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8();
  157. if (find_result.windows_sdk_version == 0) {
  158. gb_printf_err("Windows SDK not found.\n");
  159. exit(1);
  160. }
  161. if (build_context.ignore_microsoft_magic) {
  162. find_result = {};
  163. }
  164. // Add library search paths.
  165. if (find_result.vs_library_path.len > 0) {
  166. GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0);
  167. GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0);
  168. String path = {};
  169. auto add_path = [&](String path) {
  170. if (path[path.len-1] == '\\') {
  171. path.len -= 1;
  172. }
  173. link_settings = gb_string_append_fmt(link_settings, " /LIBPATH:\"%.*s\"", LIT(path));
  174. };
  175. add_path(find_result.windows_sdk_um_library_path);
  176. add_path(find_result.windows_sdk_ucrt_library_path);
  177. add_path(find_result.vs_library_path);
  178. }
  179. for_array(i, gen->module.foreign_library_paths) {
  180. String lib = gen->module.foreign_library_paths[i];
  181. GB_ASSERT(lib.len < gb_count_of(lib_str_buf)-1);
  182. isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
  183. " \"%.*s\"", LIT(lib));
  184. lib_str = gb_string_appendc(lib_str, lib_str_buf);
  185. }
  186. if (build_context.build_mode == BuildMode_DynamicLibrary) {
  187. output_ext = "dll";
  188. link_settings = gb_string_append_fmt(link_settings, " /DLL");
  189. } else {
  190. link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup");
  191. }
  192. if (build_context.pdb_filepath != "") {
  193. link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(build_context.pdb_filepath));
  194. }
  195. if (build_context.no_crt) {
  196. link_settings = gb_string_append_fmt(link_settings, " /nodefaultlib");
  197. } else {
  198. link_settings = gb_string_append_fmt(link_settings, " /defaultlib:libcmt");
  199. }
  200. if (build_context.ODIN_DEBUG) {
  201. link_settings = gb_string_append_fmt(link_settings, " /DEBUG");
  202. }
  203. gbString object_files = gb_string_make(heap_allocator(), "");
  204. defer (gb_string_free(object_files));
  205. for_array(i, gen->output_object_paths) {
  206. String object_path = gen->output_object_paths[i];
  207. object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path));
  208. }
  209. char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE";
  210. if (!build_context.use_lld) { // msvc
  211. if (build_context.has_resource) {
  212. result = system_exec_command_line_app("msvc-link",
  213. "\"rc.exe\" /nologo /fo \"%.*s.res\" \"%.*s.rc\"",
  214. LIT(output_base),
  215. LIT(build_context.resource_filepath)
  216. );
  217. if(result == 0) {
  218. result = system_exec_command_line_app("msvc-link",
  219. "\"%.*slink.exe\" %s \"%.*s.res\" -OUT:\"%.*s.%s\" %s "
  220. "/nologo /incremental:no /opt:ref /subsystem:%s "
  221. " %.*s "
  222. " %.*s "
  223. " %s "
  224. "",
  225. LIT(find_result.vs_exe_path), object_files, LIT(output_base), LIT(output_base), output_ext,
  226. link_settings,
  227. subsystem_str,
  228. LIT(build_context.link_flags),
  229. LIT(build_context.extra_linker_flags),
  230. lib_str
  231. );
  232. }
  233. } else {
  234. result = system_exec_command_line_app("msvc-link",
  235. "\"%.*slink.exe\" %s -OUT:\"%.*s.%s\" %s "
  236. "/nologo /incremental:no /opt:ref /subsystem:%s "
  237. " %.*s "
  238. " %.*s "
  239. " %s "
  240. "",
  241. LIT(find_result.vs_exe_path), object_files, LIT(output_base), output_ext,
  242. link_settings,
  243. subsystem_str,
  244. LIT(build_context.link_flags),
  245. LIT(build_context.extra_linker_flags),
  246. lib_str
  247. );
  248. }
  249. } else { // lld
  250. result = system_exec_command_line_app("msvc-link",
  251. "\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s.%s\" %s "
  252. "/nologo /incremental:no /opt:ref /subsystem:%s "
  253. " %.*s "
  254. " %.*s "
  255. " %s "
  256. "",
  257. LIT(build_context.ODIN_ROOT),
  258. LIT(output_base), object_files, output_ext,
  259. link_settings,
  260. subsystem_str,
  261. LIT(build_context.link_flags),
  262. LIT(build_context.extra_linker_flags),
  263. lib_str
  264. );
  265. }
  266. #else
  267. timings_start_section(timings, str_lit("ld-link"));
  268. // NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe
  269. char cwd[256];
  270. getcwd(&cwd[0], 256);
  271. //printf("%s\n", cwd);
  272. // NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library
  273. // files can be passed with -l:
  274. gbString lib_str = gb_string_make(heap_allocator(), "-L/");
  275. defer (gb_string_free(lib_str));
  276. for_array(i, gen->module.foreign_library_paths) {
  277. String lib = gen->module.foreign_library_paths[i];
  278. // NOTE(zangent): Sometimes, you have to use -framework on MacOS.
  279. // This allows you to specify '-f' in a #foreign_system_library,
  280. // without having to implement any new syntax specifically for MacOS.
  281. #if defined(GB_SYSTEM_OSX)
  282. if (string_ends_with(lib, str_lit(".framework"))) {
  283. // framework thingie
  284. String lib_name = lib;
  285. lib_name = remove_extension_from_path(lib_name);
  286. lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name));
  287. } else if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o")) || string_ends_with(lib, str_lit(".dylib"))) {
  288. // For:
  289. // object
  290. // dynamic lib
  291. // static libs, absolute full path relative to the file in which the lib was imported from
  292. lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
  293. } else {
  294. // dynamic or static system lib, just link regularly searching system library paths
  295. lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
  296. }
  297. #else
  298. // NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path,
  299. // since those are statically linked to at link time. shared libraries (.so) has to be
  300. // available at runtime wherever the executable is run, so we make require those to be
  301. // local to the executable (unless the system collection is used, in which case we search
  302. // the system library paths for the library file).
  303. if (string_ends_with(lib, str_lit(".a"))) {
  304. // static libs, absolute full path relative to the file in which the lib was imported from
  305. lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib));
  306. } else if (string_ends_with(lib, str_lit(".so"))) {
  307. // dynamic lib, relative path to executable
  308. // NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible
  309. // at runtimeto the executable
  310. lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib));
  311. } else {
  312. // dynamic or static system lib, just link regularly searching system library paths
  313. lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
  314. }
  315. #endif
  316. }
  317. gbString object_files = gb_string_make(heap_allocator(), "");
  318. defer (gb_string_free(object_files));
  319. for_array(i, gen->output_object_paths) {
  320. String object_path = gen->output_object_paths[i];
  321. object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path));
  322. }
  323. // Unlike the Win32 linker code, the output_ext includes the dot, because
  324. // typically executable files on *NIX systems don't have extensions.
  325. String output_ext = {};
  326. gbString link_settings = gb_string_make_reserve(heap_allocator(), 32);
  327. char const *linker;
  328. if (build_context.build_mode == BuildMode_DynamicLibrary) {
  329. // NOTE(tetra, 2020-11-06): __$startup_runtime must be called at DLL load time.
  330. // Clang, for some reason, won't let us pass the '-init' flag that lets us do this,
  331. // so use ld instead.
  332. // :UseLDForShared
  333. linker = "ld";
  334. link_settings = gb_string_appendc(link_settings, "-init '__$startup_runtime' ");
  335. // Shared libraries are .dylib on MacOS and .so on Linux.
  336. #if defined(GB_SYSTEM_OSX)
  337. output_ext = STR_LIT(".dylib");
  338. link_settings = gb_string_appendc(link_settings, "-dylib -dynamic ");
  339. #else
  340. output_ext = STR_LIT(".so");
  341. link_settings = gb_string_appendc(link_settings, "-shared ");
  342. #endif
  343. } else {
  344. #if defined(GB_SYSTEM_OSX)
  345. linker = "ld";
  346. #else
  347. // TODO(zangent): Figure out how to make ld work on Linux.
  348. // It probably has to do with including the entire CRT, but
  349. // that's quite a complicated issue to solve while remaining distro-agnostic.
  350. // Clang can figure out linker flags for us, and that's good enough _for now_.
  351. linker = "clang -Wno-unused-command-line-argument";
  352. #endif
  353. }
  354. if (build_context.out_filepath.len > 0) {
  355. //NOTE(thebirk): We have a custom -out arguments, so we should use the extension from that
  356. isize pos = string_extension_position(build_context.out_filepath);
  357. if (pos > 0) {
  358. output_ext = substring(build_context.out_filepath, pos, build_context.out_filepath.len);
  359. }
  360. }
  361. result = system_exec_command_line_app("ld-link",
  362. "%s %s -o \"%.*s%.*s\" %s "
  363. " %s "
  364. " %.*s "
  365. " %.*s "
  366. " %s "
  367. #if defined(GB_SYSTEM_OSX)
  368. // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
  369. // NOTE: If you change this (although this minimum is as low as you can go with Odin working)
  370. // make sure to also change the 'mtriple' param passed to 'opt'
  371. #if defined(GB_CPU_ARM)
  372. " -macosx_version_min 11.0.0 "
  373. #else
  374. " -macosx_version_min 10.8.0 "
  375. #endif
  376. // This points the linker to where the entry point is
  377. " -e _main "
  378. #endif
  379. , linker, object_files, LIT(output_base), LIT(output_ext),
  380. #if defined(GB_SYSTEM_OSX)
  381. "-lSystem -lm -syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib",
  382. #else
  383. "-lc -lm",
  384. #endif
  385. lib_str,
  386. LIT(build_context.link_flags),
  387. LIT(build_context.extra_linker_flags),
  388. link_settings);
  389. #if defined(GB_SYSTEM_OSX)
  390. if (build_context.ODIN_DEBUG) {
  391. // NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe
  392. // to the symbols in the object file
  393. system_exec_command_line_app("dsymutil",
  394. "dsymutil %.*s%.*s", LIT(output_base), LIT(output_ext)
  395. );
  396. }
  397. #endif
  398. #endif
  399. }
  400. return result;
  401. }
  402. #endif
  403. Array<String> setup_args(int argc, char const **argv) {
  404. gbAllocator a = heap_allocator();
  405. #if defined(GB_SYSTEM_WINDOWS)
  406. int wargc = 0;
  407. wchar_t **wargv = command_line_to_wargv(GetCommandLineW(), &wargc);
  408. auto args = array_make<String>(a, 0, wargc);
  409. for (isize i = 0; i < wargc; i++) {
  410. wchar_t *warg = wargv[i];
  411. isize wlen = string16_len(warg);
  412. String16 wstr = make_string16(warg, wlen);
  413. String arg = string16_to_string(a, wstr);
  414. if (arg.len > 0) {
  415. array_add(&args, arg);
  416. }
  417. }
  418. return args;
  419. #else
  420. auto args = array_make<String>(a, 0, argc);
  421. for (isize i = 0; i < argc; i++) {
  422. String arg = make_string_c(argv[i]);
  423. if (arg.len > 0) {
  424. array_add(&args, arg);
  425. }
  426. }
  427. return args;
  428. #endif
  429. }
  430. void print_usage_line(i32 indent, char const *fmt, ...) {
  431. while (indent --> 0) {
  432. gb_printf_err("\t");
  433. }
  434. va_list va;
  435. va_start(va, fmt);
  436. gb_printf_err_va(fmt, va);
  437. va_end(va);
  438. gb_printf_err("\n");
  439. }
  440. void usage(String argv0) {
  441. print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(argv0));
  442. print_usage_line(0, "Usage:");
  443. print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
  444. print_usage_line(0, "Commands:");
  445. print_usage_line(1, "build compile .odin file, or directory of .odin files, as an executable.");
  446. print_usage_line(1, " one must contain the program's entry point, all must be in the same package.");
  447. print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable.");
  448. print_usage_line(1, "check parse and type check .odin file");
  449. print_usage_line(1, "query parse, type check, and output a .json file containing information about the program");
  450. print_usage_line(1, "doc generate documentation .odin file, or directory of .odin files");
  451. print_usage_line(1, "version print version");
  452. print_usage_line(0, "");
  453. print_usage_line(0, "For more information of flags, apply the flag to see what is possible");
  454. print_usage_line(1, "-help");
  455. }
  456. bool string_is_valid_identifier(String str) {
  457. if (str.len <= 0) return false;
  458. isize rune_count = 0;
  459. isize w = 0;
  460. isize offset = 0;
  461. while (offset < str.len) {
  462. Rune r = 0;
  463. w = gb_utf8_decode(str.text, str.len, &r);
  464. if (r == GB_RUNE_INVALID) {
  465. return false;
  466. }
  467. if (rune_count == 0) {
  468. if (!rune_is_letter(r)) {
  469. return false;
  470. }
  471. } else {
  472. if (!rune_is_letter(r) && !rune_is_digit(r)) {
  473. return false;
  474. }
  475. }
  476. rune_count += 1;
  477. offset += w;
  478. }
  479. return true;
  480. }
  481. enum BuildFlagKind {
  482. BuildFlag_Invalid,
  483. BuildFlag_Help,
  484. BuildFlag_OutFile,
  485. BuildFlag_OptimizationLevel,
  486. BuildFlag_OptimizationMode,
  487. BuildFlag_ShowTimings,
  488. BuildFlag_ShowUnused,
  489. BuildFlag_ShowUnusedWithLocation,
  490. BuildFlag_ShowMoreTimings,
  491. BuildFlag_ShowSystemCalls,
  492. BuildFlag_ThreadCount,
  493. BuildFlag_KeepTempFiles,
  494. BuildFlag_Collection,
  495. BuildFlag_Define,
  496. BuildFlag_BuildMode,
  497. BuildFlag_Target,
  498. BuildFlag_Debug,
  499. BuildFlag_DisableAssert,
  500. BuildFlag_NoBoundsCheck,
  501. BuildFlag_NoDynamicLiterals,
  502. BuildFlag_NoCRT,
  503. BuildFlag_NoEntryPoint,
  504. BuildFlag_UseLLD,
  505. BuildFlag_Vet,
  506. BuildFlag_VetExtra,
  507. BuildFlag_UseLLVMApi,
  508. BuildFlag_IgnoreUnknownAttributes,
  509. BuildFlag_ExtraLinkerFlags,
  510. BuildFlag_Microarch,
  511. BuildFlag_DisallowDo,
  512. BuildFlag_DefaultToNilAllocator,
  513. BuildFlag_InsertSemicolon,
  514. BuildFlag_StrictStyle,
  515. BuildFlag_Compact,
  516. BuildFlag_GlobalDefinitions,
  517. BuildFlag_GoToDefinitions,
  518. BuildFlag_Short,
  519. BuildFlag_AllPackages,
  520. BuildFlag_DocFormat,
  521. BuildFlag_IgnoreWarnings,
  522. BuildFlag_WarningsAsErrors,
  523. #if defined(GB_SYSTEM_WINDOWS)
  524. BuildFlag_IgnoreVsSearch,
  525. BuildFlag_ResourceFile,
  526. BuildFlag_WindowsPdbName,
  527. BuildFlag_Subsystem,
  528. #endif
  529. BuildFlag_COUNT,
  530. };
  531. enum BuildFlagParamKind {
  532. BuildFlagParam_None,
  533. BuildFlagParam_Boolean,
  534. BuildFlagParam_Integer,
  535. BuildFlagParam_Float,
  536. BuildFlagParam_String,
  537. BuildFlagParam_COUNT,
  538. };
  539. struct BuildFlag {
  540. BuildFlagKind kind;
  541. String name;
  542. BuildFlagParamKind param_kind;
  543. u32 command_support;
  544. bool allow_mulitple;
  545. };
  546. void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind, u32 command_support, bool allow_mulitple=false) {
  547. BuildFlag flag = {kind, name, param_kind, command_support, allow_mulitple};
  548. array_add(build_flags, flag);
  549. }
  550. ExactValue build_param_to_exact_value(String name, String param) {
  551. ExactValue value = {};
  552. if (str_eq_ignore_case(param, str_lit("t")) ||
  553. str_eq_ignore_case(param, str_lit("true"))) {
  554. value = exact_value_bool(true);
  555. } else if (str_eq_ignore_case(param, str_lit("f")) ||
  556. str_eq_ignore_case(param, str_lit("false"))) {
  557. value = exact_value_bool(false);
  558. } else if (param.len > 0) {
  559. if (param[0] == '"') {
  560. value = exact_value_string(param);
  561. if (value.kind == ExactValue_String) {
  562. String s = value.value_string;
  563. if (s.len > 1 && s[0] == '"' && s[s.len-1] == '"') {
  564. value.value_string = substring(s, 1, s.len-1);
  565. }
  566. }
  567. } else if (param[0] == '-' || param[0] == '+' || gb_is_between(param[0], '0', '9')) {
  568. if (string_contains_char(param, '.')) {
  569. value = exact_value_float_from_string(param);
  570. } else {
  571. value = exact_value_integer_from_string(param);
  572. }
  573. if (value.kind == ExactValue_Invalid) {
  574. gb_printf_err("Invalid flag parameter for '%.*s' = '%.*s'\n", LIT(name), LIT(param));
  575. }
  576. }
  577. } else {
  578. gb_printf_err("Invalid flag parameter for '%.*s' = '%.*s'\n", LIT(name), LIT(param));
  579. }
  580. return value;
  581. }
  582. bool parse_build_flags(Array<String> args) {
  583. auto build_flags = array_make<BuildFlag>(heap_allocator(), 0, BuildFlag_COUNT);
  584. add_flag(&build_flags, BuildFlag_Help, str_lit("help"), BuildFlagParam_None, Command_all);
  585. add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String, Command__does_build &~ Command_test);
  586. add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"), BuildFlagParam_Integer, Command__does_build);
  587. add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("o"), BuildFlagParam_String, Command__does_build);
  588. add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("O"), BuildFlagParam_String, Command__does_build);
  589. add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None, Command__does_check);
  590. add_flag(&build_flags, BuildFlag_ShowMoreTimings, str_lit("show-more-timings"), BuildFlagParam_None, Command__does_check);
  591. add_flag(&build_flags, BuildFlag_ShowUnused, str_lit("show-unused"), BuildFlagParam_None, Command_check);
  592. add_flag(&build_flags, BuildFlag_ShowUnusedWithLocation, str_lit("show-unused-with-location"), BuildFlagParam_None, Command_check);
  593. add_flag(&build_flags, BuildFlag_ShowSystemCalls, str_lit("show-system-calls"), BuildFlagParam_None, Command_all);
  594. add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer, Command_all);
  595. add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None, Command__does_build);
  596. add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String, Command__does_check);
  597. add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String, Command__does_check, true);
  598. 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
  599. add_flag(&build_flags, BuildFlag_Target, str_lit("target"), BuildFlagParam_String, Command__does_check);
  600. add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None, Command__does_check);
  601. add_flag(&build_flags, BuildFlag_DisableAssert, str_lit("disable-assert"), BuildFlagParam_None, Command__does_check);
  602. add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None, Command__does_check);
  603. add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None, Command__does_check);
  604. add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None, Command__does_build);
  605. add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check &~ Command_test);
  606. add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None, Command__does_build);
  607. add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check);
  608. add_flag(&build_flags, BuildFlag_VetExtra, str_lit("vet-extra"), BuildFlagParam_None, Command__does_check);
  609. add_flag(&build_flags, BuildFlag_UseLLVMApi, str_lit("llvm-api"), BuildFlagParam_None, Command__does_build);
  610. add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check);
  611. add_flag(&build_flags, BuildFlag_ExtraLinkerFlags, str_lit("extra-linker-flags"), BuildFlagParam_String, Command__does_build);
  612. add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build);
  613. add_flag(&build_flags, BuildFlag_DisallowDo, str_lit("disallow-do"), BuildFlagParam_None, Command__does_check);
  614. add_flag(&build_flags, BuildFlag_DefaultToNilAllocator, str_lit("default-to-nil-allocator"), BuildFlagParam_None, Command__does_check);
  615. add_flag(&build_flags, BuildFlag_InsertSemicolon, str_lit("insert-semicolon"), BuildFlagParam_None, Command__does_check);
  616. add_flag(&build_flags, BuildFlag_StrictStyle, str_lit("strict-style"), BuildFlagParam_None, Command__does_check);
  617. add_flag(&build_flags, BuildFlag_Compact, str_lit("compact"), BuildFlagParam_None, Command_query);
  618. add_flag(&build_flags, BuildFlag_GlobalDefinitions, str_lit("global-definitions"), BuildFlagParam_None, Command_query);
  619. add_flag(&build_flags, BuildFlag_GoToDefinitions, str_lit("go-to-definitions"), BuildFlagParam_None, Command_query);
  620. add_flag(&build_flags, BuildFlag_Short, str_lit("short"), BuildFlagParam_None, Command_doc);
  621. add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc);
  622. add_flag(&build_flags, BuildFlag_DocFormat, str_lit("doc-format"), BuildFlagParam_None, Command_doc);
  623. add_flag(&build_flags, BuildFlag_IgnoreWarnings, str_lit("ignore-warnings"), BuildFlagParam_None, Command_all);
  624. add_flag(&build_flags, BuildFlag_WarningsAsErrors, str_lit("warnings-as-errors"), BuildFlagParam_None, Command_all);
  625. #if defined(GB_SYSTEM_WINDOWS)
  626. add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"), BuildFlagParam_None, Command__does_build);
  627. add_flag(&build_flags, BuildFlag_ResourceFile, str_lit("resource"), BuildFlagParam_String, Command__does_build);
  628. add_flag(&build_flags, BuildFlag_WindowsPdbName, str_lit("pdb-name"), BuildFlagParam_String, Command__does_build);
  629. add_flag(&build_flags, BuildFlag_Subsystem, str_lit("subsystem"), BuildFlagParam_String, Command__does_build);
  630. #endif
  631. GB_ASSERT(args.count >= 3);
  632. Array<String> flag_args = array_slice(args, 3, args.count);
  633. bool set_flags[BuildFlag_COUNT] = {};
  634. bool bad_flags = false;
  635. for_array(i, flag_args) {
  636. String flag = flag_args[i];
  637. if (flag[0] != '-') {
  638. gb_printf_err("Invalid flag: %.*s\n", LIT(flag));
  639. continue;
  640. }
  641. if (string_starts_with(flag, str_lit("--"))) {
  642. flag = substring(flag, 1, flag.len);
  643. }
  644. String name = substring(flag, 1, flag.len);
  645. isize end = 0;
  646. for (; end < name.len; end++) {
  647. if (name[end] == ':') break;
  648. if (name[end] == '=') break; // IMPORTANT TODO(bill): DEPRECATE THIS!!!!
  649. }
  650. name = substring(name, 0, end);
  651. String param = {};
  652. if (end < flag.len-1) param = substring(flag, 2+end, flag.len);
  653. bool is_supported = true;
  654. bool found = false;
  655. BuildFlag found_bf = {};
  656. for_array(build_flag_index, build_flags) {
  657. BuildFlag bf = build_flags[build_flag_index];
  658. if (bf.name == name) {
  659. found = true;
  660. found_bf = bf;
  661. if ((bf.command_support & build_context.command_kind) == 0) {
  662. is_supported = false;
  663. break;
  664. }
  665. if (set_flags[bf.kind]) {
  666. gb_printf_err("Previous flag set: '%.*s'\n", LIT(name));
  667. bad_flags = true;
  668. } else {
  669. ExactValue value = {};
  670. bool ok = false;
  671. if (bf.param_kind == BuildFlagParam_None) {
  672. if (param.len == 0) {
  673. ok = true;
  674. } else {
  675. gb_printf_err("Flag '%.*s' was not expecting a parameter '%.*s'\n", LIT(name), LIT(param));
  676. bad_flags = true;
  677. }
  678. } else if (param.len == 0) {
  679. gb_printf_err("Flag missing for '%.*s'\n", LIT(name));
  680. bad_flags = true;
  681. } else {
  682. ok = true;
  683. switch (bf.param_kind) {
  684. default:
  685. ok = false;
  686. break;
  687. case BuildFlagParam_Boolean: {
  688. if (str_eq_ignore_case(param, str_lit("t")) ||
  689. str_eq_ignore_case(param, str_lit("true")) ||
  690. param == "1") {
  691. value = exact_value_bool(true);
  692. } else if (str_eq_ignore_case(param, str_lit("f")) ||
  693. str_eq_ignore_case(param, str_lit("false")) ||
  694. param == "0") {
  695. value = exact_value_bool(false);
  696. } else {
  697. gb_printf_err("Invalid flag parameter for '%.*s' : '%.*s'\n", LIT(name), LIT(param));
  698. }
  699. } break;
  700. case BuildFlagParam_Integer:
  701. value = exact_value_integer_from_string(param);
  702. break;
  703. case BuildFlagParam_Float:
  704. value = exact_value_float_from_string(param);
  705. break;
  706. case BuildFlagParam_String: {
  707. value = exact_value_string(param);
  708. if (value.kind == ExactValue_String) {
  709. String s = value.value_string;
  710. if (s.len > 1 && s[0] == '"' && s[s.len-1] == '"') {
  711. value.value_string = substring(s, 1, s.len-1);
  712. }
  713. }
  714. break;
  715. }
  716. }
  717. }
  718. if (ok) {
  719. switch (bf.param_kind) {
  720. case BuildFlagParam_None:
  721. if (value.kind != ExactValue_Invalid) {
  722. gb_printf_err("%.*s expected no value, got %.*s", LIT(name), LIT(param));
  723. bad_flags = true;
  724. ok = false;
  725. }
  726. break;
  727. case BuildFlagParam_Boolean:
  728. if (value.kind != ExactValue_Bool) {
  729. gb_printf_err("%.*s expected a boolean, got %.*s", LIT(name), LIT(param));
  730. bad_flags = true;
  731. ok = false;
  732. }
  733. break;
  734. case BuildFlagParam_Integer:
  735. if (value.kind != ExactValue_Integer) {
  736. gb_printf_err("%.*s expected an integer, got %.*s", LIT(name), LIT(param));
  737. bad_flags = true;
  738. ok = false;
  739. }
  740. break;
  741. case BuildFlagParam_Float:
  742. if (value.kind != ExactValue_Float) {
  743. gb_printf_err("%.*s expected a floating pointer number, got %.*s", LIT(name), LIT(param));
  744. bad_flags = true;
  745. ok = false;
  746. }
  747. break;
  748. case BuildFlagParam_String:
  749. if (value.kind != ExactValue_String) {
  750. gb_printf_err("%.*s expected a string, got %.*s", LIT(name), LIT(param));
  751. bad_flags = true;
  752. ok = false;
  753. }
  754. break;
  755. }
  756. if (ok) switch (bf.kind) {
  757. case BuildFlag_Help:
  758. build_context.show_help = true;
  759. break;
  760. case BuildFlag_OutFile: {
  761. GB_ASSERT(value.kind == ExactValue_String);
  762. String path = value.value_string;
  763. path = string_trim_whitespace(path);
  764. if (is_build_flag_path_valid(path)) {
  765. build_context.out_filepath = path_to_full_path(heap_allocator(), path);
  766. } else {
  767. gb_printf_err("Invalid -out path, got %.*s\n", LIT(path));
  768. bad_flags = true;
  769. }
  770. break;
  771. }
  772. case BuildFlag_OptimizationLevel:
  773. GB_ASSERT(value.kind == ExactValue_Integer);
  774. if (set_flags[BuildFlag_OptimizationMode]) {
  775. gb_printf_err("Mixture of -opt and -o is not allowed\n");
  776. bad_flags = true;
  777. break;
  778. }
  779. build_context.optimization_level = cast(i32)big_int_to_i64(&value.value_integer);
  780. break;
  781. case BuildFlag_OptimizationMode:
  782. GB_ASSERT(value.kind == ExactValue_String);
  783. if (set_flags[BuildFlag_OptimizationLevel]) {
  784. gb_printf_err("Mixture of -opt and -o is not allowed\n");
  785. bad_flags = true;
  786. break;
  787. }
  788. if (value.value_string == "minimal") {
  789. build_context.optimization_level = 0;
  790. } else if (value.value_string == "size") {
  791. build_context.optimization_level = 1;
  792. } else if (value.value_string == "speed") {
  793. build_context.optimization_level = 2;
  794. } else {
  795. gb_printf_err("Invalid optimization mode for -o:<string>, got %.*s\n", LIT(value.value_string));
  796. gb_printf_err("Valid optimization modes:\n");
  797. gb_printf_err("\tminimal\n");
  798. gb_printf_err("\tsize\n");
  799. gb_printf_err("\tspeed\n");
  800. bad_flags = true;
  801. }
  802. break;
  803. case BuildFlag_ShowTimings:
  804. GB_ASSERT(value.kind == ExactValue_Invalid);
  805. build_context.show_timings = true;
  806. break;
  807. case BuildFlag_ShowUnused:
  808. GB_ASSERT(value.kind == ExactValue_Invalid);
  809. build_context.show_unused = true;
  810. break;
  811. case BuildFlag_ShowUnusedWithLocation:
  812. GB_ASSERT(value.kind == ExactValue_Invalid);
  813. build_context.show_unused = true;
  814. build_context.show_unused_with_location = true;
  815. break;
  816. case BuildFlag_ShowMoreTimings:
  817. GB_ASSERT(value.kind == ExactValue_Invalid);
  818. build_context.show_timings = true;
  819. build_context.show_more_timings = true;
  820. break;
  821. case BuildFlag_ShowSystemCalls:
  822. GB_ASSERT(value.kind == ExactValue_Invalid);
  823. build_context.show_system_calls = true;
  824. break;
  825. case BuildFlag_ThreadCount: {
  826. GB_ASSERT(value.kind == ExactValue_Integer);
  827. isize count = cast(isize)big_int_to_i64(&value.value_integer);
  828. if (count <= 0) {
  829. gb_printf_err("%.*s expected a positive non-zero number, got %.*s\n", LIT(name), LIT(param));
  830. build_context.thread_count = 1;
  831. } else {
  832. build_context.thread_count = count;
  833. }
  834. break;
  835. }
  836. case BuildFlag_KeepTempFiles:
  837. GB_ASSERT(value.kind == ExactValue_Invalid);
  838. build_context.keep_temp_files = true;
  839. break;
  840. case BuildFlag_Collection: {
  841. GB_ASSERT(value.kind == ExactValue_String);
  842. String str = value.value_string;
  843. isize eq_pos = -1;
  844. for (isize i = 0; i < str.len; i++) {
  845. if (str[i] == '=') {
  846. eq_pos = i;
  847. break;
  848. }
  849. }
  850. if (eq_pos < 0) {
  851. gb_printf_err("Expected 'name=path', got '%.*s'\n", LIT(param));
  852. bad_flags = true;
  853. break;
  854. }
  855. String name = substring(str, 0, eq_pos);
  856. String path = substring(str, eq_pos+1, str.len);
  857. if (name.len == 0 || path.len == 0) {
  858. gb_printf_err("Expected 'name=path', got '%.*s'\n", LIT(param));
  859. bad_flags = true;
  860. break;
  861. }
  862. if (!string_is_valid_identifier(name)) {
  863. gb_printf_err("Library collection name '%.*s' must be a valid identifier\n", LIT(name));
  864. bad_flags = true;
  865. break;
  866. }
  867. if (name == "_") {
  868. gb_printf_err("Library collection name cannot be an underscore\n");
  869. bad_flags = true;
  870. break;
  871. }
  872. if (name == "system") {
  873. gb_printf_err("Library collection name 'system' is reserved\n");
  874. bad_flags = true;
  875. break;
  876. }
  877. String prev_path = {};
  878. bool found = find_library_collection_path(name, &prev_path);
  879. if (found) {
  880. gb_printf_err("Library collection '%.*s' already exists with path '%.*s'\n", LIT(name), LIT(prev_path));
  881. bad_flags = true;
  882. break;
  883. }
  884. gbAllocator a = heap_allocator();
  885. String fullpath = path_to_fullpath(a, path);
  886. if (!path_is_directory(fullpath)) {
  887. gb_printf_err("Library collection '%.*s' path must be a directory, got '%.*s'\n", LIT(name), LIT(fullpath));
  888. gb_free(a, fullpath.text);
  889. bad_flags = true;
  890. break;
  891. }
  892. add_library_collection(name, path);
  893. // NOTE(bill): Allow for multiple library collections
  894. continue;
  895. }
  896. case BuildFlag_Define: {
  897. GB_ASSERT(value.kind == ExactValue_String);
  898. String str = value.value_string;
  899. isize eq_pos = -1;
  900. for (isize i = 0; i < str.len; i++) {
  901. if (str[i] == '=') {
  902. eq_pos = i;
  903. break;
  904. }
  905. }
  906. if (eq_pos < 0) {
  907. gb_printf_err("Expected 'name=value', got '%.*s'\n", LIT(param));
  908. bad_flags = true;
  909. break;
  910. }
  911. String name = substring(str, 0, eq_pos);
  912. String value = substring(str, eq_pos+1, str.len);
  913. if (name.len == 0 || value.len == 0) {
  914. gb_printf_err("Expected 'name=value', got '%.*s'\n", LIT(param));
  915. bad_flags = true;
  916. break;
  917. }
  918. if (!string_is_valid_identifier(name)) {
  919. gb_printf_err("Defined constant name '%.*s' must be a valid identifier\n", LIT(name));
  920. bad_flags = true;
  921. break;
  922. }
  923. if (name == "_") {
  924. gb_printf_err("Defined constant name cannot be an underscore\n");
  925. bad_flags = true;
  926. break;
  927. }
  928. HashKey key = hash_pointer(string_intern(name));
  929. if (map_get(&build_context.defined_values, key) != nullptr) {
  930. gb_printf_err("Defined constant '%.*s' already exists\n", LIT(name));
  931. bad_flags = true;
  932. break;
  933. }
  934. ExactValue v = build_param_to_exact_value(name, value);
  935. if (v.kind != ExactValue_Invalid) {
  936. map_set(&build_context.defined_values, key, v);
  937. } else {
  938. gb_printf_err("Invalid define constant value: '%.*s'. Define constants must be a valid Odin literal.\n", LIT(value));
  939. bad_flags = true;
  940. }
  941. break;
  942. }
  943. case BuildFlag_Target: {
  944. GB_ASSERT(value.kind == ExactValue_String);
  945. String str = value.value_string;
  946. bool found = false;
  947. for (isize i = 0; i < gb_count_of(named_targets); i++) {
  948. if (str_eq_ignore_case(str, named_targets[i].name)) {
  949. found = true;
  950. selected_target_metrics = named_targets + i;
  951. break;
  952. }
  953. }
  954. if (!found) {
  955. struct DistanceAndTarget {
  956. isize distance;
  957. isize target_index;
  958. };
  959. DistanceAndTarget distances[gb_count_of(named_targets)] = {};
  960. for (isize i = 0; i < gb_count_of(named_targets); i++) {
  961. distances[i].target_index = i;
  962. distances[i].distance = levenstein_distance_case_insensitive(str, named_targets[i].name);
  963. }
  964. gb_sort_array(distances, gb_count_of(distances), gb_isize_cmp(gb_offset_of(DistanceAndTarget, distance)));
  965. gb_printf_err("Unknown target '%.*s'\n", LIT(str));
  966. enum {MAX_SMALLEST_DISTANCE = 3};
  967. if (distances[0].distance <= MAX_SMALLEST_DISTANCE) {
  968. gb_printf_err("Did you mean:\n");
  969. for (isize i = 0; i < gb_count_of(named_targets); i++) {
  970. if (distances[i].distance > MAX_SMALLEST_DISTANCE) {
  971. break;
  972. }
  973. gb_printf_err("\t%.*s\n", LIT(named_targets[distances[i].target_index].name));
  974. }
  975. }
  976. gb_printf_err("All supported targets:\n");
  977. for (isize i = 0; i < gb_count_of(named_targets); i++) {
  978. gb_printf_err("\t%.*s\n", LIT(named_targets[i].name));
  979. }
  980. bad_flags = true;
  981. }
  982. break;
  983. }
  984. case BuildFlag_BuildMode: {
  985. GB_ASSERT(value.kind == ExactValue_String);
  986. String str = value.value_string;
  987. if (build_context.command != "build") {
  988. gb_printf_err("'build-mode' can only be used with the 'build' command\n");
  989. bad_flags = true;
  990. break;
  991. }
  992. if (str == "dll" || str == "shared") {
  993. build_context.build_mode = BuildMode_DynamicLibrary;
  994. } else if (str == "obj" || str == "object") {
  995. build_context.build_mode = BuildMode_Object;
  996. } else if (str == "exe") {
  997. build_context.build_mode = BuildMode_Executable;
  998. } else if (str == "asm" || str == "assembly" || str == "assembler") {
  999. build_context.build_mode = BuildMode_Assembly;
  1000. } else if (str == "llvm" || str == "llvm-ir") {
  1001. build_context.build_mode = BuildMode_LLVM_IR;
  1002. } else {
  1003. gb_printf_err("Unknown build mode '%.*s'\n", LIT(str));
  1004. gb_printf_err("Valid build modes:\n");
  1005. gb_printf_err("\tdll, shared\n");
  1006. gb_printf_err("\tobj, object\n");
  1007. gb_printf_err("\texe\n");
  1008. gb_printf_err("\tasm, assembly, assembler\n");
  1009. gb_printf_err("\tllvm, llvm-ir\n");
  1010. bad_flags = true;
  1011. break;
  1012. }
  1013. break;
  1014. }
  1015. case BuildFlag_Debug:
  1016. build_context.ODIN_DEBUG = true;
  1017. break;
  1018. case BuildFlag_DisableAssert:
  1019. build_context.ODIN_DISABLE_ASSERT = true;
  1020. break;
  1021. case BuildFlag_NoBoundsCheck:
  1022. build_context.no_bounds_check = true;
  1023. break;
  1024. case BuildFlag_NoDynamicLiterals:
  1025. build_context.no_dynamic_literals = true;
  1026. break;
  1027. case BuildFlag_NoCRT:
  1028. build_context.no_crt = true;
  1029. break;
  1030. case BuildFlag_NoEntryPoint:
  1031. build_context.no_entry_point = true;
  1032. break;
  1033. case BuildFlag_UseLLD:
  1034. build_context.use_lld = true;
  1035. break;
  1036. case BuildFlag_Vet:
  1037. build_context.vet = true;
  1038. break;
  1039. case BuildFlag_VetExtra:
  1040. build_context.vet = true;
  1041. build_context.vet_extra = true;
  1042. break;
  1043. case BuildFlag_UseLLVMApi:
  1044. build_context.use_llvm_api = true;
  1045. break;
  1046. case BuildFlag_IgnoreUnknownAttributes:
  1047. build_context.ignore_unknown_attributes = true;
  1048. break;
  1049. case BuildFlag_ExtraLinkerFlags:
  1050. GB_ASSERT(value.kind == ExactValue_String);
  1051. build_context.extra_linker_flags = value.value_string;
  1052. break;
  1053. case BuildFlag_Microarch:
  1054. GB_ASSERT(value.kind == ExactValue_String);
  1055. build_context.microarch = value.value_string;
  1056. string_to_lower(&build_context.microarch);
  1057. break;
  1058. case BuildFlag_DisallowDo:
  1059. build_context.disallow_do = true;
  1060. break;
  1061. case BuildFlag_DefaultToNilAllocator:
  1062. build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR = true;
  1063. break;
  1064. case BuildFlag_InsertSemicolon:
  1065. build_context.insert_semicolon = true;
  1066. break;
  1067. case BuildFlag_StrictStyle:
  1068. build_context.insert_semicolon = true;
  1069. build_context.strict_style = true;
  1070. break;
  1071. case BuildFlag_Compact:
  1072. if (!build_context.query_data_set_settings.ok) {
  1073. gb_printf_err("Invalid use of -compact flag, only allowed with 'odin query'\n");
  1074. bad_flags = true;
  1075. } else {
  1076. build_context.query_data_set_settings.compact = true;
  1077. }
  1078. break;
  1079. case BuildFlag_GlobalDefinitions:
  1080. if (!build_context.query_data_set_settings.ok) {
  1081. gb_printf_err("Invalid use of -global-definitions flag, only allowed with 'odin query'\n");
  1082. bad_flags = true;
  1083. } else if (build_context.query_data_set_settings.kind != QueryDataSet_Invalid) {
  1084. gb_printf_err("Invalid use of -global-definitions flag, a previous flag for 'odin query' was set\n");
  1085. bad_flags = true;
  1086. } else {
  1087. build_context.query_data_set_settings.kind = QueryDataSet_GlobalDefinitions;
  1088. }
  1089. break;
  1090. case BuildFlag_GoToDefinitions:
  1091. if (!build_context.query_data_set_settings.ok) {
  1092. gb_printf_err("Invalid use of -go-to-definitions flag, only allowed with 'odin query'\n");
  1093. bad_flags = true;
  1094. } else if (build_context.query_data_set_settings.kind != QueryDataSet_Invalid) {
  1095. gb_printf_err("Invalid use of -global-definitions flag, a previous flag for 'odin query' was set\n");
  1096. bad_flags = true;
  1097. } else {
  1098. build_context.query_data_set_settings.kind = QueryDataSet_GoToDefinitions;
  1099. }
  1100. break;
  1101. case BuildFlag_Short:
  1102. build_context.cmd_doc_flags |= CmdDocFlag_Short;
  1103. break;
  1104. case BuildFlag_AllPackages:
  1105. build_context.cmd_doc_flags |= CmdDocFlag_AllPackages;
  1106. break;
  1107. case BuildFlag_DocFormat:
  1108. build_context.cmd_doc_flags |= CmdDocFlag_DocFormat;
  1109. break;
  1110. case BuildFlag_IgnoreWarnings:
  1111. if (build_context.warnings_as_errors) {
  1112. gb_printf_err("-ignore-warnings cannot be used with -warnings-as-errors\n");
  1113. bad_flags = true;
  1114. } else {
  1115. build_context.ignore_warnings = true;
  1116. }
  1117. break;
  1118. case BuildFlag_WarningsAsErrors:
  1119. if (build_context.ignore_warnings) {
  1120. gb_printf_err("-warnings-as-errors cannot be used with -ignore-warnings\n");
  1121. bad_flags = true;
  1122. } else {
  1123. build_context.warnings_as_errors = true;
  1124. }
  1125. break;
  1126. #if defined(GB_SYSTEM_WINDOWS)
  1127. case BuildFlag_IgnoreVsSearch:
  1128. GB_ASSERT(value.kind == ExactValue_Invalid);
  1129. build_context.ignore_microsoft_magic = true;
  1130. break;
  1131. case BuildFlag_ResourceFile: {
  1132. GB_ASSERT(value.kind == ExactValue_String);
  1133. String path = value.value_string;
  1134. path = string_trim_whitespace(path);
  1135. if (is_build_flag_path_valid(path)) {
  1136. if(!string_ends_with(path, str_lit(".rc"))) {
  1137. gb_printf_err("Invalid -resource path %.*s, missing .rc\n", LIT(path));
  1138. bad_flags = true;
  1139. break;
  1140. }
  1141. build_context.resource_filepath = substring(path, 0, string_extension_position(path));
  1142. build_context.has_resource = true;
  1143. } else {
  1144. gb_printf_err("Invalid -resource path, got %.*s\n", LIT(path));
  1145. bad_flags = true;
  1146. }
  1147. break;
  1148. }
  1149. case BuildFlag_WindowsPdbName: {
  1150. GB_ASSERT(value.kind == ExactValue_String);
  1151. String path = value.value_string;
  1152. path = string_trim_whitespace(path);
  1153. if (is_build_flag_path_valid(path)) {
  1154. // #if defined(GB_SYSTEM_WINDOWS)
  1155. // String ext = path_extension(path);
  1156. // if (ext != ".pdb") {
  1157. // path = substring(path, 0, string_extension_position(path));
  1158. // }
  1159. // #endif
  1160. build_context.pdb_filepath = path;
  1161. } else {
  1162. gb_printf_err("Invalid -pdb-name path, got %.*s\n", LIT(path));
  1163. bad_flags = true;
  1164. }
  1165. break;
  1166. }
  1167. case BuildFlag_Subsystem: {
  1168. GB_ASSERT(value.kind == ExactValue_String);
  1169. String subsystem = value.value_string;
  1170. if (str_eq_ignore_case(subsystem, str_lit("console"))) {
  1171. build_context.use_subsystem_windows = false;
  1172. } else if (str_eq_ignore_case(subsystem, str_lit("window"))) {
  1173. build_context.use_subsystem_windows = true;
  1174. } else if (str_eq_ignore_case(subsystem, str_lit("windows"))) {
  1175. build_context.use_subsystem_windows = true;
  1176. } else {
  1177. gb_printf_err("Invalid -subsystem string, got %.*s, expected either 'console' or 'windows'\n", LIT(subsystem));
  1178. bad_flags = true;
  1179. }
  1180. break;
  1181. }
  1182. #endif
  1183. }
  1184. }
  1185. if (!bf.allow_mulitple) {
  1186. set_flags[bf.kind] = ok;
  1187. }
  1188. }
  1189. break;
  1190. }
  1191. }
  1192. if (found && !is_supported) {
  1193. gb_printf_err("Unknown flag for 'odin %.*s': '%.*s'\n", LIT(build_context.command), LIT(name));
  1194. gb_printf_err("'%.*s' is supported with the following commands:\n", LIT(name));
  1195. gb_printf_err("\t");
  1196. i32 count = 0;
  1197. for (u32 i = 0; i < 32; i++) {
  1198. if (found_bf.command_support & (1<<i)) {
  1199. if (count > 0) {
  1200. gb_printf_err(", ");
  1201. }
  1202. gb_printf_err("%s", odin_command_strings[i]);
  1203. count += 1;
  1204. }
  1205. }
  1206. gb_printf_err("\n");
  1207. bad_flags = true;
  1208. } else if (!found) {
  1209. gb_printf_err("Unknown flag: '%.*s'\n", LIT(name));
  1210. bad_flags = true;
  1211. }
  1212. }
  1213. if (build_context.query_data_set_settings.ok) {
  1214. if (build_context.query_data_set_settings.kind == QueryDataSet_Invalid) {
  1215. gb_printf_err("'odin query' requires a flag determining the kind of query data set to be returned\n");
  1216. gb_printf_err("\t-global-definitions : outputs a JSON file of global definitions\n");
  1217. gb_printf_err("\t-go-to-definitions : outputs a OGTD binary file of go to definitions for identifiers within an Odin project\n");
  1218. bad_flags = true;
  1219. }
  1220. }
  1221. return !bad_flags;
  1222. }
  1223. void show_timings(Checker *c, Timings *t) {
  1224. Parser *p = c->parser;
  1225. isize lines = p->total_line_count;
  1226. isize tokens = p->total_token_count;
  1227. isize files = 0;
  1228. isize packages = p->packages.count;
  1229. isize total_file_size = 0;
  1230. f64 total_tokenizing_time = 0;
  1231. f64 total_parsing_time = 0;
  1232. for_array(i, p->packages) {
  1233. files += p->packages[i]->files.count;
  1234. for_array(j, p->packages[i]->files) {
  1235. AstFile *file = p->packages[i]->files[j];
  1236. total_tokenizing_time += file->time_to_tokenize;
  1237. total_parsing_time += file->time_to_parse;
  1238. total_file_size += file->tokenizer.end - file->tokenizer.start;
  1239. }
  1240. }
  1241. timings_print_all(t);
  1242. if (build_context.show_more_timings) {
  1243. {
  1244. gb_printf("\n");
  1245. gb_printf("Total Lines - %td\n", lines);
  1246. gb_printf("Total Tokens - %td\n", tokens);
  1247. gb_printf("Total Files - %td\n", files);
  1248. gb_printf("Total Packages - %td\n", packages);
  1249. gb_printf("Total File Size - %td\n", total_file_size);
  1250. gb_printf("\n");
  1251. }
  1252. {
  1253. f64 time = total_tokenizing_time;
  1254. gb_printf("Tokenization Only\n");
  1255. gb_printf("LOC/s - %.3f\n", cast(f64)lines/time);
  1256. gb_printf("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines);
  1257. gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/time);
  1258. gb_printf("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens);
  1259. gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/time);
  1260. gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024));
  1261. gb_printf("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size);
  1262. gb_printf("\n");
  1263. }
  1264. {
  1265. f64 time = total_parsing_time;
  1266. gb_printf("Parsing Only\n");
  1267. gb_printf("LOC/s - %.3f\n", cast(f64)lines/time);
  1268. gb_printf("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines);
  1269. gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/time);
  1270. gb_printf("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens);
  1271. gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/time);
  1272. gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024));
  1273. gb_printf("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size);
  1274. gb_printf("\n");
  1275. }
  1276. {
  1277. TimeStamp ts = {};
  1278. for_array(i, t->sections) {
  1279. TimeStamp s = t->sections[i];
  1280. if (s.label == "parse files") {
  1281. ts = s;
  1282. break;
  1283. }
  1284. }
  1285. GB_ASSERT(ts.label == "parse files");
  1286. f64 parse_time = time_stamp_as_s(ts, t->freq);
  1287. gb_printf("Parse pass\n");
  1288. gb_printf("LOC/s - %.3f\n", cast(f64)lines/parse_time);
  1289. gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
  1290. gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
  1291. gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
  1292. gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
  1293. gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/parse_time)/(1024*1024));
  1294. gb_printf("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
  1295. gb_printf("\n");
  1296. }
  1297. {
  1298. TimeStamp ts = {};
  1299. TimeStamp ts_end = {};
  1300. for_array(i, t->sections) {
  1301. TimeStamp s = t->sections[i];
  1302. if (s.label == "type check") {
  1303. ts = s;
  1304. }
  1305. if (s.label == "type check finish") {
  1306. GB_ASSERT(ts.label != "");
  1307. ts_end = s;
  1308. break;
  1309. }
  1310. }
  1311. GB_ASSERT(ts.label != "");
  1312. GB_ASSERT(ts_end.label != "");
  1313. ts.finish = ts_end.finish;
  1314. f64 parse_time = time_stamp_as_s(ts, t->freq);
  1315. gb_printf("Checker pass\n");
  1316. gb_printf("LOC/s - %.3f\n", cast(f64)lines/parse_time);
  1317. gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
  1318. gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
  1319. gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
  1320. gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
  1321. gb_printf("MiB/s - %.3f\n", (cast(f64)total_file_size/parse_time)/(1024*1024));
  1322. gb_printf("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
  1323. gb_printf("\n");
  1324. }
  1325. {
  1326. f64 total_time = t->total_time_seconds;
  1327. gb_printf("Total pass\n");
  1328. gb_printf("LOC/s - %.3f\n", cast(f64)lines/total_time);
  1329. gb_printf("us/LOC - %.3f\n", 1.0e6*total_time/cast(f64)lines);
  1330. gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/total_time);
  1331. gb_printf("us/Token - %.3f\n", 1.0e6*total_time/cast(f64)tokens);
  1332. gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/total_time);
  1333. gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/total_time)/(1024*1024));
  1334. gb_printf("us/bytes - %.3f\n", 1.0e6*total_time/cast(f64)total_file_size);
  1335. gb_printf("\n");
  1336. }
  1337. }
  1338. }
  1339. void remove_temp_files(String output_base) {
  1340. if (build_context.keep_temp_files) return;
  1341. auto data = array_make<u8>(heap_allocator(), output_base.len + 30);
  1342. defer (array_free(&data));
  1343. isize n = output_base.len;
  1344. gb_memmove(data.data, output_base.text, n);
  1345. #define EXT_REMOVE(s) do { \
  1346. gb_memmove(data.data+n, s, gb_size_of(s)); \
  1347. gb_file_remove(cast(char const *)data.data); \
  1348. } while (0)
  1349. EXT_REMOVE(".ll");
  1350. EXT_REMOVE(".bc");
  1351. EXT_REMOVE("_memcpy_pass.bc");
  1352. if (build_context.build_mode != BuildMode_Object && !build_context.keep_object_files) {
  1353. #if defined(GB_SYSTEM_WINDOWS)
  1354. EXT_REMOVE(".obj");
  1355. EXT_REMOVE(".res");
  1356. #else
  1357. EXT_REMOVE(".o");
  1358. #endif
  1359. }
  1360. #undef EXT_REMOVE
  1361. }
  1362. i32 exec_llvm_opt(String output_base) {
  1363. #if defined(GB_SYSTEM_WINDOWS)
  1364. // For more passes arguments: http://llvm.org/docs/Passes.html
  1365. return system_exec_command_line_app("llvm-opt",
  1366. "\"%.*sbin/opt\" \"%.*s.ll\" -o \"%.*s_memcpy_pass.bc\" -memcpyopt"
  1367. "",
  1368. LIT(build_context.ODIN_ROOT),
  1369. LIT(output_base), LIT(output_base))
  1370. || system_exec_command_line_app("llvm-opt",
  1371. "\"%.*sbin/opt\" \"%.*s_memcpy_pass.bc\" -o \"%.*s.bc\" %.*s "
  1372. "",
  1373. LIT(build_context.ODIN_ROOT),
  1374. LIT(output_base), LIT(output_base),
  1375. LIT(build_context.opt_flags));
  1376. #else
  1377. // NOTE(zangent): This is separate because it seems that LLVM tools are packaged
  1378. // with the Windows version, while they will be system-provided on MacOS and GNU/Linux
  1379. return system_exec_command_line_app("llvm-opt",
  1380. "opt \"%.*s.ll\" -o \"%.*s_memcpy_pass.bc\" -memcpyopt"
  1381. "",
  1382. LIT(output_base), LIT(output_base))
  1383. || system_exec_command_line_app("llvm-opt",
  1384. "opt \"%.*s_memcpy_pass.bc\" -o \"%.*s.bc\" %.*s "
  1385. "",
  1386. LIT(output_base), LIT(output_base),
  1387. LIT(build_context.opt_flags));
  1388. #endif
  1389. }
  1390. i32 exec_llvm_llc(String output_base) {
  1391. // For more arguments: http://llvm.org/docs/CommandGuide/llc.html
  1392. #if defined(GB_SYSTEM_WINDOWS)
  1393. return system_exec_command_line_app("llvm-llc",
  1394. "\"%.*sbin\\llc\" \"%.*s.bc\" -filetype=obj -O%d "
  1395. "-o \"%.*s.obj\" "
  1396. "%.*s"
  1397. "",
  1398. LIT(build_context.ODIN_ROOT),
  1399. LIT(output_base),
  1400. build_context.optimization_level,
  1401. LIT(output_base),
  1402. LIT(build_context.llc_flags));
  1403. #else
  1404. // NOTE(zangent): Linux / Unix is unfinished and not tested very well.
  1405. return system_exec_command_line_app("llc",
  1406. "llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d "
  1407. "%.*s "
  1408. "%s%.*s",
  1409. LIT(output_base),
  1410. build_context.optimization_level,
  1411. LIT(build_context.llc_flags),
  1412. build_context.cross_compiling ? "-mtriple=" : "",
  1413. cast(int)(build_context.cross_compiling ? build_context.metrics.target_triplet.len : 0),
  1414. build_context.metrics.target_triplet.text);
  1415. #endif
  1416. }
  1417. void print_show_help(String const arg0, String const &command) {
  1418. print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(arg0));
  1419. print_usage_line(0, "Usage");
  1420. print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command));
  1421. print_usage_line(0, "");
  1422. if (command == "build") {
  1423. print_usage_line(1, "build compile .odin file, or directory of .odin files, as an executable.");
  1424. print_usage_line(1, " one must contain the program's entry point, all must be in the same package.");
  1425. } else if (command == "run") {
  1426. print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable.");
  1427. } else if (command == "check") {
  1428. print_usage_line(1, "check parse and type check .odin file");
  1429. } else if (command == "test") {
  1430. print_usage_line(1, "test build ands runs 'test_*' procedures in the initial package");
  1431. } else if (command == "query") {
  1432. print_usage_line(1, "query [experimental] parse, type check, and output a .json file containing information about the program");
  1433. } else if (command == "doc") {
  1434. print_usage_line(1, "doc generate documentation from a .odin file, or directory of .odin files");
  1435. print_usage_line(2, "Examples:");
  1436. print_usage_line(3, "odin doc core/path");
  1437. print_usage_line(3, "odin doc core/path core/path/filepath");
  1438. } else if (command == "version") {
  1439. print_usage_line(1, "version print version");
  1440. }
  1441. bool doc = command == "doc";
  1442. bool build = command == "build";
  1443. bool run_or_build = command == "run" || command == "build" || command == "test";
  1444. bool check_only = command == "check";
  1445. bool check = run_or_build || command == "check";
  1446. print_usage_line(0, "");
  1447. print_usage_line(1, "Flags");
  1448. print_usage_line(0, "");
  1449. if (doc) {
  1450. print_usage_line(1, "-short");
  1451. print_usage_line(2, "Show shortened documentation for the packages");
  1452. print_usage_line(0, "");
  1453. print_usage_line(1, "-all-packages");
  1454. print_usage_line(2, "Generates documentation for all packages used in the current project");
  1455. print_usage_line(0, "");
  1456. print_usage_line(1, "-doc-format");
  1457. print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling)");
  1458. print_usage_line(0, "");
  1459. }
  1460. if (run_or_build) {
  1461. print_usage_line(1, "-out:<filepath>");
  1462. print_usage_line(2, "Set the file name of the outputted executable");
  1463. print_usage_line(2, "Example: -out:foo.exe");
  1464. print_usage_line(0, "");
  1465. print_usage_line(1, "-opt:<integer>");
  1466. print_usage_line(2, "Set the optimization level for compilation");
  1467. print_usage_line(2, "Accepted values: 0, 1, 2, 3");
  1468. print_usage_line(2, "Example: -opt:2");
  1469. print_usage_line(0, "");
  1470. print_usage_line(1, "-o:<string>");
  1471. print_usage_line(2, "Set the optimization mode for compilation");
  1472. print_usage_line(2, "Accepted values: minimal, size, speed");
  1473. print_usage_line(2, "Example: -o:speed");
  1474. print_usage_line(0, "");
  1475. }
  1476. if (check) {
  1477. print_usage_line(1, "-show-timings");
  1478. print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds");
  1479. print_usage_line(0, "");
  1480. print_usage_line(1, "-show-more-timings");
  1481. print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds");
  1482. print_usage_line(0, "");
  1483. print_usage_line(1, "-thread-count:<integer>");
  1484. print_usage_line(2, "Override the number of threads the compiler will use to compile with");
  1485. print_usage_line(2, "Example: -thread-count:2");
  1486. print_usage_line(0, "");
  1487. }
  1488. if (check_only) {
  1489. print_usage_line(1, "-show-unused");
  1490. print_usage_line(2, "Shows unused package declarations within the current project");
  1491. print_usage_line(0, "");
  1492. print_usage_line(1, "-show-unused-with-location");
  1493. print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location");
  1494. print_usage_line(0, "");
  1495. }
  1496. if (run_or_build) {
  1497. print_usage_line(1, "-keep-temp-files");
  1498. print_usage_line(2, "Keeps the temporary files generated during compilation");
  1499. print_usage_line(0, "");
  1500. }
  1501. if (check) {
  1502. print_usage_line(1, "-collection:<name>=<filepath>");
  1503. print_usage_line(2, "Defines a library collection used for imports");
  1504. print_usage_line(2, "Example: -collection:shared:dir/to/shared");
  1505. print_usage_line(2, "Usage in Code:");
  1506. print_usage_line(3, "import \"shared:foo\"");
  1507. print_usage_line(0, "");
  1508. print_usage_line(1, "-define:<name>=<expression>");
  1509. print_usage_line(2, "Defines a global constant with a value");
  1510. print_usage_line(2, "Example: -define:SPAM=123");
  1511. print_usage_line(0, "");
  1512. }
  1513. if (build) {
  1514. print_usage_line(1, "-build-mode:<mode>");
  1515. print_usage_line(2, "Sets the build mode");
  1516. print_usage_line(2, "Available options:");
  1517. print_usage_line(3, "-build-mode:exe Build as an executable");
  1518. print_usage_line(3, "-build-mode:dll Build as a dynamically linked library");
  1519. print_usage_line(3, "-build-mode:shared Build as a dynamically linked library");
  1520. print_usage_line(3, "-build-mode:obj Build as an object file");
  1521. print_usage_line(3, "-build-mode:object Build as an object file");
  1522. print_usage_line(0, "");
  1523. }
  1524. if (check) {
  1525. print_usage_line(1, "-target:<string>");
  1526. print_usage_line(2, "Sets the target for the executable to be built in");
  1527. print_usage_line(0, "");
  1528. }
  1529. if (run_or_build) {
  1530. print_usage_line(1, "-debug");
  1531. print_usage_line(2, "Enabled debug information, and defines the global constant ODIN_DEBUG to be 'true'");
  1532. print_usage_line(0, "");
  1533. print_usage_line(1, "-disable-assert");
  1534. 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'");
  1535. print_usage_line(0, "");
  1536. print_usage_line(1, "-no-bounds-check");
  1537. print_usage_line(2, "Disables bounds checking program wide");
  1538. print_usage_line(0, "");
  1539. print_usage_line(1, "-no-crt");
  1540. print_usage_line(2, "Disables automatic linking with the C Run Time");
  1541. print_usage_line(0, "");
  1542. print_usage_line(1, "-use-lld");
  1543. print_usage_line(2, "Use the LLD linker rather than the default");
  1544. print_usage_line(0, "");
  1545. }
  1546. if (check) {
  1547. print_usage_line(1, "-vet");
  1548. print_usage_line(2, "Do extra checks on the code");
  1549. print_usage_line(2, "Extra checks include:");
  1550. print_usage_line(3, "Variable shadowing within procedures");
  1551. print_usage_line(3, "Unused declarations");
  1552. print_usage_line(0, "");
  1553. print_usage_line(1, "-vet-extra");
  1554. print_usage_line(2, "Do even more checks than standard vet on the code");
  1555. print_usage_line(2, "To treat the extra warnings as errors, use -warnings-as-errors");
  1556. print_usage_line(0, "");
  1557. print_usage_line(1, "-ignore-unknown-attributes");
  1558. print_usage_line(2, "Ignores unknown attributes");
  1559. print_usage_line(2, "This can be used with metaprogramming tools");
  1560. print_usage_line(0, "");
  1561. if (command != "test") {
  1562. print_usage_line(1, "-no-entry-point");
  1563. print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure)");
  1564. print_usage_line(0, "");
  1565. }
  1566. }
  1567. if (run_or_build) {
  1568. print_usage_line(1, "-extra-linker-flags:<string>");
  1569. print_usage_line(2, "Adds extra linker specific flags in a string");
  1570. print_usage_line(0, "");
  1571. print_usage_line(1, "-microarch:<string>");
  1572. print_usage_line(2, "Specifies the specific micro-architecture for the build in a string");
  1573. print_usage_line(2, "Examples:");
  1574. print_usage_line(3, "-microarch:sandybridge");
  1575. print_usage_line(3, "-microarch:native");
  1576. print_usage_line(0, "");
  1577. }
  1578. if (check) {
  1579. print_usage_line(1, "-disallow-do");
  1580. print_usage_line(2, "Disallows the 'do' keyword in the project");
  1581. print_usage_line(0, "");
  1582. print_usage_line(1, "-default-to-nil-allocator");
  1583. print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing");
  1584. print_usage_line(0, "");
  1585. print_usage_line(1, "-insert-semicolon");
  1586. print_usage_line(2, "Inserts semicolons on newlines during tokenization using a basic rule");
  1587. print_usage_line(0, "");
  1588. print_usage_line(1, "-strict-style");
  1589. print_usage_line(2, "Enforces code style stricter whilst parsing, requiring such things as trailing commas");
  1590. print_usage_line(0, "");
  1591. print_usage_line(1, "-ignore-warnings");
  1592. print_usage_line(2, "Ignores warning messages");
  1593. print_usage_line(0, "");
  1594. print_usage_line(1, "-warnings-as-errors");
  1595. print_usage_line(2, "Treats warning messages as error messages");
  1596. print_usage_line(0, "");
  1597. }
  1598. if (run_or_build) {
  1599. #if defined(GB_SYSTEM_WINDOWS)
  1600. print_usage_line(1, "-ignore-vs-search");
  1601. print_usage_line(2, "[Windows only]");
  1602. print_usage_line(2, "Ignores the Visual Studio search for library paths");
  1603. print_usage_line(0, "");
  1604. print_usage_line(1, "-resource:<filepath>");
  1605. print_usage_line(2, "[Windows only]");
  1606. print_usage_line(2, "Defines the resource file for the executable");
  1607. print_usage_line(2, "Example: -resource:path/to/file.rc");
  1608. print_usage_line(0, "");
  1609. print_usage_line(1, "-pdb-name:<filepath>");
  1610. print_usage_line(2, "[Windows only]");
  1611. print_usage_line(2, "Defines the generated PDB name when -debug is enabled");
  1612. print_usage_line(2, "Example: -pdb-name:different.pdb");
  1613. print_usage_line(0, "");
  1614. print_usage_line(1, "-subsystem:<option>");
  1615. print_usage_line(2, "[Windows only]");
  1616. print_usage_line(2, "Defines the subsystem for the application");
  1617. print_usage_line(2, "Available options:");
  1618. print_usage_line(3, "console");
  1619. print_usage_line(3, "windows");
  1620. print_usage_line(0, "");
  1621. #endif
  1622. }
  1623. }
  1624. void print_show_unused(Checker *c) {
  1625. CheckerInfo *info = &c->info;
  1626. auto unused = array_make<Entity *>(permanent_allocator(), 0, info->entities.count);
  1627. for_array(i, info->entities) {
  1628. Entity *e = info->entities[i];
  1629. if (e == nullptr) {
  1630. continue;
  1631. }
  1632. if (e->pkg == nullptr || e->pkg->scope == nullptr) {
  1633. continue;
  1634. }
  1635. if (e->pkg->scope->flags & ScopeFlag_Builtin) {
  1636. continue;
  1637. }
  1638. switch (e->kind) {
  1639. case Entity_Invalid:
  1640. case Entity_Builtin:
  1641. case Entity_Nil:
  1642. case Entity_Label:
  1643. continue;
  1644. case Entity_Constant:
  1645. case Entity_Variable:
  1646. case Entity_TypeName:
  1647. case Entity_Procedure:
  1648. case Entity_ProcGroup:
  1649. case Entity_ImportName:
  1650. case Entity_LibraryName:
  1651. // Fine
  1652. break;
  1653. }
  1654. if ((e->scope->flags & (ScopeFlag_Pkg|ScopeFlag_File)) == 0) {
  1655. continue;
  1656. }
  1657. if (e->token.string.len == 0) {
  1658. continue;
  1659. }
  1660. if (e->token.string == "_") {
  1661. continue;
  1662. }
  1663. if (ptr_set_exists(&info->minimum_dependency_set, e)) {
  1664. continue;
  1665. }
  1666. array_add(&unused, e);
  1667. }
  1668. gb_sort_array(unused.data, unused.count, cmp_entities_for_printing);
  1669. print_usage_line(0, "Unused Package Declarations");
  1670. AstPackage *curr_pkg = nullptr;
  1671. EntityKind curr_entity_kind = Entity_Invalid;
  1672. for_array(i, unused) {
  1673. Entity *e = unused[i];
  1674. if (curr_pkg != e->pkg) {
  1675. curr_pkg = e->pkg;
  1676. curr_entity_kind = Entity_Invalid;
  1677. print_usage_line(0, "");
  1678. print_usage_line(0, "package %.*s", LIT(curr_pkg->name));
  1679. }
  1680. if (curr_entity_kind != e->kind) {
  1681. curr_entity_kind = e->kind;
  1682. print_usage_line(1, "%s", print_entity_names[e->kind]);
  1683. }
  1684. if (build_context.show_unused_with_location) {
  1685. TokenPos pos = e->token.pos;
  1686. print_usage_line(2, "%s %.*s", token_pos_to_string(pos), LIT(e->token.string));
  1687. } else {
  1688. print_usage_line(2, "%.*s", LIT(e->token.string));
  1689. }
  1690. }
  1691. print_usage_line(0, "");
  1692. }
  1693. void enforce_platform_settings(void) {
  1694. #if defined(GB_SYSTEM_OSX) && defined(GB_CPU_ARM)
  1695. build_context.use_llvm_api = true;
  1696. #endif
  1697. }
  1698. int main(int arg_count, char const **arg_ptr) {
  1699. if (arg_count < 2) {
  1700. usage(make_string_c(arg_ptr[0]));
  1701. return 1;
  1702. }
  1703. Timings *timings = &global_timings;
  1704. timings_init(timings, str_lit("Total Time"), 128);
  1705. defer (timings_destroy(timings));
  1706. arena_init(&permanent_arena, heap_allocator());
  1707. temp_allocator_init(&temporary_allocator_data, 16*1024*1024);
  1708. arena_init(&global_ast_arena, heap_allocator());
  1709. permanent_arena.use_mutex = true;
  1710. init_string_buffer_memory();
  1711. init_string_interner();
  1712. init_global_error_collector();
  1713. init_keyword_hash_table();
  1714. global_big_int_init();
  1715. array_init(&library_collections, heap_allocator());
  1716. // NOTE(bill): 'core' cannot be (re)defined by the user
  1717. add_library_collection(str_lit("core"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("core")));
  1718. map_init(&build_context.defined_values, heap_allocator());
  1719. build_context.extra_packages.allocator = heap_allocator();
  1720. Array<String> args = setup_args(arg_count, arg_ptr);
  1721. String command = args[1];
  1722. String init_filename = {};
  1723. String run_args_string = {};
  1724. bool run_output = false;
  1725. if (command == "run" || command == "test") {
  1726. if (args.count < 3) {
  1727. usage(args[0]);
  1728. return 1;
  1729. }
  1730. build_context.command_kind = Command_run;
  1731. if (command == "test") {
  1732. build_context.command_kind = Command_test;
  1733. }
  1734. Array<String> run_args = array_make<String>(heap_allocator(), 0, arg_count);
  1735. defer (array_free(&run_args));
  1736. isize last_non_run_arg = args.count;
  1737. for_array(i, args) {
  1738. if (args[i] == "--") {
  1739. last_non_run_arg = i;
  1740. }
  1741. if (i <= last_non_run_arg) {
  1742. continue;
  1743. }
  1744. array_add(&run_args, args[i]);
  1745. }
  1746. args = array_slice(args, 0, last_non_run_arg);
  1747. run_args_string = string_join_and_quote(heap_allocator(), run_args);
  1748. init_filename = args[2];
  1749. run_output = true;
  1750. } else if (command == "build") {
  1751. if (args.count < 3) {
  1752. usage(args[0]);
  1753. return 1;
  1754. }
  1755. build_context.command_kind = Command_build;
  1756. init_filename = args[2];
  1757. } else if (command == "check") {
  1758. if (args.count < 3) {
  1759. usage(args[0]);
  1760. return 1;
  1761. }
  1762. build_context.command_kind = Command_check;
  1763. build_context.no_output_files = true;
  1764. init_filename = args[2];
  1765. } else if (command == "query") {
  1766. if (args.count < 3) {
  1767. usage(args[0]);
  1768. return 1;
  1769. }
  1770. build_context.command_kind = Command_query;
  1771. build_context.no_output_files = true;
  1772. build_context.query_data_set_settings.ok = true;
  1773. init_filename = args[2];
  1774. } else if (command == "doc") {
  1775. if (args.count < 3) {
  1776. usage(args[0]);
  1777. return 1;
  1778. }
  1779. build_context.command_kind = Command_doc;
  1780. init_filename = args[2];
  1781. for (isize i = 3; i < args.count; i++) {
  1782. auto arg = args[i];
  1783. if (string_starts_with(arg, str_lit("-"))) {
  1784. break;
  1785. }
  1786. array_add(&build_context.extra_packages, arg);
  1787. }
  1788. isize extra_count = build_context.extra_packages.count;
  1789. if (extra_count > 0) {
  1790. gb_memmove(args.data + 3, args.data + 3 + extra_count, extra_count * gb_size_of(*args.data));
  1791. args.count -= extra_count;
  1792. }
  1793. build_context.no_output_files = true;
  1794. build_context.generate_docs = true;
  1795. build_context.no_entry_point = true; // ignore entry point
  1796. #if 0
  1797. print_usage_line(0, "Documentation generation is not yet supported");
  1798. return 1;
  1799. #endif
  1800. } else if (command == "version") {
  1801. build_context.command_kind = Command_version;
  1802. gb_printf("%.*s version %.*s", LIT(args[0]), LIT(ODIN_VERSION));
  1803. #ifdef NIGHTLY
  1804. gb_printf("-nightly");
  1805. #endif
  1806. #ifdef GIT_SHA
  1807. gb_printf("-%s", GIT_SHA);
  1808. #endif
  1809. gb_printf("\n");
  1810. return 0;
  1811. } else {
  1812. usage(args[0]);
  1813. return 1;
  1814. }
  1815. if (init_filename == "-help") {
  1816. build_context.show_help = true;
  1817. }
  1818. build_context.command = command;
  1819. if (!parse_build_flags(args)) {
  1820. return 1;
  1821. }
  1822. if (build_context.show_help) {
  1823. print_show_help(args[0], command);
  1824. return 0;
  1825. }
  1826. enforce_platform_settings();
  1827. // NOTE(bill): add 'shared' directory if it is not already set
  1828. if (!find_library_collection_path(str_lit("shared"), nullptr)) {
  1829. add_library_collection(str_lit("shared"),
  1830. get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("shared")));
  1831. }
  1832. init_build_context(selected_target_metrics ? selected_target_metrics->metrics : nullptr);
  1833. // if (build_context.word_size == 4 && build_context.metrics.os != TargetOs_js) {
  1834. // print_usage_line(0, "%.*s 32-bit is not yet supported for this platform", LIT(args[0]));
  1835. // return 1;
  1836. // }
  1837. if (build_context.metrics.os == TargetOs_js) {
  1838. if (!build_context.use_llvm_api) {
  1839. print_usage_line(0, "%.*s - js platform only supported with the -llvm-api backend", LIT(args[0]));
  1840. return 1;
  1841. }
  1842. }
  1843. if (!build_context.use_llvm_api) {
  1844. if (build_context.build_mode == BuildMode_Assembly) {
  1845. print_usage_line(0, "-build-mode:assembly is only supported with the -llvm-api backend", LIT(args[0]));
  1846. return 1;
  1847. }
  1848. }
  1849. init_universal();
  1850. // TODO(bill): prevent compiling without a linker
  1851. timings_start_section(timings, str_lit("parse files"));
  1852. Parser parser = {0};
  1853. if (!init_parser(&parser)) {
  1854. return 1;
  1855. }
  1856. defer (destroy_parser(&parser));
  1857. if (parse_packages(&parser, init_filename) != ParseFile_None) {
  1858. return 1;
  1859. }
  1860. if (any_errors()) {
  1861. return 1;
  1862. }
  1863. temp_allocator_free_all(&temporary_allocator_data);
  1864. timings_start_section(timings, str_lit("type check"));
  1865. Checker checker = {0};
  1866. bool checked_inited = init_checker(&checker, &parser);
  1867. defer (if (checked_inited) {
  1868. destroy_checker(&checker);
  1869. });
  1870. if (checked_inited) {
  1871. check_parsed_files(&checker);
  1872. }
  1873. if (any_errors()) {
  1874. return 1;
  1875. }
  1876. temp_allocator_free_all(&temporary_allocator_data);
  1877. if (build_context.generate_docs) {
  1878. if (global_error_collector.count != 0) {
  1879. return 1;
  1880. }
  1881. generate_documentation(&checker);
  1882. return 0;
  1883. }
  1884. if (build_context.no_output_files) {
  1885. if (build_context.show_unused) {
  1886. print_show_unused(&checker);
  1887. }
  1888. if (build_context.query_data_set_settings.ok) {
  1889. generate_and_print_query_data(&checker, timings);
  1890. } else {
  1891. if (build_context.show_timings) {
  1892. show_timings(&checker, timings);
  1893. }
  1894. }
  1895. if (global_error_collector.count != 0) {
  1896. return 1;
  1897. }
  1898. return 0;
  1899. }
  1900. if (!checked_inited) {
  1901. return 1;
  1902. }
  1903. if (build_context.use_llvm_api) {
  1904. #if defined(LLVM_BACKEND_SUPPORT)
  1905. timings_start_section(timings, str_lit("LLVM API Code Gen"));
  1906. lbGenerator gen = {};
  1907. if (!lb_init_generator(&gen, &checker)) {
  1908. return 1;
  1909. }
  1910. lb_generate_code(&gen);
  1911. temp_allocator_free_all(&temporary_allocator_data);
  1912. switch (build_context.build_mode) {
  1913. case BuildMode_Executable:
  1914. case BuildMode_DynamicLibrary:
  1915. i32 result = linker_stage(&gen);
  1916. if(result != 0) {
  1917. return 1;
  1918. }
  1919. break;
  1920. }
  1921. if (build_context.show_timings) {
  1922. show_timings(&checker, timings);
  1923. }
  1924. remove_temp_files(gen.output_base);
  1925. #if defined(GB_COMPILER_MSVC)
  1926. if (false) {
  1927. PROCESS_MEMORY_COUNTERS_EX pmc = {};
  1928. GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
  1929. SIZE_T virtual_mem_used_by_me = pmc.PrivateUsage;
  1930. gb_printf_err("virtual_memory_used: %tu B\n", virtual_mem_used_by_me);
  1931. Parser *p = checker.parser;
  1932. isize lines = p->total_line_count;
  1933. isize tokens = p->total_token_count;
  1934. isize files = 0;
  1935. isize packages = p->packages.count;
  1936. isize total_file_size = 0;
  1937. for_array(i, p->packages) {
  1938. files += p->packages[i]->files.count;
  1939. for_array(j, p->packages[i]->files) {
  1940. AstFile *file = p->packages[i]->files[j];
  1941. total_file_size += file->tokenizer.end - file->tokenizer.start;
  1942. }
  1943. }
  1944. gb_printf_err("total_file_size: %lld B\n", total_file_size);
  1945. gb_printf_err("lines: %lld\n", lines);
  1946. gb_printf_err("files: %lld\n", files);
  1947. gb_printf_err("tokens: %lld\n", tokens);
  1948. gb_printf_err("packages: %lld\n", packages);
  1949. }
  1950. #endif
  1951. if (run_output) {
  1952. #if defined(GB_SYSTEM_WINDOWS)
  1953. return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(gen.output_base), LIT(run_args_string));
  1954. #else
  1955. //NOTE(thebirk): This whole thing is a little leaky
  1956. String output_ext = {};
  1957. String complete_path = concatenate_strings(heap_allocator(), gen.output_base, output_ext);
  1958. complete_path = path_to_full_path(heap_allocator(), complete_path);
  1959. return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string));
  1960. #endif
  1961. }
  1962. return 0;
  1963. #else
  1964. gb_printf_err("LLVM C API backend is not supported on this platform yet\n");
  1965. return 1;
  1966. #endif
  1967. } else {
  1968. irGen ir_gen = {0};
  1969. if (!ir_gen_init(&ir_gen, &checker)) {
  1970. return 1;
  1971. }
  1972. // defer (ir_gen_destroy(&ir_gen));
  1973. timings_start_section(timings, str_lit("llvm ir gen"));
  1974. ir_gen_tree(&ir_gen);
  1975. temp_allocator_free_all(&temporary_allocator_data);
  1976. timings_start_section(timings, str_lit("llvm ir opt tree"));
  1977. ir_opt_tree(&ir_gen);
  1978. temp_allocator_free_all(&temporary_allocator_data);
  1979. timings_start_section(timings, str_lit("llvm ir print"));
  1980. print_llvm_ir(&ir_gen);
  1981. temp_allocator_free_all(&temporary_allocator_data);
  1982. String output_name = ir_gen.output_name;
  1983. String output_base = ir_gen.output_base;
  1984. build_context.optimization_level = gb_clamp(build_context.optimization_level, 0, 3);
  1985. timings_start_section(timings, str_lit("llvm-opt"));
  1986. exec_llvm_opt(output_base);
  1987. timings_start_section(timings, str_lit("llvm-llc"));
  1988. exec_llvm_llc(output_base);
  1989. if (build_context.build_mode == BuildMode_Object) {
  1990. // Ignore the linker
  1991. if (build_context.show_timings) {
  1992. show_timings(&checker, timings);
  1993. }
  1994. remove_temp_files(output_base);
  1995. return 0;
  1996. }
  1997. if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) {
  1998. #ifdef GB_SYSTEM_UNIX
  1999. system_exec_command_line_app("linker", "x86_64-essence-gcc -ffreestanding -nostdlib \"%.*s.o\" -o \"%.*s\" %.*s %.*s",
  2000. LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags));
  2001. #else
  2002. gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n",
  2003. LIT(target_os_names[build_context.metrics.os]),
  2004. LIT(target_arch_names[build_context.metrics.arch])
  2005. );
  2006. #endif
  2007. } else if (build_context.cross_compiling && build_context.different_os) {
  2008. gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n",
  2009. LIT(target_os_names[build_context.metrics.os]),
  2010. LIT(target_arch_names[build_context.metrics.arch])
  2011. );
  2012. build_context.keep_object_files = true;
  2013. } else {
  2014. #if defined(GB_SYSTEM_WINDOWS)
  2015. timings_start_section(timings, str_lit("msvc-link"));
  2016. gbString lib_str = gb_string_make(heap_allocator(), "");
  2017. defer (gb_string_free(lib_str));
  2018. char lib_str_buf[1024] = {0};
  2019. char const *output_ext = "exe";
  2020. gbString link_settings = gb_string_make_reserve(heap_allocator(), 256);
  2021. defer (gb_string_free(link_settings));
  2022. // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest.
  2023. Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8();
  2024. if (find_result.windows_sdk_version == 0) {
  2025. gb_printf_err("Windows SDK not found.\n");
  2026. return 1;
  2027. }
  2028. if (build_context.ignore_microsoft_magic) {
  2029. find_result = {};
  2030. }
  2031. // Add library search paths.
  2032. if (find_result.vs_library_path.len > 0) {
  2033. GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0);
  2034. GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0);
  2035. String path = {};
  2036. auto add_path = [&](String path) {
  2037. if (path[path.len-1] == '\\') {
  2038. path.len -= 1;
  2039. }
  2040. link_settings = gb_string_append_fmt(link_settings, " /LIBPATH:\"%.*s\"", LIT(path));
  2041. };
  2042. add_path(find_result.windows_sdk_um_library_path);
  2043. add_path(find_result.windows_sdk_ucrt_library_path);
  2044. add_path(find_result.vs_library_path);
  2045. }
  2046. for_array(i, ir_gen.module.foreign_library_paths) {
  2047. String lib = ir_gen.module.foreign_library_paths[i];
  2048. GB_ASSERT(lib.len < gb_count_of(lib_str_buf)-1);
  2049. isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
  2050. " \"%.*s\"", LIT(lib));
  2051. lib_str = gb_string_appendc(lib_str, lib_str_buf);
  2052. }
  2053. if (build_context.build_mode == BuildMode_DynamicLibrary) {
  2054. output_ext = "dll";
  2055. link_settings = gb_string_append_fmt(link_settings, " /DLL");
  2056. } else {
  2057. link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup");
  2058. }
  2059. if (build_context.pdb_filepath != "") {
  2060. link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(build_context.pdb_filepath));
  2061. }
  2062. if (build_context.no_crt) {
  2063. link_settings = gb_string_append_fmt(link_settings, " /nodefaultlib");
  2064. } else {
  2065. link_settings = gb_string_append_fmt(link_settings, " /defaultlib:libcmt");
  2066. }
  2067. if (ir_gen.module.generate_debug_info) {
  2068. link_settings = gb_string_append_fmt(link_settings, " /DEBUG");
  2069. }
  2070. char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE";
  2071. if (!build_context.use_lld) { // msvc
  2072. if (build_context.has_resource) {
  2073. i32 result = system_exec_command_line_app("msvc-link",
  2074. "\"rc.exe\" /nologo /fo \"%.*s.res\" \"%.*s.rc\"",
  2075. LIT(output_base),
  2076. LIT(build_context.resource_filepath)
  2077. );
  2078. if(result != 0) {
  2079. return 1;
  2080. }
  2081. result = system_exec_command_line_app("msvc-link",
  2082. "\"%.*slink.exe\" \"%.*s.obj\" \"%.*s.res\" -OUT:\"%.*s.%s\" %s "
  2083. "/nologo /incremental:no /opt:ref /subsystem:%s "
  2084. " %.*s "
  2085. " %.*s "
  2086. " %s "
  2087. "",
  2088. LIT(find_result.vs_exe_path), LIT(output_base), LIT(output_base), LIT(output_base), output_ext,
  2089. link_settings,
  2090. subsystem_str,
  2091. LIT(build_context.link_flags),
  2092. LIT(build_context.extra_linker_flags),
  2093. lib_str
  2094. );
  2095. if(result != 0) {
  2096. return 1;
  2097. }
  2098. } else {
  2099. i32 result = system_exec_command_line_app("msvc-link",
  2100. "\"%.*slink.exe\" \"%.*s.obj\" -OUT:\"%.*s.%s\" %s "
  2101. "/nologo /incremental:no /opt:ref /subsystem:%s "
  2102. " %.*s "
  2103. " %.*s "
  2104. " %s "
  2105. "",
  2106. LIT(find_result.vs_exe_path), LIT(output_base), LIT(output_base), output_ext,
  2107. link_settings,
  2108. subsystem_str,
  2109. LIT(build_context.link_flags),
  2110. LIT(build_context.extra_linker_flags),
  2111. lib_str
  2112. );
  2113. if(result != 0) {
  2114. return 1;
  2115. }
  2116. }
  2117. } else { // lld
  2118. i32 result = system_exec_command_line_app("msvc-link",
  2119. "\"%.*s\\bin\\lld-link\" \"%.*s.obj\" -OUT:\"%.*s.%s\" %s "
  2120. "/nologo /incremental:no /opt:ref /subsystem:%s "
  2121. " %.*s "
  2122. " %.*s "
  2123. " %s "
  2124. "",
  2125. LIT(build_context.ODIN_ROOT),
  2126. LIT(output_base), LIT(output_base), output_ext,
  2127. link_settings,
  2128. subsystem_str,
  2129. LIT(build_context.link_flags),
  2130. LIT(build_context.extra_linker_flags),
  2131. lib_str
  2132. );
  2133. if(result != 0) {
  2134. return 1;
  2135. }
  2136. }
  2137. if (build_context.show_timings) {
  2138. show_timings(&checker, timings);
  2139. }
  2140. remove_temp_files(output_base);
  2141. if (run_output) {
  2142. return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string));
  2143. }
  2144. #else
  2145. timings_start_section(timings, str_lit("ld-link"));
  2146. // NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe
  2147. char cwd[256];
  2148. getcwd(&cwd[0], 256);
  2149. //printf("%s\n", cwd);
  2150. // NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library
  2151. // files can be passed with -l:
  2152. gbString lib_str = gb_string_make(heap_allocator(), "-L/");
  2153. defer (gb_string_free(lib_str));
  2154. for_array(i, ir_gen.module.foreign_library_paths) {
  2155. String lib = ir_gen.module.foreign_library_paths[i];
  2156. // NOTE(zangent): Sometimes, you have to use -framework on MacOS.
  2157. // This allows you to specify '-f' in a #foreign_system_library,
  2158. // without having to implement any new syntax specifically for MacOS.
  2159. #if defined(GB_SYSTEM_OSX)
  2160. if (string_ends_with(lib, str_lit(".framework"))) {
  2161. // framework thingie
  2162. String lib_name = lib;
  2163. lib_name = remove_extension_from_path(lib_name);
  2164. lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name));
  2165. } else if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o")) || string_ends_with(lib, str_lit(".dylib"))) {
  2166. // For:
  2167. // object
  2168. // dynamic lib
  2169. // static libs, absolute full path relative to the file in which the lib was imported from
  2170. lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
  2171. } else {
  2172. // dynamic or static system lib, just link regularly searching system library paths
  2173. lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
  2174. }
  2175. #else
  2176. // NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path,
  2177. // since those are statically linked to at link time. shared libraries (.so) has to be
  2178. // available at runtime wherever the executable is run, so we make require those to be
  2179. // local to the executable (unless the system collection is used, in which case we search
  2180. // the system library paths for the library file).
  2181. if (string_ends_with(lib, str_lit(".a"))) {
  2182. // static libs, absolute full path relative to the file in which the lib was imported from
  2183. lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib));
  2184. } else if (string_ends_with(lib, str_lit(".so"))) {
  2185. // dynamic lib, relative path to executable
  2186. // NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible
  2187. // at runtimeto the executable
  2188. lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib));
  2189. } else {
  2190. // dynamic or static system lib, just link regularly searching system library paths
  2191. lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
  2192. }
  2193. #endif
  2194. }
  2195. // Unlike the Win32 linker code, the output_ext includes the dot, because
  2196. // typically executable files on *NIX systems don't have extensions.
  2197. String output_ext = {};
  2198. gbString link_settings = gb_string_make_reserve(heap_allocator(), 32);
  2199. char const *linker;
  2200. if (build_context.build_mode == BuildMode_DynamicLibrary) {
  2201. // NOTE(tetra, 2020-11-06): __$startup_runtime must be called at DLL load time.
  2202. // Clang, for some reason, won't let us pass the '-init' flag that lets us do this,
  2203. // so use ld instead.
  2204. // :UseLDForShared
  2205. linker = "ld";
  2206. // NOTE(tetra, 2021-02-24): On Darwin, the symbol has _3_ underscores; on Linux, it only has 2.
  2207. link_settings = gb_string_append_fmt(link_settings, "-init '%s$startup_runtime' ", build_context.metrics.os == TargetOs_darwin ? "___" : "__");
  2208. // Shared libraries are .dylib on MacOS and .so on Linux.
  2209. #if defined(GB_SYSTEM_OSX)
  2210. output_ext = STR_LIT(".dylib");
  2211. link_settings = gb_string_appendc(link_settings, "-dylib -dynamic ");
  2212. #else
  2213. output_ext = STR_LIT(".so");
  2214. link_settings = gb_string_appendc(link_settings, "-shared ");
  2215. #endif
  2216. } else {
  2217. #if defined(GB_SYSTEM_OSX)
  2218. linker = "ld";
  2219. #else
  2220. // TODO(zangent): Figure out how to make ld work on Linux.
  2221. // It probably has to do with including the entire CRT, but
  2222. // that's quite a complicated issue to solve while remaining distro-agnostic.
  2223. // Clang can figure out linker flags for us, and that's good enough _for now_.
  2224. linker = "clang -Wno-unused-command-line-argument";
  2225. #endif
  2226. }
  2227. if (build_context.out_filepath.len > 0) {
  2228. //NOTE(thebirk): We have a custom -out arguments, so we should use the extension from that
  2229. isize pos = string_extension_position(build_context.out_filepath);
  2230. if (pos > 0) {
  2231. output_ext = substring(build_context.out_filepath, pos, build_context.out_filepath.len);
  2232. }
  2233. }
  2234. i32 result = system_exec_command_line_app("ld-link",
  2235. "%s \"%.*s.o\" -o \"%.*s%.*s\" %s "
  2236. " %s "
  2237. " %.*s "
  2238. " %.*s "
  2239. " %s "
  2240. #if defined(GB_SYSTEM_OSX)
  2241. // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
  2242. // NOTE: If you change this (although this minimum is as low as you can go with Odin working)
  2243. // make sure to also change the 'mtriple' param passed to 'opt'
  2244. " -macosx_version_min 10.8.0 "
  2245. // This points the linker to where the entry point is
  2246. " -e _main "
  2247. #endif
  2248. , linker, LIT(output_base), LIT(output_base), LIT(output_ext),
  2249. lib_str,
  2250. #if defined(GB_SYSTEM_OSX)
  2251. "-lSystem -lm -syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib",
  2252. #else
  2253. "-lc -lm",
  2254. #endif
  2255. LIT(build_context.link_flags),
  2256. LIT(build_context.extra_linker_flags),
  2257. link_settings);
  2258. if(result != 0) {
  2259. return 1;
  2260. }
  2261. #if defined(GB_SYSTEM_OSX)
  2262. if (build_context.ODIN_DEBUG) {
  2263. // NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe
  2264. // to the symbols in the object file
  2265. system_exec_command_line_app("dsymutil",
  2266. "dsymutil %.*s%.*s", LIT(output_base), LIT(output_ext)
  2267. );
  2268. }
  2269. #endif
  2270. if (build_context.show_timings) {
  2271. show_timings(&checker, timings);
  2272. }
  2273. remove_temp_files(output_base);
  2274. if (run_output) {
  2275. //NOTE(thebirk): This whole thing is a little leaky
  2276. String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext);
  2277. complete_path = path_to_full_path(heap_allocator(), complete_path);
  2278. return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string));
  2279. }
  2280. #endif
  2281. }
  2282. }
  2283. return 0;
  2284. }