RVCT is obsolete and no longer used. Remove support for it. Signed-off-by: Rebecca Cran <quic_rcran@quicinc.com> Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
		
			
				
	
	
		
			651 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			651 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| ## @file
 | |
| # The engine for building files
 | |
| #
 | |
| # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
| # SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| #
 | |
| 
 | |
| ##
 | |
| # Import Modules
 | |
| #
 | |
| from __future__ import print_function
 | |
| import Common.LongFilePathOs as os
 | |
| import re
 | |
| import copy
 | |
| import string
 | |
| from Common.LongFilePathSupport import OpenLongFilePath as open
 | |
| 
 | |
| from Common.GlobalData import *
 | |
| from Common.BuildToolError import *
 | |
| from Common.Misc import tdict, PathClass
 | |
| from Common.StringUtils import NormPath
 | |
| from Common.DataType import *
 | |
| from Common.TargetTxtClassObject import TargetTxtDict
 | |
| gDefaultBuildRuleFile = 'build_rule.txt'
 | |
| AutoGenReqBuildRuleVerNum = '0.1'
 | |
| 
 | |
| import Common.EdkLogger as EdkLogger
 | |
| 
 | |
| ## Convert file type to file list macro name
 | |
| #
 | |
| #   @param      FileType    The name of file type
 | |
| #
 | |
| #   @retval     string      The name of macro
 | |
| #
 | |
| def FileListMacro(FileType):
 | |
|     return "%sS" % FileType.replace("-", "_").upper()
 | |
| 
 | |
| ## Convert file type to list file macro name
 | |
| #
 | |
| #   @param      FileType    The name of file type
 | |
| #
 | |
| #   @retval     string      The name of macro
 | |
| #
 | |
| def ListFileMacro(FileType):
 | |
|     return "%s_LIST" % FileListMacro(FileType)
 | |
| 
 | |
| class TargetDescBlock(object):
 | |
|     def __init__(self, Inputs, Outputs, Commands, Dependencies):
 | |
|         self.InitWorker(Inputs, Outputs, Commands, Dependencies)
 | |
| 
 | |
|     def InitWorker(self, Inputs, Outputs, Commands, Dependencies):
 | |
|         self.Inputs = Inputs
 | |
|         self.Outputs = Outputs
 | |
|         self.Commands = Commands
 | |
|         self.Dependencies = Dependencies
 | |
|         if self.Outputs:
 | |
|             self.Target = self.Outputs[0]
 | |
|         else:
 | |
|             self.Target = None
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.Target.Path
 | |
| 
 | |
|     def __hash__(self):
 | |
|         return hash(self.Target.Path)
 | |
| 
 | |
|     def __eq__(self, Other):
 | |
|         if isinstance(Other, type(self)):
 | |
|             return Other.Target.Path == self.Target.Path
 | |
|         else:
 | |
|             return str(Other) == self.Target.Path
 | |
| 
 | |
|     def AddInput(self, Input):
 | |
|         if Input not in self.Inputs:
 | |
|             self.Inputs.append(Input)
 | |
| 
 | |
|     def IsMultipleInput(self):
 | |
|         return len(self.Inputs) > 1
 | |
| 
 | |
| ## Class for one build rule
 | |
| #
 | |
| # This represents a build rule which can give out corresponding command list for
 | |
| # building the given source file(s). The result can be used for generating the
 | |
| # target for makefile.
 | |
| #
 | |
| class FileBuildRule:
 | |
|     INC_LIST_MACRO = "INC_LIST"
 | |
|     INC_MACRO = "INC"
 | |
| 
 | |
|     ## constructor
 | |
|     #
 | |
|     #   @param  Input       The dictionary representing input file(s) for a rule
 | |
|     #   @param  Output      The list representing output file(s) for a rule
 | |
|     #   @param  Command     The list containing commands to generate the output from input
 | |
|     #
 | |
|     def __init__(self, Type, Input, Output, Command, ExtraDependency=None):
 | |
|         # The Input should not be empty
 | |
|         if not Input:
 | |
|             Input = []
 | |
|         if not Output:
 | |
|             Output = []
 | |
|         if not Command:
 | |
|             Command = []
 | |
| 
 | |
