]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Common/ToolDefClassObject.py
OvmfPkg/SerializeVariablesLib: Relax check for the read-only variable
[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
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\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
79\r
80 ## IncludeToolDefFile\r
81 #\r
82 # Load target.txt file and parse it as if it's contents were inside the main file\r
83 #\r
84 # @param Filename: Input value for full path of tools_def.txt\r
85 #\r
86 def IncludeToolDefFile(self, FileName):\r
30fdf114
LG
87 FileContent = []\r
88 if os.path.isfile(FileName):\r
89 try:\r
47fea6af 90 F = open(FileName, 'r')\r
30fdf114
LG
91 FileContent = F.readlines()\r
92 except:\r
93 EdkLogger.error("tools_def.txt parser", FILE_OPEN_FAILURE, ExtraData=FileName)\r
94 else:\r
95 EdkLogger.error("tools_def.txt parser", FILE_NOT_FOUND, ExtraData=FileName)\r
96\r
30fdf114
LG
97 for Index in range(len(FileContent)):\r
98 Line = FileContent[Index].strip()\r
99 if Line == "" or Line[0] == '#':\r
100 continue\r
8ac46e4e
MZ
101\r
102 if Line.startswith("!include"):\r
103 IncFile = Line[8:].strip()\r
104 Done, IncFile = self.ExpandMacros(IncFile)\r
105 if not Done:\r
106 EdkLogger.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE,\r
107 "Macro or Environment has not been defined",\r
108 ExtraData=IncFile[4:-1], File=FileName, Line=Index+1)\r
109 IncFile = NormPath(IncFile)\r
110\r
111 if not os.path.isabs(IncFile):\r
112 #\r
113 # try WORKSPACE\r
114 #\r
115 IncFileTmp = PathClass(IncFile, GlobalData.gWorkspace)\r
116 ErrorCode = IncFileTmp.Validate()[0]\r
117 if ErrorCode != 0:\r
118 #\r
119 # try PACKAGES_PATH\r
120 #\r
121 IncFileTmp = mws.join(GlobalData.gWorkspace, IncFile)\r
122 if not os.path.exists(IncFileTmp):\r
123 #\r
124 # try directory of current file\r
125 #\r
126 IncFileTmp = PathClass(IncFile, os.path.dirname(FileName))\r
127 ErrorCode = IncFileTmp.Validate()[0]\r
128 if ErrorCode != 0:\r
129 EdkLogger.error("tools_def.txt parser", FILE_NOT_FOUND, ExtraData=IncFile)\r
130\r
131 if type(IncFileTmp) is PathClass:\r
132 IncFile = IncFileTmp.Path\r
133 else:\r
134 IncFile = IncFileTmp\r
135\r
136 self.IncludeToolDefFile(IncFile)\r
137 continue\r
138\r
30fdf114
LG
139 NameValuePair = Line.split("=", 1)\r
140 if len(NameValuePair) != 2:\r
141 EdkLogger.warn("tools_def.txt parser", "Line %d: not correct assignment statement, skipped" % (Index + 1))\r
142 continue\r
143\r
144 Name = NameValuePair[0].strip()\r
145 Value = NameValuePair[1].strip()\r
146\r
147 if Name == "IDENTIFIER":\r
148 EdkLogger.debug(EdkLogger.DEBUG_8, "Line %d: Found identifier statement, skipped: %s" % ((Index + 1), Value))\r
149 continue\r
150\r
151 MacroDefinition = gMacroDefPattern.findall(Name)\r
152 if MacroDefinition != []:\r
153 Done, Value = self.ExpandMacros(Value)\r
154 if not Done:\r
155 EdkLogger.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE,\r
156 "Macro or Environment has not been defined",\r
157 ExtraData=Value[4:-1], File=FileName, Line=Index+1)\r
158\r
159 MacroName = MacroDefinition[0].strip()\r
160 self.MacroDictionary["DEF(%s)" % MacroName] = Value\r
161 EdkLogger.debug(EdkLogger.DEBUG_8, "Line %d: Found macro: %s = %s" % ((Index + 1), MacroName, Value))\r
162 continue\r
163\r
164 Done, Value = self.ExpandMacros(Value)\r
165 if not Done:\r
166 EdkLogger.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE,\r
167 "Macro or Environment has not been defined",\r
168 ExtraData=Value[4:-1], File=FileName, Line=Index+1)\r
169\r
170 List = Name.split('_')\r
171 if len(List) != 5:\r
172 EdkLogger.verbose("Line %d: Not a valid name of definition: %s" % ((Index + 1), Name))\r
173 continue\r
174 elif List[4] == '*':\r
175 EdkLogger.verbose("Line %d: '*' is not allowed in last field: %s" % ((Index + 1), Name))\r
176 continue\r
177 else:\r
178 self.ToolsDefTxtDictionary[Name] = Value\r
179 if List[0] != '*':\r
180 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET] += [List[0]]\r
181 if List[1] != '*':\r
182 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG] += [List[1]]\r
183 if List[2] != '*':\r
184 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH] += [List[2]]\r
185 if List[3] != '*':\r
186 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE] += [List[3]]\r
187 if List[4] == TAB_TOD_DEFINES_FAMILY and List[2] == '*' and List[3] == '*':\r
188 if TAB_TOD_DEFINES_FAMILY not in self.ToolsDefTxtDatabase:\r
189 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY] = {}\r
190 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][List[1]] = Value\r
191 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY] = {}\r
192 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][List[1]] = Value\r
193 elif List[1] not in self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY]:\r
194 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][List[1]] = Value\r
195 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][List[1]] = Value\r
196 elif self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][List[1]] != Value:\r
197 EdkLogger.verbose("Line %d: No override allowed for the family of a tool chain: %s" % ((Index + 1), Name))\r
198 if List[4] == TAB_TOD_DEFINES_BUILDRULEFAMILY and List[2] == '*' and List[3] == '*':\r
199 if TAB_TOD_DEFINES_BUILDRULEFAMILY not in self.ToolsDefTxtDatabase \\r
200 or List[1] not in self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY]:\r
201 EdkLogger.verbose("Line %d: The family is not specified, but BuildRuleFamily is specified for the tool chain: %s" % ((Index + 1), Name))\r
202 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][List[1]] = Value\r
203\r
204 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET]))\r
205 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]))\r
206 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH]))\r
207 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE]))\r
208\r
209 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET].sort()\r
210 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG].sort()\r
211 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH].sort()\r
212 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE].sort()\r
213\r
214 KeyList = [TAB_TOD_DEFINES_TARGET, TAB_TOD_DEFINES_TOOL_CHAIN_TAG, TAB_TOD_DEFINES_TARGET_ARCH, TAB_TOD_DEFINES_COMMAND_TYPE]\r
47fea6af 215 for Index in range(3, -1, -1):\r
30fdf114
LG
216 for Key in dict(self.ToolsDefTxtDictionary):\r
217 List = Key.split('_')\r
218 if List[Index] == '*':\r
219 for String in self.ToolsDefTxtDatabase[KeyList[Index]]:\r
220 List[Index] = String\r
221 NewKey = '%s_%s_%s_%s_%s' % tuple(List)\r
222 if NewKey not in self.ToolsDefTxtDictionary:\r
223 self.ToolsDefTxtDictionary[NewKey] = self.ToolsDefTxtDictionary[Key]\r
224 continue\r
225 del self.ToolsDefTxtDictionary[Key]\r
226 elif List[Index] not in self.ToolsDefTxtDatabase[KeyList[Index]]:\r
227 del self.ToolsDefTxtDictionary[Key]\r
228\r
229 ## ExpandMacros\r
230 #\r
231 # Replace defined macros with real value\r
232 #\r
233 # @param Value: The string with unreplaced macros\r
234 #\r
235 # @retval Value: The string which has been replaced with real value\r
236 #\r
237 def ExpandMacros(self, Value):\r
238 EnvReference = gEnvRefPattern.findall(Value)\r
239 for Ref in EnvReference:\r
240 if Ref not in self.MacroDictionary:\r
da92f276
LG
241 Value = Value.replace(Ref, "")\r
242 else:\r
243 Value = Value.replace(Ref, self.MacroDictionary[Ref])\r
244 \r
30fdf114
LG
245\r
246 MacroReference = gMacroRefPattern.findall(Value)\r
247 for Ref in MacroReference:\r
248 if Ref not in self.MacroDictionary:\r
249 return False, Ref\r
250 Value = Value.replace(Ref, self.MacroDictionary[Ref])\r
251\r
252 return True, Value\r
253\r
254## ToolDefDict\r
255#\r
97fa0ee9 256# Load tools_def.txt in input Conf dir\r
30fdf114 257#\r
97fa0ee9 258# @param ConfDir: Conf dir\r
30fdf114
LG
259#\r
260# @retval ToolDef An instance of ToolDefClassObject() with loaded tools_def.txt\r
261#\r
97fa0ee9
YL
262def ToolDefDict(ConfDir):\r
263 Target = TargetTxtDict(ConfDir)\r
30fdf114
LG
264 ToolDef = ToolDefClassObject()\r
265 if DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF in Target.TargetTxtDictionary:\r
97fa0ee9
YL
266 ToolsDefFile = Target.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]\r
267 if ToolsDefFile:\r
268 ToolDef.LoadToolDefFile(os.path.normpath(ToolsDefFile))\r
269 else:\r
270 ToolDef.LoadToolDefFile(os.path.normpath(os.path.join(ConfDir, gDefaultToolsDefFile)))\r
271 else:\r
272 ToolDef.LoadToolDefFile(os.path.normpath(os.path.join(ConfDir, gDefaultToolsDefFile)))\r
30fdf114
LG
273 return ToolDef\r
274\r
275##\r
276#\r
277# This acts like the main() function for the script, unless it is 'import'ed into another\r
278# script.\r
279#\r
280if __name__ == '__main__':\r
281 ToolDef = ToolDefDict(os.getenv("WORKSPACE"))\r
282 pass\r