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