build_settings.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. enum TargetOsKind {
  2. TargetOs_Invalid,
  3. TargetOs_windows,
  4. TargetOs_darwin,
  5. TargetOs_linux,
  6. TargetOs_essence,
  7. TargetOs_COUNT,
  8. };
  9. enum TargetArchKind {
  10. TargetArch_Invalid,
  11. TargetArch_amd64,
  12. TargetArch_386,
  13. TargetArch_COUNT,
  14. };
  15. enum TargetEndianKind {
  16. TargetEndian_Invalid,
  17. TargetEndian_Little,
  18. TargetEndian_Big,
  19. TargetEndian_COUNT,
  20. };
  21. String target_os_names[TargetOs_COUNT] = {
  22. str_lit(""),
  23. str_lit("windows"),
  24. str_lit("darwin"),
  25. str_lit("linux"),
  26. str_lit("essence"),
  27. };
  28. String target_arch_names[TargetArch_COUNT] = {
  29. str_lit(""),
  30. str_lit("amd64"),
  31. str_lit("386"),
  32. };
  33. String target_endian_names[TargetEndian_COUNT] = {
  34. str_lit(""),
  35. str_lit("little"),
  36. str_lit("big"),
  37. };
  38. TargetEndianKind target_endians[TargetArch_COUNT] = {
  39. TargetEndian_Invalid,
  40. TargetEndian_Little,
  41. TargetEndian_Little,
  42. };
  43. String const ODIN_VERSION = str_lit("0.11.1");
  44. struct TargetMetrics {
  45. TargetOsKind os;
  46. TargetArchKind arch;
  47. isize word_size;
  48. isize max_align;
  49. String target_triplet;
  50. };
  51. enum QueryDataSetKind {
  52. QueryDataSet_Invalid,
  53. QueryDataSet_GlobalDefinitions,
  54. QueryDataSet_GoToDefinitions,
  55. };
  56. struct QueryDataSetSettings {
  57. QueryDataSetKind kind;
  58. bool ok;
  59. bool compact;
  60. };
  61. // This stores the information for the specify architecture of this build
  62. struct BuildContext {
  63. // Constants
  64. String ODIN_OS; // target operating system
  65. String ODIN_ARCH; // target architecture
  66. String ODIN_ENDIAN; // target endian
  67. String ODIN_VENDOR; // compiler vendor
  68. String ODIN_VERSION; // compiler version
  69. String ODIN_ROOT; // Odin ROOT
  70. bool ODIN_DEBUG; // Odin in debug mode
  71. bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not
  72. TargetEndianKind endian_kind;
  73. // In bytes
  74. i64 word_size; // Size of a pointer, must be >= 4
  75. i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
  76. String command;
  77. TargetMetrics metrics;
  78. bool show_help;
  79. String out_filepath;
  80. String resource_filepath;
  81. String pdb_filepath;
  82. bool has_resource;
  83. String opt_flags;
  84. String llc_flags;
  85. String target_triplet;
  86. String link_flags;
  87. bool is_dll;
  88. bool generate_docs;
  89. i32 optimization_level;
  90. bool show_timings;
  91. bool show_more_timings;
  92. bool keep_temp_files;
  93. bool ignore_unknown_attributes;
  94. bool no_bounds_check;
  95. bool no_output_files;
  96. bool no_crt;
  97. bool use_lld;
  98. bool vet;
  99. bool cross_compiling;
  100. QueryDataSetSettings query_data_set_settings;
  101. gbAffinity affinity;
  102. isize thread_count;
  103. Map<ExactValue> defined_values; // Key:
  104. };
  105. gb_global BuildContext build_context = {0};
  106. gb_global TargetMetrics target_windows_386 = {
  107. TargetOs_windows,
  108. TargetArch_386,
  109. 4,
  110. 8,
  111. str_lit("i686-pc-windows"),
  112. };
  113. gb_global TargetMetrics target_windows_amd64 = {
  114. TargetOs_windows,
  115. TargetArch_amd64,
  116. 8,
  117. 16,
  118. str_lit("x86_64-pc-windows-gnu"),
  119. };
  120. gb_global TargetMetrics target_linux_386 = {
  121. TargetOs_linux,
  122. TargetArch_386,
  123. 4,
  124. 8,
  125. str_lit("i686-pc-linux-gnu"),
  126. };
  127. gb_global TargetMetrics target_linux_amd64 = {
  128. TargetOs_linux,
  129. TargetArch_amd64,
  130. 8,
  131. 16,
  132. str_lit("x86_64-pc-linux-gnu"),
  133. };
  134. gb_global TargetMetrics target_darwin_amd64 = {
  135. TargetOs_darwin,
  136. TargetArch_amd64,
  137. 8,
  138. 16,
  139. str_lit("x86_64-apple-darwin"),
  140. };
  141. gb_global TargetMetrics target_essence_amd64 = {
  142. TargetOs_essence,
  143. TargetArch_amd64,
  144. 8,
  145. 16,
  146. str_lit("x86_64-pc-none-elf"),
  147. };
  148. struct NamedTargetMetrics {
  149. String name;
  150. TargetMetrics *metrics;
  151. };
  152. gb_global NamedTargetMetrics named_targets[] = {
  153. { str_lit("essence_amd64"), &target_essence_amd64 },
  154. { str_lit("darwin_amd64"), &target_darwin_amd64 },
  155. { str_lit("linux_386"), &target_linux_386 },
  156. { str_lit("linux_amd64"), &target_linux_amd64 },
  157. { str_lit("windows_386"), &target_windows_386 },
  158. { str_lit("windows_amd64"), &target_windows_amd64 },
  159. };
  160. NamedTargetMetrics *selected_target_metrics;
  161. TargetOsKind get_target_os_from_string(String str) {
  162. for (isize i = 0; i < TargetOs_COUNT; i++) {
  163. if (str_eq_ignore_case(target_os_names[i], str)) {
  164. return cast(TargetOsKind)i;
  165. }
  166. }
  167. return TargetOs_Invalid;
  168. }
  169. TargetArchKind get_target_arch_from_string(String str) {
  170. for (isize i = 0; i < TargetArch_COUNT; i++) {
  171. if (str_eq_ignore_case(target_arch_names[i], str)) {
  172. return cast(TargetArchKind)i;
  173. }
  174. }
  175. return TargetArch_Invalid;
  176. }
  177. bool is_excluded_target_filename(String name) {
  178. String const ext = str_lit(".odin");
  179. String original_name = name;
  180. GB_ASSERT(string_ends_with(name, ext));
  181. name = substring(name, 0, name.len-ext.len);
  182. String str1 = {};
  183. String str2 = {};
  184. isize n = 0;
  185. str1 = name;
  186. n = str1.len;
  187. for (isize i = str1.len-1; i >= 0 && str1[i] != '_'; i--) {
  188. n -= 1;
  189. }
  190. str1 = substring(str1, n, str1.len);
  191. str2 = substring(name, 0, gb_max(n-1, 0));
  192. n = str2.len;
  193. for (isize i = str2.len-1; i >= 0 && str2[i] != '_'; i--) {
  194. n -= 1;
  195. }
  196. str2 = substring(str2, n, str2.len);
  197. if (str1 == name) {
  198. return false;
  199. }
  200. TargetOsKind os1 = get_target_os_from_string(str1);
  201. TargetArchKind arch1 = get_target_arch_from_string(str1);
  202. TargetOsKind os2 = get_target_os_from_string(str2);
  203. TargetArchKind arch2 = get_target_arch_from_string(str2);
  204. if (os1 != TargetOs_Invalid && arch2 != TargetArch_Invalid) {
  205. return os1 != build_context.metrics.os || arch2 != build_context.metrics.arch;
  206. } else if (arch1 != TargetArch_Invalid && os2 != TargetOs_Invalid) {
  207. return arch1 != build_context.metrics.arch || os2 != build_context.metrics.os;
  208. } else if (os1 != TargetOs_Invalid) {
  209. return os1 != build_context.metrics.os;
  210. } else if (arch1 != TargetArch_Invalid) {
  211. return arch1 != build_context.metrics.arch;
  212. }
  213. return false;
  214. }
  215. struct LibraryCollections {
  216. String name;
  217. String path;
  218. };
  219. gb_global Array<LibraryCollections> library_collections = {0};
  220. void add_library_collection(String name, String path) {
  221. // TODO(bill): Check the path is valid and a directory
  222. LibraryCollections lc = {name, string_trim_whitespace(path)};
  223. array_add(&library_collections, lc);
  224. }
  225. bool find_library_collection_path(String name, String *path) {
  226. for_array(i, library_collections) {
  227. if (library_collections[i].name == name) {
  228. if (path) *path = library_collections[i].path;
  229. return true;
  230. }
  231. }
  232. return false;
  233. }
  234. // TODO(bill): OS dependent versions for the BuildContext
  235. // join_path
  236. // is_dir
  237. // is_file
  238. // is_abs_path
  239. // has_subdir
  240. String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
  241. String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1};
  242. #if defined(GB_SYSTEM_WINDOWS)
  243. String odin_root_dir(void) {
  244. String path = global_module_path;
  245. isize len, i;
  246. gbTempArenaMemory tmp;
  247. wchar_t *text;
  248. if (global_module_path_set) {
  249. return global_module_path;
  250. }
  251. auto path_buf = array_make<wchar_t>(heap_allocator(), 300);
  252. len = 0;
  253. for (;;) {
  254. len = GetModuleFileNameW(nullptr, &path_buf[0], cast(int)path_buf.count);
  255. if (len == 0) {
  256. return make_string(nullptr, 0);
  257. }
  258. if (len < path_buf.count) {
  259. break;
  260. }
  261. array_resize(&path_buf, 2*path_buf.count + 300);
  262. }
  263. len += 1; // NOTE(bill): It needs an extra 1 for some reason
  264. gb_mutex_lock(&string_buffer_mutex);
  265. defer (gb_mutex_unlock(&string_buffer_mutex));
  266. tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
  267. defer (gb_temp_arena_memory_end(tmp));
  268. text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
  269. GetModuleFileNameW(nullptr, text, cast(int)len);
  270. path = string16_to_string(heap_allocator(), make_string16(text, len));
  271. for (i = path.len-1; i >= 0; i--) {
  272. u8 c = path[i];
  273. if (c == '/' || c == '\\') {
  274. break;
  275. }
  276. path.len--;
  277. }
  278. global_module_path = path;
  279. global_module_path_set = true;
  280. array_free(&path_buf);
  281. return path;
  282. }
  283. #elif defined(GB_SYSTEM_OSX)
  284. #include <mach-o/dyld.h>
  285. String path_to_fullpath(gbAllocator a, String s);
  286. String odin_root_dir(void) {
  287. String path = global_module_path;
  288. isize len, i;
  289. gbTempArenaMemory tmp;
  290. u8 *text;
  291. if (global_module_path_set) {
  292. return global_module_path;
  293. }
  294. auto path_buf = array_make<char>(heap_allocator(), 300);
  295. len = 0;
  296. for (;;) {
  297. u32 sz = path_buf.count;
  298. int res = _NSGetExecutablePath(&path_buf[0], &sz);
  299. if(res == 0) {
  300. len = sz;
  301. break;
  302. } else {
  303. array_resize(&path_buf, sz + 1);
  304. }
  305. }
  306. gb_mutex_lock(&string_buffer_mutex);
  307. defer (gb_mutex_unlock(&string_buffer_mutex));
  308. tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
  309. defer (gb_temp_arena_memory_end(tmp));
  310. text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
  311. gb_memmove(text, &path_buf[0], len);
  312. path = path_to_fullpath(heap_allocator(), make_string(text, len));
  313. for (i = path.len-1; i >= 0; i--) {
  314. u8 c = path[i];
  315. if (c == '/' || c == '\\') {
  316. break;
  317. }
  318. path.len--;
  319. }
  320. global_module_path = path;
  321. global_module_path_set = true;
  322. // array_free(&path_buf);
  323. return path;
  324. }
  325. #else
  326. // NOTE: Linux / Unix is unfinished and not tested very well.
  327. #include <sys/stat.h>
  328. String path_to_fullpath(gbAllocator a, String s);
  329. String odin_root_dir(void) {
  330. String path = global_module_path;
  331. isize len, i;
  332. gbTempArenaMemory tmp;
  333. u8 *text;
  334. if (global_module_path_set) {
  335. return global_module_path;
  336. }
  337. auto path_buf = array_make<char>(heap_allocator(), 300);
  338. defer (array_free(&path_buf));
  339. len = 0;
  340. for (;;) {
  341. // This is not a 100% reliable system, but for the purposes
  342. // of this compiler, it should be _good enough_.
  343. // That said, there's no solid 100% method on Linux to get the program's
  344. // path without checking this link. Sorry.
  345. len = readlink("/proc/self/exe", &path_buf[0], path_buf.count);
  346. if(len == 0) {
  347. return make_string(nullptr, 0);
  348. }
  349. if (len < path_buf.count) {
  350. break;
  351. }
  352. array_resize(&path_buf, 2*path_buf.count + 300);
  353. }
  354. gb_mutex_lock(&string_buffer_mutex);
  355. defer (gb_mutex_unlock(&string_buffer_mutex));
  356. tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
  357. defer (gb_temp_arena_memory_end(tmp));
  358. text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
  359. gb_memmove(text, &path_buf[0], len);
  360. path = path_to_fullpath(heap_allocator(), make_string(text, len));
  361. for (i = path.len-1; i >= 0; i--) {
  362. u8 c = path[i];
  363. if (c == '/' || c == '\\') {
  364. break;
  365. }
  366. path.len--;
  367. }
  368. global_module_path = path;
  369. global_module_path_set = true;
  370. return path;
  371. }
  372. #endif
  373. #if defined(GB_SYSTEM_WINDOWS)
  374. String path_to_fullpath(gbAllocator a, String s) {
  375. String result = {};
  376. gb_mutex_lock(&string_buffer_mutex);
  377. defer (gb_mutex_unlock(&string_buffer_mutex));
  378. gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
  379. defer (gb_temp_arena_memory_end(tmp));
  380. String16 string16 = string_to_string16(string_buffer_allocator, s);
  381. DWORD len = GetFullPathNameW(&string16[0], 0, nullptr, nullptr);
  382. if (len != 0) {
  383. wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
  384. GetFullPathNameW(&string16[0], len, text, nullptr);
  385. text[len] = 0;
  386. result = string16_to_string(a, make_string16(text, len));
  387. result = string_trim_whitespace(result);
  388. // Replace Windows style separators
  389. for (isize i = 0; i < result.len; i++) {
  390. if (result.text[i] == '\\') {
  391. result.text[i] = '/';
  392. }
  393. }
  394. }
  395. return result;
  396. }
  397. #elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
  398. String path_to_fullpath(gbAllocator a, String s) {
  399. char *p;
  400. gb_mutex_lock(&string_buffer_mutex);
  401. p = realpath(cast(char *)s.text, 0);
  402. gb_mutex_unlock(&string_buffer_mutex);
  403. if(p == nullptr) return String{};
  404. return make_string_c(p);
  405. }
  406. #else
  407. #error Implement system
  408. #endif
  409. String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
  410. u8 *str = gb_alloc_array(heap_allocator(), u8, base_dir.len+1+path.len+1);
  411. defer (gb_free(heap_allocator(), str));
  412. isize i = 0;
  413. gb_memmove(str+i, base_dir.text, base_dir.len); i += base_dir.len;
  414. gb_memmove(str+i, "/", 1); i += 1;
  415. gb_memmove(str+i, path.text, path.len); i += path.len;
  416. str[i] = 0;
  417. String res = make_string(str, i);
  418. res = string_trim_whitespace(res);
  419. return path_to_fullpath(a, res);
  420. }
  421. String get_fullpath_core(gbAllocator a, String path) {
  422. String module_dir = odin_root_dir();
  423. String core = str_lit("core/");
  424. isize str_len = module_dir.len + core.len + path.len;
  425. u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
  426. defer (gb_free(heap_allocator(), str));
  427. isize i = 0;
  428. gb_memmove(str+i, module_dir.text, module_dir.len); i += module_dir.len;
  429. gb_memmove(str+i, core.text, core.len); i += core.len;
  430. gb_memmove(str+i, path.text, path.len); i += path.len;
  431. str[i] = 0;
  432. String res = make_string(str, i);
  433. res = string_trim_whitespace(res);
  434. return path_to_fullpath(a, res);
  435. }
  436. void init_build_context(TargetMetrics *cross_target) {
  437. BuildContext *bc = &build_context;
  438. gb_affinity_init(&bc->affinity);
  439. if (bc->thread_count == 0) {
  440. bc->thread_count = gb_max(bc->affinity.thread_count, 1);
  441. }
  442. bc->ODIN_VENDOR = str_lit("odin");
  443. bc->ODIN_VERSION = ODIN_VERSION;
  444. bc->ODIN_ROOT = odin_root_dir();
  445. TargetMetrics metrics = {};
  446. #if defined(GB_ARCH_64_BIT)
  447. #if defined(GB_SYSTEM_WINDOWS)
  448. metrics = target_windows_amd64;
  449. #elif defined(GB_SYSTEM_OSX)
  450. metrics = target_darwin_amd64;
  451. #else
  452. metrics = target_linux_amd64;
  453. #endif
  454. #else
  455. #if defined(GB_SYSTEM_WINDOWS)
  456. metrics = target_windows_386;
  457. #elif defined(GB_SYSTEM_OSX)
  458. #error "Unsupported architecture"
  459. #else
  460. metrics = target_linux_386;
  461. #endif
  462. #endif
  463. if (cross_target) {
  464. metrics = *cross_target;
  465. bc->cross_compiling = true;
  466. }
  467. GB_ASSERT(metrics.os != TargetOs_Invalid);
  468. GB_ASSERT(metrics.arch != TargetArch_Invalid);
  469. GB_ASSERT(metrics.word_size > 1);
  470. GB_ASSERT(metrics.max_align > 1);
  471. bc->metrics = metrics;
  472. bc->ODIN_OS = target_os_names[metrics.os];
  473. bc->ODIN_ARCH = target_arch_names[metrics.arch];
  474. bc->ODIN_ENDIAN = target_endian_names[target_endians[metrics.arch]];
  475. bc->endian_kind = target_endians[metrics.arch];
  476. bc->word_size = metrics.word_size;
  477. bc->max_align = metrics.max_align;
  478. bc->link_flags = str_lit(" ");
  479. bc->opt_flags = str_lit(" ");
  480. bc->target_triplet = metrics.target_triplet;
  481. gbString llc_flags = gb_string_make_reserve(heap_allocator(), 64);
  482. if (bc->ODIN_DEBUG) {
  483. // llc_flags = gb_string_appendc(llc_flags, "-debug-compile ");
  484. }
  485. // NOTE(zangent): The linker flags to set the build architecture are different
  486. // across OSs. It doesn't make sense to allocate extra data on the heap
  487. // here, so I just #defined the linker flags to keep things concise.
  488. if (bc->metrics.arch == TargetArch_amd64) {
  489. llc_flags = gb_string_appendc(llc_flags, "-march=x86-64 ");
  490. switch (bc->metrics.os) {
  491. case TargetOs_windows:
  492. bc->link_flags = str_lit("/machine:x64 ");
  493. break;
  494. case TargetOs_darwin:
  495. break;
  496. case TargetOs_linux:
  497. bc->link_flags = str_lit("-arch x86-64 ");
  498. break;
  499. }
  500. } else if (bc->metrics.arch == TargetArch_386) {
  501. llc_flags = gb_string_appendc(llc_flags, "-march=x86 ");
  502. switch (bc->metrics.os) {
  503. case TargetOs_windows:
  504. bc->link_flags = str_lit("/machine:x86 ");
  505. break;
  506. case TargetOs_darwin:
  507. gb_printf_err("Unsupported architecture\n");
  508. gb_exit(1);
  509. break;
  510. case TargetOs_linux:
  511. bc->link_flags = str_lit("-arch x86 ");
  512. break;
  513. }
  514. } else {
  515. gb_printf_err("Unsupported architecture\n");;
  516. gb_exit(1);
  517. }
  518. bc->llc_flags = make_string_c(llc_flags);
  519. bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3);
  520. gbString opt_flags = gb_string_make_reserve(heap_allocator(), 64);
  521. if (bc->optimization_level != 0) {
  522. opt_flags = gb_string_append_fmt(opt_flags, "-O%d ", bc->optimization_level);
  523. // NOTE(lachsinc): The following options were previously passed during call
  524. // to opt in main.cpp:exec_llvm_opt().
  525. // -die: Dead instruction elimination
  526. // -memcpyopt: MemCpy optimization
  527. }
  528. if (bc->ODIN_DEBUG == false) {
  529. opt_flags = gb_string_appendc(opt_flags, "-memcpyopt -die ");
  530. }
  531. // NOTE(lachsinc): This optimization option was previously required to get
  532. // around an issue in fmt.odin. Thank bp for tracking it down! Leaving for now until the issue
  533. // is resolved and confirmed by Bill. Maybe it should be readded in non-debug builds.
  534. // if (bc->ODIN_DEBUG == false) {
  535. // opt_flags = gb_string_appendc(opt_flags, "-mem2reg ");
  536. // }
  537. bc->opt_flags = make_string_c(opt_flags);
  538. #undef LINK_FLAG_X64
  539. #undef LINK_FLAG_386
  540. }