env.ck 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  1. /*++
  2. Copyright (c) 2016 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. env.ck
  5. Abstract:
  6. This build module contains the environment and functions used throughout
  7. the Minoca OS build.
  8. Author:
  9. Evan Green 14-Apr-2016
  10. Environment:
  11. Build
  12. --*/
  13. TRUE = 1;
  14. FALSE = 0;
  15. arch ?= getenv("ARCH");
  16. //debug ?= getenv("DEBUG");
  17. //variant ?= getenv("VARIANT");
  18. arch ?= "x86";
  19. debug ?= "dbg";
  20. variant ?= "";
  21. outroot = "^/../..";
  22. binroot = outroot + "/bin";
  23. stripped_dir = binroot + "/stripped";
  24. cflags ?= getenv("CFLAGS") ? [getenv("CFLAGS")] : ["-Wall", "-Werror"];
  25. cppflags ?= getenv("CPPFLAGS") ? [getenv("CPPFLAGS")] : [];
  26. ldflags ?= getenv("LDFLAGS") ? [getenv("LDFLAGS")] : [];
  27. asflags ?= getenv("ASFLAGS") ? [getenv("ASLAGS")] : [];
  28. global_config = {
  29. "ARCH": arch,
  30. "DEBUG": debug,
  31. "VARIANT": variant,
  32. "BUILD_CC": getenv("BUILD_CC"),
  33. "BUILD_AR": getenv("BUILD_AR"),
  34. "BUILD_OBJCOPY": getenv("BUILD_OBJCOPY"),
  35. "BUILD_STRIP": getenv("BUILD_STRIP"),
  36. "CC": getenv("CC"),
  37. "AR": getenv("AR"),
  38. "OBJCOPY": getenv("OBJCOPY"),
  39. "STRIP": getenv("STRIP"),
  40. "RCC": getenv("RCC"),
  41. "IASL", getenv("IASL"),
  42. "SHELL": getenv("SHELL"),
  43. };
  44. build_os ?= uname_s();
  45. build_arch ?= uname_m();
  46. if (build_arch == "i686") {
  47. build_arch = "x86";
  48. } else if (build_arch == "x86-64") {
  49. build_arch = "x64";
  50. }
  51. assert(((arch == "x86") || (arch == "armv7") ||
  52. (arch == "armv6") || (arch == "x64")),
  53. "Invalid architecture");
  54. assert(((build_arch == "x86") || (build_arch == "armv7") ||
  55. (build_arch == "armv6") || (build_arch == "x64")),
  56. "Unknown build architecture");
  57. assert(((debug == "dbg") || (debug == "rel")), "Invalid debug setting");
  58. //
  59. // Set up build architecture-specific globals.
  60. //
  61. build_bfd_arch = "";
  62. build_obj_format = "";
  63. if (build_arch == "x86") {
  64. build_bfd_arch = "i386";
  65. build_obj_format = "elf32-i386";
  66. if (build_os == "Windows") {
  67. build_obj_format = "pe-i386";
  68. }
  69. } else if ((build_arch == "armv7") || (build_arch == "armv6")) {
  70. build_bfd_arch = "arm";
  71. build_obj_format = "elf32-littlearm";
  72. } else if (build_arch == "x64") {
  73. build_bfd_arch = "x86-64";
  74. build_obj_format = "elf64-x86-64";
  75. } else {
  76. print("Set build_bfd_arch and build_obj_format for new architecture.\n");
  77. }
  78. //
  79. // Set up target architecture-specific globals.
  80. //
  81. bfd_arch = "";
  82. obj_format = "";
  83. if (arch == "x86") {
  84. bfd_arch = "i386";
  85. obj_format = "elf32-i386";
  86. if (variant == "q") {
  87. tool_prefix = "i586-pc-minoca-";
  88. } else {
  89. tool_prefix = "i686-pc-minoca-";
  90. }
  91. } else if ((arch == "armv7") || (arch == "armv6")) {
  92. bfd_arch = "arm";
  93. obj_format = "elf32-littlearm";
  94. tool_prefix = "arm-none-minoca-";
  95. } else if (arch == "x64") {
  96. bfd_arch = "x86-64";
  97. obj_format = "elf64-x86-64";
  98. tool_prefix = "x86_64-pc-minoca-";
  99. }
  100. //
  101. // Set a default build compiler if none was set.
  102. //
  103. global_config["BUILD_CC"] ?= "gcc";
  104. global_config["BUILD_AR"] ?= "ar";
  105. global_config["BUILD_OBJCOPY"] ?= "objcopy";
  106. global_config["BUILD_STRIP"] ?= "strip";
  107. global_config["RCC"] ?= "windres";
  108. global_config["IASL"] ?= "iasl";
  109. global_config["SHELL"] ?= "sh";
  110. echo = "echo";
  111. //
  112. // Pin down CFLAGS and the like.
  113. //
  114. if (debug == "dbg") {
  115. cflags += ["-O1", "-DDEBUG=1"];
  116. } else {
  117. cflags += ["-O2", "-Wno-unused-but-set-variable", "-DNDEBUG"];
  118. }
  119. cflags += ["-fno-builtin",
  120. "-fno-omit-frame-pointer",
  121. "-g",
  122. "-save-temps=obj",
  123. "-ffunction-sections",
  124. "-fdata-sections",
  125. "-fvisibility=hidden"];
  126. cppflags += ["-I$//include"];
  127. //
  128. // TODO: Figure out REVISION, BUILD_TIME, BUILD_TIME_STRING, BUILD_STRING,
  129. // and BUILD_USER.
  130. //
  131. cppflags += ["-DREVISION=0 -DBUILD_TIME_STRING=\\\"\\\" -DBUILD_TIME=0 -DBUILD_STRING=\\\"\\\" -DBUILD_USER=\\\"None\\\""];
  132. build_cflags = cflags + [];
  133. build_cppflags = cppflags + [];
  134. cflags += ["-fpic"];
  135. if (build_os == "Windows") {
  136. build_cflags += ["-mno-ms-bitfields"];
  137. } else {
  138. build_cflags += ["-fpic"];
  139. }
  140. if (arch == "armv6") {
  141. cppflags += ["-march=armv6zk", "-marm", "-mfpu=vfp"];
  142. }
  143. if (arch == "x86") {
  144. cflags += ["-mno-ms-bitfields"];
  145. if (variant == "q") {
  146. cppflags += ["-Wa,-momit-lock-prefix=yes", "-march=i586"];
  147. }
  148. }
  149. asflags += ["-Wa,-g"];
  150. ldflags += ["-Wl,--gc-sections"];
  151. objcopy_flags ?= [
  152. "--rename-section .data=.rodata,alloc,load,data,contents,readonly",
  153. "-I binary",
  154. "-O " + obj_format,
  155. "-B " + bfd_arch
  156. ];
  157. build_objcopy_flags ?= [
  158. "--rename-section .data=.rodata,alloc,load,data,contents,readonly",
  159. "-I binary",
  160. "-O " + build_obj_format,
  161. "-B " + build_bfd_arch
  162. ];
  163. if (build_os == "Windows") {
  164. build_objcopy_flags += ["--prefix-symbols=_"];
  165. }
  166. //
  167. // Set a default target compiler if one was not set. On Minoca building its own
  168. // architecture, use the native compiler.
  169. //
  170. if ((build_os == "Minoca") && (build_arch == arch)) {
  171. global_config["CC"] ?= global_config["BUILD_CC"];
  172. global_config["AR"] ?= global_config["BUILD_AR"];
  173. global_config["OBJCOPY"] ?= global_config["BUILD_OBJCOPY"];
  174. global_config["STRIP"] ?= global_config["BUILD_STRIP"];
  175. } else {
  176. global_config["CC"] ?= tool_prefix + "gcc";
  177. global_config["AR"] ?= tool_prefix + "ar";
  178. global_config["OBJCOPY"] ?= tool_prefix + "objcopy";
  179. global_config["STRIP"] ?= tool_prefix + "strip";
  180. }
  181. global_config["BASE_CFLAGS"] = cflags;
  182. global_config["BASE_CPPFLAGS"] = cppflags;
  183. global_config["BASE_LDFLAGS"] = ldflags;
  184. global_config["BASE_ASFLAGS"] = asflags;
  185. global_config["OBJCOPY_FLAGS"] = objcopy_flags;
  186. global_config["BUILD_BASE_CFLAGS"] = build_cflags;
  187. global_config["BUILD_BASE_CPPFLAGS"] = build_cppflags;
  188. global_config["BUILD_BASE_LDFLAGS"] = ldflags;
  189. global_config["BUILD_BASE_ASFLAGS"] = asflags;
  190. global_config["BUILD_OBJCOPY_FLAGS"] = build_objcopy_flags;
  191. global_config["IASL_FLAGS"] = ["-we"];
  192. //
  193. // Add a config value, creating it if it does not exist.
  194. //
  195. function add_config(entry, name, value) {
  196. entry["config"] ?= {};
  197. entry["config"][name] ?= [];
  198. entry["config"][name] += [value];
  199. return;
  200. }
  201. //
  202. // Create a phony group target that depends on all the given input entries.
  203. //
  204. function group(name, entries) {
  205. entry = {
  206. "label": name,
  207. "type": "target",
  208. "tool": "phony",
  209. "inputs": entries,
  210. "config": {}
  211. };
  212. return [entry];
  213. }
  214. //
  215. // Create a copy target.
  216. //
  217. function copy(source, destination, destination_label, flags, mode) {
  218. config = {};
  219. if (flags) {
  220. config["CPFLAGS"] = flags;
  221. }
  222. if (mode) {
  223. config["config"] = mode;
  224. }
  225. entry = {
  226. "type": "target",
  227. "tool": "copy",
  228. "label": destination_label,
  229. "inputs": [source],
  230. "output": destination,
  231. "config": config
  232. };
  233. if (!destination_label) {
  234. entry["label"] = destination;
  235. }
  236. return [entry];
  237. }
  238. //
  239. // Add a stripped version of the target.
  240. //
  241. function strip(params) {
  242. tool_name = "strip";
  243. if (get(params, "build")) {
  244. tool_name = "build_strip";
  245. }
  246. params["type"] = "target";
  247. params["tool"] = tool_name;
  248. return [params];
  249. }
  250. //
  251. // Replace the current target with a copied version in the bin directory. Also
  252. // strip unless told not to.
  253. //
  254. function binplace(params) {
  255. label = get(params, "label");
  256. label ?= get(params, "output");
  257. source = get(params, "output");
  258. source ?= label;
  259. assert(label && source, "Label or source must be defined");
  260. //
  261. // Set the output since the label is going to be renamed and create the
  262. // copy target.
  263. //
  264. params["output"] = source;
  265. file_name = basename(source);
  266. destination = binroot + "/" + file_name;
  267. cpflags = get(params, "cpflags");
  268. mode = get(params, "chmod");
  269. new_original_label = label + "_orig";
  270. original_target = ":" + new_original_label;
  271. copied_entry = copy(original_target, destination, label, cpflags, mode)[0];
  272. //
  273. // The original label was given to the copied destination, so tack a _orig
  274. // on the source label.
  275. //
  276. params["label"] = new_original_label;
  277. entries = [copied_entry, params];
  278. //
  279. // Unless asked not to, create a stripped entry as well.
  280. //
  281. if (!get(params, "nostrip")) {
  282. stripped_entry = {
  283. "label": label + "_stripped",
  284. "inputs": [original_target],
  285. "output": stripped_dir + "/" + file_name,
  286. "build": get(params, "build"),
  287. };
  288. //
  289. // Make the binplaced copy depend on the stripped version.
  290. //
  291. copied_entry["implicit"] = [":" + stripped_entry["label"]];
  292. entries += strip(stripped_entry);
  293. }
  294. return entries;
  295. }
  296. //
  297. // Create a group of object file targets from source file targets. Returns a
  298. // list of the object names in the first element and the object file target
  299. // entries in the second element.
  300. //
  301. function compiled_sources(params) {
  302. inputs = params["inputs"];
  303. objs = [];
  304. entries = [];
  305. sources_config = get(params, "sources_config");
  306. prefix = get(params, "prefix");
  307. build = get(params, "build");
  308. includes = get(params, "includes");
  309. if (includes) {
  310. sources_config ?= {};
  311. sources_config["CPPFLAGS"] ?= [];
  312. for (include in includes) {
  313. sources_config["CPPFLAGS"] += ["-I" + include];
  314. }
  315. }
  316. assert(len(inputs) != 0, "Compilation must have inputs");
  317. for (input in inputs) {
  318. input_parts = split_extension(input);
  319. ext = input_parts[1];
  320. suffix = ".o";
  321. if (ext == "c") {
  322. tool = "cc";
  323. } else if (ext == "cc") {
  324. tool = "cxx";
  325. } else if (ext == "S") {
  326. tool = "as";
  327. } else if (ext == "rc") {
  328. tool = "rcc";
  329. suffix = ".rsc";
  330. } else {
  331. objs += [input];
  332. continue;
  333. }
  334. if (build) {
  335. tool = "build_" + tool;
  336. }
  337. obj_name = input_parts[0] + suffix;
  338. if (prefix) {
  339. obj_name = prefix + "/" + obj_name;
  340. }
  341. obj = {
  342. "type": "target",
  343. "label": obj_name,
  344. "output": obj_name,
  345. "inputs": [input],
  346. "tool": tool,
  347. "config": sources_config,
  348. };
  349. entries += [obj];
  350. objs += [":" + obj_name];
  351. }
  352. if (prefix) {
  353. params["output"] ?= params["label"];
  354. params["output"] = prefix + "/" + params["output"];
  355. }
  356. return [objs, entries];
  357. }
  358. //
  359. // Vanilla link of a set of sources into some sort of executable or shared
  360. // object.
  361. //
  362. function executable(params) {
  363. build = get(params, "build");
  364. compilation = compiled_sources(params);
  365. objs = compilation[0];
  366. entries = compilation[1];
  367. params["type"] = "target";
  368. params["inputs"] = objs;
  369. params["tool"] = "ld";
  370. if (build) {
  371. params["tool"] = "build_ld";
  372. }
  373. //
  374. // Convert options for text_address, linker_script, and entry to actual
  375. // LDFLAGS.
  376. //
  377. text_address = get(params, "text_address");
  378. if (text_address) {
  379. text_option = "-Wl,-Ttext-segment=" + text_address +
  380. " -Wl,-Ttext=" + text_address;
  381. add_config(params, "LDFLAGS", text_option);
  382. }
  383. linker_script = get(params, "linker_script");
  384. if (linker_script) {
  385. script_option = "-Wl,-T" + linker_script;
  386. add_config(params, "LDFLAGS", script_option);
  387. }
  388. entry = get(params, "entry");
  389. if (entry) {
  390. entry_option = "-Wl,-e" + entry + " -Wl,-u" + entry;
  391. add_config(params, "LDFLAGS", entry_option);
  392. }
  393. if (get(params, "binplace")) {
  394. entries += binplace(params);
  395. } else {
  396. entries += [params];
  397. }
  398. return entries;
  399. }
  400. //
  401. // Creates a regular position independent application.
  402. //
  403. function application(params) {
  404. build = get(params, "build");
  405. exename = get(params, "output");
  406. exename ?= params["label"];
  407. if (build && (build_os == "Windows")) {
  408. params["output"] = exename + ".exe";
  409. }
  410. add_config(params, "LDFLAGS", "-pie");
  411. return executable(params);
  412. }
  413. //
  414. // Creates a shared library or DLL.
  415. //
  416. function shared_library(params) {
  417. build = get(params, "build");
  418. soname = get(params, "output");
  419. soname ?= params["label"];
  420. major_version = get(params, "major_version");
  421. add_config(params, "LDFLAGS", "-shared");
  422. if ((!build) || (build_os != "Windows")) {
  423. soname += ".so";
  424. if (major_version != null) {
  425. soname += "." + major_version;
  426. }
  427. add_config(params, "LDFLAGS", "-Wl,-soname=" + soname);
  428. } else {
  429. soname += ".dll";
  430. }
  431. params["output"] = soname;
  432. return executable(params);
  433. }
  434. //
  435. // Creates a static archive.
  436. //
  437. function static_library(params) {
  438. compilation = compiled_sources(params);
  439. objs = compilation[0];
  440. entries = compilation[1];
  441. params["type"] = "target";
  442. output = get(params, "output");
  443. output ?= params["label"];
  444. params["output"] = output + ".a";
  445. params["inputs"] = objs;
  446. params["tool"] = "ar";
  447. if (build) {
  448. params["tool"] = "build_ar";
  449. }
  450. if (get(params, "binplace")) {
  451. entries += binplace(params);
  452. } else {
  453. entries += [params];
  454. }
  455. return entries;
  456. }
  457. //
  458. // Create a list of compiled .aml files from a list of asl files. Returns a
  459. // list where the first element is a list of all the resulting target names,
  460. // and the second element is a list of the target entries.
  461. //
  462. function compiled_asl(inputs) {
  463. entries = [];
  464. objs = [];
  465. assert(len(inputs) != 0, "Compilation must have inputs");
  466. for (input in inputs) {
  467. input_parts = split_extension(input);
  468. ext = input_parts[1];
  469. suffix = ".aml";
  470. tool = "iasl";
  471. obj_name = input_parts[0] + suffix;
  472. obj = {
  473. "type": "target",
  474. "label": obj_name,
  475. "output": obj_name,
  476. "inputs": [input],
  477. "tool": tool
  478. };
  479. entries += [obj];
  480. objs += [":" + obj_name];
  481. }
  482. return [objs, entries];
  483. }
  484. //
  485. // Create a group of object file targets from binary files. Returns a
  486. // list of the object names in the first element and the object file target
  487. // entries in the second element.
  488. //
  489. function objectified_binaries(params) {
  490. inputs = params["inputs"];
  491. objs = [];
  492. entries = [];
  493. objcopy_config = get(params, "config");
  494. prefix = get(params, "prefix");
  495. build = get(params, "build");
  496. assert(len(inputs) != 0, "Compilation must have inputs");
  497. for (input in inputs) {
  498. input_parts = split_extension(input);
  499. ext = input_parts[1];
  500. suffix = ".o";
  501. tool = "objcopy";
  502. if (build) {
  503. tool = "build_" + tool;
  504. }
  505. obj_name = input_parts[0] + suffix;
  506. if (prefix) {
  507. obj_name = prefix + "/" + obj_name;
  508. }
  509. obj = {
  510. "type": "target",
  511. "label": obj_name,
  512. "output": obj_name,
  513. "inputs": [input],
  514. "tool": tool,
  515. "config": objcopy_config,
  516. };
  517. entries += [obj];
  518. objs += [":" + obj_name];
  519. }
  520. if (prefix) {
  521. params["output"] ?= params["label"];
  522. params["output"] = prefix + "/" + params["output"];
  523. }
  524. return [objs, entries];
  525. }
  526. //
  527. // Create a single object file from a binary file.
  528. //
  529. function objectified_binary(params) {
  530. return objectified_binaries(params)[1];
  531. }
  532. //
  533. // Create a library from a set of objectified files.
  534. //
  535. function objectified_library(params) {
  536. build = get(params, "build");
  537. compilation = objectified_binaries(params);
  538. objs = compilation[0];
  539. entries = compilation[1];
  540. params["type"] = "target";
  541. output = get(params, "output");
  542. output ?= params["label"];
  543. params["output"] = output + ".a";
  544. params["inputs"] = objs;
  545. params["tool"] = "ar";
  546. if (build) {
  547. params["tool"] = "build_ar";
  548. }
  549. entries += [params];
  550. return entries;
  551. }
  552. //
  553. // Create a flat binary from an executable image.
  554. //
  555. function flattened_binary(params) {
  556. params["type"] = "target";
  557. params["tool"] = "objcopy";
  558. flags = "OBJCOPY_FLAGS";
  559. if (get(params, "build")) {
  560. params["tool"] = "build_objcopy";
  561. flags = "BUILD_OBJCOPY_FLAGS";
  562. }
  563. add_config(params, flags, "-O binary");
  564. if (get(params, "binplace")) {
  565. entries = binplace(params);
  566. } else {
  567. entries = [params];
  568. }
  569. return entries;
  570. }
  571. //
  572. // Create a Minoca kernel driver.
  573. //
  574. function driver(params) {
  575. params["entry"] ?= "DriverEntry";
  576. soname = get(params, "output");
  577. soname ?= params["label"];
  578. if (soname != "kernel") {
  579. soname += ".drv";
  580. params["output"] = soname;
  581. params["inputs"] += ["//kernel:kernel"];
  582. }
  583. add_config(params, "LDFLAGS", "-shared");
  584. add_config(params, "LDFLAGS", "-Wl,-soname=" + soname);
  585. add_config(params, "LDFLAGS", "-nostdlib");
  586. return executable(params);
  587. }
  588. //
  589. // Define a function for creating a runtime driver .FFS file from an ELF.
  590. //
  591. function uefi_runtime_ffs(name) {
  592. elfconv_config = {
  593. "ELFCONV_FLAGS": "-t efiruntimedriver"
  594. };
  595. pe = {
  596. "type": "target",
  597. "label": name,
  598. "inputs": [":" + name + ".elf"],
  599. "implicit": ["//uefi/tools/elfconv:elfconv"],
  600. "tool": "elfconv",
  601. "config": elfconv_config
  602. };
  603. ffs = {
  604. "type": "target",
  605. "label": name + ".ffs",
  606. "inputs": [":" + name],
  607. "implicit": ["//uefi/tools/genffs:genffs"],
  608. "tool": "genffs_runtime"
  609. };
  610. return [pe, ffs];
  611. }
  612. //
  613. // Define a function that creates a UEFI firmware volume object file based on
  614. // a platform name and a list of FFS inputs.
  615. //
  616. function uefi_fwvol_o(name, ffs) {
  617. fwv_name = name + "fwv";
  618. fwv = {
  619. "type": "target",
  620. "label": fwv_name,
  621. "inputs": ffs,
  622. "implicit": ["//uefi/tools/genfv:genfv"],
  623. "tool": "genfv"
  624. };
  625. fwv_o = {
  626. "label": fwv_name + ".o",
  627. "inputs": [":" + fwv_name],
  628. "tool": "objcopy",
  629. "config": {"OBJCOPY_FLAGS": global_config["OBJCOPY_FLAGS"]}
  630. };
  631. return [fwv, fwv_o];
  632. }