mirror of
				https://git.proxmox.com/git/grub2
				synced 2025-10-31 12:27:02 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			904 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			904 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #! /usr/bin/python
 | |
| #  GRUB  --  GRand Unified Bootloader
 | |
| #  Copyright (C) 2010,2011,2012,2013  Free Software Foundation, Inc.
 | |
| #
 | |
| #  GRUB is free software: you can redistribute it and/or modify
 | |
| #  it under the terms of the GNU General Public License as published by
 | |
| #  the Free Software Foundation, either version 3 of the License, or
 | |
| #  (at your option) any later version.
 | |
| #
 | |
| #  GRUB is distributed in the hope that it will be useful,
 | |
| #  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| #  GNU General Public License for more details.
 | |
| #
 | |
| #  You should have received a copy of the GNU General Public License
 | |
| #  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | |
| 
 | |
| from __future__ import print_function
 | |
| 
 | |
| __metaclass__ = type
 | |
| 
 | |
| from optparse import OptionParser
 | |
| import re
 | |
| 
 | |
| #
 | |
| # This is the python script used to generate Makefile.*.am
 | |
| #
 | |
| 
 | |
| GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot",
 | |
|                    "i386_multiboot", "i386_ieee1275", "x86_64_efi",
 | |
|                    "i386_xen", "x86_64_xen",
 | |
|                    "mips_loongson", "sparc64_ieee1275",
 | |
|                    "powerpc_ieee1275", "mips_arc", "ia64_efi",
 | |
|                    "mips_qemu_mips", "arm_uboot", "arm_efi", "arm64_efi" ]
 | |
| 
 | |
| GROUPS = {}
 | |
| 
 | |
| GROUPS["common"]   = GRUB_PLATFORMS[:]
 | |
| 
 | |
| # Groups based on CPU
 | |
| GROUPS["i386"]     = [ "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot", "i386_multiboot", "i386_ieee1275" ]
 | |
| GROUPS["x86_64"]   = [ "x86_64_efi" ]
 | |
| GROUPS["x86"]      = GROUPS["i386"] + GROUPS["x86_64"]
 | |
| GROUPS["mips"]     = [ "mips_loongson", "mips_qemu_mips", "mips_arc" ]
 | |
| GROUPS["sparc64"]  = [ "sparc64_ieee1275" ]
 | |
| GROUPS["powerpc"]  = [ "powerpc_ieee1275" ]
 | |
| GROUPS["arm"]      = [ "arm_uboot", "arm_efi" ]
 | |
| GROUPS["arm64"]    = [ "arm64_efi" ]
 | |
| 
 | |
| # Groups based on firmware
 | |
| GROUPS["efi"]  = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi" ]
 | |
| GROUPS["ieee1275"]   = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ]
 | |
| GROUPS["uboot"] = [ "arm_uboot" ]
 | |
| GROUPS["xen"]  = [ "i386_xen", "x86_64_xen" ]
 | |
| 
 | |
| # emu is a special case so many core functionality isn't needed on this platform
 | |
| GROUPS["noemu"]   = GRUB_PLATFORMS[:]; GROUPS["noemu"].remove("emu")
 | |
| 
 | |
| # Groups based on hardware features
 | |
| GROUPS["cmos"] = GROUPS["x86"][:] + ["mips_loongson", "mips_qemu_mips",
 | |
|                                      "sparc64_ieee1275", "powerpc_ieee1275"]
 | |
| GROUPS["cmos"].remove("i386_efi"); GROUPS["cmos"].remove("x86_64_efi");
 | |
| GROUPS["pci"]      = GROUPS["x86"] + ["mips_loongson"]
 | |
| GROUPS["usb"]      = GROUPS["pci"]
 | |
| 
 | |
| # If gfxterm is main output console integrate it into kernel
 | |
| GROUPS["videoinkernel"] = ["mips_loongson", "i386_coreboot" ]
 | |
| GROUPS["videomodules"]   = GRUB_PLATFORMS[:];
 | |
| for i in GROUPS["videoinkernel"]: GROUPS["videomodules"].remove(i)
 | |
| 
 | |
| # Similar for terminfo
 | |
| GROUPS["terminfoinkernel"] = [ "emu", "mips_loongson", "mips_arc", "mips_qemu_mips" ] + GROUPS["xen"] + GROUPS["ieee1275"] + GROUPS["uboot"];
 | |
| GROUPS["terminfomodule"]   = GRUB_PLATFORMS[:];
 | |
| for i in GROUPS["terminfoinkernel"]: GROUPS["terminfomodule"].remove(i)
 | |
| 
 | |
| # Flattened Device Trees (FDT)
 | |
| GROUPS["fdt"] = [ "arm64_efi", "arm_uboot", "arm_efi" ]
 | |
| 
 | |
| # Needs software helpers for division
 | |
| # Must match GRUB_DIVISION_IN_SOFTWARE in misc.h
 | |
| GROUPS["softdiv"] = GROUPS["arm"] + ["ia64_efi"]
 | |
| GROUPS["no_softdiv"]   = GRUB_PLATFORMS[:]
 | |
| for i in GROUPS["softdiv"]: GROUPS["no_softdiv"].remove(i)
 | |
| 
 | |
| # Miscellaneous groups scheduled to disappear in future
 | |
| GROUPS["i386_coreboot_multiboot_qemu"] = ["i386_coreboot", "i386_multiboot", "i386_qemu"]
 | |
| GROUPS["nopc"] = GRUB_PLATFORMS[:]; GROUPS["nopc"].remove("i386_pc")
 | |
| 
 | |
| #
 | |
| # Create platform => groups reverse map, where groups covering that
 | |
| # platform are ordered by their sizes
 | |
| #
 | |
| RMAP = {}
 | |
| for platform in GRUB_PLATFORMS:
 | |
