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