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