|     # initialize with platform itself as a group
 | |
|     RMAP[platform] = [ platform ]
 | |
| 
 | |
|     for k in GROUPS.keys():
 | |
|         v = GROUPS[k]
 | |
|         # skip groups that don't cover this platform
 | |
|         if platform not in v: continue
 | |
| 
 | |
|         bigger = []
 | |
|         smaller = []
 | |
|         # partition currently known groups based on their size
 | |
|         for group in RMAP[platform]:
 | |
|             if group in GRUB_PLATFORMS: smaller.append(group)
 | |
|             elif len(GROUPS[group]) < len(v): smaller.append(group)
 | |
|             else: bigger.append(group)
 | |
|         # insert in the middle
 | |
|         RMAP[platform] = smaller + [ k ] + bigger
 | |
| 
 | |
| #
 | |
| # Input
 | |
| #
 | |
| 
 | |
| # We support a subset of the AutoGen definitions file syntax.  Specifically,
 | |
| # compound names are disallowed; some preprocessing directives are
 | |
| # disallowed (though #if/#endif are allowed; note that, like AutoGen, #if
 | |
| # skips everything to the next #endif regardless of the value of the
 | |
| # conditional); and shell-generated strings, Scheme-generated strings, and
 | |
| # here strings are disallowed.
 | |
| 
 | |
| class AutogenToken:
 | |
|     (autogen, definitions, eof, var_name, other_name, string, number,
 | |
|      semicolon, equals, comma, lbrace, rbrace, lbracket, rbracket) = range(14)
 | |
| 
 | |
| class AutogenState:
 | |
|     (init, need_def, need_tpl, need_semi, need_name, have_name, need_value,
 | |
|      need_idx, need_rbracket, indx_name, have_value, done) = range(12)
 | |
| 
 | |
| class AutogenParseError(Exception):
 | |
|     def __init__(self, message, path, line):
 | |
|         super(AutogenParseError, self).__init__(message)
 | |
|         self.path = path
 | |
|         self.line = line
 | |
| 
 | |
|     def __str__(self):
 | |
|         return (
 | |
|             super(AutogenParseError, self).__str__() +
 | |
|             " at file %s line %d" % (self.path, self.line))
 | |
| 
 | |
| class AutogenDefinition(list):
 | |
|     def __getitem__(self, key):
 | |
|         try:
 | |
|             return super(AutogenDefinition, self).__getitem__(key)
 | |
|         except TypeError:
 | |
|             for name, value in self:
 | |
|                 if name == key:
 | |
|                     return value
 | |
| 
 | |
|     def __contains__(self, key):
 | |
|         for name, value in self:
 | |
|             if name == key:
 | |
|                 return True
 | |
|         return False
 | |
| 
 | |
|     def get(self, key, default):
 | |
|         for name, value in self:
 | |
|             if name == key:
 | |
|                 return value
 | |
|         else:
 | |
|             return default
 | |
| 
 | |
|     def find_all(self, key):
 | |
|         for name, value in self:
 | |
|             if name == key:
 | |
|                 yield value
 | |
| 
 | |
| class AutogenParser:
 | |
|     def __init__(self):
 | |
|         self.definitions = AutogenDefinition()
 | |
|         self.def_stack = [("", self.definitions)]
 | |
|         self.curdef = None
 | |
|         self.new_name = None
 | |
|         self.cur_path = None
 | |
|         self.cur_line = 0
 | |
| 
 | |
|     @staticmethod
 | |
|     def is_unquotable_char(c):
 | |
|         return (ord(c) in range(ord("!"), ord("~") + 1) and
 | |
|                 c not in "#,;<=>[\\]`{}?*'\"()")
 | |
| 
 | |
|     @staticmethod
 | |
|     def is_value_name_char(c):
 | |
|         return c in ":^-_" or c.isalnum()
 | |
| 
 | |
|     def error(self, message):
 | |
|         raise AutogenParseError(message, self.cur_file, self.cur_line)
 | |
| 
 | |
|     def read_tokens(self, f):
 | |
|         data = f.read()
 | |
|         end = len(data)
 | |
|         offset = 0
 | |
|         while offset < end:
 | |
|             while offset < end and data[offset].isspace():
 | |
|                 if data[offset] == "\n":
 | |
|                     self.cur_line += 1
 | |
|                 offset += 1
 | |
|             if offset >= end:
 | |
|                 break
 | |
|             c = data[offset]
 | |
|             if c == "#":
 | |
|                 offset += 1
 | |
|                 try:
 | |
|                     end_directive = data.index("\n", offset)
 | |
|                     directive = data[offset:end_directive]
 | |
|                     offset = end_directive
 | |
|                 except ValueError:
 | |
|                     directive = data[offset:]
 | |
|                     offset = end
 | |
|                 name, value = directive.split(None, 1)
 | |
|                 if name == "if":
 | |
|                     try:
 | |
|                         end_if = data.index("\n#endif", offset)
 | |
|                         new_offset = end_if + len("\n#endif")
 | |
|                         self.cur_line += data[offset:new_offset].count("\n")
 | |
|                         offset = new_offset
 | |
|                     except ValueError:
 | |
|                         self.error("#if without matching #endif")
 | |
|                 else:
 | |
|                     self.error("Unhandled directive '#%s'" % name)
 | |
|             elif c == "{":
 | |
|                 yield AutogenToken.lbrace, c
 | |
|                 offset += 1
 | |
|             elif c == "=":
 | |
|                 yield AutogenToken.equals, c
 | |
|                 offset += 1
 | |
|             elif c == "}":
 | |
|                 yield AutogenToken.rbrace, c
 | |
|                 offset += 1
 | |
|             elif c == "[":
 | |
|                 yield AutogenToken.lbracket, c
 | |
