build_settings.cpp 38 KB

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