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