|                 offset += 1
 | |
|             elif c == "]":
 | |
|                 yield AutogenToken.rbracket, c
 | |
|                 offset += 1
 | |
|             elif c == ";":
 | |
|                 yield AutogenToken.semicolon, c
 | |
|                 offset += 1
 | |
|             elif c == ",":
 | |
|                 yield AutogenToken.comma, c
 | |
|                 offset += 1
 | |
|             elif c in ("'", '"'):
 | |
|                 s = []
 | |
|                 while True:
 | |
|                     offset += 1
 | |
|                     if offset >= end:
 | |
|                         self.error("EOF in quoted string")
 | |
|                     if data[offset] == "\n":
 | |
|                         self.cur_line += 1
 | |
|                     if data[offset] == "\\":
 | |
|                         offset += 1
 | |
|                         if offset >= end:
 | |
|                             self.error("EOF in quoted string")
 | |
|                         if data[offset] == "\n":
 | |
|                             self.cur_line += 1
 | |
|                         # Proper escaping unimplemented; this can be filled
 | |
|                         # out if needed.
 | |
|                         s.append("\\")
 | |
|                         s.append(data[offset])
 | |
|                     elif data[offset] == c:
 | |
|                         offset += 1
 | |
|                         break
 | |
|                     else:
 | |
|                         s.append(data[offset])
 | |
|                 yield AutogenToken.string, "".join(s)
 | |
|             elif c == "/":
 | |
|                 offset += 1
 | |
|                 if data[offset] == "*":
 | |
|                     offset += 1
 | |
|                     try:
 | |
|                         end_comment = data.index("*/", offset)
 | |
|                         new_offset = end_comment + len("*/")
 | |
|                         self.cur_line += data[offset:new_offset].count("\n")
 | |
|                         offset = new_offset
 | |
|                     except ValueError:
 | |
|                         self.error("/* without matching */")
 | |
|                 elif data[offset] == "/":
 | |
|                     try:
 | |
|                         offset = data.index("\n", offset)
 | |
|                     except ValueError:
 | |
|                         pass
 | |
|             elif (c.isdigit() or
 | |
|                   (c == "-" and offset < end - 1 and
 | |
|                    data[offset + 1].isdigit())):
 | |
|                 end_number = offset + 1
 | |
|                 while end_number < end and data[end_number].isdigit():
 | |
|                     end_number += 1
 | |
|                 yield AutogenToken.number, data[offset:end_number]
 | |
|                 offset = end_number
 | |
|             elif self.is_unquotable_char(c):
 | |
|                 end_name = offset
 | |
|                 while (end_name < end and
 | |
|                        self.is_value_name_char(data[end_name])):
 | |
|                     end_name += 1
 | |
|                 if end_name < end and self.is_unquotable_char(data[end_name]):
 | |
|                     while (end_name < end and
 | |
|                            self.is_unquotable_char(data[end_name])):
 | |
|                         end_name += 1
 | |
|                     yield AutogenToken.other_name, data[offset:end_name]
 | |
|                     offset = end_name
 | |
|                 else:
 | |
|                     s = data[offset:end_name]
 | |
|                     if s.lower() == "autogen":
 | |
|                         yield AutogenToken.autogen, s
 | |
|                     elif s.lower() == "definitions":
 | |
|                         yield AutogenToken.definitions, s
 | |
|                     else:
 | |
|                         yield AutogenToken.var_name, s
 | |
|                     offset = end_name
 | |
|             else:
 | |
|                 self.error("Invalid input character '%s'" % c)
 | |
|         yield AutogenToken.eof, None
 | |
| 
 | |
|     def do_need_name_end(self, token):
 | |
|         if len(self.def_stack) > 1:
 | |
|             self.error("Definition blocks were left open")
 | |
| 
 | |
|     def do_need_name_var_name(self, token):
 | |
|         self.new_name = token
 | |
| 
 | |
|     def do_end_block(self, token):
 | |
|         if len(self.def_stack) <= 1:
 | |
|             self.error("Too many close braces")
 | |
|         new_name, parent_def = self.def_stack.pop()
 | |
|         parent_def.append((new_name, self.curdef))
 | |
|         self.curdef = parent_def
 | |
| 
 | |
|     def do_empty_val(self, token):
 | |
|         self.curdef.append((self.new_name, ""))
 | |
| 
 | |
|     def do_str_value(self, token):
 | |
|         self.curdef.append((self.new_name, token))
 | |
| 
 | |
|     def do_start_block(self, token):
 | |
|         self.def_stack.append((self.new_name, self.curdef))
 | |
|         self.curdef = AutogenDefinition()
 | |
| 
 | |
|     def do_indexed_name(self, token):
 | |
|         self.new_name = token
 | |
| 
 | |
|     def read_definitions_file(self, f):
 | |
|         self.curdef = self.definitions
 | |
|         self.cur_line = 0
 | |
|         state = AutogenState.init
 | |
| 
 | |
|         # The following transition table was reduced from the Autogen
 | |
|         # documentation:
 | |
|         #   info -f autogen -n 'Full Syntax'
 | |
