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 Common import EdkLogger
24 from Common.BuildToolError import FILE_OPEN_FAILURE
25 from Common.BuildToolError import FILE_WRITE_FAILURE
28 ## Pattern to extract contents in EDK DXS files
29 gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)
31 ## Pattern to find total FV total size, occupied size in flash report intermediate file
32 gFvTotalSizePattern = re.compile(r"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
33 gFvTakenSizePattern = re.compile(r"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
35 ## Pattern to find GUID value in flash description files
36 gPcdGuidPattern = re.compile(r"PCD\((\w+)[.](\w+)\)")
38 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
39 gOffsetGuidPattern = re.compile(r"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
41 ## Tags for section start, end and separator
42 gSectionStart = ">" + "=" * 118 + "<"
43 gSectionEnd = "<" + "=" * 118 + ">" + "\n"
44 gSectionSep = "=" * 120
46 ## Tags for subsection start, end and separator
47 gSubSectionStart = ">" + "-" * 118 + "<"
48 gSubSectionEnd = "<" + "-" * 118 + ">"
49 gSubSectionSep = "-" * 120
51 ## The look up table to map PCD type to pair of report display type and DEC type
53 'FixedAtBuild' : ('FIXED', 'FixedAtBuild'),
54 'PatchableInModule': ('PATCH', 'PatchableInModule'),
55 'FeatureFlag' : ('FLAG', 'FeatureFlag'),
56 'Dynamic' : ('DYN', 'Dynamic'),
57 'DynamicHii' : ('DYNHII', 'Dynamic'),
58 'DynamicVpd' : ('DYNVPD', 'Dynamic'),
59 'DynamicEx' : ('DEX', 'Dynamic'),
60 'DynamicExHii' : ('DEXHII', 'Dynamic'),
61 'DynamicExVpd' : ('DEXVPD', 'Dynamic'),
65 # Writes a string to the file object.
67 # This function writes a string to the file object and a new line is appended
68 # afterwards. It may optionally wraps the string for better readability.
70 # @File The file object to write
71 # @String The string to be written to the file
72 # @Wrapper Indicates whether to wrap the string
74 def FileWrite(File, String, Wrapper=False):
76 String = textwrap.fill(String, 120)
77 File.write(String + "\n")
81 # Reports library information
83 # This class reports the module library subsection in the build report file.
85 class LibraryReport(object):
87 # Constructor function for class LibraryReport
89 # This constructor function generates LibraryReport object for
92 # @param self The object pointer
93 # @param M Module context information
95 def __init__(self, M):
97 if int(str(M.AutoGenVersion), 0) >= 0x00010005:
98 self._EdkIIModule = True
100 self._EdkIIModule = False
102 for Lib in M.DependentLibraryList:
103 LibInfPath = str(Lib)
104 LibClassList = Lib.LibraryClass[0].LibraryClass
105 LibConstructorList = Lib.ConstructorList
106 LibDesstructorList = Lib.DestructorList
107 LibDepexList = Lib.DepexExpression[M.Arch, M.ModuleType]
108 self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList))
111 # Generate report for module library information
113 # This function generates report for the module library.
114 # If the module is EDKII style one, the additional library class, library
115 # constructor/destructor and dependency expression may also be reported.
117 # @param self The object pointer
118 # @param File The file object for report
120 def GenerateReport(self, File):
121 FileWrite(File, gSubSectionStart)
122 FileWrite(File, "Library")
123 if len(self.LibraryList) > 0:
124 FileWrite(File, gSubSectionSep)
125 for LibraryItem in self.LibraryList:
126 LibInfPath = LibraryItem[0]
127 FileWrite(File, LibInfPath)
130 # Report library class, library constructor and destructor for
131 # EDKII style module.
133 if self._EdkIIModule:
134 LibClass = LibraryItem[1]
136 LibConstructor = " ".join(LibraryItem[2])
138 EdkIILibInfo += " C = " + LibConstructor
139 LibDestructor = " ".join(LibraryItem[3])
141 EdkIILibInfo += " D = " + LibConstructor
142 LibDepex = " ".join(LibraryItem[3])
144 EdkIILibInfo += " Depex = " + LibDepex
146 FileWrite(File, "{%s: %s}" % (LibClass, EdkIILibInfo))
148 FileWrite(File, "{%s}" % LibClass)
150 FileWrite(File, gSubSectionEnd)
153 # Reports dependency expression information
155 # This class reports the module dependency expression subsection in the build report file.
157 class DepexReport(object):
159 # Constructor function for class DepexReport
161 # This constructor function generates DepexReport object for
162 # a module. If the module source contains the DXS file (usually EDK
163 # style module), it uses the dependency in DXS file; otherwise,
164 # it uses the dependency expression from its own INF [Depex] section
165 # and then merges with the ones from its dependent library INF.
167 # @param self The object pointer
168 # @param M Module context information
170 def __init__(self, M):
171 for Source in M.SourceFileList:
172 if os.path.splitext(Source.Path)[1].lower() == ".dxs":
173 Match = gDxsDependencyPattern.search(open(Source.Path).read())
175 self.Depex = Match.group(1).strip()
179 self.Depex = M.DepexExpressionList[M.ModuleType]
180 self.ModuleDepex = " ".join(M.Module.DepexExpression[M.Arch, M.ModuleType])
181 if not self.ModuleDepex:
182 self.ModuleDepex = "TRUE"
185 for Lib in M.DependentLibraryList:
186 LibDepex = " ".join(Lib.DepexExpression[M.Arch, M.ModuleType]).strip()
189 LibDepex = "(" + LibDepex + ")"
190 LibDepexList.append(LibDepex)
191 self.LibraryDepex = " AND ".join(LibDepexList)
192 if not self.LibraryDepex:
193 self.LibraryDepex = "(None)"
197 # Generate report for module dependency expression information
199 # This function generates report for the module dependency expression.
201 # @param self The object pointer
202 # @param File The file object for report
204 def GenerateReport(self, File):
205 FileWrite(File, gSubSectionStart)
206 FileWrite(File, "Dependency Expression (DEPEX) from %s" % self.Source)
208 if self.Source == "INF":
209 FileWrite(File, "%s" % self.Depex, True)
210 FileWrite(File, gSubSectionSep)
211 FileWrite(File, "From Module INF: %s" % self.ModuleDepex, True)
212 FileWrite(File, "From Library INF: %s" % self.LibraryDepex, True)
214 FileWrite(File, "%s" % self.Depex)
215 FileWrite(File, gSubSectionEnd)
218 # Reports dependency expression information
220 # This class reports the module build flags subsection in the build report file.
222 class BuildFlagsReport(object):
224 # Constructor function for class BuildFlagsReport
226 # This constructor function generates BuildFlagsReport object for
227 # a module. It reports the build tool chain tag and all relevant
228 # build flags to build the module.
230 # @param self The object pointer
231 # @param M Module context information
233 def __init__(self, M):
236 # Add build flags according to source file extension so that
237 # irrelevant ones can be filtered out.
239 for Source in M.SourceFileList:
240 Ext = os.path.splitext(Source.File)[1].lower()
241 if Ext in [".c", ".cc", ".cpp"]:
242 BuildOptions["CC"] = 1
243 elif Ext in [".s", ".asm"]:
244 BuildOptions["PP"] = 1
245 BuildOptions["ASM"] = 1
246 elif Ext in [".vfr"]:
247 BuildOptions["VFRPP"] = 1
248 BuildOptions["VFR"] = 1
249 elif Ext in [".dxs"]:
250 BuildOptions["APP"] = 1
251 BuildOptions["CC"] = 1
252 elif Ext in [".asl"]:
253 BuildOptions["ASLPP"] = 1
254 BuildOptions["ASL"] = 1
255 elif Ext in [".aslc"]:
256 BuildOptions["ASLCC"] = 1
257 BuildOptions["ASLDLINK"] = 1
258 BuildOptions["CC"] = 1
259 elif Ext in [".asm16"]:
260 BuildOptions["ASMLINK"] = 1
261 BuildOptions["SLINK"] = 1
262 BuildOptions["DLINK"] = 1
265 # Save module build flags.
267 self.ToolChainTag = M.ToolChain
269 for Tool in BuildOptions:
270 self.BuildFlags[Tool + "_FLAGS"] = M.BuildOption.get(Tool, {}).get("FLAGS", "")
273 # Generate report for module build flags information
275 # This function generates report for the module build flags expression.
277 # @param self The object pointer
278 # @param File The file object for report
280 def GenerateReport(self, File):
281 FileWrite(File, gSubSectionStart)
282 FileWrite(File, "Build Flags")
283 FileWrite(File, "Tool Chain Tag: %s" % self.ToolChainTag)
284 for Tool in self.BuildFlags:
285 FileWrite(File, gSubSectionSep)
286 FileWrite(File, "%s = %s" % (Tool, self.BuildFlags[Tool]), True)
288 FileWrite(File, gSubSectionEnd)
291 # Reports individual module information
293 # This class reports the module section in the build report file.
294 # It comprises of module summary, module PCD, library, dependency expression,
295 # build flags sections.
297 class ModuleReport(object):
299 # Constructor function for class ModuleReport
301 # This constructor function generates ModuleReport object for
302 # a separate module in a platform build.
304 # @param self The object pointer
305 # @param M Module context information
306 # @param DscOverridePcds Module DSC override PCD information
307 # @param ReportType The kind of report items in the final report file
309 def __init__(self, M, DscOverridePcds, ReportType):
310 self.ModuleName = M.Module.BaseName
311 self.ModuleInfPath = M.MetaFile.File
312 self.FileGuid = M.Guid
314 self.BuildTimeStamp = ""
316 self.UefiSpecVersion = M.Module.Specification.get("UEFI_SPECIFICATION_VERSION", "")
317 self.PiSpecVersion = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "")
318 self.PciDeviceId = M.Module.Defines.get("PCI_DEVICE_ID", "")
319 self.PciVendorId = M.Module.Defines.get("PCI_VENDOR_ID", "")
320 self.PciClassCode = M.Module.Defines.get("PCI_CLASS_CODE", "")
322 self.ModulePcdSet = {}
323 self.ModuleDscOverridePcds = {}
324 if "PCD" in ReportType:
326 # Collect all module used PCD set: module INF referenced directly or indirectly.
327 # It also saves module INF default values of them in case they exist.
329 for Pcd in M.ModulePcdList + M.LibraryPcdList:
330 self.ModulePcdSet.setdefault((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Type), Pcd.InfDefaultValue)
333 # Collect module DSC override PCD set for report
335 for (PcdTokenCName, PcdTokenSpaceGuidCName) in DscOverridePcds:
336 Pcd = DscOverridePcds[(PcdTokenCName, PcdTokenSpaceGuidCName)]
337 self.ModuleDscOverridePcds.setdefault((PcdTokenCName, PcdTokenSpaceGuidCName), Pcd.DefaultValue)
339 self.LibraryReport = None
340 if "LIBRARY" in ReportType:
341 self.LibraryReport = LibraryReport(M)
343 self.DepexReport = None
344 if "DEPEX" in ReportType:
345 self.DepexReport = DepexReport(M)
347 if "BUILD_FLAGS" in ReportType:
348 self.BuildFlagsReport = BuildFlagsReport(M)
351 # Generate report for module information
353 # This function generates report for separate module expression
354 # in a platform build.
356 # @param self The object pointer
357 # @param File The file object for report
358 # @param GlobalPcdReport The platform global PCD class object
359 # @param ReportType The kind of report items in the final report file
361 def GenerateReport(self, File, GlobalPcdReport, ReportType):
362 FileWrite(File, gSectionStart)
364 FileWrite(File, "Module Summary")
365 FileWrite(File, "Module Name: %s" % self.ModuleName)
366 FileWrite(File, "Module INF Path: %s" % self.ModuleInfPath)
367 FileWrite(File, "File GUID: %s" % self.FileGuid)
369 FileWrite(File, "Size: %s" % self.Size)
370 if self.BuildTimeStamp:
371 FileWrite(File, "Build Time Stamp: %s" % self.BuildTimeStamp)
373 FileWrite(File, "Driver Type: %s" % self.DriverType)
374 if self.UefiSpecVersion:
375 FileWrite(File, "UEFI Spec Version: %s" % self.DriverType)
376 if self.PiSpecVersion:
377 FileWrite(File, "PI Spec Version: %s" % self.PiSpecVersion)
379 FileWrite(File, "PCI Device ID: %s" % self.PciDeviceId)
381 FileWrite(File, "PCI Vendor ID: %s" % self.PciVendorId)
382 if self.PciClassCode:
383 FileWrite(File, "PCI Class Code: %s" % self.PciClassCode)
385 FileWrite(File, gSectionSep)
387 if "PCD" in ReportType:
388 GlobalPcdReport.GenerateReport(File, self.ModulePcdSet, self.ModuleDscOverridePcds)
390 if "LIBRARY" in ReportType:
391 self.LibraryReport.GenerateReport(File)
393 if "DEPEX" in ReportType:
394 self.DepexReport.GenerateReport(File)
396 if "BUILD_FLAGS" in ReportType:
397 self.BuildFlagsReport.GenerateReport(File)
399 FileWrite(File, gSectionEnd)
402 # Reports platform and module PCD information
404 # This class reports the platform PCD section and module PCD subsection
405 # in the build report file.
407 class PcdReport(object):
409 # Constructor function for class PcdReport
411 # This constructor function generates PcdReport object a platform build.
412 # It collects the whole PCD database from platform DSC files, platform
413 # flash description file and package DEC files.
415 # @param self The object pointer
416 # @param Wa Workspace context information
418 def __init__(self, Wa):
421 self.FdfPcdSet = Wa.FdfProfile.PcdDict
423 self.DecPcdDefault = {}
424 self.ModulePcdOverride = {}
425 for Pa in Wa.AutoGenObjectList:
427 # Collect all platform referenced PCDs and grouped them by PCD token space
430 for Pcd in Pa.AllPcdList:
431 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
432 if Pcd not in PcdList:
434 if len(Pcd.TokenCName) > self.MaxLen:
435 self.MaxLen = len(Pcd.TokenCName)
437 for ModuleKey in Pa.Platform.Modules:
439 # Collect PCD DEC default value.
441 Module = Pa.Platform.Modules[ModuleKey]
442 for Package in Module.M.Module.Packages:
443 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:
444 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue
445 self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue)
447 # Collect module override PCDs
449 for ModulePcd in Module.M.ModulePcdList + Module.M.LibraryPcdList:
450 TokenCName = ModulePcd.TokenCName
451 TokenSpaceGuid = ModulePcd.TokenSpaceGuidCName
452 ModuleDefault = ModulePcd.DefaultValue
453 ModulePath = os.path.basename(Module.M.MetaFile.File)
454 self.ModulePcdOverride.setdefault((TokenCName, TokenSpaceGuid), []).append((ModuleDefault, ModulePath))
457 # Collect PCDs defined in DSC common section
459 self.DscPcdDefault = {}
460 for Platform in Wa.BuildDatabase.WorkspaceDb.PlatformList:
461 for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds:
462 DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue
463 self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue
466 # Generate report for PCD information
468 # This function generates report for separate module expression
469 # in a platform build.
471 # @param self The object pointer
472 # @param File The file object for report
473 # @param ModulePcdSet Set of all PCDs referenced by module or None for
474 # platform PCD report
475 # @param DscOverridePcds Module DSC override PCDs set
477 def GenerateReport(self, File, ModulePcdSet, DscOverridePcds):
478 if ModulePcdSet == None:
480 # For platform global PCD section
482 FileWrite(File, gSectionStart)
483 FileWrite(File, "Platform Configuration Database Report")
484 FileWrite(File, " *P - Platform scoped PCD override in DSC file")
485 FileWrite(File, " *F - Platform scoped PCD override in FDF file")
486 FileWrite(File, " *M - Module scoped PCD override in DSC file")
487 FileWrite(File, gSectionSep)
490 # For module PCD sub-section
492 FileWrite(File, gSubSectionStart)
493 FileWrite(File, "PCD")
494 FileWrite(File, gSubSectionSep)
496 for Key in self.AllPcds:
498 # Group PCD by their token space GUID C Name
501 for Type in self.AllPcds[Key]:
503 # Group PCD by their usage type
505 TypeName, DecType = gPcdTypeMap.get(Type, ("", Type))
506 for Pcd in self.AllPcds[Key][Type]:
508 # Get PCD default value and their override relationship
510 InfDefaultValue = None
511 if ModulePcdSet != None:
512 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type) not in ModulePcdSet:
514 InfDefault = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]
518 if ModulePcdSet == None:
522 DecDefaultValue = self.DecPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, DecType))
523 DscDefaultValue = self.DscPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))
524 DscModuleOverrideValue = DscOverridePcds.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))
526 if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
527 PcdDefaultValueNumber = int(Pcd.DefaultValue.strip(), 0)
528 if DecDefaultValue == None:
531 DecDefaultValueNumber = int(DecDefaultValue.strip(), 0)
532 DecMatch = (DecDefaultValueNumber == PcdDefaultValueNumber)
534 if InfDefaultValue == None:
537 InfDefaultValueNumber = int(InfDefaultValue.strip(), 0)
538 InfMatch = (InfDefaultValueNumber == PcdDefaultValueNumber)
540 if DscDefaultValue == None:
543 DscDefaultValueNumber = int(DscDefaultValue.strip(), 0)
544 DscMatch = (DscDefaultValueNumber == PcdDefaultValueNumber)
546 if DecDefaultValue == None:
549 DecMatch = (DecDefaultValue == Pcd.DefaultValue)
551 if InfDefaultValue == None:
554 InfMatch = (InfDefaultValue == Pcd.DefaultValue)
556 if DscDefaultValue == None:
559 DscMatch = (DscDefaultValue == Pcd.DefaultValue)
562 # Report PCD item according to their override relationship
564 if DecMatch and InfMatch:
565 FileWrite(File, ' %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', Pcd.DefaultValue))
567 if DscMatch and DscModuleOverrideValue == None:
568 if (Pcd.TokenCName, Key) in self.FdfPcdSet:
569 FileWrite(File, ' *F %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', Pcd.DefaultValue))
571 FileWrite(File, ' *P %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', Pcd.DefaultValue))
573 FileWrite(File, ' *M %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', Pcd.DefaultValue))
574 if DscDefaultValue != None:
575 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', DscDefaultValue))
577 if InfDefaultValue != None:
578 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', InfDefaultValue))
580 if DecDefaultValue != None and not DecMatch:
581 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', DecDefaultValue))
583 if ModulePcdSet == None:
584 for (ModuleDefault, ModulePath) in self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), []):
585 if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
586 ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0)
587 Match = (ModulePcdDefaultValueNumber == PcdDefaultValueNumber)
589 Match = (ModuleDefault == Pcd.DefaultValue)
592 FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 19, ModulePath, ModuleDefault))
594 if ModulePcdSet == None:
595 FileWrite(File, gSectionEnd)
597 FileWrite(File, gSubSectionEnd)
601 # Reports platform information
603 # This class reports the whole platform information
605 class PlatformReport(object):
607 # Constructor function for class PlatformReport
609 # This constructor function generates PlatformReport object a platform build.
610 # It generates report for platform summary, flash, global PCDs and detailed
611 # module information for modules involved in platform build.
613 # @param self The object pointer
614 # @param Wa Workspace context information
616 def __init__(self, Wa, ReportType):
617 self._WorkspaceDir = Wa.WorkspaceDir
618 self.PlatformName = Wa.Name
619 self.PlatformDscPath = Wa.Platform
620 self.Architectures = " ".join(Wa.ArchList)
621 self.ToolChain = Wa.ToolChain
622 self.Target = Wa.BuildTarget
623 self.OutputPath = os.path.join(Wa.WorkspaceDir, Wa.OutputDir)
624 self.BuildEnvironment = platform.platform()
626 self.PcdReport = None
627 if "PCD" in ReportType:
628 self.PcdReport = PcdReport(Wa)
630 self.ModuleReportList = []
631 for Pa in Wa.AutoGenObjectList:
632 for ModuleKey in Pa.Platform.Modules:
633 for Platform in Wa.BuildDatabase.WorkspaceDb.PlatformList:
634 if ModuleKey in Platform.Modules:
635 DscOverridePcds = Platform.Modules[ModuleKey].Pcds
639 self.ModuleReportList.append(ModuleReport(Pa.Platform.Modules[ModuleKey].M, DscOverridePcds, ReportType))
642 # Generate report for the whole platform.
644 # This function generates report for platform information.
645 # It comprises of platform summary, global PCD, flash and
646 # module list sections.
648 # @param self The object pointer
649 # @param File The file object for report
650 # @param BuildDuration The total time to build the modules
651 # @param ReportType The kind of report items in the final report file
653 def GenerateReport(self, File, BuildDuration, ReportType):
654 FileWrite(File, "Platform Summary")
655 FileWrite(File, "Platform Name: %s" % self.PlatformName)
656 FileWrite(File, "Platform DSC Path: %s" % self.PlatformDscPath)
657 FileWrite(File, "Platform DSC Path: %s" % self.Architectures)
658 FileWrite(File, "Tool Chain: %s" % self.ToolChain)
659 FileWrite(File, "Target: %s" % self.Target)
660 FileWrite(File, "Output Path: %s" % self.OutputPath)
661 FileWrite(File, "Build Environment: %s" % self.BuildEnvironment)
662 FileWrite(File, "Build Duration: %s" % BuildDuration)
663 FileWrite(File, "Report Content: %s" % ", ".join(ReportType))
665 if "PCD" in ReportType:
666 self.PcdReport.GenerateReport(File, None, {})
669 for ModuleReportItem in self.ModuleReportList:
670 ModuleReportItem.GenerateReport(File, self.PcdReport, ReportType)
675 # This base class contain the routines to collect data and then
676 # applies certain format to the output report
678 class BuildReport(object):
680 # Constructor function for class BuildReport
682 # This constructor function generates BuildReport object a platform build.
683 # It generates report for platform summary, flash, global PCDs and detailed
684 # module information for modules involved in platform build.
686 # @param self The object pointer
687 # @param ReportFile The file name to save report file
688 # @param ReportType The kind of report items in the final report file
690 def __init__(self, ReportFile, ReportType):
691 self.ReportFile = ReportFile
694 if ReportType == None or "ALL" in ReportType:
695 self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "FLASH", "PREDICTION"]
697 for ReportTypeItem in ReportType:
698 if ReportTypeItem not in self.ReportType:
699 self.ReportType.append(ReportTypeItem)
702 # Adds platform report to the list
704 # This function adds a platform report to the final report list.
706 # @param self The object pointer
707 # @param Wa Workspace context information
709 def AddPlatformReport(self, Wa):
711 self.ReportList.append(PlatformReport(Wa, self.ReportType))
714 # Generates the final report.
716 # This function generates platform build report. It invokes GenerateReport()
717 # method for every platform report in the list.
719 # @param self The object pointer
720 # @param BuildDuration The total time to build the modules
722 def GenerateReport(self, BuildDuration):
725 File = open(self.ReportFile, "w+")
727 EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=self.ReportFile)
729 for Report in self.ReportList:
730 Report.GenerateReport(File, BuildDuration, self.ReportType)
732 EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile)
735 # This acts like the main() function for the script, unless it is 'import'ed into another script.
736 if __name__ == '__main__':