diff options
Diffstat (limited to 'BaseTools/Source/Python/AutoGen/BuildEngine.py')
-rw-r--r-- | BaseTools/Source/Python/AutoGen/BuildEngine.py | 622 |
1 files changed, 0 insertions, 622 deletions
diff --git a/BaseTools/Source/Python/AutoGen/BuildEngine.py b/BaseTools/Source/Python/AutoGen/BuildEngine.py deleted file mode 100644 index 73b4a97417..0000000000 --- a/BaseTools/Source/Python/AutoGen/BuildEngine.py +++ /dev/null @@ -1,622 +0,0 @@ -## @file -# The engine for building files -# -# Copyright (c) 2007, Intel Corporation. All rights reserved.<BR> -# This program and the accompanying materials -# are licensed and made available under the terms and conditions of the BSD License -# which accompanies this distribution. The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php -# -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# - -## -# Import Modules -# -import os -import re -import copy -import string - -from Common.GlobalData import * -from Common.BuildToolError import * -from Common.Misc import tdict, PathClass -from Common.String import NormPath -from Common.DataType import * - -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): - _Cache_ = {} # {TargetFile : TargetDescBlock object} - - # Factory method - def __new__(Class, Inputs, Outputs, Commands, Dependencies): - if Outputs[0] in Class._Cache_: - Tdb = Class._Cache_[Outputs[0]] - for File in Inputs: - Tdb.AddInput(File) - else: - Tdb = super(TargetDescBlock, Class).__new__(Class) - Tdb._Init(Inputs, Outputs, Commands, Dependencies) - #Class._Cache_[Outputs[0]] = Tdb - return Tdb - - def _Init(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 type(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 - - @staticmethod - def Renew(): - TargetDescBlock._Cache_ = {} - -## 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 represeting input file(s) for a rule - # @param Output The list represeting 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 "*" 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(gMacroPattern.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 = [] - for File in Input: - Base, Ext = os.path.splitext(File) - if Base.find("*") >= 0: - # There's "*" in the file name - self.IsMultipleInput = True - self.GenFileListMacro = True - elif Base.find("?") < 0: - # There's no "*" and "?" in file name - self.ExtraSourceFileList.append(File) - continue - if Ext not in self.SourceFileExtList: - self.SourceFileExtList.append(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(self.DestFileList) - CommandString = "\n\t".join(self.CommandList) - return "%s : %s\n\t%s" % (DestString, SourceString, CommandString) - - ## Check if given file extension is supported by this rule - # - # @param FileExt The extension of a file - # - # @retval True If the extension is supported - # @retval False If the extension is not supported - # - def IsSupported(self, FileExt): - return FileExt in self.SourceFileExtList - - def Instantiate(self, 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, Destionation file, List of build commands) - # - def Apply(self, SourceFile): - 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]] - TargetDesc.AddInput(SourceFile) - else: - CommandList = [] - for CommandString in self.CommandList: - CommandString = string.Template(CommandString).safe_substitute(BuildRulePlaceholderDict) - CommandString = string.Template(CommandString).safe_substitute(BuildRulePlaceholderDict) - CommandList.append(CommandString) - 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 - -## 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=["MSFT", "INTEL", "GCC", "RVCT"]): - self.RuleFile = File - # Read build rules from file if it's not none - if File != None: - try: - self.RuleContent = open(File, 'r').readlines() - except: - EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=File) - elif Content != 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 = [] - self._ArchList = [] - self._FamilyList = [] - self._TotalToolChainFamilySet = set() - self._RuleObjectList = [] # FileBuildRule object list - - self.Parse() - - # some intrinsic rules - self.RuleDatabase[TAB_DEFAULT_BINARY_FILE, "COMMON", "COMMON", "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 - - # 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): - # currenly 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 toochain family, 'COMMON' doesn't make sense any more - if len(self._TotalToolChainFamilySet) > 1 and 'COMMON' in self._TotalToolChainFamilySet: - self._TotalToolChainFamilySet.remove('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 = [] - self._ArchList = [] - self._FamilyList = [] - self._TotalToolChainFamilySet = set() - FileType = '' - RuleNameList = self.RuleContent[LineIndex][1:-1].split(',') - for RuleName in RuleNameList: - Arch = 'COMMON' - BuildType = '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) == 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] - if BuildType not in self._BuildTypeList: - self._BuildTypeList.append(BuildType) - if Arch not in self._ArchList: - self._ArchList.append(Arch) - - if '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 '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 = "COMMON" - - if Family not in FamilyList: - FamilyList.append(Family) - - self._FamilyList = FamilyList - self._TotalToolChainFamilySet.update(FamilyList) - self._State = SectionType.upper() - if '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 ParseInputFile(self, LineIndex): - FileList = [File.strip() for File in self.RuleContent[LineIndex].split(",")] - for ToolChainFamily in self._FamilyList: - InputFiles = self._RuleInfo[ToolChainFamily, self._State] - if InputFiles == None: - InputFiles = [] - self._RuleInfo[ToolChainFamily, self._State] = InputFiles - InputFiles.extend(FileList) - - ## Parse <ExtraDependency> sub-section - # - # @param LineIndex The line index of build rule text - # - def ParseCommon(self, LineIndex): - for ToolChainFamily in self._FamilyList: - Items = self._RuleInfo[ToolChainFamily, self._State] - if Items == None: - Items = [] - self._RuleInfo[ToolChainFamily, self._State] = Items - Items.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. "*" means any rule - # is applicalbe. - # - # @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 : ParseInputFile, - _OutputFile : ParseCommon, - _ExtraDependency : ParseCommon, - _Command : ParseCommon, - _UnknownSection : SkipSection, - } - -# 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", "DXE_DRIVER", "IA32", "MSFT"][1]) - print - print str(Br[".c", "DXE_DRIVER", "IA32", "INTEL"][1]) - print - print str(Br[".c", "DXE_DRIVER", "IA32", "GCC"][1]) - print - print str(Br[".ac", "ACPI_TABLE", "IA32", "MSFT"][1]) - print - print str(Br[".h", "ACPI_TABLE", "IA32", "INTEL"][1]) - print - print str(Br[".ac", "ACPI_TABLE", "IA32", "MSFT"][1]) - print - print str(Br[".s", "SEC", "IPF", "COMMON"][1]) - print - print str(Br[".s", "SEC"][1]) - |