|         transitions = {
 | |
|             AutogenState.init: {
 | |
|                 AutogenToken.autogen: (AutogenState.need_def, None),
 | |
|             },
 | |
|             AutogenState.need_def: {
 | |
|                 AutogenToken.definitions: (AutogenState.need_tpl, None),
 | |
|             },
 | |
|             AutogenState.need_tpl: {
 | |
|                 AutogenToken.var_name: (AutogenState.need_semi, None),
 | |
|                 AutogenToken.other_name: (AutogenState.need_semi, None),
 | |
|                 AutogenToken.string: (AutogenState.need_semi, None),
 | |
|             },
 | |
|             AutogenState.need_semi: {
 | |
|                 AutogenToken.semicolon: (AutogenState.need_name, None),
 | |
|             },
 | |
|             AutogenState.need_name: {
 | |
|                 AutogenToken.autogen: (AutogenState.need_def, None),
 | |
|                 AutogenToken.eof: (AutogenState.done, self.do_need_name_end),
 | |
|                 AutogenToken.var_name: (
 | |
|                     AutogenState.have_name, self.do_need_name_var_name),
 | |
|                 AutogenToken.rbrace: (
 | |
|                     AutogenState.have_value, self.do_end_block),
 | |
|             },
 | |
|             AutogenState.have_name: {
 | |
|                 AutogenToken.semicolon: (
 | |
|                     AutogenState.need_name, self.do_empty_val),
 | |
|                 AutogenToken.equals: (AutogenState.need_value, None),
 | |
|                 AutogenToken.lbracket: (AutogenState.need_idx, None),
 | |
|             },
 | |
|             AutogenState.need_value: {
 | |
|                 AutogenToken.var_name: (
 | |
|                     AutogenState.have_value, self.do_str_value),
 | |
|                 AutogenToken.other_name: (
 | |
|                     AutogenState.have_value, self.do_str_value),
 | |
|                 AutogenToken.string: (
 | |
|                     AutogenState.have_value, self.do_str_value),
 | |
|                 AutogenToken.number: (
 | |
|                     AutogenState.have_value, self.do_str_value),
 | |
|                 AutogenToken.lbrace: (
 | |
|                     AutogenState.need_name, self.do_start_block),
 | |
|             },
 | |
|             AutogenState.need_idx: {
 | |
|                 AutogenToken.var_name: (
 | |
|                     AutogenState.need_rbracket, self.do_indexed_name),
 | |
|                 AutogenToken.number: (
 | |
|                     AutogenState.need_rbracket, self.do_indexed_name),
 | |
|             },
 | |
|             AutogenState.need_rbracket: {
 | |
|                 AutogenToken.rbracket: (AutogenState.indx_name, None),
 | |
|             },
 | |
|             AutogenState.indx_name: {
 | |
|                 AutogenToken.semicolon: (
 | |
|                     AutogenState.need_name, self.do_empty_val),
 | |
|                 AutogenToken.equals: (AutogenState.need_value, None),
 | |
|             },
 | |
|             AutogenState.have_value: {
 | |
|                 AutogenToken.semicolon: (AutogenState.need_name, None),
 | |
|                 AutogenToken.comma: (AutogenState.need_value, None),
 | |
|             },
 | |
|         }
 | |
| 
 | |
|         for code, token in self.read_tokens(f):
 | |
|             if code in transitions[state]:
 | |
|                 state, handler = transitions[state][code]
 | |
|                 if handler is not None:
 | |
|                     handler(token)
 | |
|             else:
 | |
|                 self.error(
 | |
|                     "Parse error in state %s: unexpected token '%s'" % (
 | |
|                         state, token))
 | |
|             if state == AutogenState.done:
 | |
|                 break
 | |
| 
 | |
|     def read_definitions(self, path):
 | |
|         self.cur_file = path
 | |
|         with open(path) as f:
 | |
|             self.read_definitions_file(f)
 | |
| 
 | |
| defparser = AutogenParser()
 | |
| 
 | |
| #
 | |
| # Output
 | |
| #
 | |
| 
 | |
| outputs = {}
 | |
| 
 | |
| def output(s, section=''):
 | |
|     if s == "":
 | |
|         return
 | |
|     outputs.setdefault(section, [])
 | |
|     outputs[section].append(s)
 | |
| 
 | |
| def write_output(section=''):
 | |
|     for s in outputs.get(section, []):
 | |
|         print(s, end='')
 | |
| 
 | |
| #
 | |
| # Global variables
 | |
| #
 | |
| 
 | |
| def gvar_add(var, value):
 | |
|     output(var + " += " + value + "\n")
 | |
| 
 | |
| #
 | |
| # Per PROGRAM/SCRIPT variables 
 | |
| #
 | |
| 
 | |
| seen_vars = set()
 | |
| 
 | |
| def vars_init(defn, *var_list):
 | |
|     name = defn['name']
 | |
| 
 | |
|     if name not in seen_target and name not in seen_vars:
 | |
|         for var in var_list:
 | |
|             output(var + "  = \n", section='decl')
 | |
|         seen_vars.add(name)
 | |
| 
 | |
| def var_set(var, value):
 | |
|     output(var + "  = " + value + "\n")
 | |
| 
 | |
| def var_add(var, value):
 | |
|     output(var + " += " + value + "\n")
 | |
| 
 | |
| #
 | |
| # Variable names and rules
 | |
| #
 | |
| 
 | |
| canonical_name_re = re.compile(r'[^0-9A-Za-z@_]')
 | |
| canonical_name_suffix = ""
 | |
| 
 | |
| def set_canonical_name_suffix(suffix):
 | |
|     global canonical_name_suffix
 | |
|     canonical_name_suffix = suffix
 | |
| 
 | |
| def cname(defn):
 | |
|     return canonical_name_re.sub('_', defn['name'] + canonical_name_suffix)
 | |
| 
 | |
| def rule(target, source, cmd):
 | |
|     if cmd[0] == "\n":
 | |
|         output("\n" + target + ": " + source + cmd.replace("\n", "\n\t") + "\n")
 | |
|     else:
 | |
|         output("\n" + target + ": " + source + "\n\t" + cmd.replace("\n", "\n\t") + "\n")
 | |
| 
 | |
| #
 | |
| # Handle keys with platform names as values, for example:
 | |
| #
 | |
| # kernel = {
 | |
| #   nostrip = emu;
 | |
| #   ...
 | |
| # }
 | |
| #
 | |
