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