|         self.FileListMacro = FileListMacro(Type)
 | |
|         self.ListFileMacro = ListFileMacro(Type)
 | |
|         self.IncListFileMacro = self.INC_LIST_MACRO
 | |
| 
 | |
|         self.SourceFileType = Type
 | |
|         # source files listed not in TAB_STAR or "?" pattern format
 | |
|         if not ExtraDependency:
 | |
|             self.ExtraSourceFileList = []
 | |
|         else:
 | |
|             self.ExtraSourceFileList = ExtraDependency
 | |
| 
 | |
|         #
 | |
|         # Search macros used in command lines for <FILE_TYPE>_LIST and INC_LIST.
 | |
|         # If found, generate a file to keep the input files used to get over the
 | |
|         # limitation of command line length
 | |
|         #
 | |
|         self.MacroList = []
 | |
|         self.CommandList = []
 | |
|         for CmdLine in Command:
 | |
|             self.MacroList.extend(gMacroRefPattern.findall(CmdLine))
 | |
|             # replace path separator with native one
 | |
|             self.CommandList.append(CmdLine)
 | |
| 
 | |
|         # Indicate what should be generated
 | |
|         if self.FileListMacro in self.MacroList:
 | |
|             self.GenFileListMacro = True
 | |
|         else:
 | |
|             self.GenFileListMacro = False
 | |
| 
 | |
|         if self.ListFileMacro in self.MacroList:
 | |
|             self.GenListFile = True
 | |
|             self.GenFileListMacro = True
 | |
|         else:
 | |
|             self.GenListFile = False
 | |
| 
 | |
|         if self.INC_LIST_MACRO in self.MacroList:
 | |
|             self.GenIncListFile = True
 | |
|         else:
 | |
|             self.GenIncListFile = False
 | |
| 
 | |
|         # Check input files
 | |
|         self.IsMultipleInput = False
 | |
|         self.SourceFileExtList = set()
 | |
|         for File in Input:
 | |
|             Base, Ext = os.path.splitext(File)
 | |
|             if Base.find(TAB_STAR) >= 0:
 | |
|                 # There's TAB_STAR in the file name
 | |
|                 self.IsMultipleInput = True
 | |
|                 self.GenFileListMacro = True
 | |
|             elif Base.find("?") < 0:
 | |
|                 # There's no TAB_STAR and "?" in file name
 | |
|                 self.ExtraSourceFileList.append(File)
 | |
|                 continue
 | |
|             self.SourceFileExtList.add(Ext)
 | |
| 
 | |
|         # Check output files
 | |
|         self.DestFileList = []
 | |
|         for File in Output:
 | |
|             self.DestFileList.append(File)
 | |
| 
 | |
|         # All build targets generated by this rule for a module
 | |
|         self.BuildTargets = {}
 | |
| 
 | |
|     ## str() function support
 | |
|     #
 | |
|     #   @retval     string
 | |
|     #
 | |
|     def __str__(self):
 | |
|         SourceString = ""
 | |
|         SourceString += " %s %s %s" % (self.SourceFileType, " ".join(self.SourceFileExtList), self.ExtraSourceFileList)
 | |
|         DestString = ", ".join([str(i) for i in self.DestFileList])
 | |
|         CommandString = "\n\t".join(self.CommandList)
 | |
|         return "%s : %s\n\t%s" % (DestString, SourceString, CommandString)
 | |
| 
 | |
|     def Instantiate(self, Macros = None):
 | |
|         if Macros is None:
 | |
|             Macros = {}
 | |
|         NewRuleObject = copy.copy(self)
 | |
|         NewRuleObject.BuildTargets = {}
 | |
|         NewRuleObject.DestFileList = []
 | |
|         for File in self.DestFileList:
 | |
|             NewRuleObject.DestFileList.append(PathClass(NormPath(File, Macros)))
 | |
|         return NewRuleObject
 | |
| 
 | |
|     ## Apply the rule to given source file(s)
 | |
|     #
 | |
|     #   @param  SourceFile      One file or a list of files to be built
 | |
|     #   @param  RelativeToDir   The relative path of the source file
 | |
|     #   @param  PathSeparator   Path separator
 | |
|     #
 | |