| def platform_tagged(defn, platform, tag):
 | |
|     for value in defn.find_all(tag):
 | |
|         for group in RMAP[platform]:
 | |
|             if value == group:
 | |
|                 return True
 | |
|     return False
 | |
| 
 | |
| def if_platform_tagged(defn, platform, tag, snippet_if, snippet_else=None):
 | |
|     if platform_tagged(defn, platform, tag):
 | |
|         return snippet_if
 | |
|     elif snippet_else is not None:
 | |
|         return snippet_else
 | |
| 
 | |
| #
 | |
| # Handle tagged values
 | |
| #
 | |
| # module = {
 | |
| #   extra_dist = ...
 | |
| #   extra_dist = ...
 | |
| #   ...
 | |
| # };
 | |
| #
 | |
| def foreach_value(defn, tag, closure):
 | |
|     r = []
 | |
|     for value in defn.find_all(tag):
 | |
|         r.append(closure(value))
 | |
|     return ''.join(r)
 | |
| 
 | |
| #
 | |
| # Handle best matched values for a platform, for example:
 | |
| #
 | |
| # module = {
 | |
| #   cflags = '-Wall';
 | |
| #   emu_cflags = '-Wall -DGRUB_EMU=1';
 | |
| #   ...
 | |
| # }
 | |
| #
 | |
| def foreach_platform_specific_value(defn, platform, suffix, nonetag, closure):
 | |
|     r = []
 | |
|     for group in RMAP[platform]:
 | |
|         values = list(defn.find_all(group + suffix))
 | |
|         if values:
 | |
|             for value in values:
 | |
|                 r.append(closure(value))
 | |
|             break
 | |
|     else:
 | |
|         for value in defn.find_all(nonetag):
 | |
|             r.append(closure(value))
 | |
|     return ''.join(r)
 | |
| 
 | |
| #
 | |
| # Handle values from sum of all groups for a platform, for example:
 | |
| #
 | |
| # module = {
 | |
| #   common = kern/misc.c;
 | |
| #   emu = kern/emu/misc.c;
 | |
| #   ...
 | |
| # }
 | |
| #
 | |
| def foreach_platform_value(defn, platform, suffix, closure):
 | |
|     r = []
 | |
|     for group in RMAP[platform]:
 | |
|         for value in defn.find_all(group + suffix):
 | |
|             r.append(closure(value))
 | |
|     return ''.join(r)
 | |
| 
 | |
| def platform_conditional(platform, closure):
 | |
|     output("\nif COND_" + platform + "\n")
 | |
|     closure(platform)
 | |
|     output("endif\n")
 | |
| 
 | |
| #
 | |
| # Handle guarding with platform-specific "enable" keys, for example:
 | |
| #
 | |
| #  module = {
 | |
| #    name = pci;
 | |
| #    noemu = bus/pci.c;
 | |
| #    emu = bus/emu/pci.c;
 | |
| #    emu = commands/lspci.c;
 | |
| #
 | |
| #    enable = emu;
 | |
| #    enable = i386_pc;
 | |
| #    enable = x86_efi;
 | |
| #    enable = i386_ieee1275;
 | |
| #    enable = i386_coreboot;
 | |
| #  };
 | |
| #
 | |
| def foreach_enabled_platform(defn, closure):
 | |
|     if 'enable' in defn:
 | |
|         for platform in GRUB_PLATFORMS:
 | |
|             if platform_tagged(defn, platform, "enable"):
 | |
|                platform_conditional(platform, closure)
 | |
|     else:
 | |
|         for platform in GRUB_PLATFORMS:
 | |
|             platform_conditional(platform, closure)
 | |
| 
 | |
| #
 | |
| # Handle guarding with platform-specific automake conditionals, for example:
 | |
| #
 | |
| #  module = {
 | |
| #    name = usb;
 | |
| #    common = bus/usb/usb.c;
 | |
| #    noemu = bus/usb/usbtrans.c;
 | |
| #    noemu = bus/usb/usbhub.c;
 | |
| #    enable = emu;
 | |
| #    enable = i386;
 | |
| #    enable = mips_loongson;
 | |
| #    emu_condition = COND_GRUB_EMU_SDL;
 | |
| #  };
 | |
| #
 | |
| def under_platform_specific_conditionals(defn, platform, closure):
 | |
|     output(foreach_platform_specific_value(defn, platform, "_condition", "condition", lambda cond: "if " + cond + "\n"))
 | |
|     closure(defn, platform)
 | |
|     output(foreach_platform_specific_value(defn, platform, "_condition", "condition", lambda cond: "endif " + cond + "\n"))
 | |
| 
 | |
| def platform_specific_values(defn, platform, suffix, nonetag):
 | |
|     return foreach_platform_specific_value(defn, platform, suffix, nonetag,
 | |
|                                            lambda value: value + " ")
 | |
| 
 | |
| def platform_values(defn, platform, suffix):
 | |
|     return foreach_platform_value(defn, platform, suffix, lambda value: value + " ")
 | |
| 
 | |
| def extra_dist(defn):
 | |
|     return foreach_value(defn, "extra_dist", lambda value: value + " ")
 | |
| 
 | |
| def platform_sources(defn, p): return platform_values(defn, p, "")
 | |
| def platform_nodist_sources(defn, p): return platform_values(defn, p, "_nodist")
 | |
| 
 | |
| def platform_startup(defn, p): return platform_specific_values(defn, p, "_startup", "startup")
 | |
| def platform_ldadd(defn, p): return platform_specific_values(defn, p, "_ldadd", "ldadd")
 | |
| def platform_dependencies(defn, p): return platform_specific_values(defn, p, "_dependencies", "dependencies")
 | |
| def platform_cflags(defn, p): return platform_specific_values(defn, p, "_cflags", "cflags")
 | |
