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