BaseTool: Error handling for PCD datumtype.
[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.String 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 : "FixedAtBuild",
31 MODEL_PCD_PATCHABLE_IN_MODULE : "PatchableInModule",
32 MODEL_PCD_FEATURE_FLAG : "FeatureFlag",
33 MODEL_PCD_DYNAMIC : "Dynamic",
34 MODEL_PCD_DYNAMIC_DEFAULT : "Dynamic",
35 MODEL_PCD_DYNAMIC_HII : "DynamicHii",
36 MODEL_PCD_DYNAMIC_VPD : "DynamicVpd",
37 MODEL_PCD_DYNAMIC_EX : "DynamicEx",
38 MODEL_PCD_DYNAMIC_EX_DEFAULT : "DynamicEx",
39 MODEL_PCD_DYNAMIC_EX_HII : "DynamicExHii",
40 MODEL_PCD_DYNAMIC_EX_VPD : "DynamicExVpd",
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='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.__Macros = None
103 self._PrivateProtocols = None
104 self._PrivatePpis = None
105 self._PrivateGuids = None
106 self._PrivateIncludes = None
107
108 ## Get current effective macros
109 def _GetMacros(self):
110 if self.__Macros == None:
111 self.__Macros = {}
112 self.__Macros.update(GlobalData.gGlobalDefines)
113 return self.__Macros
114
115 ## Get architecture
116 def _GetArch(self):
117 return self._Arch
118
119 ## Set architecture
120 #
121 # Changing the default ARCH to another may affect all other information
122 # because all information in a platform may be ARCH-related. That's
123 # why we need to clear all internal used members, in order to cause all
124 # information to be re-retrieved.
125 #
126 # @param Value The value of ARCH
127 #
128 def _SetArch(self, Value):
129 if self._Arch == Value:
130 return
131 self._Arch = Value
132 self._Clear()
133
134 ## Retrieve all information in [Defines] section
135 #
136 # (Retriving all [Defines] information in one-shot is just to save time.)
137 #
138 def _GetHeaderInfo(self):
139 RecordList = self._RawData[MODEL_META_DATA_HEADER, self._Arch]
140 for Record in RecordList:
141 Name = Record[1]
142 if Name in self:
143 self[Name] = Record[2]
144 self._Header = 'DUMMY'
145
146 ## Retrieve package name
147 def _GetPackageName(self):
148 if self._PackageName == None:
149 if self._Header == None:
150 self._GetHeaderInfo()
151 if self._PackageName == None:
152 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "No PACKAGE_NAME", File=self.MetaFile)
153 return self._PackageName
154
155 ## Retrieve file guid
156 def _GetFileGuid(self):
157 if self._Guid == None:
158 if self._Header == None:
159 self._GetHeaderInfo()
160 if self._Guid == None:
161 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "No PACKAGE_GUID", File=self.MetaFile)
162 return self._Guid
163
164 ## Retrieve package version
165 def _GetVersion(self):
166 if self._Version == None:
167 if self._Header == None:
168 self._GetHeaderInfo()
169 if self._Version == None:
170 self._Version = ''
171 return self._Version
172
173 ## Retrieve protocol definitions (name/value pairs)
174 def _GetProtocol(self):
175 if self._Protocols == None:
176 #
177 # tdict is a special kind of dict, used for selecting correct
178 # protocol defition for given ARCH
179 #
180 ProtocolDict = tdict(True)
181 PrivateProtocolDict = tdict(True)
182 NameList = []
183 PrivateNameList = []
184 PublicNameList = []
185 # find out all protocol definitions for specific and 'common' arch
186 RecordList = self._RawData[MODEL_EFI_PROTOCOL, self._Arch]
187 for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:
188 if PrivateFlag == 'PRIVATE':
189 if Name not in PrivateNameList:
190 PrivateNameList.append(Name)
191 PrivateProtocolDict[Arch, Name] = Guid
192 if Name in PublicNameList:
193 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)
194 else:
195 if Name not in PublicNameList:
196 PublicNameList.append(Name)
197 if Name in PrivateNameList:
198 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)
199 if Name not in NameList:
200 NameList.append(Name)
201 ProtocolDict[Arch, Name] = Guid
202 # use sdict to keep the order
203 self._Protocols = sdict()
204 self._PrivateProtocols = sdict()
205 for Name in NameList:
206 #
207 # limit the ARCH to self._Arch, if no self._Arch found, tdict
208 # will automatically turn to 'common' ARCH for trying
209 #
210 self._Protocols[Name] = ProtocolDict[self._Arch, Name]
211 for Name in PrivateNameList:
212 self._PrivateProtocols[Name] = PrivateProtocolDict[self._Arch, Name]
213 return self._Protocols
214
215 ## Retrieve PPI definitions (name/value pairs)
216 def _GetPpi(self):
217 if self._Ppis == None:
218 #
219 # tdict is a special kind of dict, used for selecting correct
220 # PPI defition for given ARCH
221 #
222 PpiDict = tdict(True)
223 PrivatePpiDict = tdict(True)
224 NameList = []
225 PrivateNameList = []
226 PublicNameList = []
227 # find out all PPI definitions for specific arch and 'common' arch
228 RecordList = self._RawData[MODEL_EFI_PPI, self._Arch]
229 for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:
230 if PrivateFlag == 'PRIVATE':
231 if Name not in PrivateNameList:
232 PrivateNameList.append(Name)
233 PrivatePpiDict[Arch, Name] = Guid
234 if Name in PublicNameList:
235 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)
236 else:
237 if Name not in PublicNameList:
238 PublicNameList.append(Name)
239 if Name in PrivateNameList:
240 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)
241 if Name not in NameList:
242 NameList.append(Name)
243 PpiDict[Arch, Name] = Guid
244 # use sdict to keep the order
245 self._Ppis = sdict()
246 self._PrivatePpis = sdict()
247 for Name in NameList:
248 #
249 # limit the ARCH to self._Arch, if no self._Arch found, tdict
250 # will automatically turn to 'common' ARCH for trying
251 #
252 self._Ppis[Name] = PpiDict[self._Arch, Name]
253 for Name in PrivateNameList:
254 self._PrivatePpis[Name] = PrivatePpiDict[self._Arch, Name]
255 return self._Ppis
256
257 ## Retrieve GUID definitions (name/value pairs)
258 def _GetGuid(self):
259 if self._Guids == None:
260 #
261 # tdict is a special kind of dict, used for selecting correct
262 # GUID defition for given ARCH
263 #
264 GuidDict = tdict(True)
265 PrivateGuidDict = tdict(True)
266 NameList = []
267 PrivateNameList = []
268 PublicNameList = []
269 # find out all protocol definitions for specific and 'common' arch
270 RecordList = self._RawData[MODEL_EFI_GUID, self._Arch]
271 for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:
272 if PrivateFlag == 'PRIVATE':
273 if Name not in PrivateNameList:
274 PrivateNameList.append(Name)
275 PrivateGuidDict[Arch, Name] = Guid
276 if Name in PublicNameList:
277 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)
278 else:
279 if Name not in PublicNameList:
280 PublicNameList.append(Name)
281 if Name in PrivateNameList:
282 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)
283 if Name not in NameList:
284 NameList.append(Name)
285 GuidDict[Arch, Name] = Guid
286 # use sdict to keep the order
287 self._Guids = sdict()
288 self._PrivateGuids = sdict()
289 for Name in NameList:
290 #
291 # limit the ARCH to self._Arch, if no self._Arch found, tdict
292 # will automatically turn to 'common' ARCH for trying
293 #
294 self._Guids[Name] = GuidDict[self._Arch, Name]
295 for Name in PrivateNameList:
296 self._PrivateGuids[Name] = PrivateGuidDict[self._Arch, Name]
297 return self._Guids
298
299 ## Retrieve public include paths declared in this package
300 def _GetInclude(self):
301 if self._Includes == None or self._CommonIncludes is None:
302 self._CommonIncludes = []
303 self._Includes = []
304 self._PrivateIncludes = []
305 PublicInclues = []
306 RecordList = self._RawData[MODEL_EFI_INCLUDE, self._Arch]
307 Macros = self._Macros
308 Macros["EDK_SOURCE"] = GlobalData.gEcpSource
309 for Record in RecordList:
310 File = PathClass(NormPath(Record[0], Macros), self._PackageDir, Arch=self._Arch)
311 LineNo = Record[-1]
312 # validate the path
313 ErrorCode, ErrorInfo = File.Validate()
314 if ErrorCode != 0:
315 EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, File=self.MetaFile, Line=LineNo)
316
317 # avoid duplicate include path
318 if File not in self._Includes:
319 self._Includes.append(File)
320 if Record[4] == 'PRIVATE':
321 if File not in self._PrivateIncludes:
322 self._PrivateIncludes.append(File)
323 if File in PublicInclues:
324 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)
325 else:
326 if File not in PublicInclues:
327 PublicInclues.append(File)
328 if File in self._PrivateIncludes:
329 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)
330 if Record[3] == "COMMON":
331 self._CommonIncludes.append(File)
332 return self._Includes
333
334 ## Retrieve library class declarations (not used in build at present)
335 def _GetLibraryClass(self):
336 if self._LibraryClasses == None:
337 #
338 # tdict is a special kind of dict, used for selecting correct
339 # library class declaration for given ARCH
340 #
341 LibraryClassDict = tdict(True)
342 LibraryClassSet = set()
343 RecordList = self._RawData[MODEL_EFI_LIBRARY_CLASS, self._Arch]
344 Macros = self._Macros
345 for LibraryClass, File, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:
346 File = PathClass(NormPath(File, Macros), self._PackageDir, Arch=self._Arch)
347 # check the file validation
348 ErrorCode, ErrorInfo = File.Validate()
349 if ErrorCode != 0:
350 EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, File=self.MetaFile, Line=LineNo)
351 LibraryClassSet.add(LibraryClass)
352 LibraryClassDict[Arch, LibraryClass] = File
353 self._LibraryClasses = sdict()
354 for LibraryClass in LibraryClassSet:
355 self._LibraryClasses[LibraryClass] = LibraryClassDict[self._Arch, LibraryClass]
356 return self._LibraryClasses
357
358 ## Retrieve PCD declarations
359 def _GetPcds(self):
360 if self._Pcds == None:
361 self._Pcds = sdict()
362 self._Pcds.update(self._GetPcd(MODEL_PCD_FIXED_AT_BUILD))
363 self._Pcds.update(self._GetPcd(MODEL_PCD_PATCHABLE_IN_MODULE))
364 self._Pcds.update(self._GetPcd(MODEL_PCD_FEATURE_FLAG))
365 self._Pcds.update(self._GetPcd(MODEL_PCD_DYNAMIC))
366 self._Pcds.update(self._GetPcd(MODEL_PCD_DYNAMIC_EX))
367 return self._Pcds
368
369
370 def ProcessStructurePcd(self, StructurePcdRawDataSet):
371 s_pcd_set = OrderedDict()
372 for s_pcd,LineNo in StructurePcdRawDataSet:
373 if s_pcd.TokenSpaceGuidCName not in s_pcd_set:
374 s_pcd_set[s_pcd.TokenSpaceGuidCName] = []
375 s_pcd_set[s_pcd.TokenSpaceGuidCName].append((s_pcd,LineNo))
376
377 str_pcd_set = []
378 for pcdname in s_pcd_set:
379 dep_pkgs = []
380 struct_pcd = StructurePcd()
381 for item,LineNo in s_pcd_set[pcdname]:
382 if "<HeaderFiles>" in item.TokenCName:
383 struct_pcd.StructuredPcdIncludeFile.append(item.DefaultValue)
384 elif "<Packages>" in item.TokenCName:
385 dep_pkgs.append(item.DefaultValue)
386 elif item.DatumType == item.TokenCName:
387 struct_pcd.copy(item)
388 struct_pcd.TokenValue = struct_pcd.TokenValue.strip("{").strip()
389 struct_pcd.TokenSpaceGuidCName, struct_pcd.TokenCName = pcdname.split(".")
390 struct_pcd.PcdDefineLineNo = LineNo
391 struct_pcd.PkgPath = self.MetaFile.File
392 struct_pcd.SetDecDefaultValue(item.DefaultValue)
393 else:
394 struct_pcd.AddDefaultValue(item.TokenCName, item.DefaultValue,self.MetaFile.File,LineNo)
395
396 struct_pcd.PackageDecs = dep_pkgs
397 str_pcd_set.append(struct_pcd)
398 return str_pcd_set
399
400 ## Retrieve PCD declarations for given type
401 def _GetPcd(self, Type):
402 Pcds = sdict()
403 #
404 # tdict is a special kind of dict, used for selecting correct
405 # PCD declaration for given ARCH
406 #
407 PcdDict = tdict(True, 3)
408 # for summarizing PCD
409 PcdSet = []
410 # find out all PCDs of the 'type'
411
412 StrPcdSet = []
413 RecordList = self._RawData[Type, self._Arch]
414 for TokenSpaceGuid, PcdCName, Setting, Arch, PrivateFlag, Dummy1, Dummy2 in RecordList:
415 PcdDict[Arch, PcdCName, TokenSpaceGuid] = (Setting,Dummy2)
416 if not (PcdCName, TokenSpaceGuid) in PcdSet:
417 PcdSet.append((PcdCName, TokenSpaceGuid))
418
419 for PcdCName, TokenSpaceGuid in PcdSet:
420 #
421 # limit the ARCH to self._Arch, if no self._Arch found, tdict
422 # will automatically turn to 'common' ARCH and try again
423 #
424 Setting,LineNo = PcdDict[self._Arch, PcdCName, TokenSpaceGuid]
425 if Setting == None:
426 continue
427
428 DefaultValue, DatumType, TokenNumber = AnalyzePcdData(Setting)
429 validateranges, validlists, expressions = self._RawData.GetValidExpression(TokenSpaceGuid, PcdCName)
430 PcdObj = PcdClassObject(
431 PcdCName,
432 TokenSpaceGuid,
433 self._PCD_TYPE_STRING_[Type],
434 DatumType,
435 DefaultValue,
436 TokenNumber,
437 '',
438 {},
439 False,
440 None,
441 list(validateranges),
442 list(validlists),
443 list(expressions)
444 )
445 PcdObj.DefinitionPosition = (self.MetaFile.File,LineNo)
446 if "." in TokenSpaceGuid:
447 StrPcdSet.append((PcdObj,LineNo))
448 else:
449 Pcds[PcdCName, TokenSpaceGuid, self._PCD_TYPE_STRING_[Type]] = PcdObj
450
451 StructurePcds = self.ProcessStructurePcd(StrPcdSet)
452 for pcd in StructurePcds:
453 Pcds[pcd.TokenCName, pcd.TokenSpaceGuidCName, self._PCD_TYPE_STRING_[Type]] = pcd
454 StructPattern = re.compile(r'[_a-zA-Z][0-9A-Za-z_]*$')
455 for pcd in Pcds.values():
456 if pcd.DatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, TAB_VOID, "BOOLEAN"]:
457 if StructPattern.match(pcd.DatumType) == None:
458 EdkLogger.error('build', FORMAT_INVALID, "DatumType only support BOOLEAN, UINT8, UINT16, UINT32, UINT64, VOID* or a valid struct name.", pcd.DefinitionPosition[0],pcd.DefinitionPosition[1])
459 for struct_pcd in Pcds.values():
460 if isinstance(struct_pcd,StructurePcd) and not struct_pcd.StructuredPcdIncludeFile:
461 EdkLogger.error("build", PCD_STRUCTURE_PCD_ERROR, "The structure Pcd %s.%s header file is not found in %s line %s \n" % (struct_pcd.TokenSpaceGuidCName, struct_pcd.TokenCName,struct_pcd.DefinitionPosition[0],struct_pcd.DefinitionPosition[1] ))
462
463 return Pcds
464 @property
465 def CommonIncludes(self):
466 if self._CommonIncludes is None:
467 self.Includes
468 return self._CommonIncludes
469
470
471 _Macros = property(_GetMacros)
472 Arch = property(_GetArch, _SetArch)
473 PackageName = property(_GetPackageName)
474 Guid = property(_GetFileGuid)
475 Version = property(_GetVersion)
476
477 Protocols = property(_GetProtocol)
478 Ppis = property(_GetPpi)
479 Guids = property(_GetGuid)
480 Includes = property(_GetInclude)
481 LibraryClasses = property(_GetLibraryClass)
482 Pcds = property(_GetPcds)