| ## @file | |
| # This file is used to define each component of tools_def.txt file | |
| # | |
| # Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR> | |
| # This program and the accompanying materials | |
| # are licensed and made available under the terms and conditions of the BSD License | |
| # which accompanies this distribution. The full text of the license may be found at | |
| # http://opensource.org/licenses/bsd-license.php | |
| # | |
| # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| # | |
| ## | |
| # Import Modules | |
| # | |
| import Common.LongFilePathOs as os | |
| import re | |
| import EdkLogger | |
| from Dictionary import * | |
| from BuildToolError import * | |
| from TargetTxtClassObject import * | |
| from Common.LongFilePathSupport import OpenLongFilePath as open | |
| from Common.Misc import PathClass | |
| from Common.String import NormPath | |
| import Common.GlobalData as GlobalData | |
| from Common import GlobalData | |
| from Common.MultipleWorkspace import MultipleWorkspace as mws | |
| ## | |
| # Static variables used for pattern | |
| # | |
| gMacroRefPattern = re.compile('(DEF\([^\(\)]+\))') | |
| gEnvRefPattern = re.compile('(ENV\([^\(\)]+\))') | |
| gMacroDefPattern = re.compile("DEFINE\s+([^\s]+)") | |
| gDefaultToolsDefFile = "tools_def.txt" | |
| ## ToolDefClassObject | |
| # | |
| # This class defined content used in file tools_def.txt | |
| # | |
| # @param object: Inherited from object class | |
| # @param Filename: Input value for full path of tools_def.txt | |
| # | |
| # @var ToolsDefTxtDictionary: To store keys and values defined in target.txt | |
| # @var MacroDictionary: To store keys and values defined in DEFINE statement | |
| # | |
| class ToolDefClassObject(object): | |
| def __init__(self, FileName=None): | |
| self.ToolsDefTxtDictionary = {} | |
| self.MacroDictionary = {} | |
| for Env in os.environ: | |
| self.MacroDictionary["ENV(%s)" % Env] = os.environ[Env] | |
| if FileName != None: | |
| self.LoadToolDefFile(FileName) | |
| ## LoadToolDefFile | |
| # | |
| # Load target.txt file and parse it | |
| # | |
| # @param Filename: Input value for full path of tools_def.txt | |
| # | |
| def LoadToolDefFile(self, FileName): | |
| # set multiple workspace | |
| PackagesPath = os.getenv("PACKAGES_PATH") | |
| mws.setWs(GlobalData.gWorkspace, PackagesPath) | |
| self.ToolsDefTxtDatabase = { | |
| TAB_TOD_DEFINES_TARGET : [], | |
| TAB_TOD_DEFINES_TOOL_CHAIN_TAG : [], | |
| TAB_TOD_DEFINES_TARGET_ARCH : [], | |
| TAB_TOD_DEFINES_COMMAND_TYPE : [] | |
| } | |
| self.IncludeToolDefFile(FileName) | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET])) | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG])) | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH])) | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE])) | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET].sort() | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG].sort() | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH].sort() | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE].sort() | |
| KeyList = [TAB_TOD_DEFINES_TARGET, TAB_TOD_DEFINES_TOOL_CHAIN_TAG, TAB_TOD_DEFINES_TARGET_ARCH, TAB_TOD_DEFINES_COMMAND_TYPE] | |
| for Index in range(3, -1, -1): | |
| for Key in dict(self.ToolsDefTxtDictionary): | |
| List = Key.split('_') | |
| if List[Index] == '*': | |
| for String in self.ToolsDefTxtDatabase[KeyList[Index]]: | |
| List[Index] = String | |
| NewKey = '%s_%s_%s_%s_%s' % tuple(List) | |
| if NewKey not in self.ToolsDefTxtDictionary: | |
| self.ToolsDefTxtDictionary[NewKey] = self.ToolsDefTxtDictionary[Key] | |
| continue | |
| del self.ToolsDefTxtDictionary[Key] | |
| elif List[Index] not in self.ToolsDefTxtDatabase[KeyList[Index]]: | |
| del self.ToolsDefTxtDictionary[Key] | |
| ## IncludeToolDefFile | |
| # | |
| # Load target.txt file and parse it as if it's contents were inside the main file | |
| # | |
| # @param Filename: Input value for full path of tools_def.txt | |
| # | |
| def IncludeToolDefFile(self, FileName): | |
| FileContent = [] | |
| if os.path.isfile(FileName): | |
| try: | |
| F = open(FileName, 'r') | |
| FileContent = F.readlines() | |
| except: | |
| EdkLogger.error("tools_def.txt parser", FILE_OPEN_FAILURE, ExtraData=FileName) | |
| else: | |
| EdkLogger.error("tools_def.txt parser", FILE_NOT_FOUND, ExtraData=FileName) | |
| for Index in range(len(FileContent)): | |
| Line = FileContent[Index].strip() | |
| if Line == "" or Line[0] == '#': | |
| continue | |
| if Line.startswith("!include"): | |
| IncFile = Line[8:].strip() | |
| Done, IncFile = self.ExpandMacros(IncFile) | |
| if not Done: | |
| EdkLogger.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE, | |
| "Macro or Environment has not been defined", | |
| ExtraData=IncFile[4:-1], File=FileName, Line=Index+1) | |
| IncFile = NormPath(IncFile) | |
| if not os.path.isabs(IncFile): | |
| # | |
| # try WORKSPACE | |
| # | |
| IncFileTmp = PathClass(IncFile, GlobalData.gWorkspace) | |
| ErrorCode = IncFileTmp.Validate()[0] | |
| if ErrorCode != 0: | |
| # | |
| # try PACKAGES_PATH | |
| # | |
| IncFileTmp = mws.join(GlobalData.gWorkspace, IncFile) | |
| if not os.path.exists(IncFileTmp): | |
| # | |
| # try directory of current file | |
| # | |
| IncFileTmp = PathClass(IncFile, os.path.dirname(FileName)) | |
| ErrorCode = IncFileTmp.Validate()[0] | |
| if ErrorCode != 0: | |
| EdkLogger.error("tools_def.txt parser", FILE_NOT_FOUND, ExtraData=IncFile) | |
| if type(IncFileTmp) is PathClass: | |
| IncFile = IncFileTmp.Path | |
| else: | |
| IncFile = IncFileTmp | |
| self.IncludeToolDefFile(IncFile) | |
| continue | |
| NameValuePair = Line.split("=", 1) | |
| if len(NameValuePair) != 2: | |
| EdkLogger.warn("tools_def.txt parser", "Line %d: not correct assignment statement, skipped" % (Index + 1)) | |
| continue | |
| Name = NameValuePair[0].strip() | |
| Value = NameValuePair[1].strip() | |
| if Name == "IDENTIFIER": | |
| EdkLogger.debug(EdkLogger.DEBUG_8, "Line %d: Found identifier statement, skipped: %s" % ((Index + 1), Value)) | |
| continue | |
| MacroDefinition = gMacroDefPattern.findall(Name) | |
| if MacroDefinition != []: | |
| Done, Value = self.ExpandMacros(Value) | |
| if not Done: | |
| EdkLogger.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE, | |
| "Macro or Environment has not been defined", | |
| ExtraData=Value[4:-1], File=FileName, Line=Index+1) | |
| MacroName = MacroDefinition[0].strip() | |
| self.MacroDictionary["DEF(%s)" % MacroName] = Value | |
| EdkLogger.debug(EdkLogger.DEBUG_8, "Line %d: Found macro: %s = %s" % ((Index + 1), MacroName, Value)) | |
| continue | |
| Done, Value = self.ExpandMacros(Value) | |
| if not Done: | |
| EdkLogger.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE, | |
| "Macro or Environment has not been defined", | |
| ExtraData=Value[4:-1], File=FileName, Line=Index+1) | |
| List = Name.split('_') | |
| if len(List) != 5: | |
| EdkLogger.verbose("Line %d: Not a valid name of definition: %s" % ((Index + 1), Name)) | |
| continue | |
| elif List[4] == '*': | |
| EdkLogger.verbose("Line %d: '*' is not allowed in last field: %s" % ((Index + 1), Name)) | |
| continue | |
| else: | |
| self.ToolsDefTxtDictionary[Name] = Value | |
| if List[0] != '*': | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET] += [List[0]] | |
| if List[1] != '*': | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG] += [List[1]] | |
| if List[2] != '*': | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH] += [List[2]] | |
| if List[3] != '*': | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE] += [List[3]] | |
| if List[4] == TAB_TOD_DEFINES_FAMILY and List[2] == '*' and List[3] == '*': | |
| if TAB_TOD_DEFINES_FAMILY not in self.ToolsDefTxtDatabase: | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY] = {} | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][List[1]] = Value | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY] = {} | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][List[1]] = Value | |
| elif List[1] not in self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY]: | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][List[1]] = Value | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][List[1]] = Value | |
| elif self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][List[1]] != Value: | |
| EdkLogger.verbose("Line %d: No override allowed for the family of a tool chain: %s" % ((Index + 1), Name)) | |
| if List[4] == TAB_TOD_DEFINES_BUILDRULEFAMILY and List[2] == '*' and List[3] == '*': | |
| if TAB_TOD_DEFINES_BUILDRULEFAMILY not in self.ToolsDefTxtDatabase \ | |
| or List[1] not in self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY]: | |
| EdkLogger.verbose("Line %d: The family is not specified, but BuildRuleFamily is specified for the tool chain: %s" % ((Index + 1), Name)) | |
| self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][List[1]] = Value | |
| ## ExpandMacros | |
| # | |
| # Replace defined macros with real value | |
| # | |
| # @param Value: The string with unreplaced macros | |
| # | |
| # @retval Value: The string which has been replaced with real value | |
| # | |
| def ExpandMacros(self, Value): | |
| # os.environ contains all environment variables uppercase on Windows which cause the key in the self.MacroDictionary is uppercase, but Ref may not | |
| EnvReference = gEnvRefPattern.findall(Value) | |
| for Ref in EnvReference: | |
| if Ref not in self.MacroDictionary and Ref.upper() not in self.MacroDictionary: | |
| Value = Value.replace(Ref, "") | |
| else: | |
| if Ref in self.MacroDictionary: | |
| Value = Value.replace(Ref, self.MacroDictionary[Ref]) | |
| else: | |
| Value = Value.replace(Ref, self.MacroDictionary[Ref.upper()]) | |
| MacroReference = gMacroRefPattern.findall(Value) | |
| for Ref in MacroReference: | |
| if Ref not in self.MacroDictionary: | |
| return False, Ref | |
| Value = Value.replace(Ref, self.MacroDictionary[Ref]) | |
| return True, Value | |
| ## ToolDefDict | |
| # | |
| # Load tools_def.txt in input Conf dir | |
| # | |
| # @param ConfDir: Conf dir | |
| # | |
| # @retval ToolDef An instance of ToolDefClassObject() with loaded tools_def.txt | |
| # | |
| def ToolDefDict(ConfDir): | |
| Target = TargetTxtDict(ConfDir) | |
| ToolDef = ToolDefClassObject() | |
| if DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF in Target.TargetTxtDictionary: | |
| ToolsDefFile = Target.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF] | |
| if ToolsDefFile: | |
| ToolDef.LoadToolDefFile(os.path.normpath(ToolsDefFile)) | |
| else: | |
| ToolDef.LoadToolDefFile(os.path.normpath(os.path.join(ConfDir, gDefaultToolsDefFile))) | |
| else: | |
| ToolDef.LoadToolDefFile(os.path.normpath(os.path.join(ConfDir, gDefaultToolsDefFile))) | |
| return ToolDef | |
| ## | |
| # | |
| # This acts like the main() function for the script, unless it is 'import'ed into another | |
| # script. | |
| # | |
| if __name__ == '__main__': | |
| ToolDef = ToolDefDict(os.getenv("WORKSPACE")) | |
| pass |