| def platform_ldflags(defn, p): return platform_specific_values(defn, p, "_ldflags", "ldflags")
 | |
| def platform_cppflags(defn, p): return platform_specific_values(defn, p, "_cppflags", "cppflags")
 | |
| def platform_ccasflags(defn, p): return platform_specific_values(defn, p, "_ccasflags", "ccasflags")
 | |
| def platform_stripflags(defn, p): return platform_specific_values(defn, p, "_stripflags", "stripflags")
 | |
| def platform_objcopyflags(defn, p): return platform_specific_values(defn, p, "_objcopyflags", "objcopyflags")
 | |
| 
 | |
| #
 | |
| # Emit snippet only the first time through for the current name.
 | |
| #
 | |
| seen_target = set()
 | |
| 
 | |
| def first_time(defn, snippet):
 | |
|     if defn['name'] not in seen_target:
 | |
|         return snippet
 | |
|     return ''
 | |
| 
 | |
| def is_platform_independent(defn):
 | |
|     if 'enable' in defn:
 | |
|         return False
 | |
|     for suffix in [ "", "_nodist" ]:
 | |
|         template = platform_values(defn, GRUB_PLATFORMS[0], suffix)
 | |
|         for platform in GRUB_PLATFORMS[1:]:
 | |
|             if template != platform_values(defn, platform, suffix):
 | |
|                 return False
 | |
| 
 | |
|     for suffix in [ "startup", "ldadd", "dependencies", "cflags", "ldflags", "cppflags", "ccasflags", "stripflags", "objcopyflags", "condition" ]:
 | |
|         template = platform_specific_values(defn, GRUB_PLATFORMS[0], "_" + suffix, suffix)
 | |
|         for platform in GRUB_PLATFORMS[1:]:
 | |
|             if template != platform_specific_values(defn, platform, "_" + suffix, suffix):
 | |
|                 return False
 | |
|     for tag in [ "nostrip" ]:
 | |
|         template = platform_tagged(defn, GRUB_PLATFORMS[0], tag)
 | |
|         for platform in GRUB_PLATFORMS[1:]:
 | |
|             if template != platform_tagged(defn, platform, tag):
 | |
|                 return False
 | |
| 
 | |
|     return True
 | |
| 
 | |
| def module(defn, platform):
 | |
|     name = defn['name']
 | |
|     set_canonical_name_suffix(".module")
 | |
| 
 | |
|     gvar_add("platform_PROGRAMS", name + ".module")
 | |
|     gvar_add("MODULE_FILES", name + ".module$(EXEEXT)")
 | |
| 
 | |
|     var_set(cname(defn) + "_SOURCES", platform_sources(defn, platform) + " ## platform sources")
 | |
|     var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform) + " ## platform nodist sources")
 | |
|     var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform))
 | |
|     var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_MODULE) " + platform_cflags(defn, platform))
 | |
|     var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_MODULE) " + platform_ldflags(defn, platform))
 | |
|     var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_MODULE) " + platform_cppflags(defn, platform))
 | |
|     var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_MODULE) " + platform_ccasflags(defn, platform))
 | |
|     var_set(cname(defn) + "_DEPENDENCIES", "$(TARGET_OBJ2ELF) " + platform_dependencies(defn, platform))
 | |
| 
 | |
|     gvar_add("dist_noinst_DATA", extra_dist(defn))
 | |
|     gvar_add("BUILT_SOURCES", "$(nodist_" + cname(defn) + "_SOURCES)")
 | |
|     gvar_add("CLEANFILES", "$(nodist_" + cname(defn) + "_SOURCES)")
 | |
| 
 | |
|     gvar_add("MOD_FILES", name + ".mod")
 | |
|     gvar_add("MARKER_FILES", name + ".marker")
 | |
|     gvar_add("CLEANFILES", name + ".marker")
 | |
|     output("""
 | |
| """ + name + """.marker: $(""" + cname(defn) + """_SOURCES) $(nodist_""" + cname(defn) + """_SOURCES)
 | |
| 	$(TARGET_CPP) -DGRUB_LST_GENERATOR $(CPPFLAGS_MARKER) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(""" + cname(defn) + """_CPPFLAGS) $(CPPFLAGS) $^ > $@.new || (rm -f $@; exit 1)
 | |
| 	grep 'MARKER' $@.new > $@; rm -f $@.new
 | |
| """)
 | |
| 
 | |
| def kernel(defn, platform):
 | |
|     name = defn['name']
 | |
|     set_canonical_name_suffix(".exec")
 | |
|     gvar_add("platform_PROGRAMS", name + ".exec")
 | |
|     var_set(cname(defn) + "_SOURCES", platform_startup(defn, platform))
 | |
|     var_add(cname(defn) + "_SOURCES", platform_sources(defn, platform))
 | |
|     var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform) + " ## platform nodist sources")
 | |
|     var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform))
 | |
|     var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_KERNEL) " + platform_cflags(defn, platform))
 | |
|     var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_KERNEL) " + platform_ldflags(defn, platform))
 | |
|     var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_KERNEL) " + platform_cppflags(defn, platform))
 | |
|     var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_KERNEL) " + platform_ccasflags(defn, platform))
 | |
|     var_set(cname(defn) + "_STRIPFLAGS", "$(AM_STRIPFLAGS) $(STRIPFLAGS_KERNEL) " + platform_stripflags(defn, platform))
 | |
|     var_set(cname(defn) + "_DEPENDENCIES", "$(TARGET_OBJ2ELF)")
 | |
| 
 | |
|     gvar_add("dist_noinst_DATA", extra_dist(defn))
 | |
|     gvar_add("BUILT_SOURCES", "$(nodist_" + cname(defn) + "_SOURCES)")
 | |
|     gvar_add("CLEANFILES", "$(nodist_" + cname(defn) + "_SOURCES)")
 | |
