]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Workspace/DecBuildData.py
BaseTool: Enhance error handling.
[mirror_edk2.git] / BaseTools / Source / Python / Workspace / DecBuildData.py
CommitLineData
ae7b6df8
LG
1## @file\r
2# This file is used to create a database used by build tool\r
3#\r
a9d9ce8e 4# Copyright (c) 2008 - 2017, Intel Corporation. All rights reserved.<BR>\r
ae7b6df8
LG
5# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
6# This program and the accompanying materials\r
7# are licensed and made available under the terms and conditions of the BSD License\r
8# which accompanies this distribution. The full text of the license may be found at\r
9# http://opensource.org/licenses/bsd-license.php\r
10#\r
11# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13#\r
14from Common.String import *\r
15from Common.DataType import *\r
16from Common.Misc import *\r
17from types import *\r
18\r
19from Workspace.BuildClassObject import PackageBuildClassObject, StructurePcd, PcdClassObject\r
20\r
21## Platform build information from DEC file\r
22#\r
23# This class is used to retrieve information stored in database and convert them\r
24# into PackageBuildClassObject form for easier use for AutoGen.\r
25#\r
26class DecBuildData(PackageBuildClassObject):\r
27 # dict used to convert PCD type in database to string used by build tool\r
28 _PCD_TYPE_STRING_ = {\r
29 MODEL_PCD_FIXED_AT_BUILD : "FixedAtBuild",\r
30 MODEL_PCD_PATCHABLE_IN_MODULE : "PatchableInModule",\r
31 MODEL_PCD_FEATURE_FLAG : "FeatureFlag",\r
32 MODEL_PCD_DYNAMIC : "Dynamic",\r
33 MODEL_PCD_DYNAMIC_DEFAULT : "Dynamic",\r
34 MODEL_PCD_DYNAMIC_HII : "DynamicHii",\r
35 MODEL_PCD_DYNAMIC_VPD : "DynamicVpd",\r
36 MODEL_PCD_DYNAMIC_EX : "DynamicEx",\r
37 MODEL_PCD_DYNAMIC_EX_DEFAULT : "DynamicEx",\r
38 MODEL_PCD_DYNAMIC_EX_HII : "DynamicExHii",\r
39 MODEL_PCD_DYNAMIC_EX_VPD : "DynamicExVpd",\r
40 }\r
41\r
42 # dict used to convert part of [Defines] to members of DecBuildData directly\r
43 _PROPERTY_ = {\r
44 #\r
45 # Required Fields\r
46 #\r
47 TAB_DEC_DEFINES_PACKAGE_NAME : "_PackageName",\r
48 TAB_DEC_DEFINES_PACKAGE_GUID : "_Guid",\r
49 TAB_DEC_DEFINES_PACKAGE_VERSION : "_Version",\r
50 TAB_DEC_DEFINES_PKG_UNI_FILE : "_PkgUniFile",\r
51 }\r
52\r
53\r
54 ## Constructor of DecBuildData\r
55 #\r
56 # Initialize object of DecBuildData\r
57 #\r
58 # @param FilePath The path of package description file\r
59 # @param RawData The raw data of DEC file\r
60 # @param BuildDataBase Database used to retrieve module information\r
61 # @param Arch The target architecture\r
62 # @param Platform (not used for DecBuildData)\r
63 # @param Macros Macros used for replacement in DSC file\r
64 #\r
65 def __init__(self, File, RawData, BuildDataBase, Arch='COMMON', Target=None, Toolchain=None):\r
66 self.MetaFile = File\r
67 self._PackageDir = File.Dir\r
68 self._RawData = RawData\r
69 self._Bdb = BuildDataBase\r
70 self._Arch = Arch\r
71 self._Target = Target\r
72 self._Toolchain = Toolchain\r
73 self._Clear()\r
74\r
75 ## XXX[key] = value\r
76 def __setitem__(self, key, value):\r
77 self.__dict__[self._PROPERTY_[key]] = value\r
78\r
79 ## value = XXX[key]\r
80 def __getitem__(self, key):\r
81 return self.__dict__[self._PROPERTY_[key]]\r
82\r
83 ## "in" test support\r
84 def __contains__(self, key):\r
85 return key in self._PROPERTY_\r
86\r
87 ## Set all internal used members of DecBuildData to None\r
88 def _Clear(self):\r
89 self._Header = None\r
90 self._PackageName = None\r
91 self._Guid = None\r
92 self._Version = None\r
93 self._PkgUniFile = None\r
94 self._Protocols = None\r
95 self._Ppis = None\r
96 self._Guids = None\r
97 self._Includes = None\r
98 self._LibraryClasses = None\r
99 self._Pcds = None\r
100 self.__Macros = None\r
101 self._PrivateProtocols = None\r
102 self._PrivatePpis = None\r
103 self._PrivateGuids = None\r
104 self._PrivateIncludes = None\r
105\r
106 ## Get current effective macros\r
107 def _GetMacros(self):\r
108 if self.__Macros == None:\r
109 self.__Macros = {}\r
110 self.__Macros.update(GlobalData.gGlobalDefines)\r
111 return self.__Macros\r
112\r
113 ## Get architecture\r
114 def _GetArch(self):\r
115 return self._Arch\r
116\r
117 ## Set architecture\r
118 #\r
119 # Changing the default ARCH to another may affect all other information\r
120 # because all information in a platform may be ARCH-related. That's\r
121 # why we need to clear all internal used members, in order to cause all\r
122 # information to be re-retrieved.\r
123 #\r
124 # @param Value The value of ARCH\r
125 #\r
126 def _SetArch(self, Value):\r
127 if self._Arch == Value:\r
128 return\r
129 self._Arch = Value\r
130 self._Clear()\r
131\r
132 ## Retrieve all information in [Defines] section\r
133 #\r
134 # (Retriving all [Defines] information in one-shot is just to save time.)\r
135 #\r
136 def _GetHeaderInfo(self):\r
137 RecordList = self._RawData[MODEL_META_DATA_HEADER, self._Arch]\r
138 for Record in RecordList:\r
139 Name = Record[1]\r
140 if Name in self:\r
141 self[Name] = Record[2]\r
142 self._Header = 'DUMMY'\r
143\r
144 ## Retrieve package name\r
145 def _GetPackageName(self):\r
146 if self._PackageName == None:\r
147 if self._Header == None:\r
148 self._GetHeaderInfo()\r
149 if self._PackageName == None:\r
150 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "No PACKAGE_NAME", File=self.MetaFile)\r
151 return self._PackageName\r
152\r
153 ## Retrieve file guid\r
154 def _GetFileGuid(self):\r
155 if self._Guid == None:\r
156 if self._Header == None:\r
157 self._GetHeaderInfo()\r
158 if self._Guid == None:\r
159 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "No PACKAGE_GUID", File=self.MetaFile)\r
160 return self._Guid\r
161\r
162 ## Retrieve package version\r
163 def _GetVersion(self):\r
164 if self._Version == None:\r
165 if self._Header == None:\r
166 self._GetHeaderInfo()\r
167 if self._Version == None:\r
168 self._Version = ''\r
169 return self._Version\r
170\r
171 ## Retrieve protocol definitions (name/value pairs)\r
172 def _GetProtocol(self):\r
173 if self._Protocols == None:\r
174 #\r
175 # tdict is a special kind of dict, used for selecting correct\r
176 # protocol defition for given ARCH\r
177 #\r
178 ProtocolDict = tdict(True)\r
179 PrivateProtocolDict = tdict(True)\r
180 NameList = []\r
181 PrivateNameList = []\r
182 PublicNameList = []\r
183 # find out all protocol definitions for specific and 'common' arch\r
184 RecordList = self._RawData[MODEL_EFI_PROTOCOL, self._Arch]\r
185 for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:\r
186 if PrivateFlag == 'PRIVATE':\r
187 if Name not in PrivateNameList:\r
188 PrivateNameList.append(Name)\r
189 PrivateProtocolDict[Arch, Name] = Guid\r
190 if Name in PublicNameList:\r
191 EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)\r
192 else:\r
193 if Name not in PublicNameList:\r
194 PublicNameList.append(Name)\r
195 if Name in PrivateNameList:\r
196 EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)\r
197 if Name not in NameList:\r
198 NameList.append(Name)\r
199 ProtocolDict[Arch, Name] = Guid\r
200 # use sdict to keep the order\r
201 self._Protocols = sdict()\r
202 self._PrivateProtocols = sdict()\r
203 for Name in NameList:\r
204 #\r
205 # limit the ARCH to self._Arch, if no self._Arch found, tdict\r
206 # will automatically turn to 'common' ARCH for trying\r
207 #\r
208 self._Protocols[Name] = ProtocolDict[self._Arch, Name]\r
209 for Name in PrivateNameList:\r
210 self._PrivateProtocols[Name] = PrivateProtocolDict[self._Arch, Name]\r
211 return self._Protocols\r
212\r
213 ## Retrieve PPI definitions (name/value pairs)\r
214 def _GetPpi(self):\r
215 if self._Ppis == None:\r
216 #\r
217 # tdict is a special kind of dict, used for selecting correct\r
218 # PPI defition for given ARCH\r
219 #\r
220 PpiDict = tdict(True)\r
221 PrivatePpiDict = tdict(True)\r
222 NameList = []\r
223 PrivateNameList = []\r
224 PublicNameList = []\r
225 # find out all PPI definitions for specific arch and 'common' arch\r
226 RecordList = self._RawData[MODEL_EFI_PPI, self._Arch]\r
227 for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:\r
228 if PrivateFlag == 'PRIVATE':\r
229 if Name not in PrivateNameList:\r
230 PrivateNameList.append(Name)\r
231 PrivatePpiDict[Arch, Name] = Guid\r
232 if Name in PublicNameList:\r
233 EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)\r
234 else:\r
235 if Name not in PublicNameList:\r
236 PublicNameList.append(Name)\r
237 if Name in PrivateNameList:\r
238 EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)\r
239 if Name not in NameList:\r
240 NameList.append(Name)\r
241 PpiDict[Arch, Name] = Guid\r
242 # use sdict to keep the order\r
243 self._Ppis = sdict()\r
244 self._PrivatePpis = sdict()\r
245 for Name in NameList:\r
246 #\r
247 # limit the ARCH to self._Arch, if no self._Arch found, tdict\r
248 # will automatically turn to 'common' ARCH for trying\r
249 #\r
250 self._Ppis[Name] = PpiDict[self._Arch, Name]\r
251 for Name in PrivateNameList:\r
252 self._PrivatePpis[Name] = PrivatePpiDict[self._Arch, Name]\r
253 return self._Ppis\r
254\r
255 ## Retrieve GUID definitions (name/value pairs)\r
256 def _GetGuid(self):\r
257 if self._Guids == None:\r
258 #\r
259 # tdict is a special kind of dict, used for selecting correct\r
260 # GUID defition for given ARCH\r
261 #\r
262 GuidDict = tdict(True)\r
263 PrivateGuidDict = tdict(True)\r
264 NameList = []\r
265 PrivateNameList = []\r
266 PublicNameList = []\r
267 # find out all protocol definitions for specific and 'common' arch\r
268 RecordList = self._RawData[MODEL_EFI_GUID, self._Arch]\r
269 for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:\r
270 if PrivateFlag == 'PRIVATE':\r
271 if Name not in PrivateNameList:\r
272 PrivateNameList.append(Name)\r
273 PrivateGuidDict[Arch, Name] = Guid\r
274 if Name in PublicNameList:\r
275 EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)\r
276 else:\r
277 if Name not in PublicNameList:\r
278 PublicNameList.append(Name)\r
279 if Name in PrivateNameList:\r
280 EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)\r
281 if Name not in NameList:\r
282 NameList.append(Name)\r
283 GuidDict[Arch, Name] = Guid\r
284 # use sdict to keep the order\r
285 self._Guids = sdict()\r
286 self._PrivateGuids = sdict()\r
287 for Name in NameList:\r
288 #\r
289 # limit the ARCH to self._Arch, if no self._Arch found, tdict\r
290 # will automatically turn to 'common' ARCH for trying\r
291 #\r
292 self._Guids[Name] = GuidDict[self._Arch, Name]\r
293 for Name in PrivateNameList:\r
294 self._PrivateGuids[Name] = PrivateGuidDict[self._Arch, Name]\r
295 return self._Guids\r
296\r
297 ## Retrieve public include paths declared in this package\r
298 def _GetInclude(self):\r
299 if self._Includes == None:\r
300 self._Includes = []\r
301 self._PrivateIncludes = []\r
302 PublicInclues = []\r
303 RecordList = self._RawData[MODEL_EFI_INCLUDE, self._Arch]\r
304 Macros = self._Macros\r
305 Macros["EDK_SOURCE"] = GlobalData.gEcpSource\r
306 for Record in RecordList:\r
307 File = PathClass(NormPath(Record[0], Macros), self._PackageDir, Arch=self._Arch)\r
308 LineNo = Record[-1]\r
309 # validate the path\r
310 ErrorCode, ErrorInfo = File.Validate()\r
311 if ErrorCode != 0:\r
312 EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, File=self.MetaFile, Line=LineNo)\r
313\r
314 # avoid duplicate include path\r
315 if File not in self._Includes:\r
316 self._Includes.append(File)\r
317 if Record[4] == 'PRIVATE':\r
318 if File not in self._PrivateIncludes:\r
319 self._PrivateIncludes.append(File)\r
320 if File in PublicInclues:\r
321 EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % File, File=self.MetaFile, Line=LineNo)\r
322 else:\r
323 if File not in PublicInclues:\r
324 PublicInclues.append(File)\r
325 if File in self._PrivateIncludes:\r
326 EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % File, File=self.MetaFile, Line=LineNo)\r
327\r
328 return self._Includes\r
329\r
330 ## Retrieve library class declarations (not used in build at present)\r
331 def _GetLibraryClass(self):\r
332 if self._LibraryClasses == None:\r
333 #\r
334 # tdict is a special kind of dict, used for selecting correct\r
335 # library class declaration for given ARCH\r
336 #\r
337 LibraryClassDict = tdict(True)\r
338 LibraryClassSet = set()\r
339 RecordList = self._RawData[MODEL_EFI_LIBRARY_CLASS, self._Arch]\r
340 Macros = self._Macros\r
341 for LibraryClass, File, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:\r
342 File = PathClass(NormPath(File, Macros), self._PackageDir, Arch=self._Arch)\r
343 # check the file validation\r
344 ErrorCode, ErrorInfo = File.Validate()\r
345 if ErrorCode != 0:\r
346 EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, File=self.MetaFile, Line=LineNo)\r
347 LibraryClassSet.add(LibraryClass)\r
348 LibraryClassDict[Arch, LibraryClass] = File\r
349 self._LibraryClasses = sdict()\r
350 for LibraryClass in LibraryClassSet:\r
351 self._LibraryClasses[LibraryClass] = LibraryClassDict[self._Arch, LibraryClass]\r
352 return self._LibraryClasses\r
353\r
354 ## Retrieve PCD declarations\r
355 def _GetPcds(self):\r
356 if self._Pcds == None:\r
357 self._Pcds = sdict()\r
358 self._Pcds.update(self._GetPcd(MODEL_PCD_FIXED_AT_BUILD))\r
359 self._Pcds.update(self._GetPcd(MODEL_PCD_PATCHABLE_IN_MODULE))\r
360 self._Pcds.update(self._GetPcd(MODEL_PCD_FEATURE_FLAG))\r
361 self._Pcds.update(self._GetPcd(MODEL_PCD_DYNAMIC))\r
362 self._Pcds.update(self._GetPcd(MODEL_PCD_DYNAMIC_EX))\r
363 return self._Pcds\r
364\r
365\r
366 def ProcessStructurePcd(self, StructurePcdRawDataSet):\r
367 s_pcd_set = dict()\r
368 for s_pcd,LineNo in StructurePcdRawDataSet:\r
369 if s_pcd.TokenSpaceGuidCName not in s_pcd_set:\r
370 s_pcd_set[s_pcd.TokenSpaceGuidCName] = []\r
371 s_pcd_set[s_pcd.TokenSpaceGuidCName].append((s_pcd,LineNo))\r
372\r
373 str_pcd_set = []\r
374 for pcdname in s_pcd_set:\r
375 dep_pkgs = []\r
376 struct_pcd = StructurePcd()\r
377 for item,LineNo in s_pcd_set[pcdname]:\r
378 if "<HeaderFiles>" in item.TokenCName:\r
379 struct_pcd.StructuredPcdIncludeFile = item.DefaultValue\r
380 elif "<Packages>" in item.TokenCName:\r
381 dep_pkgs.append(item.DefaultValue)\r
382 elif item.DatumType == item.TokenCName:\r
383 struct_pcd.copy(item)\r
384 struct_pcd.TokenValue = struct_pcd.TokenValue.strip("{").strip()\r
385 struct_pcd.TokenSpaceGuidCName, struct_pcd.TokenCName = pcdname.split(".")\r
6a103440
FB
386 struct_pcd.PcdDefineLineNo = LineNo\r
387 struct_pcd.PkgPath = self.MetaFile.File\r
ae7b6df8
LG
388 else:\r
389 struct_pcd.AddDefaultValue(item.TokenCName, item.DefaultValue,self.MetaFile.File,LineNo)\r
390\r
391 struct_pcd.PackageDecs = dep_pkgs\r
392\r
393 str_pcd_set.append(struct_pcd)\r
394\r
395 return str_pcd_set\r
396\r
397 ## Retrieve PCD declarations for given type\r
398 def _GetPcd(self, Type):\r
399 Pcds = sdict()\r
400 #\r
401 # tdict is a special kind of dict, used for selecting correct\r
402 # PCD declaration for given ARCH\r
403 #\r
404 PcdDict = tdict(True, 3)\r
405 # for summarizing PCD\r
e651d06c 406 PcdSet = []\r
ae7b6df8
LG
407 # find out all PCDs of the 'type'\r
408\r
409 StrPcdSet = []\r
410 RecordList = self._RawData[Type, self._Arch]\r
411 for TokenSpaceGuid, PcdCName, Setting, Arch, PrivateFlag, Dummy1, Dummy2 in RecordList:\r
412 PcdDict[Arch, PcdCName, TokenSpaceGuid] = (Setting,Dummy2)\r
e651d06c
LG
413 if not (PcdCName, TokenSpaceGuid) in PcdSet:\r
414 PcdSet.append((PcdCName, TokenSpaceGuid))\r
ae7b6df8
LG
415\r
416 for PcdCName, TokenSpaceGuid in PcdSet:\r
417 #\r
418 # limit the ARCH to self._Arch, if no self._Arch found, tdict\r
419 # will automatically turn to 'common' ARCH and try again\r
420 #\r
421 Setting,LineNo = PcdDict[self._Arch, PcdCName, TokenSpaceGuid]\r
422 if Setting == None:\r
423 continue\r
424\r
425 DefaultValue, DatumType, TokenNumber = AnalyzePcdData(Setting)\r
426 validateranges, validlists, expressions = self._RawData.GetValidExpression(TokenSpaceGuid, PcdCName)\r
427 PcdObj = PcdClassObject(\r
428 PcdCName,\r
429 TokenSpaceGuid,\r
430 self._PCD_TYPE_STRING_[Type],\r
431 DatumType,\r
432 DefaultValue,\r
433 TokenNumber,\r
434 '',\r
435 {},\r
436 False,\r
437 None,\r
438 list(validateranges),\r
439 list(validlists),\r
440 list(expressions)\r
441 )\r
442 if "." in TokenSpaceGuid:\r
443 StrPcdSet.append((PcdObj,LineNo))\r
444 else:\r
445 Pcds[PcdCName, TokenSpaceGuid, self._PCD_TYPE_STRING_[Type]] = PcdObj\r
446\r
447 StructurePcds = self.ProcessStructurePcd(StrPcdSet)\r
448 for pcd in StructurePcds:\r
449 Pcds[pcd.TokenCName, pcd.TokenSpaceGuidCName, self._PCD_TYPE_STRING_[Type]] = pcd\r
450\r
451 return Pcds\r
452\r
453\r
454 _Macros = property(_GetMacros)\r
455 Arch = property(_GetArch, _SetArch)\r
456 PackageName = property(_GetPackageName)\r
457 Guid = property(_GetFileGuid)\r
458 Version = property(_GetVersion)\r
459\r
460 Protocols = property(_GetProtocol)\r
461 Ppis = property(_GetPpi)\r
462 Guids = property(_GetGuid)\r
463 Includes = property(_GetInclude)\r
464 LibraryClasses = property(_GetLibraryClass)\r
465 Pcds = property(_GetPcds)\r