]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Common/ToolDefClassObject.py
BaseTools: use set instead of list for a variable to be used with in
[mirror_edk2.git] / BaseTools / Source / Python / Common / ToolDefClassObject.py
1 ## @file
2 # This file is used to define each component of tools_def.txt file
3 #
4 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
9 #
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 #
13
14 ##
15 # Import Modules
16 #
17 import Common.LongFilePathOs as os
18 import re
19 import EdkLogger
20
21 from BuildToolError import *
22 from TargetTxtClassObject import *
23 from Common.LongFilePathSupport import OpenLongFilePath as open
24 from Common.Misc import PathClass
25 from Common.String import NormPath
26 import Common.GlobalData as GlobalData
27 from Common import GlobalData
28 from Common.MultipleWorkspace import MultipleWorkspace as mws
29 from DataType import TAB_TOD_DEFINES_TARGET,TAB_TOD_DEFINES_TOOL_CHAIN_TAG,\
30 TAB_TOD_DEFINES_TARGET_ARCH,TAB_TOD_DEFINES_COMMAND_TYPE\
31 ,TAB_TOD_DEFINES_FAMILY,TAB_TOD_DEFINES_BUILDRULEFAMILY
32
33
34 ##
35 # Static variables used for pattern
36 #
37 gMacroRefPattern = re.compile('(DEF\([^\(\)]+\))')
38 gEnvRefPattern = re.compile('(ENV\([^\(\)]+\))')
39 gMacroDefPattern = re.compile("DEFINE\s+([^\s]+)")
40 gDefaultToolsDefFile = "tools_def.txt"
41
42 ## ToolDefClassObject
43 #
44 # This class defined content used in file tools_def.txt
45 #
46 # @param object: Inherited from object class
47 # @param Filename: Input value for full path of tools_def.txt
48 #
49 # @var ToolsDefTxtDictionary: To store keys and values defined in target.txt
50 # @var MacroDictionary: To store keys and values defined in DEFINE statement
51 #
52 class ToolDefClassObject(object):
53 def __init__(self, FileName=None):
54 self.ToolsDefTxtDictionary = {}
55 self.MacroDictionary = {}
56 for Env in os.environ:
57 self.MacroDictionary["ENV(%s)" % Env] = os.environ[Env]
58
59 if FileName is not None:
60 self.LoadToolDefFile(FileName)
61
62 ## LoadToolDefFile
63 #
64 # Load target.txt file and parse it
65 #
66 # @param Filename: Input value for full path of tools_def.txt
67 #
68 def LoadToolDefFile(self, FileName):
69 # set multiple workspace
70 PackagesPath = os.getenv("PACKAGES_PATH")
71 mws.setWs(GlobalData.gWorkspace, PackagesPath)
72
73 self.ToolsDefTxtDatabase = {
74 TAB_TOD_DEFINES_TARGET : [],
75 TAB_TOD_DEFINES_TOOL_CHAIN_TAG : [],
76 TAB_TOD_DEFINES_TARGET_ARCH : [],
77 TAB_TOD_DEFINES_COMMAND_TYPE : []
78 }
79
80 self.IncludeToolDefFile(FileName)
81
82 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET]))
83 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]))
84 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH]))
85
86 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE]))
87
88 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET].sort()
89 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG].sort()
90 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH].sort()
91 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE].sort()
92
93 KeyList = [TAB_TOD_DEFINES_TARGET, TAB_TOD_DEFINES_TOOL_CHAIN_TAG, TAB_TOD_DEFINES_TARGET_ARCH, TAB_TOD_DEFINES_COMMAND_TYPE]
94 for Index in range(3, -1, -1):
95 for Key in dict(self.ToolsDefTxtDictionary):
96 List = Key.split('_')
97 if List[Index] == '*':
98 for String in self.ToolsDefTxtDatabase[KeyList[Index]]:
99 List[Index] = String
100 NewKey = '%s_%s_%s_%s_%s' % tuple(List)
101 if NewKey not in self.ToolsDefTxtDictionary:
102 self.ToolsDefTxtDictionary[NewKey] = self.ToolsDefTxtDictionary[Key]
103 continue
104 del self.ToolsDefTxtDictionary[Key]
105 elif List[Index] not in self.ToolsDefTxtDatabase[KeyList[Index]]:
106 del self.ToolsDefTxtDictionary[Key]
107
108
109 ## IncludeToolDefFile
110 #
111 # Load target.txt file and parse it as if it's contents were inside the main file
112 #
113 # @param Filename: Input value for full path of tools_def.txt
114 #
115 def IncludeToolDefFile(self, FileName):
116 FileContent = []
117 if os.path.isfile(FileName):
118 try:
119 F = open(FileName, 'r')
120 FileContent = F.readlines()
121 except:
122 EdkLogger.error("tools_def.txt parser", FILE_OPEN_FAILURE, ExtraData=FileName)
123 else:
124 EdkLogger.error("tools_def.txt parser", FILE_NOT_FOUND, ExtraData=FileName)
125
126 for Index in range(len(FileContent)):
127 Line = FileContent[Index].strip()
128 if Line == "" or Line[0] == '#':
129 continue
130
131 if Line.startswith("!include"):
132 IncFile = Line[8:].strip()
133 Done, IncFile = self.ExpandMacros(IncFile)
134 if not Done:
135 EdkLogger.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE,
136 "Macro or Environment has not been defined",
137 ExtraData=IncFile[4:-1], File=FileName, Line=Index+1)
138 IncFile = NormPath(IncFile)
139
140 if not os.path.isabs(IncFile):
141 #
142 # try WORKSPACE
143 #
144 IncFileTmp = PathClass(IncFile, GlobalData.gWorkspace)
145 ErrorCode = IncFileTmp.Validate()[0]
146 if ErrorCode != 0:
147 #
148 # try PACKAGES_PATH
149 #
150 IncFileTmp = mws.join(GlobalData.gWorkspace, IncFile)
151 if not os.path.exists(IncFileTmp):
152 #
153 # try directory of current file
154 #
155 IncFileTmp = PathClass(IncFile, os.path.dirname(FileName))
156 ErrorCode = IncFileTmp.Validate()[0]
157 if ErrorCode != 0:
158 EdkLogger.error("tools_def.txt parser", FILE_NOT_FOUND, ExtraData=IncFile)
159
160 if type(IncFileTmp) is PathClass:
161 IncFile = IncFileTmp.Path
162 else:
163 IncFile = IncFileTmp
164
165 self.IncludeToolDefFile(IncFile)
166 continue
167
168 NameValuePair = Line.split("=", 1)
169 if len(NameValuePair) != 2:
170 EdkLogger.warn("tools_def.txt parser", "Line %d: not correct assignment statement, skipped" % (Index + 1))
171 continue
172
173 Name = NameValuePair[0].strip()
174 Value = NameValuePair[1].strip()
175
176 if Name == "IDENTIFIER":
177 EdkLogger.debug(EdkLogger.DEBUG_8, "Line %d: Found identifier statement, skipped: %s" % ((Index + 1), Value))
178 continue
179
180 MacroDefinition = gMacroDefPattern.findall(Name)
181 if MacroDefinition != []:
182 Done, Value = self.ExpandMacros(Value)
183 if not Done:
184 EdkLogger.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE,
185 "Macro or Environment has not been defined",
186 ExtraData=Value[4:-1], File=FileName, Line=Index+1)
187
188 MacroName = MacroDefinition[0].strip()
189 self.MacroDictionary["DEF(%s)" % MacroName] = Value
190 EdkLogger.debug(EdkLogger.DEBUG_8, "Line %d: Found macro: %s = %s" % ((Index + 1), MacroName, Value))
191 continue
192
193 Done, Value = self.ExpandMacros(Value)
194 if not Done:
195 EdkLogger.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE,
196 "Macro or Environment has not been defined",
197 ExtraData=Value[4:-1], File=FileName, Line=Index+1)
198
199 List = Name.split('_')
200 if len(List) != 5:
201 EdkLogger.verbose("Line %d: Not a valid name of definition: %s" % ((Index + 1), Name))
202 continue
203 elif List[4] == '*':
204 EdkLogger.verbose("Line %d: '*' is not allowed in last field: %s" % ((Index + 1), Name))
205 continue
206 else:
207 self.ToolsDefTxtDictionary[Name] = Value
208 if List[0] != '*':
209 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET] += [List[0]]
210 if List[1] != '*':
211 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG] += [List[1]]
212 if List[2] != '*':
213 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH] += [List[2]]
214 if List[3] != '*':
215 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE] += [List[3]]
216 if List[4] == TAB_TOD_DEFINES_FAMILY and List[2] == '*' and List[3] == '*':
217 if TAB_TOD_DEFINES_FAMILY not in self.ToolsDefTxtDatabase:
218 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY] = {}
219 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][List[1]] = Value
220 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY] = {}
221 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][List[1]] = Value
222 elif List[1] not in self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY]:
223 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][List[1]] = Value
224 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][List[1]] = Value
225 elif self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][List[1]] != Value:
226 EdkLogger.verbose("Line %d: No override allowed for the family of a tool chain: %s" % ((Index + 1), Name))
227 if List[4] == TAB_TOD_DEFINES_BUILDRULEFAMILY and List[2] == '*' and List[3] == '*':
228 if TAB_TOD_DEFINES_BUILDRULEFAMILY not in self.ToolsDefTxtDatabase \
229 or List[1] not in self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY]:
230 EdkLogger.verbose("Line %d: The family is not specified, but BuildRuleFamily is specified for the tool chain: %s" % ((Index + 1), Name))
231 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][List[1]] = Value
232
233 ## ExpandMacros
234 #
235 # Replace defined macros with real value
236 #
237 # @param Value: The string with unreplaced macros
238 #
239 # @retval Value: The string which has been replaced with real value
240 #
241 def ExpandMacros(self, Value):
242 # os.environ contains all environment variables uppercase on Windows which cause the key in the self.MacroDictionary is uppercase, but Ref may not
243 EnvReference = gEnvRefPattern.findall(Value)
244 for Ref in EnvReference:
245 if Ref not in self.MacroDictionary and Ref.upper() not in self.MacroDictionary:
246 Value = Value.replace(Ref, "")
247 else:
248 if Ref in self.MacroDictionary:
249 Value = Value.replace(Ref, self.MacroDictionary[Ref])
250 else:
251 Value = Value.replace(Ref, self.MacroDictionary[Ref.upper()])
252 MacroReference = gMacroRefPattern.findall(Value)
253 for Ref in MacroReference:
254 if Ref not in self.MacroDictionary:
255 return False, Ref
256 Value = Value.replace(Ref, self.MacroDictionary[Ref])
257
258 return True, Value
259
260 ## ToolDefDict
261 #
262 # Load tools_def.txt in input Conf dir
263 #
264 # @param ConfDir: Conf dir
265 #
266 # @retval ToolDef An instance of ToolDefClassObject() with loaded tools_def.txt
267 #
268 def ToolDefDict(ConfDir):
269 Target = TargetTxtDict(ConfDir)
270 ToolDef = ToolDefClassObject()
271 if DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF in Target.TargetTxtDictionary:
272 ToolsDefFile = Target.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]
273 if ToolsDefFile:
274 ToolDef.LoadToolDefFile(os.path.normpath(ToolsDefFile))
275 else:
276 ToolDef.LoadToolDefFile(os.path.normpath(os.path.join(ConfDir, gDefaultToolsDefFile)))
277 else:
278 ToolDef.LoadToolDefFile(os.path.normpath(os.path.join(ConfDir, gDefaultToolsDefFile)))
279 return ToolDef
280
281 ##
282 #
283 # This acts like the main() function for the script, unless it is 'import'ed into another
284 # script.
285 #
286 if __name__ == '__main__':
287 ToolDef = ToolDefDict(os.getenv("WORKSPACE"))
288 pass