24f028cf0eebd421eb433957178cd46c53276a2c
[people/mcb30/basetools.git] / Source / Python / AutoGen / GenDepex.py
1 # Copyright (c) 2007, Intel Corporation
2 # All rights reserved. This program and the accompanying materials
3 # are licensed and made available under the terms and conditions of the BSD License
4 # which accompanies this distribution.    The full text of the license may be found at
5 # http://opensource.org/licenses/bsd-license.php
6 #
7 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
8 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
9
10 #
11 # This file is used to generate DEPEX file for module's dependency expression
12 #
13
14 import sys
15 import os
16 import re
17 from StringIO import StringIO
18 from struct import pack
19 from EdkIIWorkspace import CreateDirectory
20 from BuildToolError import *
21
22 gType2Phase = {
23     "BASE"              :   None,
24     "SEC"               :   "PEI",
25     "PEI_CORE"          :   "PEI",
26     "PEIM"              :   "PEI",
27     "DXE_CORE"          :   "DXE",
28     "DXE_DRIVER"        :   "DXE",
29     "DXE_SMM_DRIVER"    :   "DXE",
30     "DXE_RUNTIME_DRIVER":   "DXE",
31     "DXE_SAL_DRIVER"    :   "DXE",
32     "UEFI_DRIVER"       :   "DXE",
33     "UEFI_APPLICATION"  :   "DXE",
34 }
35
36 class DependencyExpression:
37
38     OpcodePriority = {
39         "AND"   :   1,
40         "OR"    :   1,
41         "NOT"   :   2,
42         "SOR"   :   9,
43         "BEFORE":   9,
44         "AFTER" :   9,
45     }
46
47     Opcode = {
48         "PEI"   : {
49             "PUSH"  :   0x02,
50             "AND"   :   0x03,
51             "OR"    :   0x04,
52             "NOT"   :   0x05,
53             "TRUE"  :   0x06,
54             "FALSE" :   0x07,
55             "END"   :   0x08
56         },
57
58         "DXE"   : {
59             "BEFORE":   0x00,
60             "AFTER" :   0x01,
61             "PUSH"  :   0x02,
62             "AND"   :   0x03,
63             "OR"    :   0x04,
64             "NOT"   :   0x05,
65             "TRUE"  :   0x06,
66             "FALSE" :   0x07,
67             "END"   :   0x08,
68             "SOR"   :   0x09
69         }
70     }
71
72     SupportedOpcode = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
73     
74     NonEndingOpcode = ["AND", "OR"]
75
76     ExclusiveOpcode = ["BEFORE", "AFTER"]
77     
78     AboveAllOpcode = ["SOR"]
79
80     #
81     # open and close brace must be taken as individual tokens
82     #
83     TokenPattern = re.compile("(\(|\)|\{[^{}]+\{[^{}]+\}[ ]*\}|\w+)")
84     
85     def __init__(self, expression, mtype):
86         self.Phase = gType2Phase[mtype]
87         if type(expression) == type([]):
88             self.ExpressionString = " ".join(expression)
89             self.TokenList = expression
90         else:
91             self.ExpressionString = expression
92             self.GetExpressionTokenList()
93
94         self.PostfixNotation = []
95         self.OpcodeList = []
96
97         self.GetPostfixNotation()
98         self.ValidateOpcode()
99
100     def GetExpressionTokenList(self):
101         self.TokenList = self.TokenPattern.findall(self.ExpressionString)
102
103     def GetPostfixNotation(self):
104         stack = []
105         for token in self.TokenList:
106             if token == "(":
107                 stack.append(token)
108             elif token == ")":
109                 while len(stack) > 0:
110                     if stack[-1] == '(':
111                         stack.pop()
112                         break
113                     self.PostfixNotation.append(stack.pop())
114             elif token in self.OpcodePriority:
115                 while len(stack) > 0:
116                     if stack[-1] == "(" or self.OpcodePriority[token] > self.OpcodePriority[stack[-1]]:
117                         break
118                     self.PostfixNotation.append(stack.pop())
119                 stack.append(token)
120                 self.OpcodeList.append(token)
121             else:
122                 if token not in self.Opcode[self.Phase]:
123                     self.PostfixNotation.append("PUSH")
124                 else:
125                     self.OpcodeList.append(token)
126                 self.PostfixNotation.append(token)
127         while len(stack) > 0:
128             self.PostfixNotation.append(stack.pop())
129         self.PostfixNotation.append("END")
130         #print "  ","\n   ".join(self.PostfixNotation)
131
132     def ValidateOpcode(self):
133         for op in self.AboveAllOpcode:
134             if op in self.OpcodeList and op != self.OpcodeList[0]:
135                 raise AutoGenError("Opcode=%s should be the first one in expression", op)
136         for op in self.ExclusiveOpcode:
137             if op in self.OpcodeList and len(self.OpcodeList) > 1:
138                 raise AutoGenError("Opcode=%s should be only opcode in expression", op)
139         # print "######", self.ExpressionString
140         if self.TokenList[-1] in self.NonEndingOpcode:
141             raise AutoGenError("Extra %s at the end of dependency expression" % self.TokenList[-1])
142
143     def GetGuidValue(self, guid):
144         guidValueString = guid.replace("{", "").replace("}", "").replace(" ", "")
145         guidValueList = guidValueString.split(",")
146         if len(guidValueList) != 11:
147             raise AutoGenError("Invalid GUID value string or opcode: %s" % guid)
148         return pack("1I2H8B", *(int(value, 16) for value in guidValueList))
149
150     def SaveFile(self, file, content):
151         CreateDirectory(os.path.dirname(file))
152         f = None
153         if os.path.exists(file):
154             f = open(file, 'rb')
155             if content == f.read():
156                 f.close()
157                 return
158             f.close()
159         f = open(file, "wb")
160         f.write(content)
161         f.close()
162
163     def Generate(self, file=None):
164         buffer = StringIO()
165         for item in self.PostfixNotation:
166             if item in self.Opcode[self.Phase]:
167                 buffer.write(pack("B", self.Opcode[self.Phase][item]))
168             else:
169                 buffer.write(self.GetGuidValue(item))
170
171         filePath = ""
172         if file == None:
173             sys.stdout.write(buffer.getvalue())
174             filePath = "STDOUT"
175         else:
176             self.SaveFile(file, buffer.getvalue())
177             filePath = file
178
179         buffer.close()
180         return filePath
181
182 versionNumber = "0.01"
183 __version__ = "%prog Version " + versionNumber
184 __copyright__ = "Copyright (c) 2007, Intel Corporation  All rights reserved."
185 __usage__ = "%prog [options] [dependency_expression_file]"
186
187 def GetOptions():
188     from optparse import OptionParser
189
190     parser = OptionParser(description=__copyright__, version=__version__, usage=__usage__)
191
192     parser.add_option("-o", "--output", dest="OutputFile", default=None, metavar="FILE",
193                       help="Specify the name of depex file to be generated")
194     parser.add_option("-t", "--module-type", dest="ModuleType", default=None,
195                       help="The type of module for which the dependency expression serves")
196     parser.add_option("-e", "--dependency-expression", dest="Expression", default="",
197                       help="The string of dependency expression. If this option presents, the input file will be ignored.")
198     parser.add_option("-v", "--verbose", dest="verbose", default=False, action="store_true",
199                       help="build with verbose information")
200     parser.add_option("-d", "--debug", dest="debug", default=False, action="store_true",
201                       help="build with debug information")
202     parser.add_option("-q", "--quiet", dest="quiet", default=False, action="store_true",
203                       help="build with little information")
204
205     return parser.parse_args()
206
207
208 def Main():
209     option, input = GetOptions()
210     if option.ModuleType == None or option.ModuleType not in gType2Phase:
211         print "Module type is not specified or supported"
212         return -1
213
214     try:
215         if len(input) > 0 and option.Expression == "":
216             dxsFile = input[0]
217             dxsString = open(dxsFile, 'r').read().replace("\n", " ").replace("\r", " ")
218             dxsString = re.compile("DEPENDENCY_START(.+)DEPENDENCY_END").findall(dxsString)[0]
219         elif option.Expression != "":
220             dxsString = option.Expression
221         else:
222             print "No expression string or file given"
223             return -1
224
225         dpx = DependencyExpression(dxsString, option.ModuleType)
226
227         if option.OutputFile != None:
228             dpx.Generate(option.OutputFile)
229         else:
230             dpx.Generate()
231     except Exception, e:
232         return -1
233
234     return 0
235
236 if __name__ == '__main__':
237     sys.exit(Main())