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