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