|     #   @retval     tuple       (Source file in full path, List of individual sourcefiles, Destination file, List of build commands)
 | |
|     #
 | |
|     def Apply(self, SourceFile, BuildRuleOrder=None):
 | |
|         if not self.CommandList or not self.DestFileList:
 | |
|             return None
 | |
| 
 | |
|         # source file
 | |
|         if self.IsMultipleInput:
 | |
|             SrcFileName = ""
 | |
|             SrcFileBase = ""
 | |
|             SrcFileExt = ""
 | |
|             SrcFileDir = ""
 | |
|             SrcPath = ""
 | |
|             # SourceFile must be a list
 | |
|             SrcFile = "$(%s)" % self.FileListMacro
 | |
|         else:
 | |
|             SrcFileName, SrcFileBase, SrcFileExt = SourceFile.Name, SourceFile.BaseName, SourceFile.Ext
 | |
|             if SourceFile.Root:
 | |
|                 SrcFileDir = SourceFile.SubDir
 | |
|                 if SrcFileDir == "":
 | |
|                     SrcFileDir = "."
 | |
|             else:
 | |
|                 SrcFileDir = "."
 | |
|             SrcFile = SourceFile.Path
 | |
|             SrcPath = SourceFile.Dir
 | |
| 
 | |
|         # destination file (the first one)
 | |
|         if self.DestFileList:
 | |
|             DestFile = self.DestFileList[0].Path
 | |
|             DestPath = self.DestFileList[0].Dir
 | |
|             DestFileName = self.DestFileList[0].Name
 | |
|             DestFileBase, DestFileExt = self.DestFileList[0].BaseName, self.DestFileList[0].Ext
 | |
|         else:
 | |
|             DestFile = ""
 | |
|             DestPath = ""
 | |
|             DestFileName = ""
 | |
|             DestFileBase = ""
 | |
|             DestFileExt = ""
 | |
| 
 | |
|         BuildRulePlaceholderDict = {
 | |
|             # source file
 | |
|             "src"       :   SrcFile,
 | |
|             "s_path"    :   SrcPath,
 | |
|             "s_dir"     :   SrcFileDir,
 | |
|             "s_name"    :   SrcFileName,
 | |
|             "s_base"    :   SrcFileBase,
 | |
|             "s_ext"     :   SrcFileExt,
 | |
|             # destination file
 | |
|             "dst"       :   DestFile,
 | |
|             "d_path"    :   DestPath,
 | |
|             "d_name"    :   DestFileName,
 | |
|             "d_base"    :   DestFileBase,
 | |
|             "d_ext"     :   DestFileExt,
 | |
|         }
 | |
| 
 | |
|         DstFile = []
 | |
|         for File in self.DestFileList:
 | |
|             File = string.Template(str(File)).safe_substitute(BuildRulePlaceholderDict)
 | |
|             File = string.Template(str(File)).safe_substitute(BuildRulePlaceholderDict)
 | |
|             DstFile.append(PathClass(File, IsBinary=True))
 | |
| 
 | |
|         if DstFile[0] in self.BuildTargets:
 | |
|             TargetDesc = self.BuildTargets[DstFile[0]]
 | |
|             if BuildRuleOrder and SourceFile.Ext in BuildRuleOrder:
 | |
|                 Index = BuildRuleOrder.index(SourceFile.Ext)
 | |
|                 for Input in TargetDesc.Inputs:
 | |
|                     if Input.Ext not in BuildRuleOrder or BuildRuleOrder.index(Input.Ext) > Index:
 | |
|                         #
 | |
|                         # Command line should be regenerated since some macros are different
 | |
|                         #
 | |
|                         CommandList = self._BuildCommand(BuildRulePlaceholderDict)
 | |
|                         TargetDesc.InitWorker([SourceFile], DstFile, CommandList, self.ExtraSourceFileList)
 | |
|                         break
 | |
|             else:
 | |
|                 TargetDesc.AddInput(SourceFile)
 | |
|         else:
 | |
|             CommandList = self._BuildCommand(BuildRulePlaceholderDict)
 | |
|             TargetDesc = TargetDescBlock([SourceFile], DstFile, CommandList, self.ExtraSourceFileList)
 | |
|             TargetDesc.ListFileMacro = self.ListFileMacro
 | |
