build_settings.cpp 16 KB

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