cf11121921a2ada8477b5145fcd17e3310d9827b
[people/mcb30/basetools.git] / Source / Python / AutoGen / GenDepex.py
1 ## @file\r
2 # This file is used to generate DEPEX file for module's dependency expression\r
3 #\r
4 # Copyright (c) 2007, Intel Corporation\r
5 # All rights reserved. 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
15 import sys\r
16 import os\r
17 import re\r
18 import traceback\r
19 \r
20 from StringIO import StringIO\r
21 from struct import pack\r
22 from Common.BuildToolError import *\r
23 from Common.Misc import SaveFileOnChange\r
24 from Common import EdkLogger as EdkLogger\r
25 \r
26 import antlr3\r
27 from DepexLexer import DepexLexer\r
28 from DepexParser import DepexParser\r
29 \r
30 ## Mapping between module type and EFI phase\r
31 gType2Phase = {\r
32     "BASE"              :   None,\r
33     "SEC"               :   "PEI",\r
34     "PEI_CORE"          :   "PEI",\r
35     "PEIM"              :   "PEI",\r
36     "DXE_CORE"          :   "DXE",\r
37     "DXE_DRIVER"        :   "DXE",\r
38     "DXE_SMM_DRIVER"    :   "DXE",\r
39     "DXE_RUNTIME_DRIVER":   "DXE",\r
40     "DXE_SAL_DRIVER"    :   "DXE",\r
41     "UEFI_DRIVER"       :   "DXE",\r
42     "UEFI_APPLICATION"  :   "DXE",\r
43 }\r
44 \r
45 ## Convert dependency expression string into EFI internal representation\r
46\r
47 #   DependencyExpression class is used to parse dependency expression string and\r
48 # convert it into its binary form.\r
49\r
50 class DependencyExpression:\r
51 \r
52     OpcodePriority = {\r
53         "AND"   :   1,\r
54         "OR"    :   1,\r
55         "NOT"   :   2,\r
56         # "SOR"   :   9,\r
57         # "BEFORE":   9,\r
58         # "AFTER" :   9,\r
59     }\r
60 \r
61     Opcode = {\r
62         "PEI"   : {\r
63             "PUSH"  :   0x02,\r
64             "AND"   :   0x03,\r
65             "OR"    :   0x04,\r
66             "NOT"   :   0x05,\r
67             "TRUE"  :   0x06,\r
68             "FALSE" :   0x07,\r
69             "END"   :   0x08\r
70         },\r
71 \r
72         "DXE"   : {\r
73             "BEFORE":   0x00,\r
74             "AFTER" :   0x01,\r
75             "PUSH"  :   0x02,\r
76             "AND"   :   0x03,\r
77             "OR"    :   0x04,\r
78             "NOT"   :   0x05,\r
79             "TRUE"  :   0x06,\r
80             "FALSE" :   0x07,\r
81             "END"   :   0x08,\r
82             "SOR"   :   0x09\r
83         }\r
84     }\r
85 \r
86     # all supported op codes and operands\r
87     SupportedOpcode = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "END", "SOR"]\r
88     SupportedOperand = ["TRUE", "FALSE"]\r
89     ## Constructor\r
90     # \r
91     #   @param  Expression  The list or string of dependency expression\r
92     #   @param  ModuleType  The type of the module using the dependency expression\r
93     # \r
94     def __init__(self, Expression, ModuleType, Optimize=False, File=''):\r
95         self.Phase = gType2Phase[ModuleType]\r
96         if type(Expression) == type([]):\r
97             self.ExpressionString = " ".join(Expression)\r
98         else:\r
99             self.ExpressionString = Expression\r
100 \r
101         self.File = File\r
102         self.Tokens = None\r
103         self.Parser = None\r
104 \r
105         self.PostfixNotation = []\r
106         self.TokenList = []\r
107         self.OpcodeList = []\r
108 \r
109         self.Parse()\r
110         if Optimize:\r
111             self.Optimize()\r
112 \r
113     def __str__(self):\r
114         return " ".join(self.PostfixNotation)\r
115 \r
116     def Parse(self):\r
117         self.Tokens = antlr3.CommonTokenStream(DepexLexer(antlr3.ANTLRStringStream(self.ExpressionString)))\r
118         self.Tokens.fillBuffer()\r
119         self.Parser = DepexParser(self.Tokens)\r
120         self.Parser.start(self.File)\r
121 \r
122         self.PostfixNotation = self.Parser.PostfixNotation\r
123         self.TokenList = self.Parser.TokenList\r
124         self.OpcodeList = self.Parser.OpcodeList\r
125 \r
126     ## Simply optimize the dependency expression by removing duplicated operands\r
127     def Optimize(self):\r
128         ValidOpcode = list(set(self.OpcodeList))\r
129         if len(ValidOpcode) != 1 or ValidOpcode[0] not in ['AND', 'OR']:\r
130             return\r
131         Op = ValidOpcode[0]\r
132         NewOperand = []\r
133         for Token in self.PostfixNotation:\r
134             if Token in self.SupportedOpcode or Token in NewOperand:\r
135                 continue\r
136             if Token == 'TRUE':\r
137                 if Op == 'AND':\r
138                     continue\r
139                 else:\r
140                     NewOperand.append(Token)\r
141                     break\r
142             elif Token == 'FALSE':\r
143                 if Op == 'OR':\r
144                     continue\r
145                 else:\r
146                     NewOperand.append(Token)\r
147                     break\r
148             NewOperand.append(Token)\r
149 \r
150         self.TokenList = []\r
151         while True:\r
152             self.TokenList.append(NewOperand.pop(0))\r
153             if NewOperand == []:\r
154                 break\r
155             self.TokenList.append(Op)\r
156         self.PostfixNotation = []\r
157         self.ExpressionString = ' '.join(self.TokenList)\r
158         self.Parse()\r
159 \r
160     ## Convert a GUID value in C structure format into its binary form\r
161     #\r
162     #   @param  Guid    The GUID value in C structure format\r
163     # \r
164     #   @retval array   The byte array representing the GUID value\r
165     # \r
166     def GetGuidValue(self, Guid):\r
167         GuidValueString = Guid.replace("{", "").replace("}", "").replace(" ", "")\r
168         GuidValueList = GuidValueString.split(",")\r
169         if len(GuidValueList) != 11:\r
170             EdkLogger.error("GenDepex", PARSER_ERROR, "Invalid GUID value string or opcode: %s" % Guid)\r
171         return pack("1I2H8B", *(int(value, 16) for value in GuidValueList))\r
172 \r
173     ## Save the binary form of dependency expression in file\r
174     #\r
175     #   @param  File    The path of file. If None is given, put the data on console\r
176     # \r
177     #   @retval True    If the file doesn't exist or file is changed\r
178     #   @retval False   If file exists and is not changed.\r
179     # \r
180     def Generate(self, File=None):\r
181         Buffer = StringIO()\r
182         for Item in self.PostfixNotation:\r
183             if Item in self.Opcode[self.Phase]:\r
184                 Buffer.write(pack("B", self.Opcode[self.Phase][Item]))\r
185             elif Item in self.SupportedOpcode:\r
186                 EdkLogger.error("GenDepex", FORMAT_INVALID, \r
187                                 "Opcode [%s] is not expected in %s phase" % (Item, self.Phase),\r
188                                 ExtraData=self.ExpressionString)\r
189             else:\r
190                 Buffer.write(self.GetGuidValue(Item))\r
191 \r
192         FilePath = ""\r
193         FileChangeFlag = True\r
194         if File == None:\r
195             sys.stdout.write(Buffer.getvalue())\r
196             FilePath = "STDOUT"\r
197         else:\r
198             FileChangeFlag = SaveFileOnChange(File, Buffer.getvalue(), True)\r
199 \r
200         Buffer.close()\r
201         return FileChangeFlag\r
202 \r
203 versionNumber = "0.03"\r
204 __version__ = "%prog Version " + versionNumber\r
205 __copyright__ = "Copyright (c) 2007-2008, Intel Corporation  All rights reserved."\r
206 __usage__ = "%prog [options] [dependency_expression_file]"\r
207 \r
208 ## Parse command line options\r
209 #\r
210 #   @retval OptionParser\r
211\r
212 def GetOptions():\r
213     from optparse import OptionParser\r
214 \r
215     Parser = OptionParser(description=__copyright__, version=__version__, usage=__usage__)\r
216 \r
217     Parser.add_option("-o", "--output", dest="OutputFile", default=None, metavar="FILE",\r
218                       help="Specify the name of depex file to be generated")\r
219     Parser.add_option("-t", "--module-type", dest="ModuleType", default=None,\r
220                       help="The type of module for which the dependency expression serves")\r
221     Parser.add_option("-e", "--dependency-expression", dest="Expression", default="",\r
222                       help="The string of dependency expression. If this option presents, the input file will be ignored.")\r
223     Parser.add_option("-m", "--optimize", dest="Optimize", default=False, action="store_true",\r
224                       help="Do some simple optimization on the expression.")\r
225     Parser.add_option("-v", "--verbose", dest="verbose", default=False, action="store_true",\r
226                       help="build with verbose information")\r
227     Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
228     Parser.add_option("-q", "--quiet", dest="quiet", default=False, action="store_true",\r
229                       help="build with little information")\r
230 \r
231     return Parser.parse_args()\r
232 \r
233 \r
234 ## Entrance method\r
235 #\r
236 # @retval 0     Tool was successful\r
237 # @retval 1     Tool failed\r
238 #\r
239 def Main():\r
240     EdkLogger.Initialize()\r
241     Option, Input = GetOptions()\r
242 \r
243     # Set log level\r
244     if Option.verbose != None:\r
245         EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
246     elif Option.quiet != None:\r
247         EdkLogger.SetLevel(EdkLogger.QUIET)\r
248     elif Option.debug != None:\r
249         EdkLogger.SetLevel(Option.debug + 1)\r
250     else:\r
251         EdkLogger.SetLevel(EdkLogger.INFO)\r
252 \r
253     try:\r
254         if Option.ModuleType == None or Option.ModuleType not in gType2Phase:\r
255             EdkLogger.error("GenDepex", OPTION_MISSING, "Module type is not specified or supported")\r
256 \r
257         DxsFile = ''\r
258         if len(Input) > 0 and Option.Expression == "":\r
259             DxsFile = Input[0]\r
260             DxsString = open(DxsFile, 'r').read()\r
261         elif Option.Expression != "":\r
262             if Option.Expression[0] == '"':\r
263                 DxsString = Option.Expression[1:-1]\r
264             else:\r
265                 DxsString = Option.Expression\r
266         else:\r
267             EdkLogger.error("GenDepex", OPTION_MISSING, "No expression string or file given")\r
268 \r
269         DxsString += '\n'\r
270         Dpx = DependencyExpression(DxsString, Option.ModuleType, Option.Optimize, DxsFile)\r
271 \r
272         if Option.OutputFile != None:\r
273             Dpx.Generate(Option.OutputFile)\r
274         else:\r
275             Dpx.Generate()\r
276     except BaseException, X:\r
277         EdkLogger.quiet("")\r
278         if Option != None and Option.debug != None:\r
279             EdkLogger.quiet(traceback.format_exc())\r
280         else:\r
281             EdkLogger.quiet(str(X))\r
282         return 1\r
283 \r
284     return 0\r
285 \r
286 if __name__ == '__main__':\r
287     sys.exit(Main())\r
288 \r