]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - BaseTools/Source/Python/AutoGen/GenDepex.py
BaseTools: Remove equality operator with None
[mirror_edk2.git] / BaseTools / Source / Python / AutoGen / GenDepex.py
... / ...
CommitLineData
1## @file\r
2# This file is used to generate DEPEX file for module's dependency expression\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## Import Modules\r
14#\r
15import sys\r
16import Common.LongFilePathOs as os\r
17import re\r
18import traceback\r
19from Common.LongFilePathSupport import OpenLongFilePath as open\r
20from StringIO import StringIO\r
21from struct import pack\r
22from Common.BuildToolError import *\r
23from Common.Misc import SaveFileOnChange\r
24from Common.Misc import GuidStructureStringToGuidString\r
25from Common import EdkLogger as EdkLogger\r
26from Common.BuildVersion import gBUILD_VERSION\r
27\r
28## Regular expression for matching "DEPENDENCY_START ... DEPENDENCY_END"\r
29gStartClosePattern = re.compile(".*DEPENDENCY_START(.+)DEPENDENCY_END.*", re.S)\r
30\r
31## Mapping between module type and EFI phase\r
32gType2Phase = {\r
33 "BASE" : None,\r
34 "SEC" : "PEI",\r
35 "PEI_CORE" : "PEI",\r
36 "PEIM" : "PEI",\r
37 "DXE_CORE" : "DXE",\r
38 "DXE_DRIVER" : "DXE",\r
39 "DXE_SMM_DRIVER" : "DXE",\r
40 "DXE_RUNTIME_DRIVER": "DXE",\r
41 "DXE_SAL_DRIVER" : "DXE",\r
42 "UEFI_DRIVER" : "DXE",\r
43 "UEFI_APPLICATION" : "DXE",\r
44 "SMM_CORE" : "DXE",\r
45 "MM_STANDALONE" : "MM",\r
46 "MM_CORE_STANDALONE" : "MM",\r
47}\r
48\r
49## Convert dependency expression string into EFI internal representation\r
50#\r
51# DependencyExpression class is used to parse dependency expression string and\r
52# convert it into its binary form.\r
53#\r
54class DependencyExpression:\r
55\r
56 ArchProtocols = set([\r
57 '665e3ff6-46cc-11d4-9a38-0090273fc14d', # 'gEfiBdsArchProtocolGuid'\r
58 '26baccb1-6f42-11d4-bce7-0080c73c8881', # 'gEfiCpuArchProtocolGuid'\r
59 '26baccb2-6f42-11d4-bce7-0080c73c8881', # 'gEfiMetronomeArchProtocolGuid'\r
60 '1da97072-bddc-4b30-99f1-72a0b56fff2a', # 'gEfiMonotonicCounterArchProtocolGuid'\r
61 '27cfac87-46cc-11d4-9a38-0090273fc14d', # 'gEfiRealTimeClockArchProtocolGuid'\r
62 '27cfac88-46cc-11d4-9a38-0090273fc14d', # 'gEfiResetArchProtocolGuid'\r
63 'b7dfb4e1-052f-449f-87be-9818fc91b733', # 'gEfiRuntimeArchProtocolGuid'\r
64 'a46423e3-4617-49f1-b9ff-d1bfa9115839', # 'gEfiSecurityArchProtocolGuid'\r
65 '26baccb3-6f42-11d4-bce7-0080c73c8881', # 'gEfiTimerArchProtocolGuid'\r
66 '6441f818-6362-4e44-b570-7dba31dd2453', # 'gEfiVariableWriteArchProtocolGuid'\r
67 '1e5668e2-8481-11d4-bcf1-0080c73c8881', # 'gEfiVariableArchProtocolGuid'\r
68 '665e3ff5-46cc-11d4-9a38-0090273fc14d' # 'gEfiWatchdogTimerArchProtocolGuid'\r
69 ]\r
70 )\r
71\r
72 OpcodePriority = {\r
73 "AND" : 1,\r
74 "OR" : 1,\r
75 "NOT" : 2,\r
76 # "SOR" : 9,\r
77 # "BEFORE": 9,\r
78 # "AFTER" : 9,\r
79 }\r
80\r
81 Opcode = {\r
82 "PEI" : {\r
83 "PUSH" : 0x02,\r
84 "AND" : 0x03,\r
85 "OR" : 0x04,\r
86 "NOT" : 0x05,\r
87 "TRUE" : 0x06,\r
88 "FALSE" : 0x07,\r
89 "END" : 0x08\r
90 },\r
91\r
92 "DXE" : {\r
93 "BEFORE": 0x00,\r
94 "AFTER" : 0x01,\r
95 "PUSH" : 0x02,\r
96 "AND" : 0x03,\r
97 "OR" : 0x04,\r
98 "NOT" : 0x05,\r
99 "TRUE" : 0x06,\r
100 "FALSE" : 0x07,\r
101 "END" : 0x08,\r
102 "SOR" : 0x09\r
103 },\r
104\r
105 "MM" : {\r
106 "BEFORE": 0x00,\r
107 "AFTER" : 0x01,\r
108 "PUSH" : 0x02,\r
109 "AND" : 0x03,\r
110 "OR" : 0x04,\r
111 "NOT" : 0x05,\r
112 "TRUE" : 0x06,\r
113 "FALSE" : 0x07,\r
114 "END" : 0x08,\r
115 "SOR" : 0x09\r
116 }\r
117 }\r
118\r
119 # all supported op codes and operands\r
120 SupportedOpcode = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "END", "SOR"]\r
121 SupportedOperand = ["TRUE", "FALSE"]\r
122\r
123 OpcodeWithSingleOperand = ['NOT', 'BEFORE', 'AFTER']\r
124 OpcodeWithTwoOperand = ['AND', 'OR']\r
125\r
126 # op code that should not be the last one\r
127 NonEndingOpcode = ["AND", "OR", "NOT", 'SOR']\r
128 # op code must not present at the same time\r
129 ExclusiveOpcode = ["BEFORE", "AFTER"]\r
130 # op code that should be the first one if it presents\r
131 AboveAllOpcode = ["SOR", "BEFORE", "AFTER"]\r
132\r
133 #\r
134 # open and close brace must be taken as individual tokens\r
135 #\r
136 TokenPattern = re.compile("(\(|\)|\{[^{}]+\{?[^{}]+\}?[ ]*\}|\w+)")\r
137\r
138 ## Constructor\r
139 #\r
140 # @param Expression The list or string of dependency expression\r
141 # @param ModuleType The type of the module using the dependency expression\r
142 #\r
143 def __init__(self, Expression, ModuleType, Optimize=False):\r
144 self.ModuleType = ModuleType\r
145 self.Phase = gType2Phase[ModuleType]\r
146 if type(Expression) == type([]):\r
147 self.ExpressionString = " ".join(Expression)\r
148 self.TokenList = Expression\r
149 else:\r
150 self.ExpressionString = Expression\r
151 self.GetExpressionTokenList()\r
152\r
153 self.PostfixNotation = []\r
154 self.OpcodeList = []\r
155\r
156 self.GetPostfixNotation()\r
157 self.ValidateOpcode()\r
158\r
159 EdkLogger.debug(EdkLogger.DEBUG_8, repr(self))\r
160 if Optimize:\r
161 self.Optimize()\r
162 EdkLogger.debug(EdkLogger.DEBUG_8, "\n Optimized: " + repr(self))\r
163\r
164 def __str__(self):\r
165 return " ".join(self.TokenList)\r
166\r
167 def __repr__(self):\r
168 WellForm = ''\r
169 for Token in self.PostfixNotation:\r
170 if Token in self.SupportedOpcode:\r
171 WellForm += "\n " + Token\r
172 else:\r
173 WellForm += ' ' + Token\r
174 return WellForm\r
175\r
176 ## Split the expression string into token list\r
177 def GetExpressionTokenList(self):\r
178 self.TokenList = self.TokenPattern.findall(self.ExpressionString)\r
179\r
180 ## Convert token list into postfix notation\r
181 def GetPostfixNotation(self):\r
182 Stack = []\r
183 LastToken = ''\r
184 for Token in self.TokenList:\r
185 if Token == "(":\r
186 if LastToken not in self.SupportedOpcode + ['(', '', None]:\r
187 EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: missing operator before open parentheses",\r
188 ExtraData="Near %s" % LastToken)\r
189 Stack.append(Token)\r
190 elif Token == ")":\r
191 if '(' not in Stack:\r
192 EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: mismatched parentheses",\r
193 ExtraData=str(self))\r
194 elif LastToken in self.SupportedOpcode + ['', None]:\r
195 EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: missing operand before close parentheses",\r
196 ExtraData="Near %s" % LastToken)\r
197 while len(Stack) > 0:\r
198 if Stack[-1] == '(':\r
199 Stack.pop()\r
200 break\r
201 self.PostfixNotation.append(Stack.pop())\r
202 elif Token in self.OpcodePriority:\r
203 if Token == "NOT":\r
204 if LastToken not in self.SupportedOpcode + ['(', '', None]:\r
205 EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: missing operator before NOT",\r
206 ExtraData="Near %s" % LastToken)\r
207 elif LastToken in self.SupportedOpcode + ['(', '', None]:\r
208 EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: missing operand before " + Token,\r
209 ExtraData="Near %s" % LastToken)\r
210\r
211 while len(Stack) > 0:\r
212 if Stack[-1] == "(" or self.OpcodePriority[Token] >= self.OpcodePriority[Stack[-1]]:\r
213 break\r
214 self.PostfixNotation.append(Stack.pop())\r
215 Stack.append(Token)\r
216 self.OpcodeList.append(Token)\r
217 else:\r
218 if Token not in self.SupportedOpcode:\r
219 # not OP, take it as GUID\r
220 if LastToken not in self.SupportedOpcode + ['(', '', None]:\r
221 EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: missing operator before %s" % Token,\r
222 ExtraData="Near %s" % LastToken)\r
223 if len(self.OpcodeList) == 0 or self.OpcodeList[-1] not in self.ExclusiveOpcode:\r
224 if Token not in self.SupportedOperand:\r
225 self.PostfixNotation.append("PUSH")\r
226 # check if OP is valid in this phase\r
227 elif Token in self.Opcode[self.Phase]:\r
228 if Token == "END":\r
229 break\r
230 self.OpcodeList.append(Token)\r
231 else:\r
232 EdkLogger.error("GenDepex", PARSER_ERROR,\r
233 "Opcode=%s doesn't supported in %s stage " % (Token, self.Phase),\r
234 ExtraData=str(self))\r
235 self.PostfixNotation.append(Token)\r
236 LastToken = Token\r
237\r
238 # there should not be parentheses in Stack\r
239 if '(' in Stack or ')' in Stack:\r
240 EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid dependency expression: mismatched parentheses",\r
241 ExtraData=str(self))\r
242 while len(Stack) > 0:\r
243 self.PostfixNotation.append(Stack.pop())\r
244 if self.PostfixNotation[-1] != 'END':\r
245 self.PostfixNotation.append("END")\r
246\r
247 ## Validate the dependency expression\r
248 def ValidateOpcode(self):\r
249 for Op in self.AboveAllOpcode:\r
250 if Op in self.PostfixNotation:\r
251 if Op != self.PostfixNotation[0]:\r
252 EdkLogger.error("GenDepex", PARSER_ERROR, "%s should be the first opcode in the expression" % Op,\r
253 ExtraData=str(self))\r
254 if len(self.PostfixNotation) < 3:\r
255 EdkLogger.error("GenDepex", PARSER_ERROR, "Missing operand for %s" % Op,\r
256 ExtraData=str(self))\r
257 for Op in self.ExclusiveOpcode:\r
258 if Op in self.OpcodeList:\r
259 if len(self.OpcodeList) > 1:\r
260 EdkLogger.error("GenDepex", PARSER_ERROR, "%s should be the only opcode in the expression" % Op,\r
261 ExtraData=str(self))\r
262 if len(self.PostfixNotation) < 3:\r
263 EdkLogger.error("GenDepex", PARSER_ERROR, "Missing operand for %s" % Op,\r
264 ExtraData=str(self))\r
265 if self.TokenList[-1] != 'END' and self.TokenList[-1] in self.NonEndingOpcode:\r
266 EdkLogger.error("GenDepex", PARSER_ERROR, "Extra %s at the end of the dependency expression" % self.TokenList[-1],\r
267 ExtraData=str(self))\r
268 if self.TokenList[-1] == 'END' and self.TokenList[-2] in self.NonEndingOpcode:\r
269 EdkLogger.error("GenDepex", PARSER_ERROR, "Extra %s at the end of the dependency expression" % self.TokenList[-2],\r
270 ExtraData=str(self))\r
271 if "END" in self.TokenList and "END" != self.TokenList[-1]:\r
272 EdkLogger.error("GenDepex", PARSER_ERROR, "Extra expressions after END",\r
273 ExtraData=str(self))\r
274\r
275 ## Simply optimize the dependency expression by removing duplicated operands\r
276 def Optimize(self):\r
277 ValidOpcode = list(set(self.OpcodeList))\r
278 if len(ValidOpcode) != 1 or ValidOpcode[0] not in ['AND', 'OR']:\r
279 return\r
280 Op = ValidOpcode[0]\r
281 NewOperand = []\r
282 AllOperand = set()\r
283 for Token in self.PostfixNotation:\r
284 if Token in self.SupportedOpcode or Token in NewOperand:\r
285 continue\r
286 AllOperand.add(Token)\r
287 if Token == 'TRUE':\r
288 if Op == 'AND':\r
289 continue\r
290 else:\r
291 NewOperand.append(Token)\r
292 break\r
293 elif Token == 'FALSE':\r
294 if Op == 'OR':\r
295 continue\r
296 else:\r
297 NewOperand.append(Token)\r
298 break\r
299 NewOperand.append(Token)\r
300\r
301 # don't generate depex if only TRUE operand left\r
302 if self.ModuleType == 'PEIM' and len(NewOperand) == 1 and NewOperand[0] == 'TRUE':\r
303 self.PostfixNotation = []\r
304 return\r
305\r
306 # don't generate depex if all operands are architecture protocols\r
307 if self.ModuleType in ['UEFI_DRIVER', 'DXE_DRIVER', 'DXE_RUNTIME_DRIVER', 'DXE_SAL_DRIVER', 'DXE_SMM_DRIVER', 'MM_STANDALONE'] and \\r
308 Op == 'AND' and \\r
309 self.ArchProtocols == set([GuidStructureStringToGuidString(Guid) for Guid in AllOperand]):\r
310 self.PostfixNotation = []\r
311 return\r
312\r
313 if len(NewOperand) == 0:\r
314 self.TokenList = list(AllOperand)\r
315 else:\r
316 self.TokenList = []\r
317 while True:\r
318 self.TokenList.append(NewOperand.pop(0))\r
319 if NewOperand == []:\r
320 break\r
321 self.TokenList.append(Op)\r
322 self.PostfixNotation = []\r
323 self.GetPostfixNotation()\r
324\r
325\r
326 ## Convert a GUID value in C structure format into its binary form\r
327 #\r
328 # @param Guid The GUID value in C structure format\r
329 #\r
330 # @retval array The byte array representing the GUID value\r
331 #\r
332 def GetGuidValue(self, Guid):\r
333 GuidValueString = Guid.replace("{", "").replace("}", "").replace(" ", "")\r
334 GuidValueList = GuidValueString.split(",")\r
335 if len(GuidValueList) != 11:\r
336 EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid GUID value string or opcode: %s" % Guid)\r
337 return pack("1I2H8B", *(int(value, 16) for value in GuidValueList))\r
338\r
339 ## Save the binary form of dependency expression in file\r
340 #\r
341 # @param File The path of file. If None is given, put the data on console\r
342 #\r
343 # @retval True If the file doesn't exist or file is changed\r
344 # @retval False If file exists and is not changed.\r
345 #\r
346 def Generate(self, File=None):\r
347 Buffer = StringIO()\r
348 if len(self.PostfixNotation) == 0:\r
349 return False\r
350\r
351 for Item in self.PostfixNotation:\r
352 if Item in self.Opcode[self.Phase]:\r
353 Buffer.write(pack("B", self.Opcode[self.Phase][Item]))\r
354 elif Item in self.SupportedOpcode:\r
355 EdkLogger.error("GenDepex", FORMAT_INVALID,\r
356 "Opcode [%s] is not expected in %s phase" % (Item, self.Phase),\r
357 ExtraData=self.ExpressionString)\r
358 else:\r
359 Buffer.write(self.GetGuidValue(Item))\r
360\r
361 FilePath = ""\r
362 FileChangeFlag = True\r
363 if File is None:\r
364 sys.stdout.write(Buffer.getvalue())\r
365 FilePath = "STDOUT"\r
366 else:\r
367 FileChangeFlag = SaveFileOnChange(File, Buffer.getvalue(), True)\r
368\r
369 Buffer.close()\r
370 return FileChangeFlag\r
371\r
372versionNumber = ("0.04" + " " + gBUILD_VERSION)\r
373__version__ = "%prog Version " + versionNumber\r
374__copyright__ = "Copyright (c) 2007-2010, Intel Corporation All rights reserved."\r
375__usage__ = "%prog [options] [dependency_expression_file]"\r
376\r
377## Parse command line options\r
378#\r
379# @retval OptionParser\r
380#\r
381def GetOptions():\r
382 from optparse import OptionParser\r
383\r
384 Parser = OptionParser(description=__copyright__, version=__version__, usage=__usage__)\r
385\r
386 Parser.add_option("-o", "--output", dest="OutputFile", default=None, metavar="FILE",\r
387 help="Specify the name of depex file to be generated")\r
388 Parser.add_option("-t", "--module-type", dest="ModuleType", default=None,\r
389 help="The type of module for which the dependency expression serves")\r
390 Parser.add_option("-e", "--dependency-expression", dest="Expression", default="",\r
391 help="The string of dependency expression. If this option presents, the input file will be ignored.")\r
392 Parser.add_option("-m", "--optimize", dest="Optimize", default=False, action="store_true",\r
393 help="Do some simple optimization on the expression.")\r
394 Parser.add_option("-v", "--verbose", dest="verbose", default=False, action="store_true",\r
395 help="build with verbose information")\r
396 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
397 Parser.add_option("-q", "--quiet", dest="quiet", default=False, action="store_true",\r
398 help="build with little information")\r
399\r
400 return Parser.parse_args()\r
401\r
402\r
403## Entrance method\r
404#\r
405# @retval 0 Tool was successful\r
406# @retval 1 Tool failed\r
407#\r
408def Main():\r
409 EdkLogger.Initialize()\r
410 Option, Input = GetOptions()\r
411\r
412 # Set log level\r
413 if Option.quiet:\r
414 EdkLogger.SetLevel(EdkLogger.QUIET)\r
415 elif Option.verbose:\r
416 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
417 elif Option.debug is not None:\r
418 EdkLogger.SetLevel(Option.debug + 1)\r
419 else:\r
420 EdkLogger.SetLevel(EdkLogger.INFO)\r
421\r
422 try:\r
423 if Option.ModuleType is None or Option.ModuleType not in gType2Phase:\r
424 EdkLogger.error("GenDepex", OPTION_MISSING, "Module type is not specified or supported")\r
425\r
426 DxsFile = ''\r
427 if len(Input) > 0 and Option.Expression == "":\r
428 DxsFile = Input[0]\r
429 DxsString = open(DxsFile, 'r').read().replace("\n", " ").replace("\r", " ")\r
430 DxsString = gStartClosePattern.sub("\\1", DxsString)\r
431 elif Option.Expression != "":\r
432 if Option.Expression[0] == '"':\r
433 DxsString = Option.Expression[1:-1]\r
434 else:\r
435 DxsString = Option.Expression\r
436 else:\r
437 EdkLogger.error("GenDepex", OPTION_MISSING, "No expression string or file given")\r
438\r
439 Dpx = DependencyExpression(DxsString, Option.ModuleType, Option.Optimize)\r
440 if Option.OutputFile is not None:\r
441 FileChangeFlag = Dpx.Generate(Option.OutputFile)\r
442 if not FileChangeFlag and DxsFile:\r
443 #\r
444 # Touch the output file if its time stamp is older than the original\r
445 # DXS file to avoid re-invoke this tool for the dependency check in build rule.\r
446 #\r
447 if os.stat(DxsFile)[8] > os.stat(Option.OutputFile)[8]:\r
448 os.utime(Option.OutputFile, None)\r
449 else:\r
450 Dpx.Generate()\r
451 except BaseException, X:\r
452 EdkLogger.quiet("")\r
453 if Option is not None and Option.debug is not None:\r
454 EdkLogger.quiet(traceback.format_exc())\r
455 else:\r
456 EdkLogger.quiet(str(X))\r
457 return 1\r
458\r
459 return 0\r
460\r
461if __name__ == '__main__':\r
462 sys.exit(Main())\r
463\r