]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Workspace/InfBuildData.py
BaseTools: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / BaseTools / Source / Python / Workspace / InfBuildData.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
9 from __future__ import absolute_import
10 from Common.DataType import *
11 from Common.Misc import *
12 from Common.caching import cached_property, cached_class_function
13 from types import *
14 from .MetaFileParser import *
15 from collections import OrderedDict
16 from Workspace.BuildClassObject import ModuleBuildClassObject, LibraryClassObject, PcdClassObject
17
18 ## Get Protocol value from given packages
19 #
20 # @param CName The CName of the GUID
21 # @param PackageList List of packages looking-up in
22 # @param Inffile The driver file
23 #
24 # @retval GuidValue if the CName is found in any given package
25 # @retval None if the CName is not found in all given packages
26 #
27 def _ProtocolValue(CName, PackageList, Inffile = None):
28 for P in PackageList:
29 ProtocolKeys = list(P.Protocols.keys())
30 if Inffile and P._PrivateProtocols:
31 if not Inffile.startswith(P.MetaFile.Dir):
32 ProtocolKeys = [x for x in P.Protocols if x not in P._PrivateProtocols]
33 if CName in ProtocolKeys:
34 return P.Protocols[CName]
35 return None
36
37 ## Get PPI value from given packages
38 #
39 # @param CName The CName of the GUID
40 # @param PackageList List of packages looking-up in
41 # @param Inffile The driver file
42 #
43 # @retval GuidValue if the CName is found in any given package
44 # @retval None if the CName is not found in all given packages
45 #
46 def _PpiValue(CName, PackageList, Inffile = None):
47 for P in PackageList:
48 PpiKeys = list(P.Ppis.keys())
49 if Inffile and P._PrivatePpis:
50 if not Inffile.startswith(P.MetaFile.Dir):
51 PpiKeys = [x for x in P.Ppis if x not in P._PrivatePpis]
52 if CName in PpiKeys:
53 return P.Ppis[CName]
54 return None
55
56 ## Module build information from INF file
57 #
58 # This class is used to retrieve information stored in database and convert them
59 # into ModuleBuildClassObject form for easier use for AutoGen.
60 #
61 class InfBuildData(ModuleBuildClassObject):
62 # dict used to convert PCD type in database to string used by build tool
63 _PCD_TYPE_STRING_ = {
64 MODEL_PCD_FIXED_AT_BUILD : TAB_PCDS_FIXED_AT_BUILD,
65 MODEL_PCD_PATCHABLE_IN_MODULE : TAB_PCDS_PATCHABLE_IN_MODULE,
66 MODEL_PCD_FEATURE_FLAG : TAB_PCDS_FEATURE_FLAG,
67 MODEL_PCD_DYNAMIC : TAB_PCDS_DYNAMIC,
68 MODEL_PCD_DYNAMIC_DEFAULT : TAB_PCDS_DYNAMIC,
69 MODEL_PCD_DYNAMIC_HII : TAB_PCDS_DYNAMIC_HII,
70 MODEL_PCD_DYNAMIC_VPD : TAB_PCDS_DYNAMIC_VPD,
71 MODEL_PCD_DYNAMIC_EX : TAB_PCDS_DYNAMIC_EX,
72 MODEL_PCD_DYNAMIC_EX_DEFAULT : TAB_PCDS_DYNAMIC_EX,
73 MODEL_PCD_DYNAMIC_EX_HII : TAB_PCDS_DYNAMIC_EX_HII,
74 MODEL_PCD_DYNAMIC_EX_VPD : TAB_PCDS_DYNAMIC_EX_VPD,
75 }
76
77 # dict used to convert part of [Defines] to members of InfBuildData directly
78 _PROPERTY_ = {
79 #
80 # Required Fields
81 #
82 TAB_INF_DEFINES_BASE_NAME : "_BaseName",
83 TAB_INF_DEFINES_FILE_GUID : "_Guid",
84 TAB_INF_DEFINES_MODULE_TYPE : "_ModuleType",
85 #
86 # Optional Fields
87 #
88 # TAB_INF_DEFINES_INF_VERSION : "_AutoGenVersion",
89 TAB_INF_DEFINES_COMPONENT_TYPE : "_ComponentType",
90 TAB_INF_DEFINES_MAKEFILE_NAME : "_MakefileName",
91 # TAB_INF_DEFINES_CUSTOM_MAKEFILE : "_CustomMakefile",
92 TAB_INF_DEFINES_DPX_SOURCE :"_DxsFile",
93 TAB_INF_DEFINES_VERSION_NUMBER : "_Version",
94 TAB_INF_DEFINES_VERSION_STRING : "_Version",
95 TAB_INF_DEFINES_VERSION : "_Version",
96 TAB_INF_DEFINES_PCD_IS_DRIVER : "_PcdIsDriver",
97 TAB_INF_DEFINES_SHADOW : "_Shadow"
98 }
99
100 # regular expression for converting XXX_FLAGS in [nmake] section to new type
101 _NMAKE_FLAG_PATTERN_ = re.compile("(?:EBC_)?([A-Z]+)_(?:STD_|PROJ_|ARCH_)?FLAGS(?:_DLL|_ASL|_EXE)?", re.UNICODE)
102 # dict used to convert old tool name used in [nmake] section to new ones
103 _TOOL_CODE_ = {
104 "C" : "CC",
105 BINARY_FILE_TYPE_LIB : "SLINK",
106 "LINK" : "DLINK",
107 }
108
109
110 ## Constructor of InfBuildData
111 #
112 # Initialize object of InfBuildData
113 #
114 # @param FilePath The path of platform description file
115 # @param RawData The raw data of DSC file
116 # @param BuildDataBase Database used to retrieve module/package information
117 # @param Arch The target architecture
118 # @param Platform The name of platform employing this module
119 # @param Macros Macros used for replacement in DSC file
120 #
121 def __init__(self, FilePath, RawData, BuildDatabase, Arch=TAB_ARCH_COMMON, Target=None, Toolchain=None):
122 self.MetaFile = FilePath
123 self._ModuleDir = FilePath.Dir
124 self._RawData = RawData
125 self._Bdb = BuildDatabase
126 self._Arch = Arch
127 self._Target = Target
128 self._Toolchain = Toolchain
129 self._Platform = TAB_COMMON
130 self._TailComments = None
131 self._BaseName = None
132 self._DxsFile = None
133 self._ModuleType = None
134 self._ComponentType = None
135 self._BuildType = None
136 self._Guid = None
137 self._Version = None
138 self._PcdIsDriver = None
139 self._BinaryModule = None
140 self._Shadow = None
141 self._MakefileName = None
142 self._CustomMakefile = None
143 self._Specification = None
144 self._LibraryClass = None
145 self._ModuleEntryPointList = None
146 self._ModuleUnloadImageList = None
147 self._ConstructorList = None
148 self._DestructorList = None
149 self._Defs = OrderedDict()
150 self._ProtocolComments = None
151 self._PpiComments = None
152 self._GuidsUsedByPcd = OrderedDict()
153 self._GuidComments = None
154 self._PcdComments = None
155 self._BuildOptions = None
156 self._DependencyFileList = None
157
158 ## XXX[key] = value
159 def __setitem__(self, key, value):
160 self.__dict__[self._PROPERTY_[key]] = value
161
162 ## value = XXX[key]
163 def __getitem__(self, key):
164 return self.__dict__[self._PROPERTY_[key]]
165
166 ## "in" test support
167 def __contains__(self, key):
168 return key in self._PROPERTY_
169
170 ## Get current effective macros
171 @cached_property
172 def _Macros(self):
173 RetVal = {}
174 return RetVal
175
176 ## Get architecture
177 @cached_property
178 def Arch(self):
179 return self._Arch
180
181 ## Return the name of platform employing this module
182 @cached_property
183 def Platform(self):
184 return self._Platform
185
186 @cached_property
187 def HeaderComments(self):
188 return [a[0] for a in self._RawData[MODEL_META_DATA_HEADER_COMMENT]]
189
190 @cached_property
191 def TailComments(self):
192 return [a[0] for a in self._RawData[MODEL_META_DATA_TAIL_COMMENT]]
193
194 ## Retrieve all information in [Defines] section
195 #
196 # (Retrieving all [Defines] information in one-shot is just to save time.)
197 #
198 @cached_class_function
199 def _GetHeaderInfo(self):
200 RecordList = self._RawData[MODEL_META_DATA_HEADER, self._Arch, self._Platform]
201 for Record in RecordList:
202 Name, Value = Record[1], ReplaceMacro(Record[2], self._Macros, False)
203 # items defined _PROPERTY_ don't need additional processing
204 if Name in self:
205 self[Name] = Value
206 self._Defs[Name] = Value
207 self._Macros[Name] = Value
208 # some special items in [Defines] section need special treatment
209 elif Name in ('EFI_SPECIFICATION_VERSION', 'UEFI_SPECIFICATION_VERSION', 'EDK_RELEASE_VERSION', 'PI_SPECIFICATION_VERSION'):
210 if Name in ('EFI_SPECIFICATION_VERSION', 'UEFI_SPECIFICATION_VERSION'):
211 Name = 'UEFI_SPECIFICATION_VERSION'
212 if self._Specification is None:
213 self._Specification = OrderedDict()
214 self._Specification[Name] = GetHexVerValue(Value)
215 if self._Specification[Name] is None:
216 EdkLogger.error("build", FORMAT_NOT_SUPPORTED,
217 "'%s' format is not supported for %s" % (Value, Name),
218 File=self.MetaFile, Line=Record[-1])
219 elif Name == 'LIBRARY_CLASS':
220 if self._LibraryClass is None:
221 self._LibraryClass = []
222 ValueList = GetSplitValueList(Value)
223 LibraryClass = ValueList[0]
224 if len(ValueList) > 1:
225 SupModuleList = GetSplitValueList(ValueList[1], ' ')
226 else:
227 SupModuleList = SUP_MODULE_LIST
228 self._LibraryClass.append(LibraryClassObject(LibraryClass, SupModuleList))
229 elif Name == 'ENTRY_POINT':
230 if self._ModuleEntryPointList is None:
231 self._ModuleEntryPointList = []
232 self._ModuleEntryPointList.append(Value)
233 elif Name == 'UNLOAD_IMAGE':
234 if self._ModuleUnloadImageList is None:
235 self._ModuleUnloadImageList = []
236 if not Value:
237 continue
238 self._ModuleUnloadImageList.append(Value)
239 elif Name == 'CONSTRUCTOR':
240 if self._ConstructorList is None:
241 self._ConstructorList = []
242 if not Value:
243 continue
244 self._ConstructorList.append(Value)
245 elif Name == 'DESTRUCTOR':
246 if self._DestructorList is None:
247 self._DestructorList = []
248 if not Value:
249 continue
250 self._DestructorList.append(Value)
251 elif Name == TAB_INF_DEFINES_CUSTOM_MAKEFILE:
252 TokenList = GetSplitValueList(Value)
253 if self._CustomMakefile is None:
254 self._CustomMakefile = {}
255 if len(TokenList) < 2:
256 self._CustomMakefile[TAB_COMPILER_MSFT] = TokenList[0]
257 self._CustomMakefile['GCC'] = TokenList[0]
258 else:
259 if TokenList[0] not in [TAB_COMPILER_MSFT, 'GCC']:
260 EdkLogger.error("build", FORMAT_NOT_SUPPORTED,
261 "No supported family [%s]" % TokenList[0],
262 File=self.MetaFile, Line=Record[-1])
263 self._CustomMakefile[TokenList[0]] = TokenList[1]
264 else:
265 self._Defs[Name] = Value
266 self._Macros[Name] = Value
267
268 #
269 # Retrieve information in sections specific to Edk.x modules
270 #
271 if not self._ModuleType:
272 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE,
273 "MODULE_TYPE is not given", File=self.MetaFile)
274 if self._ModuleType not in SUP_MODULE_LIST:
275 RecordList = self._RawData[MODEL_META_DATA_HEADER, self._Arch, self._Platform]
276 for Record in RecordList:
277 Name = Record[1]
278 if Name == "MODULE_TYPE":
279 LineNo = Record[6]
280 break
281 EdkLogger.error("build", FORMAT_NOT_SUPPORTED,
282 "MODULE_TYPE %s is not supported for EDK II, valid values are:\n %s" % (self._ModuleType, ' '.join(l for l in SUP_MODULE_LIST)),
283 File=self.MetaFile, Line=LineNo)
284 if (self._Specification is None) or (not 'PI_SPECIFICATION_VERSION' in self._Specification) or (int(self._Specification['PI_SPECIFICATION_VERSION'], 16) < 0x0001000A):
285 if self._ModuleType == SUP_MODULE_SMM_CORE:
286 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "SMM_CORE module type can't be used in the module with PI_SPECIFICATION_VERSION less than 0x0001000A", File=self.MetaFile)
287 if (self._Specification is None) or (not 'PI_SPECIFICATION_VERSION' in self._Specification) or (int(self._Specification['PI_SPECIFICATION_VERSION'], 16) < 0x00010032):
288 if self._ModuleType == SUP_MODULE_MM_CORE_STANDALONE:
289 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "MM_CORE_STANDALONE module type can't be used in the module with PI_SPECIFICATION_VERSION less than 0x00010032", File=self.MetaFile)
290 if self._ModuleType == SUP_MODULE_MM_STANDALONE:
291 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "MM_STANDALONE module type can't be used in the module with PI_SPECIFICATION_VERSION less than 0x00010032", File=self.MetaFile)
292 if 'PCI_DEVICE_ID' in self._Defs and 'PCI_VENDOR_ID' in self._Defs \
293 and 'PCI_CLASS_CODE' in self._Defs and 'PCI_REVISION' in self._Defs:
294 self._BuildType = 'UEFI_OPTIONROM'
295 if 'PCI_COMPRESS' in self._Defs:
296 if self._Defs['PCI_COMPRESS'] not in ('TRUE', 'FALSE'):
297 EdkLogger.error("build", FORMAT_INVALID, "Expected TRUE/FALSE for PCI_COMPRESS: %s" % self.MetaFile)
298
299 elif 'UEFI_HII_RESOURCE_SECTION' in self._Defs \
300 and self._Defs['UEFI_HII_RESOURCE_SECTION'] == 'TRUE':
301 self._BuildType = 'UEFI_HII'
302 else:
303 self._BuildType = self._ModuleType.upper()
304
305 if self._DxsFile:
306 File = PathClass(NormPath(self._DxsFile), self._ModuleDir, Arch=self._Arch)
307 # check the file validation
308 ErrorCode, ErrorInfo = File.Validate(".dxs", CaseSensitive=False)
309 if ErrorCode != 0:
310 EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo,
311 File=self.MetaFile, Line=LineNo)
312 if not self._DependencyFileList:
313 self._DependencyFileList = []
314 self._DependencyFileList.append(File)
315
316 ## Retrieve file version
317 @cached_property
318 def AutoGenVersion(self):
319 RetVal = 0x00010000
320 RecordList = self._RawData[MODEL_META_DATA_HEADER, self._Arch, self._Platform]
321 for Record in RecordList:
322 if Record[1] == TAB_INF_DEFINES_INF_VERSION:
323 if '.' in Record[2]:
324 ValueList = Record[2].split('.')
325 Major = '%04o' % int(ValueList[0], 0)
326 Minor = '%04o' % int(ValueList[1], 0)
327 RetVal = int('0x' + Major + Minor, 0)
328 else:
329 RetVal = int(Record[2], 0)
330 break
331 return RetVal
332
333 ## Retrieve BASE_NAME
334 @cached_property
335 def BaseName(self):
336 if self._BaseName is None:
337 self._GetHeaderInfo()
338 if self._BaseName is None:
339 EdkLogger.error('build', ATTRIBUTE_NOT_AVAILABLE, "No BASE_NAME name", File=self.MetaFile)
340 return self._BaseName
341
342 ## Retrieve DxsFile
343 @cached_property
344 def DxsFile(self):
345 if self._DxsFile is None:
346 self._GetHeaderInfo()
347 if self._DxsFile is None:
348 self._DxsFile = ''
349 return self._DxsFile
350
351 ## Retrieve MODULE_TYPE
352 @cached_property
353 def ModuleType(self):
354 if self._ModuleType is None:
355 self._GetHeaderInfo()
356 if self._ModuleType is None:
357 self._ModuleType = SUP_MODULE_BASE
358 if self._ModuleType not in SUP_MODULE_LIST:
359 self._ModuleType = SUP_MODULE_USER_DEFINED
360 return self._ModuleType
361
362 ## Retrieve COMPONENT_TYPE
363 @cached_property
364 def ComponentType(self):
365 if self._ComponentType is None:
366 self._GetHeaderInfo()
367 if self._ComponentType is None:
368 self._ComponentType = SUP_MODULE_USER_DEFINED
369 return self._ComponentType
370
371 ## Retrieve "BUILD_TYPE"
372 @cached_property
373 def BuildType(self):
374 if self._BuildType is None:
375 self._GetHeaderInfo()
376 if not self._BuildType:
377 self._BuildType = SUP_MODULE_BASE
378 return self._BuildType
379
380 ## Retrieve file guid
381 @cached_property
382 def Guid(self):
383 if self._Guid is None:
384 self._GetHeaderInfo()
385 if self._Guid is None:
386 self._Guid = '00000000-0000-0000-0000-000000000000'
387 return self._Guid
388
389 ## Retrieve module version
390 @cached_property
391 def Version(self):
392 if self._Version is None:
393 self._GetHeaderInfo()
394 if self._Version is None:
395 self._Version = '0.0'
396 return self._Version
397
398 ## Retrieve PCD_IS_DRIVER
399 @cached_property
400 def PcdIsDriver(self):
401 if self._PcdIsDriver is None:
402 self._GetHeaderInfo()
403 if self._PcdIsDriver is None:
404 self._PcdIsDriver = ''
405 return self._PcdIsDriver
406
407 ## Retrieve SHADOW
408 @cached_property
409 def Shadow(self):
410 if self._Shadow is None:
411 self._GetHeaderInfo()
412 if self._Shadow and self._Shadow.upper() == 'TRUE':
413 self._Shadow = True
414 else:
415 self._Shadow = False
416 return self._Shadow
417
418 ## Retrieve CUSTOM_MAKEFILE
419 @cached_property
420 def CustomMakefile(self):
421 if self._CustomMakefile is None:
422 self._GetHeaderInfo()
423 if self._CustomMakefile is None:
424 self._CustomMakefile = {}
425 return self._CustomMakefile
426
427 ## Retrieve EFI_SPECIFICATION_VERSION
428 @cached_property
429 def Specification(self):
430 if self._Specification is None:
431 self._GetHeaderInfo()
432 if self._Specification is None:
433 self._Specification = {}
434 return self._Specification
435
436 ## Retrieve LIBRARY_CLASS
437 @cached_property
438 def LibraryClass(self):
439 if self._LibraryClass is None:
440 self._GetHeaderInfo()
441 if self._LibraryClass is None:
442 self._LibraryClass = []
443 return self._LibraryClass
444
445 ## Retrieve ENTRY_POINT
446 @cached_property
447 def ModuleEntryPointList(self):
448 if self._ModuleEntryPointList is None:
449 self._GetHeaderInfo()
450 if self._ModuleEntryPointList is None:
451 self._ModuleEntryPointList = []
452 return self._ModuleEntryPointList
453
454 ## Retrieve UNLOAD_IMAGE
455 @cached_property
456 def ModuleUnloadImageList(self):
457 if self._ModuleUnloadImageList is None:
458 self._GetHeaderInfo()
459 if self._ModuleUnloadImageList is None:
460 self._ModuleUnloadImageList = []
461 return self._ModuleUnloadImageList
462
463 ## Retrieve CONSTRUCTOR
464 @cached_property
465 def ConstructorList(self):
466 if self._ConstructorList is None:
467 self._GetHeaderInfo()
468 if self._ConstructorList is None:
469 self._ConstructorList = []
470 return self._ConstructorList
471
472 ## Retrieve DESTRUCTOR
473 @cached_property
474 def DestructorList(self):
475 if self._DestructorList is None:
476 self._GetHeaderInfo()
477 if self._DestructorList is None:
478 self._DestructorList = []
479 return self._DestructorList
480
481 ## Retrieve definies other than above ones
482 @cached_property
483 def Defines(self):
484 self._GetHeaderInfo()
485 return self._Defs
486
487 ## Retrieve binary files
488 @cached_class_function
489 def _GetBinaries(self):
490 RetVal = []
491 RecordList = self._RawData[MODEL_EFI_BINARY_FILE, self._Arch, self._Platform]
492 Macros = self._Macros
493 Macros['PROCESSOR'] = self._Arch
494 for Record in RecordList:
495 FileType = Record[0]
496 LineNo = Record[-1]
497 Target = TAB_COMMON
498 FeatureFlag = []
499 if Record[2]:
500 TokenList = GetSplitValueList(Record[2], TAB_VALUE_SPLIT)
501 if TokenList:
502 Target = TokenList[0]
503 if len(TokenList) > 1:
504 FeatureFlag = Record[1:]
505
506 File = PathClass(NormPath(Record[1], Macros), self._ModuleDir, '', FileType, True, self._Arch, '', Target)
507 # check the file validation
508 ErrorCode, ErrorInfo = File.Validate()
509 if ErrorCode != 0:
510 EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, File=self.MetaFile, Line=LineNo)
511 RetVal.append(File)
512 return RetVal
513
514 ## Retrieve binary files with error check.
515 @cached_property
516 def Binaries(self):
517 RetVal = self._GetBinaries()
518 if GlobalData.gIgnoreSource and not RetVal:
519 ErrorInfo = "The INF file does not contain any RetVal to use in creating the image\n"
520 EdkLogger.error('build', RESOURCE_NOT_AVAILABLE, ExtraData=ErrorInfo, File=self.MetaFile)
521
522 return RetVal
523
524 ## Retrieve source files
525 @cached_property
526 def Sources(self):
527 self._GetHeaderInfo()
528 # Ignore all source files in a binary build mode
529 if GlobalData.gIgnoreSource:
530 return []
531
532 RetVal = []
533 RecordList = self._RawData[MODEL_EFI_SOURCE_FILE, self._Arch, self._Platform]
534 Macros = self._Macros
535 for Record in RecordList:
536 LineNo = Record[-1]
537 ToolChainFamily = Record[1]
538 TagName = Record[2]
539 ToolCode = Record[3]
540
541 File = PathClass(NormPath(Record[0], Macros), self._ModuleDir, '',
542 '', False, self._Arch, ToolChainFamily, '', TagName, ToolCode)
543 # check the file validation
544 ErrorCode, ErrorInfo = File.Validate()
545 if ErrorCode != 0:
546 EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, File=self.MetaFile, Line=LineNo)
547
548 RetVal.append(File)
549 # add any previously found dependency files to the source list
550 if self._DependencyFileList:
551 RetVal.extend(self._DependencyFileList)
552 return RetVal
553
554 ## Retrieve library classes employed by this module
555 @cached_property
556 def LibraryClasses(self):
557 RetVal = OrderedDict()
558 RecordList = self._RawData[MODEL_EFI_LIBRARY_CLASS, self._Arch, self._Platform]
559 for Record in RecordList:
560 Lib = Record[0]
561 Instance = Record[1]
562 if Instance:
563 Instance = NormPath(Instance, self._Macros)
564 RetVal[Lib] = Instance
565 else:
566 RetVal[Lib] = None
567 return RetVal
568
569 ## Retrieve library names (for Edk.x style of modules)
570 @cached_property
571 def Libraries(self):
572 RetVal = []
573 RecordList = self._RawData[MODEL_EFI_LIBRARY_INSTANCE, self._Arch, self._Platform]
574 for Record in RecordList:
575 LibraryName = ReplaceMacro(Record[0], self._Macros, False)
576 # in case of name with '.lib' extension, which is unusual in Edk.x inf
577 LibraryName = os.path.splitext(LibraryName)[0]
578 if LibraryName not in RetVal:
579 RetVal.append(LibraryName)
580 return RetVal
581
582 @cached_property
583 def ProtocolComments(self):
584 self.Protocols
585 return self._ProtocolComments
586
587 ## Retrieve protocols consumed/produced by this module
588 @cached_property
589 def Protocols(self):
590 RetVal = OrderedDict()
591 self._ProtocolComments = OrderedDict()
592 RecordList = self._RawData[MODEL_EFI_PROTOCOL, self._Arch, self._Platform]
593 for Record in RecordList:
594 CName = Record[0]
595 Value = _ProtocolValue(CName, self.Packages, self.MetaFile.Path)
596 if Value is None:
597 PackageList = "\n\t".join(str(P) for P in self.Packages)
598 EdkLogger.error('build', RESOURCE_NOT_AVAILABLE,
599 "Value of Protocol [%s] is not found under [Protocols] section in" % CName,
600 ExtraData=PackageList, File=self.MetaFile, Line=Record[-1])
601 RetVal[CName] = Value
602 CommentRecords = self._RawData[MODEL_META_DATA_COMMENT, self._Arch, self._Platform, Record[5]]
603 self._ProtocolComments[CName] = [a[0] for a in CommentRecords]
604 return RetVal
605
606 @cached_property
607 def PpiComments(self):
608 self.Ppis
609 return self._PpiComments
610
611 ## Retrieve PPIs consumed/produced by this module
612 @cached_property
613 def Ppis(self):
614 RetVal = OrderedDict()
615 self._PpiComments = OrderedDict()
616 RecordList = self._RawData[MODEL_EFI_PPI, self._Arch, self._Platform]
617 for Record in RecordList:
618 CName = Record[0]
619 Value = _PpiValue(CName, self.Packages, self.MetaFile.Path)
620 if Value is None:
621 PackageList = "\n\t".join(str(P) for P in self.Packages)
622 EdkLogger.error('build', RESOURCE_NOT_AVAILABLE,
623 "Value of PPI [%s] is not found under [Ppis] section in " % CName,
624 ExtraData=PackageList, File=self.MetaFile, Line=Record[-1])
625 RetVal[CName] = Value
626 CommentRecords = self._RawData[MODEL_META_DATA_COMMENT, self._Arch, self._Platform, Record[5]]
627 self._PpiComments[CName] = [a[0] for a in CommentRecords]
628 return RetVal
629
630 @cached_property
631 def GuidComments(self):
632 self.Guids
633 return self._GuidComments
634
635 ## Retrieve GUIDs consumed/produced by this module
636 @cached_property
637 def Guids(self):
638 RetVal = OrderedDict()
639 self._GuidComments = OrderedDict()
640 RecordList = self._RawData[MODEL_EFI_GUID, self._Arch, self._Platform]
641 for Record in RecordList:
642 CName = Record[0]
643 Value = GuidValue(CName, self.Packages, self.MetaFile.Path)
644 if Value is None:
645 PackageList = "\n\t".join(str(P) for P in self.Packages)
646 EdkLogger.error('build', RESOURCE_NOT_AVAILABLE,
647 "Value of Guid [%s] is not found under [Guids] section in" % CName,
648 ExtraData=PackageList, File=self.MetaFile, Line=Record[-1])
649 RetVal[CName] = Value
650 CommentRecords = self._RawData[MODEL_META_DATA_COMMENT, self._Arch, self._Platform, Record[5]]
651 self._GuidComments[CName] = [a[0] for a in CommentRecords]
652 return RetVal
653
654 ## Retrieve include paths necessary for this module (for Edk.x style of modules)
655 @cached_property
656 def Includes(self):
657 RetVal = []
658 Macros = self._Macros
659 Macros['PROCESSOR'] = GlobalData.gEdkGlobal.get('PROCESSOR', self._Arch)
660 RecordList = self._RawData[MODEL_EFI_INCLUDE, self._Arch, self._Platform]
661 for Record in RecordList:
662 File = NormPath(Record[0], Macros)
663 if File[0] == '.':
664 File = os.path.join(self._ModuleDir, File)
665 else:
666 File = mws.join(GlobalData.gWorkspace, File)
667 File = RealPath(os.path.normpath(File))
668 if File:
669 RetVal.append(File)
670 return RetVal
671
672 ## Retrieve packages this module depends on
673 @cached_property
674 def Packages(self):
675 RetVal = []
676 RecordList = self._RawData[MODEL_META_DATA_PACKAGE, self._Arch, self._Platform]
677 Macros = self._Macros
678 for Record in RecordList:
679 File = PathClass(NormPath(Record[0], Macros), GlobalData.gWorkspace, Arch=self._Arch)
680 # check the file validation
681 ErrorCode, ErrorInfo = File.Validate('.dec')
682 if ErrorCode != 0:
683 LineNo = Record[-1]
684 EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, File=self.MetaFile, Line=LineNo)
685 # parse this package now. we need it to get protocol/ppi/guid value
686 RetVal.append(self._Bdb[File, self._Arch, self._Target, self._Toolchain])
687 return RetVal
688
689 ## Retrieve PCD comments
690 @cached_property
691 def PcdComments(self):
692 self.Pcds
693 return self._PcdComments
694
695 ## Retrieve PCDs used in this module
696 @cached_property
697 def Pcds(self):
698 self._PcdComments = OrderedDict()
699 RetVal = OrderedDict()
700 RetVal.update(self._GetPcd(MODEL_PCD_FIXED_AT_BUILD))
701 RetVal.update(self._GetPcd(MODEL_PCD_PATCHABLE_IN_MODULE))
702 RetVal.update(self._GetPcd(MODEL_PCD_FEATURE_FLAG))
703 RetVal.update(self._GetPcd(MODEL_PCD_DYNAMIC))
704 RetVal.update(self._GetPcd(MODEL_PCD_DYNAMIC_EX))
705 return RetVal
706
707 @cached_property
708 def PcdsName(self):
709 PcdsName = set()
710 for Type in (MODEL_PCD_FIXED_AT_BUILD,MODEL_PCD_PATCHABLE_IN_MODULE,MODEL_PCD_FEATURE_FLAG,MODEL_PCD_DYNAMIC,MODEL_PCD_DYNAMIC_EX):
711 RecordList = self._RawData[Type, self._Arch, self._Platform]
712 for TokenSpaceGuid, PcdCName, _, _, _, _, _ in RecordList:
713 PcdsName.add((PcdCName, TokenSpaceGuid))
714 return PcdsName
715
716 ## Retrieve build options specific to this module
717 @cached_property
718 def BuildOptions(self):
719 if self._BuildOptions is None:
720 self._BuildOptions = OrderedDict()
721 RecordList = self._RawData[MODEL_META_DATA_BUILD_OPTION, self._Arch, self._Platform]
722 for Record in RecordList:
723 ToolChainFamily = Record[0]
724 ToolChain = Record[1]
725 Option = Record[2]
726 if (ToolChainFamily, ToolChain) not in self._BuildOptions or Option.startswith('='):
727 self._BuildOptions[ToolChainFamily, ToolChain] = Option
728 else:
729 # concatenate the option string if they're for the same tool
730 OptionString = self._BuildOptions[ToolChainFamily, ToolChain]
731 self._BuildOptions[ToolChainFamily, ToolChain] = OptionString + " " + Option
732 return self._BuildOptions
733
734 ## Retrieve dependency expression
735 @cached_property
736 def Depex(self):
737 RetVal = tdict(False, 2)
738
739 # If the module has only Binaries and no Sources, then ignore [Depex]
740 if not self.Sources and self.Binaries:
741 return RetVal
742
743 RecordList = self._RawData[MODEL_EFI_DEPEX, self._Arch]
744 # PEIM and DXE drivers must have a valid [Depex] section
745 if len(self.LibraryClass) == 0 and len(RecordList) == 0:
746 if self.ModuleType == SUP_MODULE_DXE_DRIVER or self.ModuleType == SUP_MODULE_PEIM or self.ModuleType == SUP_MODULE_DXE_SMM_DRIVER or \
747 self.ModuleType == SUP_MODULE_DXE_SAL_DRIVER or self.ModuleType == SUP_MODULE_DXE_RUNTIME_DRIVER:
748 EdkLogger.error('build', RESOURCE_NOT_AVAILABLE, "No [Depex] section or no valid expression in [Depex] section for [%s] module" \
749 % self.ModuleType, File=self.MetaFile)
750
751 if len(RecordList) != 0 and self.ModuleType == SUP_MODULE_USER_DEFINED:
752 for Record in RecordList:
753 if Record[4] not in [SUP_MODULE_PEIM, SUP_MODULE_DXE_DRIVER, SUP_MODULE_DXE_SMM_DRIVER]:
754 EdkLogger.error('build', FORMAT_INVALID,
755 "'%s' module must specify the type of [Depex] section" % self.ModuleType,
756 File=self.MetaFile)
757
758 TemporaryDictionary = OrderedDict()
759 for Record in RecordList:
760 DepexStr = ReplaceMacro(Record[0], self._Macros, False)
761 Arch = Record[3]
762 ModuleType = Record[4]
763 TokenList = DepexStr.split()
764 if (Arch, ModuleType) not in TemporaryDictionary:
765 TemporaryDictionary[Arch, ModuleType] = []
766 DepexList = TemporaryDictionary[Arch, ModuleType]
767 for Token in TokenList:
768 if Token in DEPEX_SUPPORTED_OPCODE_SET:
769 DepexList.append(Token)
770 elif Token.endswith(".inf"): # module file name
771 ModuleFile = os.path.normpath(Token)
772 Module = self.BuildDatabase[ModuleFile]
773 if Module is None:
774 EdkLogger.error('build', RESOURCE_NOT_AVAILABLE, "Module is not found in active platform",
775 ExtraData=Token, File=self.MetaFile, Line=Record[-1])
776 DepexList.append(Module.Guid)
777 else:
778 # it use the Fixed PCD format
779 if '.' in Token:
780 if tuple(Token.split('.')[::-1]) not in self.Pcds:
781 EdkLogger.error('build', RESOURCE_NOT_AVAILABLE, "PCD [{}] used in [Depex] section should be listed in module PCD section".format(Token), File=self.MetaFile, Line=Record[-1])
782 else:
783 if self.Pcds[tuple(Token.split('.')[::-1])].DatumType != TAB_VOID:
784 EdkLogger.error('build', FORMAT_INVALID, "PCD [{}] used in [Depex] section should be VOID* datum type".format(Token), File=self.MetaFile, Line=Record[-1])
785 Value = Token
786 else:
787 # get the GUID value now
788 Value = _ProtocolValue(Token, self.Packages, self.MetaFile.Path)
789 if Value is None:
790 Value = _PpiValue(Token, self.Packages, self.MetaFile.Path)
791 if Value is None:
792 Value = GuidValue(Token, self.Packages, self.MetaFile.Path)
793
794 if Value is None:
795 PackageList = "\n\t".join(str(P) for P in self.Packages)
796 EdkLogger.error('build', RESOURCE_NOT_AVAILABLE,
797 "Value of [%s] is not found in" % Token,
798 ExtraData=PackageList, File=self.MetaFile, Line=Record[-1])
799 DepexList.append(Value)
800 for Arch, ModuleType in TemporaryDictionary:
801 RetVal[Arch, ModuleType] = TemporaryDictionary[Arch, ModuleType]
802 return RetVal
803
804 ## Retrieve dependency expression
805 @cached_property
806 def DepexExpression(self):
807 RetVal = tdict(False, 2)
808 RecordList = self._RawData[MODEL_EFI_DEPEX, self._Arch]
809 TemporaryDictionary = OrderedDict()
810 for Record in RecordList:
811 DepexStr = ReplaceMacro(Record[0], self._Macros, False)
812 Arch = Record[3]
813 ModuleType = Record[4]
814 TokenList = DepexStr.split()
815 if (Arch, ModuleType) not in TemporaryDictionary:
816 TemporaryDictionary[Arch, ModuleType] = ''
817 for Token in TokenList:
818 TemporaryDictionary[Arch, ModuleType] = TemporaryDictionary[Arch, ModuleType] + Token.strip() + ' '
819 for Arch, ModuleType in TemporaryDictionary:
820 RetVal[Arch, ModuleType] = TemporaryDictionary[Arch, ModuleType]
821 return RetVal
822
823 @cached_class_function
824 def GetGuidsUsedByPcd(self):
825 self.Pcds
826 return self._GuidsUsedByPcd
827
828 ## Retrieve PCD for given type
829 def _GetPcd(self, Type):
830 Pcds = OrderedDict()
831 PcdDict = tdict(True, 4)
832 PcdList = []
833 RecordList = self._RawData[Type, self._Arch, self._Platform]
834 for TokenSpaceGuid, PcdCName, Setting, Arch, Platform, Id, LineNo in RecordList:
835 PcdDict[Arch, Platform, PcdCName, TokenSpaceGuid] = (Setting, LineNo)
836 PcdList.append((PcdCName, TokenSpaceGuid))
837 # get the guid value
838 if TokenSpaceGuid not in self.Guids:
839 Value = GuidValue(TokenSpaceGuid, self.Packages, self.MetaFile.Path)
840 if Value is None:
841 PackageList = "\n\t".join(str(P) for P in self.Packages)
842 EdkLogger.error('build', RESOURCE_NOT_AVAILABLE,
843 "Value of Guid [%s] is not found under [Guids] section in" % TokenSpaceGuid,
844 ExtraData=PackageList, File=self.MetaFile, Line=LineNo)
845 self.Guids[TokenSpaceGuid] = Value
846 self._GuidsUsedByPcd[TokenSpaceGuid] = Value
847 CommentRecords = self._RawData[MODEL_META_DATA_COMMENT, self._Arch, self._Platform, Id]
848 Comments = []
849 for CmtRec in CommentRecords:
850 Comments.append(CmtRec[0])
851 self._PcdComments[TokenSpaceGuid, PcdCName] = Comments
852
853 # resolve PCD type, value, datum info, etc. by getting its definition from package
854 _GuidDict = self.Guids.copy()
855 for PcdCName, TokenSpaceGuid in PcdList:
856 PcdRealName = PcdCName
857 Setting, LineNo = PcdDict[self._Arch, self.Platform, PcdCName, TokenSpaceGuid]
858 if Setting is None:
859 continue
860 ValueList = AnalyzePcdData(Setting)
861 DefaultValue = ValueList[0]
862 Pcd = PcdClassObject(
863 PcdCName,
864 TokenSpaceGuid,
865 '',
866 '',
867 DefaultValue,
868 '',
869 '',
870 {},
871 False,
872 self.Guids[TokenSpaceGuid]
873 )
874 if Type == MODEL_PCD_PATCHABLE_IN_MODULE and ValueList[1]:
875 # Patch PCD: TokenSpace.PcdCName|Value|Offset
876 Pcd.Offset = ValueList[1]
877
878 if (PcdRealName, TokenSpaceGuid) in GlobalData.MixedPcd:
879 for Package in self.Packages:
880 for key in Package.Pcds:
881 if (Package.Pcds[key].TokenCName, Package.Pcds[key].TokenSpaceGuidCName) == (PcdRealName, TokenSpaceGuid):
882 for item in GlobalData.MixedPcd[(PcdRealName, TokenSpaceGuid)]:
883 Pcd_Type = item[0].split('_')[-1]
884 if Pcd_Type == Package.Pcds[key].Type:
885 Value = Package.Pcds[key]
886 Value.TokenCName = Package.Pcds[key].TokenCName + '_' + Pcd_Type
887 if len(key) == 2:
888 newkey = (Value.TokenCName, key[1])
889 elif len(key) == 3:
890 newkey = (Value.TokenCName, key[1], key[2])
891 del Package.Pcds[key]
892 Package.Pcds[newkey] = Value
893 break
894 else:
895 pass
896 else:
897 pass
898
899 # get necessary info from package declaring this PCD
900 for Package in self.Packages:
901 #
902 # 'dynamic' in INF means its type is determined by platform;
903 # if platform doesn't give its type, use 'lowest' one in the
904 # following order, if any
905 #
906 # TAB_PCDS_FIXED_AT_BUILD, TAB_PCDS_PATCHABLE_IN_MODULE, TAB_PCDS_FEATURE_FLAG, TAB_PCDS_DYNAMIC, TAB_PCDS_DYNAMIC_EX
907 #
908 _GuidDict.update(Package.Guids)
909 PcdType = self._PCD_TYPE_STRING_[Type]
910 if Type == MODEL_PCD_DYNAMIC:
911 Pcd.Pending = True
912 for T in PCD_TYPE_LIST:
913 if (PcdRealName, TokenSpaceGuid) in GlobalData.MixedPcd:
914 for item in GlobalData.MixedPcd[(PcdRealName, TokenSpaceGuid)]:
915 if str(item[0]).endswith(T) and (item[0], item[1], T) in Package.Pcds:
916 PcdType = T
917 PcdCName = item[0]
918 break
919 else:
920 pass
921 break
922 else:
923 if (PcdRealName, TokenSpaceGuid, T) in Package.Pcds:
924 PcdType = T
925 break
926
927 else:
928 Pcd.Pending = False
929 if (PcdRealName, TokenSpaceGuid) in GlobalData.MixedPcd:
930 for item in GlobalData.MixedPcd[(PcdRealName, TokenSpaceGuid)]:
931 Pcd_Type = item[0].split('_')[-1]
932 if Pcd_Type == PcdType:
933 PcdCName = item[0]
934 break
935 else:
936 pass
937 else:
938 pass
939
940 if (PcdCName, TokenSpaceGuid, PcdType) in Package.Pcds:
941 PcdInPackage = Package.Pcds[PcdCName, TokenSpaceGuid, PcdType]
942 Pcd.Type = PcdType
943 Pcd.TokenValue = PcdInPackage.TokenValue
944
945 #
946 # Check whether the token value exist or not.
947 #
948 if Pcd.TokenValue is None or Pcd.TokenValue == "":
949 EdkLogger.error(
950 'build',
951 FORMAT_INVALID,
952 "No TokenValue for PCD [%s.%s] in [%s]!" % (TokenSpaceGuid, PcdRealName, str(Package)),
953 File=self.MetaFile, Line=LineNo,
954 ExtraData=None
955 )
956 #
957 # Check hexadecimal token value length and format.
958 #
959 ReIsValidPcdTokenValue = re.compile(r"^[0][x|X][0]*[0-9a-fA-F]{1,8}$", re.DOTALL)
960 if Pcd.TokenValue.startswith("0x") or Pcd.TokenValue.startswith("0X"):
961 if ReIsValidPcdTokenValue.match(Pcd.TokenValue) is None:
962 EdkLogger.error(
963 'build',
964 FORMAT_INVALID,
965 "The format of TokenValue [%s] of PCD [%s.%s] in [%s] is invalid:" % (Pcd.TokenValue, TokenSpaceGuid, PcdRealName, str(Package)),
966 File=self.MetaFile, Line=LineNo,
967 ExtraData=None
968 )
969
970 #
971 # Check decimal token value length and format.
972 #
973 else:
974 try:
975 TokenValueInt = int (Pcd.TokenValue, 10)
976 if (TokenValueInt < 0 or TokenValueInt > 4294967295):
977 EdkLogger.error(
978 'build',
979 FORMAT_INVALID,
980 "The format of TokenValue [%s] of PCD [%s.%s] in [%s] is invalid, as a decimal it should between: 0 - 4294967295!" % (Pcd.TokenValue, TokenSpaceGuid, PcdRealName, str(Package)),
981 File=self.MetaFile, Line=LineNo,
982 ExtraData=None
983 )
984 except:
985 EdkLogger.error(
986 'build',
987 FORMAT_INVALID,
988 "The format of TokenValue [%s] of PCD [%s.%s] in [%s] is invalid, it should be hexadecimal or decimal!" % (Pcd.TokenValue, TokenSpaceGuid, PcdRealName, str(Package)),
989 File=self.MetaFile, Line=LineNo,
990 ExtraData=None
991 )
992
993 Pcd.DatumType = PcdInPackage.DatumType
994 Pcd.MaxDatumSize = PcdInPackage.MaxDatumSize
995 Pcd.InfDefaultValue = Pcd.DefaultValue
996 if not Pcd.DefaultValue:
997 Pcd.DefaultValue = PcdInPackage.DefaultValue
998 else:
999 try:
1000 Pcd.DefaultValue = ValueExpressionEx(Pcd.DefaultValue, Pcd.DatumType, _GuidDict)(True)
1001 except BadExpression as Value:
1002 EdkLogger.error('Parser', FORMAT_INVALID, 'PCD [%s.%s] Value "%s", %s' %(TokenSpaceGuid, PcdRealName, Pcd.DefaultValue, Value),
1003 File=self.MetaFile, Line=LineNo)
1004 break
1005 else:
1006 EdkLogger.error(
1007 'build',
1008 FORMAT_INVALID,
1009 "PCD [%s.%s] in [%s] is not found in dependent packages:" % (TokenSpaceGuid, PcdRealName, self.MetaFile),
1010 File=self.MetaFile, Line=LineNo,
1011 ExtraData="\t%s" % '\n\t'.join(str(P) for P in self.Packages)
1012 )
1013 Pcds[PcdCName, TokenSpaceGuid] = Pcd
1014
1015 return Pcds
1016
1017 ## check whether current module is binary module
1018 @property
1019 def IsBinaryModule(self):
1020 if (self.Binaries and not self.Sources) or GlobalData.gIgnoreSource:
1021 return True
1022 return False