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
)].DefaultValue
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 DscDefaultValue
= self
.FdfPcdSet
.get((Pcd
.TokenCName
, Key
), DscDefaultValue
)
918 InfDefaultValue
= None
920 PcdValue
= DecDefaultValue
922 PcdValue
= DscDefaultValue
923 if ModulePcdSet
!= None:
924 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
926 InfDefault
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
930 BuildOptionMatch
= False
931 if GlobalData
.BuildOptionPcd
:
932 for pcd
in GlobalData
.BuildOptionPcd
:
933 if (Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
) == (pcd
[0], pcd
[1]):
935 BuildOptionMatch
= True
939 if ModulePcdSet
== None:
945 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
946 PcdValueNumber
= int(PcdValue
.strip(), 0)
947 if DecDefaultValue
== None:
950 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
951 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
953 if InfDefaultValue
== None:
956 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
957 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
959 if DscDefaultValue
== None:
962 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
963 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
965 if DecDefaultValue
== None:
968 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
970 if InfDefaultValue
== None:
973 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
975 if DscDefaultValue
== None:
978 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
981 # Report PCD item according to their override relationship
983 if DecMatch
and InfMatch
:
984 FileWrite(File
, ' %-*s: %6s %10s = %-22s' % (self
.MaxLen
, PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
985 elif BuildOptionMatch
:
986 FileWrite(File
, ' *B %-*s: %6s %10s = %-22s' % (self
.MaxLen
, PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
989 if (Pcd
.TokenCName
, Key
) in self
.FdfPcdSet
:
990 FileWrite(File
, ' *F %-*s: %6s %10s = %-22s' % (self
.MaxLen
, PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
992 FileWrite(File
, ' *P %-*s: %6s %10s = %-22s' % (self
.MaxLen
, PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
994 FileWrite(File
, ' *M %-*s: %6s %10s = %-22s' % (self
.MaxLen
, PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
996 if TypeName
in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):
997 for SkuInfo
in Pcd
.SkuInfoList
.values():
998 if TypeName
in ('DYNHII', 'DEXHII'):
999 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
1001 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
1003 if not DscMatch
and DscDefaultValue
!= None:
1004 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', DscDefaultValue
.strip()))
1006 if not InfMatch
and InfDefaultValue
!= None:
1007 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', InfDefaultValue
.strip()))
1009 if not DecMatch
and DecDefaultValue
!= None:
1010 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', DecDefaultValue
.strip()))
1012 if ModulePcdSet
== None:
1013 if not BuildOptionMatch
:
1014 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
1015 for ModulePath
in ModuleOverride
:
1016 ModuleDefault
= ModuleOverride
[ModulePath
]
1017 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
1018 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
1019 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
1021 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
1024 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 19, ModulePath
, ModuleDefault
.strip()))
1026 if ModulePcdSet
== None:
1027 FileWrite(File
, gSectionEnd
)
1029 if not ReportSubType
and ModulePcdSet
:
1030 FileWrite(File
, gSubSectionEnd
)
1035 # Reports platform and module Prediction information
1037 # This class reports the platform execution order prediction section and
1038 # module load fixed address prediction subsection in the build report file.
1040 class PredictionReport(object):
1042 # Constructor function for class PredictionReport
1044 # This constructor function generates PredictionReport object for the platform.
1046 # @param self: The object pointer
1047 # @param Wa Workspace context information
1049 def __init__(self
, Wa
):
1050 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
1051 self
._MapFileParsed
= False
1052 self
._EotToolInvoked
= False
1053 self
._FvDir
= Wa
.FvDir
1054 self
._EotDir
= Wa
.BuildDir
1055 self
._FfsEntryPoint
= {}
1057 self
._SourceList
= []
1058 self
.FixedMapDict
= {}
1063 # Collect all platform reference source files and GUID C Name
1065 for Pa
in Wa
.AutoGenObjectList
:
1066 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
1068 # BASE typed modules are EFI agnostic, so we need not scan
1069 # their source code to find PPI/Protocol produce or consume
1072 if Module
.ModuleType
== "BASE":
1075 # Add module referenced source files
1077 self
._SourceList
.append(str(Module
))
1079 for Source
in Module
.SourceFileList
:
1080 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
1081 self
._SourceList
.append(" " + str(Source
))
1082 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
1083 for IncludeFile
in IncludeList
.values():
1084 self
._SourceList
.append(" " + IncludeFile
)
1086 for Guid
in Module
.PpiList
:
1087 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
1088 for Guid
in Module
.ProtocolList
:
1089 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
1090 for Guid
in Module
.GuidList
:
1091 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
1093 if Module
.Guid
and not Module
.IsLibrary
:
1094 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
1095 if int(str(Module
.AutoGenVersion
), 0) >= 0x00010005:
1096 RealEntryPoint
= "_ModuleEntryPoint"
1098 RealEntryPoint
= EntryPoint
1099 if EntryPoint
== "_ModuleEntryPoint":
1100 CCFlags
= Module
.BuildOption
.get("CC", {}).get("FLAGS", "")
1101 Match
= gGlueLibEntryPoint
.search(CCFlags
)
1103 EntryPoint
= Match
.group(1)
1105 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
1109 # Collect platform firmware volume list as the input of EOT.
1113 for Fd
in Wa
.FdfProfile
.FdDict
:
1114 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
1115 if FdRegion
.RegionType
!= "FV":
1117 for FvName
in FdRegion
.RegionDataList
:
1118 if FvName
in self
._FvList
:
1120 self
._FvList
.append(FvName
)
1121 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1122 for Section
in Ffs
.SectionList
:
1124 for FvSection
in Section
.SectionList
:
1125 if FvSection
.FvName
in self
._FvList
:
1127 self
._FvList
.append(FvSection
.FvName
)
1128 except AttributeError:
1133 # Parse platform fixed address map files
1135 # This function parses the platform final fixed address map file to get
1136 # the database of predicted fixed address for module image base, entry point
1139 # @param self: The object pointer
1141 def _ParseMapFile(self
):
1142 if self
._MapFileParsed
:
1144 self
._MapFileParsed
= True
1145 if os
.path
.isfile(self
._MapFileName
):
1147 FileContents
= open(self
._MapFileName
).read()
1148 for Match
in gMapFileItemPattern
.finditer(FileContents
):
1149 AddressType
= Match
.group(1)
1150 BaseAddress
= Match
.group(2)
1151 EntryPoint
= Match
.group(3)
1152 Guid
= Match
.group(4).upper()
1153 List
= self
.FixedMapDict
.setdefault(Guid
, [])
1154 List
.append((AddressType
, BaseAddress
, "*I"))
1155 List
.append((AddressType
, EntryPoint
, "*E"))
1157 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
1160 # Invokes EOT tool to get the predicted the execution order.
1162 # This function invokes EOT tool to calculate the predicted dispatch order
1164 # @param self: The object pointer
1166 def _InvokeEotTool(self
):
1167 if self
._EotToolInvoked
:
1170 self
._EotToolInvoked
= True
1172 for FvName
in self
._FvList
:
1173 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
1174 if os
.path
.isfile(FvFile
):
1175 FvFileList
.append(FvFile
)
1177 if len(FvFileList
) == 0:
1180 # Write source file list and GUID file list to an intermediate file
1181 # as the input for EOT tool and dispatch List as the output file
1184 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
1185 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
1186 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
1188 TempFile
= open(SourceList
, "w+")
1189 for Item
in self
._SourceList
:
1190 FileWrite(TempFile
, Item
)
1192 TempFile
= open(GuidList
, "w+")
1193 for Key
in self
._GuidMap
:
1194 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
1198 from Eot
.Eot
import Eot
1201 # Invoke EOT tool and echo its runtime performance
1203 EotStartTime
= time
.time()
1204 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
1205 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
1206 EotEndTime
= time
.time()
1207 EotDuration
= time
.strftime("%H:%M:%S", time
.gmtime(int(round(EotEndTime
- EotStartTime
))))
1208 EdkLogger
.quiet("EOT run time: %s\n" % EotDuration
)
1211 # Parse the output of EOT tool
1213 for Line
in open(DispatchList
):
1214 if len(Line
.split()) < 4:
1216 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
1217 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
1218 if len(Symbol
) > self
.MaxLen
:
1219 self
.MaxLen
= len(Symbol
)
1220 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
1222 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1223 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1227 # Generate platform execution order report
1229 # This function generates the predicted module execution order.
1231 # @param self The object pointer
1232 # @param File The file object for report
1234 def _GenerateExecutionOrderReport(self
, File
):
1235 self
._InvokeEotTool
()
1236 if len(self
.ItemList
) == 0:
1238 FileWrite(File
, gSectionStart
)
1239 FileWrite(File
, "Execution Order Prediction")
1240 FileWrite(File
, "*P PEI phase")
1241 FileWrite(File
, "*D DXE phase")
1242 FileWrite(File
, "*E Module INF entry point name")
1243 FileWrite(File
, "*N Module notification function name")
1245 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
1246 FileWrite(File
, gSectionSep
)
1247 for Item
in self
.ItemList
:
1248 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
1250 FileWrite(File
, gSectionStart
)
1253 # Generate Fixed Address report.
1255 # This function generate the predicted fixed address report for a module
1256 # specified by Guid.
1258 # @param self The object pointer
1259 # @param File The file object for report
1260 # @param Guid The module Guid value.
1261 # @param NotifyList The list of all notify function in a module
1263 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
1264 self
._ParseMapFile
()
1265 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
1266 if not FixedAddressList
:
1269 FileWrite(File
, gSubSectionStart
)
1270 FileWrite(File
, "Fixed Address Prediction")
1271 FileWrite(File
, "*I Image Loading Address")
1272 FileWrite(File
, "*E Entry Point Address")
1273 FileWrite(File
, "*N Notification Function Address")
1274 FileWrite(File
, "*F Flash Address")
1275 FileWrite(File
, "*M Memory Address")
1276 FileWrite(File
, "*S SMM RAM Offset")
1277 FileWrite(File
, "TOM Top of Memory")
1279 FileWrite(File
, "Type Address Name")
1280 FileWrite(File
, gSubSectionSep
)
1281 for Item
in FixedAddressList
:
1286 Name
= "(Image Base)"
1287 elif Symbol
== "*E":
1288 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
1289 elif Symbol
in NotifyList
:
1297 elif "Memory" in Type
:
1303 Value
= "TOM" + Value
1305 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
1308 # Generate report for the prediction part
1310 # This function generate the predicted fixed address report for a module or
1311 # predicted module execution order for a platform.
1312 # If the input Guid is None, then, it generates the predicted module execution order;
1313 # otherwise it generated the module fixed loading address for the module specified by
1316 # @param self The object pointer
1317 # @param File The file object for report
1318 # @param Guid The module Guid value.
1320 def GenerateReport(self
, File
, Guid
):
1322 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1324 self
._GenerateExecutionOrderReport
(File
)
1327 # Reports FD region information
1329 # This class reports the FD subsection in the build report file.
1330 # It collects region information of platform flash device.
1331 # If the region is a firmware volume, it lists the set of modules
1332 # and its space information; otherwise, it only lists its region name,
1333 # base address and size in its sub-section header.
1334 # If there are nesting FVs, the nested FVs will list immediate after
1335 # this FD region subsection
1337 class FdRegionReport(object):
1339 # Discover all the nested FV name list.
1341 # This is an internal worker function to discover the all the nested FV information
1342 # in the parent firmware volume. It uses deep first search algorithm recursively to
1343 # find all the FV list name and append them to the list.
1345 # @param self The object pointer
1346 # @param FvName The name of current firmware file system
1347 # @param Wa Workspace context information
1349 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1350 FvDictKey
=FvName
.upper()
1351 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1352 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1353 for Section
in Ffs
.SectionList
:
1355 for FvSection
in Section
.SectionList
:
1356 if FvSection
.FvName
in self
.FvList
:
1358 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1359 self
.FvList
.append(FvSection
.FvName
)
1360 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1361 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1362 except AttributeError:
1366 # Constructor function for class FdRegionReport
1368 # This constructor function generates FdRegionReport object for a specified FdRegion.
1369 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1370 # volume list. This function also collects GUID map in order to dump module identification
1371 # in the final report.
1373 # @param self: The object pointer
1374 # @param FdRegion The current FdRegion object
1375 # @param Wa Workspace context information
1377 def __init__(self
, FdRegion
, Wa
):
1378 self
.Type
= FdRegion
.RegionType
1379 self
.BaseAddress
= FdRegion
.Offset
1380 self
.Size
= FdRegion
.Size
1384 self
._FvDir
= Wa
.FvDir
1387 # If the input FdRegion is not a firmware volume,
1390 if self
.Type
!= "FV":
1394 # Find all nested FVs in the FdRegion
1396 for FvName
in FdRegion
.RegionDataList
:
1397 if FvName
in self
.FvList
:
1399 self
.FvList
.append(FvName
)
1400 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1401 self
._DiscoverNestedFvList
(FvName
, Wa
)
1405 # Collect PCDs declared in DEC files.
1407 for Pa
in Wa
.AutoGenObjectList
:
1408 for Package
in Pa
.PackageList
:
1409 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1410 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1411 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1413 # Collect PCDs defined in DSC file
1415 for arch
in Wa
.ArchList
:
1416 Platform
= Wa
.BuildDatabase
[Wa
.MetaFile
, arch
]
1417 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
1418 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1419 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1422 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1424 self
._GuidsDb
["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"
1425 self
._GuidsDb
["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"
1427 # Add ACPI table storage file
1429 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1431 for Pa
in Wa
.AutoGenObjectList
:
1432 for ModuleKey
in Pa
.Platform
.Modules
:
1433 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1434 InfPath
= mws
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1435 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1438 # Collect the GUID map in the FV firmware volume
1440 for FvName
in self
.FvList
:
1441 FvDictKey
=FvName
.upper()
1442 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1443 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1446 # collect GUID map for binary EFI file in FDF file.
1448 Guid
= Ffs
.NameGuid
.upper()
1449 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1451 PcdTokenspace
= Match
.group(1)
1452 PcdToken
= Match
.group(2)
1453 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1454 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1455 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1456 for Section
in Ffs
.SectionList
:
1458 ModuleSectFile
= mws
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1459 self
._GuidsDb
[Guid
] = ModuleSectFile
1460 except AttributeError:
1462 except AttributeError:
1467 # Internal worker function to generate report for the FD region
1469 # This internal worker function to generate report for the FD region.
1470 # It the type is firmware volume, it lists offset and module identification.
1472 # @param self The object pointer
1473 # @param File The file object for report
1474 # @param Title The title for the FD subsection
1475 # @param BaseAddress The base address for the FD region
1476 # @param Size The size of the FD region
1477 # @param FvName The FV name if the FD region is a firmware volume
1479 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1480 FileWrite(File
, gSubSectionStart
)
1481 FileWrite(File
, Title
)
1482 FileWrite(File
, "Type: %s" % Type
)
1483 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1485 if self
.Type
== "FV":
1489 FvReportFileName
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv.txt")
1492 # Collect size info in the firmware volume.
1494 FvReport
= open(FvReportFileName
).read()
1495 Match
= gFvTotalSizePattern
.search(FvReport
)
1497 FvTotalSize
= int(Match
.group(1), 16)
1498 Match
= gFvTakenSizePattern
.search(FvReport
)
1500 FvTakenSize
= int(Match
.group(1), 16)
1501 FvFreeSize
= FvTotalSize
- FvTakenSize
1503 # Write size information to the report file.
1505 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1506 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1507 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1508 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1509 FileWrite(File
, "Offset Module")
1510 FileWrite(File
, gSubSectionSep
)
1512 # Write module offset and module identification to the report file.
1515 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1516 Guid
= Match
.group(2).upper()
1517 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1518 OffsetList
= OffsetInfo
.keys()
1520 for Offset
in OffsetList
:
1521 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1523 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
1525 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
1526 FileWrite(File
, gSubSectionEnd
)
1529 # Generate report for the FD region
1531 # This function generates report for the FD region.
1533 # @param self The object pointer
1534 # @param File The file object for report
1536 def GenerateReport(self
, File
):
1537 if (len(self
.FvList
) > 0):
1538 for FvItem
in self
.FvList
:
1539 Info
= self
.FvInfo
[FvItem
]
1540 self
._GenerateReport
(File
, Info
[0], "FV", Info
[1], Info
[2], FvItem
)
1542 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
1545 # Reports FD information
1547 # This class reports the FD section in the build report file.
1548 # It collects flash device information for a platform.
1550 class FdReport(object):
1552 # Constructor function for class FdReport
1554 # This constructor function generates FdReport object for a specified
1557 # @param self The object pointer
1558 # @param Fd The current Firmware device object
1559 # @param Wa Workspace context information
1561 def __init__(self
, Fd
, Wa
):
1562 self
.FdName
= Fd
.FdUiName
1563 self
.BaseAddress
= Fd
.BaseAddress
1565 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
1566 self
.FvPath
= os
.path
.join(Wa
.BuildDir
, "FV")
1567 self
.VpdFilePath
= os
.path
.join(self
.FvPath
, "%s.map" % Wa
.Platform
.VpdToolGuid
)
1568 self
.VPDBaseAddress
= 0
1570 self
.VPDInfoList
= []
1571 for index
, FdRegion
in enumerate(Fd
.RegionList
):
1572 if str(FdRegion
.RegionType
) is 'FILE' and Wa
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
1573 self
.VPDBaseAddress
= self
.FdRegionList
[index
].BaseAddress
1574 self
.VPDSize
= self
.FdRegionList
[index
].Size
1577 if os
.path
.isfile(self
.VpdFilePath
):
1578 fd
= open(self
.VpdFilePath
, "r")
1579 Lines
= fd
.readlines()
1582 if len(Line
) == 0 or Line
.startswith("#"):
1585 PcdName
, SkuId
, Offset
, Size
, Value
= Line
.split("#")[0].split("|")
1586 PcdName
, SkuId
, Offset
, Size
, Value
= PcdName
.strip(), SkuId
.strip(), Offset
.strip(), Size
.strip(), Value
.strip()
1587 if Offset
.lower().startswith('0x'):
1588 Offset
= '0x%08X' % (int(Offset
, 16) + self
.VPDBaseAddress
)
1590 Offset
= '0x%08X' % (int(Offset
, 10) + self
.VPDBaseAddress
)
1591 self
.VPDInfoList
.append("%s | %s | %s | %s | %s" % (PcdName
, SkuId
, Offset
, Size
, Value
))
1593 EdkLogger
.error("BuildReport", CODE_ERROR
, "Fail to parse VPD information file %s" % self
.VpdFilePath
)
1597 # Generate report for the firmware device.
1599 # This function generates report for the firmware device.
1601 # @param self The object pointer
1602 # @param File The file object for report
1604 def GenerateReport(self
, File
):
1605 FileWrite(File
, gSectionStart
)
1606 FileWrite(File
, "Firmware Device (FD)")
1607 FileWrite(File
, "FD Name: %s" % self
.FdName
)
1608 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
1609 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
1610 if len(self
.FdRegionList
) > 0:
1611 FileWrite(File
, gSectionSep
)
1612 for FdRegionItem
in self
.FdRegionList
:
1613 FdRegionItem
.GenerateReport(File
)
1615 if len(self
.VPDInfoList
) > 0:
1616 FileWrite(File
, gSubSectionStart
)
1617 FileWrite(File
, "FD VPD Region")
1618 FileWrite(File
, "Base Address: 0x%X" % self
.VPDBaseAddress
)
1619 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.VPDSize
, self
.VPDSize
/ 1024.0))
1620 FileWrite(File
, gSubSectionSep
)
1621 for item
in self
.VPDInfoList
:
1622 FileWrite(File
, item
)
1623 FileWrite(File
, gSubSectionEnd
)
1624 FileWrite(File
, gSectionEnd
)
1629 # Reports platform information
1631 # This class reports the whole platform information
1633 class PlatformReport(object):
1635 # Constructor function for class PlatformReport
1637 # This constructor function generates PlatformReport object a platform build.
1638 # It generates report for platform summary, flash, global PCDs and detailed
1639 # module information for modules involved in platform build.
1641 # @param self The object pointer
1642 # @param Wa Workspace context information
1643 # @param MaList The list of modules in the platform build
1645 def __init__(self
, Wa
, MaList
, ReportType
):
1646 self
._WorkspaceDir
= Wa
.WorkspaceDir
1647 self
.PlatformName
= Wa
.Name
1648 self
.PlatformDscPath
= Wa
.Platform
1649 self
.Architectures
= " ".join(Wa
.ArchList
)
1650 self
.ToolChain
= Wa
.ToolChain
1651 self
.Target
= Wa
.BuildTarget
1652 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
1653 self
.BuildEnvironment
= platform
.platform()
1655 self
.PcdReport
= None
1656 if "PCD" in ReportType
:
1657 self
.PcdReport
= PcdReport(Wa
)
1659 self
.FdReportList
= []
1660 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
== None:
1661 for Fd
in Wa
.FdfProfile
.FdDict
:
1662 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
1664 self
.PredictionReport
= None
1665 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
1666 self
.PredictionReport
= PredictionReport(Wa
)
1668 self
.DepexParser
= None
1669 if "DEPEX" in ReportType
:
1670 self
.DepexParser
= DepexParser(Wa
)
1672 self
.ModuleReportList
= []
1674 self
._IsModuleBuild
= True
1676 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
1678 self
._IsModuleBuild
= False
1679 for Pa
in Wa
.AutoGenObjectList
:
1680 ModuleAutoGenList
= []
1681 for ModuleKey
in Pa
.Platform
.Modules
:
1682 ModuleAutoGenList
.append(Pa
.Platform
.Modules
[ModuleKey
].M
)
1683 if GlobalData
.gFdfParser
!= None:
1684 if Pa
.Arch
in GlobalData
.gFdfParser
.Profile
.InfDict
:
1685 INFList
= GlobalData
.gFdfParser
.Profile
.InfDict
[Pa
.Arch
]
1686 for InfName
in INFList
:
1687 InfClass
= PathClass(NormPath(InfName
), Wa
.WorkspaceDir
, Pa
.Arch
)
1688 Ma
= ModuleAutoGen(Wa
, InfClass
, Pa
.BuildTarget
, Pa
.ToolChain
, Pa
.Arch
, Wa
.MetaFile
)
1691 if Ma
not in ModuleAutoGenList
:
1692 ModuleAutoGenList
.append(Ma
)
1693 for MGen
in ModuleAutoGenList
:
1694 self
.ModuleReportList
.append(ModuleReport(MGen
, ReportType
))
1699 # Generate report for the whole platform.
1701 # This function generates report for platform information.
1702 # It comprises of platform summary, global PCD, flash and
1703 # module list sections.
1705 # @param self The object pointer
1706 # @param File The file object for report
1707 # @param BuildDuration The total time to build the modules
1708 # @param AutoGenTime The total time of AutoGen Phase
1709 # @param MakeTime The total time of Make Phase
1710 # @param GenFdsTime The total time of GenFds Phase
1711 # @param ReportType The kind of report items in the final report file
1713 def GenerateReport(self
, File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, ReportType
):
1714 FileWrite(File
, "Platform Summary")
1715 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
1716 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
1717 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
1718 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
1719 FileWrite(File
, "Target: %s" % self
.Target
)
1720 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
1721 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
1722 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
1724 FileWrite(File
, "AutoGen Duration: %s" % AutoGenTime
)
1726 FileWrite(File
, "Make Duration: %s" % MakeTime
)
1728 FileWrite(File
, "GenFds Duration: %s" % GenFdsTime
)
1729 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
1731 if GlobalData
.MixedPcd
:
1732 FileWrite(File
, gSectionStart
)
1733 FileWrite(File
, "The following PCDs use different access methods:")
1734 FileWrite(File
, gSectionSep
)
1735 for PcdItem
in GlobalData
.MixedPcd
:
1736 FileWrite(File
, "%s.%s" % (str(PcdItem
[1]), str(PcdItem
[0])))
1737 FileWrite(File
, gSectionEnd
)
1739 if not self
._IsModuleBuild
:
1740 if "PCD" in ReportType
:
1741 self
.PcdReport
.GenerateReport(File
, None)
1743 if "FLASH" in ReportType
:
1744 for FdReportListItem
in self
.FdReportList
:
1745 FdReportListItem
.GenerateReport(File
)
1747 for ModuleReportItem
in self
.ModuleReportList
:
1748 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, self
.DepexParser
, ReportType
)
1750 if not self
._IsModuleBuild
:
1751 if "EXECUTION_ORDER" in ReportType
:
1752 self
.PredictionReport
.GenerateReport(File
, None)
1754 ## BuildReport class
1756 # This base class contain the routines to collect data and then
1757 # applies certain format to the output report
1759 class BuildReport(object):
1761 # Constructor function for class BuildReport
1763 # This constructor function generates BuildReport object a platform build.
1764 # It generates report for platform summary, flash, global PCDs and detailed
1765 # module information for modules involved in platform build.
1767 # @param self The object pointer
1768 # @param ReportFile The file name to save report file
1769 # @param ReportType The kind of report items in the final report file
1771 def __init__(self
, ReportFile
, ReportType
):
1772 self
.ReportFile
= ReportFile
1774 self
.ReportList
= []
1775 self
.ReportType
= []
1777 for ReportTypeItem
in ReportType
:
1778 if ReportTypeItem
not in self
.ReportType
:
1779 self
.ReportType
.append(ReportTypeItem
)
1781 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]
1783 # Adds platform report to the list
1785 # This function adds a platform report to the final report list.
1787 # @param self The object pointer
1788 # @param Wa Workspace context information
1789 # @param MaList The list of modules in the platform build
1791 def AddPlatformReport(self
, Wa
, MaList
=None):
1793 self
.ReportList
.append((Wa
, MaList
))
1796 # Generates the final report.
1798 # This function generates platform build report. It invokes GenerateReport()
1799 # method for every platform report in the list.
1801 # @param self The object pointer
1802 # @param BuildDuration The total time to build the modules
1803 # @param AutoGenTime The total time of AutoGen phase
1804 # @param MakeTime The total time of Make phase
1805 # @param GenFdsTime The total time of GenFds phase
1807 def GenerateReport(self
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
):
1811 for (Wa
, MaList
) in self
.ReportList
:
1812 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, self
.ReportType
)
1813 Content
= FileLinesSplit(File
.getvalue(), gLineMaxLength
)
1814 SaveFileOnChange(self
.ReportFile
, Content
, True)
1815 EdkLogger
.quiet("Build report can be found at %s" % os
.path
.abspath(self
.ReportFile
))
1817 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
1819 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
1820 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1823 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1824 if __name__
== '__main__':