From 0d2711a69397d2971079121df4326d84736c181e Mon Sep 17 00:00:00 2001 From: lgao4 Date: Sat, 29 Oct 2011 06:59:30 +0000 Subject: Sync BaseTools Trunk (version r2387) to EDKII main trunk. Signed-off-by: lgao4 Reviewed-by: gikidy git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12602 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/Python/AutoGen/AutoGen.py | 77 +- BaseTools/Source/Python/AutoGen/BuildEngine.py | 2 +- BaseTools/Source/Python/AutoGen/GenC.py | 8 + BaseTools/Source/Python/AutoGen/GenMake.py | 14 +- BaseTools/Source/Python/Common/BuildVersion.py | 2 +- BaseTools/Source/Python/Common/DataType.py | 1 + BaseTools/Source/Python/Common/Expression.py | 555 ++++++++++ BaseTools/Source/Python/Common/GlobalData.py | 11 +- BaseTools/Source/Python/Common/Misc.py | 8 +- BaseTools/Source/Python/Common/String.py | 56 +- .../Source/Python/CommonDataClass/DataClass.py | 4 +- .../Source/Python/CommonDataClass/Exceptions.py | 29 + BaseTools/Source/Python/GenFds/AprioriSection.py | 4 +- BaseTools/Source/Python/GenFds/DepexSection.py | 5 +- BaseTools/Source/Python/GenFds/Fd.py | 8 +- BaseTools/Source/Python/GenFds/FdfParser.py | 268 ++--- BaseTools/Source/Python/GenFds/FfsFileStatement.py | 4 +- BaseTools/Source/Python/GenFds/FfsInfStatement.py | 14 +- BaseTools/Source/Python/GenFds/Fv.py | 8 +- BaseTools/Source/Python/GenFds/GenFds.py | 37 +- .../Source/Python/GenFds/GenFdsGlobalVariable.py | 73 +- BaseTools/Source/Python/GenFds/Section.py | 2 +- .../Source/Python/PatchPcdValue/PatchPcdValue.py | 1 - .../Source/Python/UPT/Library/ParserValidate.py | 12 +- BaseTools/Source/Python/Workspace/MetaDataTable.py | 31 +- .../Source/Python/Workspace/MetaFileParser.py | 1126 +++++++++++++------- BaseTools/Source/Python/Workspace/MetaFileTable.py | 106 +- .../Source/Python/Workspace/WorkspaceDatabase.py | 509 ++++----- BaseTools/Source/Python/build/BuildReport.py | 46 +- BaseTools/Source/Python/build/build.py | 344 +++--- 30 files changed, 2149 insertions(+), 1216 deletions(-) create mode 100644 BaseTools/Source/Python/Common/Expression.py create mode 100644 BaseTools/Source/Python/CommonDataClass/Exceptions.py (limited to 'BaseTools/Source/Python') diff --git a/BaseTools/Source/Python/AutoGen/AutoGen.py b/BaseTools/Source/Python/AutoGen/AutoGen.py index 8150ea0b69..2def474b17 100644 --- a/BaseTools/Source/Python/AutoGen/AutoGen.py +++ b/BaseTools/Source/Python/AutoGen/AutoGen.py @@ -180,16 +180,16 @@ class WorkspaceAutoGen(AutoGen): Fvs = [] if Caps is None: Caps = [] - self.MetaFile = ActivePlatform.MetaFile + self.BuildDatabase = MetaFileDb + self.MetaFile = ActivePlatform self.WorkspaceDir = WorkspaceDir - self.Platform = ActivePlatform + self.Platform = self.BuildDatabase[self.MetaFile, 'COMMON', Target, Toolchain] self.BuildTarget = Target self.ToolChain = Toolchain self.ArchList = ArchList self.SkuId = SkuId self.UniFlag = UniFlag - self.BuildDatabase = MetaFileDb self.TargetTxt = BuildConfig self.ToolDef = ToolDefinition self.FdfFile = FlashDefinitionFile @@ -201,30 +201,74 @@ class WorkspaceAutoGen(AutoGen): # there's many relative directory operations, so ... os.chdir(self.WorkspaceDir) + # + # Merge Arch + # + if not self.ArchList: + ArchList = set(self.Platform.SupArchList) + else: + ArchList = set(self.ArchList) & set(self.Platform.SupArchList) + if not ArchList: + EdkLogger.error("build", PARAMETER_INVALID, + ExtraData = "Invalid ARCH specified. [Valid ARCH: %s]" % (" ".join(self.Platform.SupArchList))) + elif self.ArchList and len(ArchList) != len(self.ArchList): + SkippedArchList = set(self.ArchList).symmetric_difference(set(self.Platform.SupArchList)) + EdkLogger.verbose("\nArch [%s] is ignored because the platform supports [%s] only!" + % (" ".join(SkippedArchList), " ".join(self.Platform.SupArchList))) + self.ArchList = tuple(ArchList) + + # Validate build target + if self.BuildTarget not in self.Platform.BuildTargets: + EdkLogger.error("build", PARAMETER_INVALID, + ExtraData="Build target [%s] is not supported by the platform. [Valid target: %s]" + % (self.BuildTarget, " ".join(self.Platform.BuildTargets))) + + # Validate SKU ID + if not self.SkuId: + self.SkuId = 'DEFAULT' + + if self.SkuId not in self.Platform.SkuIds: + EdkLogger.error("build", PARAMETER_INVALID, + ExtraData="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]" + % (self.SkuId, " ".join(self.Platform.SkuIds.keys()))) + # parse FDF file to get PCDs in it, if any - if self.FdfFile != None and self.FdfFile != '': - # - # Make global macros available when parsing FDF file - # - InputMacroDict.update(self.BuildDatabase.WorkspaceDb._GlobalMacros) + if not self.FdfFile: + self.FdfFile = self.Platform.FlashDefinition + EdkLogger.verbose("\nFLASH_DEFINITION = %s" % self.FdfFile) + + if self.FdfFile: # # Mark now build in AutoGen Phase # - GlobalData.gAutoGenPhase = True + GlobalData.gAutoGenPhase = True Fdf = FdfParser(self.FdfFile.Path) Fdf.ParseFile() - GlobalData.gAutoGenPhase = False + GlobalData.gAutoGenPhase = False PcdSet = Fdf.Profile.PcdDict ModuleList = Fdf.Profile.InfList self.FdfProfile = Fdf.Profile + for fvname in self.FvTargetList: + if fvname.upper() not in self.FdfProfile.FvDict: + EdkLogger.error("build", OPTION_VALUE_INVALID, + "No such an FV in FDF file: %s" % fvname) else: PcdSet = {} ModuleList = [] self.FdfProfile = None + if self.FdTargetList: + EdkLogger.info("No flash definition file found. FD [%s] will be ignored." % " ".join(self.FdTargetList)) + self.FdTargetList = [] + if self.FvTargetList: + EdkLogger.info("No flash definition file found. FV [%s] will be ignored." % " ".join(self.FvTargetList)) + self.FvTargetList = [] + if self.CapTargetList: + EdkLogger.info("No flash definition file found. Capsule [%s] will be ignored." % " ".join(self.CapTargetList)) + self.CapTargetList = [] # apply SKU and inject PCDs from Flash Definition file for Arch in self.ArchList: - Platform = self.BuildDatabase[self.MetaFile, Arch] + Platform = self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain] Platform.SkuName = self.SkuId for Name, Guid in PcdSet: Platform.AddPcd(Name, Guid, PcdSet[Name, Guid]) @@ -971,7 +1015,7 @@ class PlatformAutoGen(AutoGen): ## Return the platform build data object def _GetPlatform(self): if self._Platform == None: - self._Platform = self.BuildDatabase[self.MetaFile, self.Arch] + self._Platform = self.BuildDatabase[self.MetaFile, self.Arch, self.BuildTarget, self.ToolChain] return self._Platform ## Return platform name @@ -1309,7 +1353,7 @@ class PlatformAutoGen(AutoGen): File=self.MetaFile, ExtraData="in [%s] [%s]\n\tconsumed by module [%s]" % (str(M), self.Arch, str(Module))) - LibraryModule = self.BuildDatabase[LibraryPath, self.Arch] + LibraryModule = self.BuildDatabase[LibraryPath, self.Arch, self.BuildTarget, self.ToolChain] # for those forced library instance (NULL library), add a fake library class if LibraryClassName.startswith("NULL"): LibraryModule.LibraryClass.append(LibraryClassObject(LibraryClassName, [ModuleType])) @@ -1907,6 +1951,7 @@ class ModuleAutoGen(AutoGen): self._Macro["ARCH" ] = self.Arch self._Macro["TOOLCHAIN" ] = self.ToolChain self._Macro["TOOLCHAIN_TAG" ] = self.ToolChain + self._Macro["TOOL_CHAIN_TAG" ] = self.ToolChain self._Macro["TARGET" ] = self.BuildTarget self._Macro["BUILD_DIR" ] = self.PlatformInfo.BuildDir @@ -1920,7 +1965,7 @@ class ModuleAutoGen(AutoGen): ## Return the module build data object def _GetModule(self): if self._Module == None: - self._Module = self.Workspace.BuildDatabase[self.MetaFile, self.Arch] + self._Module = self.Workspace.BuildDatabase[self.MetaFile, self.Arch, self.BuildTarget, self.ToolChain] return self._Module ## Return the module name @@ -2279,7 +2324,7 @@ class ModuleAutoGen(AutoGen): if File.IsBinary and File == Source and self._BinaryFileList != None and File in self._BinaryFileList: # Skip all files that are not binary libraries if not self.IsLibrary: - continue + continue RuleObject = self.BuildRules[TAB_DEFAULT_BINARY_FILE] elif FileType in self.BuildRules: RuleObject = self.BuildRules[FileType] @@ -2672,7 +2717,7 @@ class ModuleAutoGen(AutoGen): DpxFile = gAutoGenDepexFileName % {"module_name" : self.Name} if len(Dpx.PostfixNotation) <> 0: - self.DepexGenerated = True + self.DepexGenerated = True if Dpx.Generate(path.join(self.OutputDir, DpxFile)): AutoGenList.append(str(DpxFile)) diff --git a/BaseTools/Source/Python/AutoGen/BuildEngine.py b/BaseTools/Source/Python/AutoGen/BuildEngine.py index 73b4a97417..45a560448e 100644 --- a/BaseTools/Source/Python/AutoGen/BuildEngine.py +++ b/BaseTools/Source/Python/AutoGen/BuildEngine.py @@ -137,7 +137,7 @@ class FileBuildRule: self.MacroList = [] self.CommandList = [] for CmdLine in Command: - self.MacroList.extend(gMacroPattern.findall(CmdLine)) + self.MacroList.extend(gMacroRefPattern.findall(CmdLine)) # replace path separator with native one self.CommandList.append(CmdLine) diff --git a/BaseTools/Source/Python/AutoGen/GenC.py b/BaseTools/Source/Python/AutoGen/GenC.py index f733ac3e8d..c6b65f4924 100644 --- a/BaseTools/Source/Python/AutoGen/GenC.py +++ b/BaseTools/Source/Python/AutoGen/GenC.py @@ -956,6 +956,14 @@ def CreateModulePcdCode(Info, AutoGenC, AutoGenH, Pcd): Value = Pcd.DefaultValue Unicode = False ValueNumber = 0 + + if Pcd.DatumType == 'BOOLEAN': + BoolValue = Value.upper() + if BoolValue == 'TRUE': + Value = 1 + elif BoolValue == 'FALSE': + Value = 0 + if Pcd.DatumType in ['UINT64', 'UINT32', 'UINT16', 'UINT8']: try: if Value.upper().startswith('0X'): diff --git a/BaseTools/Source/Python/AutoGen/GenMake.py b/BaseTools/Source/Python/AutoGen/GenMake.py index 3720c8bfed..478ab0f01b 100644 --- a/BaseTools/Source/Python/AutoGen/GenMake.py +++ b/BaseTools/Source/Python/AutoGen/GenMake.py @@ -493,7 +493,7 @@ cleanlib: # convert source files and binary files to build targets self.ResultFileList = [str(T.Target) for T in self._AutoGenObject.CodaTargetList] - if len(self.ResultFileList) == 0 and len(self._AutoGenObject.SourceFileList) <> 0: + if len(self.ResultFileList) == 0 and len(self._AutoGenObject.SourceFileList) <> 0: EdkLogger.error("build", AUTOGEN_ERROR, "Nothing to build", ExtraData="[%s]" % str(self._AutoGenObject)) @@ -1253,7 +1253,7 @@ ${END}\t@cd $(BUILD_DIR) # fds: init \t-@cd $(FV_DIR) -${BEGIN}\tGenFds -f ${fdf_file} -o $(BUILD_DIR) -t $(TOOLCHAIN) -b $(TARGET) -p ${active_platform} -a ${build_architecture_list}${END}${BEGIN}${extra_options}${END}${BEGIN} -r ${fd}${END}${BEGIN} -i ${fv}${END}${BEGIN} -C ${cap}${END}${BEGIN} -D${macro}${END} +${BEGIN}\tGenFds -f ${fdf_file} -o $(BUILD_DIR) -t $(TOOLCHAIN) -b $(TARGET) -p ${active_platform} -a ${build_architecture_list} ${extra_options}${END}${BEGIN} -r ${fd} ${END}${BEGIN} -i ${fv} ${END}${BEGIN} -C ${cap} ${END}${BEGIN} -D ${macro} ${END} # # run command for emulator platform only @@ -1320,6 +1320,11 @@ ${END}\t@cd $(BUILD_DIR)\n MacroList.append('"%s=%s"' % (MacroName, GlobalData.gGlobalDefines[MacroName])) else: MacroList.append('"%s"' % MacroName) + for MacroName in GlobalData.gCommandLineDefines: + if GlobalData.gCommandLineDefines[MacroName] != "": + MacroList.append('"%s=%s"' % (MacroName, GlobalData.gCommandLineDefines[MacroName])) + else: + MacroList.append('"%s"' % MacroName) else: FdfFileList = [] @@ -1335,9 +1340,6 @@ ${END}\t@cd $(BUILD_DIR)\n if GlobalData.gCaseInsensitive: ExtraOption += " -c" - ExtraOptionList = [] - if ExtraOption: - ExtraOptionList.append(ExtraOption) MakefileName = self._FILE_NAME_[self._FileType] SubBuildCommandList = [] @@ -1369,7 +1371,7 @@ ${END}\t@cd $(BUILD_DIR)\n "fd" : PlatformInfo.FdTargetList, "fv" : PlatformInfo.FvTargetList, "cap" : PlatformInfo.CapTargetList, - "extra_options" : ExtraOptionList, + "extra_options" : ExtraOption, "macro" : MacroList, } diff --git a/BaseTools/Source/Python/Common/BuildVersion.py b/BaseTools/Source/Python/Common/BuildVersion.py index fecc40e84a..82597c0945 100644 --- a/BaseTools/Source/Python/Common/BuildVersion.py +++ b/BaseTools/Source/Python/Common/BuildVersion.py @@ -1,3 +1,3 @@ #This file is for build version number auto generation # -gBUILD_VERSION = "Build 2361" +gBUILD_VERSION = "Build 2386" diff --git a/BaseTools/Source/Python/Common/DataType.py b/BaseTools/Source/Python/Common/DataType.py index 9a2556749a..fc0a7ad026 100644 --- a/BaseTools/Source/Python/Common/DataType.py +++ b/BaseTools/Source/Python/Common/DataType.py @@ -360,6 +360,7 @@ TAB_DSC_DEFINES_ISO_LANGUAGES = 'ISO_LANGUAGES' TAB_DSC_DEFINES_DEFINE = 'DEFINE' TAB_DSC_DEFINES_VPD_TOOL_GUID = 'VPD_TOOL_GUID' TAB_FIX_LOAD_TOP_MEMORY_ADDRESS = 'FIX_LOAD_TOP_MEMORY_ADDRESS' +TAB_DSC_DEFINES_EDKGLOBAL = 'EDK_GLOBAL' # # TargetTxt Definitions diff --git a/BaseTools/Source/Python/Common/Expression.py b/BaseTools/Source/Python/Common/Expression.py new file mode 100644 index 0000000000..e2889a8dd3 --- /dev/null +++ b/BaseTools/Source/Python/Common/Expression.py @@ -0,0 +1,555 @@ +## @file +# This file is used to parse and evaluate expression in directive or PCD value. +# +# Copyright (c) 2011, Intel Corporation. All rights reserved.
+# 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 +# +from Common.GlobalData import * +from CommonDataClass.Exceptions import BadExpression +from CommonDataClass.Exceptions import SymbolNotFound +from CommonDataClass.Exceptions import WrnExpression +from Misc import GuidStringToGuidStructureString + +ERR_STRING_EXPR = 'This operator cannot be used in string expression: [%s].' +ERR_SNYTAX = 'Syntax error, the rest of expression cannot be evaluated: [%s].' +ERR_MATCH = 'No matching right parenthesis.' +ERR_STRING_TOKEN = 'Bad string token: [%s].' +ERR_MACRO_TOKEN = 'Bad macro token: [%s].' +ERR_EMPTY_TOKEN = 'Empty token is not allowed.' +ERR_PCD_RESOLVE = 'PCD token cannot be resolved: [%s].' +ERR_VALID_TOKEN = 'No more valid token found from rest of string: [%s].' +ERR_EXPR_TYPE = 'Different types found in expression.' +ERR_OPERATOR_UNSUPPORT = 'Unsupported operator: [%s]' +ERR_REL_NOT_IN = 'Expect "IN" after "not" operator.' +WRN_BOOL_EXPR = 'Operand of boolean type cannot be used in arithmetic expression.' +WRN_EQCMP_STR_OTHERS = '== Comparison between Operand of string type and Boolean/Number Type always return False.' +WRN_NECMP_STR_OTHERS = '!= Comparison between Operand of string type and Boolean/Number Type always return True.' +ERR_RELCMP_STR_OTHERS = 'Operator taking Operand of string type and Boolean/Number Type is not allowed: [%s].' +ERR_STRING_CMP = 'Unicode string and general string cannot be compared: [%s %s %s]' +ERR_ARRAY_TOKEN = 'Bad C array or C format GUID token: [%s].' +ERR_ARRAY_ELE = 'This must be HEX value for NList or Array: [%s].' + +## SplitString +# Split string to list according double quote +# For example: abc"de\"f"ghi"jkl"mn will be: ['abc', '"de\"f"', 'ghi', '"jkl"', 'mn'] +# +def SplitString(String): + # There might be escaped quote: "abc\"def\\\"ghi" + Str = String.replace('\\\\', '//').replace('\\\"', '\\\'') + RetList = [] + InQuote = False + Item = '' + for i, ch in enumerate(Str): + if ch == '"': + InQuote = not InQuote + if not InQuote: + Item += String[i] + RetList.append(Item) + Item = '' + continue + if Item: + RetList.append(Item) + Item = '' + Item += String[i] + if InQuote: + raise BadExpression(ERR_STRING_TOKEN % Item) + if Item: + RetList.append(Item) + return RetList + +## ReplaceExprMacro +# +def ReplaceExprMacro(String, Macros, ExceptionList = None): + StrList = SplitString(String) + for i, String in enumerate(StrList): + InQuote = False + if String.startswith('"'): + InQuote = True + MacroStartPos = String.find('$(') + if MacroStartPos < 0: + continue + RetStr = '' + while MacroStartPos >= 0: + RetStr = String[0:MacroStartPos] + MacroEndPos = String.find(')', MacroStartPos) + if MacroEndPos < 0: + raise BadExpression(ERR_MACRO_TOKEN % String[MacroStartPos:]) + Macro = String[MacroStartPos+2:MacroEndPos] + if Macro not in Macros: + # From C reference manual: + # If an undefined macro name appears in the constant-expression of + # !if or !elif, it is replaced by the integer constant 0. + RetStr += '0' + elif not InQuote and ExceptionList and Macro in ExceptionList: + # Make sure the macro in exception list is encapsulated by double quote + # For example: DEFINE ARCH = IA32 X64 + # $(ARCH) is replaced with "IA32 X64" + RetStr += '"' + Macros[Macro] + '"' + else: + if Macros[Macro].strip() != "": + RetStr += Macros[Macro] + else: + RetStr += '""' + RetStr += String[MacroEndPos+1:] + String = RetStr + MacroStartPos = String.find('$(') + StrList[i] = RetStr + return ''.join(StrList) + +class ValueExpression(object): + # Logical operator mapping + LogicalOperators = { + '&&' : 'and', '||' : 'or', + '!' : 'not', 'AND': 'and', + 'OR' : 'or' , 'NOT': 'not', + 'XOR': '^' , 'xor': '^', + 'EQ' : '==' , 'NE' : '!=', + 'GT' : '>' , 'LT' : '<', + 'GE' : '>=' , 'LE' : '<=', + 'IN' : 'in' + } + + NonLetterOpLst = ['+', '-', '&', '|', '^', '!', '=', '>', '<'] + + PcdPattern = re.compile(r'[_a-zA-Z][0-9A-Za-z_]*\.[_a-zA-Z][0-9A-Za-z_]*$') + HexPattern = re.compile(r'0[xX][0-9a-fA-F]+$') + RegGuidPattern = re.compile(r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}') + + SymbolPattern = re.compile("(" + "\$\([A-Z][A-Z0-9_]*\)|\$\(\w+\.\w+\)|\w+\.\w+|" + "&&|\|\||!(?!=)|" + "(?<=\W)AND(?=\W)|(?<=\W)OR(?=\W)|(?<=\W)NOT(?=\W)|(?<=\W)XOR(?=\W)|" + "(?<=\W)EQ(?=\W)|(?<=\W)NE(?=\W)|(?<=\W)GT(?=\W)|(?<=\W)LT(?=\W)|(?<=\W)GE(?=\W)|(?<=\W)LE(?=\W)" + ")") + + @staticmethod + def Eval(Operator, Oprand1, Oprand2 = None): + WrnExp = None + + if Operator not in ["==", "!=", ">=", "<=", ">", "<", "in", "not in"] and \ + (type(Oprand1) == type('') or type(Oprand2) == type('')): + raise BadExpression(ERR_STRING_EXPR % Operator) + + TypeDict = { + type(0) : 0, + type(0L) : 0, + type('') : 1, + type(True) : 2 + } + + EvalStr = '' + if Operator in ["!", "NOT", "not"]: + if type(Oprand1) == type(''): + raise BadExpression(ERR_STRING_EXPR % Operator) + EvalStr = 'not Oprand1' + else: + if Operator in ["+", "-"] and (type(True) in [type(Oprand1), type(Oprand2)]): + # Boolean in '+'/'-' will be evaluated but raise warning + WrnExp = WrnExpression(WRN_BOOL_EXPR) + elif type('') in [type(Oprand1), type(Oprand2)] and type(Oprand1)!= type(Oprand2): + # == between string and number/boolean will always return False, != return True + if Operator == "==": + WrnExp = WrnExpression(WRN_EQCMP_STR_OTHERS) + WrnExp.result = False + raise WrnExp + elif Operator == "!=": + WrnExp = WrnExpression(WRN_NECMP_STR_OTHERS) + WrnExp.result = True + raise WrnExp + else: + raise BadExpression(ERR_RELCMP_STR_OTHERS % Operator) + elif TypeDict[type(Oprand1)] != TypeDict[type(Oprand2)]: + if Operator in ["==", "!=", ">=", "<=", ">", "<"] and set((TypeDict[type(Oprand1)], TypeDict[type(Oprand2)])) == set((TypeDict[type(True)], TypeDict[type(0)])): + # comparison between number and boolean is allowed + pass + elif Operator in ['&', '|', '^', "&&", "||"] and set((TypeDict[type(Oprand1)], TypeDict[type(Oprand2)])) == set((TypeDict[type(True)], TypeDict[type(0)])): + # bitwise and logical operation between number and boolean is allowed + pass + else: + raise BadExpression(ERR_EXPR_TYPE) + if type(Oprand1) == type('') and type(Oprand2) == type(''): + if (Oprand1.startswith('L"') and not Oprand2.startswith('L"')) or \ + (not Oprand1.startswith('L"') and Oprand2.startswith('L"')): + raise BadExpression(ERR_STRING_CMP % (Oprand1, Operator, Oprand2)) + if 'in' in Operator and type(Oprand2) == type(''): + Oprand2 = Oprand2.split() + EvalStr = 'Oprand1 ' + Operator + ' Oprand2' + + # Local symbols used by built in eval function + Dict = { + 'Oprand1' : Oprand1, + 'Oprand2' : Oprand2 + } + try: + Val = eval(EvalStr, {}, Dict) + except Exception, Excpt: + raise BadExpression(str(Excpt)) + + if Operator in ['and', 'or']: + if Val: + Val = True + else: + Val = False + + if WrnExp: + WrnExp.result = Val + raise WrnExp + return Val + + def __init__(self, Expression, SymbolTable={}): + self._NoProcess = False + if type(Expression) != type(''): + self._Expr = Expression + self._NoProcess = True + return + + self._Expr = ReplaceExprMacro(Expression.strip(), + SymbolTable, + ['TARGET', 'TOOL_CHAIN_TAG', 'ARCH']) + + if not self._Expr.strip(): + self._NoProcess = True + return + + # + # The symbol table including PCD and macro mapping + # + self._Symb = SymbolTable + self._Symb.update(self.LogicalOperators) + self._Idx = 0 + self._Len = len(self._Expr) + self._Token = '' + + # Literal token without any conversion + self._LiteralToken = '' + + # Public entry for this class + def __call__(self): + if self._NoProcess: + return self._Expr + + Val = self._OrExpr() + if type(Val) == type('') and Val == 'L""': + Val = '' + + # The expression has been parsed, but the end of expression is not reached + # It means the rest does not comply EBNF of + if self._Idx != self._Len: + raise BadExpression(ERR_SNYTAX % self._Expr[self._Idx:]) + + return Val + + # Template function to parse binary operators which have same precedence + # Expr [Operator Expr]* + def _ExprFuncTemplate(self, EvalFunc, OpLst): + Val = EvalFunc() + while self._IsOperator(OpLst): + Op = self._Token + Val = self.Eval(Op, Val, EvalFunc()) + return Val + + # A [|| B]* + def _OrExpr(self): + return self._ExprFuncTemplate(self._AndExpr, ["OR", "or", "||"]) + + # A [&& B]* + def _AndExpr(self): + return self._ExprFuncTemplate(self._BitOr, ["AND", "and", "&&"]) + + # A [ | B]* + def _BitOr(self): + return self._ExprFuncTemplate(self._BitXor, ["|"]) + + # A [ ^ B]* + def _BitXor(self): + return self._ExprFuncTemplate(self._BitAnd, ["XOR", "xor", "^"]) + + # A [ & B]* + def _BitAnd(self): + return self._ExprFuncTemplate(self._EqExpr, ["&"]) + + # A [ == B]* + def _EqExpr(self): + Val = self._RelExpr() + while self._IsOperator(["==", "!=", "EQ", "NE", "IN", "in", "!", "NOT", "not"]): + Op = self._Token + if Op in ["!", "NOT", "not"]: + if not self._IsOperator(["IN", "in"]): + raise BadExpression(ERR_REL_NOT_IN) + Op += ' ' + self._Token + Val = self.Eval(Op, Val, self._RelExpr()) + return Val + + # A [ > B]* + def _RelExpr(self): + return self._ExprFuncTemplate(self._AddExpr, ["<=", ">=", "<", ">", "LE", "GE", "LT", "GT"]) + + # A [ + B]* + def _AddExpr(self): + return self._ExprFuncTemplate(self._UnaryExpr, ["+", "-"]) + + # [!]*A + def _UnaryExpr(self): + if self._IsOperator(["!", "NOT", "not"]): + Val = self._UnaryExpr() + return self.Eval('not', Val) + return self._IdenExpr() + + # Parse identifier or encapsulated expression + def _IdenExpr(self): + Tk = self._GetToken() + if Tk == '(': + Val = self._OrExpr() + try: + # _GetToken may also raise BadExpression + if self._GetToken() != ')': + raise BadExpression(ERR_MATCH) + except BadExpression: + raise BadExpression(ERR_MATCH) + return Val + return Tk + + # Skip whitespace or tab + def __SkipWS(self): + for Char in self._Expr[self._Idx:]: + if Char not in ' \t': + break + self._Idx += 1 + + # Try to convert string to number + def __IsNumberToken(self): + Radix = 10 + if self._Token.lower()[0:2] == '0x' and len(self._Token) > 2: + Radix = 16 + try: + self._Token = int(self._Token, Radix) + return True + except ValueError: + return False + except TypeError: + return False + + # Parse array: {...} + def __GetArray(self): + Token = '{' + self._Idx += 1 + self.__GetNList(True) + Token += self._LiteralToken + if self._Idx >= self._Len or self._Expr[self._Idx] != '}': + raise BadExpression(ERR_ARRAY_TOKEN % Token) + Token += '}' + + # All whitespace and tabs in array are already stripped. + IsArray = IsGuid = False + if len(Token.split(',')) == 11 and len(Token.split(',{')) == 2 \ + and len(Token.split('},')) == 1: + HexLen = [11,6,6,5,4,4,4,4,4,4,6] + HexList= Token.split(',') + if HexList[3].startswith('{') and \ + not [Index for Index, Hex in enumerate(HexList) if len(Hex) > HexLen[Index]]: + IsGuid = True + if Token.lstrip('{').rstrip('}').find('{') == -1: + if not [Hex for Hex in Token.lstrip('{').rstrip('}').split(',') if len(Hex) > 4]: + IsArray = True + if not IsArray and not IsGuid: + raise BadExpression(ERR_ARRAY_TOKEN % Token) + self._Idx += 1 + self._Token = self._LiteralToken = Token + return self._Token + + # Parse string, the format must be: "..." + def __GetString(self): + Idx = self._Idx + + # Skip left quote + self._Idx += 1 + + # Replace escape \\\", \" + Expr = self._Expr[self._Idx:].replace('\\\\', '//').replace('\\\"', '\\\'') + for Ch in Expr: + self._Idx += 1 + if Ch == '"': + break + self._Token = self._LiteralToken = self._Expr[Idx:self._Idx] + if not self._Token.endswith('"'): + raise BadExpression(ERR_STRING_TOKEN % self._Token) + self._Token = self._Token[1:-1] + return self._Token + + # Get token that is comprised by alphanumeric, underscore or dot(used by PCD) + # @param IsAlphaOp: Indicate if parsing general token or script operator(EQ, NE...) + def __GetIdToken(self, IsAlphaOp = False): + IdToken = '' + for Ch in self._Expr[self._Idx:]: + if not self.__IsIdChar(Ch): + break + self._Idx += 1 + IdToken += Ch + + self._Token = self._LiteralToken = IdToken + if not IsAlphaOp: + self.__ResolveToken() + return self._Token + + # Try to resolve token + def __ResolveToken(self): + if not self._Token: + raise BadExpression(ERR_EMPTY_TOKEN) + + # PCD token + if self.PcdPattern.match(self._Token): + if self._Token not in self._Symb: + raise SymbolNotFound(ERR_PCD_RESOLVE % self._Token) + self._Token = ValueExpression(self._Symb[self._Token], self._Symb)() + if type(self._Token) != type(''): + self._LiteralToken = hex(self._Token) + return + + if self._Token.startswith('"'): + self._Token = self._Token[1:-1] + elif self._Token in ["FALSE", "false", "False"]: + self._Token = False + elif self._Token in ["TRUE", "true", "True"]: + self._Token = True + else: + self.__IsNumberToken() + + def __GetNList(self, InArray=False): + self._GetSingleToken() + if not self.__IsHexLiteral(): + if InArray: + raise BadExpression(ERR_ARRAY_ELE % self._Token) + return self._Token + + self.__SkipWS() + Expr = self._Expr[self._Idx:] + if not Expr.startswith(','): + return self._Token + + NList = self._LiteralToken + while Expr.startswith(','): + NList += ',' + self._Idx += 1 + self.__SkipWS() + self._GetSingleToken() + if not self.__IsHexLiteral(): + raise BadExpression(ERR_ARRAY_ELE % self._Token) + NList += self._LiteralToken + self.__SkipWS() + Expr = self._Expr[self._Idx:] + self._Token = self._LiteralToken = NList + return self._Token + + def __IsHexLiteral(self): + if self._LiteralToken.startswith('{') and \ + self._LiteralToken.endswith('}'): + return True + + if self.HexPattern.match(self._LiteralToken): + Token = self._LiteralToken[2:] + Token = Token.lstrip('0') + if not Token: + self._LiteralToken = '0x0' + else: + self._LiteralToken = '0x' + Token + return True + return False + + def _GetToken(self): + return self.__GetNList() + + @staticmethod + def __IsIdChar(Ch): + return Ch in '._/:' or Ch.isalnum() + + # Parse operand + def _GetSingleToken(self): + self.__SkipWS() + Expr = self._Expr[self._Idx:] + if Expr.startswith('L"'): + # Skip L + self._Idx += 1 + UStr = self.__GetString() + self._Token = 'L"' + UStr + '"' + return self._Token + + self._Token = '' + if Expr: + Ch = Expr[0] + Match = self.RegGuidPattern.match(Expr) + if Match and not Expr[Match.end():Match.end()+1].isalnum() \ + and Expr[Match.end():Match.end()+1] != '_': + self._Idx += Match.end() + self._Token = ValueExpression(GuidStringToGuidStructureString(Expr[0:Match.end()]))() + return self._Token + elif self.__IsIdChar(Ch): + return self.__GetIdToken() + elif Ch == '"': + return self.__GetString() + elif Ch == '{': + return self.__GetArray() + elif Ch == '(' or Ch == ')': + self._Idx += 1 + self._Token = Ch + return self._Token + + raise BadExpression(ERR_VALID_TOKEN % Expr) + + # Parse operator + def _GetOperator(self): + self.__SkipWS() + LegalOpLst = ['&&', '||', '!=', '==', '>=', '<='] + self.NonLetterOpLst + + self._Token = '' + Expr = self._Expr[self._Idx:] + + # Reach end of expression + if not Expr: + return '' + + # Script operator: LT, GT, LE, GE, EQ, NE, and, or, xor, not + if Expr[0].isalpha(): + return self.__GetIdToken(True) + + # Start to get regular operator: +, -, <, > ... + if Expr[0] not in self.NonLetterOpLst: + return '' + + OpToken = '' + for Ch in Expr: + if Ch in self.NonLetterOpLst: + if '!' == Ch and OpToken in ['!=', '!']: + break + self._Idx += 1 + OpToken += Ch + else: + break + + if OpToken not in LegalOpLst: + raise BadExpression(ERR_OPERATOR_UNSUPPORT % OpToken) + self._Token = OpToken + return OpToken + + # Check if current token matches the operators given from OpList + def _IsOperator(self, OpList): + Idx = self._Idx + self._GetOperator() + if self._Token in OpList: + if self._Token in self.LogicalOperators: + self._Token = self.LogicalOperators[self._Token] + return True + self._Idx = Idx + return False + +if __name__ == '__main__': + pass + + diff --git a/BaseTools/Source/Python/Common/GlobalData.py b/BaseTools/Source/Python/Common/GlobalData.py index 37ae2d33eb..bc7e047676 100644 --- a/BaseTools/Source/Python/Common/GlobalData.py +++ b/BaseTools/Source/Python/Common/GlobalData.py @@ -22,9 +22,11 @@ gEcpSource = "EdkCompatibilityPkg" gOptions = None gCaseInsensitive = False -gGlobalDefines = {} gAllFiles = None +gGlobalDefines = {} +gPlatformDefines = {} +gCommandLineDefines = {} gEdkGlobal = {} gOverrideDir = {} @@ -33,8 +35,13 @@ gProcessingFile = '' gBuildingModule = '' ## Regular expression for matching macro used in DSC/DEC/INF file inclusion -gMacroPattern = re.compile("\$\(([_A-Z][_A-Z0-9]*)\)", re.UNICODE) +gMacroRefPattern = re.compile("\$\(([A-Z][_A-Z0-9]*)\)", re.UNICODE) +gMacroDefPattern = re.compile("^(DEFINE|EDK_GLOBAL)[ \t]+") +gMacroNamePattern = re.compile("^[A-Z][A-Z0-9_]*$") +# C-style wide string pattern +gWideStringPattern = re.compile('(\W|\A)L"') # # A global variable for whether current build in AutoGen phase or not. # gAutoGenPhase = False + diff --git a/BaseTools/Source/Python/Common/Misc.py b/BaseTools/Source/Python/Common/Misc.py index 731bbf1458..50504aa73c 100644 --- a/BaseTools/Source/Python/Common/Misc.py +++ b/BaseTools/Source/Python/Common/Misc.py @@ -156,7 +156,7 @@ def GuidStructureStringToGuidValueName(GuidValue): guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "") guidValueList = guidValueString.split(",") if len(guidValueList) != 11: - EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue) + EdkLogger.error(None, FORMAT_INVALID, "Invalid GUID value string [%s]" % GuidValue) return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % ( int(guidValueList[0], 16), int(guidValueList[1], 16), @@ -1431,6 +1431,9 @@ class PathClass(object): self._Key = self.Path.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target return self._Key + def _GetTimeStamp(self): + return os.stat(self.Path)[8] + def Validate(self, Type='', CaseSensitive=True): if GlobalData.gCaseInsensitive: CaseSensitive = False @@ -1465,6 +1468,7 @@ class PathClass(object): return ErrorCode, ErrorInfo Key = property(_GetFileKey) + TimeStamp = property(_GetTimeStamp) ## Parse PE image to get the required PE informaion. # @@ -1482,7 +1486,7 @@ class PeImageClass(): self.SectionHeaderList = [] self.ErrorInfo = '' try: - PeObject = open(PeFile, 'rb') + PeObject = open(PeFile, 'rb') except: self.ErrorInfo = self.FileName + ' can not be found\n' return diff --git a/BaseTools/Source/Python/Common/String.py b/BaseTools/Source/Python/Common/String.py index 4880768866..a35f728dc0 100644 --- a/BaseTools/Source/Python/Common/String.py +++ b/BaseTools/Source/Python/Common/String.py @@ -22,6 +22,7 @@ import EdkLogger as EdkLogger import GlobalData from BuildToolError import * +from CommonDataClass.Exceptions import * gHexVerPatt = re.compile('0x[a-f0-9]{4}[a-f0-9]{4}$',re.IGNORECASE) gHumanReadableVerPatt = re.compile(r'([1-9][0-9]*|0)\.[0-9]{1,2}$') @@ -39,7 +40,52 @@ gHumanReadableVerPatt = re.compile(r'([1-9][0-9]*|0)\.[0-9]{1,2}$') # @retval list() A list for splitted string # def GetSplitValueList(String, SplitTag = DataType.TAB_VALUE_SPLIT, MaxSplit = -1): - return map(lambda l: l.strip(), String.split(SplitTag, MaxSplit)) + ValueList = [] + Last = 0 + Escaped = False + InString = False + for Index in range(0, len(String)): + Char = String[Index] + + if not Escaped: + # Found a splitter not in a string, split it + if not InString and Char == SplitTag: + ValueList.append(String[Last:Index].strip()) + Last = Index+1 + if MaxSplit > 0 and len(ValueList) >= MaxSplit: + break + + if Char == '\\' and InString: + Escaped = True + elif Char == '"': + if not InString: + InString = True + else: + InString = False + else: + Escaped = False + + if Last < len(String): + ValueList.append(String[Last:].strip()) + elif Last == len(String): + ValueList.append('') + + return ValueList + +## GetSplitList +# +# Get a value list from a string with multiple values splited with SplitString +# The default SplitTag is DataType.TAB_VALUE_SPLIT +# 'AAA|BBB|CCC' -> ['AAA', 'BBB', 'CCC'] +# +# @param String: The input string to be splitted +# @param SplitStr: The split key, default is DataType.TAB_VALUE_SPLIT +# @param MaxSplit: The max number of split values, default is -1 +# +# @retval list() A list for splitted string +# +def GetSplitList(String, SplitStr = DataType.TAB_VALUE_SPLIT, MaxSplit = -1): + return map(lambda l: l.strip(), String.split(SplitStr, MaxSplit)) ## MergeArches # @@ -210,16 +256,18 @@ def ReplaceMacros(StringList, MacroDefinitions={}, SelfReplacement = False): # # @retval string The string whose macros are replaced # -def ReplaceMacro(String, MacroDefinitions={}, SelfReplacement = False): +def ReplaceMacro(String, MacroDefinitions={}, SelfReplacement=False, RaiseError=False): LastString = String - while MacroDefinitions: - MacroUsed = GlobalData.gMacroPattern.findall(String) + while String and MacroDefinitions: + MacroUsed = GlobalData.gMacroRefPattern.findall(String) # no macro found in String, stop replacing if len(MacroUsed) == 0: break for Macro in MacroUsed: if Macro not in MacroDefinitions: + if RaiseError: + raise SymbolNotFound("%s not defined" % Macro) if SelfReplacement: String = String.replace("$(%s)" % Macro, '') continue diff --git a/BaseTools/Source/Python/CommonDataClass/DataClass.py b/BaseTools/Source/Python/CommonDataClass/DataClass.py index ebb0358b0b..3d971c84cd 100644 --- a/BaseTools/Source/Python/CommonDataClass/DataClass.py +++ b/BaseTools/Source/Python/CommonDataClass/DataClass.py @@ -89,11 +89,13 @@ MODEL_META_DATA_COMPONENT = 5009 MODEL_META_DATA_USER_EXTENSION = 5010 MODEL_META_DATA_PACKAGE = 5011 MODEL_META_DATA_NMAKE = 5012 -MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF = 50013 +MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF = 5013 MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF = 5014 MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH = 5015 MODEL_META_DATA_COMMENT = 5016 MODEL_META_DATA_GLOBAL_DEFINE = 5017 +MODEL_META_DATA_SECTION_HEADER = 5100 +MODEL_META_DATA_SUBSECTION_HEADER = 5200 MODEL_EXTERNAL_DEPENDENCY = 10000 diff --git a/BaseTools/Source/Python/CommonDataClass/Exceptions.py b/BaseTools/Source/Python/CommonDataClass/Exceptions.py new file mode 100644 index 0000000000..50541e80f2 --- /dev/null +++ b/BaseTools/Source/Python/CommonDataClass/Exceptions.py @@ -0,0 +1,29 @@ +## @file +# This file is used to define common Exceptions class used in python tools +# +# Copyright (c) 2011, Intel Corporation. All rights reserved.
+# 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. + +## Exceptions used in Expression +class EvaluationException(Exception): + pass + +class BadExpression(EvaluationException): + pass + +class WrnExpression(Exception): + pass + +## Exceptions used in macro replacements +class MacroException(Exception): + pass + +class SymbolNotFound(MacroException): + pass + diff --git a/BaseTools/Source/Python/GenFds/AprioriSection.py b/BaseTools/Source/Python/GenFds/AprioriSection.py index bb40d756c8..a6dace82a6 100644 --- a/BaseTools/Source/Python/GenFds/AprioriSection.py +++ b/BaseTools/Source/Python/GenFds/AprioriSection.py @@ -79,11 +79,11 @@ class AprioriSection (AprioriSectionClassObject): InfFileName = GenFdsGlobalVariable.MacroExtend(InfFileName, Dict, Arch) if Arch != None: - Inf = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClass(InfFileName, GenFdsGlobalVariable.WorkSpaceDir), Arch] + Inf = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClass(InfFileName, GenFdsGlobalVariable.WorkSpaceDir), Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] Guid = Inf.Guid else: - Inf = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClass(InfFileName, GenFdsGlobalVariable.WorkSpaceDir), 'COMMON'] + Inf = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClass(InfFileName, GenFdsGlobalVariable.WorkSpaceDir), 'COMMON', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] Guid = Inf.Guid self.BinFileList = Inf.Module.Binaries diff --git a/BaseTools/Source/Python/GenFds/DepexSection.py b/BaseTools/Source/Python/GenFds/DepexSection.py index 39678b23e9..b7b1ae7d93 100644 --- a/BaseTools/Source/Python/GenFds/DepexSection.py +++ b/BaseTools/Source/Python/GenFds/DepexSection.py @@ -39,7 +39,10 @@ class DepexSection (DepexSectionClassObject): def __FindGuidValue(self, CName): for Arch in GenFdsGlobalVariable.ArchList: - for PkgDb in GenFdsGlobalVariable.WorkSpace.PackageList: + for PkgDb in GenFdsGlobalVariable.WorkSpace.GetPackageList(GenFdsGlobalVariable.ActivePlatform, + Arch, + GenFdsGlobalVariable.TargetName, + GenFdsGlobalVariable.ToolChainTag): if CName in PkgDb.Ppis: return PkgDb.Ppis[CName] if CName in PkgDb.Protocols: diff --git a/BaseTools/Source/Python/GenFds/Fd.py b/BaseTools/Source/Python/GenFds/Fd.py index cbfd6715ca..aa4d2e8262 100644 --- a/BaseTools/Source/Python/GenFds/Fd.py +++ b/BaseTools/Source/Python/GenFds/Fd.py @@ -71,11 +71,11 @@ class FD(FDClassObject): for RegionObj in self.RegionList : if RegionObj.RegionType == 'CAPSULE': - continue + continue if RegionObj.Offset + RegionObj.Size <= PreviousRegionStart: - pass + pass elif RegionObj.Offset <= PreviousRegionStart or (RegionObj.Offset >=PreviousRegionStart and RegionObj.Offset < PreviousRegionStart + PreviousRegionSize): - pass + pass elif RegionObj.Offset > PreviousRegionStart + PreviousRegionSize: GenFdsGlobalVariable.InfLogger('Padding region starting from offset 0x%X, with size 0x%X' %(PreviousRegionStart + PreviousRegionSize, RegionObj.Offset - (PreviousRegionStart + PreviousRegionSize))) PadRegion = Region.Region() @@ -88,7 +88,7 @@ class FD(FDClassObject): # Call each region's AddToBuffer function # if PreviousRegionSize > self.Size: - pass + pass GenFdsGlobalVariable.VerboseLogger('Call each region\'s AddToBuffer function') RegionObj.AddToBuffer (TempFdBuffer, self.BaseAddress, self.BlockSizeList, self.ErasePolarity, GenFds.ImageBinDict, self.vtfRawDict, self.DefineVarDict) diff --git a/BaseTools/Source/Python/GenFds/FdfParser.py b/BaseTools/Source/Python/GenFds/FdfParser.py index 4f555e32bb..e3a018c66c 100644 --- a/BaseTools/Source/Python/GenFds/FdfParser.py +++ b/BaseTools/Source/Python/GenFds/FdfParser.py @@ -15,6 +15,8 @@ ## # Import Modules # +import re + import Fd import Region import Fv @@ -45,6 +47,8 @@ from Common.BuildToolError import * from Common import EdkLogger from Common.Misc import PathClass from Common.String import NormPath +import Common.GlobalData as GlobalData +from Common.Expression import * from Common import GlobalData import re @@ -68,6 +72,9 @@ T_CHAR_BACKSLASH, T_CHAR_DOUBLE_QUOTE, T_CHAR_SINGLE_QUOTE, T_CHAR_STAR, T_CHAR_ SEPERATOR_TUPLE = ('=', '|', ',', '{', '}') +RegionSizePattern = re.compile("\s*(?P(?:0x|0X)?[a-fA-F0-9]+)\s*\|\s*(?P(?:0x|0X)?[a-fA-F0-9]+)\s*") +RegionSizeGuidPattern = re.compile("\s*(?P\w+\.\w+)\s*\|\s*(?P\w+\.\w+)\s*") + IncludeFileList = [] # Macro passed from command line, which has greatest priority and can NOT be overridden by those in FDF InputMacroDict = {} @@ -211,6 +218,10 @@ class FdfParser: if GenFdsGlobalVariable.WorkSpaceDir == '': GenFdsGlobalVariable.WorkSpaceDir = os.getenv("WORKSPACE") + InputMacroDict.update(GlobalData.gPlatformDefines) + InputMacroDict.update(GlobalData.gGlobalDefines) + InputMacroDict.update(GlobalData.gCommandLineDefines) + ## __IsWhiteSpace() method # # Whether char at current FileBufferPos is whitespace @@ -317,10 +328,10 @@ class FdfParser: # def __GetOneChar(self): if self.CurrentOffsetWithinLine == len(self.Profile.FileLinesList[self.CurrentLineNumber - 1]) - 1: - self.CurrentLineNumber += 1 - self.CurrentOffsetWithinLine = 0 + self.CurrentLineNumber += 1 + self.CurrentOffsetWithinLine = 0 else: - self.CurrentOffsetWithinLine += 1 + self.CurrentOffsetWithinLine += 1 ## __CurrentChar() method # @@ -564,7 +575,7 @@ class FdfParser: self.Profile.FileLinesList[IncludeLine - 1] = ''.join(TempList) self.Rewind() - + def __GetIfListCurrentItemStat(self, IfList): if len(IfList) == 0: return True @@ -574,8 +585,7 @@ class FdfParser: return False return True - - + ## PreprocessConditionalStatement() method # # Preprocess conditional statement. @@ -586,9 +596,10 @@ class FdfParser: def PreprocessConditionalStatement(self): # IfList is a stack of if branches with elements of list [Pos, CondSatisfied, BranchDetermined] IfList = [] + RegionLayoutLine = 0 while self.__GetNextToken(): if self.__Token == 'DEFINE': - if self.__GetIfListCurrentItemStat(IfList): + if self.__GetIfListCurrentItemStat(IfList): DefineLine = self.CurrentLineNumber - 1 DefineOffset = self.CurrentOffsetWithinLine - len('DEFINE') if not self.__GetNextToken(): @@ -609,60 +620,48 @@ class FdfParser: MacProfile.MacroName = Macro MacProfile.MacroValue = Value AllMacroList.append(MacProfile) + InputMacroDict[MacProfile.MacroName] = MacProfile.MacroValue self.__WipeOffArea.append(((DefineLine, DefineOffset), (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) + elif self.__Token == 'SET': + PcdPair = self.__GetNextPcdName() + PcdName = "%s.%s" % (PcdPair[1], PcdPair[0]) + if not self.__IsToken( "="): + raise Warning("expected '='", self.FileName, self.CurrentLineNumber) + if not self.__GetNextToken(): + raise Warning("expected value", self.FileName, self.CurrentLineNumber) + + Value = self.__Token + if Value.startswith("{"): + # deal with value with {} + if not self.__SkipToToken( "}"): + raise Warning("expected '}'", self.FileName, self.CurrentLineNumber) + Value += self.__SkippedChars + + InputMacroDict[PcdName] = Value elif self.__Token in ('!ifdef', '!ifndef', '!if'): IfStartPos = (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - len(self.__Token)) IfList.append([IfStartPos, None, None]) + CondLabel = self.__Token + Expression = self.__GetExpression() - MacroName, NotFlag = self.__GetMacroName() - NotDefineFlag = False - if CondLabel == '!ifndef': - NotDefineFlag = True - if CondLabel == '!ifdef' or CondLabel == '!ifndef': - if NotFlag: - raise Warning("'NOT' operation not allowed for Macro name", self.FileName, self.CurrentLineNumber) - if CondLabel == '!if': - - if not self.__GetNextOp(): - raise Warning("expected !endif", self.FileName, self.CurrentLineNumber) - - if self.__Token in ('!=', '==', '>', '<', '>=', '<='): - Op = self.__Token - if not self.__GetNextToken(): - raise Warning("expected value", self.FileName, self.CurrentLineNumber) - if self.__GetStringData(): - pass - MacroValue = self.__Token - ConditionSatisfied = self.__EvaluateConditional(MacroName, IfList[-1][0][0] + 1, Op, MacroValue) - if NotFlag: - ConditionSatisfied = not ConditionSatisfied - BranchDetermined = ConditionSatisfied - else: - self.CurrentOffsetWithinLine -= len(self.__Token) - ConditionSatisfied = self.__EvaluateConditional(MacroName, IfList[-1][0][0] + 1, None, 'Bool') - if NotFlag: - ConditionSatisfied = not ConditionSatisfied - BranchDetermined = ConditionSatisfied - IfList[-1] = [IfList[-1][0], ConditionSatisfied, BranchDetermined] - if ConditionSatisfied: - self.__WipeOffArea.append((IfList[-1][0], (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) - + ConditionSatisfied = self.__EvaluateConditional(Expression, IfList[-1][0][0] + 1, 'eval') else: - ConditionSatisfied = self.__EvaluateConditional(MacroName, IfList[-1][0][0] + 1) - if NotDefineFlag: + ConditionSatisfied = self.__EvaluateConditional(Expression, IfList[-1][0][0] + 1, 'in') + if CondLabel == '!ifndef': ConditionSatisfied = not ConditionSatisfied - BranchDetermined = ConditionSatisfied - IfList[-1] = [IfList[-1][0], ConditionSatisfied, BranchDetermined] - if ConditionSatisfied: - self.__WipeOffArea.append((IfStartPos, (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) + BranchDetermined = ConditionSatisfied + IfList[-1] = [IfList[-1][0], ConditionSatisfied, BranchDetermined] + if ConditionSatisfied: + self.__WipeOffArea.append((IfList[-1][0], (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) elif self.__Token in ('!elseif', '!else'): ElseStartPos = (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - len(self.__Token)) if len(IfList) <= 0: raise Warning("Missing !if statement", self.FileName, self.CurrentLineNumber) + if IfList[-1][1]: IfList[-1] = [ElseStartPos, False, True] self.__WipeOffArea.append((ElseStartPos, (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) @@ -670,27 +669,8 @@ class FdfParser: self.__WipeOffArea.append((IfList[-1][0], ElseStartPos)) IfList[-1] = [ElseStartPos, True, IfList[-1][2]] if self.__Token == '!elseif': - MacroName, NotFlag = self.__GetMacroName() - if not self.__GetNextOp(): - raise Warning("expected !endif", self.FileName, self.CurrentLineNumber) - - if self.__Token in ('!=', '==', '>', '<', '>=', '<='): - Op = self.__Token - if not self.__GetNextToken(): - raise Warning("expected value", self.FileName, self.CurrentLineNumber) - if self.__GetStringData(): - pass - MacroValue = self.__Token - ConditionSatisfied = self.__EvaluateConditional(MacroName, IfList[-1][0][0] + 1, Op, MacroValue) - if NotFlag: - ConditionSatisfied = not ConditionSatisfied - - else: - self.CurrentOffsetWithinLine -= len(self.__Token) - ConditionSatisfied = self.__EvaluateConditional(MacroName, IfList[-1][0][0] + 1, None, 'Bool') - if NotFlag: - ConditionSatisfied = not ConditionSatisfied - + Expression = self.__GetExpression() + ConditionSatisfied = self.__EvaluateConditional(Expression, IfList[-1][0][0] + 1, 'eval') IfList[-1] = [IfList[-1][0], ConditionSatisfied, IfList[-1][2]] if IfList[-1][1]: @@ -699,8 +679,6 @@ class FdfParser: else: IfList[-1][2] = True self.__WipeOffArea.append((IfList[-1][0], (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) - - elif self.__Token == '!endif': if IfList[-1][1]: self.__WipeOffArea.append(((self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - len('!endif')), (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) @@ -708,106 +686,48 @@ class FdfParser: self.__WipeOffArea.append((IfList[-1][0], (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) IfList.pop() + elif not IfList: # Don't use PCDs inside conditional directive + if self.CurrentLineNumber <= RegionLayoutLine: + # Don't try the same line twice + continue + RegionSize = RegionSizePattern.match(self.Profile.FileLinesList[self.CurrentLineNumber - 1]) + if not RegionSize: + RegionLayoutLine = self.CurrentLineNumber + continue + RegionSizeGuid = RegionSizeGuidPattern.match(self.Profile.FileLinesList[self.CurrentLineNumber]) + if not RegionSizeGuid: + RegionLayoutLine = self.CurrentLineNumber + 1 + continue + InputMacroDict[RegionSizeGuid.group('base')] = RegionSize.group('base') + InputMacroDict[RegionSizeGuid.group('size')] = RegionSize.group('size') + RegionLayoutLine = self.CurrentLineNumber + 1 - - if len(IfList) > 0: + if IfList: raise Warning("Missing !endif", self.FileName, self.CurrentLineNumber) self.Rewind() - def __EvaluateConditional(self, Name, Line, Op = None, Value = None): - + def __EvaluateConditional(self, Expression, Line, Op = None, Value = None): FileLineTuple = GetRealFileLine(self.FileName, Line) - if Name in InputMacroDict: - MacroValue = InputMacroDict[Name] - if Op == None: - if Value == 'Bool' and MacroValue == None or MacroValue.upper() == 'FALSE': - return False - return True - elif Op == '!=': - if Value != MacroValue: - return True - else: - return False - elif Op == '==': - if Value == MacroValue: - return True - else: - return False - else: - if (self.__IsHex(Value) or Value.isdigit()) and (self.__IsHex(MacroValue) or (MacroValue != None and MacroValue.isdigit())): - InputVal = long(Value, 0) - MacroVal = long(MacroValue, 0) - if Op == '>': - if MacroVal > InputVal: - return True - else: - return False - elif Op == '>=': - if MacroVal >= InputVal: - return True - else: - return False - elif Op == '<': - if MacroVal < InputVal: - return True - else: - return False - elif Op == '<=': - if MacroVal <= InputVal: - return True - else: - return False - else: - return False - else: - raise Warning("Value %s is not a number", self.FileName, Line) - - for Profile in AllMacroList: - if Profile.MacroName == Name and Profile.DefinedAtLine <= FileLineTuple[1]: - if Op == None: - if Value == 'Bool' and Profile.MacroValue == None or Profile.MacroValue.upper() == 'FALSE': - return False - return True - elif Op == '!=': - if Value != Profile.MacroValue: - return True - else: - return False - elif Op == '==': - if Value == Profile.MacroValue: - return True - else: - return False - else: - if (self.__IsHex(Value) or Value.isdigit()) and (self.__IsHex(Profile.MacroValue) or (Profile.MacroValue != None and Profile.MacroValue.isdigit())): - InputVal = long(Value, 0) - MacroVal = long(Profile.MacroValue, 0) - if Op == '>': - if MacroVal > InputVal: - return True - else: - return False - elif Op == '>=': - if MacroVal >= InputVal: - return True - else: - return False - elif Op == '<': - if MacroVal < InputVal: - return True - else: - return False - elif Op == '<=': - if MacroVal <= InputVal: - return True - else: - return False - else: - return False - else: - raise Warning("Value %s is not a number", self.FileName, Line) - - return False + if Op == 'eval': + try: + return ValueExpression(Expression, InputMacroDict)() + except SymbolNotFound: + return False + except WrnExpression, Excpt: + # + # Catch expression evaluation warning here. We need to report + # the precise number of line and return the evaluation result + # + EdkLogger.warn('Parser', "Suspicious expression: %s" % str(Excpt), + File=self.FileName, ExtraData=self.__CurrentLine(), + Line=Line) + return Excpt.result + except Exception, Excpt: + raise Warning("Invalid expression", *FileLineTuple) + else: + if Expression.startswith('$(') and Expression[-1] == ')': + Expression = Expression[2:-1] + return Expression in InputMacroDict ## __IsToken() method # @@ -866,6 +786,16 @@ class FdfParser: return True return False + def __GetExpression(self): + Line = self.Profile.FileLinesList[self.CurrentLineNumber - 1] + Index = len(Line) - 1 + while Line[Index] in ['\r', '\n']: + Index -= 1 + ExpressionString = self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine:Index+1] + self.CurrentOffsetWithinLine += len(ExpressionString) + ExpressionString = ExpressionString.strip() + return ExpressionString + ## __GetNextWord() method # # Get next C name from file lines @@ -1208,7 +1138,7 @@ class FdfParser: for Pos in self.__WipeOffArea: self.__ReplaceFragment(Pos[0], Pos[1]) self.Profile.FileLinesList = ["".join(list) for list in self.Profile.FileLinesList] - + while self.__GetDefines(): pass @@ -2014,8 +1944,8 @@ class FdfParser: if not IsValidBaseAddrValue.match(self.__Token.upper()): raise Warning("Unknown FV base address value '%s'" % self.__Token, self.FileName, self.CurrentLineNumber) Obj.FvBaseAddress = self.__Token - return True - + return True + ## __GetFvForceRebase() method # # Get FvForceRebase for FV @@ -2047,7 +1977,8 @@ class FdfParser: Obj.FvForceRebase = None return True - + + ## __GetFvAttributes() method # # Get attributes for FV @@ -2475,6 +2406,7 @@ class FdfParser: if ErrorCode != 0: EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo) + if not self.__IsToken( "}"): raise Warning("expected '}'", self.FileName, self.CurrentLineNumber) diff --git a/BaseTools/Source/Python/GenFds/FfsFileStatement.py b/BaseTools/Source/Python/GenFds/FfsFileStatement.py index b858549361..04527fe00f 100644 --- a/BaseTools/Source/Python/GenFds/FfsFileStatement.py +++ b/BaseTools/Source/Python/GenFds/FfsFileStatement.py @@ -71,7 +71,7 @@ class FileStatement (FileStatementClassObject) : OutputDir = os.path.join(GenFdsGlobalVariable.FfsDir, self.NameGuid) if not os.path.exists(OutputDir): - os.makedirs(OutputDir) + os.makedirs(OutputDir) Dict.update(self.DefineVarDict) SectionAlignments = None @@ -98,7 +98,7 @@ class FileStatement (FileStatementClassObject) : SectionFiles = [] Index = 0 SectionAlignments = [] - for section in self.SectionList: + for section in self.SectionList : Index = Index + 1 SecIndex = '%d' %Index # process the inside FvImage from FvSection or GuidSection diff --git a/BaseTools/Source/Python/GenFds/FfsInfStatement.py b/BaseTools/Source/Python/GenFds/FfsInfStatement.py index c6f29f6ddd..96e212cae7 100644 --- a/BaseTools/Source/Python/GenFds/FfsInfStatement.py +++ b/BaseTools/Source/Python/GenFds/FfsInfStatement.py @@ -163,7 +163,7 @@ class FfsInfStatement(FfsInfStatementClassObject): if self.CurrentArch != None: - Inf = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClassObj, self.CurrentArch] + Inf = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClassObj, self.CurrentArch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] # # Set Ffs BaseName, MdouleGuid, ModuleType, Version, OutputPath # @@ -181,7 +181,7 @@ class FfsInfStatement(FfsInfStatementClassObject): self.ShadowFromInfFile = Inf.Shadow else: - Inf = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClassObj, 'COMMON'] + Inf = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClassObj, 'COMMON', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] self.BaseName = Inf.BaseName self.ModuleGuid = Inf.Guid self.ModuleType = Inf.ModuleType @@ -363,27 +363,27 @@ class FfsInfStatement(FfsInfStatementClassObject): InfFileKey = os.path.normpath(os.path.join(GenFdsGlobalVariable.WorkSpaceDir, self.InfFileName)) DscArchList = [] - PlatformDataBase = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'IA32'] + PlatformDataBase = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'IA32', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] if PlatformDataBase != None: if InfFileKey in PlatformDataBase.Modules: DscArchList.append ('IA32') - PlatformDataBase = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'X64'] + PlatformDataBase = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'X64', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] if PlatformDataBase != None: if InfFileKey in PlatformDataBase.Modules: DscArchList.append ('X64') - PlatformDataBase = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'IPF'] + PlatformDataBase = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'IPF', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] if PlatformDataBase != None: if InfFileKey in (PlatformDataBase.Modules): DscArchList.append ('IPF') - PlatformDataBase = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'ARM'] + PlatformDataBase = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'ARM', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] if PlatformDataBase != None: if InfFileKey in (PlatformDataBase.Modules): DscArchList.append ('ARM') - PlatformDataBase = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'EBC'] + PlatformDataBase = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'EBC', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] if PlatformDataBase != None: if InfFileKey in (PlatformDataBase.Modules): DscArchList.append ('EBC') diff --git a/BaseTools/Source/Python/GenFds/Fv.py b/BaseTools/Source/Python/GenFds/Fv.py index f186ab0e73..fd5ad0e9ac 100644 --- a/BaseTools/Source/Python/GenFds/Fv.py +++ b/BaseTools/Source/Python/GenFds/Fv.py @@ -48,7 +48,7 @@ class FV (FvClassObject): self.CapsuleName = None self.FvBaseAddress = None self.FvForceRebase = None - + ## AddToBuffer() # # Generate Fv and add it to the Buffer @@ -83,13 +83,13 @@ class FV (FvClassObject): elif RegionData.upper() + 'fv' in GenFds.ImageBinDict.keys(): continue elif self.UiFvName.upper() == RegionData.upper(): - GenFdsGlobalVariable.ErrorLogger("Capsule %s in FD region can't contain a FV %s in FD region." % (self.CapsuleName, self.UiFvName.upper())) + GenFdsGlobalVariable.ErrorLogger("Capsule %s in FD region can't contain a FV %s in FD region." % (self.CapsuleName, self.UiFvName.upper())) GenFdsGlobalVariable.InfLogger( "\nGenerating %s FV" %self.UiFvName) if self.FvBaseAddress != None: - BaseAddress = self.FvBaseAddress - + BaseAddress = self.FvBaseAddress + self.__InitializeInf__(BaseAddress, BlockSize, BlockNum, ErasePloarity, VtfDict) # # First Process the Apriori section diff --git a/BaseTools/Source/Python/GenFds/GenFds.py b/BaseTools/Source/Python/GenFds/GenFds.py index cadd36c922..0219783b03 100644 --- a/BaseTools/Source/Python/GenFds/GenFds.py +++ b/BaseTools/Source/Python/GenFds/GenFds.py @@ -161,20 +161,22 @@ def main(): if len(List) == 2: if List[0].strip() == "EFI_SOURCE": GlobalData.gEfiSource = List[1].strip() + GlobalData.gGlobalDefines["EFI_SOURCE"] = GlobalData.gEfiSource continue elif List[0].strip() == "EDK_SOURCE": GlobalData.gEdkSource = List[1].strip() + GlobalData.gGlobalDefines["EDK_SOURCE"] = GlobalData.gEdkSource continue + elif List[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]: + GlobalData.gGlobalDefines[List[0].strip()] = List[1].strip() else: - GlobalData.gEdkGlobal[List[0].strip()] = List[1].strip() - FdfParser.InputMacroDict[List[0].strip()] = List[1].strip() + GlobalData.gCommandLineDefines[List[0].strip()] = List[1].strip() else: - FdfParser.InputMacroDict[List[0].strip()] = "" + GlobalData.gCommandLineDefines[List[0].strip()] = "TRUE" + os.environ["WORKSPACE"] = Workspace """call Workspace build create database""" - os.environ["WORKSPACE"] = Workspace - FdfParser.InputMacroDict["WORKSPACE"] = Workspace - BuildWorkSpace = WorkspaceDatabase(':memory:', FdfParser.InputMacroDict) + BuildWorkSpace = WorkspaceDatabase(None) BuildWorkSpace.InitDatabase() # @@ -187,15 +189,15 @@ def main(): ArchList = Options.archList.split(',') else: # EdkLogger.error("GenFds", OPTION_MISSING, "Missing build ARCH") - ArchList = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'COMMON'].SupArchList + ArchList = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'COMMON', Options.BuildTarget, Options.ToolChain].SupArchList - TargetArchList = set(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'COMMON'].SupArchList) & set(ArchList) + TargetArchList = set(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'COMMON', Options.BuildTarget, Options.ToolChain].SupArchList) & set(ArchList) if len(TargetArchList) == 0: EdkLogger.error("GenFds", GENFDS_ERROR, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList), str(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'COMMON'].SupArchList))) for Arch in ArchList: - GenFdsGlobalVariable.OutputDirFromDscDict[Arch] = NormPath(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch].OutputDirectory) - GenFdsGlobalVariable.PlatformName = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch].PlatformName + GenFdsGlobalVariable.OutputDirFromDscDict[Arch] = NormPath(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, Options.BuildTarget, Options.ToolChain].OutputDirectory) + GenFdsGlobalVariable.PlatformName = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, Options.BuildTarget, Options.ToolChain].PlatformName if (Options.outputDir): OutputDirFromCommandLine = GenFdsGlobalVariable.ReplaceWorkspaceMacro(Options.outputDir) @@ -276,7 +278,8 @@ def main(): ExtraData="Please send email to edk2-buildtools-devel@lists.sourceforge.net for help, attaching following call stack trace!\n", RaiseError=False ) - EdkLogger.quiet(traceback.format_exc()) + if Options.debug != None: + EdkLogger.quiet(traceback.format_exc()) ReturnCode = CODE_ERROR return ReturnCode @@ -482,7 +485,7 @@ class GenFds : # @retval None # def PreprocessImage(BuildDb, DscFile): - PcdDict = BuildDb.BuildObject[DscFile, 'COMMON'].Pcds + PcdDict = BuildDb.BuildObject[DscFile, 'COMMON', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Pcds PcdValue = '' for Key in PcdDict: PcdObj = PcdDict[Key] @@ -501,20 +504,20 @@ class GenFds : if Int64PcdValue > 0: TopAddress = Int64PcdValue - ModuleDict = BuildDb.BuildObject[DscFile, 'COMMON'].Modules + ModuleDict = BuildDb.BuildObject[DscFile, 'COMMON', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Modules for Key in ModuleDict: - ModuleObj = BuildDb.BuildObject[Key, 'COMMON'] + ModuleObj = BuildDb.BuildObject[Key, 'COMMON', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] print ModuleObj.BaseName + ' ' + ModuleObj.ModuleType def GenerateGuidXRefFile(BuildDb, ArchList): GuidXRefFileName = os.path.join(GenFdsGlobalVariable.FvDir, "Guid.xref") GuidXRefFile = StringIO.StringIO('') for Arch in ArchList: - PlatformDataBase = BuildDb.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch] + PlatformDataBase = BuildDb.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] for ModuleFile in PlatformDataBase.Modules: - Module = BuildDb.BuildObject[ModuleFile, Arch] + Module = BuildDb.BuildObject[ModuleFile, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] GuidXRefFile.write("%s %s\n" % (Module.Guid, Module.BaseName)) - SaveFileOnChange(GuidXRefFileName, GuidXRefFile.getvalue(), False) + SaveFileOnChange(GuidXRefFileName, GuidXRefFile.getvalue(), False) GuidXRefFile.close() GenFdsGlobalVariable.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName) diff --git a/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py b/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py index 236283751e..ea6b191bc1 100644 --- a/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py +++ b/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py @@ -117,7 +117,7 @@ class GenFdsGlobalVariable: if not BuildRuleDatabase: return {} - PathClassObj = PathClass(str(Inf.MetaFile).lstrip(GenFdsGlobalVariable.WorkSpaceDir), + PathClassObj = PathClass(Inf.MetaFile.File, GenFdsGlobalVariable.WorkSpaceDir) Macro = {} Macro["WORKSPACE" ] = GenFdsGlobalVariable.WorkSpaceDir @@ -135,6 +135,7 @@ class GenFdsGlobalVariable: Macro["ARCH" ] = Arch Macro["TOOLCHAIN" ] = GenFdsGlobalVariable.ToolChainTag Macro["TOOLCHAIN_TAG" ] = GenFdsGlobalVariable.ToolChainTag + Macro["TOOL_CHAIN_TAG" ] = GenFdsGlobalVariable.ToolChainTag Macro["TARGET" ] = GenFdsGlobalVariable.TargetName Macro["BUILD_DIR" ] = GenFdsGlobalVariable.OutputDirDict[Arch] @@ -280,8 +281,8 @@ class GenFdsGlobalVariable: FvAddressFile.writelines("[options]" + T_CHAR_LF) BsAddress = '0' for Arch in ArchList: - if GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch].BsBaseAddress: - BsAddress = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch].BsBaseAddress + if GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].BsBaseAddress: + BsAddress = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].BsBaseAddress break FvAddressFile.writelines("EFI_BOOT_DRIVER_BASE_ADDRESS = " + \ @@ -290,8 +291,8 @@ class GenFdsGlobalVariable: RtAddress = '0' for Arch in ArchList: - if GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch].RtBaseAddress: - RtAddress = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch].RtBaseAddress + if GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].RtBaseAddress: + RtAddress = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].RtBaseAddress FvAddressFile.writelines("EFI_RUNTIME_DRIVER_BASE_ADDRESS = " + \ RtAddress + \ @@ -345,10 +346,6 @@ class GenFdsGlobalVariable: @staticmethod def GenerateSection(Output, Input, Type=None, CompressionType=None, Guid=None, GuidHdrLen=None, GuidAttr=[], Ui=None, Ver=None, InputAlign=None): - if not GenFdsGlobalVariable.NeedsUpdate(Output, Input): - return - GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input)) - Cmd = ["GenSec"] if Type not in [None, '']: Cmd += ["-s", Type] @@ -388,6 +385,13 @@ class GenFdsGlobalVariable: else: Cmd += ["-o", Output] Cmd += Input + + CommandFile = Output + '.txt' + SaveFileOnChange(CommandFile, ' '.join(Cmd), False) + if not GenFdsGlobalVariable.NeedsUpdate(Output, list(Input) + [CommandFile]): + return + GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input)) + GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate section") @staticmethod @@ -402,10 +406,6 @@ class GenFdsGlobalVariable: @staticmethod def GenerateFfs(Output, Input, Type, Guid, Fixed=False, CheckSum=False, Align=None, SectionAlign=None): - if not GenFdsGlobalVariable.NeedsUpdate(Output, Input): - return - GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input)) - Cmd = ["GenFfs", "-t", Type, "-g", Guid] if Fixed == True: Cmd += ["-x"] @@ -419,6 +419,13 @@ class GenFdsGlobalVariable: Cmd += ("-i", Input[I]) if SectionAlign not in [None, '', []] and SectionAlign[I] not in [None, '']: Cmd += ("-n", SectionAlign[I]) + + CommandFile = Output + '.txt' + SaveFileOnChange(CommandFile, ' '.join(Cmd), False) + if not GenFdsGlobalVariable.NeedsUpdate(Output, list(Input) + [CommandFile]): + return + GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input)) + GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate FFS") @staticmethod @@ -436,7 +443,7 @@ class GenFdsGlobalVariable: Cmd +=["-F", "FALSE"] elif ForceRebase == True: Cmd +=["-F", "TRUE"] - + if Capsule: Cmd += ["-c"] if Dump: @@ -653,25 +660,9 @@ class GenFdsGlobalVariable: TokenCName = PcdPair[1] PcdValue = '' - for Platform in GenFdsGlobalVariable.WorkSpace.PlatformList: - # - # Only process platform which match current build option. - # - if Platform.MetaFile == GenFdsGlobalVariable.ActivePlatform: - PcdDict = Platform.Pcds - for Key in PcdDict: - PcdObj = PcdDict[Key] - if (PcdObj.TokenCName == TokenCName) and (PcdObj.TokenSpaceGuidCName == TokenSpace): - if PcdObj.Type != 'FixedAtBuild': - EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not FixedAtBuild type." % PcdPattern) - if PcdObj.DatumType != 'VOID*': - EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not VOID* datum type." % PcdPattern) - - PcdValue = PcdObj.DefaultValue - return PcdValue - - for Package in GenFdsGlobalVariable.WorkSpace.PackageList: - PcdDict = Package.Pcds + for Arch in GenFdsGlobalVariable.ArchList: + Platform = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] + PcdDict = Platform.Pcds for Key in PcdDict: PcdObj = PcdDict[Key] if (PcdObj.TokenCName == TokenCName) and (PcdObj.TokenSpaceGuidCName == TokenSpace): @@ -682,6 +673,22 @@ class GenFdsGlobalVariable: PcdValue = PcdObj.DefaultValue return PcdValue + + for Package in GenFdsGlobalVariable.WorkSpace.GetPackageList(GenFdsGlobalVariable.ActivePlatform, + Arch, + GenFdsGlobalVariable.TargetName, + GenFdsGlobalVariable.ToolChainTag): + PcdDict = Package.Pcds + for Key in PcdDict: + PcdObj = PcdDict[Key] + if (PcdObj.TokenCName == TokenCName) and (PcdObj.TokenSpaceGuidCName == TokenSpace): + if PcdObj.Type != 'FixedAtBuild': + EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not FixedAtBuild type." % PcdPattern) + if PcdObj.DatumType != 'VOID*': + EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not VOID* datum type." % PcdPattern) + + PcdValue = PcdObj.DefaultValue + return PcdValue return PcdValue diff --git a/BaseTools/Source/Python/GenFds/Section.py b/BaseTools/Source/Python/GenFds/Section.py index ef9720a660..6f57ad5681 100644 --- a/BaseTools/Source/Python/GenFds/Section.py +++ b/BaseTools/Source/Python/GenFds/Section.py @@ -1,7 +1,7 @@ ## @file # section base class # -# Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.
+# Copyright (c) 2007-2011, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License diff --git a/BaseTools/Source/Python/PatchPcdValue/PatchPcdValue.py b/BaseTools/Source/Python/PatchPcdValue/PatchPcdValue.py index a8c36ea3c3..3f6c575128 100644 --- a/BaseTools/Source/Python/PatchPcdValue/PatchPcdValue.py +++ b/BaseTools/Source/Python/PatchPcdValue/PatchPcdValue.py @@ -23,7 +23,6 @@ from optparse import make_option from Common.BuildToolError import * import Common.EdkLogger as EdkLogger from Common.BuildVersion import gBUILD_VERSION - import array # Version and Copyright diff --git a/BaseTools/Source/Python/UPT/Library/ParserValidate.py b/BaseTools/Source/Python/UPT/Library/ParserValidate.py index d6b9a096c7..8efb56a61a 100644 --- a/BaseTools/Source/Python/UPT/Library/ParserValidate.py +++ b/BaseTools/Source/Python/UPT/Library/ParserValidate.py @@ -17,6 +17,7 @@ PaserValidate import os.path import re +import platform from Library.DataType import MODULE_LIST from Library.DataType import COMPONENT_TYPE_LIST @@ -281,9 +282,14 @@ def IsValidPath(Path, Root): # @param Path: path to be checked # def IsValidInstallPath(Path): - if os.path.isabs(Path): - return False - + if platform.platform().find("Windows") >= 0: + if os.path.isabs(Path): + return False + else: + if Path[1:2] == ':' or Path.find('\\') >=0: + return False + if os.path.isabs(Path): + return False if Path.startswith('.'): return False diff --git a/BaseTools/Source/Python/Workspace/MetaDataTable.py b/BaseTools/Source/Python/Workspace/MetaDataTable.py index 64f0480c37..34ef4903df 100644 --- a/BaseTools/Source/Python/Workspace/MetaDataTable.py +++ b/BaseTools/Source/Python/Workspace/MetaDataTable.py @@ -140,6 +140,10 @@ class Table(object): def SetEndFlag(self): self.Exec("insert into %s values(%s)" % (self.Table, self._DUMMY_)) + # + # Need to execution commit for table data changed. + # + self.Cur.connection.commit() def IsIntegral(self): Result = self.Exec("select min(ID) from %s" % (self.Table)) @@ -147,6 +151,9 @@ class Table(object): return False return True + def GetAll(self): + return self.Exec("select * from %s where ID > 0 order by ID" % (self.Table)) + ## TableFile # # This class defined a table used for file @@ -198,19 +205,15 @@ class TableFile(Table): # # @retval FileID: The ID after record is inserted # - def InsertFile(self, FileFullPath, Model): - (Filepath, Name) = os.path.split(FileFullPath) - (Root, Ext) = os.path.splitext(FileFullPath) - TimeStamp = os.stat(FileFullPath)[8] - File = FileClass(-1, Name, Ext, Filepath, FileFullPath, Model, '', [], [], []) + def InsertFile(self, File, Model): return self.Insert( - Name, - Ext, - Filepath, - FileFullPath, - Model, - TimeStamp - ) + File.Name, + File.Ext, + File.Dir, + File.Path, + Model, + File.TimeStamp + ) ## Get ID of a given file # @@ -218,8 +221,8 @@ class TableFile(Table): # # @retval ID ID value of given file in the table # - def GetFileId(self, FilePath): - QueryScript = "select ID from %s where FullPath = '%s'" % (self.Table, FilePath) + def GetFileId(self, File): + QueryScript = "select ID from %s where FullPath = '%s'" % (self.Table, str(File)) RecordList = self.Exec(QueryScript) if len(RecordList) == 0: return None diff --git a/BaseTools/Source/Python/Workspace/MetaFileParser.py b/BaseTools/Source/Python/Workspace/MetaFileParser.py index 4bad21298a..bfa7054396 100644 --- a/BaseTools/Source/Python/Workspace/MetaFileParser.py +++ b/BaseTools/Source/Python/Workspace/MetaFileParser.py @@ -15,14 +15,75 @@ # Import Modules # import os +import re import time import copy import Common.EdkLogger as EdkLogger +import Common.GlobalData as GlobalData + from CommonDataClass.DataClass import * from Common.DataType import * from Common.String import * -from Common.Misc import Blist, GuidStructureStringToGuidString, CheckPcdDatum +from Common.Misc import GuidStructureStringToGuidString, CheckPcdDatum, PathClass, AnalyzePcdData +from Common.Expression import * +from CommonDataClass.Exceptions import * + +from MetaFileTable import MetaFileStorage + +## A decorator used to parse macro definition +def ParseMacro(Parser): + def MacroParser(self): + Match = gMacroDefPattern.match(self._CurrentLine) + if not Match: + # Not 'DEFINE/EDK_GLOBAL' statement, call decorated method + Parser(self) + return + + TokenList = GetSplitValueList(self._CurrentLine[Match.end(1):], TAB_EQUAL_SPLIT, 1) + # Syntax check + if not TokenList[0]: + EdkLogger.error('Parser', FORMAT_INVALID, "No macro name given", + ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) + if len(TokenList) < 2: + TokenList.append('') + + Type = Match.group(1) + Name, Value = TokenList + # Global macros can be only defined via environment variable + if Name in GlobalData.gGlobalDefines: + EdkLogger.error('Parser', FORMAT_INVALID, "%s can only be defined via environment variable" % Name, + ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) + # Only upper case letters, digit and '_' are allowed + if not gMacroNamePattern.match(Name): + EdkLogger.error('Parser', FORMAT_INVALID, "The macro name must be in the pattern [A-Z][A-Z0-9_]*", + ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) + + self._ItemType = self.DataType[Type] + # DEFINE defined macros + if self._ItemType == MODEL_META_DATA_DEFINE: + if self._SectionType == MODEL_META_DATA_HEADER: + self._FileLocalMacros[Name] = Value + else: + SectionDictKey = self._SectionType, self._Scope[0][0], self._Scope[0][1] + if SectionDictKey not in self._SectionsMacroDict: + self._SectionsMacroDict[SectionDictKey] = {} + SectionLocalMacros = self._SectionsMacroDict[SectionDictKey] + SectionLocalMacros[Name] = Value + # EDK_GLOBAL defined macros + elif type(self) != DscParser: + EdkLogger.error('Parser', FORMAT_INVALID, "EDK_GLOBAL can only be used in .dsc file", + ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) + elif self._SectionType != MODEL_META_DATA_HEADER: + EdkLogger.error('Parser', FORMAT_INVALID, "EDK_GLOBAL can only be used under [Defines] section", + ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) + elif (Name in self._FileLocalMacros) and (self._FileLocalMacros[Name] != Value): + EdkLogger.error('Parser', FORMAT_INVALID, "EDK_GLOBAL defined a macro with the same name and different value as one defined by 'DEFINE'", + ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) + + self._ValueList = [Type, Name, Value] + + return MacroParser ## Base class of parser # @@ -73,23 +134,21 @@ class MetaFileParser(object): # @param Owner Owner ID (for sub-section parsing) # @param From ID from which the data comes (for !INCLUDE directive) # - def __init__(self, FilePath, FileType, Table, Macros=None, Owner=-1, From=-1): - # prevent re-initialization - if hasattr(self, "_Table"): - return + def __init__(self, FilePath, FileType, Table, Owner=-1, From=-1): self._Table = Table + self._RawTable = Table self._FileType = FileType self.MetaFile = FilePath - self._FileDir = os.path.dirname(self.MetaFile) - self._Macros = copy.copy(Macros) - self._Macros["WORKSPACE"] = os.environ["WORKSPACE"] + self._FileDir = self.MetaFile.Dir + self._Defines = {} + self._FileLocalMacros = {} + self._SectionsMacroDict = {} # for recursive parsing - self._Owner = Owner + self._Owner = [Owner] self._From = From # parsr status for parsing - self._Content = None self._ValueList = ['', '', '', '', ''] self._Scope = [] self._LineIndex = 0 @@ -99,9 +158,13 @@ class MetaFileParser(object): self._InSubsection = False self._SubsectionType = MODEL_UNKNOWN self._SubsectionName = '' + self._ItemType = MODEL_UNKNOWN self._LastItem = -1 self._Enabled = 0 self._Finished = False + self._PostProcessed = False + # Different version of meta-file has different way to parse. + self._Version = 0 ## Store the parsed data in table def _Store(self, *Args): @@ -111,6 +174,10 @@ class MetaFileParser(object): def Start(self): raise NotImplementedError + ## Notify a post-process is needed + def DoPostProcess(self): + self._PostProcessed = False + ## Set parsing complete flag in both class and table def _Done(self): self._Finished = True @@ -118,15 +185,8 @@ class MetaFileParser(object): if self._From == -1: self._Table.SetEndFlag() - ## Return the table containg parsed data - # - # If the parse complete flag is not set, this method will try to parse the - # file before return the table - # - def _GetTable(self): - if not self._Finished: - self.Start() - return self._Table + def _PostProcess(self): + self._PostProcessed = True ## Get the parse complete flag def _GetFinished(self): @@ -138,12 +198,30 @@ class MetaFileParser(object): ## Use [] style to query data in table, just for readability # - # DataInfo = [data_type, scope1(arch), scope2(platform,moduletype)] + # DataInfo = [data_type, scope1(arch), scope2(platform/moduletype)] # def __getitem__(self, DataInfo): if type(DataInfo) != type(()): DataInfo = (DataInfo,) - return self.Table.Query(*DataInfo) + + # Parse the file first, if necessary + if not self._Finished: + if self._RawTable.IsIntegrity(): + self._Finished = True + else: + self._Table = self._RawTable + self._PostProcessed = False + self.Start() + + # No specific ARCH or Platform given, use raw data + if self._RawTable and (len(DataInfo) == 1 or DataInfo[1] == None): + return self._RawTable.Query(*DataInfo) + + # Do post-process if necessary + if not self._PostProcessed: + self._PostProcess() + + return self._Table.Query(*DataInfo) ## Data parser for the common format in different type of file # @@ -151,6 +229,7 @@ class MetaFileParser(object): # # xxx1 | xxx2 | xxx3 # + @ParseMacro def _CommonParser(self): TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT) self._ValueList[0:len(TokenList)] = TokenList @@ -159,15 +238,14 @@ class MetaFileParser(object): # # Only path can have macro used. So we need to replace them before use. # + @ParseMacro def _PathParser(self): TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT) self._ValueList[0:len(TokenList)] = TokenList - if len(self._Macros) > 0: - for Index in range(0, len(self._ValueList)): - Value = self._ValueList[Index] - if Value == None or Value == '': - continue - self._ValueList[Index] = NormPath(Value, self._Macros) + # Don't do macro replacement for dsc file at this point + if type(self) != DscParser: + Macros = self._Macros + self._ValueList = [ReplaceMacro(Value, Macros) for Value in self._ValueList] ## Skip unsupported data def _Skip(self): @@ -217,47 +295,47 @@ class MetaFileParser(object): if 'COMMON' in ArchList and len(ArchList) > 1: EdkLogger.error('Parser', FORMAT_INVALID, "'common' ARCH must not be used with specific ARCHs", File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine) + # If the section information is needed later, it should be stored in database + self._ValueList[0] = self._SectionName ## [defines] section parser + @ParseMacro def _DefineParser(self): TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1) - self._ValueList[0:len(TokenList)] = TokenList - if self._ValueList[1] == '': - EdkLogger.error('Parser', FORMAT_INVALID, "No value specified", + self._ValueList[1:len(TokenList)] = TokenList + if not self._ValueList[1]: + EdkLogger.error('Parser', FORMAT_INVALID, "No name specified", ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) - - ## DEFINE name=value parser - def _MacroParser(self): - TokenList = GetSplitValueList(self._CurrentLine, ' ', 1) - MacroType = TokenList[0] - if len(TokenList) < 2 or TokenList[1] == '': - EdkLogger.error('Parser', FORMAT_INVALID, "No macro name/value given", - ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) - TokenList = GetSplitValueList(TokenList[1], TAB_EQUAL_SPLIT, 1) - if TokenList[0] == '': - EdkLogger.error('Parser', FORMAT_INVALID, "No macro name given", + if not self._ValueList[2]: + EdkLogger.error('Parser', FORMAT_INVALID, "No value specified", ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) - # Macros defined in the command line override ones defined in the meta-data file - if not TokenList[0] in self._Macros: - if len(TokenList) == 1: - self._Macros[TokenList[0]] = '' - else: - # keep the macro definition for later use - self._Macros[TokenList[0]] = ReplaceMacro(TokenList[1], self._Macros, False) + Name, Value = self._ValueList[1], self._ValueList[2] + # Sometimes, we need to make differences between EDK and EDK2 modules + if Name == 'INF_VERSION': + try: + self._Version = int(Value, 0) + except: + EdkLogger.error('Parser', FORMAT_INVALID, "Invalid version number", + ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) - return TokenList[0], self._Macros[TokenList[0]] + Value = ReplaceMacro(Value, self._Macros) + if type(self) == InfParser and self._Version < 0x00010005: + # EDK module allows using defines as macros + self._FileLocalMacros[Name] = Value + self._Defines[Name] = Value ## [BuildOptions] section parser + @ParseMacro def _BuildOptionParser(self): TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1) TokenList2 = GetSplitValueList(TokenList[0], ':', 1) if len(TokenList2) == 2: - self._ValueList[0] = TokenList2[0] # toolchain family - self._ValueList[1] = TokenList2[1] # keys + self._ValueList[0] = TokenList2[0] # toolchain family + self._ValueList[1] = TokenList2[1] # keys else: self._ValueList[1] = TokenList[0] - if len(TokenList) == 2: # value + if len(TokenList) == 2 and type(self) != DscParser: # value self._ValueList[2] = ReplaceMacro(TokenList[1], self._Macros) if self._ValueList[1].count('_') != 4: @@ -270,9 +348,27 @@ class MetaFileParser(object): Line=self._LineIndex+1 ) + def _GetMacros(self): + Macros = {} + Macros.update(self._FileLocalMacros) + Macros.update(self._GetApplicableSectionMacro()) + return Macros + + + ## Get section Macros that are applicable to current line, which may come from other sections + ## that share the same name while scope is wider + def _GetApplicableSectionMacro(self): + Macros = {} + + for SectionType, Scope1, Scope2 in self._SectionsMacroDict: + if (SectionType == self._SectionType) and (Scope1 == self._Scope[0][0] or Scope1 == "COMMON") and (Scope2 == self._Scope[0][1] or Scope2 == "COMMON"): + Macros.update(self._SectionsMacroDict[(SectionType, Scope1, Scope2)]) + + return Macros + _SectionParser = {} - Table = property(_GetTable) Finished = property(_GetFinished, _SetFinished) + _Macros = property(_GetMacros) ## INF file parser class @@ -287,6 +383,7 @@ class InfParser(MetaFileParser): DataType = { TAB_UNKNOWN.upper() : MODEL_UNKNOWN, TAB_INF_DEFINES.upper() : MODEL_META_DATA_HEADER, + TAB_DSC_DEFINES_DEFINE : MODEL_META_DATA_DEFINE, TAB_BUILD_OPTIONS.upper() : MODEL_META_DATA_BUILD_OPTION, TAB_INCLUDES.upper() : MODEL_EFI_INCLUDE, TAB_LIBRARIES.upper() : MODEL_EFI_LIBRARY_INSTANCE, @@ -316,26 +413,30 @@ class InfParser(MetaFileParser): # @param Table Database used to retrieve module/package information # @param Macros Macros used for replacement in file # - def __init__(self, FilePath, FileType, Table, Macros=None): - MetaFileParser.__init__(self, FilePath, FileType, Table, Macros) + def __init__(self, FilePath, FileType, Table): + # prevent re-initialization + if hasattr(self, "_Table"): + return + MetaFileParser.__init__(self, FilePath, FileType, Table) ## Parser starter def Start(self): NmakeLine = '' + Content = '' try: - self._Content = open(self.MetaFile, 'r').readlines() + Content = open(str(self.MetaFile), 'r').readlines() except: EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile) # parse the file line by line IsFindBlockComment = False - for Index in range(0, len(self._Content)): + for Index in range(0, len(Content)): # skip empty, commented, block commented lines - Line = CleanString(self._Content[Index], AllowCppStyleComment=True) + Line = CleanString(Content[Index], AllowCppStyleComment=True) NextLine = '' - if Index + 1 < len(self._Content): - NextLine = CleanString(self._Content[Index + 1]) + if Index + 1 < len(Content): + NextLine = CleanString(Content[Index + 1]) if Line == '': continue if Line.find(DataType.TAB_COMMENT_EDK_START) > -1: @@ -353,6 +454,29 @@ class InfParser(MetaFileParser): # section header if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END: self._SectionHeaderParser() + # Check invalid sections + if self._Version < 0x00010005: + if self._SectionType in [MODEL_META_DATA_BUILD_OPTION, + MODEL_EFI_LIBRARY_CLASS, + MODEL_META_DATA_PACKAGE, + MODEL_PCD_FIXED_AT_BUILD, + MODEL_PCD_PATCHABLE_IN_MODULE, + MODEL_PCD_FEATURE_FLAG, + MODEL_PCD_DYNAMIC_EX, + MODEL_PCD_DYNAMIC, + MODEL_EFI_GUID, + MODEL_EFI_PROTOCOL, + MODEL_EFI_PPI, + MODEL_META_DATA_USER_EXTENSION]: + EdkLogger.error('Parser', FORMAT_INVALID, + "Section [%s] is not allowed in inf file without version" % (self._SectionName), + ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) + elif self._SectionType in [MODEL_EFI_INCLUDE, + MODEL_EFI_LIBRARY_INSTANCE, + MODEL_META_DATA_NMAKE]: + EdkLogger.error('Parser', FORMAT_INVALID, + "Section [%s] is not allowed in inf file with version 0x%08x" % (self._SectionName, self._Version), + ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) continue # merge two lines specified by '\' in section NMAKE elif self._SectionType == MODEL_META_DATA_NMAKE: @@ -370,10 +494,6 @@ class InfParser(MetaFileParser): else: self._CurrentLine = NmakeLine + Line NmakeLine = '' - elif Line.upper().startswith('DEFINE '): - # file private macros - self._MacroParser() - continue # section content self._ValueList = ['','',''] @@ -392,7 +512,7 @@ class InfParser(MetaFileParser): self._ValueList[2], Arch, Platform, - self._Owner, + self._Owner[-1], self._LineIndex+1, -1, self._LineIndex+1, @@ -411,9 +531,13 @@ class InfParser(MetaFileParser): def _IncludeParser(self): TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT) self._ValueList[0:len(TokenList)] = TokenList - if len(self._Macros) > 0: + Macros = self._Macros + if Macros: for Index in range(0, len(self._ValueList)): Value = self._ValueList[Index] + if not Value: + continue + if Value.upper().find('$(EFI_SOURCE)\Edk'.upper()) > -1 or Value.upper().find('$(EFI_SOURCE)/Edk'.upper()) > -1: Value = '$(EDK_SOURCE)' + Value[17:] if Value.find('$(EFI_SOURCE)') > -1 or Value.find('$(EDK_SOURCE)') > -1: @@ -425,34 +549,30 @@ class InfParser(MetaFileParser): else: Value = '$(EFI_SOURCE)/' + Value - if Value == None or Value == '': - continue - self._ValueList[Index] = NormPath(Value, self._Macros) + self._ValueList[Index] = ReplaceMacro(Value, Macros) ## Parse [Sources] section # # Only path can have macro used. So we need to replace them before use. # + @ParseMacro def _SourceFileParser(self): TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT) self._ValueList[0:len(TokenList)] = TokenList + Macros = self._Macros # For Acpi tables, remove macro like ' TABLE_NAME=Sata1' - if 'COMPONENT_TYPE' in self._Macros: - if self._Macros['COMPONENT_TYPE'].upper() == 'ACPITABLE': + if 'COMPONENT_TYPE' in Macros: + if self._Defines['COMPONENT_TYPE'].upper() == 'ACPITABLE': self._ValueList[0] = GetSplitValueList(self._ValueList[0], ' ', 1)[0] - if self._Macros['BASE_NAME'] == 'Microcode': + if self._Defines['BASE_NAME'] == 'Microcode': pass - if len(self._Macros) > 0: - for Index in range(0, len(self._ValueList)): - Value = self._ValueList[Index] - if Value == None or Value == '': - continue - self._ValueList[Index] = NormPath(Value, self._Macros) + self._ValueList = [ReplaceMacro(Value, Macros) for Value in self._ValueList] ## Parse [Binaries] section # # Only path can have macro used. So we need to replace them before use. # + @ParseMacro def _BinaryFileParser(self): TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 2) if len(TokenList) < 2: @@ -468,27 +588,19 @@ class InfParser(MetaFileParser): ExtraData=self._CurrentLine + " ( | [| ])", File=self.MetaFile, Line=self._LineIndex+1) self._ValueList[0:len(TokenList)] = TokenList - self._ValueList[1] = NormPath(self._ValueList[1], self._Macros) + self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros) - ## [defines] section parser - def _DefineParser(self): - TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1) - self._ValueList[0:len(TokenList)] = TokenList - if self._ValueList[1] == '': - EdkLogger.error('Parser', FORMAT_INVALID, "No value specified", - ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) - self._Macros[TokenList[0]] = ReplaceMacro(TokenList[1], self._Macros, False) - - ## [nmake] section parser (EDK.x style only) + ## [nmake] section parser (Edk.x style only) def _NmakeParser(self): TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1) self._ValueList[0:len(TokenList)] = TokenList # remove macros - self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros, False) + self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros) # remove self-reference in macro setting #self._ValueList[1] = ReplaceMacro(self._ValueList[1], {self._ValueList[0]:''}) ## [FixedPcd], [FeaturePcd], [PatchPcd], [Pcd] and [PcdEx] sections parser + @ParseMacro def _PcdParser(self): TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1) ValueList = GetSplitValueList(TokenList[0], TAB_SPLIT) @@ -503,6 +615,7 @@ class InfParser(MetaFileParser): EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified", ExtraData=self._CurrentLine + " (.)", File=self.MetaFile, Line=self._LineIndex+1) + # if value are 'True', 'true', 'TRUE' or 'False', 'false', 'FALSE', replace with integer 1 or 0. if self._ValueList[2] != '': InfPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1) @@ -512,18 +625,19 @@ class InfParser(MetaFileParser): self._ValueList[2] = TokenList[1].replace(InfPcdValueList[0], '0', 1); ## [depex] section parser + @ParseMacro def _DepexParser(self): self._ValueList[0:1] = [self._CurrentLine] _SectionParser = { MODEL_UNKNOWN : MetaFileParser._Skip, - MODEL_META_DATA_HEADER : _DefineParser, + MODEL_META_DATA_HEADER : MetaFileParser._DefineParser, MODEL_META_DATA_BUILD_OPTION : MetaFileParser._BuildOptionParser, - MODEL_EFI_INCLUDE : _IncludeParser, # for EDK.x modules - MODEL_EFI_LIBRARY_INSTANCE : MetaFileParser._CommonParser, # for EDK.x modules + MODEL_EFI_INCLUDE : _IncludeParser, # for Edk.x modules + MODEL_EFI_LIBRARY_INSTANCE : MetaFileParser._CommonParser, # for Edk.x modules MODEL_EFI_LIBRARY_CLASS : MetaFileParser._PathParser, MODEL_META_DATA_PACKAGE : MetaFileParser._PathParser, - MODEL_META_DATA_NMAKE : _NmakeParser, # for EDK.x modules + MODEL_META_DATA_NMAKE : _NmakeParser, # for Edk.x modules MODEL_PCD_FIXED_AT_BUILD : _PcdParser, MODEL_PCD_PATCHABLE_IN_MODULE : _PcdParser, MODEL_PCD_FEATURE_FLAG : _PcdParser, @@ -566,6 +680,8 @@ class DscParser(MetaFileParser): TAB_COMPONENTS.upper() : MODEL_META_DATA_COMPONENT, TAB_COMPONENTS_SOURCE_OVERRIDE_PATH.upper() : MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH, TAB_DSC_DEFINES.upper() : MODEL_META_DATA_HEADER, + TAB_DSC_DEFINES_DEFINE : MODEL_META_DATA_DEFINE, + TAB_DSC_DEFINES_EDKGLOBAL : MODEL_META_DATA_GLOBAL_DEFINE, TAB_INCLUDE.upper() : MODEL_META_DATA_INCLUDE, TAB_IF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_IF, TAB_IF_DEF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF, @@ -575,37 +691,26 @@ class DscParser(MetaFileParser): TAB_END_IF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF, } - # sections which allow "!include" directive - _IncludeAllowedSection = [ - TAB_COMMON_DEFINES.upper(), - TAB_LIBRARIES.upper(), - TAB_LIBRARY_CLASSES.upper(), - TAB_SKUIDS.upper(), - TAB_COMPONENTS.upper(), - TAB_BUILD_OPTIONS.upper(), - TAB_PCDS_FIXED_AT_BUILD_NULL.upper(), - TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper(), - TAB_PCDS_FEATURE_FLAG_NULL.upper(), - TAB_PCDS_DYNAMIC_DEFAULT_NULL.upper(), - TAB_PCDS_DYNAMIC_HII_NULL.upper(), - TAB_PCDS_DYNAMIC_VPD_NULL.upper(), - TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL.upper(), - TAB_PCDS_DYNAMIC_EX_HII_NULL.upper(), - TAB_PCDS_DYNAMIC_EX_VPD_NULL.upper(), - ] - - # operators which can be used in "!if/!ifdef/!ifndef" directives - _OP_ = { - "!" : lambda a: not a, - "!=" : lambda a,b: a!=b, - "==" : lambda a,b: a==b, - ">" : lambda a,b: a>b, - "<" : lambda a,b: a" : lambda a,b: a>=b, - ">=" : lambda a,b: a>=b, - "<=" : lambda a,b: a<=b, - "=<" : lambda a,b: a<=b, - } + # Valid names in define section + DefineKeywords = [ + "DSC_SPECIFICATION", + "PLATFORM_NAME", + "PLATFORM_GUID", + "PLATFORM_VERSION", + "SKUID_IDENTIFIER", + "SUPPORTED_ARCHITECTURES", + "BUILD_TARGETS", + "OUTPUT_DIRECTORY", + "FLASH_DEFINITION", + "BUILD_NUMBER", + "RFC_LANGUAGES", + "ISO_LANGUAGES", + "TIME_STAMP_FILE", + "VPD_TOOL_GUID", + "FIX_LOAD_TOP_MEMORY_ADDRESS" + ] + + SymbolPattern = ValueExpression.SymbolPattern ## Constructor of DscParser # @@ -618,162 +723,99 @@ class DscParser(MetaFileParser): # @param Owner Owner ID (for sub-section parsing) # @param From ID from which the data comes (for !INCLUDE directive) # - def __init__(self, FilePath, FileType, Table, Macros=None, Owner=-1, From=-1): - MetaFileParser.__init__(self, FilePath, FileType, Table, Macros, Owner, From) + def __init__(self, FilePath, FileType, Table, Owner=-1, From=-1): + # prevent re-initialization + if hasattr(self, "_Table"): + return + MetaFileParser.__init__(self, FilePath, FileType, Table, Owner, From) + self._Version = 0x00010005 # Only EDK2 dsc file is supported # to store conditional directive evaluation result - self._Eval = Blist() + self._DirectiveStack = [] + self._DirectiveEvalStack = [] + self._Enabled = 1 + + # Final valid replacable symbols + self._Symbols = {} + # + # Map the ID between the original table and new table to track + # the owner item + # + self._IdMapping = {-1:-1} ## Parser starter def Start(self): + Content = '' try: - if self._Content == None: - self._Content = open(self.MetaFile, 'r').readlines() + Content = open(str(self.MetaFile), 'r').readlines() except: EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile) - for Index in range(0, len(self._Content)): - Line = CleanString(self._Content[Index]) + for Index in range(0, len(Content)): + Line = CleanString(Content[Index]) # skip empty line if Line == '': continue + self._CurrentLine = Line self._LineIndex = Index - if self._InSubsection and self._Owner == -1: - self._Owner = self._LastItem + if self._InSubsection and self._Owner[-1] == -1: + self._Owner.append(self._LastItem) # section header if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END: - self._SectionHeaderParser() - continue + self._SectionType = MODEL_META_DATA_SECTION_HEADER # subsection ending - elif Line[0] == '}': + elif Line[0] == '}' and self._InSubsection: self._InSubsection = False self._SubsectionType = MODEL_UNKNOWN self._SubsectionName = '' - self._Owner = -1 + self._Owner.pop() continue # subsection header elif Line[0] == TAB_OPTION_START and Line[-1] == TAB_OPTION_END: - self._SubsectionHeaderParser() - continue + self._SubsectionType = MODEL_META_DATA_SUBSECTION_HEADER # directive line elif Line[0] == '!': self._DirectiveParser() continue - # file private macros - elif Line.upper().startswith('DEFINE '): - if self._Enabled < 0: - # Do not parse the macro and add it to self._Macros dictionary if directives - # statement is evaluated to false. - continue - - (Name, Value) = self._MacroParser() - # Make the defined macro in DSC [Defines] section also - # available for FDF file. - if self._SectionName == TAB_COMMON_DEFINES.upper(): - self._LastItem = self._Store( - MODEL_META_DATA_GLOBAL_DEFINE, - Name, - Value, - '', - 'COMMON', - 'COMMON', - self._Owner, - self._From, - self._LineIndex+1, - -1, - self._LineIndex+1, - -1, - self._Enabled - ) - continue - elif Line.upper().startswith('EDK_GLOBAL '): - if self._Enabled < 0: - # Do not parse the macro and add it to self._Macros dictionary - # if previous directives statement is evaluated to false. - continue - - (Name, Value) = self._MacroParser() - for Arch, ModuleType in self._Scope: - self._LastItem = self._Store( - MODEL_META_DATA_DEFINE, - Name, - Value, - '', - Arch, - 'COMMON', - self._Owner, - self._From, - self._LineIndex+1, - -1, - self._LineIndex+1, - -1, - self._Enabled - ) - continue - # section content if self._InSubsection: SectionType = self._SubsectionType - SectionName = self._SubsectionName else: SectionType = self._SectionType - SectionName = self._SectionName + self._ItemType = SectionType self._ValueList = ['', '', ''] self._SectionParser[SectionType](self) if self._ValueList == None: continue - # # Model, Value1, Value2, Value3, Arch, ModuleType, BelongsToItem=-1, BelongsToFile=-1, # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1 # for Arch, ModuleType in self._Scope: self._LastItem = self._Store( - SectionType, - self._ValueList[0], - self._ValueList[1], - self._ValueList[2], - Arch, - ModuleType, - self._Owner, - self._From, - self._LineIndex+1, - -1, - self._LineIndex+1, - -1, - self._Enabled - ) + self._ItemType, + self._ValueList[0], + self._ValueList[1], + self._ValueList[2], + Arch, + ModuleType, + self._Owner[-1], + self._From, + self._LineIndex+1, + -1, + self._LineIndex+1, + -1, + self._Enabled + ) + + if self._DirectiveStack: + Type, Line, Text = self._DirectiveStack[-1] + EdkLogger.error('Parser', FORMAT_INVALID, "No matching '!endif' found", + ExtraData=Text, File=self.MetaFile, Line=Line) self._Done() - ## [defines] section parser - def _DefineParser(self): - TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1) - if len(TokenList) < 2: - EdkLogger.error('Parser', FORMAT_INVALID, "No value specified", - ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) - # 'FLASH_DEFINITION', 'OUTPUT_DIRECTORY' need special processing - if TokenList[0] in ['FLASH_DEFINITION', 'OUTPUT_DIRECTORY']: - TokenList[1] = NormPath(TokenList[1], self._Macros) - self._ValueList[0:len(TokenList)] = TokenList - # Treat elements in the [defines] section as global macros for FDF file. - self._LastItem = self._Store( - MODEL_META_DATA_GLOBAL_DEFINE, - TokenList[0], - TokenList[1], - '', - 'COMMON', - 'COMMON', - self._Owner, - self._From, - self._LineIndex+1, - -1, - self._LineIndex+1, - -1, - self._Enabled - ) - ## parser def _SubsectionHeaderParser(self): self._SubsectionName = self._CurrentLine[1:-1].upper() @@ -782,13 +824,16 @@ class DscParser(MetaFileParser): else: self._SubsectionType = MODEL_UNKNOWN EdkLogger.warn("Parser", "Unrecognized sub-section", File=self.MetaFile, - Line=self._LineIndex+1, ExtraData=self._CurrentLine) + Line=self._LineIndex+1, ExtraData=self._CurrentLine) + self._ValueList[0] = self._SubsectionName ## Directive statement parser def _DirectiveParser(self): self._ValueList = ['','',''] TokenList = GetSplitValueList(self._CurrentLine, ' ', 1) self._ValueList[0:len(TokenList)] = TokenList + + # Syntax check DirectiveName = self._ValueList[0].upper() if DirectiveName not in self.DataType: EdkLogger.error("Parser", FORMAT_INVALID, "Unknown directive [%s]" % DirectiveName, @@ -797,134 +842,89 @@ class DscParser(MetaFileParser): EdkLogger.error("Parser", FORMAT_INVALID, "Missing expression", File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine) - # keep the directive in database first - self._LastItem = self._Store( - self.DataType[DirectiveName], - self._ValueList[0], - self._ValueList[1], - self._ValueList[2], - 'COMMON', - 'COMMON', - self._Owner, - self._From, - self._LineIndex + 1, - -1, - self._LineIndex + 1, - -1, - 0 - ) - - # process the directive - if DirectiveName == "!INCLUDE": - if not self._SectionName in self._IncludeAllowedSection: - EdkLogger.error("Parser", FORMAT_INVALID, File=self.MetaFile, Line=self._LineIndex+1, - ExtraData="'!include' is not allowed under section [%s]" % self._SectionName) - # the included file must be relative to workspace - IncludedFile = os.path.join(os.environ["WORKSPACE"], NormPath(self._ValueList[1], self._Macros)) - Parser = DscParser(IncludedFile, self._FileType, self._Table, self._Macros, From=self._LastItem) - # set the parser status with current status - Parser._SectionName = self._SectionName - Parser._SectionType = self._SectionType - Parser._Scope = self._Scope - Parser._Enabled = self._Enabled - try: - Parser.Start() - except: - EdkLogger.error("Parser", PARSER_ERROR, File=self.MetaFile, Line=self._LineIndex+1, - ExtraData="Failed to parse content in file %s" % IncludedFile) - # insert an imaginary token in the DSC table to indicate its external dependency on another file - self._Store(MODEL_EXTERNAL_DEPENDENCY, IncludedFile, str(os.stat(IncludedFile)[8]), "") - # update current status with sub-parser's status - self._SectionName = Parser._SectionName - self._SectionType = Parser._SectionType - self._Scope = Parser._Scope - self._Enabled = Parser._Enabled - self._Macros.update(Parser._Macros) - else: - if DirectiveName in ["!IF", "!IFDEF", "!IFNDEF"]: - # evaluate the expression - Result = self._Evaluate(self._ValueList[1]) - if DirectiveName == "!IFNDEF": - Result = not Result - self._Eval.append(Result) - elif DirectiveName in ["!ELSEIF"]: - # evaluate the expression - self._Eval[-1] = (not self._Eval[-1]) & self._Evaluate(self._ValueList[1]) - elif DirectiveName in ["!ELSE"]: - self._Eval[-1] = not self._Eval[-1] - elif DirectiveName in ["!ENDIF"]: - if len(self._Eval) > 0: - self._Eval.pop() - else: - EdkLogger.error("Parser", FORMAT_INVALID, "!IF..[!ELSE]..!ENDIF doesn't match", - File=self.MetaFile, Line=self._LineIndex+1) - if self._Eval.Result == False: - self._Enabled = 0 - len(self._Eval) - else: - self._Enabled = len(self._Eval) - ## Evaluate the Token for its value; for now only macros are supported. - def _EvaluateToken(self, TokenName, Expression): - if TokenName.startswith("$(") and TokenName.endswith(")"): - Name = TokenName[2:-1] - return self._Macros.get(Name) - else: - EdkLogger.error('Parser', FORMAT_INVALID, "Unknown operand '%(Token)s', " - "please use '$(%(Token)s)' if '%(Token)s' is a macro" % {"Token" : TokenName}, - File=self.MetaFile, Line=self._LineIndex+1, ExtraData=Expression) - - ## Evaluate the value of expression in "if/ifdef/ifndef" directives - def _Evaluate(self, Expression): - TokenList = Expression.split() - TokenNumber = len(TokenList) - # one operand, guess it's just a macro name - if TokenNumber == 1: - TokenValue = self._EvaluateToken(TokenList[0], Expression) - return TokenValue != None - # two operands, suppose it's "!xxx" format - elif TokenNumber == 2: - Op = TokenList[0] - if Op not in self._OP_: - EdkLogger.error('Parser', FORMAT_INVALID, "Unsupported operator [%s]" % Op, File=self.MetaFile, - Line=self._LineIndex+1, ExtraData=Expression) - if TokenList[1].upper() == 'TRUE': - Value = True + ItemType = self.DataType[DirectiveName] + if ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF: + # Remove all directives between !if and !endif, including themselves + while self._DirectiveStack: + # Remove any !else or !elseif + DirectiveInfo = self._DirectiveStack.pop() + if DirectiveInfo[0] in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF, + MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF, + MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]: + break else: - Value = False - return self._OP_[Op](Value) - # three operands - elif TokenNumber == 3: - TokenValue = TokenList[0] - if TokenValue != "": - if TokenValue[0] in ["'", '"'] and TokenValue[-1] in ["'", '"']: - TokenValue = TokenValue[1:-1] - if TokenValue.startswith("$(") and TokenValue.endswith(")"): - TokenValue = self._EvaluateToken(TokenValue, Expression) - if TokenValue == None: - return False - if TokenValue != "": - if TokenValue[0] in ["'", '"'] and TokenValue[-1] in ["'", '"']: - TokenValue = TokenValue[1:-1] - - Value = TokenList[2] - if Value != "": - if Value[0] in ["'", '"'] and Value[-1] in ["'", '"']: - Value = Value[1:-1] - if Value.startswith("$(") and Value.endswith(")"): - Value = self._EvaluateToken(Value, Expression) - if Value == None: - return False - if Value != "": - if Value[0] in ["'", '"'] and Value[-1] in ["'", '"']: - Value = Value[1:-1] - Op = TokenList[1] - if Op not in self._OP_: - EdkLogger.error('Parser', FORMAT_INVALID, "Unsupported operator [%s]" % Op, File=self.MetaFile, - Line=self._LineIndex+1, ExtraData=Expression) - return self._OP_[Op](TokenValue, Value) - else: - EdkLogger.error('Parser', FORMAT_INVALID, File=self.MetaFile, Line=self._LineIndex+1, - ExtraData=Expression) + EdkLogger.error("Parser", FORMAT_INVALID, "Redundant '!endif'", + File=self.MetaFile, Line=self._LineIndex+1, + ExtraData=self._CurrentLine) + elif ItemType != MODEL_META_DATA_INCLUDE: + # Break if there's a !else is followed by a !elseif + if ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF and \ + self._DirectiveStack and \ + self._DirectiveStack[-1][0] == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE: + EdkLogger.error("Parser", FORMAT_INVALID, "'!elseif' after '!else'", + File=self.MetaFile, Line=self._LineIndex+1, + ExtraData=self._CurrentLine) + self._DirectiveStack.append((ItemType, self._LineIndex+1, self._CurrentLine)) + elif self._From > 0: + EdkLogger.error('Parser', FORMAT_INVALID, + "No '!include' allowed in included file", + ExtraData=self._CurrentLine, File=self.MetaFile, + Line=self._LineIndex+1) + + # + # Model, Value1, Value2, Value3, Arch, ModuleType, BelongsToItem=-1, BelongsToFile=-1, + # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1 + # + self._LastItem = self._Store( + ItemType, + self._ValueList[0], + self._ValueList[1], + self._ValueList[2], + 'COMMON', + 'COMMON', + self._Owner[-1], + self._From, + self._LineIndex+1, + -1, + self._LineIndex+1, + -1, + 0 + ) + + ## [defines] section parser + @ParseMacro + def _DefineParser(self): + TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1) + self._ValueList[1:len(TokenList)] = TokenList + + # Syntax check + if not self._ValueList[1]: + EdkLogger.error('Parser', FORMAT_INVALID, "No name specified", + ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) + if not self._ValueList[2]: + EdkLogger.error('Parser', FORMAT_INVALID, "No value specified", + ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) + if not self._ValueList[1] in self.DefineKeywords: + EdkLogger.error('Parser', FORMAT_INVALID, + "Unknown keyword found: %s. " + "If this is a macro you must " + "add it as a DEFINE in the DSC" % self._ValueList[1], + ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) + self._Defines[self._ValueList[1]] = self._ValueList[2] + self._ItemType = self.DataType[TAB_DSC_DEFINES.upper()] + + @ParseMacro + def _SkuIdParser(self): + TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT) + if len(TokenList) != 2: + EdkLogger.error('Parser', FORMAT_INVALID, "Correct format is '|'", + ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) + self._ValueList[0:len(TokenList)] = TokenList + + ## Parse Edk style of library modules + def _LibraryInstanceParser(self): + self._ValueList[0] = self._CurrentLine ## PCD sections parser # @@ -940,8 +940,9 @@ class DscParser(MetaFileParser): # [PcdsDynamicVpd] # [PcdsDynamicHii] # + @ParseMacro def _PcdParser(self): - TokenList = GetSplitValueList(ReplaceMacro(self._CurrentLine, self._Macros), TAB_VALUE_SPLIT, 1) + TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1) self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT) if len(TokenList) == 2: self._ValueList[2] = TokenList[1] @@ -959,17 +960,18 @@ class DscParser(MetaFileParser): self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '1', 1); elif DscPcdValueList[0] in ['False', 'false', 'FALSE']: self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '0', 1); - + ## [components] section parser + @ParseMacro def _ComponentParser(self): if self._CurrentLine[-1] == '{': self._ValueList[0] = self._CurrentLine[0:-1].strip() self._InSubsection = True else: self._ValueList[0] = self._CurrentLine - if len(self._Macros) > 0: - self._ValueList[0] = NormPath(self._ValueList[0], self._Macros) + ## [LibraryClasses] section + @ParseMacro def _LibraryClassParser(self): TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT) if len(TokenList) < 2: @@ -984,35 +986,357 @@ class DscParser(MetaFileParser): EdkLogger.error('Parser', FORMAT_INVALID, "No library instance specified", ExtraData=self._CurrentLine + " (|)", File=self.MetaFile, Line=self._LineIndex+1) + self._ValueList[0:len(TokenList)] = TokenList - if len(self._Macros) > 0: - self._ValueList[1] = NormPath(self._ValueList[1], self._Macros) def _CompponentSourceOverridePathParser(self): - if len(self._Macros) > 0: - self._ValueList[0] = NormPath(self._CurrentLine, self._Macros) + self._ValueList[0] = self._CurrentLine + + ## [BuildOptions] section parser + @ParseMacro + def _BuildOptionParser(self): + TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1) + TokenList2 = GetSplitValueList(TokenList[0], ':', 1) + if len(TokenList2) == 2: + self._ValueList[0] = TokenList2[0] # toolchain family + self._ValueList[1] = TokenList2[1] # keys + else: + self._ValueList[1] = TokenList[0] + if len(TokenList) == 2: # value + self._ValueList[2] = TokenList[1] + + if self._ValueList[1].count('_') != 4: + EdkLogger.error( + 'Parser', + FORMAT_INVALID, + "'%s' must be in format of ____FLAGS" % self._ValueList[1], + ExtraData=self._CurrentLine, + File=self.MetaFile, + Line=self._LineIndex+1 + ) + + ## Override parent's method since we'll do all macro replacements in parser + def _GetMacros(self): + Macros = {} + Macros.update(self._FileLocalMacros) + Macros.update(self._GetApplicableSectionMacro()) + Macros.update(GlobalData.gEdkGlobal) + Macros.update(GlobalData.gPlatformDefines) + Macros.update(GlobalData.gCommandLineDefines) + # PCD cannot be referenced in macro definition + if self._ItemType not in [MODEL_META_DATA_DEFINE, MODEL_META_DATA_GLOBAL_DEFINE]: + Macros.update(self._Symbols) + return Macros + + def _PostProcess(self): + Processer = { + MODEL_META_DATA_SECTION_HEADER : self.__ProcessSectionHeader, + MODEL_META_DATA_SUBSECTION_HEADER : self.__ProcessSubsectionHeader, + MODEL_META_DATA_HEADER : self.__ProcessDefine, + MODEL_META_DATA_DEFINE : self.__ProcessDefine, + MODEL_META_DATA_GLOBAL_DEFINE : self.__ProcessDefine, + MODEL_META_DATA_INCLUDE : self.__ProcessDirective, + MODEL_META_DATA_CONDITIONAL_STATEMENT_IF : self.__ProcessDirective, + MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE : self.__ProcessDirective, + MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF : self.__ProcessDirective, + MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF : self.__ProcessDirective, + MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF : self.__ProcessDirective, + MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF : self.__ProcessDirective, + MODEL_EFI_SKU_ID : self.__ProcessSkuId, + MODEL_EFI_LIBRARY_INSTANCE : self.__ProcessLibraryInstance, + MODEL_EFI_LIBRARY_CLASS : self.__ProcessLibraryClass, + MODEL_PCD_FIXED_AT_BUILD : self.__ProcessPcd, + MODEL_PCD_PATCHABLE_IN_MODULE : self.__ProcessPcd, + MODEL_PCD_FEATURE_FLAG : self.__ProcessPcd, + MODEL_PCD_DYNAMIC_DEFAULT : self.__ProcessPcd, + MODEL_PCD_DYNAMIC_HII : self.__ProcessPcd, + MODEL_PCD_DYNAMIC_VPD : self.__ProcessPcd, + MODEL_PCD_DYNAMIC_EX_DEFAULT : self.__ProcessPcd, + MODEL_PCD_DYNAMIC_EX_HII : self.__ProcessPcd, + MODEL_PCD_DYNAMIC_EX_VPD : self.__ProcessPcd, + MODEL_META_DATA_COMPONENT : self.__ProcessComponent, + MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH : self.__ProcessSourceOverridePath, + MODEL_META_DATA_BUILD_OPTION : self.__ProcessBuildOption, + MODEL_UNKNOWN : self._Skip, + MODEL_META_DATA_USER_EXTENSION : self._Skip, + } + + self._Table = MetaFileStorage(self._RawTable.Cur, self.MetaFile, MODEL_FILE_DSC, True) + self._Table.Create() + self._DirectiveStack = [] + self._DirectiveEvalStack = [] + self._FileWithError = self.MetaFile + self._FileLocalMacros = {} + self._SectionsMacroDict = {} + GlobalData.gPlatformDefines = {} + + # Get all macro and PCD which has straitforward value + self.__RetrievePcdValue() + self._Content = self._RawTable.GetAll() + self._ContentIndex = 0 + while self._ContentIndex < len(self._Content) : + Id, self._ItemType, V1, V2, V3, S1, S2, Owner, self._From, \ + LineStart, ColStart, LineEnd, ColEnd, Enabled = self._Content[self._ContentIndex] + + if self._From < 0: + self._FileWithError = self.MetaFile + + self._ContentIndex += 1 + + self._Scope = [[S1, S2]] + self._LineIndex = LineStart - 1 + self._ValueList = [V1, V2, V3] + + try: + Processer[self._ItemType]() + except EvaluationException, Excpt: + # + # Only catch expression evaluation error here. We need to report + # the precise number of line on which the error occurred + # + EdkLogger.error('Parser', FORMAT_INVALID, "Invalid expression: %s" % str(Excpt), + File=self._FileWithError, ExtraData=' '.join(self._ValueList), + Line=self._LineIndex+1) + except MacroException, Excpt: + EdkLogger.error('Parser', FORMAT_INVALID, str(Excpt), + File=self._FileWithError, ExtraData=' '.join(self._ValueList), + Line=self._LineIndex+1) + + if self._ValueList == None: + continue + + NewOwner = self._IdMapping.get(Owner, -1) + self._Enabled = int((not self._DirectiveEvalStack) or (False not in self._DirectiveEvalStack)) + self._LastItem = self._Store( + self._ItemType, + self._ValueList[0], + self._ValueList[1], + self._ValueList[2], + S1, + S2, + NewOwner, + self._From, + self._LineIndex+1, + -1, + self._LineIndex+1, + -1, + self._Enabled + ) + self._IdMapping[Id] = self._LastItem + + GlobalData.gPlatformDefines.update(self._FileLocalMacros) + self._PostProcessed = True + self._Content = None + + def __ProcessSectionHeader(self): + self._SectionName = self._ValueList[0] + if self._SectionName in self.DataType: + self._SectionType = self.DataType[self._SectionName] + else: + self._SectionType = MODEL_UNKNOWN + + def __ProcessSubsectionHeader(self): + self._SubsectionName = self._ValueList[0] + if self._SubsectionName in self.DataType: + self._SubsectionType = self.DataType[self._SubsectionName] + else: + self._SubsectionType = MODEL_UNKNOWN + + def __RetrievePcdValue(self): + Records = self._RawTable.Query(MODEL_PCD_FEATURE_FLAG, BelongsToItem=-1.0) + for TokenSpaceGuid,PcdName,Value,Dummy2,Dummy3,ID,Line in Records: + Value, DatumType, MaxDatumSize = AnalyzePcdData(Value) + # Only use PCD whose value is straitforward (no macro and PCD) + if self.SymbolPattern.findall(Value): + continue + Name = TokenSpaceGuid + '.' + PcdName + # Don't use PCD with different values. + if Name in self._Symbols and self._Symbols[Name] != Value: + self._Symbols.pop(Name) + continue + self._Symbols[Name] = Value + + Records = self._RawTable.Query(MODEL_PCD_FIXED_AT_BUILD, BelongsToItem=-1.0) + for TokenSpaceGuid,PcdName,Value,Dummy2,Dummy3,ID,Line in Records: + Value, DatumType, MaxDatumSize = AnalyzePcdData(Value) + # Only use PCD whose value is straitforward (no macro and PCD) + if self.SymbolPattern.findall(Value): + continue + Name = TokenSpaceGuid+'.'+PcdName + # Don't use PCD with different values. + if Name in self._Symbols and self._Symbols[Name] != Value: + self._Symbols.pop(Name) + continue + self._Symbols[Name] = Value + + def __ProcessDefine(self): + if not self._Enabled: + return + + Type, Name, Value = self._ValueList + Value = ReplaceMacro(Value, self._Macros, False) + if self._ItemType == MODEL_META_DATA_DEFINE: + if self._SectionType == MODEL_META_DATA_HEADER: + self._FileLocalMacros[Name] = Value + else: + SectionDictKey = self._SectionType, self._Scope[0][0], self._Scope[0][1] + if SectionDictKey not in self._SectionsMacroDict: + self._SectionsMacroDict[SectionDictKey] = {} + SectionLocalMacros = self._SectionsMacroDict[SectionDictKey] + SectionLocalMacros[Name] = Value + elif self._ItemType == MODEL_META_DATA_GLOBAL_DEFINE: + GlobalData.gEdkGlobal[Name] = Value + + # + # Keyword in [Defines] section can be used as Macros + # + if (self._ItemType == MODEL_META_DATA_HEADER) and (self._SectionType == MODEL_META_DATA_HEADER): + self._FileLocalMacros[Name] = Value + + self._ValueList = [Type, Name, Value] + + def __ProcessDirective(self): + Result = None + if self._ItemType in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF, + MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF]: + Macros = self._Macros + Macros.update(GlobalData.gGlobalDefines) + try: + Result = ValueExpression(self._ValueList[1], Macros)() + except SymbolNotFound, Exc: + EdkLogger.debug(EdkLogger.DEBUG_5, str(Exc), self._ValueList[1]) + Result = False + except WrnExpression, Excpt: + # + # Catch expression evaluation warning here. We need to report + # the precise number of line and return the evaluation result + # + EdkLogger.warn('Parser', "Suspicious expression: %s" % str(Excpt), + File=self._FileWithError, ExtraData=' '.join(self._ValueList), + Line=self._LineIndex+1) + Result = Excpt.result + + if self._ItemType in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF, + MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF, + MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]: + self._DirectiveStack.append(self._ItemType) + if self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_IF: + Result = bool(Result) + else: + Macro = self._ValueList[1] + Macro = Macro[2:-1] if (Macro.startswith("$(") and Macro.endswith(")")) else Macro + Result = Macro in self._Macros + if self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF: + Result = not Result + self._DirectiveEvalStack.append(Result) + elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF: + self._DirectiveStack.append(self._ItemType) + self._DirectiveEvalStack[-1] = not self._DirectiveEvalStack[-1] + self._DirectiveEvalStack.append(bool(Result)) + elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE: + self._DirectiveStack[-1] = self._ItemType + self._DirectiveEvalStack[-1] = not self._DirectiveEvalStack[-1] + elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF: + # Back to the nearest !if/!ifdef/!ifndef + while self._DirectiveStack: + self._DirectiveEvalStack.pop() + Directive = self._DirectiveStack.pop() + if Directive in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF, + MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF, + MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE, + MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]: + break + elif self._ItemType == MODEL_META_DATA_INCLUDE: + # The included file must be relative to workspace + IncludedFile = NormPath(ReplaceMacro(self._ValueList[1], self._Macros, RaiseError=True)) + IncludedFile = PathClass(IncludedFile, GlobalData.gWorkspace) + ErrorCode, ErrorInfo = IncludedFile.Validate() + if ErrorCode != 0: + EdkLogger.error('parser', ErrorCode, File=self._FileWithError, + Line=self._LineIndex+1, ExtraData=ErrorInfo) + + self._FileWithError = IncludedFile + + IncludedFileTable = MetaFileStorage(self._Table.Cur, IncludedFile, MODEL_FILE_DSC, False) + Owner = self._Content[self._ContentIndex-1][0] + Parser = DscParser(IncludedFile, self._FileType, IncludedFileTable, + Owner=Owner, From=Owner) + + # set the parser status with current status + Parser._SectionName = self._SectionName + Parser._SectionType = self._SectionType + Parser._Scope = self._Scope + Parser._Enabled = self._Enabled + # Parse the included file + Parser.Start() + + # update current status with sub-parser's status + self._SectionName = Parser._SectionName + self._SectionType = Parser._SectionType + self._Scope = Parser._Scope + self._Enabled = Parser._Enabled + + # Insert all records in the table for the included file into dsc file table + Records = IncludedFileTable.GetAll() + if Records: + self._Content[self._ContentIndex:self._ContentIndex] = Records + + def __ProcessSkuId(self): + self._ValueList = [ReplaceMacro(Value, self._Macros, RaiseError=True) + for Value in self._ValueList] + + def __ProcessLibraryInstance(self): + self._ValueList = [ReplaceMacro(Value, self._Macros) for Value in self._ValueList] + + def __ProcessLibraryClass(self): + self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros, RaiseError=True) + + def __ProcessPcd(self): + ValueList = GetSplitValueList(self._ValueList[2]) + if len(ValueList) > 1 and ValueList[1] == 'VOID*': + PcdValue = ValueList[0] + ValueList[0] = ReplaceMacro(PcdValue, self._Macros) + else: + PcdValue = ValueList[-1] + ValueList[-1] = ReplaceMacro(PcdValue, self._Macros) + + self._ValueList[2] = '|'.join(ValueList) + + def __ProcessComponent(self): + self._ValueList[0] = ReplaceMacro(self._ValueList[0], self._Macros) + + def __ProcessSourceOverridePath(self): + self._ValueList[0] = ReplaceMacro(self._ValueList[0], self._Macros) + + def __ProcessBuildOption(self): + self._ValueList = [ReplaceMacro(Value, self._Macros, RaiseError=False) + for Value in self._ValueList] _SectionParser = { - MODEL_META_DATA_HEADER : _DefineParser, - MODEL_EFI_SKU_ID : MetaFileParser._CommonParser, - MODEL_EFI_LIBRARY_INSTANCE : MetaFileParser._PathParser, - MODEL_EFI_LIBRARY_CLASS : _LibraryClassParser, - MODEL_PCD_FIXED_AT_BUILD : _PcdParser, - MODEL_PCD_PATCHABLE_IN_MODULE : _PcdParser, - MODEL_PCD_FEATURE_FLAG : _PcdParser, - MODEL_PCD_DYNAMIC_DEFAULT : _PcdParser, - MODEL_PCD_DYNAMIC_HII : _PcdParser, - MODEL_PCD_DYNAMIC_VPD : _PcdParser, - MODEL_PCD_DYNAMIC_EX_DEFAULT : _PcdParser, - MODEL_PCD_DYNAMIC_EX_HII : _PcdParser, - MODEL_PCD_DYNAMIC_EX_VPD : _PcdParser, - MODEL_META_DATA_COMPONENT : _ComponentParser, - MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH : _CompponentSourceOverridePathParser, - MODEL_META_DATA_BUILD_OPTION : MetaFileParser._BuildOptionParser, - MODEL_UNKNOWN : MetaFileParser._Skip, - MODEL_META_DATA_USER_EXTENSION : MetaFileParser._Skip, + MODEL_META_DATA_HEADER : _DefineParser, + MODEL_EFI_SKU_ID : _SkuIdParser, + MODEL_EFI_LIBRARY_INSTANCE : _LibraryInstanceParser, + MODEL_EFI_LIBRARY_CLASS : _LibraryClassParser, + MODEL_PCD_FIXED_AT_BUILD : _PcdParser, + MODEL_PCD_PATCHABLE_IN_MODULE : _PcdParser, + MODEL_PCD_FEATURE_FLAG : _PcdParser, + MODEL_PCD_DYNAMIC_DEFAULT : _PcdParser, + MODEL_PCD_DYNAMIC_HII : _PcdParser, + MODEL_PCD_DYNAMIC_VPD : _PcdParser, + MODEL_PCD_DYNAMIC_EX_DEFAULT : _PcdParser, + MODEL_PCD_DYNAMIC_EX_HII : _PcdParser, + MODEL_PCD_DYNAMIC_EX_VPD : _PcdParser, + MODEL_META_DATA_COMPONENT : _ComponentParser, + MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH : _CompponentSourceOverridePathParser, + MODEL_META_DATA_BUILD_OPTION : _BuildOptionParser, + MODEL_UNKNOWN : MetaFileParser._Skip, + MODEL_META_DATA_USER_EXTENSION : MetaFileParser._Skip, + MODEL_META_DATA_SECTION_HEADER : MetaFileParser._SectionHeaderParser, + MODEL_META_DATA_SUBSECTION_HEADER : _SubsectionHeaderParser, } + _Macros = property(_GetMacros) + ## DEC file parser class # # @param FilePath The path of platform description file @@ -1045,20 +1369,24 @@ class DecParser(MetaFileParser): # @param Table Database used to retrieve module/package information # @param Macros Macros used for replacement in file # - def __init__(self, FilePath, FileType, Table, Macro=None): - MetaFileParser.__init__(self, FilePath, FileType, Table, Macro, -1) + def __init__(self, FilePath, FileType, Table): + # prevent re-initialization + if hasattr(self, "_Table"): + return + MetaFileParser.__init__(self, FilePath, FileType, Table, -1) self._Comments = [] + self._Version = 0x00010005 # Only EDK2 dec file is supported ## Parser starter def Start(self): + Content = '' try: - if self._Content == None: - self._Content = open(self.MetaFile, 'r').readlines() + Content = open(str(self.MetaFile), 'r').readlines() except: EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile) - for Index in range(0, len(self._Content)): - Line, Comment = CleanString2(self._Content[Index]) + for Index in range(0, len(Content)): + Line, Comment = CleanString2(Content[Index]) self._CurrentLine = Line self._LineIndex = Index @@ -1074,9 +1402,6 @@ class DecParser(MetaFileParser): self._SectionHeaderParser() self._Comments = [] continue - elif Line.startswith('DEFINE '): - self._MacroParser() - continue elif len(self._SectionType) == 0: self._Comments = [] continue @@ -1100,7 +1425,7 @@ class DecParser(MetaFileParser): self._ValueList[2], Arch, ModuleType, - self._Owner, + self._Owner[-1], self._LineIndex+1, -1, self._LineIndex+1, @@ -1180,6 +1505,7 @@ class DecParser(MetaFileParser): File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine) ## [guids], [ppis] and [protocols] section parser + @ParseMacro def _GuidParser(self): TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1) if len(TokenList) < 2: @@ -1210,6 +1536,7 @@ class DecParser(MetaFileParser): # [PcdsDynamicEx # [PcdsDynamic] # + @ParseMacro def _PcdParser(self): TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1) self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT) @@ -1268,6 +1595,7 @@ class DecParser(MetaFileParser): if not IsValid: EdkLogger.error('Parser', FORMAT_INVALID, Cause, ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1) + if ValueList[0] in ['True', 'true', 'TRUE']: ValueList[0] = '1' elif ValueList[0] in ['False', 'false', 'FALSE']: diff --git a/BaseTools/Source/Python/Workspace/MetaFileTable.py b/BaseTools/Source/Python/Workspace/MetaFileTable.py index d8dacacd64..f20eab9688 100644 --- a/BaseTools/Source/Python/Workspace/MetaFileTable.py +++ b/BaseTools/Source/Python/Workspace/MetaFileTable.py @@ -14,13 +14,58 @@ ## # Import Modules # +import uuid + import Common.EdkLogger as EdkLogger -from MetaDataTable import Table + +from MetaDataTable import Table, TableFile from MetaDataTable import ConvertToSqlString +from CommonDataClass.DataClass import MODEL_FILE_DSC, MODEL_FILE_DEC, MODEL_FILE_INF, \ + MODEL_FILE_OTHERS -## Python class representation of table storing module data -class ModuleTable(Table): +class MetaFileTable(Table): # TRICK: use file ID as the part before '.' + _ID_STEP_ = 0.00000001 + _ID_MAX_ = 0.99999999 + + ## Constructor + def __init__(self, Cursor, MetaFile, FileType, Temporary): + self.MetaFile = MetaFile + + self._FileIndexTable = TableFile(Cursor) + self._FileIndexTable.Create(False) + + FileId = self._FileIndexTable.GetFileId(MetaFile) + if not FileId: + FileId = self._FileIndexTable.InsertFile(MetaFile, FileType) + + if Temporary: + TableName = "_%s_%s_%s" % (FileType, FileId, uuid.uuid4().hex) + else: + TableName = "_%s_%s" % (FileType, FileId) + + #Table.__init__(self, Cursor, TableName, FileId, False) + Table.__init__(self, Cursor, TableName, FileId, Temporary) + self.Create(not self.IsIntegrity()) + + def IsIntegrity(self): + try: + Result = self.Cur.execute("select ID from %s where ID<0" % (self.Table)).fetchall() + if not Result: + return False + + TimeStamp = self.MetaFile.TimeStamp + if TimeStamp != self._FileIndexTable.GetFileTimeStamp(self.IdBase): + # update the timestamp in database + self._FileIndexTable.SetFileTimeStamp(self.IdBase, TimeStamp) + return False + except Exception, Exc: + EdkLogger.debug(EdkLogger.DEBUG_5, str(Exc)) + return False + return True + +## Python class representation of table storing module data +class ModuleTable(MetaFileTable): _ID_STEP_ = 0.00000001 _ID_MAX_ = 0.99999999 _COLUMN_ = ''' @@ -42,8 +87,8 @@ class ModuleTable(Table): _DUMMY_ = "-1, -1, '====', '====', '====', '====', '====', -1, -1, -1, -1, -1, -1" ## Constructor - def __init__(self, Cursor, Name='Inf', IdBase=0, Temporary=False): - Table.__init__(self, Cursor, Name, IdBase, Temporary) + def __init__(self, Cursor, MetaFile, Temporary): + MetaFileTable.__init__(self, Cursor, MetaFile, MODEL_FILE_INF, Temporary) ## Insert a record into table Inf # @@ -100,9 +145,7 @@ class ModuleTable(Table): return self.Exec(SqlCommand) ## Python class representation of table storing package data -class PackageTable(Table): - _ID_STEP_ = 0.00000001 - _ID_MAX_ = 0.99999999 +class PackageTable(MetaFileTable): _COLUMN_ = ''' ID REAL PRIMARY KEY, Model INTEGER NOT NULL, @@ -122,8 +165,8 @@ class PackageTable(Table): _DUMMY_ = "-1, -1, '====', '====', '====', '====', '====', -1, -1, -1, -1, -1, -1" ## Constructor - def __init__(self, Cursor, Name='Dec', IdBase=0, Temporary=False): - Table.__init__(self, Cursor, Name, IdBase, Temporary) + def __init__(self, Cursor, MetaFile, Temporary): + MetaFileTable.__init__(self, Cursor, MetaFile, MODEL_FILE_DEC, Temporary) ## Insert table # @@ -179,9 +222,7 @@ class PackageTable(Table): return self.Exec(SqlCommand) ## Python class representation of table storing platform data -class PlatformTable(Table): - _ID_STEP_ = 0.00000001 - _ID_MAX_ = 0.99999999 +class PlatformTable(MetaFileTable): _COLUMN_ = ''' ID REAL PRIMARY KEY, Model INTEGER NOT NULL, @@ -202,8 +243,8 @@ class PlatformTable(Table): _DUMMY_ = "-1, -1, '====', '====', '====', '====', '====', -1, -1, -1, -1, -1, -1, -1" ## Constructor - def __init__(self, Cursor, Name='Dsc', IdBase=0, Temporary=False): - Table.__init__(self, Cursor, Name, IdBase, Temporary) + def __init__(self, Cursor, MetaFile, Temporary): + MetaFileTable.__init__(self, Cursor, MetaFile, MODEL_FILE_DSC, Temporary) ## Insert table # @@ -254,7 +295,7 @@ class PlatformTable(Table): # @retval: A recordSet of all found records # def Query(self, Model, Scope1=None, Scope2=None, BelongsToItem=None, FromItem=None): - ConditionString = "Model=%s AND Enabled>=0" % Model + ConditionString = "Model=%s AND Enabled>0" % Model ValueString = "Value1,Value2,Value3,Scope1,Scope2,ID,StartLine" if Scope1 != None and Scope1 != 'COMMON': @@ -273,3 +314,36 @@ class PlatformTable(Table): SqlCommand = "SELECT %s FROM %s WHERE %s" % (ValueString, self.Table, ConditionString) return self.Exec(SqlCommand) +## Factory class to produce different storage for different type of meta-file +class MetaFileStorage(object): + _FILE_TABLE_ = { + MODEL_FILE_INF : ModuleTable, + MODEL_FILE_DEC : PackageTable, + MODEL_FILE_DSC : PlatformTable, + MODEL_FILE_OTHERS : MetaFileTable, + } + + _FILE_TYPE_ = { + ".inf" : MODEL_FILE_INF, + ".dec" : MODEL_FILE_DEC, + ".dsc" : MODEL_FILE_DSC, + } + + ## Constructor + def __new__(Class, Cursor, MetaFile, FileType=None, Temporary=False): + # no type given, try to find one + if not FileType: + if MetaFile.Type in self._FILE_TYPE_: + FileType = Class._FILE_TYPE_[MetaFile.Type] + else: + FileType = MODEL_FILE_OTHERS + + # don't pass the type around if it's well known + if FileType == MODEL_FILE_OTHERS: + Args = (Cursor, MetaFile, FileType, Temporary) + else: + Args = (Cursor, MetaFile, Temporary) + + # create the storage object and return it to caller + return Class._FILE_TABLE_[FileType](*Args) + diff --git a/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py b/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py index ac2ca057cc..71e98a94be 100644 --- a/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py +++ b/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py @@ -92,20 +92,14 @@ class DscBuildData(PlatformBuildClassObject): # @param Platform (not used for DscBuildData) # @param Macros Macros used for replacement in DSC file # - def __init__(self, FilePath, RawData, BuildDataBase, Arch='COMMON', Platform='DUMMY', Macros={}): + def __init__(self, FilePath, RawData, BuildDataBase, Arch='COMMON', Target=None, Toolchain=None): self.MetaFile = FilePath self._RawData = RawData self._Bdb = BuildDataBase self._Arch = Arch - self._Macros = Macros + self._Target = Target + self._Toolchain = Toolchain self._Clear() - RecordList = self._RawData[MODEL_META_DATA_DEFINE, self._Arch] - for Record in RecordList: - GlobalData.gEdkGlobal[Record[0]] = Record[1] - - RecordList = self._RawData[MODEL_META_DATA_GLOBAL_DEFINE, self._Arch] - for Record in RecordList: - GlobalData.gGlobalDefines[Record[0]] = Record[1] ## XXX[key] = value def __setitem__(self, key, value): @@ -145,6 +139,16 @@ class DscBuildData(PlatformBuildClassObject): self._RFCLanguages = None self._ISOLanguages = None self._VpdToolGuid = None + self.__Macros = None + + ## Get current effective macros + def _GetMacros(self): + if self.__Macros == None: + self.__Macros = {} + self.__Macros.update(GlobalData.gPlatformDefines) + self.__Macros.update(GlobalData.gGlobalDefines) + self.__Macros.update(GlobalData.gCommandLineDefines) + return self.__Macros ## Get architecture def _GetArch(self): @@ -172,37 +176,40 @@ class DscBuildData(PlatformBuildClassObject): def _GetHeaderInfo(self): RecordList = self._RawData[MODEL_META_DATA_HEADER, self._Arch] for Record in RecordList: - Name = Record[0] + Name = Record[1] # items defined _PROPERTY_ don't need additional processing if Name in self: - self[Name] = Record[1] + self[Name] = Record[2] # some special items in [Defines] section need special treatment elif Name == TAB_DSC_DEFINES_OUTPUT_DIRECTORY: - self._OutputDirectory = NormPath(Record[1], self._Macros) + self._OutputDirectory = NormPath(Record[2], self._Macros) if ' ' in self._OutputDirectory: EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in OUTPUT_DIRECTORY", File=self.MetaFile, Line=Record[-1], ExtraData=self._OutputDirectory) elif Name == TAB_DSC_DEFINES_FLASH_DEFINITION: - self._FlashDefinition = PathClass(NormPath(Record[1], self._Macros), GlobalData.gWorkspace) + self._FlashDefinition = PathClass(NormPath(Record[2], self._Macros), GlobalData.gWorkspace) ErrorCode, ErrorInfo = self._FlashDefinition.Validate('.fdf') if ErrorCode != 0: EdkLogger.error('build', ErrorCode, File=self.MetaFile, Line=Record[-1], ExtraData=ErrorInfo) elif Name == TAB_DSC_DEFINES_SUPPORTED_ARCHITECTURES: - self._SupArchList = GetSplitValueList(Record[1], TAB_VALUE_SPLIT) + self._SupArchList = GetSplitValueList(Record[2], TAB_VALUE_SPLIT) elif Name == TAB_DSC_DEFINES_BUILD_TARGETS: - self._BuildTargets = GetSplitValueList(Record[1]) + self._BuildTargets = GetSplitValueList(Record[2]) elif Name == TAB_DSC_DEFINES_SKUID_IDENTIFIER: if self._SkuName == None: - self._SkuName = Record[1] + self._SkuName = Record[2] elif Name == TAB_FIX_LOAD_TOP_MEMORY_ADDRESS: - self._LoadFixAddress = Record[1] + try: + self._LoadFixAddress = int (Record[2], 0) + except: + EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS %s is not valid dec or hex string" % (Record[2])) elif Name == TAB_DSC_DEFINES_RFC_LANGUAGES: - if not Record[1] or Record[1][0] != '"' or Record[1][-1] != '"' or len(Record[1]) == 1: + if not Record[2] or Record[2][0] != '"' or Record[2][-1] != '"' or len(Record[2]) == 1: EdkLogger.error('build', FORMAT_NOT_SUPPORTED, 'language code for RFC_LANGUAGES must have double quotes around it, for example: RFC_LANGUAGES = "en-us;zh-hans"', File=self.MetaFile, Line=Record[-1]) - LanguageCodes = Record[1][1:-1] + LanguageCodes = Record[2][1:-1] if not LanguageCodes: EdkLogger.error('build', FORMAT_NOT_SUPPORTED, 'one or more RFC4646 format language code must be provided for RFC_LANGUAGES statement', File=self.MetaFile, Line=Record[-1]) @@ -213,10 +220,10 @@ class DscBuildData(PlatformBuildClassObject): File=self.MetaFile, Line=Record[-1]) self._RFCLanguages = LanguageList elif Name == TAB_DSC_DEFINES_ISO_LANGUAGES: - if not Record[1] or Record[1][0] != '"' or Record[1][-1] != '"' or len(Record[1]) == 1: + if not Record[2] or Record[2][0] != '"' or Record[2][-1] != '"' or len(Record[2]) == 1: EdkLogger.error('build', FORMAT_NOT_SUPPORTED, 'language code for ISO_LANGUAGES must have double quotes around it, for example: ISO_LANGUAGES = "engchn"', File=self.MetaFile, Line=Record[-1]) - LanguageCodes = Record[1][1:-1] + LanguageCodes = Record[2][1:-1] if not LanguageCodes: EdkLogger.error('build', FORMAT_NOT_SUPPORTED, 'one or more ISO639-2 format language code must be provided for ISO_LANGUAGES statement', File=self.MetaFile, Line=Record[-1]) @@ -233,10 +240,10 @@ class DscBuildData(PlatformBuildClassObject): # for VPD_TOOL_GUID is correct. # try: - uuid.UUID(Record[1]) + uuid.UUID(Record[2]) except: EdkLogger.error("build", FORMAT_INVALID, "Invalid GUID format for VPD_TOOL_GUID", File=self.MetaFile) - self._VpdToolGuid = Record[1] + self._VpdToolGuid = Record[2] # set _Header to non-None in order to avoid database re-querying self._Header = 'DUMMY' @@ -368,8 +375,18 @@ class DscBuildData(PlatformBuildClassObject): if self._LoadFixAddress == None: if self._Header == None: self._GetHeaderInfo() + if self._LoadFixAddress == None: - self._LoadFixAddress = '' + self._LoadFixAddress = self._Macros.get(TAB_FIX_LOAD_TOP_MEMORY_ADDRESS, '0') + + try: + self._LoadFixAddress = int (self._LoadFixAddress, 0) + except: + EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS %s is not valid dec or hex string" % (self._LoadFixAddress)) + if self._LoadFixAddress < 0: + EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is set to the invalid negative value %s" % (self._LoadFixAddress)) + if self._LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self._LoadFixAddress % 0x1000 != 0: + EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is set to the invalid unaligned 4K value %s" % (self._LoadFixAddress)) return self._LoadFixAddress ## Retrieve RFCLanguage filter @@ -389,7 +406,6 @@ class DscBuildData(PlatformBuildClassObject): if self._ISOLanguages == None: self._ISOLanguages = [] return self._ISOLanguages - ## Retrieve the GUID string for VPD tool def _GetVpdToolGuid(self): if self._VpdToolGuid == None: @@ -402,8 +418,8 @@ class DscBuildData(PlatformBuildClassObject): ## Retrieve [SkuIds] section information def _GetSkuIds(self): if self._SkuIds == None: - self._SkuIds = {} - RecordList = self._RawData[MODEL_EFI_SKU_ID] + self._SkuIds = sdict() + RecordList = self._RawData[MODEL_EFI_SKU_ID, self._Arch] for Record in RecordList: if Record[0] in [None, '']: EdkLogger.error('build', FORMAT_INVALID, 'No Sku ID number', @@ -423,8 +439,8 @@ class DscBuildData(PlatformBuildClassObject): self._Modules = sdict() RecordList = self._RawData[MODEL_META_DATA_COMPONENT, self._Arch] - Macros = {"EDK_SOURCE":GlobalData.gEcpSource, "EFI_SOURCE":GlobalData.gEfiSource} - Macros.update(self._Macros) + Macros = self._Macros + Macros["EDK_SOURCE"] = GlobalData.gEcpSource for Record in RecordList: ModuleFile = PathClass(NormPath(Record[0], Macros), GlobalData.gWorkspace, Arch=self._Arch) ModuleId = Record[5] @@ -530,9 +546,8 @@ class DscBuildData(PlatformBuildClassObject): LibraryClassDict = tdict(True, 3) # track all library class names LibraryClassSet = set() - RecordList = self._RawData[MODEL_EFI_LIBRARY_CLASS, self._Arch] - Macros = {"EDK_SOURCE":GlobalData.gEcpSource, "EFI_SOURCE":GlobalData.gEfiSource} - Macros.update(self._Macros) + RecordList = self._RawData[MODEL_EFI_LIBRARY_CLASS, self._Arch, None, -1] + Macros = self._Macros for Record in RecordList: LibraryClass, LibraryInstance, Dummy, Arch, ModuleType, Dummy, LineNo = Record if LibraryClass == '' or LibraryClass == 'NULL': @@ -564,7 +579,8 @@ class DscBuildData(PlatformBuildClassObject): continue self._LibraryClasses[LibraryClass, ModuleType] = LibraryInstance - # for EDK style library instances, which are listed in different section + # for Edk style library instances, which are listed in different section + Macros["EDK_SOURCE"] = GlobalData.gEcpSource RecordList = self._RawData[MODEL_EFI_LIBRARY_INSTANCE, self._Arch] for Record in RecordList: File = PathClass(NormPath(Record[0], Macros), GlobalData.gWorkspace, Arch=self._Arch) @@ -581,14 +597,14 @@ class DscBuildData(PlatformBuildClassObject): # to parse it here. (self._Bdb[] will trigger a file parse if it # hasn't been parsed) # - Library = self._Bdb[File, self._Arch] + Library = self._Bdb[File, self._Arch, self._Target, self._Toolchain] self._LibraryClasses[Library.BaseName, ':dummy:'] = Library return self._LibraryClasses ## Retrieve all PCD settings in platform def _GetPcds(self): if self._Pcds == None: - self._Pcds = {} + self._Pcds = sdict() self._Pcds.update(self._GetPcd(MODEL_PCD_FIXED_AT_BUILD)) self._Pcds.update(self._GetPcd(MODEL_PCD_PATCHABLE_IN_MODULE)) self._Pcds.update(self._GetPcd(MODEL_PCD_FEATURE_FLAG)) @@ -603,17 +619,17 @@ class DscBuildData(PlatformBuildClassObject): ## Retrieve [BuildOptions] def _GetBuildOptions(self): if self._BuildOptions == None: - self._BuildOptions = {} + self._BuildOptions = sdict() # # Retrieve build option for EDKII style module # - RecordList = self._RawData[MODEL_META_DATA_BUILD_OPTION, 'COMMON', EDKII_NAME] + RecordList = self._RawData[MODEL_META_DATA_BUILD_OPTION, self._Arch, EDKII_NAME] for ToolChainFamily, ToolChain, Option, Dummy1, Dummy2, Dummy3, Dummy4 in RecordList: self._BuildOptions[ToolChainFamily, ToolChain, EDKII_NAME] = Option # # Retrieve build option for EDK style module # - RecordList = self._RawData[MODEL_META_DATA_BUILD_OPTION, 'COMMON', EDK_NAME] + RecordList = self._RawData[MODEL_META_DATA_BUILD_OPTION, self._Arch, EDK_NAME] for ToolChainFamily, ToolChain, Option, Dummy1, Dummy2, Dummy3, Dummy4 in RecordList: self._BuildOptions[ToolChainFamily, ToolChain, EDK_NAME] = Option return self._BuildOptions @@ -625,7 +641,7 @@ class DscBuildData(PlatformBuildClassObject): # @retval a dict object contains settings of given PCD type # def _GetPcd(self, Type): - Pcds = {} + Pcds = sdict() # # tdict is a special dict kind of type, used for selecting correct # PCD settings for certain ARCH @@ -664,7 +680,7 @@ class DscBuildData(PlatformBuildClassObject): # @retval a dict object contains settings of given PCD type # def _GetDynamicPcd(self, Type): - Pcds = {} + Pcds = sdict() # # tdict is a special dict kind of type, used for selecting correct # PCD settings for certain ARCH and SKU @@ -706,7 +722,7 @@ class DscBuildData(PlatformBuildClassObject): # @retval a dict object contains settings of given PCD type # def _GetDynamicHiiPcd(self, Type): - Pcds = {} + Pcds = sdict() # # tdict is a special dict kind of type, used for selecting correct # PCD settings for certain ARCH and SKU @@ -746,7 +762,7 @@ class DscBuildData(PlatformBuildClassObject): # @retval a dict object contains settings of given PCD type # def _GetDynamicVpdPcd(self, Type): - Pcds = {} + Pcds = sdict() # # tdict is a special dict kind of type, used for selecting correct # PCD settings for certain ARCH and SKU @@ -814,6 +830,7 @@ class DscBuildData(PlatformBuildClassObject): self.Pcds[Name, Guid] = PcdClassObject(Name, Guid, '', '', '', '', '', {}, False, None) self.Pcds[Name, Guid].DefaultValue = Value + _Macros = property(_GetMacros) Arch = property(_GetArch, _SetArch) Platform = property(_GetPlatformName) PlatformName = property(_GetPlatformName) @@ -884,13 +901,14 @@ class DecBuildData(PackageBuildClassObject): # @param Platform (not used for DecBuildData) # @param Macros Macros used for replacement in DSC file # - def __init__(self, File, RawData, BuildDataBase, Arch='COMMON', Platform='DUMMY', Macros={}): + def __init__(self, File, RawData, BuildDataBase, Arch='COMMON', Target=None, Toolchain=None): self.MetaFile = File self._PackageDir = File.Dir self._RawData = RawData self._Bdb = BuildDataBase self._Arch = Arch - self._Macros = Macros + self._Target = Target + self._Toolchain = Toolchain self._Clear() ## XXX[key] = value @@ -918,6 +936,14 @@ class DecBuildData(PackageBuildClassObject): self._Includes = None self._LibraryClasses = None self._Pcds = None + self.__Macros = None + + ## Get current effective macros + def _GetMacros(self): + if self.__Macros == None: + self.__Macros = {} + self.__Macros.update(GlobalData.gGlobalDefines) + return self.__Macros ## Get architecture def _GetArch(self): @@ -943,11 +969,11 @@ class DecBuildData(PackageBuildClassObject): # (Retriving all [Defines] information in one-shot is just to save time.) # def _GetHeaderInfo(self): - RecordList = self._RawData[MODEL_META_DATA_HEADER] + RecordList = self._RawData[MODEL_META_DATA_HEADER, self._Arch] for Record in RecordList: - Name = Record[0] + Name = Record[1] if Name in self: - self[Name] = Record[1] + self[Name] = Record[2] self._Header = 'DUMMY' ## Retrieve package name @@ -1057,8 +1083,8 @@ class DecBuildData(PackageBuildClassObject): if self._Includes == None: self._Includes = [] RecordList = self._RawData[MODEL_EFI_INCLUDE, self._Arch] - Macros = {"EDK_SOURCE":GlobalData.gEcpSource, "EFI_SOURCE":GlobalData.gEfiSource} - Macros.update(self._Macros) + Macros = self._Macros + Macros["EDK_SOURCE"] = GlobalData.gEcpSource for Record in RecordList: File = PathClass(NormPath(Record[0], Macros), self._PackageDir, Arch=self._Arch) LineNo = Record[-1] @@ -1082,8 +1108,7 @@ class DecBuildData(PackageBuildClassObject): LibraryClassDict = tdict(True) LibraryClassSet = set() RecordList = self._RawData[MODEL_EFI_LIBRARY_CLASS, self._Arch] - Macros = {"EDK_SOURCE":GlobalData.gEcpSource, "EFI_SOURCE":GlobalData.gEfiSource} - Macros.update(self._Macros) + Macros = self._Macros for LibraryClass, File, Dummy, Arch, ID, LineNo in RecordList: File = PathClass(NormPath(File, Macros), self._PackageDir, Arch=self._Arch) # check the file validation @@ -1100,7 +1125,7 @@ class DecBuildData(PackageBuildClassObject): ## Retrieve PCD declarations def _GetPcds(self): if self._Pcds == None: - self._Pcds = {} + self._Pcds = sdict() self._Pcds.update(self._GetPcd(MODEL_PCD_FIXED_AT_BUILD)) self._Pcds.update(self._GetPcd(MODEL_PCD_PATCHABLE_IN_MODULE)) self._Pcds.update(self._GetPcd(MODEL_PCD_FEATURE_FLAG)) @@ -1110,7 +1135,7 @@ class DecBuildData(PackageBuildClassObject): ## Retrieve PCD declarations for given type def _GetPcd(self, Type): - Pcds = {} + Pcds = sdict() # # tdict is a special kind of dict, used for selecting correct # PCD declaration for given ARCH @@ -1150,6 +1175,7 @@ class DecBuildData(PackageBuildClassObject): return Pcds + _Macros = property(_GetMacros) Arch = property(_GetArch, _SetArch) PackageName = property(_GetPackageName) Guid = property(_GetFileGuid) @@ -1194,7 +1220,7 @@ class InfBuildData(ModuleBuildClassObject): # # Optional Fields # - TAB_INF_DEFINES_INF_VERSION : "_AutoGenVersion", + #TAB_INF_DEFINES_INF_VERSION : "_AutoGenVersion", TAB_INF_DEFINES_COMPONENT_TYPE : "_ComponentType", TAB_INF_DEFINES_MAKEFILE_NAME : "_MakefileName", #TAB_INF_DEFINES_CUSTOM_MAKEFILE : "_CustomMakefile", @@ -1249,14 +1275,15 @@ class InfBuildData(ModuleBuildClassObject): # @param Platform The name of platform employing this module # @param Macros Macros used for replacement in DSC file # - def __init__(self, FilePath, RawData, BuildDatabase, Arch='COMMON', Platform='COMMON', Macros={}): + def __init__(self, FilePath, RawData, BuildDatabase, Arch='COMMON', Target=None, Toolchain=None): self.MetaFile = FilePath self._ModuleDir = FilePath.Dir self._RawData = RawData self._Bdb = BuildDatabase self._Arch = Arch + self._Target = Target + self._Toolchain = Toolchain self._Platform = 'COMMON' - self._Macros = Macros self._SourceOverridePath = None if FilePath.Key in GlobalData.gOverrideDir: self._SourceOverridePath = GlobalData.gOverrideDir[FilePath.Key] @@ -1310,7 +1337,17 @@ class InfBuildData(ModuleBuildClassObject): self._BuildOptions = None self._Depex = None self._DepexExpression = None - #self._SourceOverridePath = None + self.__Macros = None + + ## Get current effective macros + def _GetMacros(self): + if self.__Macros == None: + self.__Macros = {} + # EDK_GLOBAL defined macros can be applied to EDK modoule + if self.AutoGenVersion < 0x00010005: + self.__Macros.update(GlobalData.gEdkGlobal) + self.__Macros.update(GlobalData.gGlobalDefines) + return self.__Macros ## Get architecture def _GetArch(self): @@ -1354,26 +1391,25 @@ class InfBuildData(ModuleBuildClassObject): def _GetHeaderInfo(self): RecordList = self._RawData[MODEL_META_DATA_HEADER, self._Arch, self._Platform] for Record in RecordList: - Record = ReplaceMacros(Record, GlobalData.gEdkGlobal, False) - Name = Record[0] + Name, Value = Record[1], ReplaceMacro(Record[2], self._Macros, False) # items defined _PROPERTY_ don't need additional processing if Name in self: - self[Name] = Record[1] + self[Name] = Value # some special items in [Defines] section need special treatment elif Name in ('EFI_SPECIFICATION_VERSION', 'UEFI_SPECIFICATION_VERSION', 'EDK_RELEASE_VERSION', 'PI_SPECIFICATION_VERSION'): if Name in ('EFI_SPECIFICATION_VERSION', 'UEFI_SPECIFICATION_VERSION'): Name = 'UEFI_SPECIFICATION_VERSION' if self._Specification == None: self._Specification = sdict() - self._Specification[Name] = GetHexVerValue(Record[1]) + self._Specification[Name] = GetHexVerValue(Value) if self._Specification[Name] == None: EdkLogger.error("build", FORMAT_NOT_SUPPORTED, - "'%s' format is not supported for %s" % (Record[1], Name), + "'%s' format is not supported for %s" % (Value, Name), File=self.MetaFile, Line=Record[-1]) elif Name == 'LIBRARY_CLASS': if self._LibraryClass == None: self._LibraryClass = [] - ValueList = GetSplitValueList(Record[1]) + ValueList = GetSplitValueList(Value) LibraryClass = ValueList[0] if len(ValueList) > 1: SupModuleList = GetSplitValueList(ValueList[1], ' ') @@ -1383,27 +1419,27 @@ class InfBuildData(ModuleBuildClassObject): elif Name == 'ENTRY_POINT': if self._ModuleEntryPointList == None: self._ModuleEntryPointList = [] - self._ModuleEntryPointList.append(Record[1]) + self._ModuleEntryPointList.append(Value) elif Name == 'UNLOAD_IMAGE': if self._ModuleUnloadImageList == None: self._ModuleUnloadImageList = [] - if Record[1] == '': + if not Value: continue - self._ModuleUnloadImageList.append(Record[1]) + self._ModuleUnloadImageList.append(Value) elif Name == 'CONSTRUCTOR': if self._ConstructorList == None: self._ConstructorList = [] - if Record[1] == '': + if not Value: continue - self._ConstructorList.append(Record[1]) + self._ConstructorList.append(Value) elif Name == 'DESTRUCTOR': if self._DestructorList == None: self._DestructorList = [] - if Record[1] == '': + if not Value: continue - self._DestructorList.append(Record[1]) + self._DestructorList.append(Value) elif Name == TAB_INF_DEFINES_CUSTOM_MAKEFILE: - TokenList = GetSplitValueList(Record[1]) + TokenList = GetSplitValueList(Value) if self._CustomMakefile == None: self._CustomMakefile = {} if len(TokenList) < 2: @@ -1418,25 +1454,25 @@ class InfBuildData(ModuleBuildClassObject): else: if self._Defs == None: self._Defs = sdict() - self._Defs[Name] = Record[1] + self._Defs[Name] = Value # - # Retrieve information in sections specific to EDK.x modules + # Retrieve information in sections specific to Edk.x modules # - if self._AutoGenVersion >= 0x00010005: # _AutoGenVersion may be None, which is less than anything + if self.AutoGenVersion >= 0x00010005: if not self._ModuleType: EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "MODULE_TYPE is not given", File=self.MetaFile) if self._ModuleType not in SUP_MODULE_LIST: RecordList = self._RawData[MODEL_META_DATA_HEADER, self._Arch, self._Platform] for Record in RecordList: - Name = Record[0] + Name = Record[1] if Name == "MODULE_TYPE": LineNo = Record[6] break EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "MODULE_TYPE %s is not supported for EDK II, valid values are:\n %s" % (self._ModuleType,' '.join(l for l in SUP_MODULE_LIST)), - File=self.MetaFile, Line=LineNo) + File=self.MetaFile, Line=LineNo) if (self._Specification == None) or (not 'PI_SPECIFICATION_VERSION' in self._Specification) or (int(self._Specification['PI_SPECIFICATION_VERSION'], 16) < 0x0001000A): if self._ModuleType == SUP_MODULE_SMM_CORE: EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "SMM_CORE module type can't be used in the module with PI_SPECIFICATION_VERSION less than 0x0001000A", File=self.MetaFile) @@ -1459,29 +1495,28 @@ class InfBuildData(ModuleBuildClassObject): if self.Sources == None: self._Sources = [] self._Sources.append(File) - else: - self._BuildType = self._ComponentType.upper() + else: if not self._ComponentType: EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "COMPONENT_TYPE is not given", File=self.MetaFile) + self._BuildType = self._ComponentType.upper() if self._ComponentType in self._MODULE_TYPE_: self._ModuleType = self._MODULE_TYPE_[self._ComponentType] if self._ComponentType == 'LIBRARY': self._LibraryClass = [LibraryClassObject(self._BaseName, SUP_MODULE_LIST)] # make use some [nmake] section macros + Macros = self._Macros + Macros["EDK_SOURCE"] = GlobalData.gEcpSource + Macros['PROCESSOR'] = self._Arch RecordList = self._RawData[MODEL_META_DATA_NMAKE, self._Arch, self._Platform] for Name,Value,Dummy,Arch,Platform,ID,LineNo in RecordList: - Value = Value.replace('$(PROCESSOR)', self._Arch) - Name = Name.replace('$(PROCESSOR)', self._Arch) - Name, Value = ReplaceMacros((Name, Value), GlobalData.gEdkGlobal, True) + Value = ReplaceMacro(Value, Macros, True) if Name == "IMAGE_ENTRY_POINT": if self._ModuleEntryPointList == None: self._ModuleEntryPointList = [] self._ModuleEntryPointList.append(Value) elif Name == "DPX_SOURCE": - Macros = {"EDK_SOURCE":GlobalData.gEcpSource, "EFI_SOURCE":GlobalData.gEfiSource} - Macros.update(self._Macros) - File = PathClass(NormPath(Value, Macros), self._ModuleDir, Arch=self._Arch) + File = PathClass(NormPath(Value), self._ModuleDir, Arch=self._Arch) # check the file validation ErrorCode, ErrorInfo = File.Validate(".dxs", CaseSensitive=False) if ErrorCode != 0: @@ -1505,9 +1540,9 @@ class InfBuildData(ModuleBuildClassObject): else: Tool = ToolList[0] ToolChain = "*_*_*_%s_FLAGS" % Tool - ToolChainFamily = 'MSFT' # EDK.x only support MSFT tool chain + ToolChainFamily = 'MSFT' # Edk.x only support MSFT tool chain #ignore not replaced macros in value - ValueList = GetSplitValueList(' ' + Value, '/D') + ValueList = GetSplitList(' ' + Value, '/D') Dummy = ValueList[0] for Index in range(1, len(ValueList)): if ValueList[Index][-1] == '=' or ValueList[Index] == '': @@ -1525,8 +1560,11 @@ class InfBuildData(ModuleBuildClassObject): ## Retrieve file version def _GetInfVersion(self): if self._AutoGenVersion == None: - if self._Header_ == None: - self._GetHeaderInfo() + RecordList = self._RawData[MODEL_META_DATA_HEADER, self._Arch, self._Platform] + for Record in RecordList: + if Record[1] == TAB_INF_DEFINES_INF_VERSION: + self._AutoGenVersion = int(Record[2], 0) + break if self._AutoGenVersion == None: self._AutoGenVersion = 0x00010000 return self._AutoGenVersion @@ -1693,10 +1731,10 @@ class InfBuildData(ModuleBuildClassObject): if self._Binaries == None: self._Binaries = [] RecordList = self._RawData[MODEL_EFI_BINARY_FILE, self._Arch, self._Platform] - Macros = {"EDK_SOURCE":GlobalData.gEcpSource, "EFI_SOURCE":GlobalData.gEfiSource, 'PROCESSOR':self._Arch} - Macros.update(self._Macros) + Macros = self._Macros + Macros["EDK_SOURCE"] = GlobalData.gEcpSource + Macros['PROCESSOR'] = self._Arch for Record in RecordList: - Record = ReplaceMacros(Record, GlobalData.gEdkGlobal, False) FileType = Record[0] LineNo = Record[-1] Target = 'COMMON' @@ -1721,17 +1759,17 @@ class InfBuildData(ModuleBuildClassObject): if self._Sources == None: self._Sources = [] RecordList = self._RawData[MODEL_EFI_SOURCE_FILE, self._Arch, self._Platform] - Macros = {"EDK_SOURCE":GlobalData.gEcpSource, "EFI_SOURCE":GlobalData.gEfiSource, 'PROCESSOR':self._Arch} - Macros.update(self._Macros) + Macros = self._Macros + Macros["EDK_SOURCE"] = GlobalData.gEcpSource + Macros['PROCESSOR'] = self._Arch for Record in RecordList: - Record = ReplaceMacros(Record, GlobalData.gEdkGlobal, False) LineNo = Record[-1] ToolChainFamily = Record[1] TagName = Record[2] ToolCode = Record[3] FeatureFlag = Record[4] - if self._AutoGenVersion < 0x00010005: - # old module source files (EDK) + if self.AutoGenVersion < 0x00010005: + # old module source files (Edk) File = PathClass(NormPath(Record[0], Macros), self._ModuleDir, self._SourceOverridePath, '', False, self._Arch, ToolChainFamily, '', TagName, ToolCode) # check the file validation @@ -1760,23 +1798,22 @@ class InfBuildData(ModuleBuildClassObject): self._LibraryClasses = sdict() RecordList = self._RawData[MODEL_EFI_LIBRARY_CLASS, self._Arch, self._Platform] for Record in RecordList: - Record = ReplaceMacros(Record, GlobalData.gEdkGlobal, False) Lib = Record[0] Instance = Record[1] - if Instance != None and Instance != '': + if Instance: Instance = NormPath(Instance, self._Macros) self._LibraryClasses[Lib] = Instance return self._LibraryClasses - ## Retrieve library names (for EDK.x style of modules) + ## Retrieve library names (for Edk.x style of modules) def _GetLibraryNames(self): if self._Libraries == None: self._Libraries = [] RecordList = self._RawData[MODEL_EFI_LIBRARY_INSTANCE, self._Arch, self._Platform] for Record in RecordList: - # in case of name with '.lib' extension, which is unusual in EDK.x inf - Record = ReplaceMacros(Record, GlobalData.gEdkGlobal, False) - LibraryName = os.path.splitext(Record[0])[0] + LibraryName = ReplaceMacro(Record[0], self._Macros, False) + # in case of name with '.lib' extension, which is unusual in Edk.x inf + LibraryName = os.path.splitext(LibraryName)[0] if LibraryName not in self._Libraries: self._Libraries.append(LibraryName) return self._Libraries @@ -1829,23 +1866,23 @@ class InfBuildData(ModuleBuildClassObject): self._Guids[CName] = Value return self._Guids - ## Retrieve include paths necessary for this module (for EDK.x style of modules) + ## Retrieve include paths necessary for this module (for Edk.x style of modules) def _GetIncludes(self): if self._Includes == None: self._Includes = [] if self._SourceOverridePath: self._Includes.append(self._SourceOverridePath) + + Macros = self._Macros + if 'PROCESSOR' in GlobalData.gEdkGlobal.keys(): + Macros['PROCESSOR'] = GlobalData.gEdkGlobal['PROCESSOR'] + else: + Macros['PROCESSOR'] = self._Arch RecordList = self._RawData[MODEL_EFI_INCLUDE, self._Arch, self._Platform] - # [includes] section must be used only in old (EDK.x) inf file - if self.AutoGenVersion >= 0x00010005 and len(RecordList) > 0: - EdkLogger.error('build', FORMAT_NOT_SUPPORTED, "No [include] section allowed", - File=self.MetaFile, Line=RecordList[0][-1]-1) for Record in RecordList: - Record = ReplaceMacros(Record, GlobalData.gEdkGlobal, False) - Record[0] = Record[0].replace('$(PROCESSOR)', self._Arch) - Record[0] = ReplaceMacro(Record[0], {'EFI_SOURCE' : GlobalData.gEfiSource}, False) if Record[0].find('EDK_SOURCE') > -1: - File = NormPath(ReplaceMacro(Record[0], {'EDK_SOURCE' : GlobalData.gEcpSource}, False), self._Macros) + Macros['EDK_SOURCE'] = GlobalData.gEcpSource + File = NormPath(Record[0], self._Macros) if File[0] == '.': File = os.path.join(self._ModuleDir, File) else: @@ -1855,7 +1892,8 @@ class InfBuildData(ModuleBuildClassObject): self._Includes.append(File) #TRICK: let compiler to choose correct header file - File = NormPath(ReplaceMacro(Record[0], {'EDK_SOURCE' : GlobalData.gEdkSource}, False), self._Macros) + Macros['EDK_SOURCE'] = GlobalData.gEdkSource + File = NormPath(Record[0], self._Macros) if File[0] == '.': File = os.path.join(self._ModuleDir, File) else: @@ -1864,7 +1902,7 @@ class InfBuildData(ModuleBuildClassObject): if File: self._Includes.append(File) else: - File = NormPath(Record[0], self._Macros) + File = NormPath(Record[0], Macros) if File[0] == '.': File = os.path.join(self._ModuleDir, File) else: @@ -1879,8 +1917,8 @@ class InfBuildData(ModuleBuildClassObject): if self._Packages == None: self._Packages = [] RecordList = self._RawData[MODEL_META_DATA_PACKAGE, self._Arch, self._Platform] - Macros = {"EDK_SOURCE":GlobalData.gEcpSource, "EFI_SOURCE":GlobalData.gEfiSource} - Macros.update(self._Macros) + Macros = self._Macros + Macros['EDK_SOURCE'] = GlobalData.gEcpSource for Record in RecordList: File = PathClass(NormPath(Record[0], Macros), GlobalData.gWorkspace, Arch=self._Arch) LineNo = Record[-1] @@ -1889,7 +1927,7 @@ class InfBuildData(ModuleBuildClassObject): if ErrorCode != 0: EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, File=self.MetaFile, Line=LineNo) # parse this package now. we need it to get protocol/ppi/guid value - Package = self._Bdb[File, self._Arch] + Package = self._Bdb[File, self._Arch, self._Target, self._Toolchain] self._Packages.append(Package) return self._Packages @@ -1921,7 +1959,7 @@ class InfBuildData(ModuleBuildClassObject): self._BuildOptions[ToolChainFamily, ToolChain] = OptionString + " " + Option return self._BuildOptions - ## Retrieve depedency expression + ## Retrieve dependency expression def _GetDepex(self): if self._Depex == None: self._Depex = tdict(False, 2) @@ -1929,8 +1967,8 @@ class InfBuildData(ModuleBuildClassObject): # If the module has only Binaries and no Sources, then ignore [Depex] if self.Sources == None or self.Sources == []: - if self.Binaries <> None and self.Binaries <> []: - return self._Depex + if self.Binaries != None and self.Binaries != []: + return self._Depex # PEIM and DXE drivers must have a valid [Depex] section if len(self.LibraryClass) == 0 and len(RecordList) == 0: @@ -1939,12 +1977,12 @@ class InfBuildData(ModuleBuildClassObject): EdkLogger.error('build', RESOURCE_NOT_AVAILABLE, "No [Depex] section or no valid expression in [Depex] section for [%s] module" \ % self.ModuleType, File=self.MetaFile) - Depex = {} + Depex = sdict() for Record in RecordList: - Record = ReplaceMacros(Record, GlobalData.gEdkGlobal, False) + DepexStr = ReplaceMacro(Record[0], self._Macros, False) Arch = Record[3] ModuleType = Record[4] - TokenList = Record[0].split() + TokenList = DepexStr.split() if (Arch, ModuleType) not in Depex: Depex[Arch, ModuleType] = [] DepexList = Depex[Arch, ModuleType] @@ -1980,12 +2018,12 @@ class InfBuildData(ModuleBuildClassObject): if self._DepexExpression == None: self._DepexExpression = tdict(False, 2) RecordList = self._RawData[MODEL_EFI_DEPEX, self._Arch] - DepexExpression = {} + DepexExpression = sdict() for Record in RecordList: - Record = ReplaceMacros(Record, GlobalData.gEdkGlobal, False) + DepexStr = ReplaceMacro(Record[0], self._Macros, False) Arch = Record[3] ModuleType = Record[4] - TokenList = Record[0].split() + TokenList = DepexStr.split() if (Arch, ModuleType) not in DepexExpression: DepexExpression[Arch, ModuleType] = '' for Token in TokenList: @@ -2123,6 +2161,7 @@ class InfBuildData(ModuleBuildClassObject): return Pcds + _Macros = property(_GetMacros) Arch = property(_GetArch, _SetArch) Platform = property(_GetPlatform, _SetPlatform) @@ -2170,21 +2209,6 @@ class InfBuildData(ModuleBuildClassObject): # @prarm RenewDb=False Create new database file if it's already there # class WorkspaceDatabase(object): - # file parser - _FILE_PARSER_ = { - MODEL_FILE_INF : InfParser, - MODEL_FILE_DEC : DecParser, - MODEL_FILE_DSC : DscParser, - MODEL_FILE_FDF : None, #FdfParser, - MODEL_FILE_CIF : None - } - - # file table - _FILE_TABLE_ = { - MODEL_FILE_INF : ModuleTable, - MODEL_FILE_DEC : PackageTable, - MODEL_FILE_DSC : PlatformTable, - } # default database file path _DB_PATH_ = "Conf/.cache/build.db" @@ -2194,11 +2218,18 @@ class WorkspaceDatabase(object): # to avoid unnecessary re-parsing # class BuildObjectFactory(object): + _FILE_TYPE_ = { ".inf" : MODEL_FILE_INF, ".dec" : MODEL_FILE_DEC, ".dsc" : MODEL_FILE_DSC, - ".fdf" : MODEL_FILE_FDF, + } + + # file parser + _FILE_PARSER_ = { + MODEL_FILE_INF : InfParser, + MODEL_FILE_DEC : DecParser, + MODEL_FILE_DSC : DscParser, } # convert to xxxBuildData object @@ -2206,7 +2237,6 @@ class WorkspaceDatabase(object): MODEL_FILE_INF : InfBuildData, MODEL_FILE_DEC : DecBuildData, MODEL_FILE_DSC : DscBuildData, - MODEL_FILE_FDF : None #FlashDefTable, } _CACHE_ = {} # (FilePath, Arch) : @@ -2215,46 +2245,61 @@ class WorkspaceDatabase(object): def __init__(self, WorkspaceDb): self.WorkspaceDb = WorkspaceDb - # key = (FilePath, Arch='COMMON') + # key = (FilePath, Arch=None) def __contains__(self, Key): FilePath = Key[0] - Arch = 'COMMON' if len(Key) > 1: Arch = Key[1] + else: + Arch = None return (FilePath, Arch) in self._CACHE_ - # key = (FilePath, Arch='COMMON') + # key = (FilePath, Arch=None, Target=None, Toochain=None) def __getitem__(self, Key): FilePath = Key[0] - Arch = 'COMMON' - Platform = 'COMMON' - if len(Key) > 1: + KeyLength = len(Key) + if KeyLength > 1: Arch = Key[1] - if len(Key) > 2: - Platform = Key[2] + else: + Arch = None + if KeyLength > 2: + Target = Key[2] + else: + Target = None + if KeyLength > 3: + Toolchain = Key[3] + else: + Toolchain = None # if it's generated before, just return the cached one - Key = (FilePath, Arch) + Key = (FilePath, Arch, Target, Toolchain) if Key in self._CACHE_: return self._CACHE_[Key] # check file type - Ext = FilePath.Ext.lower() + Ext = FilePath.Type if Ext not in self._FILE_TYPE_: return None FileType = self._FILE_TYPE_[Ext] if FileType not in self._GENERATOR_: return None - # get table for current file - MetaFile = self.WorkspaceDb[FilePath, FileType, self.WorkspaceDb._GlobalMacros] + # get the parser ready for this file + MetaFile = self._FILE_PARSER_[FileType]( + FilePath, + FileType, + MetaFileStorage(self.WorkspaceDb.Cur, FilePath, FileType) + ) + # alwasy do post-process, in case of macros change + MetaFile.DoPostProcess() + # object the build is based on BuildObject = self._GENERATOR_[FileType]( FilePath, MetaFile, self, Arch, - Platform, - self.WorkspaceDb._GlobalMacros, + Target, + Toolchain ) self._CACHE_[Key] = BuildObject return BuildObject @@ -2274,11 +2319,9 @@ class WorkspaceDatabase(object): # @param GlobalMacros Global macros used for replacement during file parsing # @prarm RenewDb=False Create new database file if it's already there # - def __init__(self, DbPath, GlobalMacros={}, RenewDb=False): + def __init__(self, DbPath, RenewDb=False): self._DbClosedFlag = False - self._GlobalMacros = GlobalMacros - - if DbPath == None or DbPath == '': + if not DbPath: DbPath = os.path.normpath(os.path.join(GlobalData.gWorkspace, self._DB_PATH_)) # don't create necessary path for db in memory @@ -2306,6 +2349,7 @@ class WorkspaceDatabase(object): # create table for internal uses self.TblDataModel = TableDataModel(self.Cur) self.TblFile = TableFile(self.Cur) + self.Platform = None # conversion object for build or file format conversion purpose self.BuildObject = WorkspaceDatabase.BuildObjectFactory(self) @@ -2324,41 +2368,6 @@ class WorkspaceDatabase(object): # @return Bool value for whether need renew workspace databse # def _CheckWhetherDbNeedRenew (self, force, DbPath): - DbDir = os.path.split(DbPath)[0] - MacroFilePath = os.path.normpath(os.path.join(DbDir, "build.mac")) - MacroMatch = False - if os.path.exists(MacroFilePath) and os.path.isfile(MacroFilePath): - LastMacros = None - try: - f = open(MacroFilePath,'r') - LastMacros = pickle.load(f) - f.close() - except IOError: - pass - except: - f.close() - - if LastMacros != None and type(LastMacros) is DictType: - if LastMacros == self._GlobalMacros: - MacroMatch = True - for Macro in LastMacros.keys(): - if not (Macro in self._GlobalMacros and LastMacros[Macro] == self._GlobalMacros[Macro]): - MacroMatch = False; - break; - - if not MacroMatch: - # save command line macros to file - try: - f = open(MacroFilePath,'w') - pickle.dump(self._GlobalMacros, f, 2) - f.close() - except IOError: - pass - except: - f.close() - - force = True - # if database does not exist, we need do nothing if not os.path.exists(DbPath): return False @@ -2423,6 +2432,9 @@ determine whether database file is out of date!\n") def QueryTable(self, Table): Table.Query() + def __del__(self): + self.Close() + ## Close entire database # # Commit all first @@ -2435,83 +2447,28 @@ determine whether database file is out of date!\n") self.Conn.close() self._DbClosedFlag = True - ## Get unique file ID for the gvien file - def GetFileId(self, FilePath): - return self.TblFile.GetFileId(FilePath) - - ## Get file type value for the gvien file ID - def GetFileType(self, FileId): - return self.TblFile.GetFileType(FileId) - - ## Get time stamp stored in file table - def GetTimeStamp(self, FileId): - return self.TblFile.GetFileTimeStamp(FileId) - - ## Update time stamp in file table - def SetTimeStamp(self, FileId, TimeStamp): - return self.TblFile.SetFileTimeStamp(FileId, TimeStamp) - - ## Check if a table integrity flag exists or not - def CheckIntegrity(self, TableName): - try: - Result = self.Cur.execute("select min(ID) from %s" % (TableName)).fetchall() - if Result[0][0] != -1: - return False - # - # Check whether the meta data file has external dependency by comparing the time stamp - # - Sql = "select Value1, Value2 from %s where Model=%d" % (TableName, MODEL_EXTERNAL_DEPENDENCY) - for Dependency in self.Cur.execute(Sql).fetchall(): - if str(os.stat(Dependency[0])[8]) != Dependency[1]: - return False - except: - return False - return True - - ## Compose table name for given file type and file ID - def GetTableName(self, FileType, FileId): - return "_%s_%s" % (FileType, FileId) - - ## Return a temp table containing all content of the given file - # - # @param FileInfo The tuple containing path and type of a file - # - def __getitem__(self, FileInfo): - FilePath, FileType, Macros = FileInfo - if FileType not in self._FILE_TABLE_: - return None - - # flag used to indicate if it's parsed or not - FilePath = str(FilePath) - Parsed = False - FileId = self.GetFileId(FilePath) - if FileId != None: - TimeStamp = os.stat(FilePath)[8] - TableName = self.GetTableName(FileType, FileId) - if TimeStamp != self.GetTimeStamp(FileId): - # update the timestamp in database - self.SetTimeStamp(FileId, TimeStamp) - else: - # if the table exists and is integrity, don't parse it - Parsed = self.CheckIntegrity(TableName) - else: - FileId = self.TblFile.InsertFile(FilePath, FileType) - TableName = self.GetTableName(FileType, FileId) - - FileTable = self._FILE_TABLE_[FileType](self.Cur, TableName, FileId) - FileTable.Create(not Parsed) - Parser = self._FILE_PARSER_[FileType](FilePath, FileType, FileTable, Macros) - # set the "Finished" flag in parser in order to avoid re-parsing (if parsed) - Parser.Finished = Parsed - return Parser - ## Summarize all packages in the database - def _GetPackageList(self): - PackageList = [] - for Module in self.ModuleList: - for Package in Module.Packages: + def GetPackageList(self, Platform, Arch, TargetName, ToolChainTag): + self.Platform = Platform + PackageList =[] + Pa = self.BuildObject[self.Platform, 'COMMON'] + # + # Get Package related to Modules + # + for Module in Pa.Modules: + ModuleObj = self.BuildObject[Module, Arch, TargetName, ToolChainTag] + for Package in ModuleObj.Packages: if Package not in PackageList: PackageList.append(Package) + # + # Get Packages related to Libraries + # + for Lib in Pa.LibraryInstances: + LibObj = self.BuildObject[Lib, Arch, TargetName, ToolChainTag] + for Package in LibObj.Packages: + if Package not in PackageList: + PackageList.append(Package) + return PackageList ## Summarize all platforms in the database @@ -2526,21 +2483,7 @@ determine whether database file is out of date!\n") PlatformList.append(Platform) return PlatformList - ## Summarize all modules in the database - def _GetModuleList(self): - ModuleList = [] - for ModuleFile in self.TblFile.GetFileList(MODEL_FILE_INF): - try: - Module = self.BuildObject[PathClass(ModuleFile), 'COMMON'] - except: - Module = None - if Module != None: - ModuleList.append(Module) - return ModuleList - PlatformList = property(_GetPlatformList) - PackageList = property(_GetPackageList) - ModuleList = property(_GetModuleList) ## # diff --git a/BaseTools/Source/Python/build/BuildReport.py b/BaseTools/Source/Python/build/BuildReport.py index c6e49f9999..f3555d705d 100644 --- a/BaseTools/Source/Python/build/BuildReport.py +++ b/BaseTools/Source/Python/build/BuildReport.py @@ -4,7 +4,7 @@ # This module contains the functionality to generate build report after # build all target completes successfully. # -# Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+# Copyright (c) 2010, Intel Corporation. All rights reserved.
# 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 @@ -184,16 +184,17 @@ class DepexParser(object): # def __init__(self, Wa): self._GuidDb = {} - for Package in Wa.BuildDatabase.WorkspaceDb.PackageList: - for Protocol in Package.Protocols: - GuidValue = GuidStructureStringToGuidString(Package.Protocols[Protocol]) - self._GuidDb[GuidValue.upper()] = Protocol - for Ppi in Package.Ppis: - GuidValue = GuidStructureStringToGuidString(Package.Ppis[Ppi]) - self._GuidDb[GuidValue.upper()] = Ppi - for Guid in Package.Guids: - GuidValue = GuidStructureStringToGuidString(Package.Guids[Guid]) - self._GuidDb[GuidValue.upper()] = Guid + for Pa in Wa.AutoGenObjectList: + for Package in Pa.PackageList: + for Protocol in Package.Protocols: + GuidValue = GuidStructureStringToGuidString(Package.Protocols[Protocol]) + self._GuidDb[GuidValue.upper()] = Protocol + for Ppi in Package.Ppis: + GuidValue = GuidStructureStringToGuidString(Package.Ppis[Ppi]) + self._GuidDb[GuidValue.upper()] = Ppi + for Guid in Package.Guids: + GuidValue = GuidStructureStringToGuidString(Package.Guids[Guid]) + self._GuidDb[GuidValue.upper()] = Guid ## # Parse the binary dependency expression files. @@ -486,7 +487,7 @@ class ModuleReport(object): # if ModuleType == "DXE_SMM_DRIVER": PiSpec = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000") - if int(PiSpec, 16) >= 0x0001000A: + if int(PiSpec, 0) >= 0x0001000A: ModuleType = "SMM_DRIVER" self.DriverType = gDriverTypeMap.get(ModuleType, "0x2 (FREE_FORM)") self.UefiSpecVersion = M.Module.Specification.get("UEFI_SPECIFICATION_VERSION", "") @@ -641,10 +642,11 @@ class PcdReport(object): # Collect PCD DEC default value. # self.DecPcdDefault = {} - for Package in Wa.BuildDatabase.WorkspaceDb.PackageList: - for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds: - DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue - self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue) + for Pa in Wa.AutoGenObjectList: + for Package in Pa.PackageList: + for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds: + DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue + self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue) # # Collect PCDs defined in DSC common section # @@ -1174,14 +1176,14 @@ class FdRegionReport(object): self._DiscoverNestedFvList(FvName, Wa) PlatformPcds = {} - # # Collect PCDs declared in DEC files. - # - for Package in Wa.BuildDatabase.WorkspaceDb.PackageList: - for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds: - DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue - PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue + # + for Pa in Wa.AutoGenObjectList: + for Package in Pa.PackageList: + for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds: + DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue + PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue # # Collect PCDs defined in DSC common section # diff --git a/BaseTools/Source/Python/build/build.py b/BaseTools/Source/Python/build/build.py index 9502bf3364..0319103138 100644 --- a/BaseTools/Source/Python/build/build.py +++ b/BaseTools/Source/Python/build/build.py @@ -172,6 +172,12 @@ def CheckEnvVariable(): GlobalData.gEdkSource = EdkSourceDir GlobalData.gEcpSource = EcpSourceDir + GlobalData.gGlobalDefines["WORKSPACE"] = WorkspaceDir + GlobalData.gGlobalDefines["EFI_SOURCE"] = EfiSourceDir + GlobalData.gGlobalDefines["EDK_SOURCE"] = EdkSourceDir + GlobalData.gGlobalDefines["ECP_SOURCE"] = EcpSourceDir + GlobalData.gGlobalDefines["EDK_TOOLS_PATH"] = os.environ["EDK_TOOLS_PATH"] + ## Get normalized file path # # Convert the path to be local format, and remove the WORKSPACE path at the @@ -301,10 +307,14 @@ class BuildUnit: self.WorkingDir = WorkingDir self.Target = Target self.BuildCommand = BuildCommand - if BuildCommand == None or len(BuildCommand) == 0: - EdkLogger.error("build", OPTION_MISSING, "No build command found for", + if not BuildCommand: + EdkLogger.error("build", OPTION_MISSING, + "No build command found for this module. " + "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." % + (Obj.BuildTarget, Obj.ToolChain, Obj.Arch), ExtraData=str(Obj)) + ## str() method # # It just returns the string representation of self.BuildObject @@ -690,93 +700,59 @@ class Build(): # # @param Target The build command target, one of gSupportedTarget # @param WorkspaceDir The directory of workspace - # @param Platform The DSC file of active platform - # @param Module The INF file of active module, if any - # @param Arch The Arch list of platform or module - # @param ToolChain The name list of toolchain - # @param BuildTarget The "DEBUG" or "RELEASE" build - # @param FlashDefinition The FDF file of active platform - # @param FdList=[] The FD names to be individually built - # @param FvList=[] The FV names to be individually built - # @param MakefileType The type of makefile (for MSFT make or GNU make) - # @param SilentMode Indicate multi-thread build mode - # @param ThreadNumber The maximum number of thread if in multi-thread build mode - # @param SkipAutoGen Skip AutoGen step - # @param Reparse Re-parse all meta files - # @param SkuId SKU id from command line - # - def __init__(self, Target, WorkspaceDir, Platform, Module, Arch, ToolChain, - BuildTarget, FlashDefinition, FdList=[], FvList=[], CapList=[], - MakefileType="nmake", SilentMode=False, ThreadNumber=2, - SkipAutoGen=False, Reparse=False, SkuId=None, - ReportFile=None, ReportType=None, UniFlag=None): - - self.WorkspaceDir = WorkspaceDir + # @param BuildOptions Build options passed from command line + # + def __init__(self, Target, WorkspaceDir, BuildOptions): + self.WorkspaceDir = WorkspaceDir self.Target = Target - self.PlatformFile = Platform - self.ModuleFile = Module - self.ArchList = Arch - self.ToolChainList = ToolChain - self.BuildTargetList= BuildTarget - self.Fdf = FlashDefinition - self.FdList = FdList - self.FvList = FvList - self.CapList = CapList - self.MakefileType = MakefileType - self.SilentMode = SilentMode - self.ThreadNumber = ThreadNumber - self.SkipAutoGen = SkipAutoGen - self.Reparse = Reparse - self.SkuId = SkuId + self.PlatformFile = BuildOptions.PlatformFile + self.ModuleFile = BuildOptions.ModuleFile + self.ArchList = BuildOptions.TargetArch + self.ToolChainList = BuildOptions.ToolChain + self.BuildTargetList= BuildOptions.BuildTarget + self.Fdf = BuildOptions.FdfFile + self.FdList = BuildOptions.RomImage + self.FvList = BuildOptions.FvImage + self.CapList = BuildOptions.CapName + self.SilentMode = BuildOptions.SilentMode + self.ThreadNumber = BuildOptions.ThreadNumber + self.SkipAutoGen = BuildOptions.SkipAutoGen + self.Reparse = BuildOptions.Reparse + self.SkuId = BuildOptions.SkuId self.SpawnMode = True - self.BuildReport = BuildReport(ReportFile, ReportType) + self.BuildReport = BuildReport(BuildOptions.ReportFile, BuildOptions.ReportType) self.TargetTxt = TargetTxtClassObject() self.ToolDef = ToolDefClassObject() - self.Db = WorkspaceDatabase(None, GlobalData.gGlobalDefines, self.Reparse) - #self.Db = WorkspaceDatabase(None, {}, self.Reparse) + if BuildOptions.DisableCache: + self.Db = WorkspaceDatabase(":memory:") + else: + self.Db = WorkspaceDatabase(None, self.Reparse) self.BuildDatabase = self.Db.BuildObject self.Platform = None self.LoadFixAddress = 0 - self.UniFlag = UniFlag + self.UniFlag = BuildOptions.Flag # print dot character during doing some time-consuming work self.Progress = Utils.Progressor() - # parse target.txt, tools_def.txt, and platform file - #self.RestoreBuildData() - self.LoadConfiguration() - - # - # @attention Treat $(TARGET)/$(TOOL_CHAIN_TAG) in meta data files as special macro when it has only one build target/toolchain. - # This is not a complete support for $(TARGET)/$(TOOL_CHAIN_TAG) macro as it can only support one build target/toolchain in ONE - # invocation of build command. However, it should cover the frequent usage model that $(TARGET)/$(TOOL_CHAIN_TAG) macro - # is used in DSC/FDF files to specify different libraries & PCD setting for debug/release build. - # - if len(self.BuildTargetList) == 1: - self.Db._GlobalMacros.setdefault("TARGET", self.BuildTargetList[0]) - if len(self.ToolChainList) == 1: - self.Db._GlobalMacros.setdefault("TOOL_CHAIN_TAG", self.ToolChainList[0]) - self.InitBuild() # print current build environment and configuration - EdkLogger.quiet("%-24s = %s" % ("WORKSPACE", os.environ["WORKSPACE"])) - EdkLogger.quiet("%-24s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"])) - EdkLogger.quiet("%-24s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"])) - EdkLogger.quiet("%-24s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"])) - EdkLogger.quiet("%-24s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"])) - - EdkLogger.info('\n%-24s = %s' % ("TARGET_ARCH", ' '.join(self.ArchList))) - EdkLogger.info('%-24s = %s' % ("TARGET", ' '.join(self.BuildTargetList))) - EdkLogger.info('%-24s = %s' % ("TOOL_CHAIN_TAG", ' '.join(self.ToolChainList))) - - EdkLogger.info('\n%-24s = %s' % ("Active Platform", self.PlatformFile)) - - if self.Fdf != None and self.Fdf != "": - EdkLogger.info('%-24s = %s' % ("Flash Image Definition", self.Fdf)) - - if self.ModuleFile != None and self.ModuleFile != "": - EdkLogger.info('%-24s = %s' % ("Active Module", self.ModuleFile)) + EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"])) + EdkLogger.quiet("%-16s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"])) + EdkLogger.quiet("%-16s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"])) + EdkLogger.quiet("%-16s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"])) + EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"])) + + EdkLogger.info("") + if self.ArchList: + EdkLogger.info('%-16s = %s' % ("Architecture(s)", ' '.join(self.ArchList))) + EdkLogger.info('%-16s = %s' % ("Build target", ' '.join(self.BuildTargetList))) + EdkLogger.info('%-16s = %s' % ("Toolchain", ' '.join(self.ToolChainList))) + + #EdkLogger.info('\n%-24s = %s' % ("Active Platform", self.PlatformFile)) + if self.ModuleFile: + EdkLogger.info('%-16s = %s' % ("Active Module", self.ModuleFile)) os.chdir(self.WorkspaceDir) self.Progress.Start("\nProcessing meta-data") @@ -805,15 +781,16 @@ class Build(): EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile) # if no ARCH given in command line, get it from target.txt - if self.ArchList == None or len(self.ArchList) == 0: + if not self.ArchList: self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH] + self.ArchList = tuple(self.ArchList) # if no build target given in command line, get it from target.txt - if self.BuildTargetList == None or len(self.BuildTargetList) == 0: + if not self.BuildTargetList: self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET] # if no tool chain given in command line, get it from target.txt - if self.ToolChainList == None or len(self.ToolChainList) == 0: + if not self.ToolChainList: self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG] if self.ToolChainList == None or len(self.ToolChainList) == 0: EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n") @@ -859,9 +836,6 @@ class Build(): ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n") self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir) - ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False) - if ErrorCode != 0: - EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo) ## Initialize build configuration # @@ -869,90 +843,17 @@ class Build(): # command line and target.txt, then get the final build configurations. # def InitBuild(self): - ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc") + # parse target.txt, tools_def.txt, and platform file + self.LoadConfiguration() + + # Allow case-insensitive for those from command line or configuration file + ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False) if ErrorCode != 0: EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo) # create metafile database self.Db.InitDatabase() - # we need information in platform description file to determine how to build - self.Platform = self.BuildDatabase[self.PlatformFile, 'COMMON'] - if not self.Fdf: - self.Fdf = self.Platform.FlashDefinition - - LoadFixAddressString = None - if TAB_FIX_LOAD_TOP_MEMORY_ADDRESS in GlobalData.gGlobalDefines: - LoadFixAddressString = GlobalData.gGlobalDefines[TAB_FIX_LOAD_TOP_MEMORY_ADDRESS] - else: - LoadFixAddressString = self.Platform.LoadFixAddress - - if LoadFixAddressString != None and LoadFixAddressString != '': - try: - if LoadFixAddressString.upper().startswith('0X'): - self.LoadFixAddress = int (LoadFixAddressString, 16) - else: - self.LoadFixAddress = int (LoadFixAddressString) - except: - EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS %s is not valid dec or hex string" % (LoadFixAddressString)) - if self.LoadFixAddress < 0: - EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is set to the invalid negative value %s" % (LoadFixAddressString)) - if self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress % 0x1000 != 0: - EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is set to the invalid unaligned 4K value %s" % (LoadFixAddressString)) - - if self.SkuId == None or self.SkuId == '': - self.SkuId = self.Platform.SkuName - - # check FD/FV build target - if self.Fdf == None or self.Fdf == "": - if self.FdList != []: - EdkLogger.info("No flash definition file found. FD [%s] will be ignored." % " ".join(self.FdList)) - self.FdList = [] - if self.FvList != []: - EdkLogger.info("No flash definition file found. FV [%s] will be ignored." % " ".join(self.FvList)) - self.FvList = [] - else: - # - # Mark now build in AutoGen Phase - # - GlobalData.gAutoGenPhase = True - FdfParserObj = FdfParser(str(self.Fdf)) - for key in self.Db._GlobalMacros: - InputMacroDict[key] = self.Db._GlobalMacros[key] - FdfParserObj.ParseFile() - for fvname in self.FvList: - if fvname.upper() not in FdfParserObj.Profile.FvDict.keys(): - EdkLogger.error("build", OPTION_VALUE_INVALID, - "No such an FV in FDF file: %s" % fvname) - GlobalData.gAutoGenPhase = False - - # - # Merge Arch - # - if self.ArchList == None or len(self.ArchList) == 0: - ArchList = set(self.Platform.SupArchList) - else: - ArchList = set(self.ArchList) & set(self.Platform.SupArchList) - if len(ArchList) == 0: - EdkLogger.error("build", PARAMETER_INVALID, - ExtraData = "Active platform supports [%s] only, but [%s] is given." - % (" ".join(self.Platform.SupArchList), " ".join(self.ArchList))) - elif len(ArchList) != len(self.ArchList): - SkippedArchList = set(self.ArchList).symmetric_difference(set(self.Platform.SupArchList)) - EdkLogger.verbose("\nArch [%s] is ignored because active platform supports [%s] but [%s] is specified !" - % (" ".join(SkippedArchList), " ".join(self.Platform.SupArchList), " ".join(self.ArchList))) - self.ArchList = tuple(ArchList) - - # Merge build target - if self.BuildTargetList == None or len(self.BuildTargetList) == 0: - BuildTargetList = self.Platform.BuildTargets - else: - BuildTargetList = list(set(self.BuildTargetList) & set(self.Platform.BuildTargets)) - if BuildTargetList == []: - EdkLogger.error("build", PARAMETER_INVALID, "Active platform only supports [%s], but [%s] is given" - % (" ".join(self.Platform.BuildTargets), " ".join(self.BuildTargetList))) - self.BuildTargetList = BuildTargetList - ## Build a module or platform # # Create autogen code and makefile for a module or platform, and the launch @@ -1000,7 +901,11 @@ class Build(): BuildCommand = AutoGenObject.BuildCommand if BuildCommand == None or len(BuildCommand) == 0: - EdkLogger.error("build", OPTION_MISSING, ExtraData="No MAKE command found for [%s, %s, %s]" % Key) + EdkLogger.error("build", OPTION_MISSING, + "No build command found for this module. " + "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." % + (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch), + ExtraData=str(AutoGenObject)) BuildCommand = BuildCommand + [Target] LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir) @@ -1011,7 +916,7 @@ class Build(): # # First should close DB. # - self.Db.Close() + self.Db.Close() RemoveDirectory(gBuildCacheDir, True) except WindowsError, X: EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X)) @@ -1121,7 +1026,7 @@ class Build(): ## Collect MAP information of all FVs # def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList): - if self.Fdf != '': + if self.Fdf: # First get the XIP base address for FV map file. GuidPattern = re.compile("[-a-fA-F0-9]+") GuidName = re.compile("\(GUID=[-a-fA-F0-9]+") @@ -1318,10 +1223,13 @@ class Build(): # def _BuildPlatform(self): for BuildTarget in self.BuildTargetList: + GlobalData.gGlobalDefines['TARGET'] = BuildTarget for ToolChain in self.ToolChainList: + GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain + GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain Wa = WorkspaceAutoGen( self.WorkspaceDir, - self.Platform, + self.PlatformFile, BuildTarget, ToolChain, self.ArchList, @@ -1335,18 +1243,21 @@ class Build(): self.SkuId, self.UniFlag ) + self.Fdf = Wa.FdfFile + self.LoadFixAddress = Wa.Platform.LoadFixAddress self.BuildReport.AddPlatformReport(Wa) self.Progress.Stop("done!") self._Build(self.Target, Wa) # Create MAP file when Load Fix Address is enabled. if self.Target in ["", "all", "fds"]: - for Arch in self.ArchList: + for Arch in Wa.ArchList: + GlobalData.gGlobalDefines['ARCH'] = Arch # # Check whether the set fix address is above 4G for 32bit image. # if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000: - EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS can't be set to larger than or equal to 4G for the platorm with IA32 or ARM arch modules") + EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS can't be set to larger than or equal to 4G for the platform with IA32 or ARM arch modules") # # Get Module List # @@ -1364,12 +1275,12 @@ class Build(): # Rebase module to the preferred memory address before GenFds # self._CollectModuleMapBuffer(MapBuffer, ModuleList) - if self.Fdf != '': + if self.Fdf: # # create FDS again for the updated EFI image # self._Build("fds", Wa) - if self.Fdf != '': + if self.Fdf: # # Create MAP file for all platform FVs after GenFds. # @@ -1383,14 +1294,17 @@ class Build(): # def _BuildModule(self): for BuildTarget in self.BuildTargetList: + GlobalData.gGlobalDefines['TARGET'] = BuildTarget for ToolChain in self.ToolChainList: + GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain + GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain # # module build needs platform build information, so get platform # AutoGen first # Wa = WorkspaceAutoGen( self.WorkspaceDir, - self.Platform, + self.PlatformFile, BuildTarget, ToolChain, self.ArchList, @@ -1404,10 +1318,13 @@ class Build(): self.SkuId, self.UniFlag ) + self.Fdf = Wa.FdfFile + self.LoadFixAddress = Wa.Platform.LoadFixAddress Wa.CreateMakeFile(False) self.Progress.Stop("done!") MaList = [] - for Arch in self.ArchList: + for Arch in Wa.ArchList: + GlobalData.gGlobalDefines['ARCH'] = Arch Ma = ModuleAutoGen(Wa, self.ModuleFile, BuildTarget, ToolChain, Arch, self.PlatformFile) if Ma == None: continue MaList.append(Ma) @@ -1421,12 +1338,12 @@ class Build(): "Module for [%s] is not a component of active platform."\ " Please make sure that the ARCH and inf file path are"\ " given in the same as in [%s]" %\ - (', '.join(self.ArchList), self.Platform), + (', '.join(Wa.ArchList), self.PlatformFile), ExtraData=self.ModuleFile ) # Create MAP file when Load Fix Address is enabled. - if self.Target == "fds" and self.Fdf != '': - for Arch in self.ArchList: + if self.Target == "fds" and self.Fdf: + for Arch in Wa.ArchList: # # Check whether the set fix address is above 4G for 32bit image. # @@ -1466,10 +1383,13 @@ class Build(): # def _MultiThreadBuildPlatform(self): for BuildTarget in self.BuildTargetList: + GlobalData.gGlobalDefines['TARGET'] = BuildTarget for ToolChain in self.ToolChainList: + GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain + GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain Wa = WorkspaceAutoGen( self.WorkspaceDir, - self.Platform, + self.PlatformFile, BuildTarget, ToolChain, self.ArchList, @@ -1483,13 +1403,16 @@ class Build(): self.SkuId, self.UniFlag ) + self.Fdf = Wa.FdfFile + self.LoadFixAddress = Wa.Platform.LoadFixAddress self.BuildReport.AddPlatformReport(Wa) Wa.CreateMakeFile(False) # multi-thread exit flag ExitFlag = threading.Event() ExitFlag.clear() - for Arch in self.ArchList: + for Arch in Wa.ArchList: + GlobalData.gGlobalDefines['ARCH'] = Arch Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch) if Pa == None: continue @@ -1546,7 +1469,7 @@ class Build(): # Create MAP file when Load Fix Address is enabled. if self.Target in ["", "all", "fds"]: - for Arch in self.ArchList: + for Arch in Wa.ArchList: # # Check whether the set fix address is above 4G for 32bit image. # @@ -1569,7 +1492,7 @@ class Build(): if self.LoadFixAddress != 0: self._CollectModuleMapBuffer(MapBuffer, ModuleList) - if self.Fdf != '': + if self.Fdf: # # Generate FD image if there's a FDF file found # @@ -1586,20 +1509,32 @@ class Build(): ## Generate GuidedSectionTools.txt in the FV directories. # def CreateGuidedSectionToolsFile(self): - for Arch in self.ArchList: - for BuildTarget in self.BuildTargetList: - for ToolChain in self.ToolChainList: - FvDir = os.path.join( - self.WorkspaceDir, - self.Platform.OutputDirectory, - '_'.join((BuildTarget, ToolChain)), - 'FV' - ) - if not os.path.exists(FvDir): - continue + for BuildTarget in self.BuildTargetList: + for ToolChain in self.ToolChainList: + Wa = WorkspaceAutoGen( + self.WorkspaceDir, + self.PlatformFile, + BuildTarget, + ToolChain, + self.ArchList, + self.BuildDatabase, + self.TargetTxt, + self.ToolDef, + self.Fdf, + self.FdList, + self.FvList, + self.CapList, + self.SkuId, + self.UniFlag + ) + FvDir = Wa.FvDir + if not os.path.exists(FvDir): + continue + + for Arch in self.ArchList: # Build up the list of supported architectures for this build prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch) - + # Look through the tool definitions for GUIDed tools guidAttribs = [] for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems(): @@ -1614,7 +1549,7 @@ class Build(): path = self.ToolDef.ToolsDefTxtDictionary[path] path = self.GetFullPathOfTool(path) guidAttribs.append((guid, toolName, path)) - + # Write out GuidedSecTools.txt toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt') toolsFile = open(toolsFile, 'wt') @@ -1642,7 +1577,7 @@ class Build(): ## Launch the module or platform build # def Launch(self): - if self.ModuleFile == None or self.ModuleFile == "": + if not self.ModuleFile: if not self.SpawnMode or self.Target not in ["", "all"]: self.SpawnMode = False self._BuildPlatform() @@ -1687,8 +1622,13 @@ def ParseDefines(DefineList=[]): if DefineList != None: for Define in DefineList: DefineTokenList = Define.split("=", 1) + if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]): + EdkLogger.error('build', FORMAT_INVALID, + "The macro name must be in the pattern [A-Z][A-Z0-9_]*", + ExtraData=DefineTokenList[0]) + if len(DefineTokenList) == 1: - DefineDict[DefineTokenList[0]] = "" + DefineDict[DefineTokenList[0]] = "TRUE" else: DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip() return DefineDict @@ -1737,10 +1677,7 @@ def MyOptionParser(): Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.") Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.") - Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", help="Don't check case of file name.") - - # Parser.add_option("-D", "--define", action="append", dest="Defines", metavar="NAME[=[VALUE]]", - # help="Define global macro which can be used in DSC/DEC/INF files.") + Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.") Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.") Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.") @@ -1762,6 +1699,7 @@ def MyOptionParser(): help="Specify the specific option to parse EDK UNI file. Must be one of: [-c, -s]. -c is for EDK framework UNI file, and -s is for EDK UEFI UNI file. "\ "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\ "will override the setting in [BuildOptions] section of platform DSC.") + Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism") (Opt, Args)=Parser.parse_args() return (Opt, Args) @@ -1826,11 +1764,12 @@ def Main(): EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target, ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget))) - GlobalData.gGlobalDefines = ParseDefines(Option.Macros) # # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH # CheckEnvVariable() + GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros)) + Workspace = os.getenv("WORKSPACE") # # Get files real name in workspace dir @@ -1861,9 +1800,6 @@ def Main(): if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0: Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace) Option.PlatformFile = PathClass(Option.PlatformFile, Workspace) - ErrorCode, ErrorInfo = Option.PlatformFile.Validate(".dsc", False) - if ErrorCode != 0: - EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo) if Option.FdfFile != None: if os.path.isabs (Option.FdfFile): @@ -1877,12 +1813,7 @@ def Main(): if Option.Flag != None and Option.Flag not in ['-c', '-s']: EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s") - MyBuild = Build(Target, Workspace, Option.PlatformFile, Option.ModuleFile, - Option.TargetArch, Option.ToolChain, Option.BuildTarget, - Option.FdfFile, Option.RomImage, Option.FvImage, Option.CapName, - None, Option.SilentMode, Option.ThreadNumber, - Option.SkipAutoGen, Option.Reparse, Option.SkuId, - Option.ReportFile, Option.ReportType, Option.Flag) + MyBuild = Build(Target, Workspace, Option) MyBuild.Launch() #MyBuild.DumpBuildData() except FatalError, X: @@ -1925,7 +1856,8 @@ def Main(): ExtraData="\n(Please send email to edk2-buildtools-devel@lists.sourceforge.net for help, attaching following call stack trace!)\n", RaiseError=False ) - EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc()) + if Option != None and Option.debug != None: + EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc()) ReturnCode = CODE_ERROR finally: Utils.Progressor.Abort() -- cgit v1.2.3