gentpl.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  1. #! /usr/bin/python
  2. # GRUB -- GRand Unified Bootloader
  3. # Copyright (C) 2010,2011,2012,2013 Free Software Foundation, Inc.
  4. #
  5. # GRUB is free software: you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation, either version 3 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # GRUB is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  17. from __future__ import print_function
  18. __metaclass__ = type
  19. from optparse import OptionParser
  20. import re
  21. #
  22. # This is the python script used to generate Makefile.*.am
  23. #
  24. GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot",
  25. "i386_multiboot", "i386_ieee1275", "x86_64_efi",
  26. "i386_xen", "x86_64_xen", "i386_xen_pvh",
  27. "mips_loongson", "sparc64_ieee1275",
  28. "powerpc_ieee1275", "mips_arc", "ia64_efi",
  29. "mips_qemu_mips", "arm_uboot", "arm_efi", "arm64_efi",
  30. "arm_coreboot", "loongarch64_efi", "riscv32_efi", "riscv64_efi" ]
  31. GROUPS = {}
  32. GROUPS["common"] = GRUB_PLATFORMS[:]
  33. # Groups based on CPU
  34. GROUPS["i386"] = [ "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot", "i386_multiboot", "i386_ieee1275" ]
  35. GROUPS["x86_64"] = [ "x86_64_efi" ]
  36. GROUPS["x86"] = GROUPS["i386"] + GROUPS["x86_64"]
  37. GROUPS["mips"] = [ "mips_loongson", "mips_qemu_mips", "mips_arc" ]
  38. GROUPS["sparc64"] = [ "sparc64_ieee1275" ]
  39. GROUPS["powerpc"] = [ "powerpc_ieee1275" ]
  40. GROUPS["arm"] = [ "arm_uboot", "arm_efi", "arm_coreboot" ]
  41. GROUPS["arm64"] = [ "arm64_efi" ]
  42. GROUPS["loongarch64"] = [ "loongarch64_efi" ]
  43. GROUPS["riscv32"] = [ "riscv32_efi" ]
  44. GROUPS["riscv64"] = [ "riscv64_efi" ]
  45. # Groups based on firmware
  46. GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi",
  47. "loongarch64_efi", "riscv32_efi", "riscv64_efi" ]
  48. GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ]
  49. GROUPS["uboot"] = [ "arm_uboot" ]
  50. GROUPS["xen"] = [ "i386_xen", "x86_64_xen" ]
  51. GROUPS["coreboot"] = [ "i386_coreboot", "arm_coreboot" ]
  52. # emu is a special case so many core functionality isn't needed on this platform
  53. GROUPS["noemu"] = GRUB_PLATFORMS[:]; GROUPS["noemu"].remove("emu")
  54. # Groups based on hardware features
  55. GROUPS["cmos"] = GROUPS["x86"][:] + ["mips_loongson", "mips_qemu_mips",
  56. "sparc64_ieee1275", "powerpc_ieee1275"]
  57. GROUPS["cmos"].remove("i386_efi"); GROUPS["cmos"].remove("x86_64_efi");
  58. GROUPS["pci"] = GROUPS["x86"] + ["mips_loongson"]
  59. GROUPS["usb"] = GROUPS["pci"] + ["arm_coreboot"]
  60. # If gfxterm is main output console integrate it into kernel
  61. GROUPS["videoinkernel"] = ["mips_loongson", "i386_coreboot", "arm_coreboot" ]
  62. GROUPS["videomodules"] = GRUB_PLATFORMS[:];
  63. for i in GROUPS["videoinkernel"]: GROUPS["videomodules"].remove(i)
  64. # Similar for terminfo
  65. GROUPS["terminfoinkernel"] = [ "emu", "mips_loongson", "mips_arc", "mips_qemu_mips", "i386_xen_pvh" ] + GROUPS["xen"] + GROUPS["ieee1275"] + GROUPS["uboot"];
  66. GROUPS["terminfomodule"] = GRUB_PLATFORMS[:];
  67. for i in GROUPS["terminfoinkernel"]: GROUPS["terminfomodule"].remove(i)
  68. # Flattened Device Trees (FDT)
  69. GROUPS["fdt"] = [ "arm64_efi", "arm_uboot", "arm_efi", "loongarch64_efi", "riscv32_efi", "riscv64_efi" ]
  70. # Needs software helpers for division
  71. # Must match GRUB_DIVISION_IN_SOFTWARE in misc.h
  72. GROUPS["softdiv"] = GROUPS["arm"] + ["ia64_efi"] + GROUPS["riscv32"]
  73. GROUPS["no_softdiv"] = GRUB_PLATFORMS[:]
  74. for i in GROUPS["softdiv"]: GROUPS["no_softdiv"].remove(i)
  75. # Miscellaneous groups scheduled to disappear in future
  76. GROUPS["i386_coreboot_multiboot_qemu"] = ["i386_coreboot", "i386_multiboot", "i386_qemu"]
  77. GROUPS["nopc"] = GRUB_PLATFORMS[:]; GROUPS["nopc"].remove("i386_pc")
  78. #
  79. # Create platform => groups reverse map, where groups covering that
  80. # platform are ordered by their sizes
  81. #
  82. RMAP = {}
  83. for platform in GRUB_PLATFORMS:
  84. # initialize with platform itself as a group
  85. RMAP[platform] = [ platform ]
  86. for k in GROUPS.keys():
  87. v = GROUPS[k]
  88. # skip groups that don't cover this platform
  89. if platform not in v: continue
  90. bigger = []
  91. smaller = []
  92. # partition currently known groups based on their size
  93. for group in RMAP[platform]:
  94. if group in GRUB_PLATFORMS: smaller.append(group)
  95. elif len(GROUPS[group]) < len(v): smaller.append(group)
  96. else: bigger.append(group)
  97. # insert in the middle
  98. RMAP[platform] = smaller + [ k ] + bigger
  99. #
  100. # Input
  101. #
  102. # We support a subset of the AutoGen definitions file syntax. Specifically,
  103. # compound names are disallowed; some preprocessing directives are
  104. # disallowed (though #if/#endif are allowed; note that, like AutoGen, #if
  105. # skips everything to the next #endif regardless of the value of the
  106. # conditional); and shell-generated strings, Scheme-generated strings, and
  107. # here strings are disallowed.
  108. class AutogenToken:
  109. (autogen, definitions, eof, var_name, other_name, string, number,
  110. semicolon, equals, comma, lbrace, rbrace, lbracket, rbracket) = range(14)
  111. class AutogenState:
  112. (init, need_def, need_tpl, need_semi, need_name, have_name, need_value,
  113. need_idx, need_rbracket, indx_name, have_value, done) = range(12)
  114. class AutogenParseError(Exception):
  115. def __init__(self, message, path, line):
  116. super(AutogenParseError, self).__init__(message)
  117. self.path = path
  118. self.line = line
  119. def __str__(self):
  120. return (
  121. super(AutogenParseError, self).__str__() +
  122. " at file %s line %d" % (self.path, self.line))
  123. class AutogenDefinition(list):
  124. def __getitem__(self, key):
  125. try:
  126. return super(AutogenDefinition, self).__getitem__(key)
  127. except TypeError:
  128. for name, value in self:
  129. if name == key:
  130. return value
  131. def __contains__(self, key):
  132. for name, value in self:
  133. if name == key:
  134. return True
  135. return False
  136. def get(self, key, default):
  137. for name, value in self:
  138. if name == key:
  139. return value
  140. else:
  141. return default
  142. def find_all(self, key):
  143. for name, value in self:
  144. if name == key:
  145. yield value
  146. class AutogenParser:
  147. def __init__(self):
  148. self.definitions = AutogenDefinition()
  149. self.def_stack = [("", self.definitions)]
  150. self.curdef = None
  151. self.new_name = None
  152. self.cur_path = None
  153. self.cur_line = 0
  154. @staticmethod
  155. def is_unquotable_char(c):
  156. return (ord(c) in range(ord("!"), ord("~") + 1) and
  157. c not in "#,;<=>[\\]`{}?*'\"()")
  158. @staticmethod
  159. def is_value_name_char(c):
  160. return c in ":^-_" or c.isalnum()
  161. def error(self, message):
  162. raise AutogenParseError(message, self.cur_file, self.cur_line)
  163. def read_tokens(self, f):
  164. data = f.read()
  165. end = len(data)
  166. offset = 0
  167. while offset < end:
  168. while offset < end and data[offset].isspace():
  169. if data[offset] == "\n":
  170. self.cur_line += 1
  171. offset += 1
  172. if offset >= end:
  173. break
  174. c = data[offset]
  175. if c == "#":
  176. offset += 1
  177. try:
  178. end_directive = data.index("\n", offset)
  179. directive = data[offset:end_directive]
  180. offset = end_directive
  181. except ValueError:
  182. directive = data[offset:]
  183. offset = end
  184. name, value = directive.split(None, 1)
  185. if name == "if":
  186. try:
  187. end_if = data.index("\n#endif", offset)
  188. new_offset = end_if + len("\n#endif")
  189. self.cur_line += data[offset:new_offset].count("\n")
  190. offset = new_offset
  191. except ValueError:
  192. self.error("#if without matching #endif")
  193. else:
  194. self.error("Unhandled directive '#%s'" % name)
  195. elif c == "{":
  196. yield AutogenToken.lbrace, c
  197. offset += 1
  198. elif c == "=":
  199. yield AutogenToken.equals, c
  200. offset += 1
  201. elif c == "}":
  202. yield AutogenToken.rbrace, c
  203. offset += 1
  204. elif c == "[":
  205. yield AutogenToken.lbracket, c
  206. offset += 1
  207. elif c == "]":
  208. yield AutogenToken.rbracket, c
  209. offset += 1
  210. elif c == ";":
  211. yield AutogenToken.semicolon, c
  212. offset += 1
  213. elif c == ",":
  214. yield AutogenToken.comma, c
  215. offset += 1
  216. elif c in ("'", '"'):
  217. s = []
  218. while True:
  219. offset += 1
  220. if offset >= end:
  221. self.error("EOF in quoted string")
  222. if data[offset] == "\n":
  223. self.cur_line += 1
  224. if data[offset] == "\\":
  225. offset += 1
  226. if offset >= end:
  227. self.error("EOF in quoted string")
  228. if data[offset] == "\n":
  229. self.cur_line += 1
  230. # Proper escaping unimplemented; this can be filled
  231. # out if needed.
  232. s.append("\\")
  233. s.append(data[offset])
  234. elif data[offset] == c:
  235. offset += 1
  236. break
  237. else:
  238. s.append(data[offset])
  239. yield AutogenToken.string, "".join(s)
  240. elif c == "/":
  241. offset += 1
  242. if data[offset] == "*":
  243. offset += 1
  244. try:
  245. end_comment = data.index("*/", offset)
  246. new_offset = end_comment + len("*/")
  247. self.cur_line += data[offset:new_offset].count("\n")
  248. offset = new_offset
  249. except ValueError:
  250. self.error("/* without matching */")
  251. elif data[offset] == "/":
  252. try:
  253. offset = data.index("\n", offset)
  254. except ValueError:
  255. pass
  256. elif (c.isdigit() or
  257. (c == "-" and offset < end - 1 and
  258. data[offset + 1].isdigit())):
  259. end_number = offset + 1
  260. while end_number < end and data[end_number].isdigit():
  261. end_number += 1
  262. yield AutogenToken.number, data[offset:end_number]
  263. offset = end_number
  264. elif self.is_unquotable_char(c):
  265. end_name = offset
  266. while (end_name < end and
  267. self.is_value_name_char(data[end_name])):
  268. end_name += 1
  269. if end_name < end and self.is_unquotable_char(data[end_name]):
  270. while (end_name < end and
  271. self.is_unquotable_char(data[end_name])):
  272. end_name += 1
  273. yield AutogenToken.other_name, data[offset:end_name]
  274. offset = end_name
  275. else:
  276. s = data[offset:end_name]
  277. if s.lower() == "autogen":
  278. yield AutogenToken.autogen, s
  279. elif s.lower() == "definitions":
  280. yield AutogenToken.definitions, s
  281. else:
  282. yield AutogenToken.var_name, s
  283. offset = end_name
  284. else:
  285. self.error("Invalid input character '%s'" % c)
  286. yield AutogenToken.eof, None
  287. def do_need_name_end(self, token):
  288. if len(self.def_stack) > 1:
  289. self.error("Definition blocks were left open")
  290. def do_need_name_var_name(self, token):
  291. self.new_name = token
  292. def do_end_block(self, token):
  293. if len(self.def_stack) <= 1:
  294. self.error("Too many close braces")
  295. new_name, parent_def = self.def_stack.pop()
  296. parent_def.append((new_name, self.curdef))
  297. self.curdef = parent_def
  298. def do_empty_val(self, token):
  299. self.curdef.append((self.new_name, ""))
  300. def do_str_value(self, token):
  301. self.curdef.append((self.new_name, token))
  302. def do_start_block(self, token):
  303. self.def_stack.append((self.new_name, self.curdef))
  304. self.curdef = AutogenDefinition()
  305. def do_indexed_name(self, token):
  306. self.new_name = token
  307. def read_definitions_file(self, f):
  308. self.curdef = self.definitions
  309. self.cur_line = 0
  310. state = AutogenState.init
  311. # The following transition table was reduced from the Autogen
  312. # documentation:
  313. # info -f autogen -n 'Full Syntax'
  314. transitions = {
  315. AutogenState.init: {
  316. AutogenToken.autogen: (AutogenState.need_def, None),
  317. },
  318. AutogenState.need_def: {
  319. AutogenToken.definitions: (AutogenState.need_tpl, None),
  320. },
  321. AutogenState.need_tpl: {
  322. AutogenToken.var_name: (AutogenState.need_semi, None),
  323. AutogenToken.other_name: (AutogenState.need_semi, None),
  324. AutogenToken.string: (AutogenState.need_semi, None),
  325. },
  326. AutogenState.need_semi: {
  327. AutogenToken.semicolon: (AutogenState.need_name, None),
  328. },
  329. AutogenState.need_name: {
  330. AutogenToken.autogen: (AutogenState.need_def, None),
  331. AutogenToken.eof: (AutogenState.done, self.do_need_name_end),
  332. AutogenToken.var_name: (
  333. AutogenState.have_name, self.do_need_name_var_name),
  334. AutogenToken.rbrace: (
  335. AutogenState.have_value, self.do_end_block),
  336. },
  337. AutogenState.have_name: {
  338. AutogenToken.semicolon: (
  339. AutogenState.need_name, self.do_empty_val),
  340. AutogenToken.equals: (AutogenState.need_value, None),
  341. AutogenToken.lbracket: (AutogenState.need_idx, None),
  342. },
  343. AutogenState.need_value: {
  344. AutogenToken.var_name: (
  345. AutogenState.have_value, self.do_str_value),
  346. AutogenToken.other_name: (
  347. AutogenState.have_value, self.do_str_value),
  348. AutogenToken.string: (
  349. AutogenState.have_value, self.do_str_value),
  350. AutogenToken.number: (
  351. AutogenState.have_value, self.do_str_value),
  352. AutogenToken.lbrace: (
  353. AutogenState.need_name, self.do_start_block),
  354. },
  355. AutogenState.need_idx: {
  356. AutogenToken.var_name: (
  357. AutogenState.need_rbracket, self.do_indexed_name),
  358. AutogenToken.number: (
  359. AutogenState.need_rbracket, self.do_indexed_name),
  360. },
  361. AutogenState.need_rbracket: {
  362. AutogenToken.rbracket: (AutogenState.indx_name, None),
  363. },
  364. AutogenState.indx_name: {
  365. AutogenToken.semicolon: (
  366. AutogenState.need_name, self.do_empty_val),
  367. AutogenToken.equals: (AutogenState.need_value, None),
  368. },
  369. AutogenState.have_value: {
  370. AutogenToken.semicolon: (AutogenState.need_name, None),
  371. AutogenToken.comma: (AutogenState.need_value, None),
  372. },
  373. }
  374. for code, token in self.read_tokens(f):
  375. if code in transitions[state]:
  376. state, handler = transitions[state][code]
  377. if handler is not None:
  378. handler(token)
  379. else:
  380. self.error(
  381. "Parse error in state %s: unexpected token '%s'" % (
  382. state, token))
  383. if state == AutogenState.done:
  384. break
  385. def read_definitions(self, path):
  386. self.cur_file = path
  387. with open(path) as f:
  388. self.read_definitions_file(f)
  389. defparser = AutogenParser()
  390. #
  391. # Output
  392. #
  393. outputs = {}
  394. def output(s, section=''):
  395. if s == "":
  396. return
  397. outputs.setdefault(section, [])
  398. outputs[section].append(s)
  399. def write_output(section=''):
  400. for s in outputs.get(section, []):
  401. print(s, end='')
  402. #
  403. # Global variables
  404. #
  405. def gvar_add(var, value):
  406. output(var + " += " + value + "\n")
  407. #
  408. # Per PROGRAM/SCRIPT variables
  409. #
  410. seen_vars = set()
  411. def vars_init(defn, *var_list):
  412. name = defn['name']
  413. if name not in seen_target and name not in seen_vars:
  414. for var in var_list:
  415. output(var + " = \n", section='decl')
  416. seen_vars.add(name)
  417. def var_set(var, value):
  418. output(var + " = " + value + "\n")
  419. def var_add(var, value):
  420. output(var + " += " + value + "\n")
  421. #
  422. # Variable names and rules
  423. #
  424. canonical_name_re = re.compile(r'[^0-9A-Za-z@_]')
  425. canonical_name_suffix = ""
  426. def set_canonical_name_suffix(suffix):
  427. global canonical_name_suffix
  428. canonical_name_suffix = suffix
  429. def cname(defn):
  430. return canonical_name_re.sub('_', defn['name'] + canonical_name_suffix)
  431. def rule(target, source, cmd):
  432. if cmd[0] == "\n":
  433. output("\n" + target + ": " + source + cmd.replace("\n", "\n\t") + "\n")
  434. else:
  435. output("\n" + target + ": " + source + "\n\t" + cmd.replace("\n", "\n\t") + "\n")
  436. #
  437. # Handle keys with platform names as values, for example:
  438. #
  439. # kernel = {
  440. # nostrip = emu;
  441. # ...
  442. # }
  443. #
  444. def platform_tagged(defn, platform, tag):
  445. for value in defn.find_all(tag):
  446. for group in RMAP[platform]:
  447. if value == group:
  448. return True
  449. return False
  450. def if_platform_tagged(defn, platform, tag, snippet_if, snippet_else=None):
  451. if platform_tagged(defn, platform, tag):
  452. return snippet_if
  453. elif snippet_else is not None:
  454. return snippet_else
  455. #
  456. # Handle tagged values
  457. #
  458. # module = {
  459. # extra_dist = ...
  460. # extra_dist = ...
  461. # ...
  462. # };
  463. #
  464. def foreach_value(defn, tag, closure):
  465. r = []
  466. for value in defn.find_all(tag):
  467. r.append(closure(value))
  468. return ''.join(r)
  469. #
  470. # Handle best matched values for a platform, for example:
  471. #
  472. # module = {
  473. # cflags = '-Wall';
  474. # emu_cflags = '-Wall -DGRUB_EMU=1';
  475. # ...
  476. # }
  477. #
  478. def foreach_platform_specific_value(defn, platform, suffix, nonetag, closure):
  479. r = []
  480. for group in RMAP[platform]:
  481. values = list(defn.find_all(group + suffix))
  482. if values:
  483. for value in values:
  484. r.append(closure(value))
  485. break
  486. else:
  487. for value in defn.find_all(nonetag):
  488. r.append(closure(value))
  489. return ''.join(r)
  490. #
  491. # Handle values from sum of all groups for a platform, for example:
  492. #
  493. # module = {
  494. # common = kern/misc.c;
  495. # emu = kern/emu/misc.c;
  496. # ...
  497. # }
  498. #
  499. def foreach_platform_value(defn, platform, suffix, closure):
  500. r = []
  501. for group in RMAP[platform]:
  502. for value in defn.find_all(group + suffix):
  503. r.append(closure(value))
  504. r.sort()
  505. return ''.join(r)
  506. def platform_conditional(platform, closure):
  507. output("\nif COND_" + platform + "\n")
  508. closure(platform)
  509. output("endif\n")
  510. #
  511. # Handle guarding with platform-specific "enable" keys, for example:
  512. #
  513. # module = {
  514. # name = pci;
  515. # noemu = bus/pci.c;
  516. # emu = bus/emu/pci.c;
  517. # emu = commands/lspci.c;
  518. #
  519. # enable = emu;
  520. # enable = i386_pc;
  521. # enable = x86_efi;
  522. # enable = i386_ieee1275;
  523. # enable = i386_coreboot;
  524. # };
  525. #
  526. def foreach_enabled_platform(defn, closure):
  527. if 'enable' in defn:
  528. for platform in GRUB_PLATFORMS:
  529. if platform_tagged(defn, platform, "enable"):
  530. platform_conditional(platform, closure)
  531. else:
  532. for platform in GRUB_PLATFORMS:
  533. platform_conditional(platform, closure)
  534. #
  535. # Handle guarding with platform-specific automake conditionals, for example:
  536. #
  537. # module = {
  538. # name = usb;
  539. # common = bus/usb/usb.c;
  540. # noemu = bus/usb/usbtrans.c;
  541. # noemu = bus/usb/usbhub.c;
  542. # enable = emu;
  543. # enable = i386;
  544. # enable = mips_loongson;
  545. # emu_condition = COND_GRUB_EMU_SDL;
  546. # };
  547. #
  548. def under_platform_specific_conditionals(defn, platform, closure):
  549. output(foreach_platform_specific_value(defn, platform, "_condition", "condition", lambda cond: "if " + cond + "\n"))
  550. closure(defn, platform)
  551. output(foreach_platform_specific_value(defn, platform, "_condition", "condition", lambda cond: "endif " + cond + "\n"))
  552. def platform_specific_values(defn, platform, suffix, nonetag):
  553. return foreach_platform_specific_value(defn, platform, suffix, nonetag,
  554. lambda value: value + " ")
  555. def platform_values(defn, platform, suffix):
  556. return foreach_platform_value(defn, platform, suffix, lambda value: value + " ")
  557. def extra_dist(defn):
  558. return foreach_value(defn, "extra_dist", lambda value: value + " ")
  559. def extra_dep(defn):
  560. return foreach_value(defn, "depends", lambda value: value + " ")
  561. def platform_sources(defn, p): return platform_values(defn, p, "_head") + platform_values(defn, p, "")
  562. def platform_nodist_sources(defn, p): return platform_values(defn, p, "_nodist")
  563. def platform_startup(defn, p): return platform_specific_values(defn, p, "_startup", "startup")
  564. def platform_ldadd(defn, p): return platform_specific_values(defn, p, "_ldadd", "ldadd")
  565. def platform_dependencies(defn, p): return platform_specific_values(defn, p, "_dependencies", "dependencies")
  566. def platform_cflags(defn, p): return platform_specific_values(defn, p, "_cflags", "cflags")
  567. def platform_ldflags(defn, p): return platform_specific_values(defn, p, "_ldflags", "ldflags")
  568. def platform_cppflags(defn, p): return platform_specific_values(defn, p, "_cppflags", "cppflags")
  569. def platform_ccasflags(defn, p): return platform_specific_values(defn, p, "_ccasflags", "ccasflags")
  570. def platform_stripflags(defn, p): return platform_specific_values(defn, p, "_stripflags", "stripflags")
  571. def platform_objcopyflags(defn, p): return platform_specific_values(defn, p, "_objcopyflags", "objcopyflags")
  572. #
  573. # Emit snippet only the first time through for the current name.
  574. #
  575. seen_target = set()
  576. def first_time(defn, snippet):
  577. if defn['name'] not in seen_target:
  578. return snippet
  579. return ''
  580. def is_platform_independent(defn):
  581. if 'enable' in defn:
  582. return False
  583. for suffix in [ "", "_head", "_nodist" ]:
  584. template = platform_values(defn, GRUB_PLATFORMS[0], suffix)
  585. for platform in GRUB_PLATFORMS[1:]:
  586. if template != platform_values(defn, platform, suffix):
  587. return False
  588. for suffix in [ "startup", "ldadd", "dependencies", "cflags", "ldflags", "cppflags", "ccasflags", "stripflags", "objcopyflags", "condition" ]:
  589. template = platform_specific_values(defn, GRUB_PLATFORMS[0], "_" + suffix, suffix)
  590. for platform in GRUB_PLATFORMS[1:]:
  591. if template != platform_specific_values(defn, platform, "_" + suffix, suffix):
  592. return False
  593. for tag in [ "nostrip" ]:
  594. template = platform_tagged(defn, GRUB_PLATFORMS[0], tag)
  595. for platform in GRUB_PLATFORMS[1:]:
  596. if template != platform_tagged(defn, platform, tag):
  597. return False
  598. return True
  599. def module(defn, platform):
  600. name = defn['name']
  601. set_canonical_name_suffix(".module")
  602. gvar_add("platform_PROGRAMS", name + ".module")
  603. gvar_add("MODULE_FILES", name + ".module$(EXEEXT)")
  604. var_set(cname(defn) + "_SOURCES", platform_sources(defn, platform) + " ## platform sources")
  605. var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform) + " ## platform nodist sources")
  606. var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform))
  607. var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_MODULE) " + platform_cflags(defn, platform))
  608. var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_MODULE) " + platform_ldflags(defn, platform))
  609. var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_MODULE) " + platform_cppflags(defn, platform))
  610. var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_MODULE) " + platform_ccasflags(defn, platform))
  611. var_set(cname(defn) + "_DEPENDENCIES", "$(TARGET_OBJ2ELF) " + platform_dependencies(defn, platform))
  612. gvar_add("dist_noinst_DATA", extra_dist(defn))
  613. gvar_add("BUILT_SOURCES", "$(nodist_" + cname(defn) + "_SOURCES)")
  614. gvar_add("CLEANFILES", "$(nodist_" + cname(defn) + "_SOURCES)")
  615. gvar_add("MOD_FILES", name + ".mod")
  616. gvar_add("MARKER_FILES", name + ".marker")
  617. gvar_add("CLEANFILES", name + ".marker")
  618. for dep in defn.find_all("depends"):
  619. gvar_add("EXTRA_DEPS", "depends " + name + " " + dep + ":")
  620. output("""
  621. """ + name + """.marker: $(""" + cname(defn) + """_SOURCES) $(nodist_""" + cname(defn) + """_SOURCES)
  622. $(TARGET_CPP) -DGRUB_LST_GENERATOR $(CPPFLAGS_MARKER) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(""" + cname(defn) + """_CPPFLAGS) $(CPPFLAGS) $^ > $@.new || (rm -f $@; exit 1)
  623. grep 'MARKER' $@.new | grep -v '^#' > $@; rm -f $@.new
  624. """)
  625. def kernel(defn, platform):
  626. name = defn['name']
  627. set_canonical_name_suffix(".exec")
  628. gvar_add("platform_PROGRAMS", name + ".exec")
  629. var_set(cname(defn) + "_SOURCES", platform_startup(defn, platform))
  630. var_add(cname(defn) + "_SOURCES", platform_sources(defn, platform))
  631. var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform) + " ## platform nodist sources")
  632. var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform))
  633. var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_KERNEL) " + platform_cflags(defn, platform))
  634. var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_KERNEL) " + platform_ldflags(defn, platform))
  635. var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_KERNEL) " + platform_cppflags(defn, platform))
  636. var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_KERNEL) " + platform_ccasflags(defn, platform))
  637. var_set(cname(defn) + "_STRIPFLAGS", "$(AM_STRIPFLAGS) $(STRIPFLAGS_KERNEL) " + platform_stripflags(defn, platform))
  638. var_set(cname(defn) + "_DEPENDENCIES", "$(TARGET_OBJ2ELF)")
  639. gvar_add("dist_noinst_DATA", extra_dist(defn))
  640. gvar_add("BUILT_SOURCES", "$(nodist_" + cname(defn) + "_SOURCES)")
  641. gvar_add("CLEANFILES", "$(nodist_" + cname(defn) + "_SOURCES)")
  642. gvar_add("platform_DATA", name + ".img")
  643. gvar_add("CLEANFILES", name + ".img")
  644. rule(name + ".img", name + ".exec$(EXEEXT)",
  645. if_platform_tagged(defn, platform, "nostrip",
  646. """if test x$(TARGET_APPLE_LINKER) = x1; then \
  647. $(TARGET_OBJCONV) -f$(TARGET_MODULE_FORMAT) -nr:_grub_mod_init:grub_mod_init -nr:_grub_mod_fini:grub_mod_fini -ed2022 -wd1106 -nu -nd $< $@; \
  648. elif test ! -z '$(TARGET_OBJ2ELF)'; then \
  649. $(TARGET_OBJ2ELF) $< $@ || (rm -f $@; exit 1); \
  650. else cp $< $@; fi""",
  651. """if test x$(TARGET_APPLE_LINKER) = x1; then \
  652. $(TARGET_STRIP) -S -x $(""" + cname(defn) + """) -o $@.bin $<; \
  653. $(TARGET_OBJCONV) -f$(TARGET_MODULE_FORMAT) -nr:_grub_mod_init:grub_mod_init -nr:_grub_mod_fini:grub_mod_fini -ed2022 -ed2016 -wd1106 -nu -nd $@.bin $@; \
  654. rm -f $@.bin; \
  655. elif test ! -z '$(TARGET_OBJ2ELF)'; then \
  656. """ + "$(TARGET_STRIP) $(" + cname(defn) + "_STRIPFLAGS) -o $@.bin $< && \
  657. $(TARGET_OBJ2ELF) $@.bin $@ || (rm -f $@; rm -f $@.bin; exit 1); \
  658. rm -f $@.bin; \
  659. else """ + "$(TARGET_STRIP) $(" + cname(defn) + "_STRIPFLAGS) -o $@ $<; \
  660. fi"""))
  661. def image(defn, platform):
  662. name = defn['name']
  663. set_canonical_name_suffix(".image")
  664. gvar_add("platform_PROGRAMS", name + ".image")
  665. var_set(cname(defn) + "_SOURCES", platform_sources(defn, platform))
  666. var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform) + "## platform nodist sources")
  667. var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform))
  668. var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_IMAGE) " + platform_cflags(defn, platform))
  669. var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_IMAGE) " + platform_ldflags(defn, platform))
  670. var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_IMAGE) " + platform_cppflags(defn, platform))
  671. var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_IMAGE) " + platform_ccasflags(defn, platform))
  672. var_set(cname(defn) + "_OBJCOPYFLAGS", "$(OBJCOPYFLAGS_IMAGE) " + platform_objcopyflags(defn, platform))
  673. # var_set(cname(defn) + "_DEPENDENCIES", platform_dependencies(defn, platform) + " " + platform_ldadd(defn, platform))
  674. gvar_add("dist_noinst_DATA", extra_dist(defn))
  675. gvar_add("BUILT_SOURCES", "$(nodist_" + cname(defn) + "_SOURCES)")
  676. gvar_add("CLEANFILES", "$(nodist_" + cname(defn) + "_SOURCES)")
  677. gvar_add("platform_DATA", name + ".img")
  678. gvar_add("CLEANFILES", name + ".img")
  679. rule(name + ".img", name + ".image$(EXEEXT)", """
  680. if test x$(TARGET_APPLE_LINKER) = x1; then \
  681. $(MACHO2IMG) $< $@; \
  682. else \
  683. $(TARGET_OBJCOPY) $(""" + cname(defn) + """_OBJCOPYFLAGS) --strip-unneeded -R .note -R .comment -R .note.gnu.build-id -R .MIPS.abiflags -R .reginfo -R .rel.dyn -R .note.gnu.gold-version -R .note.gnu.property -R .ARM.exidx -R .interp $< $@; \
  684. fi
  685. """)
  686. def library(defn, platform):
  687. name = defn['name']
  688. set_canonical_name_suffix("")
  689. vars_init(defn,
  690. cname(defn) + "_SOURCES",
  691. "nodist_" + cname(defn) + "_SOURCES",
  692. cname(defn) + "_CFLAGS",
  693. cname(defn) + "_CPPFLAGS",
  694. cname(defn) + "_CCASFLAGS")
  695. # cname(defn) + "_DEPENDENCIES")
  696. if name not in seen_target:
  697. gvar_add("noinst_LIBRARIES", name)
  698. var_add(cname(defn) + "_SOURCES", platform_sources(defn, platform))
  699. var_add("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform))
  700. var_add(cname(defn) + "_CFLAGS", first_time(defn, "$(AM_CFLAGS) $(CFLAGS_LIBRARY) ") + platform_cflags(defn, platform))
  701. var_add(cname(defn) + "_CPPFLAGS", first_time(defn, "$(AM_CPPFLAGS) $(CPPFLAGS_LIBRARY) ") + platform_cppflags(defn, platform))
  702. var_add(cname(defn) + "_CCASFLAGS", first_time(defn, "$(AM_CCASFLAGS) $(CCASFLAGS_LIBRARY) ") + platform_ccasflags(defn, platform))
  703. # var_add(cname(defn) + "_DEPENDENCIES", platform_dependencies(defn, platform) + " " + platform_ldadd(defn, platform))
  704. gvar_add("dist_noinst_DATA", extra_dist(defn))
  705. if name not in seen_target:
  706. gvar_add("BUILT_SOURCES", "$(nodist_" + cname(defn) + "_SOURCES)")
  707. gvar_add("CLEANFILES", "$(nodist_" + cname(defn) + "_SOURCES)")
  708. def installdir(defn, default="bin"):
  709. return defn.get('installdir', default)
  710. def manpage(defn, adddeps):
  711. name = defn['name']
  712. mansection = defn['mansection']
  713. output("if COND_MAN_PAGES\n")
  714. gvar_add("man_MANS", name + "." + mansection)
  715. rule(name + "." + mansection, name + " " + adddeps, """
  716. chmod a+x """ + name + """
  717. PATH=$(builddir):$$PATH pkgdatadir=$(builddir) $(HELP2MAN) --section=""" + mansection + """ -i $(top_srcdir)/docs/man/""" + name + """.h2m -o $@ """ + name + """
  718. """)
  719. gvar_add("CLEANFILES", name + "." + mansection)
  720. output("endif\n")
  721. def program(defn, platform, test=False):
  722. name = defn['name']
  723. set_canonical_name_suffix("")
  724. if 'testcase' in defn:
  725. gvar_add("check_PROGRAMS_" + defn['testcase'], name)
  726. else:
  727. var_add(installdir(defn) + "_PROGRAMS", name)
  728. if 'mansection' in defn:
  729. manpage(defn, "")
  730. var_set(cname(defn) + "_SOURCES", platform_sources(defn, platform))
  731. var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform))
  732. var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform))
  733. var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_PROGRAM) " + platform_cflags(defn, platform))
  734. var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_PROGRAM) " + platform_ldflags(defn, platform))
  735. var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_PROGRAM) " + platform_cppflags(defn, platform))
  736. var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_PROGRAM) " + platform_ccasflags(defn, platform))
  737. # var_set(cname(defn) + "_DEPENDENCIES", platform_dependencies(defn, platform) + " " + platform_ldadd(defn, platform))
  738. gvar_add("dist_noinst_DATA", extra_dist(defn))
  739. gvar_add("BUILT_SOURCES", "$(nodist_" + cname(defn) + "_SOURCES)")
  740. gvar_add("CLEANFILES", "$(nodist_" + cname(defn) + "_SOURCES)")
  741. def data(defn, platform):
  742. var_add("dist_" + installdir(defn) + "_DATA", platform_sources(defn, platform))
  743. gvar_add("dist_noinst_DATA", extra_dist(defn))
  744. def transform_data(defn, platform):
  745. name = defn['name']
  746. var_add(installdir(defn) + "_DATA", name)
  747. rule(name, "$(top_builddir)/config.status " + platform_sources(defn, platform) + platform_dependencies(defn, platform), """
  748. (for x in """ + platform_sources(defn, platform) + """; do cat $(srcdir)/"$$x"; done) | $(top_builddir)/config.status --file=$@:-
  749. chmod a+x """ + name + """
  750. """)
  751. gvar_add("CLEANFILES", name)
  752. gvar_add("EXTRA_DIST", extra_dist(defn))
  753. gvar_add("dist_noinst_DATA", platform_sources(defn, platform))
  754. def script(defn, platform):
  755. name = defn['name']
  756. if 'testcase' in defn:
  757. gvar_add("check_SCRIPTS_" + defn['testcase'], name)
  758. else:
  759. var_add(installdir(defn) + "_SCRIPTS", name)
  760. if 'mansection' in defn:
  761. manpage(defn, "grub-mkconfig_lib")
  762. rule(name, "$(top_builddir)/config.status " + platform_sources(defn, platform) + platform_dependencies(defn, platform), """
  763. (for x in """ + platform_sources(defn, platform) + """; do cat $(srcdir)/"$$x"; done) | $(top_builddir)/config.status --file=$@:-
  764. chmod a+x """ + name + """
  765. """)
  766. gvar_add("CLEANFILES", name)
  767. gvar_add("EXTRA_DIST", extra_dist(defn))
  768. gvar_add("dist_noinst_DATA", platform_sources(defn, platform))
  769. def rules(target, closure):
  770. seen_target.clear()
  771. seen_vars.clear()
  772. for defn in defparser.definitions.find_all(target):
  773. if is_platform_independent(defn):
  774. under_platform_specific_conditionals(defn, GRUB_PLATFORMS[0], closure)
  775. else:
  776. foreach_enabled_platform(
  777. defn,
  778. lambda p: under_platform_specific_conditionals(defn, p, closure))
  779. # Remember that we've seen this target.
  780. seen_target.add(defn['name'])
  781. parser = OptionParser(usage="%prog DEFINITION-FILES")
  782. _, args = parser.parse_args()
  783. for arg in args:
  784. defparser.read_definitions(arg)
  785. rules("module", module)
  786. rules("kernel", kernel)
  787. rules("image", image)
  788. rules("library", library)
  789. rules("program", program)
  790. rules("script", script)
  791. rules("data", data)
  792. rules("transform_data", transform_data)
  793. write_output(section='decl')
  794. write_output()