|             TargetDesc.FileListMacro = self.FileListMacro
 | |
|             TargetDesc.IncListFileMacro = self.IncListFileMacro
 | |
|             TargetDesc.GenFileListMacro = self.GenFileListMacro
 | |
|             TargetDesc.GenListFile = self.GenListFile
 | |
|             TargetDesc.GenIncListFile = self.GenIncListFile
 | |
|             self.BuildTargets[DstFile[0]] = TargetDesc
 | |
|         return TargetDesc
 | |
| 
 | |
|     def _BuildCommand(self, Macros):
 | |
|         CommandList = []
 | |
|         for CommandString in self.CommandList:
 | |
|             CommandString = string.Template(CommandString).safe_substitute(Macros)
 | |
|             CommandString = string.Template(CommandString).safe_substitute(Macros)
 | |
|             CommandList.append(CommandString)
 | |
|         return CommandList
 | |
| 
 | |
| ## Class for build rules
 | |
| #
 | |
| # BuildRule class parses rules defined in a file or passed by caller, and converts
 | |
| # the rule into FileBuildRule object.
 | |
| #
 | |
| class BuildRule:
 | |
|     _SectionHeader = "SECTIONHEADER"
 | |
|     _Section = "SECTION"
 | |
|     _SubSectionHeader = "SUBSECTIONHEADER"
 | |
|     _SubSection = "SUBSECTION"
 | |
|     _InputFile = "INPUTFILE"
 | |
|     _OutputFile = "OUTPUTFILE"
 | |
|     _ExtraDependency = "EXTRADEPENDENCY"
 | |
|     _Command = "COMMAND"
 | |
|     _UnknownSection = "UNKNOWNSECTION"
 | |
| 
 | |
|     _SubSectionList = [_InputFile, _OutputFile, _Command]
 | |
| 
 | |
|     _PATH_SEP = "(+)"
 | |
|     _FileTypePattern = re.compile("^[_a-zA-Z][_\-0-9a-zA-Z]*$")
 | |
|     _BinaryFileRule = FileBuildRule(TAB_DEFAULT_BINARY_FILE, [], [os.path.join("$(OUTPUT_DIR)", "${s_name}")],
 | |
|                                     ["$(CP) ${src} ${dst}"], [])
 | |
| 
 | |
|     ## Constructor
 | |
|     #
 | |
|     #   @param  File                The file containing build rules in a well defined format
 | |
|     #   @param  Content             The string list of build rules in a well defined format
 | |
|     #   @param  LineIndex           The line number from which the parsing will begin
 | |
|     #   @param  SupportedFamily     The list of supported tool chain families
 | |
|     #
 | |
|     def __init__(self, File=None, Content=None, LineIndex=0, SupportedFamily=[TAB_COMPILER_MSFT, "INTEL", "GCC"]):
 | |
|         self.RuleFile = File
 | |
|         # Read build rules from file if it's not none
 | |
|         if File is not None:
 | |
|             try:
 | |
|                 self.RuleContent = open(File, 'r').readlines()
 | |
|             except:
 | |
|                 EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=File)
 | |
|         elif Content is not None:
 | |
|             self.RuleContent = Content
 | |
|         else:
 | |
|             EdkLogger.error("build", PARAMETER_MISSING, ExtraData="No rule file or string given")
 | |
| 
 | |
|         self.SupportedToolChainFamilyList = SupportedFamily
 | |
|         self.RuleDatabase = tdict(True, 4)  # {FileExt, ModuleType, Arch, Family : FileBuildRule object}
 | |
|         self.Ext2FileType = {}  # {ext : file-type}
 | |
|         self.FileTypeList = set()
 | |
| 
 | |
|         self._LineIndex = LineIndex
 | |
|         self._State = ""
 | |
|         self._RuleInfo = tdict(True, 2)     # {toolchain family : {"InputFile": {}, "OutputFile" : [], "Command" : []}}
 | |
|         self._FileType = ''
 | |
|         self._BuildTypeList = set()
 | |
|         self._ArchList = set()
 | |
|         self._FamilyList = []
 | |
|         self._TotalToolChainFamilySet = set()
 | |
|         self._RuleObjectList = [] # FileBuildRule object list
 | |
