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.
25 from datetime
import datetime
26 from Common
import EdkLogger
27 from Common
.Misc
import GuidStructureByteArrayToGuidString
28 from Common
.Misc
import GuidStructureStringToGuidString
29 from Common
.InfClassObject
import gComponentType2ModuleType
30 from Common
.BuildToolError
import FILE_OPEN_FAILURE
31 from Common
.BuildToolError
import FILE_WRITE_FAILURE
32 from Common
.BuildToolError
import CODE_ERROR
35 ## Pattern to extract contents in EDK DXS files
36 gDxsDependencyPattern
= re
.compile(r
"DEPENDENCY_START(.+)DEPENDENCY_END", re
.DOTALL
)
38 ## Pattern to find total FV total size, occupied size in flash report intermediate file
39 gFvTotalSizePattern
= re
.compile(r
"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
40 gFvTakenSizePattern
= re
.compile(r
"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
42 ## Pattern to find module size and time stamp in module summary report intermediate file
43 gModuleSizePattern
= re
.compile(r
"MODULE_SIZE = (\d+)")
44 gTimeStampPattern
= re
.compile(r
"TIME_STAMP = (\d+)")
46 ## Pattern to find GUID value in flash description files
47 gPcdGuidPattern
= re
.compile(r
"PCD\((\w+)[.](\w+)\)")
49 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
50 gOffsetGuidPattern
= re
.compile(r
"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
52 ## Pattern to find module base address and entry point in fixed flash map file
53 gModulePattern
= r
"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
54 gMapFileItemPattern
= re
.compile(gModulePattern
% {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
56 ## Pattern to find all module referenced header files in source files
57 gIncludePattern
= re
.compile(r
'#include\s*["<]([^">]+)[">]')
58 gIncludePattern2
= re
.compile(r
"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
60 ## Pattern to find the entry point for EDK module using EDKII Glue library
61 gGlueLibEntryPoint
= re
.compile(r
"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
63 ## Tags for section start, end and separator
64 gSectionStart
= ">" + "=" * 118 + "<"
65 gSectionEnd
= "<" + "=" * 118 + ">" + "\n"
66 gSectionSep
= "=" * 120
68 ## Tags for subsection start, end and separator
69 gSubSectionStart
= ">" + "-" * 118 + "<"
70 gSubSectionEnd
= "<" + "-" * 118 + ">"
71 gSubSectionSep
= "-" * 120
73 ## The look up table to map PCD type to pair of report display type and DEC type
75 'FixedAtBuild' : ('FIXED', 'FixedAtBuild'),
76 'PatchableInModule': ('PATCH', 'PatchableInModule'),
77 'FeatureFlag' : ('FLAG', 'FeatureFlag'),
78 'Dynamic' : ('DYN', 'Dynamic'),
79 'DynamicHii' : ('DYNHII', 'Dynamic'),
80 'DynamicVpd' : ('DYNVPD', 'Dynamic'),
81 'DynamicEx' : ('DEX', 'Dynamic'),
82 'DynamicExHii' : ('DEXHII', 'Dynamic'),
83 'DynamicExVpd' : ('DEXVPD', 'Dynamic'),
86 ## The look up table to map module type to driver type
88 'SEC' : '0x3 (SECURITY_CORE)',
89 'PEI_CORE' : '0x4 (PEI_CORE)',
90 'PEIM' : '0x6 (PEIM)',
91 'DXE_CORE' : '0x5 (DXE_CORE)',
92 'DXE_DRIVER' : '0x7 (DRIVER)',
93 'DXE_SAL_DRIVER' : '0x7 (DRIVER)',
94 'DXE_SMM_DRIVER' : '0x7 (DRIVER)',
95 'DXE_RUNTIME_DRIVER': '0x7 (DRIVER)',
96 'UEFI_DRIVER' : '0x7 (DRIVER)',
97 'UEFI_APPLICATION' : '0x9 (APPLICATION)',
98 'SMM_CORE' : '0xD (SMM_CORE)',
99 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
103 # Writes a string to the file object.
105 # This function writes a string to the file object and a new line is appended
106 # afterwards. It may optionally wraps the string for better readability.
108 # @File The file object to write
109 # @String The string to be written to the file
110 # @Wrapper Indicates whether to wrap the string
112 def FileWrite(File
, String
, Wrapper
=False):
114 String
= textwrap
.fill(String
, 120)
115 File
.write(String
+ "\r\n")
118 # Find all the header file that the module source directly includes.
120 # This function scans source code to find all header files the module may
121 # include. This is not accurate but very effective to find all the header
122 # file the module might include with #include statement.
124 # @Source The source file name
125 # @IncludePathList The list of include path to find the source file.
126 # @IncludeFiles The dictionary of current found include files.
128 def FindIncludeFiles(Source
, IncludePathList
, IncludeFiles
):
129 FileContents
= open(Source
).read()
131 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
133 for Match
in gIncludePattern
.finditer(FileContents
):
134 FileName
= Match
.group(1).strip()
135 for Dir
in [os
.path
.dirname(Source
)] + IncludePathList
:
136 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
137 if os
.path
.exists(FullFileName
):
138 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
142 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
144 for Match
in gIncludePattern2
.finditer(FileContents
):
146 Type
= Match
.group(1)
147 if "ARCH_PROTOCOL" in Type
:
148 FileName
= "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
149 elif "PROTOCOL" in Type
:
150 FileName
= "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
152 FileName
= "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key
}
154 FileName
= "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key
}
157 for Dir
in IncludePathList
:
158 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
159 if os
.path
.exists(FullFileName
):
160 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
164 # Reports library information
166 # This class reports the module library subsection in the build report file.
168 class LibraryReport(object):
170 # Constructor function for class LibraryReport
172 # This constructor function generates LibraryReport object for
175 # @param self The object pointer
176 # @param M Module context information
178 def __init__(self
, M
):
179 self
.LibraryList
= []
180 if int(str(M
.AutoGenVersion
), 0) >= 0x00010005:
181 self
._EdkIIModule
= True
183 self
._EdkIIModule
= False
185 for Lib
in M
.DependentLibraryList
:
186 LibInfPath
= str(Lib
)
187 LibClassList
= Lib
.LibraryClass
[0].LibraryClass
188 LibConstructorList
= Lib
.ConstructorList
189 LibDesstructorList
= Lib
.DestructorList
190 LibDepexList
= Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]
191 self
.LibraryList
.append((LibInfPath
, LibClassList
, LibConstructorList
, LibDesstructorList
, LibDepexList
))
194 # Generate report for module library information
196 # This function generates report for the module library.
197 # If the module is EDKII style one, the additional library class, library
198 # constructor/destructor and dependency expression may also be reported.
200 # @param self The object pointer
201 # @param File The file object for report
203 def GenerateReport(self
, File
):
204 FileWrite(File
, gSubSectionStart
)
205 FileWrite(File
, "Library")
206 if len(self
.LibraryList
) > 0:
207 FileWrite(File
, gSubSectionSep
)
208 for LibraryItem
in self
.LibraryList
:
209 LibInfPath
= LibraryItem
[0]
210 FileWrite(File
, LibInfPath
)
213 # Report library class, library constructor and destructor for
214 # EDKII style module.
216 if self
._EdkIIModule
:
217 LibClass
= LibraryItem
[1]
219 LibConstructor
= " ".join(LibraryItem
[2])
221 EdkIILibInfo
+= " C = " + LibConstructor
222 LibDestructor
= " ".join(LibraryItem
[3])
224 EdkIILibInfo
+= " D = " + LibDestructor
225 LibDepex
= " ".join(LibraryItem
[4])
227 EdkIILibInfo
+= " Depex = " + LibDepex
229 FileWrite(File
, "{%s: %s}" % (LibClass
, EdkIILibInfo
))
231 FileWrite(File
, "{%s}" % LibClass
)
233 FileWrite(File
, gSubSectionEnd
)
236 # Reports dependency expression information
238 # This class reports the module dependency expression subsection in the build report file.
240 class DepexReport(object):
242 # Constructor function for class DepexReport
244 # This constructor function generates DepexReport object for
245 # a module. If the module source contains the DXS file (usually EDK
246 # style module), it uses the dependency in DXS file; otherwise,
247 # it uses the dependency expression from its own INF [Depex] section
248 # and then merges with the ones from its dependent library INF.
250 # @param self The object pointer
251 # @param M Module context information
253 def __init__(self
, M
):
255 ModuleType
= M
.ModuleType
257 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
259 if ModuleType
in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "UEFI_APPLICATION"]:
262 for Source
in M
.SourceFileList
:
263 if os
.path
.splitext(Source
.Path
)[1].lower() == ".dxs":
264 Match
= gDxsDependencyPattern
.search(open(Source
.Path
).read())
266 self
.Depex
= Match
.group(1).strip()
270 self
.Depex
= M
.DepexExpressionList
.get(M
.ModuleType
, "")
271 self
.ModuleDepex
= " ".join(M
.Module
.DepexExpression
[M
.Arch
, M
.ModuleType
])
272 if not self
.ModuleDepex
:
273 self
.ModuleDepex
= "(None)"
276 for Lib
in M
.DependentLibraryList
:
277 LibDepex
= " ".join(Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]).strip()
279 LibDepexList
.append("(" + LibDepex
+ ")")
280 self
.LibraryDepex
= " AND ".join(LibDepexList
)
281 if not self
.LibraryDepex
:
282 self
.LibraryDepex
= "(None)"
286 # Generate report for module dependency expression information
288 # This function generates report for the module dependency expression.
290 # @param self The object pointer
291 # @param File The file object for report
293 def GenerateReport(self
, File
):
297 FileWrite(File
, gSubSectionStart
)
298 FileWrite(File
, "Dependency Expression (DEPEX) from %s" % self
.Source
)
300 if self
.Source
== "INF":
301 FileWrite(File
, "%s" % self
.Depex
, True)
302 FileWrite(File
, gSubSectionSep
)
303 FileWrite(File
, "From Module INF: %s" % self
.ModuleDepex
, True)
304 FileWrite(File
, "From Library INF: %s" % self
.LibraryDepex
, True)
306 FileWrite(File
, "%s" % self
.Depex
)
307 FileWrite(File
, gSubSectionEnd
)
310 # Reports dependency expression information
312 # This class reports the module build flags subsection in the build report file.
314 class BuildFlagsReport(object):
316 # Constructor function for class BuildFlagsReport
318 # This constructor function generates BuildFlagsReport object for
319 # a module. It reports the build tool chain tag and all relevant
320 # build flags to build the module.
322 # @param self The object pointer
323 # @param M Module context information
325 def __init__(self
, M
):
328 # Add build flags according to source file extension so that
329 # irrelevant ones can be filtered out.
331 for Source
in M
.SourceFileList
:
332 Ext
= os
.path
.splitext(Source
.File
)[1].lower()
333 if Ext
in [".c", ".cc", ".cpp"]:
334 BuildOptions
["CC"] = 1
335 elif Ext
in [".s", ".asm"]:
336 BuildOptions
["PP"] = 1
337 BuildOptions
["ASM"] = 1
338 elif Ext
in [".vfr"]:
339 BuildOptions
["VFRPP"] = 1
340 BuildOptions
["VFR"] = 1
341 elif Ext
in [".dxs"]:
342 BuildOptions
["APP"] = 1
343 BuildOptions
["CC"] = 1
344 elif Ext
in [".asl"]:
345 BuildOptions
["ASLPP"] = 1
346 BuildOptions
["ASL"] = 1
347 elif Ext
in [".aslc"]:
348 BuildOptions
["ASLCC"] = 1
349 BuildOptions
["ASLDLINK"] = 1
350 BuildOptions
["CC"] = 1
351 elif Ext
in [".asm16"]:
352 BuildOptions
["ASMLINK"] = 1
353 BuildOptions
["SLINK"] = 1
354 BuildOptions
["DLINK"] = 1
357 # Save module build flags.
359 self
.ToolChainTag
= M
.ToolChain
361 for Tool
in BuildOptions
:
362 self
.BuildFlags
[Tool
+ "_FLAGS"] = M
.BuildOption
.get(Tool
, {}).get("FLAGS", "")
365 # Generate report for module build flags information
367 # This function generates report for the module build flags expression.
369 # @param self The object pointer
370 # @param File The file object for report
372 def GenerateReport(self
, File
):
373 FileWrite(File
, gSubSectionStart
)
374 FileWrite(File
, "Build Flags")
375 FileWrite(File
, "Tool Chain Tag: %s" % self
.ToolChainTag
)
376 for Tool
in self
.BuildFlags
:
377 FileWrite(File
, gSubSectionSep
)
378 FileWrite(File
, "%s = %s" % (Tool
, self
.BuildFlags
[Tool
]), True)
380 FileWrite(File
, gSubSectionEnd
)
384 # Reports individual module information
386 # This class reports the module section in the build report file.
387 # It comprises of module summary, module PCD, library, dependency expression,
388 # build flags sections.
390 class ModuleReport(object):
392 # Constructor function for class ModuleReport
394 # This constructor function generates ModuleReport object for
395 # a separate module in a platform build.
397 # @param self The object pointer
398 # @param M Module context information
399 # @param ReportType The kind of report items in the final report file
401 def __init__(self
, M
, ReportType
):
402 self
.ModuleName
= M
.Module
.BaseName
403 self
.ModuleInfPath
= M
.MetaFile
.File
404 self
.FileGuid
= M
.Guid
406 self
.BuildTimeStamp
= None
409 ModuleType
= M
.ModuleType
411 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
413 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
415 if ModuleType
== "DXE_SMM_DRIVER":
416 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
417 if int(PiSpec
, 0) >= 0x0001000A:
418 ModuleType
= "SMM_DRIVER"
419 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "0x2 (FREE_FORM)")
420 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
421 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
422 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
423 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
424 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
426 self
._BuildDir
= M
.BuildDir
427 self
.ModulePcdSet
= {}
428 if "PCD" in ReportType
:
430 # Collect all module used PCD set: module INF referenced directly or indirectly.
431 # It also saves module INF default values of them in case they exist.
433 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
434 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
436 self
.LibraryReport
= None
437 if "LIBRARY" in ReportType
:
438 self
.LibraryReport
= LibraryReport(M
)
440 self
.DepexReport
= None
441 if "DEPEX" in ReportType
:
442 self
.DepexReport
= DepexReport(M
)
444 if "BUILD_FLAGS" in ReportType
:
445 self
.BuildFlagsReport
= BuildFlagsReport(M
)
449 # Generate report for module information
451 # This function generates report for separate module expression
452 # in a platform build.
454 # @param self The object pointer
455 # @param File The file object for report
456 # @param GlobalPcdReport The platform global PCD class object
457 # @param ReportType The kind of report items in the final report file
459 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, ReportType
):
460 FileWrite(File
, gSectionStart
)
462 FwReportFileName
= os
.path
.join(self
._BuildDir
, "DEBUG", self
.ModuleName
+ ".txt")
463 if os
.path
.isfile(FwReportFileName
):
465 FileContents
= open(FwReportFileName
).read()
466 Match
= gModuleSizePattern
.search(FileContents
)
468 self
.Size
= int(Match
.group(1))
470 Match
= gTimeStampPattern
.search(FileContents
)
472 self
.BuildTimeStamp
= datetime
.fromtimestamp(int(Match
.group(1)))
474 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
476 FileWrite(File
, "Module Summary")
477 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
478 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
479 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
481 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
482 if self
.BuildTimeStamp
:
483 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
485 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
486 if self
.UefiSpecVersion
:
487 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
488 if self
.PiSpecVersion
:
489 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
491 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
493 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
494 if self
.PciClassCode
:
495 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
497 FileWrite(File
, gSectionSep
)
499 if "PCD" in ReportType
:
500 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
)
502 if "LIBRARY" in ReportType
:
503 self
.LibraryReport
.GenerateReport(File
)
505 if "DEPEX" in ReportType
:
506 self
.DepexReport
.GenerateReport(File
)
508 if "BUILD_FLAGS" in ReportType
:
509 self
.BuildFlagsReport
.GenerateReport(File
)
511 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
512 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
514 FileWrite(File
, gSectionEnd
)
517 # Reports platform and module PCD information
519 # This class reports the platform PCD section and module PCD subsection
520 # in the build report file.
522 class PcdReport(object):
524 # Constructor function for class PcdReport
526 # This constructor function generates PcdReport object a platform build.
527 # It collects the whole PCD database from platform DSC files, platform
528 # flash description file and package DEC files.
530 # @param self The object pointer
531 # @param Wa Workspace context information
533 def __init__(self
, Wa
):
537 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
541 self
.ModulePcdOverride
= {}
542 for Pa
in Wa
.AutoGenObjectList
:
544 # Collect all platform referenced PCDs and grouped them by PCD token space
547 for Pcd
in Pa
.AllPcdList
:
548 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
549 if Pcd
not in PcdList
:
551 if len(Pcd
.TokenCName
) > self
.MaxLen
:
552 self
.MaxLen
= len(Pcd
.TokenCName
)
554 for Module
in Pa
.Platform
.Modules
.values():
556 # Collect module override PCDs
558 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
559 TokenCName
= ModulePcd
.TokenCName
560 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
561 ModuleDefault
= ModulePcd
.DefaultValue
562 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
563 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
567 # Collect PCD DEC default value.
569 self
.DecPcdDefault
= {}
570 for Package
in Wa
.BuildDatabase
.WorkspaceDb
.PackageList
:
571 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
572 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
573 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
575 # Collect PCDs defined in DSC common section
577 self
.DscPcdDefault
= {}
578 for Platform
in Wa
.BuildDatabase
.WorkspaceDb
.PlatformList
:
579 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
580 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
581 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
584 # Generate report for PCD information
586 # This function generates report for separate module expression
587 # in a platform build.
589 # @param self The object pointer
590 # @param File The file object for report
591 # @param ModulePcdSet Set of all PCDs referenced by module or None for
592 # platform PCD report
593 # @param DscOverridePcds Module DSC override PCDs set
595 def GenerateReport(self
, File
, ModulePcdSet
):
596 if ModulePcdSet
== None:
598 # For platform global PCD section
600 FileWrite(File
, gSectionStart
)
601 FileWrite(File
, "Platform Configuration Database Report")
602 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
603 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
604 FileWrite(File
, " *M - Module scoped PCD override in DSC file")
605 FileWrite(File
, gSectionSep
)
608 # For module PCD sub-section
610 FileWrite(File
, gSubSectionStart
)
611 FileWrite(File
, "PCD")
612 FileWrite(File
, gSubSectionSep
)
614 for Key
in self
.AllPcds
:
616 # Group PCD by their token space GUID C Name
619 for Type
in self
.AllPcds
[Key
]:
621 # Group PCD by their usage type
623 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
624 for Pcd
in self
.AllPcds
[Key
][Type
]:
626 # Get PCD default value and their override relationship
628 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
629 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
630 DscDefaultValue
= self
.FdfPcdSet
.get((Pcd
.TokenCName
, Key
), DscDefaultValue
)
631 InfDefaultValue
= None
633 PcdValue
= DecDefaultValue
635 PcdValue
= DscDefaultValue
636 if ModulePcdSet
!= None:
637 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
639 InfDefault
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
643 if ModulePcdSet
== None:
649 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
650 PcdValueNumber
= int(PcdValue
.strip(), 0)
651 if DecDefaultValue
== None:
654 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
655 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
657 if InfDefaultValue
== None:
660 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
661 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
663 if DscDefaultValue
== None:
666 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
667 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
669 if DecDefaultValue
== None:
672 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
674 if InfDefaultValue
== None:
677 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
679 if DscDefaultValue
== None:
682 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
685 # Report PCD item according to their override relationship
687 if DecMatch
and InfMatch
:
688 FileWrite(File
, ' %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
691 if (Pcd
.TokenCName
, Key
) in self
.FdfPcdSet
:
692 FileWrite(File
, ' *F %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
694 FileWrite(File
, ' *P %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
696 FileWrite(File
, ' *M %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
698 if TypeName
in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):
699 for SkuInfo
in Pcd
.SkuInfoList
.values():
700 if TypeName
in ('DYNHII', 'DEXHII'):
701 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
703 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
705 if not DscMatch
and DscDefaultValue
!= None:
706 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', DscDefaultValue
.strip()))
708 if not InfMatch
and InfDefaultValue
!= None:
709 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', InfDefaultValue
.strip()))
711 if not DecMatch
and DecDefaultValue
!= None:
712 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', DecDefaultValue
.strip()))
714 if ModulePcdSet
== None:
715 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
716 for ModulePath
in ModuleOverride
:
717 ModuleDefault
= ModuleOverride
[ModulePath
]
718 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
719 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
720 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
722 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
725 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 19, ModulePath
, ModuleDefault
.strip()))
727 if ModulePcdSet
== None:
728 FileWrite(File
, gSectionEnd
)
730 FileWrite(File
, gSubSectionEnd
)
735 # Reports platform and module Prediction information
737 # This class reports the platform execution order prediction section and
738 # module load fixed address prediction subsection in the build report file.
740 class PredictionReport(object):
742 # Constructor function for class PredictionReport
744 # This constructor function generates PredictionReport object for the platform.
746 # @param self: The object pointer
747 # @param Wa Workspace context information
749 def __init__(self
, Wa
):
750 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
751 self
._MapFileParsed
= False
752 self
._EotToolInvoked
= False
753 self
._FvDir
= Wa
.FvDir
754 self
._EotDir
= Wa
.BuildDir
755 self
._FfsEntryPoint
= {}
757 self
._SourceList
= []
758 self
.FixedMapDict
= {}
763 # Collect all platform reference source files and GUID C Name
765 for Pa
in Wa
.AutoGenObjectList
:
766 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
768 # Add module referenced source files
770 self
._SourceList
.append(str(Module
))
772 for Source
in Module
.SourceFileList
:
773 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
774 self
._SourceList
.append(" " + str(Source
))
775 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
776 for IncludeFile
in IncludeList
.values():
777 self
._SourceList
.append(" " + IncludeFile
)
779 for Guid
in Module
.PpiList
:
780 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
781 for Guid
in Module
.ProtocolList
:
782 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
783 for Guid
in Module
.GuidList
:
784 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
786 if Module
.Guid
and not Module
.IsLibrary
:
787 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
788 if int(str(Module
.AutoGenVersion
), 0) >= 0x00010005:
789 RealEntryPoint
= "_ModuleEntryPoint"
791 RealEntryPoint
= EntryPoint
792 if EntryPoint
== "_ModuleEntryPoint":
793 CCFlags
= Module
.BuildOption
.get("CC", {}).get("FLAGS", "")
794 Match
= gGlueLibEntryPoint
.search(CCFlags
)
796 EntryPoint
= Match
.group(1)
798 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
802 # Collect platform firmware volume list as the input of EOT.
806 for Fd
in Wa
.FdfProfile
.FdDict
:
807 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
808 if FdRegion
.RegionType
!= "FV":
810 for FvName
in FdRegion
.RegionDataList
:
811 if FvName
in self
._FvList
:
813 self
._FvList
.append(FvName
)
814 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
815 for Section
in Ffs
.SectionList
:
817 for FvSection
in Section
.SectionList
:
818 if FvSection
.FvName
in self
._FvList
:
820 self
._FvList
.append(FvSection
.FvName
)
821 except AttributeError:
826 # Parse platform fixed address map files
828 # This function parses the platform final fixed address map file to get
829 # the database of predicted fixed address for module image base, entry point
832 # @param self: The object pointer
834 def _ParseMapFile(self
):
835 if self
._MapFileParsed
:
837 self
._MapFileParsed
= True
838 if os
.path
.isfile(self
._MapFileName
):
840 FileContents
= open(self
._MapFileName
).read()
841 for Match
in gMapFileItemPattern
.finditer(FileContents
):
842 AddressType
= Match
.group(1)
843 BaseAddress
= Match
.group(2)
844 EntryPoint
= Match
.group(3)
845 Guid
= Match
.group(4).upper()
846 List
= self
.FixedMapDict
.setdefault(Guid
, [])
847 List
.append((AddressType
, BaseAddress
, "*I"))
848 List
.append((AddressType
, EntryPoint
, "*E"))
850 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
853 # Invokes EOT tool to get the predicted the execution order.
855 # This function invokes EOT tool to calculate the predicted dispatch order
857 # @param self: The object pointer
859 def _InvokeEotTool(self
):
860 if self
._EotToolInvoked
:
863 self
._EotToolInvoked
= True
865 for FvName
in self
._FvList
:
866 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
867 if os
.path
.isfile(FvFile
):
868 FvFileList
.append(FvFile
)
870 if len(FvFileList
) == 0:
873 # Write source file list and GUID file list to an intermediate file
874 # as the input for EOT tool and dispatch List as the output file
877 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
878 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
879 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
881 TempFile
= open(SourceList
, "w+")
882 for Item
in self
._SourceList
:
883 FileWrite(TempFile
, Item
)
885 TempFile
= open(GuidList
, "w+")
886 for Key
in self
._GuidMap
:
887 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
891 from Eot
.Eot
import Eot
895 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
896 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
899 # Parse the output of EOT tool
901 for Line
in open(DispatchList
):
902 if len(Line
.split()) < 4:
904 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
905 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
906 if len(Symbol
) > self
.MaxLen
:
907 self
.MaxLen
= len(Symbol
)
908 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
910 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
911 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
915 # Generate platform execution order report
917 # This function generates the predicted module execution order.
919 # @param self The object pointer
920 # @param File The file object for report
922 def _GenerateExecutionOrderReport(self
, File
):
923 self
._InvokeEotTool
()
924 if len(self
.ItemList
) == 0:
926 FileWrite(File
, gSectionStart
)
927 FileWrite(File
, "Execution Order Prediction")
928 FileWrite(File
, "*P PEI phase")
929 FileWrite(File
, "*D DXE phase")
930 FileWrite(File
, "*E Module INF entry point name")
931 FileWrite(File
, "*N Module notification function name")
933 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
934 FileWrite(File
, gSectionSep
)
935 for Item
in self
.ItemList
:
936 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
938 FileWrite(File
, gSectionStart
)
941 # Generate Fixed Address report.
943 # This function generate the predicted fixed address report for a module
946 # @param self The object pointer
947 # @param File The file object for report
948 # @param Guid The module Guid value.
949 # @param NotifyList The list of all notify function in a module
951 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
953 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
954 if not FixedAddressList
:
957 FileWrite(File
, gSubSectionStart
)
958 FileWrite(File
, "Fixed Address Prediction")
959 FileWrite(File
, "*I Image Loading Address")
960 FileWrite(File
, "*E Entry Point Address")
961 FileWrite(File
, "*N Notification Function Address")
962 FileWrite(File
, "*F Flash Address")
963 FileWrite(File
, "*M Memory Address")
964 FileWrite(File
, "*S SMM RAM Offset")
965 FileWrite(File
, "TOM Top of Memory")
967 FileWrite(File
, "Type Address Name")
968 FileWrite(File
, gSubSectionSep
)
969 for Item
in FixedAddressList
:
974 Name
= "(Image Base)"
976 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
977 elif Symbol
in NotifyList
:
985 elif "Memory" in Type
:
991 Value
= "TOM" + Value
993 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
996 # Generate report for the prediction part
998 # This function generate the predicted fixed address report for a module or
999 # predicted module execution order for a platform.
1000 # If the input Guid is None, then, it generates the predicted module execution order;
1001 # otherwise it generated the module fixed loading address for the module specified by
1004 # @param self The object pointer
1005 # @param File The file object for report
1006 # @param Guid The module Guid value.
1008 def GenerateReport(self
, File
, Guid
):
1010 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1012 self
._GenerateExecutionOrderReport
(File
)
1015 # Reports FD region information
1017 # This class reports the FD subsection in the build report file.
1018 # It collects region information of platform flash device.
1019 # If the region is a firmware volume, it lists the set of modules
1020 # and its space information; otherwise, it only lists its region name,
1021 # base address and size in its sub-section header.
1022 # If there are nesting FVs, the nested FVs will list immediate after
1023 # this FD region subsection
1025 class FdRegionReport(object):
1027 # Discover all the nested FV name list.
1029 # This is an internal worker function to discover the all the nested FV information
1030 # in the parent firmware volume. It uses deep first search algorithm recursively to
1031 # find all the FV list name and append them to the list.
1033 # @param self The object pointer
1034 # @param FvName The name of current firmware file system
1035 # @param Wa Workspace context information
1037 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1038 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1039 for Section
in Ffs
.SectionList
:
1041 for FvSection
in Section
.SectionList
:
1042 if FvSection
.FvName
in self
.FvList
:
1044 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1045 self
.FvList
.append(FvSection
.FvName
)
1046 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1047 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1048 except AttributeError:
1052 # Constructor function for class FdRegionReport
1054 # This constructor function generates FdRegionReport object for a specified FdRegion.
1055 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1056 # volume list. This function also collects GUID map in order to dump module identification
1057 # in the final report.
1059 # @param self: The object pointer
1060 # @param FdRegion The current FdRegion object
1061 # @param Wa Workspace context information
1063 def __init__(self
, FdRegion
, Wa
):
1064 self
.Type
= FdRegion
.RegionType
1065 self
.BaseAddress
= FdRegion
.Offset
1066 self
.Size
= FdRegion
.Size
1070 self
._FvDir
= Wa
.FvDir
1073 # If the input FdRegion is not a firmware volume,
1076 if self
.Type
!= "FV":
1080 # Find all nested FVs in the FdRegion
1082 for FvName
in FdRegion
.RegionDataList
:
1083 if FvName
in self
.FvList
:
1085 self
.FvList
.append(FvName
)
1086 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1087 self
._DiscoverNestedFvList
(FvName
, Wa
)
1092 # Collect PCDs declared in DEC files.
1094 for Package
in Wa
.BuildDatabase
.WorkspaceDb
.PackageList
:
1095 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1096 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1097 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1099 # Collect PCDs defined in DSC common section
1101 for Platform
in Wa
.BuildDatabase
.WorkspaceDb
.PlatformList
:
1102 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
1103 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1104 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1107 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1109 self
._GuidsDb
["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"
1110 self
._GuidsDb
["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"
1112 # Add ACPI table storage file
1114 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1116 for Pa
in Wa
.AutoGenObjectList
:
1117 for ModuleKey
in Pa
.Platform
.Modules
:
1118 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1119 InfPath
= os
.path
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1120 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1123 # Collect the GUID map in the FV firmware volume
1125 for FvName
in self
.FvList
:
1126 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1129 # collect GUID map for binary EFI file in FDF file.
1131 Guid
= Ffs
.NameGuid
.upper()
1132 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1134 PcdTokenspace
= Match
.group(1)
1135 PcdToken
= Match
.group(2)
1136 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1137 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1138 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1139 for Section
in Ffs
.SectionList
:
1141 ModuleSectFile
= os
.path
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1142 self
._GuidsDb
[Guid
] = ModuleSectFile
1143 except AttributeError:
1145 except AttributeError:
1150 # Internal worker function to generate report for the FD region
1152 # This internal worker function to generate report for the FD region.
1153 # It the type is firmware volume, it lists offset and module identification.
1155 # @param self The object pointer
1156 # @param File The file object for report
1157 # @param Title The title for the FD subsection
1158 # @param BaseAddress The base address for the FD region
1159 # @param Size The size of the FD region
1160 # @param FvName The FV name if the FD region is a firmware volume
1162 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1163 FileWrite(File
, gSubSectionStart
)
1164 FileWrite(File
, Title
)
1165 FileWrite(File
, "Type: %s" % Type
)
1166 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1168 if self
.Type
== "FV":
1172 FvReportFileName
= os
.path
.join(self
._FvDir
, FvName
+ ".fv.txt")
1175 # Collect size info in the firmware volume.
1177 FvReport
= open(FvReportFileName
).read()
1178 Match
= gFvTotalSizePattern
.search(FvReport
)
1180 FvTotalSize
= int(Match
.group(1), 16)
1181 Match
= gFvTakenSizePattern
.search(FvReport
)
1183 FvTakenSize
= int(Match
.group(1), 16)
1184 FvFreeSize
= FvTotalSize
- FvTakenSize
1186 # Write size information to the report file.
1188 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1189 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1190 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1191 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1192 FileWrite(File
, "Offset Module")
1193 FileWrite(File
, gSubSectionSep
)
1195 # Write module offset and module identification to the report file.
1198 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1199 Guid
= Match
.group(2).upper()
1200 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1201 OffsetList
= OffsetInfo
.keys()
1203 for Offset
in OffsetList
:
1204 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1206 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
1208 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
1209 FileWrite(File
, gSubSectionEnd
)
1212 # Generate report for the FD region
1214 # This function generates report for the FD region.
1216 # @param self The object pointer
1217 # @param File The file object for report
1219 def GenerateReport(self
, File
):
1220 if (len(self
.FvList
) > 0):
1221 for FvItem
in self
.FvList
:
1222 Info
= self
.FvInfo
[FvItem
]
1223 self
._GenerateReport
(File
, Info
[0], "FV", Info
[1], Info
[2], FvItem
)
1225 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
1228 # Reports FD information
1230 # This class reports the FD section in the build report file.
1231 # It collects flash device information for a platform.
1233 class FdReport(object):
1235 # Constructor function for class FdReport
1237 # This constructor function generates FdReport object for a specified
1240 # @param self The object pointer
1241 # @param Fd The current Firmware device object
1242 # @param Wa Workspace context information
1244 def __init__(self
, Fd
, Wa
):
1245 self
.FdName
= Fd
.FdUiName
1246 self
.BaseAddress
= Fd
.BaseAddress
1248 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
1251 # Generate report for the firmware device.
1253 # This function generates report for the firmware device.
1255 # @param self The object pointer
1256 # @param File The file object for report
1258 def GenerateReport(self
, File
):
1259 FileWrite(File
, gSectionStart
)
1260 FileWrite(File
, "Firmware Device (FD)")
1261 FileWrite(File
, "FD Name: %s" % self
.FdName
)
1262 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
1263 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
1264 if len(self
.FdRegionList
) > 0:
1265 FileWrite(File
, gSectionSep
)
1266 for FdRegionItem
in self
.FdRegionList
:
1267 FdRegionItem
.GenerateReport(File
)
1269 FileWrite(File
, gSectionEnd
)
1274 # Reports platform information
1276 # This class reports the whole platform information
1278 class PlatformReport(object):
1280 # Constructor function for class PlatformReport
1282 # This constructor function generates PlatformReport object a platform build.
1283 # It generates report for platform summary, flash, global PCDs and detailed
1284 # module information for modules involved in platform build.
1286 # @param self The object pointer
1287 # @param Wa Workspace context information
1288 # @param MaList The list of modules in the platform build
1290 def __init__(self
, Wa
, MaList
, ReportType
):
1291 self
._WorkspaceDir
= Wa
.WorkspaceDir
1292 self
.PlatformName
= Wa
.Name
1293 self
.PlatformDscPath
= Wa
.Platform
1294 self
.Architectures
= " ".join(Wa
.ArchList
)
1295 self
.ToolChain
= Wa
.ToolChain
1296 self
.Target
= Wa
.BuildTarget
1297 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
1298 self
.BuildEnvironment
= platform
.platform()
1300 self
.PcdReport
= None
1301 if "PCD" in ReportType
:
1302 self
.PcdReport
= PcdReport(Wa
)
1304 self
.FdReportList
= []
1305 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
== None:
1306 for Fd
in Wa
.FdfProfile
.FdDict
:
1307 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
1309 self
.PredictionReport
= None
1310 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
1311 self
.PredictionReport
= PredictionReport(Wa
)
1313 self
.ModuleReportList
= []
1315 self
._IsModuleBuild
= True
1317 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
1319 self
._IsModuleBuild
= False
1320 for Pa
in Wa
.AutoGenObjectList
:
1321 for ModuleKey
in Pa
.Platform
.Modules
:
1322 self
.ModuleReportList
.append(ModuleReport(Pa
.Platform
.Modules
[ModuleKey
].M
, ReportType
))
1327 # Generate report for the whole platform.
1329 # This function generates report for platform information.
1330 # It comprises of platform summary, global PCD, flash and
1331 # module list sections.
1333 # @param self The object pointer
1334 # @param File The file object for report
1335 # @param BuildDuration The total time to build the modules
1336 # @param ReportType The kind of report items in the final report file
1338 def GenerateReport(self
, File
, BuildDuration
, ReportType
):
1339 FileWrite(File
, "Platform Summary")
1340 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
1341 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
1342 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
1343 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
1344 FileWrite(File
, "Target: %s" % self
.Target
)
1345 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
1346 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
1347 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
1348 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
1350 if not self
._IsModuleBuild
:
1351 if "PCD" in ReportType
:
1352 self
.PcdReport
.GenerateReport(File
, None)
1354 if "FLASH" in ReportType
:
1355 for FdReportListItem
in self
.FdReportList
:
1356 FdReportListItem
.GenerateReport(File
)
1358 for ModuleReportItem
in self
.ModuleReportList
:
1359 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, ReportType
)
1361 if not self
._IsModuleBuild
:
1362 if "EXECUTION_ORDER" in ReportType
:
1363 self
.PredictionReport
.GenerateReport(File
, None)
1365 ## BuildReport class
1367 # This base class contain the routines to collect data and then
1368 # applies certain format to the output report
1370 class BuildReport(object):
1372 # Constructor function for class BuildReport
1374 # This constructor function generates BuildReport object a platform build.
1375 # It generates report for platform summary, flash, global PCDs and detailed
1376 # module information for modules involved in platform build.
1378 # @param self The object pointer
1379 # @param ReportFile The file name to save report file
1380 # @param ReportType The kind of report items in the final report file
1382 def __init__(self
, ReportFile
, ReportType
):
1383 self
.ReportFile
= ReportFile
1385 self
.ReportList
= []
1386 self
.ReportType
= []
1388 for ReportTypeItem
in ReportType
:
1389 if ReportTypeItem
not in self
.ReportType
:
1390 self
.ReportType
.append(ReportTypeItem
)
1392 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "FLASH", "FIXED_ADDRESS"]
1394 # Adds platform report to the list
1396 # This function adds a platform report to the final report list.
1398 # @param self The object pointer
1399 # @param Wa Workspace context information
1400 # @param MaList The list of modules in the platform build
1402 def AddPlatformReport(self
, Wa
, MaList
=None):
1404 self
.ReportList
.append((Wa
, MaList
))
1407 # Generates the final report.
1409 # This function generates platform build report. It invokes GenerateReport()
1410 # method for every platform report in the list.
1412 # @param self The object pointer
1413 # @param BuildDuration The total time to build the modules
1415 def GenerateReport(self
, BuildDuration
):
1418 File
= open(self
.ReportFile
, "w+")
1420 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=self
.ReportFile
)
1422 for (Wa
, MaList
) in self
.ReportList
:
1423 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, self
.ReportType
)
1424 EdkLogger
.quiet("Report successfully saved to %s" % os
.path
.abspath(self
.ReportFile
))
1426 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
1428 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
1429 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1432 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1433 if __name__
== '__main__':