]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Common/ToolDefClassObject.py
BaseTools: Replace BSD License with BSD+Patent License
[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
938cf4c3 4# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>\r
2e351cbe 5# SPDX-License-Identifier: BSD-2-Clause-Patent\r
30fdf114
LG
6#\r
7\r
8##\r
9# Import Modules\r
10#\r
1ccc4d89 11from __future__ import absolute_import\r
1be2ed90 12import Common.LongFilePathOs as os\r
30fdf114 13import re\r
f3fc5b47 14from . import EdkLogger\r
30fdf114 15\r
f3fc5b47 16from .BuildToolError import *\r
938cf4c3 17from Common.TargetTxtClassObject import TargetTxtDict\r
1be2ed90 18from Common.LongFilePathSupport import OpenLongFilePath as open\r
8ac46e4e 19from Common.Misc import PathClass\r
5a57246e 20from Common.StringUtils import NormPath\r
8ac46e4e
MZ
21import Common.GlobalData as GlobalData\r
22from Common import GlobalData\r
23from Common.MultipleWorkspace import MultipleWorkspace as mws\r
f3fc5b47 24from .DataType import TAB_TOD_DEFINES_TARGET, TAB_TOD_DEFINES_TOOL_CHAIN_TAG,\\r
ccaa7754 25 TAB_TOD_DEFINES_TARGET_ARCH, TAB_TOD_DEFINES_COMMAND_TYPE\\r
bc39c5cb
JC
26 , TAB_TOD_DEFINES_FAMILY, TAB_TOD_DEFINES_BUILDRULEFAMILY,\\r
27 TAB_STAR, TAB_TAT_DEFINES_TOOL_CHAIN_CONF\r
ce3082a6 28\r
30fdf114
LG
29\r
30##\r
08dd311f 31# Static variables used for pattern\r
30fdf114
LG
32#\r
33gMacroRefPattern = re.compile('(DEF\([^\(\)]+\))')\r
34gEnvRefPattern = re.compile('(ENV\([^\(\)]+\))')\r
35gMacroDefPattern = re.compile("DEFINE\s+([^\s]+)")\r
97fa0ee9 36gDefaultToolsDefFile = "tools_def.txt"\r
30fdf114
LG
37\r
38## ToolDefClassObject\r
39#\r
40# This class defined content used in file tools_def.txt\r
41#\r
42# @param object: Inherited from object class\r
43# @param Filename: Input value for full path of tools_def.txt\r
44#\r
45# @var ToolsDefTxtDictionary: To store keys and values defined in target.txt\r
46# @var MacroDictionary: To store keys and values defined in DEFINE statement\r
47#\r
48class ToolDefClassObject(object):\r
47fea6af 49 def __init__(self, FileName=None):\r
30fdf114
LG
50 self.ToolsDefTxtDictionary = {}\r
51 self.MacroDictionary = {}\r
52 for Env in os.environ:\r
53 self.MacroDictionary["ENV(%s)" % Env] = os.environ[Env]\r
54\r
4231a819 55 if FileName is not None:\r
30fdf114
LG
56 self.LoadToolDefFile(FileName)\r
57\r
58 ## LoadToolDefFile\r
59 #\r
8b14b35b 60 # Load target.txt file and parse it\r
30fdf114
LG
61 #\r
62 # @param Filename: Input value for full path of tools_def.txt\r
63 #\r
64 def LoadToolDefFile(self, FileName):\r
8ac46e4e
MZ
65 # set multiple workspace\r
66 PackagesPath = os.getenv("PACKAGES_PATH")\r
67 mws.setWs(GlobalData.gWorkspace, PackagesPath)\r
68\r
69 self.ToolsDefTxtDatabase = {\r
70 TAB_TOD_DEFINES_TARGET : [],\r
71 TAB_TOD_DEFINES_TOOL_CHAIN_TAG : [],\r
72 TAB_TOD_DEFINES_TARGET_ARCH : [],\r
73 TAB_TOD_DEFINES_COMMAND_TYPE : []\r
74 }\r
75\r
76 self.IncludeToolDefFile(FileName)\r
77\r
6608330d
MZ
78 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET]))\r
79 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]))\r
80 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH]))\r
81\r
82 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE]))\r
83\r
84 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET].sort()\r
85 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG].sort()\r
86 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH].sort()\r
87 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE].sort()\r
88\r
89 KeyList = [TAB_TOD_DEFINES_TARGET, TAB_TOD_DEFINES_TOOL_CHAIN_TAG, TAB_TOD_DEFINES_TARGET_ARCH, TAB_TOD_DEFINES_COMMAND_TYPE]\r
90 for Index in range(3, -1, -1):\r
13d9e051
CJ
91 # make a copy of the keys to enumerate over to prevent issues when\r
92 # adding/removing items from the original dict.\r
93 for Key in list(self.ToolsDefTxtDictionary.keys()):\r
6608330d 94 List = Key.split('_')\r
bc39c5cb 95 if List[Index] == TAB_STAR:\r
6608330d
MZ
96 for String in self.ToolsDefTxtDatabase[KeyList[Index]]:\r
97 List[Index] = String\r
98 NewKey = '%s_%s_%s_%s_%s' % tuple(List)\r
99 if NewKey not in self.ToolsDefTxtDictionary:\r
100 self.ToolsDefTxtDictionary[NewKey] = self.ToolsDefTxtDictionary[Key]\r
6608330d
MZ
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
0d1f5b2b 157 if isinstance(IncFileTmp, PathClass):\r
8ac46e4e
MZ
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
bc39c5cb 200 elif List[4] == TAB_STAR:\r
30fdf114
LG
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
bc39c5cb 205 if List[0] != TAB_STAR:\r
30fdf114 206 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET] += [List[0]]\r
bc39c5cb 207 if List[1] != TAB_STAR:\r
30fdf114 208 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG] += [List[1]]\r
bc39c5cb 209 if List[2] != TAB_STAR:\r
30fdf114 210 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH] += [List[2]]\r
bc39c5cb 211 if List[3] != TAB_STAR:\r
30fdf114 212 self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE] += [List[3]]\r
bc39c5cb 213 if List[4] == TAB_TOD_DEFINES_FAMILY and List[2] == TAB_STAR and List[3] == TAB_STAR:\r
30fdf114
LG
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
bc39c5cb 224 if List[4] == TAB_TOD_DEFINES_BUILDRULEFAMILY and List[2] == TAB_STAR and List[3] == TAB_STAR:\r
30fdf114
LG
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 267 ToolDef = ToolDefClassObject()\r
bc39c5cb
JC
268 if TAB_TAT_DEFINES_TOOL_CHAIN_CONF in Target.TargetTxtDictionary:\r
269 ToolsDefFile = Target.TargetTxtDictionary[TAB_TAT_DEFINES_TOOL_CHAIN_CONF]\r
97fa0ee9
YL
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