]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/AutoGen/GenDepex.py
BaseTools: remove redundant content in InfSectionParser
[mirror_edk2.git] / BaseTools / Source / Python / AutoGen / GenDepex.py
CommitLineData
30fdf114
LG
1## @file\r
2# This file is used to generate DEPEX file for module's dependency expression\r
3#\r
1be2ed90 4# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>\r
40d841f6 5# This program and the accompanying materials\r
30fdf114
LG
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
1be2ed90 16import Common.LongFilePathOs as os\r
30fdf114
LG
17import re\r
18import traceback\r
1be2ed90 19from Common.LongFilePathSupport import OpenLongFilePath as open\r
30fdf114
LG
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
b36d134f 26from Common.BuildVersion import gBUILD_VERSION\r
8bb63e37 27from Common.DataType import *\r
30fdf114
LG
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
8bb63e37
CJ
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
30fdf114
LG
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
5a9c3e3e
SV
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
30fdf114
LG
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
8bb63e37 303 if self.ModuleType == SUP_MODULE_PEIM and len(NewOperand) == 1 and NewOperand[0] == 'TRUE':\r
30fdf114 304 self.PostfixNotation = []\r
47fea6af 305 return\r
30fdf114
LG
306\r
307 # don't generate depex if all operands are architecture protocols\r
8bb63e37 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
30fdf114
LG
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
4231a819 364 if File is None:\r
30fdf114
LG
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
b36d134f 373versionNumber = ("0.04" + " " + gBUILD_VERSION)\r
30fdf114 374__version__ = "%prog Version " + versionNumber\r
52302d4d 375__copyright__ = "Copyright (c) 2007-2010, Intel Corporation All rights reserved."\r
30fdf114
LG
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
4231a819 418 elif Option.debug is not None:\r
30fdf114
LG
419 EdkLogger.SetLevel(Option.debug + 1)\r
420 else:\r
421 EdkLogger.SetLevel(EdkLogger.INFO)\r
422\r
423 try:\r
4231a819 424 if Option.ModuleType is None or Option.ModuleType not in gType2Phase:\r
30fdf114
LG
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
4231a819 441 if Option.OutputFile is not None:\r
14c48571 442 FileChangeFlag = Dpx.Generate(Option.OutputFile)\r
47fea6af 443 if not FileChangeFlag and DxsFile:\r
14c48571 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
30fdf114
LG
450 else:\r
451 Dpx.Generate()\r
452 except BaseException, X:\r
453 EdkLogger.quiet("")\r
4231a819 454 if Option is not None and Option.debug is not None:\r
30fdf114
LG
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