|         self._FileVersion = ""
 | |
| 
 | |
|         self.Parse()
 | |
| 
 | |
|         # some intrinsic rules
 | |
|         self.RuleDatabase[TAB_DEFAULT_BINARY_FILE, TAB_COMMON, TAB_COMMON, TAB_COMMON] = self._BinaryFileRule
 | |
|         self.FileTypeList.add(TAB_DEFAULT_BINARY_FILE)
 | |
| 
 | |
|     ## Parse the build rule strings
 | |
|     def Parse(self):
 | |
|         self._State = self._Section
 | |
|         for Index in range(self._LineIndex, len(self.RuleContent)):
 | |
|             # Clean up the line and replace path separator with native one
 | |
|             Line = self.RuleContent[Index].strip().replace(self._PATH_SEP, os.path.sep)
 | |
|             self.RuleContent[Index] = Line
 | |
| 
 | |
|             # find the build_rule_version
 | |
|             if Line and Line[0] == "#" and Line.find(TAB_BUILD_RULE_VERSION) != -1:
 | |
|                 if Line.find("=") != -1 and Line.find("=") < (len(Line) - 1) and (Line[(Line.find("=") + 1):]).split():
 | |
|                     self._FileVersion = (Line[(Line.find("=") + 1):]).split()[0]
 | |
|             # skip empty or comment line
 | |
|             if Line == "" or Line[0] == "#":
 | |
|                 continue
 | |
| 
 | |
|             # find out section header, enclosed by []
 | |
|             if Line[0] == '[' and Line[-1] == ']':
 | |
|                 # merge last section information into rule database
 | |
|                 self.EndOfSection()
 | |
|                 self._State = self._SectionHeader
 | |
|             # find out sub-section header, enclosed by <>
 | |
|             elif Line[0] == '<' and Line[-1] == '>':
 | |
|                 if self._State != self._UnknownSection:
 | |
|                     self._State = self._SubSectionHeader
 | |
| 
 | |
|             # call section handler to parse each (sub)section
 | |
|             self._StateHandler[self._State](self, Index)
 | |
|         # merge last section information into rule database
 | |
|         self.EndOfSection()
 | |
| 
 | |
|     ## Parse definitions under a section
 | |
|     #
 | |
|     #   @param  LineIndex   The line index of build rule text
 | |
|     #
 | |
|     def ParseSection(self, LineIndex):
 | |
|         pass
 | |
| 
 | |
|     ## Parse definitions under a subsection
 | |
|     #
 | |
|     #   @param  LineIndex   The line index of build rule text
 | |
|     #
 | |
|     def ParseSubSection(self, LineIndex):
 | |
|         # currently nothing here
 | |
|         pass
 | |
| 
 | |
|     ## Placeholder for not supported sections
 | |
|     #
 | |
|     #   @param  LineIndex   The line index of build rule text
 | |
|     #
 | |
|     def SkipSection(self, LineIndex):
 | |
|         pass
 | |
| 
 | |
|     ## Merge section information just got into rule database
 | |
|     def EndOfSection(self):
 | |
|         Database = self.RuleDatabase
 | |
|         # if there's specific toolchain family, 'COMMON' doesn't make sense any more
 | |
|         if len(self._TotalToolChainFamilySet) > 1 and TAB_COMMON in self._TotalToolChainFamilySet:
 | |
|             self._TotalToolChainFamilySet.remove(TAB_COMMON)
 | |
|         for Family in self._TotalToolChainFamilySet:
 | |
|             Input = self._RuleInfo[Family, self._InputFile]
 | |
|             Output = self._RuleInfo[Family, self._OutputFile]
 | |
|             Command = self._RuleInfo[Family, self._Command]
 | |
|             ExtraDependency = self._RuleInfo[Family, self._ExtraDependency]
 | |
| 
 | |
|             BuildRule = FileBuildRule(self._FileType, Input, Output, Command, ExtraDependency)
 | |
|             for BuildType in self._BuildTypeList:
 | |
|                 for Arch in self._ArchList:
 | |
|                     Database[self._FileType, BuildType, Arch, Family] = BuildRule
 | |
|                     for FileExt in BuildRule.SourceFileExtList:
 | |