| 
 | |
|     gvar_add("platform_DATA", name + ".img")
 | |
|     gvar_add("CLEANFILES", name + ".img")
 | |
|     rule(name + ".img", name + ".exec$(EXEEXT)",
 | |
|          if_platform_tagged(defn, platform, "nostrip",
 | |
| """if test x$(TARGET_APPLE_LINKER) = x1; then \
 | |
|      $(TARGET_OBJCONV) -f$(TARGET_MODULE_FORMAT) -nr:_grub_mod_init:grub_mod_init -nr:_grub_mod_fini:grub_mod_fini -ed2022 -wd1106 -nu -nd $< $@; \
 | |
|    elif test ! -z '$(TARGET_OBJ2ELF)'; then \
 | |
|      $(TARGET_OBJ2ELF) $< $@ || (rm -f $@; exit 1); \
 | |
|    else cp $< $@; fi""",
 | |
| """if test x$(TARGET_APPLE_LINKER) = x1; then \
 | |
|   $(TARGET_STRIP) -S -x $(""" + cname(defn) + """) -o $@.bin $<; \
 | |
|   $(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 $@; \
 | |
|   rm -f $@.bin; \
 | |
|    elif test ! -z '$(TARGET_OBJ2ELF)'; then \
 | |
|      """  + "$(TARGET_STRIP) $(" + cname(defn) + "_STRIPFLAGS) -o $@.bin $< && \
 | |
|      $(TARGET_OBJ2ELF) $@.bin $@ || (rm -f $@; rm -f $@.bin; exit 1); \
 | |
|      rm -f $@.bin; \
 | |
| else """  + "$(TARGET_STRIP) $(" + cname(defn) + "_STRIPFLAGS) -o $@ $<; \
 | |
| fi"""))
 | |
| 
 | |
| def image(defn, platform):
 | |
|     name = defn['name']
 | |
|     set_canonical_name_suffix(".image")
 | |
|     gvar_add("platform_PROGRAMS", name + ".image")
 | |
|     var_set(cname(defn) + "_SOURCES", platform_sources(defn, platform))
 | |
|     var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform) + "## platform nodist sources")
 | |
|     var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform))
 | |
|     var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_IMAGE) " + platform_cflags(defn, platform))
 | |
|     var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_IMAGE) " + platform_ldflags(defn, platform))
 | |
|     var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_IMAGE) " + platform_cppflags(defn, platform))
 | |
|     var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_IMAGE) " + platform_ccasflags(defn, platform))
 | |
|     var_set(cname(defn) + "_OBJCOPYFLAGS", "$(OBJCOPYFLAGS_IMAGE) " + platform_objcopyflags(defn, platform))
 | |
|     # var_set(cname(defn) + "_DEPENDENCIES", platform_dependencies(defn, platform) + " " + platform_ldadd(defn, platform))
 | |
| 
 | |
|     gvar_add("dist_noinst_DATA", extra_dist(defn))
 | |
|     gvar_add("BUILT_SOURCES", "$(nodist_" + cname(defn) + "_SOURCES)")
 | |
|     gvar_add("CLEANFILES", "$(nodist_" + cname(defn) + "_SOURCES)")
 | |
| 
 | |
|     gvar_add("platform_DATA", name + ".img")
 | |
|     gvar_add("CLEANFILES", name + ".img")
 | |
|     rule(name + ".img", name + ".image$(EXEEXT)", """
 | |
| if test x$(TARGET_APPLE_LINKER) = x1; then \
 | |
|   $(MACHO2IMG) $< $@; \
 | |
| else \
 | |
|   $(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 .ARM.exidx $< $@; \
 | |
| fi
 | |
| """)
 | |
| 
 | |
| def library(defn, platform):
 | |
|     name = defn['name']
 | |
|     set_canonical_name_suffix("")
 | |
| 
 | |
|     vars_init(defn,
 | |
|               cname(defn) + "_SOURCES",
 | |
|               "nodist_" + cname(defn) + "_SOURCES",
 | |
|               cname(defn) + "_CFLAGS",
 | |
|               cname(defn) + "_CPPFLAGS",
 | |
|               cname(defn) + "_CCASFLAGS")
 | |
|     #         cname(defn) + "_DEPENDENCIES")
 | |
| 
 | |
|     if name not in seen_target:
 | |
|         gvar_add("noinst_LIBRARIES", name)
 | |
|     var_add(cname(defn) + "_SOURCES", platform_sources(defn, platform))
 | |
