]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Common/ToolDefClassObject.py
BaseTools: Add new RegExp for future use
[mirror_edk2.git] / BaseTools / Source / Python / Common / ToolDefClassObject.py
CommitLineData
30fdf114
LG
1## @file\r
2# This file is used to define each component of tools_def.txt file\r
3#\r
18ca2fec 4# Copyright (c) 2007 - 2016, 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\r
14##\r
15# Import Modules\r
16#\r
1be2ed90 17import Common.LongFilePathOs as os\r
30fdf114
LG
18import re\r
19import EdkLogger\r
20\r
21from Dictionary import *\r
22from BuildToolError import *\r
23from TargetTxtClassObject import *\r
1be2ed90 24from Common.LongFilePathSupport import OpenLongFilePath as open\r
8ac46e4e
MZ
25from Common.Misc import PathClass\r
26from Common.String import NormPath\r
27import Common.GlobalData as GlobalData\r
28from Common import GlobalData\r
29from Common.MultipleWorkspace import MultipleWorkspace as mws\r
30fdf114
LG
30\r
31##\r
08dd311f 32# Static variables used for pattern\r
30fdf114
LG
33#\r
34gMacroRefPattern = re.compile('(DEF\([^\(\)]+\))')\r
35gEnvRefPattern = re.compile('(ENV\([^\(\)]+\))')\r
36gMacroDefPattern = re.compile("DEFINE\s+([^\s]+)")\r
97fa0ee9 37gDefaultToolsDefFile = "tools_def.txt"\r
30fdf114
LG
38\r
39## ToolDefClassObject\r
40#\r
41# This class defined content used in file tools_def.txt\r
42#\r
43# @param object: Inherited from object class\r
44# @param Filename: Input value for full path of tools_def.txt\r
45#\r
46# @var ToolsDefTxtDictionary: To store keys and values defined in target.txt\r
47# @var MacroDictionary: To store keys and values defined in DEFINE statement\r
48#\r
49class ToolDefClassObject(object):\r
47fea6af 50 def __init__(self, FileName=None):\r
30fdf114
LG
51 self.ToolsDefTxtDictionary = {}\r
52 self.MacroDictionary = {}\r
53 for Env in os.environ:\r
54 self.MacroDictionary["ENV(%s)" % Env] = os.environ[Env]\r
55\r
56 if FileName != None:\r
57 self.LoadToolDefFile(FileName)\r
58\r
59 ## LoadToolDefFile\r
60 #\r
8b14b35b 61 # Load target.txt file and parse it\r
30fdf114
LG
62 #\r
63 # @param Filename: Input value for full path of tools_def.txt\r
64 #\r
65 def LoadToolDefFile(self, FileName):\r
8ac46e4e
MZ
66 # set multiple workspace\r
67 PackagesPath = os.getenv("PACKAGES_PATH")\r
68 mws.setWs(GlobalData.gWorkspace, PackagesPath)\r
69\r
70 self.ToolsDefTxtDatabase = {\r
71 TAB_TOD_DEFINES_TARGET : [],\r
72 TAB_TOD_DEFINES_TOOL_CHAIN_TAG : [],\r
73 TAB_TOD_DEFINES_TARGET_ARCH : [],\r
74 TAB_TOD_DEFINES_COMMAND_TYPE : []\r
75 }\r
76\r
77 self.IncludeToolDefFile(FileName)\r
78\r
6608330d
MZ
79 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET]))\r
80 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]))\r
81 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH]))\r
82\r
83 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE]))\r
84\r
85 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET].sort()\r
86 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG].sort()\r
87 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH].sort()\r
88 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE].sort()\r
89\r
90 KeyList = [TAB_TOD_DEFINES_TARGET, TAB_TOD_DEFINES_TOOL_CHAIN_TAG, TAB_TOD_DEFINES_TARGET_ARCH, TAB_TOD_DEFINES_COMMAND_TYPE]\r
91 for Index in range(3, -1, -1):\r
92 for Key in dict(self.ToolsDefTxtDictionary):\r
93 List = Key.split('_')\r
94 if List[Index] == '*':\r
95 for String in self.ToolsDefTxtDatabase[KeyList[Index]]:\r
96 List[Index] = String\r
97 NewKey = '%s_%s_%s_%s_%s' % tuple(List)\r
98 if NewKey not in self.ToolsDefTxtDictionary:\r
99 self.ToolsDefTxtDictionary[NewKey] = self.ToolsDefTxtDictionary[Key]\r
100 continue\r
101 del self.ToolsDefTxtDictionary[Key]\r
102 elif List[Index] not in self.ToolsDefTxtDatabase[KeyList[Index]]:\r
103 del self.ToolsDefTxtDictionary[Key]\r
104\r
8ac46e4e
MZ
105\r
106 ## IncludeToolDefFile\r
107 #\r
108 # Load target.txt file and parse it as if it's contents were inside the main file\r
109 #\r
110 # @param Filename: Input value for full path of tools_def.txt\r
111 #\r
112 def IncludeToolDefFile(self, FileName):\r
30fdf114
LG
113 FileContent = []\r
114 if os.path.isfile(FileName):\r
115 try:\r
47fea6af 116 F = open(FileName, 'r')\r
30fdf114
LG
117 FileContent = F.readlines()\r
118 except:\r
119 EdkLogger.error("tools_def.txt parser", FILE_OPEN_FAILURE, ExtraData=FileName)\r
120 else:\r
121 EdkLogger.error("tools_def.txt parser", FILE_NOT_FOUND, ExtraData=FileName)\r
122\r
30fdf114
LG
123 for Index in range(len(FileContent)):\r
124 Line = FileContent[Index].strip()\r
125 if Line == "" or Line[0] == '#':\r
126 continue\r
8ac46e4e
MZ
127\r
128 if Line.startswith("!include"):\r
129 IncFile = Line[8:].strip()\r
130 Done, IncFile = self.ExpandMacros(IncFile)\r
131 if not Done:\r
132 EdkLogger.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE,\r
133 "Macro or Environment has not been defined",\r
134 ExtraData=IncFile[4:-1], File=FileName, Line=Index+1)\r
135 IncFile = NormPath(IncFile)\r
136\r
137 if not os.path.isabs(IncFile):\r
138 #\r
139 # try WORKSPACE\r
140 #\r
141 IncFileTmp = PathClass(IncFile, GlobalData.gWorkspace)\r
142 ErrorCode = IncFileTmp.Validate()[0]\r
143 if ErrorCode != 0:\r
144 #\r
145 # try PACKAGES_PATH\r
146 #\r
147 IncFileTmp = mws.join(GlobalData.gWorkspace, IncFile)\r
148 if not os.path.exists(IncFileTmp):\r
149 #\r
150 # try directory of current file\r
151 #\r
152 IncFileTmp = PathClass(IncFile, os.path.dirname(FileName))\r
153 ErrorCode = IncFileTmp.Validate()[0]\r
154 if ErrorCode != 0:\r
155 EdkLogger.error("tools_def.txt parser", FILE_NOT_FOUND, ExtraData=IncFile)\r
156\r
157 if type(IncFileTmp) is PathClass:\r
158 IncFile = IncFileTmp.Path\r
159 else:\r
160 IncFile = IncFileTmp\r
161\r
162 self.IncludeToolDefFile(IncFile)\r
163 continue\r
164\r
30fdf114
LG
165 NameValuePair = Line.split("=", 1)\r
166 if len(NameValuePair) != 2:\r
167 EdkLogger.warn("tools_def.txt parser", "Line %d: not correct assignment statement, skipped" % (Index + 1))\r
168 continue\r
169\r
170 Name = NameValuePair[0].strip()\r
171 Value = NameValuePair[1].strip()\r
172\r
173 if Name == "IDENTIFIER":\r
174 EdkLogger.debug(EdkLogger.DEBUG_8, "Line %d: Found identifier statement, skipped: %s" % ((Index + 1), Value))\r
175 continue\r
176\r
177 MacroDefinition = gMacroDefPattern.findall(Name)\r
178 if MacroDefinition != []:\r
179 Done, Value = self.ExpandMacros(Value)\r
180 if not Done:\r
181 EdkLogger.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE,\r
182 "Macro or Environment has not been defined",\r
183 ExtraData=Value[4:-1], File=FileName, Line=Index+1)\r
184\r
185 MacroName = MacroDefinition[0].strip()\r
186 self.MacroDictionary["DEF(%s)" % MacroName] = Value\r
187 EdkLogger.debug(EdkLogger.DEBUG_8, "Line %d: Found macro: %s = %s" % ((Index + 1), MacroName, Value))\r
188 continue\r
189\r
190 Done, Value = self.ExpandMacros(Value)\r
191 if not Done:\r
192 EdkLogger.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE,\r
193 "Macro or Environment has not been defined",\r
194 ExtraData=Value[4:-1], File=FileName, Line=Index+1)\r
195\r
196 List = Name.split('_')\r
197 if len(List) != 5:\r
198 EdkLogger.verbose("Line %d: Not a valid name of definition: %s" % ((Index + 1), Name))\r
199 continue\r
200 elif List[4] == '*':\r
201 EdkLogger.verbose("Line %d: '*' is not allowed in last field: %s" % ((Index + 1), Name))\r
202 continue\r
203 else:\r
204 self.ToolsDefTxtDictionary[Name] = Value\r
205 if List[0] != '*':\r
206 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET] += [List[0]]\r
207 if List[1] != '*':\r
208 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG] += [List[1]]\r
209 if List[2] != '*':\r
210 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH] += [List[2]]\r
211 if List[3] != '*':\r
212 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE] += [List[3]]\r
213 if List[4] == TAB_TOD_DEFINES_FAMILY and List[2] == '*' and List[3] == '*':\r
214 if TAB_TOD_DEFINES_FAMILY not in self.ToolsDefTxtDatabase:\r
215 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY] = {}\r
216 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][List[1]] = Value\r
217 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY] = {}\r
218 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][List[1]] = Value\r
219 elif List[1] not in self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY]:\r
220 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][List[1]] = Value\r
221 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][List[1]] = Value\r
222 elif self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][List[1]] != Value:\r
223 EdkLogger.verbose("Line %d: No override allowed for the family of a tool chain: %s" % ((Index + 1), Name))\r
224 if List[4] == TAB_TOD_DEFINES_BUILDRULEFAMILY and List[2] == '*' and List[3] == '*':\r
225 if TAB_TOD_DEFINES_BUILDRULEFAMILY not in self.ToolsDefTxtDatabase \\r
226 or List[1] not in self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY]:\r
227 EdkLogger.verbose("Line %d: The family is not specified, but BuildRuleFamily is specified for the tool chain: %s" % ((Index + 1), Name))\r
228 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][List[1]] = Value\r
229\r
30fdf114
LG
230 ## ExpandMacros\r
231 #\r
232 # Replace defined macros with real value\r
233 #\r
234 # @param Value: The string with unreplaced macros\r
235 #\r
236 # @retval Value: The string which has been replaced with real value\r
237 #\r
238 def ExpandMacros(self, Value):\r
18ca2fec 239 # os.environ contains all environment variables uppercase on Windows which cause the key in the self.MacroDictionary is uppercase, but Ref may not\r
30fdf114
LG
240 EnvReference = gEnvRefPattern.findall(Value)\r
241 for Ref in EnvReference:\r
18ca2fec 242 if Ref not in self.MacroDictionary and Ref.upper() not in self.MacroDictionary:\r
da92f276
LG
243 Value = Value.replace(Ref, "")\r
244 else:\r
18ca2fec
YZ
245 if Ref in self.MacroDictionary:\r
246 Value = Value.replace(Ref, self.MacroDictionary[Ref])\r
247 else:\r
248 Value = Value.replace(Ref, self.MacroDictionary[Ref.upper()])\r
30fdf114
LG
249 MacroReference = gMacroRefPattern.findall(Value)\r
250 for Ref in MacroReference:\r
251 if Ref not in self.MacroDictionary:\r
252 return False, Ref\r
253 Value = Value.replace(Ref, self.MacroDictionary[Ref])\r
254\r
255 return True, Value\r
256\r
257## ToolDefDict\r
258#\r
97fa0ee9 259# Load tools_def.txt in input Conf dir\r
30fdf114 260#\r
97fa0ee9 261# @param ConfDir: Conf dir\r
30fdf114
LG
262#\r
263# @retval ToolDef An instance of ToolDefClassObject() with loaded tools_def.txt\r
264#\r
97fa0ee9
YL
265def ToolDefDict(ConfDir):\r
266 Target = TargetTxtDict(ConfDir)\r
30fdf114
LG
267 ToolDef = ToolDefClassObject()\r
268 if DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF in Target.TargetTxtDictionary:\r
97fa0ee9
YL
269 ToolsDefFile = Target.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]\r
270 if ToolsDefFile:\r
271 ToolDef.LoadToolDefFile(os.path.normpath(ToolsDefFile))\r
272 else:\r
273 ToolDef.LoadToolDefFile(os.path.normpath(os.path.join(ConfDir, gDefaultToolsDefFile)))\r
274 else:\r
275 ToolDef.LoadToolDefFile(os.path.normpath(os.path.join(ConfDir, gDefaultToolsDefFile)))\r
30fdf114
LG
276 return ToolDef\r
277\r
278##\r
279#\r
280# This acts like the main() function for the script, unless it is 'import'ed into another\r
281# script.\r
282#\r
283if __name__ == '__main__':\r
284 ToolDef = ToolDefDict(os.getenv("WORKSPACE"))\r
285 pass\r