|                         self.Ext2FileType[FileExt] = self._FileType
 | |
| 
 | |
|     ## Parse section header
 | |
|     #
 | |
|     #   @param  LineIndex   The line index of build rule text
 | |
|     #
 | |
|     def ParseSectionHeader(self, LineIndex):
 | |
|         self._RuleInfo = tdict(True, 2)
 | |
|         self._BuildTypeList = set()
 | |
|         self._ArchList = set()
 | |
|         self._FamilyList = []
 | |
|         self._TotalToolChainFamilySet = set()
 | |
|         FileType = ''
 | |
|         RuleNameList = self.RuleContent[LineIndex][1:-1].split(',')
 | |
|         for RuleName in RuleNameList:
 | |
|             Arch = TAB_COMMON
 | |
|             BuildType = TAB_COMMON
 | |
|             TokenList = [Token.strip().upper() for Token in RuleName.split('.')]
 | |
|             # old format: Build.File-Type
 | |
|             if TokenList[0] == "BUILD":
 | |
|                 if len(TokenList) == 1:
 | |
|                     EdkLogger.error("build", FORMAT_INVALID, "Invalid rule section",
 | |
|                                     File=self.RuleFile, Line=LineIndex + 1,
 | |
|                                     ExtraData=self.RuleContent[LineIndex])
 | |
| 
 | |
|                 FileType = TokenList[1]
 | |
|                 if FileType == '':
 | |
|                     EdkLogger.error("build", FORMAT_INVALID, "No file type given",
 | |
|                                     File=self.RuleFile, Line=LineIndex + 1,
 | |
|                                     ExtraData=self.RuleContent[LineIndex])
 | |
|                 if self._FileTypePattern.match(FileType) is None:
 | |
|                     EdkLogger.error("build", FORMAT_INVALID, File=self.RuleFile, Line=LineIndex + 1,
 | |
|                                     ExtraData="Only character, number (non-first character), '_' and '-' are allowed in file type")
 | |
|             # new format: File-Type.Build-Type.Arch
 | |
|             else:
 | |
|                 if FileType == '':
 | |
|                     FileType = TokenList[0]
 | |
|                 elif FileType != TokenList[0]:
 | |
|                     EdkLogger.error("build", FORMAT_INVALID,
 | |
|                                     "Different file types are not allowed in the same rule section",
 | |
|                                     File=self.RuleFile, Line=LineIndex + 1,
 | |
|                                     ExtraData=self.RuleContent[LineIndex])
 | |
|                 if len(TokenList) > 1:
 | |
|                     BuildType = TokenList[1]
 | |
|                 if len(TokenList) > 2:
 | |
|                     Arch = TokenList[2]
 | |
|             self._BuildTypeList.add(BuildType)
 | |
|             self._ArchList.add(Arch)
 | |
| 
 | |
|         if TAB_COMMON in self._BuildTypeList and len(self._BuildTypeList) > 1:
 | |
|             EdkLogger.error("build", FORMAT_INVALID,
 | |
|                             "Specific build types must not be mixed with common one",
 | |
|                             File=self.RuleFile, Line=LineIndex + 1,
 | |
|                             ExtraData=self.RuleContent[LineIndex])
 | |
|         if TAB_COMMON in self._ArchList and len(self._ArchList) > 1:
 | |
|             EdkLogger.error("build", FORMAT_INVALID,
 | |
|                             "Specific ARCH must not be mixed with common one",
 | |
|                             File=self.RuleFile, Line=LineIndex + 1,
 | |
|                             ExtraData=self.RuleContent[LineIndex])
 | |
| 
 | |
|         self._FileType = FileType
 | |
|         self._State = self._Section
 | |
|         self.FileTypeList.add(FileType)
 | |
| 
 | |
|     ## Parse sub-section header
 | |
|     #
 | |
|     #   @param  LineIndex   The line index of build rule text
 | |
|     #
 | |
|     def ParseSubSectionHeader(self, LineIndex):
 | |
|         SectionType = ""
 | |
|         List = self.RuleContent[LineIndex][1:-1].split(',')
 | |
|         FamilyList = []
 | |
|         for Section in List:
 | |
|             TokenList = Section.split('.')
 | |
