build_settings.cpp 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561
  1. #if defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD)
  2. #include <sys/types.h>
  3. #include <sys/sysctl.h>
  4. #endif
  5. // #if defined(GB_SYSTEM_WINDOWS)
  6. // #define DEFAULT_TO_THREADED_CHECKER
  7. // #endif
  8. enum TargetOsKind : u16 {
  9. TargetOs_Invalid,
  10. TargetOs_windows,
  11. TargetOs_darwin,
  12. TargetOs_linux,
  13. TargetOs_essence,
  14. TargetOs_freebsd,
  15. TargetOs_openbsd,
  16. TargetOs_wasi,
  17. TargetOs_js,
  18. TargetOs_freestanding,
  19. TargetOs_COUNT,
  20. };
  21. enum TargetArchKind : u16 {
  22. TargetArch_Invalid,
  23. TargetArch_amd64,
  24. TargetArch_i386,
  25. TargetArch_arm32,
  26. TargetArch_arm64,
  27. TargetArch_wasm32,
  28. TargetArch_wasm64,
  29. TargetArch_COUNT,
  30. };
  31. enum TargetEndianKind : u8 {
  32. TargetEndian_Invalid,
  33. TargetEndian_Little,
  34. TargetEndian_Big,
  35. TargetEndian_COUNT,
  36. };
  37. enum TargetABIKind : u16 {
  38. TargetABI_Default,
  39. TargetABI_Win64,
  40. TargetABI_SysV,
  41. TargetABI_COUNT,
  42. };
  43. String target_os_names[TargetOs_COUNT] = {
  44. str_lit(""),
  45. str_lit("windows"),
  46. str_lit("darwin"),
  47. str_lit("linux"),
  48. str_lit("essence"),
  49. str_lit("freebsd"),
  50. str_lit("openbsd"),
  51. str_lit("wasi"),
  52. str_lit("js"),
  53. str_lit("freestanding"),
  54. };
  55. String target_arch_names[TargetArch_COUNT] = {
  56. str_lit(""),
  57. str_lit("amd64"),
  58. str_lit("i386"),
  59. str_lit("arm32"),
  60. str_lit("arm64"),
  61. str_lit("wasm32"),
  62. str_lit("wasm64"),
  63. };
  64. String target_endian_names[TargetEndian_COUNT] = {
  65. str_lit(""),
  66. str_lit("little"),
  67. str_lit("big"),
  68. };
  69. String target_abi_names[TargetABI_COUNT] = {
  70. str_lit(""),
  71. str_lit("win64"),
  72. str_lit("sysv"),
  73. };
  74. TargetEndianKind target_endians[TargetArch_COUNT] = {
  75. TargetEndian_Invalid,
  76. TargetEndian_Little,
  77. TargetEndian_Little,
  78. TargetEndian_Little,
  79. TargetEndian_Little,
  80. TargetEndian_Little,
  81. };
  82. #ifndef ODIN_VERSION_RAW
  83. #define ODIN_VERSION_RAW "dev-unknown-unknown"
  84. #endif
  85. String const ODIN_VERSION = str_lit(ODIN_VERSION_RAW);
  86. struct TargetMetrics {
  87. TargetOsKind os;
  88. TargetArchKind arch;
  89. isize word_size;
  90. isize max_align;
  91. isize max_simd_align;
  92. String target_triplet;
  93. String target_data_layout;
  94. TargetABIKind abi;
  95. };
  96. enum QueryDataSetKind {
  97. QueryDataSet_Invalid,
  98. QueryDataSet_GlobalDefinitions,
  99. QueryDataSet_GoToDefinitions,
  100. };
  101. struct QueryDataSetSettings {
  102. QueryDataSetKind kind;
  103. bool ok;
  104. bool compact;
  105. };
  106. enum BuildModeKind {
  107. BuildMode_Executable,
  108. BuildMode_DynamicLibrary,
  109. BuildMode_Object,
  110. BuildMode_Assembly,
  111. BuildMode_LLVM_IR,
  112. BuildMode_COUNT,
  113. };
  114. enum CommandKind : u32 {
  115. Command_run = 1<<0,
  116. Command_build = 1<<1,
  117. Command_check = 1<<3,
  118. Command_query = 1<<4,
  119. Command_doc = 1<<5,
  120. Command_version = 1<<6,
  121. Command_test = 1<<7,
  122. Command_strip_semicolon = 1<<8,
  123. Command_bug_report = 1<<9,
  124. Command__does_check = Command_run|Command_build|Command_check|Command_query|Command_doc|Command_test|Command_strip_semicolon,
  125. Command__does_build = Command_run|Command_build|Command_test,
  126. Command_all = ~(u32)0,
  127. };
  128. char const *odin_command_strings[32] = {
  129. "run",
  130. "build",
  131. "check",
  132. "query",
  133. "doc",
  134. "version",
  135. "test",
  136. "strip-semicolon",
  137. };
  138. enum CmdDocFlag : u32 {
  139. CmdDocFlag_Short = 1<<0,
  140. CmdDocFlag_AllPackages = 1<<1,
  141. CmdDocFlag_DocFormat = 1<<2,
  142. };
  143. enum TimingsExportFormat : i32 {
  144. TimingsExportUnspecified = 0,
  145. TimingsExportJson = 1,
  146. TimingsExportCSV = 2,
  147. };
  148. enum ErrorPosStyle {
  149. ErrorPosStyle_Default, // path(line:column) msg
  150. ErrorPosStyle_Unix, // path:line:column: msg
  151. ErrorPosStyle_COUNT
  152. };
  153. enum RelocMode : u8 {
  154. RelocMode_Default,
  155. RelocMode_Static,
  156. RelocMode_PIC,
  157. RelocMode_DynamicNoPIC,
  158. };
  159. enum BuildPath : u8 {
  160. BuildPath_Main_Package, // Input Path to the package directory (or file) we're building.
  161. BuildPath_RC, // Input Path for .rc file, can be set with `-resource:`.
  162. BuildPath_RES, // Output Path for .res file, generated from previous.
  163. BuildPath_Win_SDK_Bin_Path, // windows_sdk_bin_path
  164. BuildPath_Win_SDK_UM_Lib, // windows_sdk_um_library_path
  165. BuildPath_Win_SDK_UCRT_Lib, // windows_sdk_ucrt_library_path
  166. BuildPath_VS_EXE, // vs_exe_path
  167. BuildPath_VS_LIB, // vs_library_path
  168. BuildPath_Output, // Output Path for .exe, .dll, .so, etc. Can be overridden with `-out:`.
  169. BuildPath_PDB, // Output Path for .pdb file, can be overridden with `-pdb-name:`.
  170. BuildPathCOUNT,
  171. };
  172. // This stores the information for the specify architecture of this build
  173. struct BuildContext {
  174. // Constants
  175. String ODIN_OS; // target operating system
  176. String ODIN_ARCH; // target architecture
  177. String ODIN_VENDOR; // compiler vendor
  178. String ODIN_VERSION; // compiler version
  179. String ODIN_ROOT; // Odin ROOT
  180. String ODIN_BUILD_PROJECT_NAME; // Odin main/initial package's directory name
  181. bool ODIN_DEBUG; // Odin in debug mode
  182. bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not
  183. bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing)
  184. bool ODIN_FOREIGN_ERROR_PROCEDURES;
  185. bool ODIN_VALGRIND_SUPPORT;
  186. ErrorPosStyle ODIN_ERROR_POS_STYLE;
  187. TargetEndianKind endian_kind;
  188. // In bytes
  189. i64 word_size; // Size of a pointer, must be >= 4
  190. i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
  191. i64 max_simd_align; // max alignment, must be >= 1 (and typically >= word_size)
  192. CommandKind command_kind;
  193. String command;
  194. TargetMetrics metrics;
  195. bool show_help;
  196. Array<Path> build_paths; // Contains `Path` objects to output filename, pdb, resource and intermediate files.
  197. // BuildPath enum contains the indices of paths we know *before* the work starts.
  198. String out_filepath;
  199. String resource_filepath;
  200. String pdb_filepath;
  201. bool has_resource;
  202. String link_flags;
  203. String extra_linker_flags;
  204. String extra_assembler_flags;
  205. String microarch;
  206. BuildModeKind build_mode;
  207. bool generate_docs;
  208. i32 optimization_level;
  209. bool show_timings;
  210. TimingsExportFormat export_timings_format;
  211. String export_timings_file;
  212. bool show_unused;
  213. bool show_unused_with_location;
  214. bool show_more_timings;
  215. bool show_system_calls;
  216. bool keep_temp_files;
  217. bool ignore_unknown_attributes;
  218. bool no_bounds_check;
  219. bool no_dynamic_literals;
  220. bool no_output_files;
  221. bool no_crt;
  222. bool no_entry_point;
  223. bool use_lld;
  224. bool vet;
  225. bool vet_extra;
  226. bool cross_compiling;
  227. bool different_os;
  228. bool keep_object_files;
  229. bool disallow_do;
  230. bool strict_style;
  231. bool strict_style_init_only;
  232. bool ignore_warnings;
  233. bool warnings_as_errors;
  234. bool show_error_line;
  235. bool ignore_lazy;
  236. bool use_subsystem_windows;
  237. bool ignore_microsoft_magic;
  238. bool linker_map_file;
  239. bool use_separate_modules;
  240. bool threaded_checker;
  241. bool show_debug_messages;
  242. bool copy_file_contents;
  243. bool disallow_rtti;
  244. RelocMode reloc_mode;
  245. bool disable_red_zone;
  246. u32 cmd_doc_flags;
  247. Array<String> extra_packages;
  248. QueryDataSetSettings query_data_set_settings;
  249. StringSet test_names;
  250. gbAffinity affinity;
  251. isize thread_count;
  252. PtrMap<char const *, ExactValue> defined_values;
  253. BlockingMutex target_features_mutex;
  254. StringSet target_features_set;
  255. String target_features_string;
  256. String minimum_os_version_string;
  257. };
  258. gb_global BuildContext build_context = {0};
  259. bool global_warnings_as_errors(void) {
  260. return build_context.warnings_as_errors;
  261. }
  262. bool global_ignore_warnings(void) {
  263. return build_context.ignore_warnings;
  264. }
  265. gb_global TargetMetrics target_windows_i386 = {
  266. TargetOs_windows,
  267. TargetArch_i386,
  268. 4, 4, 8,
  269. str_lit("i386-pc-windows-msvc"),
  270. };
  271. gb_global TargetMetrics target_windows_amd64 = {
  272. TargetOs_windows,
  273. TargetArch_amd64,
  274. 8, 8, 16,
  275. str_lit("x86_64-pc-windows-msvc"),
  276. str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
  277. };
  278. gb_global TargetMetrics target_linux_i386 = {
  279. TargetOs_linux,
  280. TargetArch_i386,
  281. 4, 4, 8,
  282. str_lit("i386-pc-linux-gnu"),
  283. };
  284. gb_global TargetMetrics target_linux_amd64 = {
  285. TargetOs_linux,
  286. TargetArch_amd64,
  287. 8, 8, 16,
  288. str_lit("x86_64-pc-linux-gnu"),
  289. str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
  290. };
  291. gb_global TargetMetrics target_linux_arm64 = {
  292. TargetOs_linux,
  293. TargetArch_arm64,
  294. 8, 8, 16,
  295. str_lit("aarch64-linux-elf"),
  296. str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"),
  297. };
  298. gb_global TargetMetrics target_linux_arm32 = {
  299. TargetOs_linux,
  300. TargetArch_arm32,
  301. 4, 4, 8,
  302. str_lit("arm-linux-gnu"),
  303. str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"),
  304. };
  305. gb_global TargetMetrics target_darwin_amd64 = {
  306. TargetOs_darwin,
  307. TargetArch_amd64,
  308. 8, 8, 16,
  309. str_lit("x86_64-apple-darwin"),
  310. str_lit("e-m:o-i64:64-f80:128-n8:16:32:64-S128"),
  311. };
  312. gb_global TargetMetrics target_darwin_arm64 = {
  313. TargetOs_darwin,
  314. TargetArch_arm64,
  315. 8, 8, 16,
  316. str_lit("arm64-apple-macosx11.0.0"),
  317. str_lit("e-m:o-i64:64-i128:128-n32:64-S128"), // TODO(bill): Is this correct?
  318. };
  319. gb_global TargetMetrics target_freebsd_i386 = {
  320. TargetOs_freebsd,
  321. TargetArch_i386,
  322. 4, 4, 8,
  323. str_lit("i386-unknown-freebsd-elf"),
  324. };
  325. gb_global TargetMetrics target_freebsd_amd64 = {
  326. TargetOs_freebsd,
  327. TargetArch_amd64,
  328. 8, 8, 16,
  329. str_lit("x86_64-unknown-freebsd-elf"),
  330. str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
  331. };
  332. gb_global TargetMetrics target_openbsd_amd64 = {
  333. TargetOs_openbsd,
  334. TargetArch_amd64,
  335. 8, 8, 16,
  336. str_lit("x86_64-unknown-openbsd-elf"),
  337. str_lit("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"),
  338. };
  339. gb_global TargetMetrics target_essence_amd64 = {
  340. TargetOs_essence,
  341. TargetArch_amd64,
  342. 8, 8, 16,
  343. str_lit("x86_64-pc-none-elf"),
  344. };
  345. gb_global TargetMetrics target_freestanding_wasm32 = {
  346. TargetOs_freestanding,
  347. TargetArch_wasm32,
  348. 4, 8, 16,
  349. str_lit("wasm32-freestanding-js"),
  350. str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
  351. };
  352. gb_global TargetMetrics target_js_wasm32 = {
  353. TargetOs_js,
  354. TargetArch_wasm32,
  355. 4, 8, 16,
  356. str_lit("wasm32-js-js"),
  357. str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
  358. };
  359. gb_global TargetMetrics target_wasi_wasm32 = {
  360. TargetOs_wasi,
  361. TargetArch_wasm32,
  362. 4, 8, 16,
  363. str_lit("wasm32-wasi-js"),
  364. str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
  365. };
  366. gb_global TargetMetrics target_js_wasm64 = {
  367. TargetOs_js,
  368. TargetArch_wasm64,
  369. 8, 8, 16,
  370. str_lit("wasm64-js-js"),
  371. str_lit(""),
  372. };
  373. gb_global TargetMetrics target_freestanding_amd64_sysv = {
  374. TargetOs_freestanding,
  375. TargetArch_amd64,
  376. 8, 8, 16,
  377. str_lit("x86_64-pc-none-gnu"),
  378. str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
  379. TargetABI_SysV,
  380. };
  381. struct NamedTargetMetrics {
  382. String name;
  383. TargetMetrics *metrics;
  384. };
  385. gb_global NamedTargetMetrics named_targets[] = {
  386. { str_lit("darwin_amd64"), &target_darwin_amd64 },
  387. { str_lit("darwin_arm64"), &target_darwin_arm64 },
  388. { str_lit("essence_amd64"), &target_essence_amd64 },
  389. { str_lit("linux_i386"), &target_linux_i386 },
  390. { str_lit("linux_amd64"), &target_linux_amd64 },
  391. { str_lit("linux_arm64"), &target_linux_arm64 },
  392. { str_lit("linux_arm32"), &target_linux_arm32 },
  393. { str_lit("windows_i386"), &target_windows_i386 },
  394. { str_lit("windows_amd64"), &target_windows_amd64 },
  395. { str_lit("freebsd_i386"), &target_freebsd_i386 },
  396. { str_lit("freebsd_amd64"), &target_freebsd_amd64 },
  397. { str_lit("openbsd_amd64"), &target_openbsd_amd64 },
  398. { str_lit("freestanding_wasm32"), &target_freestanding_wasm32 },
  399. { str_lit("wasi_wasm32"), &target_wasi_wasm32 },
  400. { str_lit("js_wasm32"), &target_js_wasm32 },
  401. // { str_lit("js_wasm64"), &target_js_wasm64 },
  402. { str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
  403. };
  404. NamedTargetMetrics *selected_target_metrics;
  405. TargetOsKind get_target_os_from_string(String str) {
  406. for (isize i = 0; i < TargetOs_COUNT; i++) {
  407. if (str_eq_ignore_case(target_os_names[i], str)) {
  408. return cast(TargetOsKind)i;
  409. }
  410. }
  411. return TargetOs_Invalid;
  412. }
  413. TargetArchKind get_target_arch_from_string(String str) {
  414. for (isize i = 0; i < TargetArch_COUNT; i++) {
  415. if (str_eq_ignore_case(target_arch_names[i], str)) {
  416. return cast(TargetArchKind)i;
  417. }
  418. }
  419. return TargetArch_Invalid;
  420. }
  421. bool is_excluded_target_filename(String name) {
  422. String original_name = name;
  423. name = remove_extension_from_path(name);
  424. if (string_starts_with(name, str_lit("."))) {
  425. // Ignore .*.odin files
  426. return true;
  427. }
  428. if (build_context.command_kind != Command_test) {
  429. String test_suffix = str_lit("_test");
  430. if (string_ends_with(name, test_suffix) && name != test_suffix) {
  431. // Ignore *_test.odin files
  432. return true;
  433. }
  434. }
  435. String str1 = {};
  436. String str2 = {};
  437. isize n = 0;
  438. str1 = name;
  439. n = str1.len;
  440. for (isize i = str1.len-1; i >= 0 && str1[i] != '_'; i--) {
  441. n -= 1;
  442. }
  443. str1 = substring(str1, n, str1.len);
  444. str2 = substring(name, 0, gb_max(n-1, 0));
  445. n = str2.len;
  446. for (isize i = str2.len-1; i >= 0 && str2[i] != '_'; i--) {
  447. n -= 1;
  448. }
  449. str2 = substring(str2, n, str2.len);
  450. if (str1 == name) {
  451. return false;
  452. }
  453. TargetOsKind os1 = get_target_os_from_string(str1);
  454. TargetArchKind arch1 = get_target_arch_from_string(str1);
  455. TargetOsKind os2 = get_target_os_from_string(str2);
  456. TargetArchKind arch2 = get_target_arch_from_string(str2);
  457. if (os1 != TargetOs_Invalid && arch2 != TargetArch_Invalid) {
  458. return os1 != build_context.metrics.os || arch2 != build_context.metrics.arch;
  459. } else if (arch1 != TargetArch_Invalid && os2 != TargetOs_Invalid) {
  460. return arch1 != build_context.metrics.arch || os2 != build_context.metrics.os;
  461. } else if (os1 != TargetOs_Invalid) {
  462. return os1 != build_context.metrics.os;
  463. } else if (arch1 != TargetArch_Invalid) {
  464. return arch1 != build_context.metrics.arch;
  465. }
  466. return false;
  467. }
  468. struct LibraryCollections {
  469. String name;
  470. String path;
  471. };
  472. gb_global Array<LibraryCollections> library_collections = {0};
  473. void add_library_collection(String name, String path) {
  474. // TODO(bill): Check the path is valid and a directory
  475. LibraryCollections lc = {name, string_trim_whitespace(path)};
  476. array_add(&library_collections, lc);
  477. }
  478. bool find_library_collection_path(String name, String *path) {
  479. for_array(i, library_collections) {
  480. if (library_collections[i].name == name) {
  481. if (path) *path = library_collections[i].path;
  482. return true;
  483. }
  484. }
  485. return false;
  486. }
  487. bool is_arch_wasm(void) {
  488. switch (build_context.metrics.arch) {
  489. case TargetArch_wasm32:
  490. case TargetArch_wasm64:
  491. return true;
  492. }
  493. return false;
  494. }
  495. bool is_arch_x86(void) {
  496. switch (build_context.metrics.arch) {
  497. case TargetArch_i386:
  498. case TargetArch_amd64:
  499. return true;
  500. }
  501. return false;
  502. }
  503. bool allow_check_foreign_filepath(void) {
  504. switch (build_context.metrics.arch) {
  505. case TargetArch_wasm32:
  506. case TargetArch_wasm64:
  507. return false;
  508. }
  509. return true;
  510. }
  511. // TODO(bill): OS dependent versions for the BuildContext
  512. // join_path
  513. // is_dir
  514. // is_file
  515. // is_abs_path
  516. // has_subdir
  517. String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
  518. String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1};
  519. String const WASM_MODULE_NAME_SEPARATOR = str_lit("..");
  520. String internal_odin_root_dir(void);
  521. String odin_root_dir(void) {
  522. if (global_module_path_set) {
  523. return global_module_path;
  524. }
  525. gbAllocator a = permanent_allocator();
  526. char const *found = gb_get_env("ODIN_ROOT", a);
  527. if (found) {
  528. String path = path_to_full_path(a, make_string_c(found));
  529. if (path[path.len-1] != '/' && path[path.len-1] != '\\') {
  530. #if defined(GB_SYSTEM_WINDOWS)
  531. path = concatenate_strings(a, path, WIN32_SEPARATOR_STRING);
  532. #else
  533. path = concatenate_strings(a, path, NIX_SEPARATOR_STRING);
  534. #endif
  535. }
  536. global_module_path = path;
  537. global_module_path_set = true;
  538. return global_module_path;
  539. }
  540. return internal_odin_root_dir();
  541. }
  542. #if defined(GB_SYSTEM_WINDOWS)
  543. String internal_odin_root_dir(void) {
  544. String path = global_module_path;
  545. isize len, i;
  546. wchar_t *text;
  547. if (global_module_path_set) {
  548. return global_module_path;
  549. }
  550. auto path_buf = array_make<wchar_t>(heap_allocator(), 300);
  551. len = 0;
  552. for (;;) {
  553. len = GetModuleFileNameW(nullptr, &path_buf[0], cast(int)path_buf.count);
  554. if (len == 0) {
  555. return make_string(nullptr, 0);
  556. }
  557. if (len < path_buf.count) {
  558. break;
  559. }
  560. array_resize(&path_buf, 2*path_buf.count + 300);
  561. }
  562. len += 1; // NOTE(bill): It needs an extra 1 for some reason
  563. mutex_lock(&string_buffer_mutex);
  564. defer (mutex_unlock(&string_buffer_mutex));
  565. text = gb_alloc_array(permanent_allocator(), wchar_t, len+1);
  566. GetModuleFileNameW(nullptr, text, cast(int)len);
  567. path = string16_to_string(heap_allocator(), make_string16(text, len));
  568. for (i = path.len-1; i >= 0; i--) {
  569. u8 c = path[i];
  570. if (c == '/' || c == '\\') {
  571. break;
  572. }
  573. path.len--;
  574. }
  575. global_module_path = path;
  576. global_module_path_set = true;
  577. array_free(&path_buf);
  578. return path;
  579. }
  580. #elif defined(GB_SYSTEM_OSX)
  581. #include <mach-o/dyld.h>
  582. String path_to_fullpath(gbAllocator a, String s);
  583. String internal_odin_root_dir(void) {
  584. String path = global_module_path;
  585. isize len, i;
  586. u8 *text;
  587. if (global_module_path_set) {
  588. return global_module_path;
  589. }
  590. auto path_buf = array_make<char>(heap_allocator(), 300);
  591. len = 0;
  592. for (;;) {
  593. u32 sz = path_buf.count;
  594. int res = _NSGetExecutablePath(&path_buf[0], &sz);
  595. if(res == 0) {
  596. len = sz;
  597. break;
  598. } else {
  599. array_resize(&path_buf, sz + 1);
  600. }
  601. }
  602. mutex_lock(&string_buffer_mutex);
  603. defer (mutex_unlock(&string_buffer_mutex));
  604. text = gb_alloc_array(permanent_allocator(), u8, len + 1);
  605. gb_memmove(text, &path_buf[0], len);
  606. path = path_to_fullpath(heap_allocator(), make_string(text, len));
  607. for (i = path.len-1; i >= 0; i--) {
  608. u8 c = path[i];
  609. if (c == '/' || c == '\\') {
  610. break;
  611. }
  612. path.len--;
  613. }
  614. global_module_path = path;
  615. global_module_path_set = true;
  616. // array_free(&path_buf);
  617. return path;
  618. }
  619. #else
  620. // NOTE: Linux / Unix is unfinished and not tested very well.
  621. #include <sys/stat.h>
  622. String path_to_fullpath(gbAllocator a, String s);
  623. String internal_odin_root_dir(void) {
  624. String path = global_module_path;
  625. isize len, i;
  626. u8 *text;
  627. if (global_module_path_set) {
  628. return global_module_path;
  629. }
  630. auto path_buf = array_make<char>(heap_allocator(), 300);
  631. defer (array_free(&path_buf));
  632. len = 0;
  633. for (;;) {
  634. // This is not a 100% reliable system, but for the purposes
  635. // of this compiler, it should be _good enough_.
  636. // That said, there's no solid 100% method on Linux to get the program's
  637. // path without checking this link. Sorry.
  638. #if defined(GB_SYSTEM_FREEBSD)
  639. int mib[4];
  640. mib[0] = CTL_KERN;
  641. mib[1] = KERN_PROC;
  642. mib[2] = KERN_PROC_PATHNAME;
  643. mib[3] = -1;
  644. len = path_buf.count;
  645. sysctl(mib, 4, &path_buf[0], (size_t *) &len, NULL, 0);
  646. #elif defined(GB_SYSTEM_NETBSD)
  647. len = readlink("/proc/curproc/exe", &path_buf[0], path_buf.count);
  648. #elif defined(GB_SYSTEM_DRAGONFLYBSD)
  649. len = readlink("/proc/curproc/file", &path_buf[0], path_buf.count);
  650. #elif defined(GB_SYSTEM_LINUX)
  651. len = readlink("/proc/self/exe", &path_buf[0], path_buf.count);
  652. #elif defined(GB_SYSTEM_OPENBSD)
  653. int error;
  654. int mib[] = {
  655. CTL_KERN,
  656. KERN_PROC_ARGS,
  657. getpid(),
  658. KERN_PROC_ARGV,
  659. };
  660. // get argv size
  661. error = sysctl(mib, 4, NULL, (size_t *) &len, NULL, 0);
  662. if (error == -1) {
  663. // sysctl error
  664. return make_string(nullptr, 0);
  665. }
  666. // get argv
  667. char **argv = (char **)gb_malloc(len);
  668. error = sysctl(mib, 4, argv, (size_t *) &len, NULL, 0);
  669. if (error == -1) {
  670. // sysctl error
  671. gb_mfree(argv);
  672. return make_string(nullptr, 0);
  673. }
  674. // NOTE(Jeroen):
  675. // On OpenBSD, if `odin` is on the path, `argv[0]` will contain just `odin`,
  676. // even though that isn't then the relative path.
  677. // When run from Odin's directory, it returns `./odin`.
  678. // Check argv[0] for lack of / to see if it's a reference to PATH.
  679. // If so, walk PATH to find the executable.
  680. len = gb_strlen(argv[0]);
  681. bool slash_found = false;
  682. bool odin_found = false;
  683. for (int i = 0; i < len; i += 1) {
  684. if (argv[0][i] == '/') {
  685. slash_found = true;
  686. break;
  687. }
  688. }
  689. if (slash_found) {
  690. // copy argv[0] to path_buf
  691. if(len < path_buf.count) {
  692. gb_memmove(&path_buf[0], argv[0], len);
  693. odin_found = true;
  694. }
  695. } else {
  696. gbAllocator a = heap_allocator();
  697. char const *path_env = gb_get_env("PATH", a);
  698. defer (gb_free(a, cast(void *)path_env));
  699. if (path_env) {
  700. int path_len = gb_strlen(path_env);
  701. int path_start = 0;
  702. int path_end = 0;
  703. for (; path_start < path_len; ) {
  704. for (; path_end <= path_len; path_end++) {
  705. if (path_env[path_end] == ':' || path_end == path_len) {
  706. break;
  707. }
  708. }
  709. String path_needle = (const String)make_string((const u8 *)(path_env + path_start), path_end - path_start);
  710. String argv0 = (const String)make_string((const u8 *)argv[0], len);
  711. String odin_candidate = concatenate3_strings(a, path_needle, STR_LIT("/"), argv0);
  712. defer (gb_free(a, odin_candidate.text));
  713. if (gb_file_exists((const char *)odin_candidate.text)) {
  714. len = odin_candidate.len;
  715. if(len < path_buf.count) {
  716. gb_memmove(&path_buf[0], odin_candidate.text, len);
  717. }
  718. odin_found = true;
  719. break;
  720. }
  721. path_start = path_end + 1;
  722. path_end = path_start;
  723. if (path_start > path_len) {
  724. break;
  725. }
  726. }
  727. }
  728. if (!odin_found) {
  729. gb_printf_err("Odin could not locate itself in PATH, and ODIN_ROOT wasn't set either.\n");
  730. }
  731. }
  732. gb_mfree(argv);
  733. #endif
  734. if(len == 0 || len == -1) {
  735. return make_string(nullptr, 0);
  736. }
  737. if (len < path_buf.count) {
  738. break;
  739. }
  740. array_resize(&path_buf, 2*path_buf.count + 300);
  741. }
  742. mutex_lock(&string_buffer_mutex);
  743. defer (mutex_unlock(&string_buffer_mutex));
  744. text = gb_alloc_array(permanent_allocator(), u8, len + 1);
  745. gb_memmove(text, &path_buf[0], len);
  746. path = path_to_fullpath(heap_allocator(), make_string(text, len));
  747. for (i = path.len-1; i >= 0; i--) {
  748. u8 c = path[i];
  749. if (c == '/' || c == '\\') {
  750. break;
  751. }
  752. path.len--;
  753. }
  754. global_module_path = path;
  755. global_module_path_set = true;
  756. return path;
  757. }
  758. #endif
  759. gb_global BlockingMutex fullpath_mutex;
  760. #if defined(GB_SYSTEM_WINDOWS)
  761. String path_to_fullpath(gbAllocator a, String s) {
  762. String result = {};
  763. mutex_lock(&fullpath_mutex);
  764. defer (mutex_unlock(&fullpath_mutex));
  765. String16 string16 = string_to_string16(heap_allocator(), s);
  766. defer (gb_free(heap_allocator(), string16.text));
  767. DWORD len = GetFullPathNameW(&string16[0], 0, nullptr, nullptr);
  768. if (len != 0) {
  769. wchar_t *text = gb_alloc_array(permanent_allocator(), wchar_t, len+1);
  770. GetFullPathNameW(&string16[0], len, text, nullptr);
  771. text[len] = 0;
  772. result = string16_to_string(a, make_string16(text, len));
  773. result = string_trim_whitespace(result);
  774. // Replace Windows style separators
  775. for (isize i = 0; i < result.len; i++) {
  776. if (result.text[i] == '\\') {
  777. result.text[i] = '/';
  778. }
  779. }
  780. }
  781. return result;
  782. }
  783. #elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
  784. String path_to_fullpath(gbAllocator a, String s) {
  785. char *p;
  786. mutex_lock(&fullpath_mutex);
  787. p = realpath(cast(char *)s.text, 0);
  788. mutex_unlock(&fullpath_mutex);
  789. if(p == nullptr) return String{};
  790. return make_string_c(p);
  791. }
  792. #else
  793. #error Implement system
  794. #endif
  795. String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
  796. u8 *str = gb_alloc_array(heap_allocator(), u8, base_dir.len+1+path.len+1);
  797. defer (gb_free(heap_allocator(), str));
  798. isize i = 0;
  799. gb_memmove(str+i, base_dir.text, base_dir.len); i += base_dir.len;
  800. gb_memmove(str+i, "/", 1); i += 1;
  801. gb_memmove(str+i, path.text, path.len); i += path.len;
  802. str[i] = 0;
  803. // IMPORTANT NOTE(bill): Remove trailing path separators
  804. // this is required to make sure there is a conventional
  805. // notation for the path
  806. for (/**/; i > 0; i--) {
  807. u8 c = str[i-1];
  808. if (c != '/' && c != '\\') {
  809. break;
  810. }
  811. }
  812. String res = make_string(str, i);
  813. res = string_trim_whitespace(res);
  814. return path_to_fullpath(a, res);
  815. }
  816. String get_fullpath_core(gbAllocator a, String path) {
  817. String module_dir = odin_root_dir();
  818. String core = str_lit("core/");
  819. isize str_len = module_dir.len + core.len + path.len;
  820. u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
  821. defer (gb_free(heap_allocator(), str));
  822. isize i = 0;
  823. gb_memmove(str+i, module_dir.text, module_dir.len); i += module_dir.len;
  824. gb_memmove(str+i, core.text, core.len); i += core.len;
  825. gb_memmove(str+i, path.text, path.len); i += path.len;
  826. str[i] = 0;
  827. String res = make_string(str, i);
  828. res = string_trim_whitespace(res);
  829. return path_to_fullpath(a, res);
  830. }
  831. bool show_error_line(void) {
  832. return build_context.show_error_line;
  833. }
  834. bool has_asm_extension(String const &path) {
  835. String ext = path_extension(path);
  836. if (ext == ".asm") {
  837. return true;
  838. } else if (ext == ".s") {
  839. return true;
  840. } else if (ext == ".S") {
  841. return true;
  842. }
  843. return false;
  844. }
  845. // temporary
  846. char *token_pos_to_string(TokenPos const &pos) {
  847. gbString s = gb_string_make_reserve(temporary_allocator(), 128);
  848. String file = get_file_path_string(pos.file_id);
  849. switch (build_context.ODIN_ERROR_POS_STYLE) {
  850. default: /*fallthrough*/
  851. case ErrorPosStyle_Default:
  852. s = gb_string_append_fmt(s, "%.*s(%d:%d)", LIT(file), pos.line, pos.column);
  853. break;
  854. case ErrorPosStyle_Unix:
  855. s = gb_string_append_fmt(s, "%.*s:%d:%d:", LIT(file), pos.line, pos.column);
  856. break;
  857. }
  858. return s;
  859. }
  860. void init_build_context(TargetMetrics *cross_target) {
  861. BuildContext *bc = &build_context;
  862. gb_affinity_init(&bc->affinity);
  863. if (bc->thread_count == 0) {
  864. bc->thread_count = gb_max(bc->affinity.thread_count, 1);
  865. }
  866. bc->ODIN_VENDOR = str_lit("odin");
  867. bc->ODIN_VERSION = ODIN_VERSION;
  868. bc->ODIN_ROOT = odin_root_dir();
  869. {
  870. char const *found = gb_get_env("ODIN_ERROR_POS_STYLE", permanent_allocator());
  871. if (found) {
  872. ErrorPosStyle kind = ErrorPosStyle_Default;
  873. String style = make_string_c(found);
  874. style = string_trim_whitespace(style);
  875. if (style == "" || style == "default" || style == "odin") {
  876. kind = ErrorPosStyle_Default;
  877. } else if (style == "unix" || style == "gcc" || style == "clang" || style == "llvm") {
  878. kind = ErrorPosStyle_Unix;
  879. } else {
  880. gb_printf_err("Invalid ODIN_ERROR_POS_STYLE: got %.*s\n", LIT(style));
  881. gb_printf_err("Valid formats:\n");
  882. gb_printf_err("\t\"default\" or \"odin\"\n");
  883. gb_printf_err("\t\tpath(line:column) message\n");
  884. gb_printf_err("\t\"unix\"\n");
  885. gb_printf_err("\t\tpath:line:column: message\n");
  886. gb_exit(1);
  887. }
  888. build_context.ODIN_ERROR_POS_STYLE = kind;
  889. }
  890. }
  891. bc->copy_file_contents = true;
  892. TargetMetrics *metrics = nullptr;
  893. #if defined(GB_ARCH_64_BIT)
  894. #if defined(GB_SYSTEM_WINDOWS)
  895. metrics = &target_windows_amd64;
  896. #elif defined(GB_SYSTEM_OSX)
  897. #if defined(GB_CPU_ARM)
  898. metrics = &target_darwin_arm64;
  899. #else
  900. metrics = &target_darwin_amd64;
  901. #endif
  902. #elif defined(GB_SYSTEM_FREEBSD)
  903. metrics = &target_freebsd_amd64;
  904. #elif defined(GB_SYSTEM_OPENBSD)
  905. metrics = &target_openbsd_amd64;
  906. #elif defined(GB_CPU_ARM)
  907. metrics = &target_linux_arm64;
  908. #else
  909. metrics = &target_linux_amd64;
  910. #endif
  911. #else
  912. #if defined(GB_SYSTEM_WINDOWS)
  913. metrics = &target_windows_i386;
  914. #elif defined(GB_SYSTEM_OSX)
  915. #error "Build Error: Unsupported architecture"
  916. #elif defined(GB_SYSTEM_FREEBSD)
  917. metrics = &target_freebsd_i386;
  918. #else
  919. metrics = &target_linux_i386;
  920. #endif
  921. #endif
  922. if (cross_target != nullptr && metrics != cross_target) {
  923. bc->different_os = cross_target->os != metrics->os;
  924. bc->cross_compiling = true;
  925. metrics = cross_target;
  926. }
  927. GB_ASSERT(metrics->os != TargetOs_Invalid);
  928. GB_ASSERT(metrics->arch != TargetArch_Invalid);
  929. GB_ASSERT(metrics->word_size > 1);
  930. GB_ASSERT(metrics->max_align > 1);
  931. GB_ASSERT(metrics->max_simd_align > 1);
  932. bc->metrics = *metrics;
  933. bc->ODIN_OS = target_os_names[metrics->os];
  934. bc->ODIN_ARCH = target_arch_names[metrics->arch];
  935. bc->endian_kind = target_endians[metrics->arch];
  936. bc->word_size = metrics->word_size;
  937. bc->max_align = metrics->max_align;
  938. bc->max_simd_align = metrics->max_simd_align;
  939. bc->link_flags = str_lit(" ");
  940. #if defined(DEFAULT_TO_THREADED_CHECKER)
  941. bc->threaded_checker = true;
  942. #endif
  943. if (bc->disable_red_zone) {
  944. if (is_arch_wasm() && bc->metrics.os == TargetOs_freestanding) {
  945. gb_printf_err("-disable-red-zone is not support for this target");
  946. gb_exit(1);
  947. }
  948. }
  949. if (bc->metrics.os == TargetOs_freestanding) {
  950. bc->no_entry_point = true;
  951. } else {
  952. if (bc->disallow_rtti) {
  953. gb_printf_err("-disallow-rtti is only allowed on freestanding targets\n");
  954. gb_exit(1);
  955. }
  956. }
  957. // NOTE(zangent): The linker flags to set the build architecture are different
  958. // across OSs. It doesn't make sense to allocate extra data on the heap
  959. // here, so I just #defined the linker flags to keep things concise.
  960. if (bc->metrics.arch == TargetArch_amd64) {
  961. switch (bc->metrics.os) {
  962. case TargetOs_windows:
  963. bc->link_flags = str_lit("/machine:x64 ");
  964. break;
  965. case TargetOs_darwin:
  966. break;
  967. case TargetOs_linux:
  968. bc->link_flags = str_lit("-arch x86-64 ");
  969. break;
  970. case TargetOs_freebsd:
  971. bc->link_flags = str_lit("-arch x86-64 ");
  972. break;
  973. case TargetOs_openbsd:
  974. bc->link_flags = str_lit("-arch x86-64 ");
  975. break;
  976. }
  977. } else if (bc->metrics.arch == TargetArch_i386) {
  978. switch (bc->metrics.os) {
  979. case TargetOs_windows:
  980. bc->link_flags = str_lit("/machine:x86 ");
  981. break;
  982. case TargetOs_darwin:
  983. gb_printf_err("Unsupported architecture\n");
  984. gb_exit(1);
  985. break;
  986. case TargetOs_linux:
  987. bc->link_flags = str_lit("-arch x86 ");
  988. break;
  989. case TargetOs_freebsd:
  990. bc->link_flags = str_lit("-arch x86 ");
  991. break;
  992. }
  993. } else if (bc->metrics.arch == TargetArch_arm32) {
  994. switch (bc->metrics.os) {
  995. case TargetOs_linux:
  996. bc->link_flags = str_lit("-arch arm ");
  997. break;
  998. default:
  999. gb_printf_err("Compiler Error: Unsupported architecture\n");
  1000. gb_exit(1);
  1001. }
  1002. } else if (bc->metrics.arch == TargetArch_arm64) {
  1003. switch (bc->metrics.os) {
  1004. case TargetOs_darwin:
  1005. bc->link_flags = str_lit("-arch arm64 ");
  1006. break;
  1007. case TargetOs_linux:
  1008. bc->link_flags = str_lit("-arch aarch64 ");
  1009. break;
  1010. }
  1011. } else if (is_arch_wasm()) {
  1012. gbString link_flags = gb_string_make(heap_allocator(), " ");
  1013. // link_flags = gb_string_appendc(link_flags, "--export-all ");
  1014. // link_flags = gb_string_appendc(link_flags, "--export-table ");
  1015. link_flags = gb_string_appendc(link_flags, "--allow-undefined ");
  1016. if (bc->metrics.arch == TargetArch_wasm64) {
  1017. link_flags = gb_string_appendc(link_flags, "-mwasm64 ");
  1018. }
  1019. if (bc->no_entry_point) {
  1020. link_flags = gb_string_appendc(link_flags, "--no-entry ");
  1021. }
  1022. bc->link_flags = make_string_c(link_flags);
  1023. // Disallow on wasm
  1024. bc->use_separate_modules = false;
  1025. } else {
  1026. gb_printf_err("Compiler Error: Unsupported architecture\n");
  1027. gb_exit(1);
  1028. }
  1029. bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3);
  1030. bc->ODIN_VALGRIND_SUPPORT = is_arch_x86() && build_context.metrics.os != TargetOs_windows;
  1031. #undef LINK_FLAG_X64
  1032. #undef LINK_FLAG_386
  1033. }
  1034. #if defined(GB_SYSTEM_WINDOWS)
  1035. // NOTE(IC): In order to find Visual C++ paths without relying on environment variables.
  1036. // NOTE(Jeroen): No longer needed in `main.cpp -> linker_stage`. We now resolve those paths in `init_build_paths`.
  1037. #include "microsoft_craziness.h"
  1038. #endif
  1039. Array<String> split_by_comma(String const &list) {
  1040. isize n = 1;
  1041. for (isize i = 0; i < list.len; i++) {
  1042. if (list.text[i] == ',') {
  1043. n++;
  1044. }
  1045. }
  1046. auto res = array_make<String>(heap_allocator(), n);
  1047. String s = list;
  1048. for (isize i = 0; i < n; i++) {
  1049. isize m = string_index_byte(s, ',');
  1050. if (m < 0) {
  1051. res[i] = s;
  1052. break;
  1053. }
  1054. res[i] = substring(s, 0, m);
  1055. s = substring(s, m+1, s.len);
  1056. }
  1057. return res;
  1058. }
  1059. bool check_target_feature_is_valid(TokenPos pos, String const &feature) {
  1060. // TODO(bill): check_target_feature_is_valid
  1061. return true;
  1062. }
  1063. bool check_target_feature_is_enabled(TokenPos pos, String const &target_feature_list) {
  1064. BuildContext *bc = &build_context;
  1065. mutex_lock(&bc->target_features_mutex);
  1066. defer (mutex_unlock(&bc->target_features_mutex));
  1067. auto items = split_by_comma(target_feature_list);
  1068. array_free(&items);
  1069. for_array(i, items) {
  1070. String const &item = items.data[i];
  1071. if (!check_target_feature_is_valid(pos, item)) {
  1072. error(pos, "Target feature '%.*s' is not valid", LIT(item));
  1073. return false;
  1074. }
  1075. if (!string_set_exists(&bc->target_features_set, item)) {
  1076. error(pos, "Target feature '%.*s' is not enabled", LIT(item));
  1077. return false;
  1078. }
  1079. }
  1080. return true;
  1081. }
  1082. void enable_target_feature(TokenPos pos, String const &target_feature_list) {
  1083. BuildContext *bc = &build_context;
  1084. mutex_lock(&bc->target_features_mutex);
  1085. defer (mutex_unlock(&bc->target_features_mutex));
  1086. auto items = split_by_comma(target_feature_list);
  1087. for_array(i, items) {
  1088. String const &item = items.data[i];
  1089. if (!check_target_feature_is_valid(pos, item)) {
  1090. error(pos, "Target feature '%.*s' is not valid", LIT(item));
  1091. continue;
  1092. }
  1093. string_set_add(&bc->target_features_set, item);
  1094. }
  1095. array_free(&items);
  1096. }
  1097. char const *target_features_set_to_cstring(gbAllocator allocator, bool with_quotes) {
  1098. isize len = 0;
  1099. for_array(i, build_context.target_features_set.entries) {
  1100. if (i != 0) {
  1101. len += 1;
  1102. }
  1103. String feature = build_context.target_features_set.entries[i].value;
  1104. len += feature.len;
  1105. if (with_quotes) len += 2;
  1106. }
  1107. char *features = gb_alloc_array(allocator, char, len+1);
  1108. len = 0;
  1109. for_array(i, build_context.target_features_set.entries) {
  1110. if (i != 0) {
  1111. features[len++] = ',';
  1112. }
  1113. if (with_quotes) features[len++] = '"';
  1114. String feature = build_context.target_features_set.entries[i].value;
  1115. gb_memmove(features + len, feature.text, feature.len);
  1116. len += feature.len;
  1117. if (with_quotes) features[len++] = '"';
  1118. }
  1119. features[len++] = 0;
  1120. return features;
  1121. }
  1122. // NOTE(Jeroen): Set/create the output and other paths and report an error as appropriate.
  1123. // We've previously called `parse_build_flags`, so `out_filepath` should be set.
  1124. bool init_build_paths(String init_filename) {
  1125. gbAllocator ha = heap_allocator();
  1126. BuildContext *bc = &build_context;
  1127. // NOTE(Jeroen): We're pre-allocating BuildPathCOUNT slots so that certain paths are always at the same enumerated index.
  1128. array_init(&bc->build_paths, permanent_allocator(), BuildPathCOUNT);
  1129. string_set_init(&bc->target_features_set, heap_allocator(), 1024);
  1130. mutex_init(&bc->target_features_mutex);
  1131. // [BuildPathMainPackage] Turn given init path into a `Path`, which includes normalizing it into a full path.
  1132. bc->build_paths[BuildPath_Main_Package] = path_from_string(ha, init_filename);
  1133. {
  1134. String build_project_name = last_path_element(bc->build_paths[BuildPath_Main_Package].basename);
  1135. GB_ASSERT(build_project_name.len > 0);
  1136. bc->ODIN_BUILD_PROJECT_NAME = build_project_name;
  1137. }
  1138. bool produces_output_file = false;
  1139. if (bc->command_kind == Command_doc && bc->cmd_doc_flags & CmdDocFlag_DocFormat) {
  1140. produces_output_file = true;
  1141. } else if (bc->command_kind & Command__does_build) {
  1142. produces_output_file = true;
  1143. }
  1144. if (!produces_output_file) {
  1145. // Command doesn't produce output files. We're done.
  1146. return true;
  1147. }
  1148. #if defined(GB_SYSTEM_WINDOWS)
  1149. if (bc->metrics.os == TargetOs_windows) {
  1150. if (bc->resource_filepath.len > 0) {
  1151. bc->build_paths[BuildPath_RC] = path_from_string(ha, bc->resource_filepath);
  1152. bc->build_paths[BuildPath_RES] = path_from_string(ha, bc->resource_filepath);
  1153. bc->build_paths[BuildPath_RC].ext = copy_string(ha, STR_LIT("rc"));
  1154. bc->build_paths[BuildPath_RES].ext = copy_string(ha, STR_LIT("res"));
  1155. }
  1156. if (bc->pdb_filepath.len > 0) {
  1157. bc->build_paths[BuildPath_PDB] = path_from_string(ha, bc->pdb_filepath);
  1158. }
  1159. if ((bc->command_kind & Command__does_build) && (!bc->ignore_microsoft_magic)) {
  1160. // 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.
  1161. Find_Result find_result = find_visual_studio_and_windows_sdk();
  1162. defer (mc_free_all());
  1163. if (find_result.windows_sdk_version == 0) {
  1164. gb_printf_err("Windows SDK not found.\n");
  1165. return false;
  1166. }
  1167. if (!build_context.use_lld && find_result.vs_exe_path.len == 0) {
  1168. gb_printf_err("link.exe not found.\n");
  1169. return false;
  1170. }
  1171. if (find_result.vs_library_path.len == 0) {
  1172. gb_printf_err("VS library path not found.\n");
  1173. return false;
  1174. }
  1175. if (find_result.windows_sdk_um_library_path.len > 0) {
  1176. GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0);
  1177. if (find_result.windows_sdk_bin_path.len > 0) {
  1178. bc->build_paths[BuildPath_Win_SDK_Bin_Path] = path_from_string(ha, find_result.windows_sdk_bin_path);
  1179. }
  1180. if (find_result.windows_sdk_um_library_path.len > 0) {
  1181. bc->build_paths[BuildPath_Win_SDK_UM_Lib] = path_from_string(ha, find_result.windows_sdk_um_library_path);
  1182. }
  1183. if (find_result.windows_sdk_ucrt_library_path.len > 0) {
  1184. bc->build_paths[BuildPath_Win_SDK_UCRT_Lib] = path_from_string(ha, find_result.windows_sdk_ucrt_library_path);
  1185. }
  1186. if (find_result.vs_exe_path.len > 0) {
  1187. bc->build_paths[BuildPath_VS_EXE] = path_from_string(ha, find_result.vs_exe_path);
  1188. }
  1189. if (find_result.vs_library_path.len > 0) {
  1190. bc->build_paths[BuildPath_VS_LIB] = path_from_string(ha, find_result.vs_library_path);
  1191. }
  1192. }
  1193. }
  1194. }
  1195. #endif
  1196. // All the build targets and OSes.
  1197. String output_extension;
  1198. if (bc->command_kind == Command_doc && bc->cmd_doc_flags & CmdDocFlag_DocFormat) {
  1199. output_extension = STR_LIT("odin-doc");
  1200. } else if (is_arch_wasm()) {
  1201. output_extension = STR_LIT("wasm");
  1202. } else if (build_context.build_mode == BuildMode_Executable) {
  1203. // By default use a .bin executable extension.
  1204. output_extension = STR_LIT("bin");
  1205. if (build_context.metrics.os == TargetOs_windows) {
  1206. output_extension = STR_LIT("exe");
  1207. } else if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) {
  1208. output_extension = make_string(nullptr, 0);
  1209. }
  1210. } else if (build_context.build_mode == BuildMode_DynamicLibrary) {
  1211. // By default use a .so shared library extension.
  1212. output_extension = STR_LIT("so");
  1213. if (build_context.metrics.os == TargetOs_windows) {
  1214. output_extension = STR_LIT("dll");
  1215. } else if (build_context.metrics.os == TargetOs_darwin) {
  1216. output_extension = STR_LIT("dylib");
  1217. }
  1218. } else if (build_context.build_mode == BuildMode_Object) {
  1219. // By default use a .o object extension.
  1220. output_extension = STR_LIT("o");
  1221. if (build_context.metrics.os == TargetOs_windows) {
  1222. output_extension = STR_LIT("obj");
  1223. }
  1224. } else if (build_context.build_mode == BuildMode_Assembly) {
  1225. // By default use a .S asm extension.
  1226. output_extension = STR_LIT("S");
  1227. } else if (build_context.build_mode == BuildMode_LLVM_IR) {
  1228. output_extension = STR_LIT("ll");
  1229. } else {
  1230. GB_PANIC("Unhandled build mode/target combination.\n");
  1231. }
  1232. if (bc->out_filepath.len > 0) {
  1233. bc->build_paths[BuildPath_Output] = path_from_string(ha, bc->out_filepath);
  1234. if (build_context.metrics.os == TargetOs_windows) {
  1235. String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]);
  1236. defer (gb_free(ha, output_file.text));
  1237. if (path_is_directory(bc->build_paths[BuildPath_Output])) {
  1238. gb_printf_err("Output path %.*s is a directory.\n", LIT(output_file));
  1239. return false;
  1240. } else if (bc->build_paths[BuildPath_Output].ext.len == 0) {
  1241. gb_printf_err("Output path %.*s must have an appropriate extension.\n", LIT(output_file));
  1242. return false;
  1243. }
  1244. }
  1245. } else {
  1246. Path output_path;
  1247. if (str_eq(init_filename, str_lit("."))) {
  1248. // We must name the output file after the current directory.
  1249. debugf("Output name will be created from current base name %.*s.\n", LIT(bc->build_paths[BuildPath_Main_Package].basename));
  1250. String last_element = last_path_element(bc->build_paths[BuildPath_Main_Package].basename);
  1251. if (last_element.len == 0) {
  1252. gb_printf_err("The output name is created from the last path element. `%.*s` has none. Use `-out:output_name.ext` to set it.\n", LIT(bc->build_paths[BuildPath_Main_Package].basename));
  1253. return false;
  1254. }
  1255. output_path.basename = copy_string(ha, bc->build_paths[BuildPath_Main_Package].basename);
  1256. output_path.name = copy_string(ha, last_element);
  1257. } else {
  1258. // Init filename was not 'current path'.
  1259. // Contruct the output name from the path elements as usual.
  1260. String output_name = init_filename;
  1261. // If it ends with a trailing (back)slash, strip it before continuing.
  1262. while (output_name.len > 0 && (output_name[output_name.len-1] == '/' || output_name[output_name.len-1] == '\\')) {
  1263. output_name.len -= 1;
  1264. }
  1265. output_name = remove_directory_from_path(output_name);
  1266. output_name = remove_extension_from_path(output_name);
  1267. output_name = copy_string(ha, string_trim_whitespace(output_name));
  1268. output_path = path_from_string(ha, output_name);
  1269. // Replace extension.
  1270. if (output_path.ext.len > 0) {
  1271. gb_free(ha, output_path.ext.text);
  1272. }
  1273. }
  1274. output_path.ext = copy_string(ha, output_extension);
  1275. bc->build_paths[BuildPath_Output] = output_path;
  1276. }
  1277. // Do we have an extension? We might not if the output filename was supplied.
  1278. if (bc->build_paths[BuildPath_Output].ext.len == 0) {
  1279. if (build_context.metrics.os == TargetOs_windows || build_context.build_mode != BuildMode_Executable) {
  1280. bc->build_paths[BuildPath_Output].ext = copy_string(ha, output_extension);
  1281. }
  1282. }
  1283. // Check if output path is a directory.
  1284. if (path_is_directory(bc->build_paths[BuildPath_Output])) {
  1285. String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]);
  1286. defer (gb_free(ha, output_file.text));
  1287. gb_printf_err("Output path %.*s is a directory.\n", LIT(output_file));
  1288. return false;
  1289. }
  1290. if (bc->target_features_string.len != 0) {
  1291. enable_target_feature({}, bc->target_features_string);
  1292. }
  1293. return true;
  1294. }