2 # Routines for generating build report.
4 # This module contains the functionality to generate build report after
5 # build all target completes successfully.
7 # Copyright (c) 2010, Intel Corporation
8 # All rights reserved. This program and the accompanying materials
9 # are licensed and made available under the terms and conditions of the BSD License
10 # which accompanies this distribution. The full text of the license may be found at
11 # http://opensource.org/licenses/bsd-license.php
13 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
23 from datetime import datetime
24 from Common import EdkLogger
25 from Common.Misc import GuidStructureByteArrayToGuidString
26 from Common.Misc import GuidStructureStringToGuidString
27 from Common.InfClassObject import gComponentType2ModuleType
28 from Common.BuildToolError import FILE_OPEN_FAILURE
29 from Common.BuildToolError import FILE_WRITE_FAILURE
30 from Eot.Eot import Eot
33 ## Pattern to extract contents in EDK DXS files
34 gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)
36 ## Pattern to find total FV total size, occupied size in flash report intermediate file
37 gFvTotalSizePattern = re.compile(r"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
38 gFvTakenSizePattern = re.compile(r"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
40 ## Pattern to find module size and time stamp in module summary report intermediate file
41 gModuleSizePattern = re.compile(r"MODULE_SIZE = (\d+)")
42 gTimeStampPattern = re.compile(r"TIME_STAMP = (\d+)")
44 ## Pattern to find GUID value in flash description files
45 gPcdGuidPattern = re.compile(r"PCD\((\w+)[.](\w+)\)")
47 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
48 gOffsetGuidPattern = re.compile(r"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
50 ## Pattern to find module base address and entry point in fixed flash map file
51 gModulePattern = r"\n\w+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
52 gMapFileItemPattern = re.compile(gModulePattern % {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
54 ## Pattern to find all module referenced header files in source files
55 gIncludePattern = re.compile(r'#include\s*["<]([^">]+)[">]')
56 gIncludePattern2 = re.compile(r"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
58 ## Pattern to find the entry point for EDK module using EDKII Glue library
59 gGlueLibEntryPoint = re.compile(r"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
61 ## Tags for section start, end and separator
62 gSectionStart = ">" + "=" * 118 + "<"
63 gSectionEnd = "<" + "=" * 118 + ">" + "\n"
64 gSectionSep = "=" * 120
66 ## Tags for subsection start, end and separator
67 gSubSectionStart = ">" + "-" * 118 + "<"
68 gSubSectionEnd = "<" + "-" * 118 + ">"
69 gSubSectionSep = "-" * 120
71 ## The look up table to map PCD type to pair of report display type and DEC type
73 'FixedAtBuild' : ('FIXED', 'FixedAtBuild'),
74 'PatchableInModule': ('PATCH', 'PatchableInModule'),
75 'FeatureFlag' : ('FLAG', 'FeatureFlag'),
76 'Dynamic' : ('DYN', 'Dynamic'),
77 'DynamicHii' : ('DYNHII', 'Dynamic'),
78 'DynamicVpd' : ('DYNVPD', 'Dynamic'),
79 'DynamicEx' : ('DEX', 'Dynamic'),
80 'DynamicExHii' : ('DEXHII', 'Dynamic'),
81 'DynamicExVpd' : ('DEXVPD', 'Dynamic'),
84 ## The look up table to map module type to driver type
86 'SEC' : '0x3 (SECURITY_CORE)',
87 'PEI_CORE' : '0x4 (PEI_CORE)',
88 'PEIM' : '0x6 (PEIM)',
89 'DXE_CORE' : '0x5 (DXE_CORE)',
90 'DXE_DRIVER' : '0x7 (DRIVER)',
91 'DXE_SAL_DRIVER' : '0x7 (DRIVER)',
92 'DXE_SMM_DRIVER' : '0x7 (DRIVER)',
93 'DXE_RUNTIME_DRIVER': '0x7 (DRIVER)',
94 'UEFI_DRIVER' : '0x7 (DRIVER)',
95 'UEFI_APPLICATION' : '0x9 (APPLICATION)',
96 'SMM_CORE' : '0xD (SMM_CORE)',
100 # Writes a string to the file object.
102 # This function writes a string to the file object and a new line is appended
103 # afterwards. It may optionally wraps the string for better readability.
105 # @File The file object to write
106 # @String The string to be written to the file
107 # @Wrapper Indicates whether to wrap the string
109 def FileWrite(File, String, Wrapper=False):
111 String = textwrap.fill(String, 120)
112 File.write(String + "\n")
115 # Find all the header file that the module source directly includes.
117 # This function scans source code to find all header files the module may
118 # include. This is not accurate but very effective to find all the header
119 # file the module might include with #include statement.
121 # @Source The source file name
122 # @IncludePathList The list of include path to find the source file.
123 # @IncludeFiles The dictionary of current found include files.
125 def FindIncludeFiles(Source, IncludePathList, IncludeFiles):
126 FileContents = open(Source).read()
128 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
130 for Match in gIncludePattern.finditer(FileContents):
131 FileName = Match.group(1).strip()
132 for Dir in [os.path.dirname(Source)] + IncludePathList:
133 FullFileName = os.path.normpath(os.path.join(Dir, FileName))
134 if os.path.exists(FullFileName):
135 IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName
139 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
141 for Match in gIncludePattern2.finditer(FileContents):
143 Type = Match.group(1)
144 if "ARCH_PROTOCOL" in Type:
145 FileName = "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key}
146 elif "PROTOCOL" in Type:
147 FileName = "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key}
149 FileName = "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key}
151 FileName = "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key}
154 for Dir in IncludePathList:
155 FullFileName = os.path.normpath(os.path.join(Dir, FileName))
156 if os.path.exists(FullFileName):
157 IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName
161 # Reports library information
163 # This class reports the module library subsection in the build report file.
165 class LibraryReport(object):
167 # Constructor function for class LibraryReport
169 # This constructor function generates LibraryReport object for
172 # @param self The object pointer
173 # @param M Module context information
175 def __init__(self, M):
176 self.LibraryList = []
177 if int(str(M.AutoGenVersion), 0) >= 0x00010005:
178 self._EdkIIModule = True
180 self._EdkIIModule = False
182 for Lib in M.DependentLibraryList:
183 LibInfPath = str(Lib)
184 LibClassList = Lib.LibraryClass[0].LibraryClass
185 LibConstructorList = Lib.ConstructorList
186 LibDesstructorList = Lib.DestructorList
187 LibDepexList = Lib.DepexExpression[M.Arch, M.ModuleType]
188 self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList))
191 # Generate report for module library information
193 # This function generates report for the module library.
194 # If the module is EDKII style one, the additional library class, library
195 # constructor/destructor and dependency expression may also be reported.
197 # @param self The object pointer
198 # @param File The file object for report
200 def GenerateReport(self, File):
201 FileWrite(File, gSubSectionStart)
202 FileWrite(File, "Library")
203 if len(self.LibraryList) > 0:
204 FileWrite(File, gSubSectionSep)
205 for LibraryItem in self.LibraryList:
206 LibInfPath = LibraryItem[0]
207 FileWrite(File, LibInfPath)
210 # Report library class, library constructor and destructor for
211 # EDKII style module.
213 if self._EdkIIModule:
214 LibClass = LibraryItem[1]
216 LibConstructor = " ".join(LibraryItem[2])
218 EdkIILibInfo += " C = " + LibConstructor
219 LibDestructor = " ".join(LibraryItem[3])
221 EdkIILibInfo += " D = " + LibConstructor
222 LibDepex = " ".join(LibraryItem[3])
224 EdkIILibInfo += " Depex = " + LibDepex
226 FileWrite(File, "{%s: %s}" % (LibClass, EdkIILibInfo))
228 FileWrite(File, "{%s}" % LibClass)
230 FileWrite(File, gSubSectionEnd)
233 # Reports dependency expression information
235 # This class reports the module dependency expression subsection in the build report file.
237 class DepexReport(object):
239 # Constructor function for class DepexReport
241 # This constructor function generates DepexReport object for
242 # a module. If the module source contains the DXS file (usually EDK
243 # style module), it uses the dependency in DXS file; otherwise,
244 # it uses the dependency expression from its own INF [Depex] section
245 # and then merges with the ones from its dependent library INF.
247 # @param self The object pointer
248 # @param M Module context information
250 def __init__(self, M):
251 for Source in M.SourceFileList:
252 if os.path.splitext(Source.Path)[1].lower() == ".dxs":
253 Match = gDxsDependencyPattern.search(open(Source.Path).read())
255 self.Depex = Match.group(1).strip()
259 self.Depex = M.DepexExpressionList[M.ModuleType]
260 self.ModuleDepex = " ".join(M.Module.DepexExpression[M.Arch, M.ModuleType])
261 if not self.ModuleDepex:
262 self.ModuleDepex = "TRUE"
265 for Lib in M.DependentLibraryList:
266 LibDepex = " ".join(Lib.DepexExpression[M.Arch, M.ModuleType]).strip()
269 LibDepex = "(" + LibDepex + ")"
270 LibDepexList.append(LibDepex)
271 self.LibraryDepex = " AND ".join(LibDepexList)
272 if not self.LibraryDepex:
273 self.LibraryDepex = "(None)"
277 # Generate report for module dependency expression information
279 # This function generates report for the module dependency expression.
281 # @param self The object pointer
282 # @param File The file object for report
284 def GenerateReport(self, File):
285 FileWrite(File, gSubSectionStart)
286 FileWrite(File, "Dependency Expression (DEPEX) from %s" % self.Source)
288 if self.Source == "INF":
289 FileWrite(File, "%s" % self.Depex, True)
290 FileWrite(File, gSubSectionSep)
291 FileWrite(File, "From Module INF: %s" % self.ModuleDepex, True)
292 FileWrite(File, "From Library INF: %s" % self.LibraryDepex, True)
294 FileWrite(File, "%s" % self.Depex)
295 FileWrite(File, gSubSectionEnd)
298 # Reports dependency expression information
300 # This class reports the module build flags subsection in the build report file.
302 class BuildFlagsReport(object):
304 # Constructor function for class BuildFlagsReport
306 # This constructor function generates BuildFlagsReport object for
307 # a module. It reports the build tool chain tag and all relevant
308 # build flags to build the module.
310 # @param self The object pointer
311 # @param M Module context information
313 def __init__(self, M):
316 # Add build flags according to source file extension so that
317 # irrelevant ones can be filtered out.
319 for Source in M.SourceFileList:
320 Ext = os.path.splitext(Source.File)[1].lower()
321 if Ext in [".c", ".cc", ".cpp"]:
322 BuildOptions["CC"] = 1
323 elif Ext in [".s", ".asm"]:
324 BuildOptions["PP"] = 1
325 BuildOptions["ASM"] = 1
326 elif Ext in [".vfr"]:
327 BuildOptions["VFRPP"] = 1
328 BuildOptions["VFR"] = 1
329 elif Ext in [".dxs"]:
330 BuildOptions["APP"] = 1
331 BuildOptions["CC"] = 1
332 elif Ext in [".asl"]:
333 BuildOptions["ASLPP"] = 1
334 BuildOptions["ASL"] = 1
335 elif Ext in [".aslc"]:
336 BuildOptions["ASLCC"] = 1
337 BuildOptions["ASLDLINK"] = 1
338 BuildOptions["CC"] = 1
339 elif Ext in [".asm16"]:
340 BuildOptions["ASMLINK"] = 1
341 BuildOptions["SLINK"] = 1
342 BuildOptions["DLINK"] = 1
345 # Save module build flags.
347 self.ToolChainTag = M.ToolChain
349 for Tool in BuildOptions:
350 self.BuildFlags[Tool + "_FLAGS"] = M.BuildOption.get(Tool, {}).get("FLAGS", "")
353 # Generate report for module build flags information
355 # This function generates report for the module build flags expression.
357 # @param self The object pointer
358 # @param File The file object for report
360 def GenerateReport(self, File):
361 FileWrite(File, gSubSectionStart)
362 FileWrite(File, "Build Flags")
363 FileWrite(File, "Tool Chain Tag: %s" % self.ToolChainTag)
364 for Tool in self.BuildFlags:
365 FileWrite(File, gSubSectionSep)
366 FileWrite(File, "%s = %s" % (Tool, self.BuildFlags[Tool]), True)
368 FileWrite(File, gSubSectionEnd)
372 # Reports individual module information
374 # This class reports the module section in the build report file.
375 # It comprises of module summary, module PCD, library, dependency expression,
376 # build flags sections.
378 class ModuleReport(object):
380 # Constructor function for class ModuleReport
382 # This constructor function generates ModuleReport object for
383 # a separate module in a platform build.
385 # @param self The object pointer
386 # @param M Module context information
387 # @param DscOverridePcds Module DSC override PCD information
388 # @param ReportType The kind of report items in the final report file
390 def __init__(self, M, DscOverridePcds, ReportType):
391 self.ModuleName = M.Module.BaseName
392 self.ModuleInfPath = M.MetaFile.File
393 self.FileGuid = M.Guid
395 self.BuildTimeStamp = None
397 ModuleType = M.ModuleType
399 ModuleType = gComponentType2ModuleType.get(M.ComponentType, "")
400 self.DriverType = gDriverTypeMap.get(ModuleType, "")
401 self.UefiSpecVersion = M.Module.Specification.get("UEFI_SPECIFICATION_VERSION", "")
402 self.PiSpecVersion = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "")
403 self.PciDeviceId = M.Module.Defines.get("PCI_DEVICE_ID", "")
404 self.PciVendorId = M.Module.Defines.get("PCI_VENDOR_ID", "")
405 self.PciClassCode = M.Module.Defines.get("PCI_CLASS_CODE", "")
407 self._BuildDir = M.BuildDir
408 self.ModulePcdSet = {}
409 self.ModuleDscOverridePcds = {}
410 if "PCD" in ReportType:
412 # Collect all module used PCD set: module INF referenced directly or indirectly.
413 # It also saves module INF default values of them in case they exist.
415 for Pcd in M.ModulePcdList + M.LibraryPcdList:
416 self.ModulePcdSet.setdefault((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Type), Pcd.InfDefaultValue)
419 # Collect module DSC override PCD set for report
421 for (PcdTokenCName, PcdTokenSpaceGuidCName) in DscOverridePcds:
422 Pcd = DscOverridePcds[(PcdTokenCName, PcdTokenSpaceGuidCName)]
423 self.ModuleDscOverridePcds.setdefault((PcdTokenCName, PcdTokenSpaceGuidCName), Pcd.DefaultValue)
425 self.LibraryReport = None
426 if "LIBRARY" in ReportType:
427 self.LibraryReport = LibraryReport(M)
429 self.DepexReport = None
430 if "DEPEX" in ReportType:
431 self.DepexReport = DepexReport(M)
433 if "BUILD_FLAGS" in ReportType:
434 self.BuildFlagsReport = BuildFlagsReport(M)
438 # Generate report for module information
440 # This function generates report for separate module expression
441 # in a platform build.
443 # @param self The object pointer
444 # @param File The file object for report
445 # @param GlobalPcdReport The platform global PCD class object
446 # @param ReportType The kind of report items in the final report file
448 def GenerateReport(self, File, GlobalPcdReport, GlobalPredictionReport, ReportType):
449 FileWrite(File, gSectionStart)
451 FwReportFileName = os.path.join(self._BuildDir, "DEBUG", self.ModuleName + ".txt")
452 if os.path.isfile(FwReportFileName):
454 FileContents = open(FwReportFileName).read()
455 Match = gModuleSizePattern.search(FileContents)
457 self.Size = int(Match.group(1))
459 Match = gTimeStampPattern.search(FileContents)
461 self.BuildTimeStamp = datetime.utcfromtimestamp(int(Match.group(1)))
463 EdkLogger.warn(None, "Fail to read report file", FwReportFileName)
465 FileWrite(File, "Module Summary")
466 FileWrite(File, "Module Name: %s" % self.ModuleName)
467 FileWrite(File, "Module INF Path: %s" % self.ModuleInfPath)
468 FileWrite(File, "File GUID: %s" % self.FileGuid)
470 FileWrite(File, "Size: 0x%X (%.2fK)" % (self.Size, self.Size / 1024.0))
471 if self.BuildTimeStamp:
472 FileWrite(File, "Build Time Stamp: %s" % self.BuildTimeStamp)
474 FileWrite(File, "Driver Type: %s" % self.DriverType)
475 if self.UefiSpecVersion:
476 FileWrite(File, "UEFI Spec Version: %s" % self.DriverType)
477 if self.PiSpecVersion:
478 FileWrite(File, "PI Spec Version: %s" % self.PiSpecVersion)
480 FileWrite(File, "PCI Device ID: %s" % self.PciDeviceId)
482 FileWrite(File, "PCI Vendor ID: %s" % self.PciVendorId)
483 if self.PciClassCode:
484 FileWrite(File, "PCI Class Code: %s" % self.PciClassCode)
486 FileWrite(File, gSectionSep)
488 if "PCD" in ReportType:
489 GlobalPcdReport.GenerateReport(File, self.ModulePcdSet, self.ModuleDscOverridePcds)
491 if "LIBRARY" in ReportType:
492 self.LibraryReport.GenerateReport(File)
494 if "DEPEX" in ReportType:
495 self.DepexReport.GenerateReport(File)
497 if "BUILD_FLAGS" in ReportType:
498 self.BuildFlagsReport.GenerateReport(File)
500 if "PREDICTION" in ReportType:
501 GlobalPredictionReport.GenerateReport(File, self.FileGuid)
503 FileWrite(File, gSectionEnd)
506 # Reports platform and module PCD information
508 # This class reports the platform PCD section and module PCD subsection
509 # in the build report file.
511 class PcdReport(object):
513 # Constructor function for class PcdReport
515 # This constructor function generates PcdReport object a platform build.
516 # It collects the whole PCD database from platform DSC files, platform
517 # flash description file and package DEC files.
519 # @param self The object pointer
520 # @param Wa Workspace context information
522 def __init__(self, Wa):
526 self.FdfPcdSet = Wa.FdfProfile.PcdDict
530 self.DecPcdDefault = {}
531 self.ModulePcdOverride = {}
532 for Pa in Wa.AutoGenObjectList:
534 # Collect all platform referenced PCDs and grouped them by PCD token space
537 for Pcd in Pa.AllPcdList:
538 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
539 if Pcd not in PcdList:
541 if len(Pcd.TokenCName) > self.MaxLen:
542 self.MaxLen = len(Pcd.TokenCName)
544 for ModuleKey in Pa.Platform.Modules:
546 # Collect PCD DEC default value.
548 Module = Pa.Platform.Modules[ModuleKey]
549 for Package in Module.M.Module.Packages:
550 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:
551 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue
552 self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue)
554 # Collect module override PCDs
556 for ModulePcd in Module.M.ModulePcdList + Module.M.LibraryPcdList:
557 TokenCName = ModulePcd.TokenCName
558 TokenSpaceGuid = ModulePcd.TokenSpaceGuidCName
559 ModuleDefault = ModulePcd.DefaultValue
560 ModulePath = os.path.basename(Module.M.MetaFile.File)
561 self.ModulePcdOverride.setdefault((TokenCName, TokenSpaceGuid), []).append((ModuleDefault, ModulePath))
564 # Collect PCDs defined in DSC common section
566 self.DscPcdDefault = {}
567 for Platform in Wa.BuildDatabase.WorkspaceDb.PlatformList:
568 for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds:
569 DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue
570 self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue
573 # Generate report for PCD information
575 # This function generates report for separate module expression
576 # in a platform build.
578 # @param self The object pointer
579 # @param File The file object for report
580 # @param ModulePcdSet Set of all PCDs referenced by module or None for
581 # platform PCD report
582 # @param DscOverridePcds Module DSC override PCDs set
584 def GenerateReport(self, File, ModulePcdSet, DscOverridePcds):
585 if ModulePcdSet == None:
587 # For platform global PCD section
589 FileWrite(File, gSectionStart)
590 FileWrite(File, "Platform Configuration Database Report")
591 FileWrite(File, " *P - Platform scoped PCD override in DSC file")
592 FileWrite(File, " *F - Platform scoped PCD override in FDF file")
593 FileWrite(File, " *M - Module scoped PCD override in DSC file")
594 FileWrite(File, gSectionSep)
597 # For module PCD sub-section
599 FileWrite(File, gSubSectionStart)
600 FileWrite(File, "PCD")
601 FileWrite(File, gSubSectionSep)
603 for Key in self.AllPcds:
605 # Group PCD by their token space GUID C Name
608 for Type in self.AllPcds[Key]:
610 # Group PCD by their usage type
612 TypeName, DecType = gPcdTypeMap.get(Type, ("", Type))
613 for Pcd in self.AllPcds[Key][Type]:
615 # Get PCD default value and their override relationship
617 InfDefaultValue = None
618 if ModulePcdSet != None:
619 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type) not in ModulePcdSet:
621 InfDefault = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]
625 if ModulePcdSet == None:
629 DecDefaultValue = self.DecPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, DecType))
630 DscDefaultValue = self.DscPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))
631 DscModuleOverrideValue = DscOverridePcds.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))
633 if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
634 PcdDefaultValueNumber = int(Pcd.DefaultValue.strip(), 0)
635 if DecDefaultValue == None:
638 DecDefaultValueNumber = int(DecDefaultValue.strip(), 0)
639 DecMatch = (DecDefaultValueNumber == PcdDefaultValueNumber)
641 if InfDefaultValue == None:
644 InfDefaultValueNumber = int(InfDefaultValue.strip(), 0)
645 InfMatch = (InfDefaultValueNumber == PcdDefaultValueNumber)
647 if DscDefaultValue == None:
650 DscDefaultValueNumber = int(DscDefaultValue.strip(), 0)
651 DscMatch = (DscDefaultValueNumber == PcdDefaultValueNumber)
653 if DecDefaultValue == None:
656 DecMatch = (DecDefaultValue == Pcd.DefaultValue)
658 if InfDefaultValue == None:
661 InfMatch = (InfDefaultValue == Pcd.DefaultValue)
663 if DscDefaultValue == None:
666 DscMatch = (DscDefaultValue == Pcd.DefaultValue)
669 # Report PCD item according to their override relationship
671 if DecMatch and InfMatch:
672 FileWrite(File, ' %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', Pcd.DefaultValue))
674 if DscMatch and DscModuleOverrideValue == None:
675 if (Pcd.TokenCName, Key) in self.FdfPcdSet:
676 FileWrite(File, ' *F %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', Pcd.DefaultValue))
678 FileWrite(File, ' *P %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', Pcd.DefaultValue))
680 FileWrite(File, ' *M %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', Pcd.DefaultValue))
681 if DscDefaultValue != None:
682 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', DscDefaultValue))
684 if InfDefaultValue != None:
685 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', InfDefaultValue))
687 if DecDefaultValue != None and not DecMatch:
688 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', DecDefaultValue))
690 if ModulePcdSet == None:
691 for (ModuleDefault, ModulePath) in self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), []):
692 if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
693 ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0)
694 Match = (ModulePcdDefaultValueNumber == PcdDefaultValueNumber)
696 Match = (ModuleDefault == Pcd.DefaultValue)
699 FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 19, ModulePath, ModuleDefault))
701 if ModulePcdSet == None:
702 FileWrite(File, gSectionEnd)
704 FileWrite(File, gSubSectionEnd)
709 # Reports platform and module Prediction information
711 # This class reports the platform execution order prediction section and
712 # module load fixed address prediction subsection in the build report file.
714 class PredictionReport(object):
716 # Constructor function for class PredictionReport
718 # This constructor function generates PredictionReport object for the platform.
720 # @param self: The object pointer
721 # @param Wa Workspace context information
723 def __init__(self, Wa):
724 self._MapFileName = os.path.join(Wa.BuildDir, Wa.Name + ".map")
725 self._MapFileParsed = False
726 self._EotToolInvoked = False
727 self._FvDir = Wa.FvDir
729 self.FixedMapDict = {}
733 self._SourceFileList = os.path.join(Wa.BuildDir, Wa.Name + "_SourceFileList.txt")
734 SourceList = open(self._SourceFileList, "w+")
736 self._FfsEntryPoint = {}
739 # Collect all platform reference source files and write to the an intermediate file
740 # for EOT tool to parse.
743 for Pa in Wa.AutoGenObjectList:
744 for Module in Pa.LibraryAutoGenList + Pa.ModuleAutoGenList:
746 # Add module referenced source files
748 SourceList.write(str(Module) + "\n")
750 for Source in Module.SourceFileList:
751 if os.path.splitext(str(Source))[1].lower() == ".c":
752 SourceList.write(" " + str(Source) + "\n")
753 FindIncludeFiles(Source.Path, Module.IncludePathList, IncludeList)
754 for IncludeFile in IncludeList.values():
755 SourceList.write(" " + IncludeFile + "\n")
757 for Guid in Module.PpiList:
758 GuidMap[Guid] = GuidStructureStringToGuidString(Module.PpiList[Guid])
759 for Guid in Module.ProtocolList:
760 GuidMap[Guid] = GuidStructureStringToGuidString(Module.ProtocolList[Guid])
761 for Guid in Module.GuidList:
762 GuidMap[Guid] = GuidStructureStringToGuidString(Module.GuidList[Guid])
764 if Module.Guid and not Module.IsLibrary:
765 EntryPoint = " ".join(Module.Module.ModuleEntryPointList)
766 if int(str(Module.AutoGenVersion), 0) >= 0x00010005:
767 RealEntryPoint = "_ModuleEntryPoint"
769 RealEntryPoint = EntryPoint
770 if EntryPoint == "_ModuleEntryPoint":
771 CCFlags = Module.BuildOption.get("CC", {}).get("FLAGS", "")
772 Match = gGlueLibEntryPoint.search(CCFlags)
774 EntryPoint = Match.group(1)
776 self._FfsEntryPoint[Module.Guid.upper()] = (EntryPoint, RealEntryPoint)
781 # Write platform referenced GUID list as the input of EOT tool
782 # to calculate module dependency GUID
784 self._GuidList = os.path.join(Wa.BuildDir, Wa.Name + "_GuidList.txt")
785 GuidList = open(self._GuidList, "w+")
787 GuidList.write("%s %s\n" % (Guid, GuidMap[Guid]))
791 # Collect platform firmware volume list as the input of EOT.
794 for Fd in Wa.FdfProfile.FdDict:
795 for FdRegion in Wa.FdfProfile.FdDict[Fd].RegionList:
796 if FdRegion.RegionType != "FV":
798 for FvName in FdRegion.RegionDataList:
799 if FvName in self._FvList:
801 self._FvList.append(FvName)
802 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
803 for Section in Ffs.SectionList:
805 for FvSection in Section.SectionList:
806 if FvSection.FvName in self._FvList:
808 self._FvList.append(FvSection.FvName)
809 except AttributeError:
813 self._Dispatch = os.path.join(Wa.BuildDir, Wa.Name + "_Dispatch.log")
816 # Parse platform fixed address map files
818 # This function parses the platform final fixed address map file to get
819 # the database of predicted fixed address for module image base, entry point
822 # @param self: The object pointer
824 def _ParseMapFile(self):
825 if self._MapFileParsed:
827 self._MapFileParsed = True
828 if os.path.isfile(self._MapFileName):
830 FileContents = open(self._MapFileName).read()
831 for Match in gMapFileItemPattern.finditer(FileContents):
832 AddressType = Match.group(1)
833 BaseAddress = Match.group(2)
834 EntryPoint = Match.group(3)
835 Guid = Match.group(4).upper()
836 List = self.FixedMapDict.setdefault(Guid, [])
837 List.append((AddressType, BaseAddress, "*I"))
838 List.append((AddressType, EntryPoint, "*E"))
840 EdkLogger.warn(None, "Cannot open file to read", self._MapFileName)
843 # Invokes EOT tool to get the predicted the execution order.
845 # This function invokes EOT tool to calculate the predicted dispatch order
847 # @param self: The object pointer
849 def _InvokeEotTool(self):
850 if self._EotToolInvoked:
853 self._EotToolInvoked = True
855 for FvName in self._FvList:
856 FvFile = os.path.join(self._FvDir, FvName + ".Fv")
857 if os.path.isfile(FvFile):
858 FvFileList.append(FvFile)
863 Eot(CommandLineOption=False, SourceFileList=self._SourceFileList, GuidList=self._GuidList,
864 FvFileList=' '.join(FvFileList), Dispatch=self._Dispatch, IsInit=True)
867 # Parse the output of EOT tool
869 for Line in open(self._Dispatch):
870 (Guid, Phase, FfsName, FilePath) = Line.split()
871 Symbol = self._FfsEntryPoint.get(Guid, [FfsName, ""])[0]
872 if len(Symbol) > self.MaxLen:
873 self.MaxLen = len(Symbol)
874 self.ItemList.append((Phase, Symbol, FilePath))
877 # Generate platform execution order report
879 # This function generates the predicted module execution order.
881 # @param self The object pointer
882 # @param File The file object for report
884 def _GenerateExecutionOrderReport(self, File):
885 FileWrite(File, gSectionStart)
886 FileWrite(File, "Execution Order Prediction")
887 FileWrite(File, "*P PEI phase")
888 FileWrite(File, "*D DXE phase")
889 FileWrite(File, "*E Module INF entry point name")
890 FileWrite(File, "*N Module notification function name")
892 FileWrite(File, "Type %-*s %s" % (self.MaxLen, "Symbol", "Module INF Path"))
893 FileWrite(File, gSectionSep)
894 for Item in self.ItemList:
895 FileWrite(File, "*%sE %-*s %s" % (Item[0], self.MaxLen, Item[1], Item[2]))
897 FileWrite(File, gSectionStart)
900 # Generate Fixed Address report.
902 # This function generate the predicted fixed address report for a module
905 # @param self The object pointer
906 # @param File The file object for report
907 # @param Guid The module Guid value.
908 # @param NotifyList The list of all notify function in a module
910 def _GenerateFixedAddressReport(self, File, Guid, NotifyList):
911 FixedAddressList = self.FixedMapDict.get(Guid)
912 if not FixedAddressList:
915 FileWrite(File, gSubSectionStart)
916 FileWrite(File, "Fixed Address Prediction")
917 FileWrite(File, "*I Image Loading Address")
918 FileWrite(File, "*E Entry Point Address")
919 FileWrite(File, "*N Notification Function Address")
920 FileWrite(File, "*F Flash Address")
921 FileWrite(File, "*M Memory Address")
922 FileWrite(File, "*S SMM RAM Address")
923 FileWrite(File, "TOM Top of Memory")
925 FileWrite(File, "Type Address Name")
926 FileWrite(File, gSubSectionSep)
927 for Item in FixedAddressList:
932 Name = "(Image Base)"
934 Name = self._FfsEntryPoint.get(Guid, ["", "_ModuleEntryPoint"])[1]
935 elif Symbol in NotifyList:
943 elif "Memory" in Type:
949 Value = "TOM" + Value
951 FileWrite(File, "%s %-16s %s" % (Symbol, Value, Name))
954 # Generate report for the prediction part
956 # This function generate the predicted fixed address report for a module or
957 # predicted module execution order for a platform.
958 # If the input Guid is None, then, it generates the predicted module execution order;
959 # otherwise it generated the module fixed loading address for the module specified by
962 # @param self The object pointer
963 # @param File The file object for report
964 # @param Guid The module Guid value.
966 def GenerateReport(self, File, Guid):
968 self._InvokeEotTool()
970 self._GenerateFixedAddressReport(File, Guid.upper(), [])
972 self._GenerateExecutionOrderReport(File)
975 # Reports FD region information
977 # This class reports the FD subsection in the build report file.
978 # It collects region information of platform flash device.
979 # If the region is a firmware volume, it lists the set of modules
980 # and its space information; otherwise, it only lists its region name,
981 # base address and size in its sub-section header.
982 # If there are nesting FVs, the nested FVs will list immediate after
983 # this FD region subsection
985 class FdRegionReport(object):
987 # Discover all the nested FV name list.
989 # This is an internal worker function to discover the all the nested FV information
990 # in the parent firmware volume. It uses deep first search algorithm recursively to
991 # find all the FV list name and append them to the list.
993 # @param self The object pointer
994 # @param FvName The name of current firmware file system
995 # @param Wa Workspace context information
997 def _DiscoverNestedFvList(self, FvName, Wa):
998 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
999 for Section in Ffs.SectionList:
1001 for FvSection in Section.SectionList:
1002 if FvSection.FvName in self.FvList:
1004 self._GuidsDb[Ffs.NameGuid.upper()] = FvSection.FvName
1005 self.FvList.append(FvSection.FvName)
1006 self.FvInfo[FvSection.FvName] = ("Nested FV", 0, 0)
1007 self._DiscoverNestedFvList(FvSection.FvName, Wa)
1008 except AttributeError:
1012 # Constructor function for class FdRegionReport
1014 # This constructor function generates FdRegionReport object for a specified FdRegion.
1015 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1016 # volume list. This function also collects GUID map in order to dump module identification
1017 # in the final report.
1019 # @param self: The object pointer
1020 # @param FdRegion The current FdRegion object
1021 # @param Wa Workspace context information
1023 def __init__(self, FdRegion, Wa):
1024 self.Type = FdRegion.RegionType
1025 self.BaseAddress = FdRegion.Offset
1026 self.Size = FdRegion.Size
1030 self._FvDir = Wa.FvDir
1033 # If the input FdRegion is not a firmware volume,
1036 if self.Type != "FV":
1040 # Find all nested FVs in the FdRegion
1042 for FvName in FdRegion.RegionDataList:
1043 if FvName in self.FvList:
1045 self.FvList.append(FvName)
1046 self.FvInfo[FvName] = ("Fd Region", self.BaseAddress, self.Size)
1047 self._DiscoverNestedFvList(FvName, Wa)
1050 for Pa in Wa.AutoGenObjectList:
1052 for ModuleKey in Pa.Platform.Modules:
1054 # Collect PCD DEC default value.
1056 Module = Pa.Platform.Modules[ModuleKey]
1057 for Package in Module.M.Module.Packages:
1058 if Package not in PackageList:
1059 PackageList.append(Package)
1061 for Package in PackageList:
1062 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:
1063 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue
1064 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue
1067 # Collect PCDs defined in DSC common section
1069 for Platform in Wa.BuildDatabase.WorkspaceDb.PlatformList:
1070 for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds:
1071 DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue
1072 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue
1075 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1077 self._GuidsDb["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"
1078 self._GuidsDb["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"
1080 # Add ACPI table storage file
1082 self._GuidsDb["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1084 # Collect the GUID map in the FV firmware volume
1086 for FvName in self.FvList:
1087 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
1090 # Collect GUID, module mapping from INF file
1092 InfFileName = Ffs.InfFileName
1096 InfPath = os.path.join(Wa.WorkspaceDir, InfFileName)
1097 for Line in open(InfPath):
1098 ItemList = Line.split("#")[0].split("=")
1099 if len(ItemList) == 2:
1100 Key = ItemList[0].strip().upper()
1101 Value = ItemList[1].strip()
1102 if Key == "FILE_GUID":
1103 FileGuid = Value.upper()
1104 if Key == "BASE_NAME":
1107 self._GuidsDb[FileGuid] = "%s (%s)" % (ModuleName, InfPath)
1109 EdkLogger.warn(None, "Cannot open file to read", InfPath)
1110 except AttributeError:
1113 # collect GUID map for binary EFI file in FDF file.
1115 Guid = Ffs.NameGuid.upper()
1116 Match = gPcdGuidPattern.match(Ffs.NameGuid)
1118 PcdTokenspace = Match.group(1)
1119 PcdToken = Match.group(2)
1120 if (PcdToken, PcdTokenspace) in PlatformPcds:
1121 GuidValue = PlatformPcds[(PcdToken, PcdTokenspace)]
1122 Guid = GuidStructureByteArrayToGuidString(GuidValue).upper()
1124 for Section in Ffs.SectionList:
1126 ModuleSectFile = os.path.join(Wa.WorkspaceDir, Section.SectFileName)
1127 self._GuidsDb[Guid] = ModuleSectFile
1128 except AttributeError:
1130 except AttributeError:
1135 # Internal worker function to generate report for the FD region
1137 # This internal worker function to generate report for the FD region.
1138 # It the type is firmware volume, it lists offset and module identification.
1140 # @param self The object pointer
1141 # @param File The file object for report
1142 # @param Title The title for the FD subsection
1143 # @param BaseAddress The base address for the FD region
1144 # @param Size The size of the FD region
1145 # @param FvName The FV name if the FD region is a firmware volume
1147 def _GenerateReport(self, File, Title, Type, BaseAddress, Size=0, FvName=None):
1148 FileWrite(File, gSubSectionStart)
1149 FileWrite(File, Title)
1150 FileWrite(File, "Type: %s" % Type)
1151 FileWrite(File, "Base Address: 0x%X" % BaseAddress)
1153 if self.Type == "FV":
1157 FvReportFileName = os.path.join(self._FvDir, FvName + ".fv.txt")
1160 # Collect size info in the firmware volume.
1162 FvReport = open(FvReportFileName).read()
1163 Match = gFvTotalSizePattern.search(FvReport)
1165 FvTotalSize = int(Match.group(1), 16)
1166 Match = gFvTakenSizePattern.search(FvReport)
1168 FvTakenSize = int(Match.group(1), 16)
1169 FvFreeSize = FvTotalSize - FvTakenSize
1171 # Write size information to the report file.
1173 FileWrite(File, "Size: 0x%X (%.0fK)" % (FvTotalSize, FvTotalSize / 1024.0))
1174 FileWrite(File, "Fv Name: %s (%.1f%% Full)" % (FvName, FvTakenSize * 100.0 / FvTotalSize))
1175 FileWrite(File, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize, FvTakenSize / 1024.0))
1176 FileWrite(File, "Free Size: 0x%X (%.0fK)" % (FvFreeSize, FvFreeSize / 1024.0))
1177 FileWrite(File, "Offset Module")
1178 FileWrite(File, gSubSectionSep)
1180 # Write module offset and module identification to the report file.
1182 for Match in gOffsetGuidPattern.finditer(FvReport):
1183 Guid = Match.group(2).upper()
1184 Offset = int(Match.group(1), 16)
1185 FileWrite (File, "0x%07X %s" % (Offset, self._GuidsDb.get(Guid, Guid)))
1187 EdkLogger.warn(None, "Fail to read report file", FvReportFileName)
1189 FileWrite(File, "Size: 0x%X (%.0fK)" % (Size, Size / 1024.0))
1190 FileWrite(File, gSubSectionEnd)
1193 # Generate report for the FD region
1195 # This function generates report for the FD region.
1197 # @param self The object pointer
1198 # @param File The file object for report
1200 def GenerateReport(self, File):
1201 if (len(self.FvList) > 0):
1202 for FvItem in self.FvList:
1203 Info = self.FvInfo[FvItem]
1204 self._GenerateReport(File, Info[0], "FV", Info[1], Info[2], FvItem)
1206 self._GenerateReport(File, "FD Region", self.Type, self.BaseAddress, self.Size)
1209 # Reports FD information
1211 # This class reports the FD section in the build report file.
1212 # It collects flash device information for a platform.
1214 class FdReport(object):
1216 # Constructor function for class FdReport
1218 # This constructor function generates FdReport object for a specified
1221 # @param self The object pointer
1222 # @param Fd The current Firmware device object
1223 # @param Wa Workspace context information
1225 def __init__(self, Fd, Wa):
1226 self.FdName = Fd.FdUiName
1227 self.BaseAddress = Fd.BaseAddress
1229 self.FdRegionList = [FdRegionReport(FdRegion, Wa) for FdRegion in Fd.RegionList]
1232 # Generate report for the firmware device.
1234 # This function generates report for the firmware device.
1236 # @param self The object pointer
1237 # @param File The file object for report
1239 def GenerateReport(self, File):
1240 FileWrite(File, gSectionStart)
1241 FileWrite(File, "Firmware Device (FD)")
1242 FileWrite(File, "FD Name: %s" % self.FdName)
1243 FileWrite(File, "Base Address: 0x%s" % self.BaseAddress)
1244 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.Size, self.Size / 1024.0))
1245 if len(self.FdRegionList) > 0:
1246 FileWrite(File, gSectionSep)
1247 for FdRegionItem in self.FdRegionList:
1248 FdRegionItem.GenerateReport(File)
1250 FileWrite(File, gSectionEnd)
1255 # Reports platform information
1257 # This class reports the whole platform information
1259 class PlatformReport(object):
1261 # Constructor function for class PlatformReport
1263 # This constructor function generates PlatformReport object a platform build.
1264 # It generates report for platform summary, flash, global PCDs and detailed
1265 # module information for modules involved in platform build.
1267 # @param self The object pointer
1268 # @param Wa Workspace context information
1270 def __init__(self, Wa, ReportType):
1271 self._WorkspaceDir = Wa.WorkspaceDir
1272 self.PlatformName = Wa.Name
1273 self.PlatformDscPath = Wa.Platform
1274 self.Architectures = " ".join(Wa.ArchList)
1275 self.ToolChain = Wa.ToolChain
1276 self.Target = Wa.BuildTarget
1277 self.OutputPath = os.path.join(Wa.WorkspaceDir, Wa.OutputDir)
1278 self.BuildEnvironment = platform.platform()
1280 self.PcdReport = None
1281 if "PCD" in ReportType:
1282 self.PcdReport = PcdReport(Wa)
1284 self.FdReportList = []
1285 if "FLASH" in ReportType and Wa.FdfProfile:
1286 for Fd in Wa.FdfProfile.FdDict:
1287 self.FdReportList.append(FdReport(Wa.FdfProfile.FdDict[Fd], Wa))
1289 self.PredictionReport = None
1290 if "PREDICTION" in ReportType:
1291 self.PredictionReport = PredictionReport(Wa)
1293 self.ModuleReportList = []
1294 for Pa in Wa.AutoGenObjectList:
1295 for ModuleKey in Pa.Platform.Modules:
1296 for Platform in Wa.BuildDatabase.WorkspaceDb.PlatformList:
1297 if ModuleKey in Platform.Modules:
1298 DscOverridePcds = Platform.Modules[ModuleKey].Pcds
1301 DscOverridePcds = {}
1302 self.ModuleReportList.append(ModuleReport(Pa.Platform.Modules[ModuleKey].M, DscOverridePcds, ReportType))
1307 # Generate report for the whole platform.
1309 # This function generates report for platform information.
1310 # It comprises of platform summary, global PCD, flash and
1311 # module list sections.
1313 # @param self The object pointer
1314 # @param File The file object for report
1315 # @param BuildDuration The total time to build the modules
1316 # @param ReportType The kind of report items in the final report file
1318 def GenerateReport(self, File, BuildDuration, ReportType):
1319 FileWrite(File, "Platform Summary")
1320 FileWrite(File, "Platform Name: %s" % self.PlatformName)
1321 FileWrite(File, "Platform DSC Path: %s" % self.PlatformDscPath)
1322 FileWrite(File, "Platform DSC Path: %s" % self.Architectures)
1323 FileWrite(File, "Tool Chain: %s" % self.ToolChain)
1324 FileWrite(File, "Target: %s" % self.Target)
1325 FileWrite(File, "Output Path: %s" % self.OutputPath)
1326 FileWrite(File, "Build Environment: %s" % self.BuildEnvironment)
1327 FileWrite(File, "Build Duration: %s" % BuildDuration)
1328 FileWrite(File, "Report Content: %s" % ", ".join(ReportType))
1330 if "PCD" in ReportType:
1331 self.PcdReport.GenerateReport(File, None, {})
1333 if "FLASH" in ReportType:
1334 for FdReportListItem in self.FdReportList:
1335 FdReportListItem.GenerateReport(File)
1337 for ModuleReportItem in self.ModuleReportList:
1338 ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, ReportType)
1340 if "PREDICTION" in ReportType:
1341 self.PredictionReport.GenerateReport(File, None)
1343 ## BuildReport class
1345 # This base class contain the routines to collect data and then
1346 # applies certain format to the output report
1348 class BuildReport(object):
1350 # Constructor function for class BuildReport
1352 # This constructor function generates BuildReport object a platform build.
1353 # It generates report for platform summary, flash, global PCDs and detailed
1354 # module information for modules involved in platform build.
1356 # @param self The object pointer
1357 # @param ReportFile The file name to save report file
1358 # @param ReportType The kind of report items in the final report file
1360 def __init__(self, ReportFile, ReportType):
1361 self.ReportFile = ReportFile
1363 self.ReportList = []
1364 self.ReportType = []
1365 if ReportType == None or "ALL" in ReportType:
1366 self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "FLASH", "PREDICTION"]
1368 for ReportTypeItem in ReportType:
1369 if ReportTypeItem not in self.ReportType:
1370 self.ReportType.append(ReportTypeItem)
1373 # Adds platform report to the list
1375 # This function adds a platform report to the final report list.
1377 # @param self The object pointer
1378 # @param Wa Workspace context information
1380 def AddPlatformReport(self, Wa):
1382 self.ReportList.append(PlatformReport(Wa, self.ReportType))
1385 # Generates the final report.
1387 # This function generates platform build report. It invokes GenerateReport()
1388 # method for every platform report in the list.
1390 # @param self The object pointer
1391 # @param BuildDuration The total time to build the modules
1393 def GenerateReport(self, BuildDuration):
1396 File = open(self.ReportFile, "w+")
1398 EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=self.ReportFile)
1400 for Report in self.ReportList:
1401 Report.GenerateReport(File, BuildDuration, self.ReportType)
1403 EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile)
1406 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1407 if __name__ == '__main__':