env.ck 18 KB

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