|             Type = TokenList[0].strip().upper()
 | |
| 
 | |
|             if SectionType == "":
 | |
|                 SectionType = Type
 | |
|             elif SectionType != Type:
 | |
|                 EdkLogger.error("build", FORMAT_INVALID,
 | |
|                                 "Two different section types are not allowed in the same sub-section",
 | |
|                                 File=self.RuleFile, Line=LineIndex + 1,
 | |
|                                 ExtraData=self.RuleContent[LineIndex])
 | |
| 
 | |
|             if len(TokenList) > 1:
 | |
|                 Family = TokenList[1].strip().upper()
 | |
|             else:
 | |
|                 Family = TAB_COMMON
 | |
| 
 | |
|             if Family not in FamilyList:
 | |
|                 FamilyList.append(Family)
 | |
| 
 | |
|         self._FamilyList = FamilyList
 | |
|         self._TotalToolChainFamilySet.update(FamilyList)
 | |
|         self._State = SectionType.upper()
 | |
|         if TAB_COMMON in FamilyList and len(FamilyList) > 1:
 | |
|             EdkLogger.error("build", FORMAT_INVALID,
 | |
|                             "Specific tool chain family should not be mixed with general one",
 | |
|                             File=self.RuleFile, Line=LineIndex + 1,
 | |
|                             ExtraData=self.RuleContent[LineIndex])
 | |
|         if self._State not in self._StateHandler:
 | |
|             EdkLogger.error("build", FORMAT_INVALID, File=self.RuleFile, Line=LineIndex + 1,
 | |
|                             ExtraData="Unknown subsection: %s" % self.RuleContent[LineIndex])
 | |
|     ## Parse <InputFile> sub-section
 | |
|     #
 | |
|     #   @param  LineIndex   The line index of build rule text
 | |
|     #
 | |
|     def ParseInputFileSubSection(self, LineIndex):
 | |
|         FileList = [File.strip() for File in self.RuleContent[LineIndex].split(",")]
 | |
|         for ToolChainFamily in self._FamilyList:
 | |
|             if self._RuleInfo[ToolChainFamily, self._State] is None:
 | |
|                 self._RuleInfo[ToolChainFamily, self._State] = []
 | |
|             self._RuleInfo[ToolChainFamily, self._State].extend(FileList)
 | |
| 
 | |
|     ## Parse <ExtraDependency> sub-section
 | |
|     ## Parse <OutputFile> sub-section
 | |
|     ## Parse <Command> sub-section
 | |
|     #
 | |
|     #   @param  LineIndex   The line index of build rule text
 | |
|     #
 | |
|     def ParseCommonSubSection(self, LineIndex):
 | |
|         for ToolChainFamily in self._FamilyList:
 | |
|             if self._RuleInfo[ToolChainFamily, self._State] is None:
 | |
|                 self._RuleInfo[ToolChainFamily, self._State] = []
 | |
|             self._RuleInfo[ToolChainFamily, self._State].append(self.RuleContent[LineIndex])
 | |
| 
 | |
|     ## Get a build rule via [] operator
 | |
|     #
 | |
|     #   @param  FileExt             The extension of a file
 | |
|     #   @param  ToolChainFamily     The tool chain family name
 | |
|     #   @param  BuildVersion        The build version number. TAB_STAR means any rule
 | |
|     #                               is applicable.
 | |
|     #
 | |
|     #   @retval FileType        The file type string
 | |
|     #   @retval FileBuildRule   The object of FileBuildRule
 | |
|     #
 | |
|     # Key = (FileExt, ModuleType, Arch, ToolChainFamily)
 | |
|     def __getitem__(self, Key):
 | |
|         if not Key:
 | |
|             return None
 | |
| 
 | |
|         if Key[0] in self.Ext2FileType:
 | |
|             Type = self.Ext2FileType[Key[0]]
 | |
|         elif Key[0].upper() in self.FileTypeList:
 | |
|             Type = Key[0].upper()
 | |
|         else:
 | |
|             return None
 | |
| 
 | |
|         if len(Key) > 1:
 | |
|             Key = (Type,) + Key[1:]
 | |
|         else:
 | |
|             Key = (Type,)
 | |
|         return self.RuleDatabase[Key]
 | |
| 
 | |
