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 - 2017, 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.
19 import Common
.LongFilePathOs
as os
30 from datetime
import datetime
31 from StringIO
import StringIO
32 from Common
import EdkLogger
33 from Common
.Misc
import SaveFileOnChange
34 from Common
.Misc
import GuidStructureByteArrayToGuidString
35 from Common
.Misc
import GuidStructureStringToGuidString
36 from Common
.InfClassObject
import gComponentType2ModuleType
37 from Common
.BuildToolError
import FILE_WRITE_FAILURE
38 from Common
.BuildToolError
import CODE_ERROR
39 from Common
.BuildToolError
import COMMAND_FAILURE
40 from Common
.DataType
import TAB_LINE_BREAK
41 from Common
.DataType
import TAB_DEPEX
42 from Common
.DataType
import TAB_SLASH
43 from Common
.DataType
import TAB_SPACE_SPLIT
44 from Common
.DataType
import TAB_BRG_PCD
45 from Common
.DataType
import TAB_BRG_LIBRARY
46 from Common
.DataType
import TAB_BACK_SLASH
47 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
48 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
49 import Common
.GlobalData
as GlobalData
50 from AutoGen
.AutoGen
import ModuleAutoGen
51 from Common
.Misc
import PathClass
52 from Common
.String
import NormPath
54 ## Pattern to extract contents in EDK DXS files
55 gDxsDependencyPattern
= re
.compile(r
"DEPENDENCY_START(.+)DEPENDENCY_END", re
.DOTALL
)
57 ## Pattern to find total FV total size, occupied size in flash report intermediate file
58 gFvTotalSizePattern
= re
.compile(r
"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
59 gFvTakenSizePattern
= re
.compile(r
"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
61 ## Pattern to find module size and time stamp in module summary report intermediate file
62 gModuleSizePattern
= re
.compile(r
"MODULE_SIZE = (\d+)")
63 gTimeStampPattern
= re
.compile(r
"TIME_STAMP = (\d+)")
65 ## Pattern to find GUID value in flash description files
66 gPcdGuidPattern
= re
.compile(r
"PCD\((\w+)[.](\w+)\)")
68 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
69 gOffsetGuidPattern
= re
.compile(r
"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
71 ## Pattern to find module base address and entry point in fixed flash map file
72 gModulePattern
= r
"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
73 gMapFileItemPattern
= re
.compile(gModulePattern
% {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
75 ## Pattern to find all module referenced header files in source files
76 gIncludePattern
= re
.compile(r
'#include\s*["<]([^">]+)[">]')
77 gIncludePattern2
= re
.compile(r
"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
79 ## Pattern to find the entry point for EDK module using EDKII Glue library
80 gGlueLibEntryPoint
= re
.compile(r
"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
82 ## Tags for MaxLength of line in report
85 ## Tags for end of line in report
88 ## Tags for section start, end and separator
89 gSectionStart
= ">" + "=" * (gLineMaxLength
- 2) + "<"
90 gSectionEnd
= "<" + "=" * (gLineMaxLength
- 2) + ">" + "\n"
91 gSectionSep
= "=" * gLineMaxLength
93 ## Tags for subsection start, end and separator
94 gSubSectionStart
= ">" + "-" * (gLineMaxLength
- 2) + "<"
95 gSubSectionEnd
= "<" + "-" * (gLineMaxLength
- 2) + ">"
96 gSubSectionSep
= "-" * gLineMaxLength
99 ## The look up table to map PCD type to pair of report display type and DEC type
101 'FixedAtBuild' : ('FIXED', 'FixedAtBuild'),
102 'PatchableInModule': ('PATCH', 'PatchableInModule'),
103 'FeatureFlag' : ('FLAG', 'FeatureFlag'),
104 'Dynamic' : ('DYN', 'Dynamic'),
105 'DynamicHii' : ('DYNHII', 'Dynamic'),
106 'DynamicVpd' : ('DYNVPD', 'Dynamic'),
107 'DynamicEx' : ('DEX', 'DynamicEx'),
108 'DynamicExHii' : ('DEXHII', 'DynamicEx'),
109 'DynamicExVpd' : ('DEXVPD', 'DynamicEx'),
112 ## The look up table to map module type to driver type
114 'SEC' : '0x3 (SECURITY_CORE)',
115 'PEI_CORE' : '0x4 (PEI_CORE)',
116 'PEIM' : '0x6 (PEIM)',
117 'DXE_CORE' : '0x5 (DXE_CORE)',
118 'DXE_DRIVER' : '0x7 (DRIVER)',
119 'DXE_SAL_DRIVER' : '0x7 (DRIVER)',
120 'DXE_SMM_DRIVER' : '0x7 (DRIVER)',
121 'DXE_RUNTIME_DRIVER': '0x7 (DRIVER)',
122 'UEFI_DRIVER' : '0x7 (DRIVER)',
123 'UEFI_APPLICATION' : '0x9 (APPLICATION)',
124 'SMM_CORE' : '0xD (SMM_CORE)',
125 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
126 'MM_STANDALONE' : '0xE (MM_STANDALONE)',
127 'MM_CORE_STANDALONE' : '0xF (MM_CORE_STANDALONE)'
130 ## The look up table of the supported opcode in the dependency expression binaries
131 gOpCodeList
= ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
134 # Writes a string to the file object.
136 # This function writes a string to the file object and a new line is appended
137 # afterwards. It may optionally wraps the string for better readability.
139 # @File The file object to write
140 # @String The string to be written to the file
141 # @Wrapper Indicates whether to wrap the string
143 def FileWrite(File
, String
, Wrapper
=False):
145 String
= textwrap
.fill(String
, 120)
146 File
.write(String
+ gEndOfLine
)
149 # Find all the header file that the module source directly includes.
151 # This function scans source code to find all header files the module may
152 # include. This is not accurate but very effective to find all the header
153 # file the module might include with #include statement.
155 # @Source The source file name
156 # @IncludePathList The list of include path to find the source file.
157 # @IncludeFiles The dictionary of current found include files.
159 def FindIncludeFiles(Source
, IncludePathList
, IncludeFiles
):
160 FileContents
= open(Source
).read()
162 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
164 for Match
in gIncludePattern
.finditer(FileContents
):
165 FileName
= Match
.group(1).strip()
166 for Dir
in [os
.path
.dirname(Source
)] + IncludePathList
:
167 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
168 if os
.path
.exists(FullFileName
):
169 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
173 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
175 for Match
in gIncludePattern2
.finditer(FileContents
):
177 Type
= Match
.group(1)
178 if "ARCH_PROTOCOL" in Type
:
179 FileName
= "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
180 elif "PROTOCOL" in Type
:
181 FileName
= "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
183 FileName
= "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key
}
185 FileName
= "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key
}
188 for Dir
in IncludePathList
:
189 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
190 if os
.path
.exists(FullFileName
):
191 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
194 ## Split each lines in file
196 # This method is used to split the lines in file to make the length of each line
197 # less than MaxLength.
199 # @param Content The content of file
200 # @param MaxLength The Max Length of the line
202 def FileLinesSplit(Content
=None, MaxLength
=None):
203 ContentList
= Content
.split(TAB_LINE_BREAK
)
206 for Line
in ContentList
:
207 while len(Line
.rstrip()) > MaxLength
:
208 LineSpaceIndex
= Line
.rfind(TAB_SPACE_SPLIT
, 0, MaxLength
)
209 LineSlashIndex
= Line
.rfind(TAB_SLASH
, 0, MaxLength
)
210 LineBackSlashIndex
= Line
.rfind(TAB_BACK_SLASH
, 0, MaxLength
)
211 if max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
) > 0:
212 LineBreakIndex
= max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
)
214 LineBreakIndex
= MaxLength
215 NewContentList
.append(Line
[:LineBreakIndex
])
216 Line
= Line
[LineBreakIndex
:]
218 NewContentList
.append(Line
)
219 for NewLine
in NewContentList
:
220 NewContent
+= NewLine
+ TAB_LINE_BREAK
222 NewContent
= NewContent
.replace(TAB_LINE_BREAK
, gEndOfLine
).replace('\r\r\n', gEndOfLine
)
228 # Parse binary dependency expression section
230 # This utility class parses the dependency expression section and translate the readable
231 # GUID name and value.
233 class DepexParser(object):
235 # Constructor function for class DepexParser
237 # This constructor function collect GUID values so that the readable
238 # GUID name can be translated.
240 # @param self The object pointer
241 # @param Wa Workspace context information
243 def __init__(self
, Wa
):
245 for Pa
in Wa
.AutoGenObjectList
:
246 for Package
in Pa
.PackageList
:
247 for Protocol
in Package
.Protocols
:
248 GuidValue
= GuidStructureStringToGuidString(Package
.Protocols
[Protocol
])
249 self
._GuidDb
[GuidValue
.upper()] = Protocol
250 for Ppi
in Package
.Ppis
:
251 GuidValue
= GuidStructureStringToGuidString(Package
.Ppis
[Ppi
])
252 self
._GuidDb
[GuidValue
.upper()] = Ppi
253 for Guid
in Package
.Guids
:
254 GuidValue
= GuidStructureStringToGuidString(Package
.Guids
[Guid
])
255 self
._GuidDb
[GuidValue
.upper()] = Guid
258 # Parse the binary dependency expression files.
260 # This function parses the binary dependency expression file and translate it
261 # to the instruction list.
263 # @param self The object pointer
264 # @param DepexFileName The file name of binary dependency expression file.
266 def ParseDepexFile(self
, DepexFileName
):
267 DepexFile
= open(DepexFileName
, "rb")
269 OpCode
= DepexFile
.read(1)
271 Statement
= gOpCodeList
[struct
.unpack("B", OpCode
)[0]]
272 if Statement
in ["BEFORE", "AFTER", "PUSH"]:
273 GuidValue
= "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
274 struct
.unpack("=LHHBBBBBBBB", DepexFile
.read(16))
275 GuidString
= self
._GuidDb
.get(GuidValue
, GuidValue
)
276 Statement
= "%s %s" % (Statement
, GuidString
)
277 DepexStatement
.append(Statement
)
278 OpCode
= DepexFile
.read(1)
280 return DepexStatement
283 # Reports library information
285 # This class reports the module library subsection in the build report file.
287 class LibraryReport(object):
289 # Constructor function for class LibraryReport
291 # This constructor function generates LibraryReport object for
294 # @param self The object pointer
295 # @param M Module context information
297 def __init__(self
, M
):
298 self
.LibraryList
= []
299 if int(str(M
.AutoGenVersion
), 0) >= 0x00010005:
300 self
._EdkIIModule
= True
302 self
._EdkIIModule
= False
304 for Lib
in M
.DependentLibraryList
:
305 LibInfPath
= str(Lib
)
306 LibClassList
= Lib
.LibraryClass
[0].LibraryClass
307 LibConstructorList
= Lib
.ConstructorList
308 LibDesstructorList
= Lib
.DestructorList
309 LibDepexList
= Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]
310 for LibAutoGen
in M
.LibraryAutoGenList
:
311 if LibInfPath
== LibAutoGen
.MetaFile
.Path
:
312 LibTime
= LibAutoGen
.BuildTime
314 self
.LibraryList
.append((LibInfPath
, LibClassList
, LibConstructorList
, LibDesstructorList
, LibDepexList
, LibTime
))
317 # Generate report for module library information
319 # This function generates report for the module library.
320 # If the module is EDKII style one, the additional library class, library
321 # constructor/destructor and dependency expression may also be reported.
323 # @param self The object pointer
324 # @param File The file object for report
326 def GenerateReport(self
, File
):
327 if len(self
.LibraryList
) > 0:
328 FileWrite(File
, gSubSectionStart
)
329 FileWrite(File
, TAB_BRG_LIBRARY
)
330 FileWrite(File
, gSubSectionSep
)
331 for LibraryItem
in self
.LibraryList
:
332 LibInfPath
= LibraryItem
[0]
333 FileWrite(File
, LibInfPath
)
336 # Report library class, library constructor and destructor for
337 # EDKII style module.
339 if self
._EdkIIModule
:
340 LibClass
= LibraryItem
[1]
342 LibConstructor
= " ".join(LibraryItem
[2])
344 EdkIILibInfo
+= " C = " + LibConstructor
345 LibDestructor
= " ".join(LibraryItem
[3])
347 EdkIILibInfo
+= " D = " + LibDestructor
348 LibDepex
= " ".join(LibraryItem
[4])
350 EdkIILibInfo
+= " Depex = " + LibDepex
352 EdkIILibInfo
+= " Time = " + LibraryItem
[5]
354 FileWrite(File
, "{%s: %s}" % (LibClass
, EdkIILibInfo
))
356 FileWrite(File
, "{%s}" % LibClass
)
358 FileWrite(File
, gSubSectionEnd
)
361 # Reports dependency expression information
363 # This class reports the module dependency expression subsection in the build report file.
365 class DepexReport(object):
367 # Constructor function for class DepexReport
369 # This constructor function generates DepexReport object for
370 # a module. If the module source contains the DXS file (usually EDK
371 # style module), it uses the dependency in DXS file; otherwise,
372 # it uses the dependency expression from its own INF [Depex] section
373 # and then merges with the ones from its dependent library INF.
375 # @param self The object pointer
376 # @param M Module context information
378 def __init__(self
, M
):
380 self
._DepexFileName
= os
.path
.join(M
.BuildDir
, "OUTPUT", M
.Module
.BaseName
+ ".depex")
381 ModuleType
= M
.ModuleType
383 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
385 if ModuleType
in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "MM_CORE_STANDALONE", "UEFI_APPLICATION"]:
388 for Source
in M
.SourceFileList
:
389 if os
.path
.splitext(Source
.Path
)[1].lower() == ".dxs":
390 Match
= gDxsDependencyPattern
.search(open(Source
.Path
).read())
392 self
.Depex
= Match
.group(1).strip()
396 self
.Depex
= M
.DepexExpressionList
.get(M
.ModuleType
, "")
397 self
.ModuleDepex
= " ".join(M
.Module
.DepexExpression
[M
.Arch
, M
.ModuleType
])
398 if not self
.ModuleDepex
:
399 self
.ModuleDepex
= "(None)"
402 for Lib
in M
.DependentLibraryList
:
403 LibDepex
= " ".join(Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]).strip()
405 LibDepexList
.append("(" + LibDepex
+ ")")
406 self
.LibraryDepex
= " AND ".join(LibDepexList
)
407 if not self
.LibraryDepex
:
408 self
.LibraryDepex
= "(None)"
412 # Generate report for module dependency expression information
414 # This function generates report for the module dependency expression.
416 # @param self The object pointer
417 # @param File The file object for report
418 # @param GlobalDepexParser The platform global Dependency expression parser object
420 def GenerateReport(self
, File
, GlobalDepexParser
):
423 FileWrite(File
, gSubSectionStart
)
424 if os
.path
.isfile(self
._DepexFileName
):
426 DepexStatements
= GlobalDepexParser
.ParseDepexFile(self
._DepexFileName
)
427 FileWrite(File
, "Final Dependency Expression (DEPEX) Instructions")
428 for DepexStatement
in DepexStatements
:
429 FileWrite(File
, " %s" % DepexStatement
)
430 FileWrite(File
, gSubSectionSep
)
432 EdkLogger
.warn(None, "Dependency expression file is corrupted", self
._DepexFileName
)
434 FileWrite(File
, "Dependency Expression (DEPEX) from %s" % self
.Source
)
436 if self
.Source
== "INF":
437 FileWrite(File
, "%s" % self
.Depex
, True)
438 FileWrite(File
, gSubSectionSep
)
439 FileWrite(File
, "From Module INF: %s" % self
.ModuleDepex
, True)
440 FileWrite(File
, "From Library INF: %s" % self
.LibraryDepex
, True)
442 FileWrite(File
, "%s" % self
.Depex
)
443 FileWrite(File
, gSubSectionEnd
)
446 # Reports dependency expression information
448 # This class reports the module build flags subsection in the build report file.
450 class BuildFlagsReport(object):
452 # Constructor function for class BuildFlagsReport
454 # This constructor function generates BuildFlagsReport object for
455 # a module. It reports the build tool chain tag and all relevant
456 # build flags to build the module.
458 # @param self The object pointer
459 # @param M Module context information
461 def __init__(self
, M
):
464 # Add build flags according to source file extension so that
465 # irrelevant ones can be filtered out.
467 for Source
in M
.SourceFileList
:
468 Ext
= os
.path
.splitext(Source
.File
)[1].lower()
469 if Ext
in [".c", ".cc", ".cpp"]:
470 BuildOptions
["CC"] = 1
471 elif Ext
in [".s", ".asm"]:
472 BuildOptions
["PP"] = 1
473 BuildOptions
["ASM"] = 1
474 elif Ext
in [".vfr"]:
475 BuildOptions
["VFRPP"] = 1
476 BuildOptions
["VFR"] = 1
477 elif Ext
in [".dxs"]:
478 BuildOptions
["APP"] = 1
479 BuildOptions
["CC"] = 1
480 elif Ext
in [".asl"]:
481 BuildOptions
["ASLPP"] = 1
482 BuildOptions
["ASL"] = 1
483 elif Ext
in [".aslc"]:
484 BuildOptions
["ASLCC"] = 1
485 BuildOptions
["ASLDLINK"] = 1
486 BuildOptions
["CC"] = 1
487 elif Ext
in [".asm16"]:
488 BuildOptions
["ASMLINK"] = 1
489 BuildOptions
["SLINK"] = 1
490 BuildOptions
["DLINK"] = 1
493 # Save module build flags.
495 self
.ToolChainTag
= M
.ToolChain
497 for Tool
in BuildOptions
:
498 self
.BuildFlags
[Tool
+ "_FLAGS"] = M
.BuildOption
.get(Tool
, {}).get("FLAGS", "")
501 # Generate report for module build flags information
503 # This function generates report for the module build flags expression.
505 # @param self The object pointer
506 # @param File The file object for report
508 def GenerateReport(self
, File
):
509 FileWrite(File
, gSubSectionStart
)
510 FileWrite(File
, "Build Flags")
511 FileWrite(File
, "Tool Chain Tag: %s" % self
.ToolChainTag
)
512 for Tool
in self
.BuildFlags
:
513 FileWrite(File
, gSubSectionSep
)
514 FileWrite(File
, "%s = %s" % (Tool
, self
.BuildFlags
[Tool
]), True)
516 FileWrite(File
, gSubSectionEnd
)
520 # Reports individual module information
522 # This class reports the module section in the build report file.
523 # It comprises of module summary, module PCD, library, dependency expression,
524 # build flags sections.
526 class ModuleReport(object):
528 # Constructor function for class ModuleReport
530 # This constructor function generates ModuleReport object for
531 # a separate module in a platform build.
533 # @param self The object pointer
534 # @param M Module context information
535 # @param ReportType The kind of report items in the final report file
537 def __init__(self
, M
, ReportType
):
538 self
.ModuleName
= M
.Module
.BaseName
539 self
.ModuleInfPath
= M
.MetaFile
.File
540 self
.FileGuid
= M
.Guid
542 self
.BuildTimeStamp
= None
546 ModuleType
= M
.ModuleType
548 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
550 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
552 if ModuleType
== "DXE_SMM_DRIVER":
553 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
554 if int(PiSpec
, 0) >= 0x0001000A:
555 ModuleType
= "SMM_DRIVER"
556 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "0x2 (FREE_FORM)")
557 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
558 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
559 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
560 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
561 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
562 self
.BuildTime
= M
.BuildTime
564 self
._BuildDir
= M
.BuildDir
565 self
.ModulePcdSet
= {}
566 if "PCD" in ReportType
:
568 # Collect all module used PCD set: module INF referenced directly or indirectly.
569 # It also saves module INF default values of them in case they exist.
571 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
572 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
574 self
.LibraryReport
= None
575 if "LIBRARY" in ReportType
:
576 self
.LibraryReport
= LibraryReport(M
)
578 self
.DepexReport
= None
579 if "DEPEX" in ReportType
:
580 self
.DepexReport
= DepexReport(M
)
582 if "BUILD_FLAGS" in ReportType
:
583 self
.BuildFlagsReport
= BuildFlagsReport(M
)
587 # Generate report for module 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 GlobalPcdReport The platform global PCD report object
595 # @param GlobalPredictionReport The platform global Prediction report object
596 # @param GlobalDepexParser The platform global Dependency expression parser object
597 # @param ReportType The kind of report items in the final report file
599 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, GlobalDepexParser
, ReportType
):
600 FileWrite(File
, gSectionStart
)
602 FwReportFileName
= os
.path
.join(self
._BuildDir
, "DEBUG", self
.ModuleName
+ ".txt")
603 if os
.path
.isfile(FwReportFileName
):
605 FileContents
= open(FwReportFileName
).read()
606 Match
= gModuleSizePattern
.search(FileContents
)
608 self
.Size
= int(Match
.group(1))
610 Match
= gTimeStampPattern
.search(FileContents
)
612 self
.BuildTimeStamp
= datetime
.fromtimestamp(int(Match
.group(1)))
614 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
616 if "HASH" in ReportType
:
617 OutputDir
= os
.path
.join(self
._BuildDir
, "OUTPUT")
618 DefaultEFIfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ ".efi")
619 if os
.path
.isfile(DefaultEFIfile
):
620 Tempfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ "_hash.tmp")
621 # rebase the efi image since its base address may not zero
622 cmd
= ["GenFw", "--rebase", str(0), "-o", Tempfile
, DefaultEFIfile
]
624 PopenObject
= subprocess
.Popen(' '.join(cmd
), stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
626 EdkLogger
.error("GenFw", COMMAND_FAILURE
, ExtraData
="%s: %s" % (str(X
), cmd
[0]))
627 EndOfProcedure
= threading
.Event()
628 EndOfProcedure
.clear()
629 if PopenObject
.stderr
:
630 StdErrThread
= threading
.Thread(target
=ReadMessage
, args
=(PopenObject
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
631 StdErrThread
.setName("STDERR-Redirector")
632 StdErrThread
.setDaemon(False)
634 # waiting for program exit
636 if PopenObject
.stderr
:
638 if PopenObject
.returncode
!= 0:
639 EdkLogger
.error("GenFw", COMMAND_FAILURE
, "Failed to generate firmware hash image for %s" % (DefaultEFIfile
))
640 if os
.path
.isfile(Tempfile
):
641 self
.Hash
= hashlib
.sha1()
642 buf
= open(Tempfile
, 'rb').read()
643 if self
.Hash
.update(buf
):
644 self
.Hash
= self
.Hash
.update(buf
)
645 self
.Hash
= self
.Hash
.hexdigest()
648 FileWrite(File
, "Module Summary")
649 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
650 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
651 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
653 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
655 FileWrite(File
, "SHA1 HASH: %s *%s" % (self
.Hash
, self
.ModuleName
+ ".efi"))
656 if self
.BuildTimeStamp
:
657 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
659 FileWrite(File
, "Module Build Time: %s" % self
.BuildTime
)
661 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
662 if self
.UefiSpecVersion
:
663 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
664 if self
.PiSpecVersion
:
665 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
667 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
669 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
670 if self
.PciClassCode
:
671 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
673 FileWrite(File
, gSectionSep
)
675 if "PCD" in ReportType
:
676 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
)
678 if "LIBRARY" in ReportType
:
679 self
.LibraryReport
.GenerateReport(File
)
681 if "DEPEX" in ReportType
:
682 self
.DepexReport
.GenerateReport(File
, GlobalDepexParser
)
684 if "BUILD_FLAGS" in ReportType
:
685 self
.BuildFlagsReport
.GenerateReport(File
)
687 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
688 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
690 FileWrite(File
, gSectionEnd
)
692 def ReadMessage(From
, To
, ExitFlag
):
694 # read one line a time
695 Line
= From
.readline()
696 # empty string means "end"
697 if Line
!= None and Line
!= "":
705 # Reports platform and module PCD information
707 # This class reports the platform PCD section and module PCD subsection
708 # in the build report file.
710 class PcdReport(object):
712 # Constructor function for class PcdReport
714 # This constructor function generates PcdReport object a platform build.
715 # It collects the whole PCD database from platform DSC files, platform
716 # flash description file and package DEC files.
718 # @param self The object pointer
719 # @param Wa Workspace context information
721 def __init__(self
, Wa
):
724 self
.ConditionalPcds
= {}
727 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
731 self
.ModulePcdOverride
= {}
732 for Pa
in Wa
.AutoGenObjectList
:
734 # Collect all platform referenced PCDs and grouped them by PCD token space
737 for Pcd
in Pa
.AllPcdList
:
738 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
739 if Pcd
not in PcdList
:
741 if len(Pcd
.TokenCName
) > self
.MaxLen
:
742 self
.MaxLen
= len(Pcd
.TokenCName
)
744 # Collect the PCD defined in DSC/FDF file, but not used in module
746 UnusedPcdFullList
= []
747 for item
in Pa
.Platform
.Pcds
:
748 Pcd
= Pa
.Platform
.Pcds
[item
]
750 # check the Pcd in FDF file, whether it is used in module first
751 for T
in ["FixedAtBuild", "PatchableInModule", "FeatureFlag", "Dynamic", "DynamicEx"]:
752 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(T
, [])
758 for package
in Pa
.PackageList
:
759 for T
in ["FixedAtBuild", "PatchableInModule", "FeatureFlag", "Dynamic", "DynamicEx"]:
760 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
) in package
.Pcds
:
763 if not Pcd
.DatumType
:
764 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
)].DatumType
768 if not Pcd
.DatumType
:
770 # Try to remove Hii and Vpd suffix
771 if PcdType
.startswith("DynamicEx"):
772 PcdType
= "DynamicEx"
773 elif PcdType
.startswith("Dynamic"):
775 for package
in Pa
.PackageList
:
776 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
) in package
.Pcds
:
777 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
)].DatumType
780 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
781 if Pcd
not in PcdList
and Pcd
not in UnusedPcdFullList
:
782 UnusedPcdFullList
.append(Pcd
)
783 if len(Pcd
.TokenCName
) > self
.MaxLen
:
784 self
.MaxLen
= len(Pcd
.TokenCName
)
786 if GlobalData
.gConditionalPcds
:
787 for PcdItem
in GlobalData
.gConditionalPcds
:
789 (TokenSpaceGuidCName
, TokenCName
) = PcdItem
.split('.')
790 if (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
.keys():
791 Pcd
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)]
792 PcdList
= self
.ConditionalPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
793 if Pcd
not in PcdList
:
797 if UnusedPcdFullList
:
798 for Pcd
in UnusedPcdFullList
:
799 if Pcd
.TokenSpaceGuidCName
+ '.' + Pcd
.TokenCName
in GlobalData
.gConditionalPcds
:
801 UnusedPcdList
.append(Pcd
)
803 for Pcd
in UnusedPcdList
:
804 PcdList
= self
.UnusedPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
805 if Pcd
not in PcdList
:
808 for Module
in Pa
.Platform
.Modules
.values():
810 # Collect module override PCDs
812 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
813 TokenCName
= ModulePcd
.TokenCName
814 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
815 ModuleDefault
= ModulePcd
.DefaultValue
816 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
817 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
821 # Collect PCD DEC default value.
823 self
.DecPcdDefault
= {}
824 for Pa
in Wa
.AutoGenObjectList
:
825 for Package
in Pa
.PackageList
:
826 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
827 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
828 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
830 # Collect PCDs defined in DSC common section
832 self
.DscPcdDefault
= {}
833 for Arch
in Wa
.ArchList
:
834 Platform
= Wa
.BuildDatabase
[Wa
.MetaFile
, Arch
, Wa
.BuildTarget
, Wa
.ToolChain
]
835 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
836 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DscDefaultValue
838 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
840 def GenerateReport(self
, File
, ModulePcdSet
):
841 if self
.ConditionalPcds
:
842 self
.GenerateReportDetail(File
, ModulePcdSet
, 1)
844 self
.GenerateReportDetail(File
, ModulePcdSet
, 2)
845 self
.GenerateReportDetail(File
, ModulePcdSet
)
848 # Generate report for PCD information
850 # This function generates report for separate module expression
851 # in a platform build.
853 # @param self The object pointer
854 # @param File The file object for report
855 # @param ModulePcdSet Set of all PCDs referenced by module or None for
856 # platform PCD report
857 # @param ReportySubType 0 means platform/module PCD report, 1 means Conditional
858 # directives section report, 2 means Unused Pcds section report
859 # @param DscOverridePcds Module DSC override PCDs set
861 def GenerateReportDetail(self
, File
, ModulePcdSet
, ReportSubType
= 0):
862 PcdDict
= self
.AllPcds
863 if ReportSubType
== 1:
864 PcdDict
= self
.ConditionalPcds
865 elif ReportSubType
== 2:
866 PcdDict
= self
.UnusedPcds
868 if ModulePcdSet
== None:
869 FileWrite(File
, gSectionStart
)
870 if ReportSubType
== 1:
871 FileWrite(File
, "Conditional Directives used by the build system")
872 elif ReportSubType
== 2:
873 FileWrite(File
, "PCDs not used by modules or in conditional directives")
875 FileWrite(File
, "Platform Configuration Database Report")
877 FileWrite(File
, " *B - PCD override in the build option")
878 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
879 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
880 if not ReportSubType
:
881 FileWrite(File
, " *M - Module scoped PCD override")
882 FileWrite(File
, gSectionSep
)
884 if not ReportSubType
and ModulePcdSet
:
886 # For module PCD sub-section
888 FileWrite(File
, gSubSectionStart
)
889 FileWrite(File
, TAB_BRG_PCD
)
890 FileWrite(File
, gSubSectionSep
)
894 # Group PCD by their token space GUID C Name
897 for Type
in PcdDict
[Key
]:
899 # Group PCD by their usage type
901 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
902 for Pcd
in PcdDict
[Key
][Type
]:
903 PcdTokenCName
= Pcd
.TokenCName
905 if GlobalData
.MixedPcd
:
906 for PcdKey
in GlobalData
.MixedPcd
:
907 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdKey
]:
908 PcdTokenCName
= PcdKey
[0]
910 if MixedPcdFlag
and not ModulePcdSet
:
913 # Get PCD default value and their override relationship
915 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
916 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
917 DscDefaultValBak
= DscDefaultValue
918 DscDefaultValue
= self
.FdfPcdSet
.get((Pcd
.TokenCName
, Key
), DscDefaultValue
)
919 InfDefaultValue
= None
921 PcdValue
= DecDefaultValue
923 PcdValue
= DscDefaultValue
924 if ModulePcdSet
!= None:
925 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
927 InfDefault
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
931 BuildOptionMatch
= False
932 if GlobalData
.BuildOptionPcd
:
933 for pcd
in GlobalData
.BuildOptionPcd
:
934 if (Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
) == (pcd
[0], pcd
[1]):
936 BuildOptionMatch
= True
940 if ModulePcdSet
== None:
946 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
947 PcdValueNumber
= int(PcdValue
.strip(), 0)
948 if DecDefaultValue
== None:
951 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
952 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
954 if InfDefaultValue
== None:
957 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
958 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
960 if DscDefaultValue
== None:
963 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
964 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
966 if DecDefaultValue
== None:
969 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
971 if InfDefaultValue
== None:
974 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
976 if DscDefaultValue
== None:
979 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
982 # Report PCD item according to their override relationship
984 if DecMatch
and InfMatch
:
985 FileWrite(File
, ' %-*s: %6s %10s = %-22s' % (self
.MaxLen
, PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
986 elif BuildOptionMatch
:
987 FileWrite(File
, ' *B %-*s: %6s %10s = %-22s' % (self
.MaxLen
, PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
990 if (Pcd
.TokenCName
, Key
) in self
.FdfPcdSet
:
991 FileWrite(File
, ' *F %-*s: %6s %10s = %-22s' % (self
.MaxLen
, PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
993 FileWrite(File
, ' *P %-*s: %6s %10s = %-22s' % (self
.MaxLen
, PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
995 FileWrite(File
, ' *M %-*s: %6s %10s = %-22s' % (self
.MaxLen
, PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
997 if TypeName
in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):
998 for SkuInfo
in Pcd
.SkuInfoList
.values():
999 if TypeName
in ('DYNHII', 'DEXHII'):
1000 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
1002 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
1004 if not DscMatch
and DscDefaultValBak
!= None:
1005 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', DscDefaultValBak
.strip()))
1007 if not InfMatch
and InfDefaultValue
!= None:
1008 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', InfDefaultValue
.strip()))
1010 if not DecMatch
and DecDefaultValue
!= None:
1011 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', DecDefaultValue
.strip()))
1013 if ModulePcdSet
== None:
1014 if not BuildOptionMatch
:
1015 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
1016 for ModulePath
in ModuleOverride
:
1017 ModuleDefault
= ModuleOverride
[ModulePath
]
1018 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
1019 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
1020 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
1022 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
1025 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 19, ModulePath
, ModuleDefault
.strip()))
1027 if ModulePcdSet
== None:
1028 FileWrite(File
, gSectionEnd
)
1030 if not ReportSubType
and ModulePcdSet
:
1031 FileWrite(File
, gSubSectionEnd
)
1036 # Reports platform and module Prediction information
1038 # This class reports the platform execution order prediction section and
1039 # module load fixed address prediction subsection in the build report file.
1041 class PredictionReport(object):
1043 # Constructor function for class PredictionReport
1045 # This constructor function generates PredictionReport object for the platform.
1047 # @param self: The object pointer
1048 # @param Wa Workspace context information
1050 def __init__(self
, Wa
):
1051 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
1052 self
._MapFileParsed
= False
1053 self
._EotToolInvoked
= False
1054 self
._FvDir
= Wa
.FvDir
1055 self
._EotDir
= Wa
.BuildDir
1056 self
._FfsEntryPoint
= {}
1058 self
._SourceList
= []
1059 self
.FixedMapDict
= {}
1064 # Collect all platform reference source files and GUID C Name
1066 for Pa
in Wa
.AutoGenObjectList
:
1067 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
1069 # BASE typed modules are EFI agnostic, so we need not scan
1070 # their source code to find PPI/Protocol produce or consume
1073 if Module
.ModuleType
== "BASE":
1076 # Add module referenced source files
1078 self
._SourceList
.append(str(Module
))
1080 for Source
in Module
.SourceFileList
:
1081 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
1082 self
._SourceList
.append(" " + str(Source
))
1083 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
1084 for IncludeFile
in IncludeList
.values():
1085 self
._SourceList
.append(" " + IncludeFile
)
1087 for Guid
in Module
.PpiList
:
1088 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
1089 for Guid
in Module
.ProtocolList
:
1090 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
1091 for Guid
in Module
.GuidList
:
1092 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
1094 if Module
.Guid
and not Module
.IsLibrary
:
1095 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
1096 if int(str(Module
.AutoGenVersion
), 0) >= 0x00010005:
1097 RealEntryPoint
= "_ModuleEntryPoint"
1099 RealEntryPoint
= EntryPoint
1100 if EntryPoint
== "_ModuleEntryPoint":
1101 CCFlags
= Module
.BuildOption
.get("CC", {}).get("FLAGS", "")
1102 Match
= gGlueLibEntryPoint
.search(CCFlags
)
1104 EntryPoint
= Match
.group(1)
1106 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
1110 # Collect platform firmware volume list as the input of EOT.
1114 for Fd
in Wa
.FdfProfile
.FdDict
:
1115 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
1116 if FdRegion
.RegionType
!= "FV":
1118 for FvName
in FdRegion
.RegionDataList
:
1119 if FvName
in self
._FvList
:
1121 self
._FvList
.append(FvName
)
1122 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1123 for Section
in Ffs
.SectionList
:
1125 for FvSection
in Section
.SectionList
:
1126 if FvSection
.FvName
in self
._FvList
:
1128 self
._FvList
.append(FvSection
.FvName
)
1129 except AttributeError:
1134 # Parse platform fixed address map files
1136 # This function parses the platform final fixed address map file to get
1137 # the database of predicted fixed address for module image base, entry point
1140 # @param self: The object pointer
1142 def _ParseMapFile(self
):
1143 if self
._MapFileParsed
:
1145 self
._MapFileParsed
= True
1146 if os
.path
.isfile(self
._MapFileName
):
1148 FileContents
= open(self
._MapFileName
).read()
1149 for Match
in gMapFileItemPattern
.finditer(FileContents
):
1150 AddressType
= Match
.group(1)
1151 BaseAddress
= Match
.group(2)
1152 EntryPoint
= Match
.group(3)
1153 Guid
= Match
.group(4).upper()
1154 List
= self
.FixedMapDict
.setdefault(Guid
, [])
1155 List
.append((AddressType
, BaseAddress
, "*I"))
1156 List
.append((AddressType
, EntryPoint
, "*E"))
1158 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
1161 # Invokes EOT tool to get the predicted the execution order.
1163 # This function invokes EOT tool to calculate the predicted dispatch order
1165 # @param self: The object pointer
1167 def _InvokeEotTool(self
):
1168 if self
._EotToolInvoked
:
1171 self
._EotToolInvoked
= True
1173 for FvName
in self
._FvList
:
1174 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
1175 if os
.path
.isfile(FvFile
):
1176 FvFileList
.append(FvFile
)
1178 if len(FvFileList
) == 0:
1181 # Write source file list and GUID file list to an intermediate file
1182 # as the input for EOT tool and dispatch List as the output file
1185 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
1186 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
1187 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
1189 TempFile
= open(SourceList
, "w+")
1190 for Item
in self
._SourceList
:
1191 FileWrite(TempFile
, Item
)
1193 TempFile
= open(GuidList
, "w+")
1194 for Key
in self
._GuidMap
:
1195 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
1199 from Eot
.Eot
import Eot
1202 # Invoke EOT tool and echo its runtime performance
1204 EotStartTime
= time
.time()
1205 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
1206 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
1207 EotEndTime
= time
.time()
1208 EotDuration
= time
.strftime("%H:%M:%S", time
.gmtime(int(round(EotEndTime
- EotStartTime
))))
1209 EdkLogger
.quiet("EOT run time: %s\n" % EotDuration
)
1212 # Parse the output of EOT tool
1214 for Line
in open(DispatchList
):
1215 if len(Line
.split()) < 4:
1217 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
1218 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
1219 if len(Symbol
) > self
.MaxLen
:
1220 self
.MaxLen
= len(Symbol
)
1221 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
1223 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1224 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1228 # Generate platform execution order report
1230 # This function generates the predicted module execution order.
1232 # @param self The object pointer
1233 # @param File The file object for report
1235 def _GenerateExecutionOrderReport(self
, File
):
1236 self
._InvokeEotTool
()
1237 if len(self
.ItemList
) == 0:
1239 FileWrite(File
, gSectionStart
)
1240 FileWrite(File
, "Execution Order Prediction")
1241 FileWrite(File
, "*P PEI phase")
1242 FileWrite(File
, "*D DXE phase")
1243 FileWrite(File
, "*E Module INF entry point name")
1244 FileWrite(File
, "*N Module notification function name")
1246 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
1247 FileWrite(File
, gSectionSep
)
1248 for Item
in self
.ItemList
:
1249 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
1251 FileWrite(File
, gSectionStart
)
1254 # Generate Fixed Address report.
1256 # This function generate the predicted fixed address report for a module
1257 # specified by Guid.
1259 # @param self The object pointer
1260 # @param File The file object for report
1261 # @param Guid The module Guid value.
1262 # @param NotifyList The list of all notify function in a module
1264 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
1265 self
._ParseMapFile
()
1266 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
1267 if not FixedAddressList
:
1270 FileWrite(File
, gSubSectionStart
)
1271 FileWrite(File
, "Fixed Address Prediction")
1272 FileWrite(File
, "*I Image Loading Address")
1273 FileWrite(File
, "*E Entry Point Address")
1274 FileWrite(File
, "*N Notification Function Address")
1275 FileWrite(File
, "*F Flash Address")
1276 FileWrite(File
, "*M Memory Address")
1277 FileWrite(File
, "*S SMM RAM Offset")
1278 FileWrite(File
, "TOM Top of Memory")
1280 FileWrite(File
, "Type Address Name")
1281 FileWrite(File
, gSubSectionSep
)
1282 for Item
in FixedAddressList
:
1287 Name
= "(Image Base)"
1288 elif Symbol
== "*E":
1289 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
1290 elif Symbol
in NotifyList
:
1298 elif "Memory" in Type
:
1304 Value
= "TOM" + Value
1306 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
1309 # Generate report for the prediction part
1311 # This function generate the predicted fixed address report for a module or
1312 # predicted module execution order for a platform.
1313 # If the input Guid is None, then, it generates the predicted module execution order;
1314 # otherwise it generated the module fixed loading address for the module specified by
1317 # @param self The object pointer
1318 # @param File The file object for report
1319 # @param Guid The module Guid value.
1321 def GenerateReport(self
, File
, Guid
):
1323 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1325 self
._GenerateExecutionOrderReport
(File
)
1328 # Reports FD region information
1330 # This class reports the FD subsection in the build report file.
1331 # It collects region information of platform flash device.
1332 # If the region is a firmware volume, it lists the set of modules
1333 # and its space information; otherwise, it only lists its region name,
1334 # base address and size in its sub-section header.
1335 # If there are nesting FVs, the nested FVs will list immediate after
1336 # this FD region subsection
1338 class FdRegionReport(object):
1340 # Discover all the nested FV name list.
1342 # This is an internal worker function to discover the all the nested FV information
1343 # in the parent firmware volume. It uses deep first search algorithm recursively to
1344 # find all the FV list name and append them to the list.
1346 # @param self The object pointer
1347 # @param FvName The name of current firmware file system
1348 # @param Wa Workspace context information
1350 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1351 FvDictKey
=FvName
.upper()
1352 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1353 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1354 for Section
in Ffs
.SectionList
:
1356 for FvSection
in Section
.SectionList
:
1357 if FvSection
.FvName
in self
.FvList
:
1359 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1360 self
.FvList
.append(FvSection
.FvName
)
1361 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1362 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1363 except AttributeError:
1367 # Constructor function for class FdRegionReport
1369 # This constructor function generates FdRegionReport object for a specified FdRegion.
1370 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1371 # volume list. This function also collects GUID map in order to dump module identification
1372 # in the final report.
1374 # @param self: The object pointer
1375 # @param FdRegion The current FdRegion object
1376 # @param Wa Workspace context information
1378 def __init__(self
, FdRegion
, Wa
):
1379 self
.Type
= FdRegion
.RegionType
1380 self
.BaseAddress
= FdRegion
.Offset
1381 self
.Size
= FdRegion
.Size
1385 self
._FvDir
= Wa
.FvDir
1388 # If the input FdRegion is not a firmware volume,
1391 if self
.Type
!= "FV":
1395 # Find all nested FVs in the FdRegion
1397 for FvName
in FdRegion
.RegionDataList
:
1398 if FvName
in self
.FvList
:
1400 self
.FvList
.append(FvName
)
1401 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1402 self
._DiscoverNestedFvList
(FvName
, Wa
)
1406 # Collect PCDs declared in DEC files.
1408 for Pa
in Wa
.AutoGenObjectList
:
1409 for Package
in Pa
.PackageList
:
1410 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1411 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1412 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1414 # Collect PCDs defined in DSC file
1416 for arch
in Wa
.ArchList
:
1417 Platform
= Wa
.BuildDatabase
[Wa
.MetaFile
, arch
]
1418 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
1419 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1420 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1423 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1425 self
._GuidsDb
["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"
1426 self
._GuidsDb
["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"
1428 # Add ACPI table storage file
1430 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1432 for Pa
in Wa
.AutoGenObjectList
:
1433 for ModuleKey
in Pa
.Platform
.Modules
:
1434 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1435 InfPath
= mws
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1436 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1439 # Collect the GUID map in the FV firmware volume
1441 for FvName
in self
.FvList
:
1442 FvDictKey
=FvName
.upper()
1443 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1444 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1447 # collect GUID map for binary EFI file in FDF file.
1449 Guid
= Ffs
.NameGuid
.upper()
1450 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1452 PcdTokenspace
= Match
.group(1)
1453 PcdToken
= Match
.group(2)
1454 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1455 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1456 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1457 for Section
in Ffs
.SectionList
:
1459 ModuleSectFile
= mws
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1460 self
._GuidsDb
[Guid
] = ModuleSectFile
1461 except AttributeError:
1463 except AttributeError:
1468 # Internal worker function to generate report for the FD region
1470 # This internal worker function to generate report for the FD region.
1471 # It the type is firmware volume, it lists offset and module identification.
1473 # @param self The object pointer
1474 # @param File The file object for report
1475 # @param Title The title for the FD subsection
1476 # @param BaseAddress The base address for the FD region
1477 # @param Size The size of the FD region
1478 # @param FvName The FV name if the FD region is a firmware volume
1480 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1481 FileWrite(File
, gSubSectionStart
)
1482 FileWrite(File
, Title
)
1483 FileWrite(File
, "Type: %s" % Type
)
1484 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1486 if self
.Type
== "FV":
1490 FvReportFileName
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv.txt")
1493 # Collect size info in the firmware volume.
1495 FvReport
= open(FvReportFileName
).read()
1496 Match
= gFvTotalSizePattern
.search(FvReport
)
1498 FvTotalSize
= int(Match
.group(1), 16)
1499 Match
= gFvTakenSizePattern
.search(FvReport
)
1501 FvTakenSize
= int(Match
.group(1), 16)
1502 FvFreeSize
= FvTotalSize
- FvTakenSize
1504 # Write size information to the report file.
1506 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1507 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1508 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1509 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1510 FileWrite(File
, "Offset Module")
1511 FileWrite(File
, gSubSectionSep
)
1513 # Write module offset and module identification to the report file.
1516 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1517 Guid
= Match
.group(2).upper()
1518 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1519 OffsetList
= OffsetInfo
.keys()
1521 for Offset
in OffsetList
:
1522 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1524 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
1526 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
1527 FileWrite(File
, gSubSectionEnd
)
1530 # Generate report for the FD region
1532 # This function generates report for the FD region.
1534 # @param self The object pointer
1535 # @param File The file object for report
1537 def GenerateReport(self
, File
):
1538 if (len(self
.FvList
) > 0):
1539 for FvItem
in self
.FvList
:
1540 Info
= self
.FvInfo
[FvItem
]
1541 self
._GenerateReport
(File
, Info
[0], "FV", Info
[1], Info
[2], FvItem
)
1543 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
1546 # Reports FD information
1548 # This class reports the FD section in the build report file.
1549 # It collects flash device information for a platform.
1551 class FdReport(object):
1553 # Constructor function for class FdReport
1555 # This constructor function generates FdReport object for a specified
1558 # @param self The object pointer
1559 # @param Fd The current Firmware device object
1560 # @param Wa Workspace context information
1562 def __init__(self
, Fd
, Wa
):
1563 self
.FdName
= Fd
.FdUiName
1564 self
.BaseAddress
= Fd
.BaseAddress
1566 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
1567 self
.FvPath
= os
.path
.join(Wa
.BuildDir
, "FV")
1568 self
.VpdFilePath
= os
.path
.join(self
.FvPath
, "%s.map" % Wa
.Platform
.VpdToolGuid
)
1569 self
.VPDBaseAddress
= 0
1571 self
.VPDInfoList
= []
1572 for index
, FdRegion
in enumerate(Fd
.RegionList
):
1573 if str(FdRegion
.RegionType
) is 'FILE' and Wa
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
1574 self
.VPDBaseAddress
= self
.FdRegionList
[index
].BaseAddress
1575 self
.VPDSize
= self
.FdRegionList
[index
].Size
1578 if os
.path
.isfile(self
.VpdFilePath
):
1579 fd
= open(self
.VpdFilePath
, "r")
1580 Lines
= fd
.readlines()
1583 if len(Line
) == 0 or Line
.startswith("#"):
1586 PcdName
, SkuId
, Offset
, Size
, Value
= Line
.split("#")[0].split("|")
1587 PcdName
, SkuId
, Offset
, Size
, Value
= PcdName
.strip(), SkuId
.strip(), Offset
.strip(), Size
.strip(), Value
.strip()
1588 if Offset
.lower().startswith('0x'):
1589 Offset
= '0x%08X' % (int(Offset
, 16) + self
.VPDBaseAddress
)
1591 Offset
= '0x%08X' % (int(Offset
, 10) + self
.VPDBaseAddress
)
1592 self
.VPDInfoList
.append("%s | %s | %s | %s | %s" % (PcdName
, SkuId
, Offset
, Size
, Value
))
1594 EdkLogger
.error("BuildReport", CODE_ERROR
, "Fail to parse VPD information file %s" % self
.VpdFilePath
)
1598 # Generate report for the firmware device.
1600 # This function generates report for the firmware device.
1602 # @param self The object pointer
1603 # @param File The file object for report
1605 def GenerateReport(self
, File
):
1606 FileWrite(File
, gSectionStart
)
1607 FileWrite(File
, "Firmware Device (FD)")
1608 FileWrite(File
, "FD Name: %s" % self
.FdName
)
1609 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
1610 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
1611 if len(self
.FdRegionList
) > 0:
1612 FileWrite(File
, gSectionSep
)
1613 for FdRegionItem
in self
.FdRegionList
:
1614 FdRegionItem
.GenerateReport(File
)
1616 if len(self
.VPDInfoList
) > 0:
1617 FileWrite(File
, gSubSectionStart
)
1618 FileWrite(File
, "FD VPD Region")
1619 FileWrite(File
, "Base Address: 0x%X" % self
.VPDBaseAddress
)
1620 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.VPDSize
, self
.VPDSize
/ 1024.0))
1621 FileWrite(File
, gSubSectionSep
)
1622 for item
in self
.VPDInfoList
:
1623 FileWrite(File
, item
)
1624 FileWrite(File
, gSubSectionEnd
)
1625 FileWrite(File
, gSectionEnd
)
1630 # Reports platform information
1632 # This class reports the whole platform information
1634 class PlatformReport(object):
1636 # Constructor function for class PlatformReport
1638 # This constructor function generates PlatformReport object a platform build.
1639 # It generates report for platform summary, flash, global PCDs and detailed
1640 # module information for modules involved in platform build.
1642 # @param self The object pointer
1643 # @param Wa Workspace context information
1644 # @param MaList The list of modules in the platform build
1646 def __init__(self
, Wa
, MaList
, ReportType
):
1647 self
._WorkspaceDir
= Wa
.WorkspaceDir
1648 self
.PlatformName
= Wa
.Name
1649 self
.PlatformDscPath
= Wa
.Platform
1650 self
.Architectures
= " ".join(Wa
.ArchList
)
1651 self
.ToolChain
= Wa
.ToolChain
1652 self
.Target
= Wa
.BuildTarget
1653 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
1654 self
.BuildEnvironment
= platform
.platform()
1656 self
.PcdReport
= None
1657 if "PCD" in ReportType
:
1658 self
.PcdReport
= PcdReport(Wa
)
1660 self
.FdReportList
= []
1661 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
== None:
1662 for Fd
in Wa
.FdfProfile
.FdDict
:
1663 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
1665 self
.PredictionReport
= None
1666 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
1667 self
.PredictionReport
= PredictionReport(Wa
)
1669 self
.DepexParser
= None
1670 if "DEPEX" in ReportType
:
1671 self
.DepexParser
= DepexParser(Wa
)
1673 self
.ModuleReportList
= []
1675 self
._IsModuleBuild
= True
1677 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
1679 self
._IsModuleBuild
= False
1680 for Pa
in Wa
.AutoGenObjectList
:
1681 ModuleAutoGenList
= []
1682 for ModuleKey
in Pa
.Platform
.Modules
:
1683 ModuleAutoGenList
.append(Pa
.Platform
.Modules
[ModuleKey
].M
)
1684 if GlobalData
.gFdfParser
!= None:
1685 if Pa
.Arch
in GlobalData
.gFdfParser
.Profile
.InfDict
:
1686 INFList
= GlobalData
.gFdfParser
.Profile
.InfDict
[Pa
.Arch
]
1687 for InfName
in INFList
:
1688 InfClass
= PathClass(NormPath(InfName
), Wa
.WorkspaceDir
, Pa
.Arch
)
1689 Ma
= ModuleAutoGen(Wa
, InfClass
, Pa
.BuildTarget
, Pa
.ToolChain
, Pa
.Arch
, Wa
.MetaFile
)
1692 if Ma
not in ModuleAutoGenList
:
1693 ModuleAutoGenList
.append(Ma
)
1694 for MGen
in ModuleAutoGenList
:
1695 self
.ModuleReportList
.append(ModuleReport(MGen
, ReportType
))
1700 # Generate report for the whole platform.
1702 # This function generates report for platform information.
1703 # It comprises of platform summary, global PCD, flash and
1704 # module list sections.
1706 # @param self The object pointer
1707 # @param File The file object for report
1708 # @param BuildDuration The total time to build the modules
1709 # @param AutoGenTime The total time of AutoGen Phase
1710 # @param MakeTime The total time of Make Phase
1711 # @param GenFdsTime The total time of GenFds Phase
1712 # @param ReportType The kind of report items in the final report file
1714 def GenerateReport(self
, File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, ReportType
):
1715 FileWrite(File
, "Platform Summary")
1716 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
1717 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
1718 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
1719 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
1720 FileWrite(File
, "Target: %s" % self
.Target
)
1721 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
1722 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
1723 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
1725 FileWrite(File
, "AutoGen Duration: %s" % AutoGenTime
)
1727 FileWrite(File
, "Make Duration: %s" % MakeTime
)
1729 FileWrite(File
, "GenFds Duration: %s" % GenFdsTime
)
1730 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
1732 if GlobalData
.MixedPcd
:
1733 FileWrite(File
, gSectionStart
)
1734 FileWrite(File
, "The following PCDs use different access methods:")
1735 FileWrite(File
, gSectionSep
)
1736 for PcdItem
in GlobalData
.MixedPcd
:
1737 FileWrite(File
, "%s.%s" % (str(PcdItem
[1]), str(PcdItem
[0])))
1738 FileWrite(File
, gSectionEnd
)
1740 if not self
._IsModuleBuild
:
1741 if "PCD" in ReportType
:
1742 self
.PcdReport
.GenerateReport(File
, None)
1744 if "FLASH" in ReportType
:
1745 for FdReportListItem
in self
.FdReportList
:
1746 FdReportListItem
.GenerateReport(File
)
1748 for ModuleReportItem
in self
.ModuleReportList
:
1749 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, self
.DepexParser
, ReportType
)
1751 if not self
._IsModuleBuild
:
1752 if "EXECUTION_ORDER" in ReportType
:
1753 self
.PredictionReport
.GenerateReport(File
, None)
1755 ## BuildReport class
1757 # This base class contain the routines to collect data and then
1758 # applies certain format to the output report
1760 class BuildReport(object):
1762 # Constructor function for class BuildReport
1764 # This constructor function generates BuildReport object a platform build.
1765 # It generates report for platform summary, flash, global PCDs and detailed
1766 # module information for modules involved in platform build.
1768 # @param self The object pointer
1769 # @param ReportFile The file name to save report file
1770 # @param ReportType The kind of report items in the final report file
1772 def __init__(self
, ReportFile
, ReportType
):
1773 self
.ReportFile
= ReportFile
1775 self
.ReportList
= []
1776 self
.ReportType
= []
1778 for ReportTypeItem
in ReportType
:
1779 if ReportTypeItem
not in self
.ReportType
:
1780 self
.ReportType
.append(ReportTypeItem
)
1782 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]
1784 # Adds platform report to the list
1786 # This function adds a platform report to the final report list.
1788 # @param self The object pointer
1789 # @param Wa Workspace context information
1790 # @param MaList The list of modules in the platform build
1792 def AddPlatformReport(self
, Wa
, MaList
=None):
1794 self
.ReportList
.append((Wa
, MaList
))
1797 # Generates the final report.
1799 # This function generates platform build report. It invokes GenerateReport()
1800 # method for every platform report in the list.
1802 # @param self The object pointer
1803 # @param BuildDuration The total time to build the modules
1804 # @param AutoGenTime The total time of AutoGen phase
1805 # @param MakeTime The total time of Make phase
1806 # @param GenFdsTime The total time of GenFds phase
1808 def GenerateReport(self
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
):
1812 for (Wa
, MaList
) in self
.ReportList
:
1813 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, self
.ReportType
)
1814 Content
= FileLinesSplit(File
.getvalue(), gLineMaxLength
)
1815 SaveFileOnChange(self
.ReportFile
, Content
, True)
1816 EdkLogger
.quiet("Build report can be found at %s" % os
.path
.abspath(self
.ReportFile
))
1818 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
1820 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
1821 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1824 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1825 if __name__
== '__main__':