|     var_add("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform))
 | |
|     var_add(cname(defn) + "_CFLAGS", first_time(defn, "$(AM_CFLAGS) $(CFLAGS_LIBRARY) ") + platform_cflags(defn, platform))
 | |
|     var_add(cname(defn) + "_CPPFLAGS", first_time(defn, "$(AM_CPPFLAGS) $(CPPFLAGS_LIBRARY) ") + platform_cppflags(defn, platform))
 | |
|     var_add(cname(defn) + "_CCASFLAGS", first_time(defn, "$(AM_CCASFLAGS) $(CCASFLAGS_LIBRARY) ") + platform_ccasflags(defn, platform))
 | |
|     # var_add(cname(defn) + "_DEPENDENCIES", platform_dependencies(defn, platform) + " " + platform_ldadd(defn, platform))
 | |
| 
 | |
|     gvar_add("dist_noinst_DATA", extra_dist(defn))
 | |
|     if name not in seen_target:
 | |
|         gvar_add("BUILT_SOURCES", "$(nodist_" + cname(defn) + "_SOURCES)")
 | |
|         gvar_add("CLEANFILES", "$(nodist_" + cname(defn) + "_SOURCES)")
 | |
| 
 | |
| def installdir(defn, default="bin"):
 | |
|     return defn.get('installdir', default)
 | |
| 
 | |
| def manpage(defn, adddeps):
 | |
|     name = defn['name']
 | |
|     mansection = defn['mansection']
 | |
| 
 | |
|     output("if COND_MAN_PAGES\n")
 | |
|     gvar_add("man_MANS", name + "." + mansection)
 | |
|     rule(name + "." + mansection, name + " " + adddeps, """
 | |
| chmod a+x """ + name + """
 | |
| PATH=$(builddir):$$PATH pkgdatadir=$(builddir) $(HELP2MAN) --section=""" + mansection + """ -i $(top_srcdir)/docs/man/""" + name + """.h2m -o $@ """ + name + """
 | |
| """)
 | |
|     gvar_add("CLEANFILES", name + "." + mansection)
 | |
|     output("endif\n")
 | |
| 
 | |
| def program(defn, platform, test=False):
 | |
|     name = defn['name']
 | |
|     set_canonical_name_suffix("")
 | |
| 
 | |
|     if 'testcase' in defn:
 | |
|         gvar_add("check_PROGRAMS", name)
 | |
|         gvar_add("TESTS", name)
 | |
|     else:
 | |
|         var_add(installdir(defn) + "_PROGRAMS", name)
 | |
|         if 'mansection' in defn:
 | |
|             manpage(defn, "")
 | |
| 
 | |
|     var_set(cname(defn) + "_SOURCES", platform_sources(defn, platform))
 | |
|     var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform))
 | |
|     var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform))
 | |
|     var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_PROGRAM) " + platform_cflags(defn, platform))
 | |
|     var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_PROGRAM) " + platform_ldflags(defn, platform))
 | |
|     var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_PROGRAM) " + platform_cppflags(defn, platform))
 | |
|     var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_PROGRAM) " + platform_ccasflags(defn, platform))
 | |
|     # var_set(cname(defn) + "_DEPENDENCIES", platform_dependencies(defn, platform) + " " + platform_ldadd(defn, platform))
 | |
| 
 | |
|     gvar_add("dist_noinst_DATA", extra_dist(defn))
 | |
|     gvar_add("BUILT_SOURCES", "$(nodist_" + cname(defn) + "_SOURCES)")
 | |
|     gvar_add("CLEANFILES", "$(nodist_" + cname(defn) + "_SOURCES)")
 | |
| 
 | |
| def data(defn, platform):
 | |
|     var_add("dist_" + installdir(defn) + "_DATA", platform_sources(defn, platform))
 | |
|     gvar_add("dist_noinst_DATA", extra_dist(defn))
 | |
| 
 | |
| def transform_data(defn, platform):
 | |
|     name = defn['name']
 | |
| 
 | |
|     var_add(installdir(defn) + "_DATA", name)
 | |
| 
 | |
|     rule(name, "$(top_builddir)/config.status " + platform_sources(defn, platform) + platform_dependencies(defn, platform), """
 | |
| (for x in """ + platform_sources(defn, platform) + """; do cat $(srcdir)/"$$x"; done) | $(top_builddir)/config.status --file=$@:-
 | |
| chmod a+x """ + name + """
 | |
| """)
 | |
| 
 | |
|     gvar_add("CLEANFILES", name)
 | |
|     gvar_add("EXTRA_DIST", extra_dist(defn))
 | |
|     gvar_add("dist_noinst_DATA", platform_sources(defn, platform))
 | |
| 
 | |
| def script(defn, platform):
 | |
|     name = defn['name']
 | |
| 
 | |
|     if 'testcase' in defn:
 | |
|         gvar_add("check_SCRIPTS", name)
 | |
|         gvar_add ("TESTS", name)
 | |
|     else:
 | |
|         var_add(installdir(defn) + "_SCRIPTS", name)
 | |
|         if 'mansection' in defn:
 | |
|             manpage(defn, "grub-mkconfig_lib")
 | |
| 
 | |
|     rule(name, "$(top_builddir)/config.status " + platform_sources(defn, platform) + platform_dependencies(defn, platform), """
 | |
| (for x in """ + platform_sources(defn, platform) + """; do cat $(srcdir)/"$$x"; done) | $(top_builddir)/config.status --file=$@:-
 | |
| chmod a+x """ + name + """
 | |
| """)
 | |
| 
 | |
|     gvar_add("CLEANFILES", name)
 | |
|     gvar_add("EXTRA_DIST", extra_dist(defn))
 | |
|     gvar_add("dist_noinst_DATA", platform_sources(defn, platform))
 | |
| 
 | |
| def rules(target, closure):
 | |
|     seen_target.clear()
 | |
|     seen_vars.clear()
 | |
| 
 | |
|     for defn in defparser.definitions.find_all(target):
 | |
|         if is_platform_independent(defn):
 | |
|             under_platform_specific_conditionals(defn, GRUB_PLATFORMS[0], closure)
 | |
|         else:
 | |
|             foreach_enabled_platform(
 | |
|                 defn,
 | |
|                 lambda p: under_platform_specific_conditionals(defn, p, closure))
 | |
|         # Remember that we've seen this target.
 | |
|         seen_target.add(defn['name'])
 | |
| 
 | |
| parser = OptionParser(usage="%prog DEFINITION-FILES")
 | |
| _, args = parser.parse_args()
 | |
| 
 | |
| for arg in args:
 | |
|     defparser.read_definitions(arg)
 | |
| 
 | |
| rules("module", module)
 | |
| rules("kernel", kernel)
 | |
| rules("image", image)
 | |
| rules("library", library)
 | |
| rules("program", program)
 | |
| rules("script", script)
 | |
| rules("data", data)
 | |
| rules("transform_data", transform_data)
 | |
| 
 | |
| write_output(section='decl')
 | |
| write_output()
 | 