|     _StateHandler = {
 | |
|         _SectionHeader     : ParseSectionHeader,
 | |
|         _Section           : ParseSection,
 | |
|         _SubSectionHeader  : ParseSubSectionHeader,
 | |
|         _SubSection        : ParseSubSection,
 | |
|         _InputFile         : ParseInputFileSubSection,
 | |
|         _OutputFile        : ParseCommonSubSection,
 | |
|         _ExtraDependency   : ParseCommonSubSection,
 | |
|         _Command           : ParseCommonSubSection,
 | |
|         _UnknownSection    : SkipSection,
 | |
|     }
 | |
| 
 | |
| class ToolBuildRule():
 | |
| 
 | |
|     def __new__(cls, *args, **kw):
 | |
|         if not hasattr(cls, '_instance'):
 | |
|             orig = super(ToolBuildRule, cls)
 | |
|             cls._instance = orig.__new__(cls, *args, **kw)
 | |
|         return cls._instance
 | |
| 
 | |
|     def __init__(self):
 | |
|         if not hasattr(self, 'ToolBuildRule'):
 | |
|             self._ToolBuildRule = None
 | |
| 
 | |
|     @property
 | |
|     def ToolBuildRule(self):
 | |
|         if not self._ToolBuildRule:
 | |
|             self._GetBuildRule()
 | |
|         return self._ToolBuildRule
 | |
| 
 | |
|     def _GetBuildRule(self):
 | |
|         BuildRuleFile = None
 | |
|         TargetObj = TargetTxtDict()
 | |
|         TargetTxt = TargetObj.Target
 | |
|         if TAB_TAT_DEFINES_BUILD_RULE_CONF in TargetTxt.TargetTxtDictionary:
 | |
|             BuildRuleFile = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_BUILD_RULE_CONF]
 | |
|         if not BuildRuleFile:
 | |
|             BuildRuleFile = gDefaultBuildRuleFile
 | |
|         RetVal = BuildRule(BuildRuleFile)
 | |
|         if RetVal._FileVersion == "":
 | |
|             RetVal._FileVersion = AutoGenReqBuildRuleVerNum
 | |
|         else:
 | |
|             if RetVal._FileVersion < AutoGenReqBuildRuleVerNum :
 | |
|                 # If Build Rule's version is less than the version number required by the tools, halting the build.
 | |
|                 EdkLogger.error("build", AUTOGEN_ERROR,
 | |
|                                 ExtraData="The version number [%s] of build_rule.txt is less than the version number required by the AutoGen.(the minimum required version number is [%s])"\
 | |
|                                  % (RetVal._FileVersion, AutoGenReqBuildRuleVerNum))
 | |
|         self._ToolBuildRule = RetVal
 | |
| 
 | |
| # This acts like the main() function for the script, unless it is 'import'ed into another
 | |
| # script.
 | |
| if __name__ == '__main__':
 | |
|     import sys
 | |
|     EdkLogger.Initialize()
 | |
|     if len(sys.argv) > 1:
 | |
|         Br = BuildRule(sys.argv[1])
 | |
|         print(str(Br[".c", SUP_MODULE_DXE_DRIVER, "IA32", TAB_COMPILER_MSFT][1]))
 | |
|         print()
 | |
|         print(str(Br[".c", SUP_MODULE_DXE_DRIVER, "IA32", "INTEL"][1]))
 | |
|         print()
 | |
|         print(str(Br[".c", SUP_MODULE_DXE_DRIVER, "IA32", "GCC"][1]))
 | |
|         print()
 | |
|         print(str(Br[".ac", "ACPI_TABLE", "IA32", TAB_COMPILER_MSFT][1]))
 | |
|         print()
 | |
|         print(str(Br[".h", "ACPI_TABLE", "IA32", "INTEL"][1]))
 | |
|         print()
 | |
|         print(str(Br[".ac", "ACPI_TABLE", "IA32", TAB_COMPILER_MSFT][1]))
 | |
|         print()
 | |
|         print(str(Br[".s", SUP_MODULE_SEC, "IPF", "COMMON"][1]))
 | |
|         print()
 | |
|         print(str(Br[".s", SUP_MODULE_SEC][1]))
 | |
| 
 |