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. All rights reserved.<BR>
8 # 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.
26 from datetime
import datetime
27 from StringIO
import StringIO
28 from Common
import EdkLogger
29 from Common
.Misc
import SaveFileOnChange
30 from Common
.Misc
import GuidStructureByteArrayToGuidString
31 from Common
.Misc
import GuidStructureStringToGuidString
32 from Common
.InfClassObject
import gComponentType2ModuleType
33 from Common
.BuildToolError
import FILE_WRITE_FAILURE
34 from Common
.BuildToolError
import CODE_ERROR
37 ## Pattern to extract contents in EDK DXS files
38 gDxsDependencyPattern
= re
.compile(r
"DEPENDENCY_START(.+)DEPENDENCY_END", re
.DOTALL
)
40 ## Pattern to find total FV total size, occupied size in flash report intermediate file
41 gFvTotalSizePattern
= re
.compile(r
"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
42 gFvTakenSizePattern
= re
.compile(r
"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
44 ## Pattern to find module size and time stamp in module summary report intermediate file
45 gModuleSizePattern
= re
.compile(r
"MODULE_SIZE = (\d+)")
46 gTimeStampPattern
= re
.compile(r
"TIME_STAMP = (\d+)")
48 ## Pattern to find GUID value in flash description files
49 gPcdGuidPattern
= re
.compile(r
"PCD\((\w+)[.](\w+)\)")
51 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
52 gOffsetGuidPattern
= re
.compile(r
"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
54 ## Pattern to find module base address and entry point in fixed flash map file
55 gModulePattern
= r
"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
56 gMapFileItemPattern
= re
.compile(gModulePattern
% {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
58 ## Pattern to find all module referenced header files in source files
59 gIncludePattern
= re
.compile(r
'#include\s*["<]([^">]+)[">]')
60 gIncludePattern2
= re
.compile(r
"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
62 ## Pattern to find the entry point for EDK module using EDKII Glue library
63 gGlueLibEntryPoint
= re
.compile(r
"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
65 ## Tags for section start, end and separator
66 gSectionStart
= ">" + "=" * 118 + "<"
67 gSectionEnd
= "<" + "=" * 118 + ">" + "\n"
68 gSectionSep
= "=" * 120
70 ## Tags for subsection start, end and separator
71 gSubSectionStart
= ">" + "-" * 118 + "<"
72 gSubSectionEnd
= "<" + "-" * 118 + ">"
73 gSubSectionSep
= "-" * 120
75 ## The look up table to map PCD type to pair of report display type and DEC type
77 'FixedAtBuild' : ('FIXED', 'FixedAtBuild'),
78 'PatchableInModule': ('PATCH', 'PatchableInModule'),
79 'FeatureFlag' : ('FLAG', 'FeatureFlag'),
80 'Dynamic' : ('DYN', 'Dynamic'),
81 'DynamicHii' : ('DYNHII', 'Dynamic'),
82 'DynamicVpd' : ('DYNVPD', 'Dynamic'),
83 'DynamicEx' : ('DEX', 'Dynamic'),
84 'DynamicExHii' : ('DEXHII', 'Dynamic'),
85 'DynamicExVpd' : ('DEXVPD', 'Dynamic'),
88 ## The look up table to map module type to driver type
90 'SEC' : '0x3 (SECURITY_CORE)',
91 'PEI_CORE' : '0x4 (PEI_CORE)',
92 'PEIM' : '0x6 (PEIM)',
93 'DXE_CORE' : '0x5 (DXE_CORE)',
94 'DXE_DRIVER' : '0x7 (DRIVER)',
95 'DXE_SAL_DRIVER' : '0x7 (DRIVER)',
96 'DXE_SMM_DRIVER' : '0x7 (DRIVER)',
97 'DXE_RUNTIME_DRIVER': '0x7 (DRIVER)',
98 'UEFI_DRIVER' : '0x7 (DRIVER)',
99 'UEFI_APPLICATION' : '0x9 (APPLICATION)',
100 'SMM_CORE' : '0xD (SMM_CORE)',
101 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
105 # Writes a string to the file object.
107 # This function writes a string to the file object and a new line is appended
108 # afterwards. It may optionally wraps the string for better readability.
110 # @File The file object to write
111 # @String The string to be written to the file
112 # @Wrapper Indicates whether to wrap the string
114 def FileWrite(File
, String
, Wrapper
=False):
116 String
= textwrap
.fill(String
, 120)
117 File
.write(String
+ "\r\n")
120 # Find all the header file that the module source directly includes.
122 # This function scans source code to find all header files the module may
123 # include. This is not accurate but very effective to find all the header
124 # file the module might include with #include statement.
126 # @Source The source file name
127 # @IncludePathList The list of include path to find the source file.
128 # @IncludeFiles The dictionary of current found include files.
130 def FindIncludeFiles(Source
, IncludePathList
, IncludeFiles
):
131 FileContents
= open(Source
).read()
133 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
135 for Match
in gIncludePattern
.finditer(FileContents
):
136 FileName
= Match
.group(1).strip()
137 for Dir
in [os
.path
.dirname(Source
)] + IncludePathList
:
138 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
139 if os
.path
.exists(FullFileName
):
140 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
144 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
146 for Match
in gIncludePattern2
.finditer(FileContents
):
148 Type
= Match
.group(1)
149 if "ARCH_PROTOCOL" in Type
:
150 FileName
= "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
151 elif "PROTOCOL" in Type
:
152 FileName
= "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
154 FileName
= "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key
}
156 FileName
= "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key
}
159 for Dir
in IncludePathList
:
160 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
161 if os
.path
.exists(FullFileName
):
162 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
166 # Reports library information
168 # This class reports the module library subsection in the build report file.
170 class LibraryReport(object):
172 # Constructor function for class LibraryReport
174 # This constructor function generates LibraryReport object for
177 # @param self The object pointer
178 # @param M Module context information
180 def __init__(self
, M
):
181 self
.LibraryList
= []
182 if int(str(M
.AutoGenVersion
), 0) >= 0x00010005:
183 self
._EdkIIModule
= True
185 self
._EdkIIModule
= False
187 for Lib
in M
.DependentLibraryList
:
188 LibInfPath
= str(Lib
)
189 LibClassList
= Lib
.LibraryClass
[0].LibraryClass
190 LibConstructorList
= Lib
.ConstructorList
191 LibDesstructorList
= Lib
.DestructorList
192 LibDepexList
= Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]
193 self
.LibraryList
.append((LibInfPath
, LibClassList
, LibConstructorList
, LibDesstructorList
, LibDepexList
))
196 # Generate report for module library information
198 # This function generates report for the module library.
199 # If the module is EDKII style one, the additional library class, library
200 # constructor/destructor and dependency expression may also be reported.
202 # @param self The object pointer
203 # @param File The file object for report
205 def GenerateReport(self
, File
):
206 FileWrite(File
, gSubSectionStart
)
207 FileWrite(File
, "Library")
208 if len(self
.LibraryList
) > 0:
209 FileWrite(File
, gSubSectionSep
)
210 for LibraryItem
in self
.LibraryList
:
211 LibInfPath
= LibraryItem
[0]
212 FileWrite(File
, LibInfPath
)
215 # Report library class, library constructor and destructor for
216 # EDKII style module.
218 if self
._EdkIIModule
:
219 LibClass
= LibraryItem
[1]
221 LibConstructor
= " ".join(LibraryItem
[2])
223 EdkIILibInfo
+= " C = " + LibConstructor
224 LibDestructor
= " ".join(LibraryItem
[3])
226 EdkIILibInfo
+= " D = " + LibDestructor
227 LibDepex
= " ".join(LibraryItem
[4])
229 EdkIILibInfo
+= " Depex = " + LibDepex
231 FileWrite(File
, "{%s: %s}" % (LibClass
, EdkIILibInfo
))
233 FileWrite(File
, "{%s}" % LibClass
)
235 FileWrite(File
, gSubSectionEnd
)
238 # Reports dependency expression information
240 # This class reports the module dependency expression subsection in the build report file.
242 class DepexReport(object):
244 # Constructor function for class DepexReport
246 # This constructor function generates DepexReport object for
247 # a module. If the module source contains the DXS file (usually EDK
248 # style module), it uses the dependency in DXS file; otherwise,
249 # it uses the dependency expression from its own INF [Depex] section
250 # and then merges with the ones from its dependent library INF.
252 # @param self The object pointer
253 # @param M Module context information
255 def __init__(self
, M
):
257 ModuleType
= M
.ModuleType
259 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
261 if ModuleType
in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "UEFI_APPLICATION"]:
264 for Source
in M
.SourceFileList
:
265 if os
.path
.splitext(Source
.Path
)[1].lower() == ".dxs":
266 Match
= gDxsDependencyPattern
.search(open(Source
.Path
).read())
268 self
.Depex
= Match
.group(1).strip()
272 self
.Depex
= M
.DepexExpressionList
.get(M
.ModuleType
, "")
273 self
.ModuleDepex
= " ".join(M
.Module
.DepexExpression
[M
.Arch
, M
.ModuleType
])
274 if not self
.ModuleDepex
:
275 self
.ModuleDepex
= "(None)"
278 for Lib
in M
.DependentLibraryList
:
279 LibDepex
= " ".join(Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]).strip()
281 LibDepexList
.append("(" + LibDepex
+ ")")
282 self
.LibraryDepex
= " AND ".join(LibDepexList
)
283 if not self
.LibraryDepex
:
284 self
.LibraryDepex
= "(None)"
288 # Generate report for module dependency expression information
290 # This function generates report for the module dependency expression.
292 # @param self The object pointer
293 # @param File The file object for report
295 def GenerateReport(self
, File
):
299 FileWrite(File
, gSubSectionStart
)
300 FileWrite(File
, "Dependency Expression (DEPEX) from %s" % self
.Source
)
302 if self
.Source
== "INF":
303 FileWrite(File
, "%s" % self
.Depex
, True)
304 FileWrite(File
, gSubSectionSep
)
305 FileWrite(File
, "From Module INF: %s" % self
.ModuleDepex
, True)
306 FileWrite(File
, "From Library INF: %s" % self
.LibraryDepex
, True)
308 FileWrite(File
, "%s" % self
.Depex
)
309 FileWrite(File
, gSubSectionEnd
)
312 # Reports dependency expression information
314 # This class reports the module build flags subsection in the build report file.
316 class BuildFlagsReport(object):
318 # Constructor function for class BuildFlagsReport
320 # This constructor function generates BuildFlagsReport object for
321 # a module. It reports the build tool chain tag and all relevant
322 # build flags to build the module.
324 # @param self The object pointer
325 # @param M Module context information
327 def __init__(self
, M
):
330 # Add build flags according to source file extension so that
331 # irrelevant ones can be filtered out.
333 for Source
in M
.SourceFileList
:
334 Ext
= os
.path
.splitext(Source
.File
)[1].lower()
335 if Ext
in [".c", ".cc", ".cpp"]:
336 BuildOptions
["CC"] = 1
337 elif Ext
in [".s", ".asm"]:
338 BuildOptions
["PP"] = 1
339 BuildOptions
["ASM"] = 1
340 elif Ext
in [".vfr"]:
341 BuildOptions
["VFRPP"] = 1
342 BuildOptions
["VFR"] = 1
343 elif Ext
in [".dxs"]:
344 BuildOptions
["APP"] = 1
345 BuildOptions
["CC"] = 1
346 elif Ext
in [".asl"]:
347 BuildOptions
["ASLPP"] = 1
348 BuildOptions
["ASL"] = 1
349 elif Ext
in [".aslc"]:
350 BuildOptions
["ASLCC"] = 1
351 BuildOptions
["ASLDLINK"] = 1
352 BuildOptions
["CC"] = 1
353 elif Ext
in [".asm16"]:
354 BuildOptions
["ASMLINK"] = 1
355 BuildOptions
["SLINK"] = 1
356 BuildOptions
["DLINK"] = 1
359 # Save module build flags.
361 self
.ToolChainTag
= M
.ToolChain
363 for Tool
in BuildOptions
:
364 self
.BuildFlags
[Tool
+ "_FLAGS"] = M
.BuildOption
.get(Tool
, {}).get("FLAGS", "")
367 # Generate report for module build flags information
369 # This function generates report for the module build flags expression.
371 # @param self The object pointer
372 # @param File The file object for report
374 def GenerateReport(self
, File
):
375 FileWrite(File
, gSubSectionStart
)
376 FileWrite(File
, "Build Flags")
377 FileWrite(File
, "Tool Chain Tag: %s" % self
.ToolChainTag
)
378 for Tool
in self
.BuildFlags
:
379 FileWrite(File
, gSubSectionSep
)
380 FileWrite(File
, "%s = %s" % (Tool
, self
.BuildFlags
[Tool
]), True)
382 FileWrite(File
, gSubSectionEnd
)
386 # Reports individual module information
388 # This class reports the module section in the build report file.
389 # It comprises of module summary, module PCD, library, dependency expression,
390 # build flags sections.
392 class ModuleReport(object):
394 # Constructor function for class ModuleReport
396 # This constructor function generates ModuleReport object for
397 # a separate module in a platform build.
399 # @param self The object pointer
400 # @param M Module context information
401 # @param ReportType The kind of report items in the final report file
403 def __init__(self
, M
, ReportType
):
404 self
.ModuleName
= M
.Module
.BaseName
405 self
.ModuleInfPath
= M
.MetaFile
.File
406 self
.FileGuid
= M
.Guid
408 self
.BuildTimeStamp
= None
411 ModuleType
= M
.ModuleType
413 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
415 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
417 if ModuleType
== "DXE_SMM_DRIVER":
418 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
419 if int(PiSpec
, 0) >= 0x0001000A:
420 ModuleType
= "SMM_DRIVER"
421 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "0x2 (FREE_FORM)")
422 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
423 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
424 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
425 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
426 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
428 self
._BuildDir
= M
.BuildDir
429 self
.ModulePcdSet
= {}
430 if "PCD" in ReportType
:
432 # Collect all module used PCD set: module INF referenced directly or indirectly.
433 # It also saves module INF default values of them in case they exist.
435 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
436 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
438 self
.LibraryReport
= None
439 if "LIBRARY" in ReportType
:
440 self
.LibraryReport
= LibraryReport(M
)
442 self
.DepexReport
= None
443 if "DEPEX" in ReportType
:
444 self
.DepexReport
= DepexReport(M
)
446 if "BUILD_FLAGS" in ReportType
:
447 self
.BuildFlagsReport
= BuildFlagsReport(M
)
451 # Generate report for module information
453 # This function generates report for separate module expression
454 # in a platform build.
456 # @param self The object pointer
457 # @param File The file object for report
458 # @param GlobalPcdReport The platform global PCD class object
459 # @param ReportType The kind of report items in the final report file
461 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, ReportType
):
462 FileWrite(File
, gSectionStart
)
464 FwReportFileName
= os
.path
.join(self
._BuildDir
, "DEBUG", self
.ModuleName
+ ".txt")
465 if os
.path
.isfile(FwReportFileName
):
467 FileContents
= open(FwReportFileName
).read()
468 Match
= gModuleSizePattern
.search(FileContents
)
470 self
.Size
= int(Match
.group(1))
472 Match
= gTimeStampPattern
.search(FileContents
)
474 self
.BuildTimeStamp
= datetime
.fromtimestamp(int(Match
.group(1)))
476 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
478 FileWrite(File
, "Module Summary")
479 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
480 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
481 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
483 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
484 if self
.BuildTimeStamp
:
485 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
487 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
488 if self
.UefiSpecVersion
:
489 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
490 if self
.PiSpecVersion
:
491 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
493 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
495 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
496 if self
.PciClassCode
:
497 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
499 FileWrite(File
, gSectionSep
)
501 if "PCD" in ReportType
:
502 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
)
504 if "LIBRARY" in ReportType
:
505 self
.LibraryReport
.GenerateReport(File
)
507 if "DEPEX" in ReportType
:
508 self
.DepexReport
.GenerateReport(File
)
510 if "BUILD_FLAGS" in ReportType
:
511 self
.BuildFlagsReport
.GenerateReport(File
)
513 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
514 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
516 FileWrite(File
, gSectionEnd
)
519 # Reports platform and module PCD information
521 # This class reports the platform PCD section and module PCD subsection
522 # in the build report file.
524 class PcdReport(object):
526 # Constructor function for class PcdReport
528 # This constructor function generates PcdReport object a platform build.
529 # It collects the whole PCD database from platform DSC files, platform
530 # flash description file and package DEC files.
532 # @param self The object pointer
533 # @param Wa Workspace context information
535 def __init__(self
, Wa
):
539 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
543 self
.ModulePcdOverride
= {}
544 for Pa
in Wa
.AutoGenObjectList
:
546 # Collect all platform referenced PCDs and grouped them by PCD token space
549 for Pcd
in Pa
.AllPcdList
:
550 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
551 if Pcd
not in PcdList
:
553 if len(Pcd
.TokenCName
) > self
.MaxLen
:
554 self
.MaxLen
= len(Pcd
.TokenCName
)
556 for Module
in Pa
.Platform
.Modules
.values():
558 # Collect module override PCDs
560 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
561 TokenCName
= ModulePcd
.TokenCName
562 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
563 ModuleDefault
= ModulePcd
.DefaultValue
564 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
565 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
569 # Collect PCD DEC default value.
571 self
.DecPcdDefault
= {}
572 for Package
in Wa
.BuildDatabase
.WorkspaceDb
.PackageList
:
573 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
574 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
575 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
577 # Collect PCDs defined in DSC common section
579 self
.DscPcdDefault
= {}
580 for Platform
in Wa
.BuildDatabase
.WorkspaceDb
.PlatformList
:
581 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
582 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
584 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
587 # Generate report for PCD information
589 # This function generates report for separate module expression
590 # in a platform build.
592 # @param self The object pointer
593 # @param File The file object for report
594 # @param ModulePcdSet Set of all PCDs referenced by module or None for
595 # platform PCD report
596 # @param DscOverridePcds Module DSC override PCDs set
598 def GenerateReport(self
, File
, ModulePcdSet
):
599 if ModulePcdSet
== None:
601 # For platform global PCD section
603 FileWrite(File
, gSectionStart
)
604 FileWrite(File
, "Platform Configuration Database Report")
605 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
606 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
607 FileWrite(File
, " *M - Module scoped PCD override")
608 FileWrite(File
, gSectionSep
)
611 # For module PCD sub-section
613 FileWrite(File
, gSubSectionStart
)
614 FileWrite(File
, "PCD")
615 FileWrite(File
, gSubSectionSep
)
617 for Key
in self
.AllPcds
:
619 # Group PCD by their token space GUID C Name
622 for Type
in self
.AllPcds
[Key
]:
624 # Group PCD by their usage type
626 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
627 for Pcd
in self
.AllPcds
[Key
][Type
]:
629 # Get PCD default value and their override relationship
631 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
632 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
633 DscDefaultValue
= self
.FdfPcdSet
.get((Pcd
.TokenCName
, Key
), DscDefaultValue
)
634 InfDefaultValue
= None
636 PcdValue
= DecDefaultValue
638 PcdValue
= DscDefaultValue
639 if ModulePcdSet
!= None:
640 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
642 InfDefault
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
646 if ModulePcdSet
== None:
652 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
653 PcdValueNumber
= int(PcdValue
.strip(), 0)
654 if DecDefaultValue
== None:
657 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
658 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
660 if InfDefaultValue
== None:
663 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
664 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
666 if DscDefaultValue
== None:
669 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
670 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
672 if DecDefaultValue
== None:
675 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
677 if InfDefaultValue
== None:
680 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
682 if DscDefaultValue
== None:
685 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
688 # Report PCD item according to their override relationship
690 if DecMatch
and InfMatch
:
691 FileWrite(File
, ' %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
694 if (Pcd
.TokenCName
, Key
) in self
.FdfPcdSet
:
695 FileWrite(File
, ' *F %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
697 FileWrite(File
, ' *P %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
699 FileWrite(File
, ' *M %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
701 if TypeName
in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):
702 for SkuInfo
in Pcd
.SkuInfoList
.values():
703 if TypeName
in ('DYNHII', 'DEXHII'):
704 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
706 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
708 if not DscMatch
and DscDefaultValue
!= None:
709 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', DscDefaultValue
.strip()))
711 if not InfMatch
and InfDefaultValue
!= None:
712 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', InfDefaultValue
.strip()))
714 if not DecMatch
and DecDefaultValue
!= None:
715 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', DecDefaultValue
.strip()))
717 if ModulePcdSet
== None:
718 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
719 for ModulePath
in ModuleOverride
:
720 ModuleDefault
= ModuleOverride
[ModulePath
]
721 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
722 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
723 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
725 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
728 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 19, ModulePath
, ModuleDefault
.strip()))
730 if ModulePcdSet
== None:
731 FileWrite(File
, gSectionEnd
)
733 FileWrite(File
, gSubSectionEnd
)
738 # Reports platform and module Prediction information
740 # This class reports the platform execution order prediction section and
741 # module load fixed address prediction subsection in the build report file.
743 class PredictionReport(object):
745 # Constructor function for class PredictionReport
747 # This constructor function generates PredictionReport object for the platform.
749 # @param self: The object pointer
750 # @param Wa Workspace context information
752 def __init__(self
, Wa
):
753 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
754 self
._MapFileParsed
= False
755 self
._EotToolInvoked
= False
756 self
._FvDir
= Wa
.FvDir
757 self
._EotDir
= Wa
.BuildDir
758 self
._FfsEntryPoint
= {}
760 self
._SourceList
= []
761 self
.FixedMapDict
= {}
766 # Collect all platform reference source files and GUID C Name
768 for Pa
in Wa
.AutoGenObjectList
:
769 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
771 # BASE typed modules are EFI agnostic, so we need not scan
772 # their source code to find PPI/Protocol produce or consume
775 if Module
.ModuleType
== "BASE":
778 # Add module referenced source files
780 self
._SourceList
.append(str(Module
))
782 for Source
in Module
.SourceFileList
:
783 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
784 self
._SourceList
.append(" " + str(Source
))
785 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
786 for IncludeFile
in IncludeList
.values():
787 self
._SourceList
.append(" " + IncludeFile
)
789 for Guid
in Module
.PpiList
:
790 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
791 for Guid
in Module
.ProtocolList
:
792 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
793 for Guid
in Module
.GuidList
:
794 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
796 if Module
.Guid
and not Module
.IsLibrary
:
797 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
798 if int(str(Module
.AutoGenVersion
), 0) >= 0x00010005:
799 RealEntryPoint
= "_ModuleEntryPoint"
801 RealEntryPoint
= EntryPoint
802 if EntryPoint
== "_ModuleEntryPoint":
803 CCFlags
= Module
.BuildOption
.get("CC", {}).get("FLAGS", "")
804 Match
= gGlueLibEntryPoint
.search(CCFlags
)
806 EntryPoint
= Match
.group(1)
808 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
812 # Collect platform firmware volume list as the input of EOT.
816 for Fd
in Wa
.FdfProfile
.FdDict
:
817 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
818 if FdRegion
.RegionType
!= "FV":
820 for FvName
in FdRegion
.RegionDataList
:
821 if FvName
in self
._FvList
:
823 self
._FvList
.append(FvName
)
824 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
825 for Section
in Ffs
.SectionList
:
827 for FvSection
in Section
.SectionList
:
828 if FvSection
.FvName
in self
._FvList
:
830 self
._FvList
.append(FvSection
.FvName
)
831 except AttributeError:
836 # Parse platform fixed address map files
838 # This function parses the platform final fixed address map file to get
839 # the database of predicted fixed address for module image base, entry point
842 # @param self: The object pointer
844 def _ParseMapFile(self
):
845 if self
._MapFileParsed
:
847 self
._MapFileParsed
= True
848 if os
.path
.isfile(self
._MapFileName
):
850 FileContents
= open(self
._MapFileName
).read()
851 for Match
in gMapFileItemPattern
.finditer(FileContents
):
852 AddressType
= Match
.group(1)
853 BaseAddress
= Match
.group(2)
854 EntryPoint
= Match
.group(3)
855 Guid
= Match
.group(4).upper()
856 List
= self
.FixedMapDict
.setdefault(Guid
, [])
857 List
.append((AddressType
, BaseAddress
, "*I"))
858 List
.append((AddressType
, EntryPoint
, "*E"))
860 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
863 # Invokes EOT tool to get the predicted the execution order.
865 # This function invokes EOT tool to calculate the predicted dispatch order
867 # @param self: The object pointer
869 def _InvokeEotTool(self
):
870 if self
._EotToolInvoked
:
873 self
._EotToolInvoked
= True
875 for FvName
in self
._FvList
:
876 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
877 if os
.path
.isfile(FvFile
):
878 FvFileList
.append(FvFile
)
880 if len(FvFileList
) == 0:
883 # Write source file list and GUID file list to an intermediate file
884 # as the input for EOT tool and dispatch List as the output file
887 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
888 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
889 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
891 TempFile
= open(SourceList
, "w+")
892 for Item
in self
._SourceList
:
893 FileWrite(TempFile
, Item
)
895 TempFile
= open(GuidList
, "w+")
896 for Key
in self
._GuidMap
:
897 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
901 from Eot
.Eot
import Eot
904 # Invoke EOT tool and echo its runtime performance
906 EotStartTime
= time
.time()
907 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
908 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
909 EotEndTime
= time
.time()
910 EotDuration
= time
.strftime("%H:%M:%S", time
.gmtime(int(round(EotEndTime
- EotStartTime
))))
911 EdkLogger
.quiet("EOT run time: %s\n" % EotDuration
)
914 # Parse the output of EOT tool
916 for Line
in open(DispatchList
):
917 if len(Line
.split()) < 4:
919 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
920 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
921 if len(Symbol
) > self
.MaxLen
:
922 self
.MaxLen
= len(Symbol
)
923 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
925 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
926 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
930 # Generate platform execution order report
932 # This function generates the predicted module execution order.
934 # @param self The object pointer
935 # @param File The file object for report
937 def _GenerateExecutionOrderReport(self
, File
):
938 self
._InvokeEotTool
()
939 if len(self
.ItemList
) == 0:
941 FileWrite(File
, gSectionStart
)
942 FileWrite(File
, "Execution Order Prediction")
943 FileWrite(File
, "*P PEI phase")
944 FileWrite(File
, "*D DXE phase")
945 FileWrite(File
, "*E Module INF entry point name")
946 FileWrite(File
, "*N Module notification function name")
948 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
949 FileWrite(File
, gSectionSep
)
950 for Item
in self
.ItemList
:
951 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
953 FileWrite(File
, gSectionStart
)
956 # Generate Fixed Address report.
958 # This function generate the predicted fixed address report for a module
961 # @param self The object pointer
962 # @param File The file object for report
963 # @param Guid The module Guid value.
964 # @param NotifyList The list of all notify function in a module
966 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
968 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
969 if not FixedAddressList
:
972 FileWrite(File
, gSubSectionStart
)
973 FileWrite(File
, "Fixed Address Prediction")
974 FileWrite(File
, "*I Image Loading Address")
975 FileWrite(File
, "*E Entry Point Address")
976 FileWrite(File
, "*N Notification Function Address")
977 FileWrite(File
, "*F Flash Address")
978 FileWrite(File
, "*M Memory Address")
979 FileWrite(File
, "*S SMM RAM Offset")
980 FileWrite(File
, "TOM Top of Memory")
982 FileWrite(File
, "Type Address Name")
983 FileWrite(File
, gSubSectionSep
)
984 for Item
in FixedAddressList
:
989 Name
= "(Image Base)"
991 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
992 elif Symbol
in NotifyList
:
1000 elif "Memory" in Type
:
1006 Value
= "TOM" + Value
1008 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
1011 # Generate report for the prediction part
1013 # This function generate the predicted fixed address report for a module or
1014 # predicted module execution order for a platform.
1015 # If the input Guid is None, then, it generates the predicted module execution order;
1016 # otherwise it generated the module fixed loading address for the module specified by
1019 # @param self The object pointer
1020 # @param File The file object for report
1021 # @param Guid The module Guid value.
1023 def GenerateReport(self
, File
, Guid
):
1025 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1027 self
._GenerateExecutionOrderReport
(File
)
1030 # Reports FD region information
1032 # This class reports the FD subsection in the build report file.
1033 # It collects region information of platform flash device.
1034 # If the region is a firmware volume, it lists the set of modules
1035 # and its space information; otherwise, it only lists its region name,
1036 # base address and size in its sub-section header.
1037 # If there are nesting FVs, the nested FVs will list immediate after
1038 # this FD region subsection
1040 class FdRegionReport(object):
1042 # Discover all the nested FV name list.
1044 # This is an internal worker function to discover the all the nested FV information
1045 # in the parent firmware volume. It uses deep first search algorithm recursively to
1046 # find all the FV list name and append them to the list.
1048 # @param self The object pointer
1049 # @param FvName The name of current firmware file system
1050 # @param Wa Workspace context information
1052 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1053 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1054 for Section
in Ffs
.SectionList
:
1056 for FvSection
in Section
.SectionList
:
1057 if FvSection
.FvName
in self
.FvList
:
1059 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1060 self
.FvList
.append(FvSection
.FvName
)
1061 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1062 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1063 except AttributeError:
1067 # Constructor function for class FdRegionReport
1069 # This constructor function generates FdRegionReport object for a specified FdRegion.
1070 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1071 # volume list. This function also collects GUID map in order to dump module identification
1072 # in the final report.
1074 # @param self: The object pointer
1075 # @param FdRegion The current FdRegion object
1076 # @param Wa Workspace context information
1078 def __init__(self
, FdRegion
, Wa
):
1079 self
.Type
= FdRegion
.RegionType
1080 self
.BaseAddress
= FdRegion
.Offset
1081 self
.Size
= FdRegion
.Size
1085 self
._FvDir
= Wa
.FvDir
1088 # If the input FdRegion is not a firmware volume,
1091 if self
.Type
!= "FV":
1095 # Find all nested FVs in the FdRegion
1097 for FvName
in FdRegion
.RegionDataList
:
1098 if FvName
in self
.FvList
:
1100 self
.FvList
.append(FvName
)
1101 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1102 self
._DiscoverNestedFvList
(FvName
, Wa
)
1107 # Collect PCDs declared in DEC files.
1109 for Package
in Wa
.BuildDatabase
.WorkspaceDb
.PackageList
:
1110 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1111 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1112 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1114 # Collect PCDs defined in DSC common section
1116 for Platform
in Wa
.BuildDatabase
.WorkspaceDb
.PlatformList
:
1117 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
1118 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1119 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1122 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1124 self
._GuidsDb
["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"
1125 self
._GuidsDb
["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"
1127 # Add ACPI table storage file
1129 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1131 for Pa
in Wa
.AutoGenObjectList
:
1132 for ModuleKey
in Pa
.Platform
.Modules
:
1133 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1134 InfPath
= os
.path
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1135 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1138 # Collect the GUID map in the FV firmware volume
1140 for FvName
in self
.FvList
:
1141 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1144 # collect GUID map for binary EFI file in FDF file.
1146 Guid
= Ffs
.NameGuid
.upper()
1147 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1149 PcdTokenspace
= Match
.group(1)
1150 PcdToken
= Match
.group(2)
1151 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1152 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1153 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1154 for Section
in Ffs
.SectionList
:
1156 ModuleSectFile
= os
.path
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1157 self
._GuidsDb
[Guid
] = ModuleSectFile
1158 except AttributeError:
1160 except AttributeError:
1165 # Internal worker function to generate report for the FD region
1167 # This internal worker function to generate report for the FD region.
1168 # It the type is firmware volume, it lists offset and module identification.
1170 # @param self The object pointer
1171 # @param File The file object for report
1172 # @param Title The title for the FD subsection
1173 # @param BaseAddress The base address for the FD region
1174 # @param Size The size of the FD region
1175 # @param FvName The FV name if the FD region is a firmware volume
1177 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1178 FileWrite(File
, gSubSectionStart
)
1179 FileWrite(File
, Title
)
1180 FileWrite(File
, "Type: %s" % Type
)
1181 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1183 if self
.Type
== "FV":
1187 FvReportFileName
= os
.path
.join(self
._FvDir
, FvName
+ ".fv.txt")
1190 # Collect size info in the firmware volume.
1192 FvReport
= open(FvReportFileName
).read()
1193 Match
= gFvTotalSizePattern
.search(FvReport
)
1195 FvTotalSize
= int(Match
.group(1), 16)
1196 Match
= gFvTakenSizePattern
.search(FvReport
)
1198 FvTakenSize
= int(Match
.group(1), 16)
1199 FvFreeSize
= FvTotalSize
- FvTakenSize
1201 # Write size information to the report file.
1203 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1204 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1205 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1206 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1207 FileWrite(File
, "Offset Module")
1208 FileWrite(File
, gSubSectionSep
)
1210 # Write module offset and module identification to the report file.
1213 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1214 Guid
= Match
.group(2).upper()
1215 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1216 OffsetList
= OffsetInfo
.keys()
1218 for Offset
in OffsetList
:
1219 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1221 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
1223 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
1224 FileWrite(File
, gSubSectionEnd
)
1227 # Generate report for the FD region
1229 # This function generates report for the FD region.
1231 # @param self The object pointer
1232 # @param File The file object for report
1234 def GenerateReport(self
, File
):
1235 if (len(self
.FvList
) > 0):
1236 for FvItem
in self
.FvList
:
1237 Info
= self
.FvInfo
[FvItem
]
1238 self
._GenerateReport
(File
, Info
[0], "FV", Info
[1], Info
[2], FvItem
)
1240 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
1243 # Reports FD information
1245 # This class reports the FD section in the build report file.
1246 # It collects flash device information for a platform.
1248 class FdReport(object):
1250 # Constructor function for class FdReport
1252 # This constructor function generates FdReport object for a specified
1255 # @param self The object pointer
1256 # @param Fd The current Firmware device object
1257 # @param Wa Workspace context information
1259 def __init__(self
, Fd
, Wa
):
1260 self
.FdName
= Fd
.FdUiName
1261 self
.BaseAddress
= Fd
.BaseAddress
1263 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
1266 # Generate report for the firmware device.
1268 # This function generates report for the firmware device.
1270 # @param self The object pointer
1271 # @param File The file object for report
1273 def GenerateReport(self
, File
):
1274 FileWrite(File
, gSectionStart
)
1275 FileWrite(File
, "Firmware Device (FD)")
1276 FileWrite(File
, "FD Name: %s" % self
.FdName
)
1277 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
1278 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
1279 if len(self
.FdRegionList
) > 0:
1280 FileWrite(File
, gSectionSep
)
1281 for FdRegionItem
in self
.FdRegionList
:
1282 FdRegionItem
.GenerateReport(File
)
1284 FileWrite(File
, gSectionEnd
)
1289 # Reports platform information
1291 # This class reports the whole platform information
1293 class PlatformReport(object):
1295 # Constructor function for class PlatformReport
1297 # This constructor function generates PlatformReport object a platform build.
1298 # It generates report for platform summary, flash, global PCDs and detailed
1299 # module information for modules involved in platform build.
1301 # @param self The object pointer
1302 # @param Wa Workspace context information
1303 # @param MaList The list of modules in the platform build
1305 def __init__(self
, Wa
, MaList
, ReportType
):
1306 self
._WorkspaceDir
= Wa
.WorkspaceDir
1307 self
.PlatformName
= Wa
.Name
1308 self
.PlatformDscPath
= Wa
.Platform
1309 self
.Architectures
= " ".join(Wa
.ArchList
)
1310 self
.ToolChain
= Wa
.ToolChain
1311 self
.Target
= Wa
.BuildTarget
1312 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
1313 self
.BuildEnvironment
= platform
.platform()
1315 self
.PcdReport
= None
1316 if "PCD" in ReportType
:
1317 self
.PcdReport
= PcdReport(Wa
)
1319 self
.FdReportList
= []
1320 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
== None:
1321 for Fd
in Wa
.FdfProfile
.FdDict
:
1322 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
1324 self
.PredictionReport
= None
1325 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
1326 self
.PredictionReport
= PredictionReport(Wa
)
1328 self
.ModuleReportList
= []
1330 self
._IsModuleBuild
= True
1332 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
1334 self
._IsModuleBuild
= False
1335 for Pa
in Wa
.AutoGenObjectList
:
1336 for ModuleKey
in Pa
.Platform
.Modules
:
1337 self
.ModuleReportList
.append(ModuleReport(Pa
.Platform
.Modules
[ModuleKey
].M
, ReportType
))
1342 # Generate report for the whole platform.
1344 # This function generates report for platform information.
1345 # It comprises of platform summary, global PCD, flash and
1346 # module list sections.
1348 # @param self The object pointer
1349 # @param File The file object for report
1350 # @param BuildDuration The total time to build the modules
1351 # @param ReportType The kind of report items in the final report file
1353 def GenerateReport(self
, File
, BuildDuration
, ReportType
):
1354 FileWrite(File
, "Platform Summary")
1355 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
1356 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
1357 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
1358 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
1359 FileWrite(File
, "Target: %s" % self
.Target
)
1360 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
1361 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
1362 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
1363 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
1365 if not self
._IsModuleBuild
:
1366 if "PCD" in ReportType
:
1367 self
.PcdReport
.GenerateReport(File
, None)
1369 if "FLASH" in ReportType
:
1370 for FdReportListItem
in self
.FdReportList
:
1371 FdReportListItem
.GenerateReport(File
)
1373 for ModuleReportItem
in self
.ModuleReportList
:
1374 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, ReportType
)
1376 if not self
._IsModuleBuild
:
1377 if "EXECUTION_ORDER" in ReportType
:
1378 self
.PredictionReport
.GenerateReport(File
, None)
1380 ## BuildReport class
1382 # This base class contain the routines to collect data and then
1383 # applies certain format to the output report
1385 class BuildReport(object):
1387 # Constructor function for class BuildReport
1389 # This constructor function generates BuildReport object a platform build.
1390 # It generates report for platform summary, flash, global PCDs and detailed
1391 # module information for modules involved in platform build.
1393 # @param self The object pointer
1394 # @param ReportFile The file name to save report file
1395 # @param ReportType The kind of report items in the final report file
1397 def __init__(self
, ReportFile
, ReportType
):
1398 self
.ReportFile
= ReportFile
1400 self
.ReportList
= []
1401 self
.ReportType
= []
1403 for ReportTypeItem
in ReportType
:
1404 if ReportTypeItem
not in self
.ReportType
:
1405 self
.ReportType
.append(ReportTypeItem
)
1407 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "FLASH", "FIXED_ADDRESS"]
1409 # Adds platform report to the list
1411 # This function adds a platform report to the final report list.
1413 # @param self The object pointer
1414 # @param Wa Workspace context information
1415 # @param MaList The list of modules in the platform build
1417 def AddPlatformReport(self
, Wa
, MaList
=None):
1419 self
.ReportList
.append((Wa
, MaList
))
1422 # Generates the final report.
1424 # This function generates platform build report. It invokes GenerateReport()
1425 # method for every platform report in the list.
1427 # @param self The object pointer
1428 # @param BuildDuration The total time to build the modules
1430 def GenerateReport(self
, BuildDuration
):
1434 for (Wa
, MaList
) in self
.ReportList
:
1435 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, self
.ReportType
)
1436 SaveFileOnChange(self
.ReportFile
, File
.getvalue(), False)
1437 EdkLogger
.quiet("Build report can be found at %s" % os
.path
.abspath(self
.ReportFile
))
1439 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
1441 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
1442 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1445 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1446 if __name__
== '__main__':