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 self
.LibraryList
.append((LibInfPath
, LibClassList
, LibConstructorList
, LibDesstructorList
, LibDepexList
))
313 # Generate report for module library information
315 # This function generates report for the module library.
316 # If the module is EDKII style one, the additional library class, library
317 # constructor/destructor and dependency expression may also be reported.
319 # @param self The object pointer
320 # @param File The file object for report
322 def GenerateReport(self
, File
):
323 if len(self
.LibraryList
) > 0:
324 FileWrite(File
, gSubSectionStart
)
325 FileWrite(File
, TAB_BRG_LIBRARY
)
326 FileWrite(File
, gSubSectionSep
)
327 for LibraryItem
in self
.LibraryList
:
328 LibInfPath
= LibraryItem
[0]
329 FileWrite(File
, LibInfPath
)
332 # Report library class, library constructor and destructor for
333 # EDKII style module.
335 if self
._EdkIIModule
:
336 LibClass
= LibraryItem
[1]
338 LibConstructor
= " ".join(LibraryItem
[2])
340 EdkIILibInfo
+= " C = " + LibConstructor
341 LibDestructor
= " ".join(LibraryItem
[3])
343 EdkIILibInfo
+= " D = " + LibDestructor
344 LibDepex
= " ".join(LibraryItem
[4])
346 EdkIILibInfo
+= " Depex = " + LibDepex
348 FileWrite(File
, "{%s: %s}" % (LibClass
, EdkIILibInfo
))
350 FileWrite(File
, "{%s}" % LibClass
)
352 FileWrite(File
, gSubSectionEnd
)
355 # Reports dependency expression information
357 # This class reports the module dependency expression subsection in the build report file.
359 class DepexReport(object):
361 # Constructor function for class DepexReport
363 # This constructor function generates DepexReport object for
364 # a module. If the module source contains the DXS file (usually EDK
365 # style module), it uses the dependency in DXS file; otherwise,
366 # it uses the dependency expression from its own INF [Depex] section
367 # and then merges with the ones from its dependent library INF.
369 # @param self The object pointer
370 # @param M Module context information
372 def __init__(self
, M
):
374 self
._DepexFileName
= os
.path
.join(M
.BuildDir
, "OUTPUT", M
.Module
.BaseName
+ ".depex")
375 ModuleType
= M
.ModuleType
377 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
379 if ModuleType
in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "MM_CORE_STANDALONE", "UEFI_APPLICATION"]:
382 for Source
in M
.SourceFileList
:
383 if os
.path
.splitext(Source
.Path
)[1].lower() == ".dxs":
384 Match
= gDxsDependencyPattern
.search(open(Source
.Path
).read())
386 self
.Depex
= Match
.group(1).strip()
390 self
.Depex
= M
.DepexExpressionList
.get(M
.ModuleType
, "")
391 self
.ModuleDepex
= " ".join(M
.Module
.DepexExpression
[M
.Arch
, M
.ModuleType
])
392 if not self
.ModuleDepex
:
393 self
.ModuleDepex
= "(None)"
396 for Lib
in M
.DependentLibraryList
:
397 LibDepex
= " ".join(Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]).strip()
399 LibDepexList
.append("(" + LibDepex
+ ")")
400 self
.LibraryDepex
= " AND ".join(LibDepexList
)
401 if not self
.LibraryDepex
:
402 self
.LibraryDepex
= "(None)"
406 # Generate report for module dependency expression information
408 # This function generates report for the module dependency expression.
410 # @param self The object pointer
411 # @param File The file object for report
412 # @param GlobalDepexParser The platform global Dependency expression parser object
414 def GenerateReport(self
, File
, GlobalDepexParser
):
417 FileWrite(File
, gSubSectionStart
)
418 if os
.path
.isfile(self
._DepexFileName
):
420 DepexStatements
= GlobalDepexParser
.ParseDepexFile(self
._DepexFileName
)
421 FileWrite(File
, "Final Dependency Expression (DEPEX) Instructions")
422 for DepexStatement
in DepexStatements
:
423 FileWrite(File
, " %s" % DepexStatement
)
424 FileWrite(File
, gSubSectionSep
)
426 EdkLogger
.warn(None, "Dependency expression file is corrupted", self
._DepexFileName
)
428 FileWrite(File
, "Dependency Expression (DEPEX) from %s" % self
.Source
)
430 if self
.Source
== "INF":
431 FileWrite(File
, "%s" % self
.Depex
, True)
432 FileWrite(File
, gSubSectionSep
)
433 FileWrite(File
, "From Module INF: %s" % self
.ModuleDepex
, True)
434 FileWrite(File
, "From Library INF: %s" % self
.LibraryDepex
, True)
436 FileWrite(File
, "%s" % self
.Depex
)
437 FileWrite(File
, gSubSectionEnd
)
440 # Reports dependency expression information
442 # This class reports the module build flags subsection in the build report file.
444 class BuildFlagsReport(object):
446 # Constructor function for class BuildFlagsReport
448 # This constructor function generates BuildFlagsReport object for
449 # a module. It reports the build tool chain tag and all relevant
450 # build flags to build the module.
452 # @param self The object pointer
453 # @param M Module context information
455 def __init__(self
, M
):
458 # Add build flags according to source file extension so that
459 # irrelevant ones can be filtered out.
461 for Source
in M
.SourceFileList
:
462 Ext
= os
.path
.splitext(Source
.File
)[1].lower()
463 if Ext
in [".c", ".cc", ".cpp"]:
464 BuildOptions
["CC"] = 1
465 elif Ext
in [".s", ".asm"]:
466 BuildOptions
["PP"] = 1
467 BuildOptions
["ASM"] = 1
468 elif Ext
in [".vfr"]:
469 BuildOptions
["VFRPP"] = 1
470 BuildOptions
["VFR"] = 1
471 elif Ext
in [".dxs"]:
472 BuildOptions
["APP"] = 1
473 BuildOptions
["CC"] = 1
474 elif Ext
in [".asl"]:
475 BuildOptions
["ASLPP"] = 1
476 BuildOptions
["ASL"] = 1
477 elif Ext
in [".aslc"]:
478 BuildOptions
["ASLCC"] = 1
479 BuildOptions
["ASLDLINK"] = 1
480 BuildOptions
["CC"] = 1
481 elif Ext
in [".asm16"]:
482 BuildOptions
["ASMLINK"] = 1
483 BuildOptions
["SLINK"] = 1
484 BuildOptions
["DLINK"] = 1
487 # Save module build flags.
489 self
.ToolChainTag
= M
.ToolChain
491 for Tool
in BuildOptions
:
492 self
.BuildFlags
[Tool
+ "_FLAGS"] = M
.BuildOption
.get(Tool
, {}).get("FLAGS", "")
495 # Generate report for module build flags information
497 # This function generates report for the module build flags expression.
499 # @param self The object pointer
500 # @param File The file object for report
502 def GenerateReport(self
, File
):
503 FileWrite(File
, gSubSectionStart
)
504 FileWrite(File
, "Build Flags")
505 FileWrite(File
, "Tool Chain Tag: %s" % self
.ToolChainTag
)
506 for Tool
in self
.BuildFlags
:
507 FileWrite(File
, gSubSectionSep
)
508 FileWrite(File
, "%s = %s" % (Tool
, self
.BuildFlags
[Tool
]), True)
510 FileWrite(File
, gSubSectionEnd
)
514 # Reports individual module information
516 # This class reports the module section in the build report file.
517 # It comprises of module summary, module PCD, library, dependency expression,
518 # build flags sections.
520 class ModuleReport(object):
522 # Constructor function for class ModuleReport
524 # This constructor function generates ModuleReport object for
525 # a separate module in a platform build.
527 # @param self The object pointer
528 # @param M Module context information
529 # @param ReportType The kind of report items in the final report file
531 def __init__(self
, M
, ReportType
):
532 self
.ModuleName
= M
.Module
.BaseName
533 self
.ModuleInfPath
= M
.MetaFile
.File
534 self
.FileGuid
= M
.Guid
536 self
.BuildTimeStamp
= None
540 ModuleType
= M
.ModuleType
542 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
544 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
546 if ModuleType
== "DXE_SMM_DRIVER":
547 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
548 if int(PiSpec
, 0) >= 0x0001000A:
549 ModuleType
= "SMM_DRIVER"
550 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "0x2 (FREE_FORM)")
551 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
552 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
553 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
554 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
555 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
557 self
._BuildDir
= M
.BuildDir
558 self
.ModulePcdSet
= {}
559 if "PCD" in ReportType
:
561 # Collect all module used PCD set: module INF referenced directly or indirectly.
562 # It also saves module INF default values of them in case they exist.
564 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
565 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
567 self
.LibraryReport
= None
568 if "LIBRARY" in ReportType
:
569 self
.LibraryReport
= LibraryReport(M
)
571 self
.DepexReport
= None
572 if "DEPEX" in ReportType
:
573 self
.DepexReport
= DepexReport(M
)
575 if "BUILD_FLAGS" in ReportType
:
576 self
.BuildFlagsReport
= BuildFlagsReport(M
)
580 # Generate report for module information
582 # This function generates report for separate module expression
583 # in a platform build.
585 # @param self The object pointer
586 # @param File The file object for report
587 # @param GlobalPcdReport The platform global PCD report object
588 # @param GlobalPredictionReport The platform global Prediction report object
589 # @param GlobalDepexParser The platform global Dependency expression parser object
590 # @param ReportType The kind of report items in the final report file
592 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, GlobalDepexParser
, ReportType
):
593 FileWrite(File
, gSectionStart
)
595 FwReportFileName
= os
.path
.join(self
._BuildDir
, "DEBUG", self
.ModuleName
+ ".txt")
596 if os
.path
.isfile(FwReportFileName
):
598 FileContents
= open(FwReportFileName
).read()
599 Match
= gModuleSizePattern
.search(FileContents
)
601 self
.Size
= int(Match
.group(1))
603 Match
= gTimeStampPattern
.search(FileContents
)
605 self
.BuildTimeStamp
= datetime
.fromtimestamp(int(Match
.group(1)))
607 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
609 if "HASH" in ReportType
:
610 OutputDir
= os
.path
.join(self
._BuildDir
, "OUTPUT")
611 DefaultEFIfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ ".efi")
612 if os
.path
.isfile(DefaultEFIfile
):
613 Tempfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ "_hash.tmp")
614 # rebase the efi image since its base address may not zero
615 cmd
= ["GenFw", "--rebase", str(0), "-o", Tempfile
, DefaultEFIfile
]
617 PopenObject
= subprocess
.Popen(' '.join(cmd
), stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
619 EdkLogger
.error("GenFw", COMMAND_FAILURE
, ExtraData
="%s: %s" % (str(X
), cmd
[0]))
620 EndOfProcedure
= threading
.Event()
621 EndOfProcedure
.clear()
622 if PopenObject
.stderr
:
623 StdErrThread
= threading
.Thread(target
=ReadMessage
, args
=(PopenObject
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
624 StdErrThread
.setName("STDERR-Redirector")
625 StdErrThread
.setDaemon(False)
627 # waiting for program exit
629 if PopenObject
.stderr
:
631 if PopenObject
.returncode
!= 0:
632 EdkLogger
.error("GenFw", COMMAND_FAILURE
, "Failed to generate firmware hash image for %s" % (DefaultEFIfile
))
633 if os
.path
.isfile(Tempfile
):
634 self
.Hash
= hashlib
.sha1()
635 buf
= open(Tempfile
, 'rb').read()
636 if self
.Hash
.update(buf
):
637 self
.Hash
= self
.Hash
.update(buf
)
638 self
.Hash
= self
.Hash
.hexdigest()
641 FileWrite(File
, "Module Summary")
642 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
643 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
644 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
646 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
648 FileWrite(File
, "SHA1 HASH: %s *%s" % (self
.Hash
, self
.ModuleName
+ ".efi"))
649 if self
.BuildTimeStamp
:
650 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
652 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
653 if self
.UefiSpecVersion
:
654 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
655 if self
.PiSpecVersion
:
656 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
658 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
660 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
661 if self
.PciClassCode
:
662 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
664 FileWrite(File
, gSectionSep
)
666 if "PCD" in ReportType
:
667 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
)
669 if "LIBRARY" in ReportType
:
670 self
.LibraryReport
.GenerateReport(File
)
672 if "DEPEX" in ReportType
:
673 self
.DepexReport
.GenerateReport(File
, GlobalDepexParser
)
675 if "BUILD_FLAGS" in ReportType
:
676 self
.BuildFlagsReport
.GenerateReport(File
)
678 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
679 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
681 FileWrite(File
, gSectionEnd
)
683 def ReadMessage(From
, To
, ExitFlag
):
685 # read one line a time
686 Line
= From
.readline()
687 # empty string means "end"
688 if Line
!= None and Line
!= "":
696 # Reports platform and module PCD information
698 # This class reports the platform PCD section and module PCD subsection
699 # in the build report file.
701 class PcdReport(object):
703 # Constructor function for class PcdReport
705 # This constructor function generates PcdReport object a platform build.
706 # It collects the whole PCD database from platform DSC files, platform
707 # flash description file and package DEC files.
709 # @param self The object pointer
710 # @param Wa Workspace context information
712 def __init__(self
, Wa
):
715 self
.ConditionalPcds
= {}
718 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
722 self
.ModulePcdOverride
= {}
723 for Pa
in Wa
.AutoGenObjectList
:
725 # Collect all platform referenced PCDs and grouped them by PCD token space
728 for Pcd
in Pa
.AllPcdList
:
729 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
730 if Pcd
not in PcdList
:
732 if len(Pcd
.TokenCName
) > self
.MaxLen
:
733 self
.MaxLen
= len(Pcd
.TokenCName
)
735 # Collect the PCD defined in DSC/FDF file, but not used in module
737 UnusedPcdFullList
= []
738 for item
in Pa
.Platform
.Pcds
:
739 Pcd
= Pa
.Platform
.Pcds
[item
]
741 # check the Pcd in FDF file, whether it is used in module first
742 for T
in ["FixedAtBuild", "PatchableInModule", "FeatureFlag", "Dynamic", "DynamicEx"]:
743 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(T
, [])
749 for package
in Pa
.PackageList
:
750 for T
in ["FixedAtBuild", "PatchableInModule", "FeatureFlag", "Dynamic", "DynamicEx"]:
751 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
) in package
.Pcds
:
754 if not Pcd
.DatumType
:
755 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
)].DatumType
759 if not Pcd
.DatumType
:
761 # Try to remove Hii and Vpd suffix
762 if PcdType
.startswith("DynamicEx"):
763 PcdType
= "DynamicEx"
764 elif PcdType
.startswith("Dynamic"):
766 for package
in Pa
.PackageList
:
767 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
) in package
.Pcds
:
768 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
)].DatumType
771 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
772 if Pcd
not in PcdList
and Pcd
not in UnusedPcdFullList
:
773 UnusedPcdFullList
.append(Pcd
)
774 if len(Pcd
.TokenCName
) > self
.MaxLen
:
775 self
.MaxLen
= len(Pcd
.TokenCName
)
777 if GlobalData
.gConditionalPcds
:
778 for PcdItem
in GlobalData
.gConditionalPcds
:
780 (TokenSpaceGuidCName
, TokenCName
) = PcdItem
.split('.')
781 if (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
.keys():
782 Pcd
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)]
783 PcdList
= self
.ConditionalPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
784 if Pcd
not in PcdList
:
788 if UnusedPcdFullList
:
789 for Pcd
in UnusedPcdFullList
:
790 if Pcd
.TokenSpaceGuidCName
+ '.' + Pcd
.TokenCName
in GlobalData
.gConditionalPcds
:
792 UnusedPcdList
.append(Pcd
)
794 for Pcd
in UnusedPcdList
:
795 PcdList
= self
.UnusedPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
796 if Pcd
not in PcdList
:
799 for Module
in Pa
.Platform
.Modules
.values():
801 # Collect module override PCDs
803 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
804 TokenCName
= ModulePcd
.TokenCName
805 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
806 ModuleDefault
= ModulePcd
.DefaultValue
807 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
808 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
812 # Collect PCD DEC default value.
814 self
.DecPcdDefault
= {}
815 for Pa
in Wa
.AutoGenObjectList
:
816 for Package
in Pa
.PackageList
:
817 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
818 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
819 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
821 # Collect PCDs defined in DSC common section
823 self
.DscPcdDefault
= {}
824 for Arch
in Wa
.ArchList
:
825 Platform
= Wa
.BuildDatabase
[Wa
.MetaFile
, Arch
, Wa
.BuildTarget
, Wa
.ToolChain
]
826 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
827 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
829 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
831 def GenerateReport(self
, File
, ModulePcdSet
):
832 if self
.ConditionalPcds
:
833 self
.GenerateReportDetail(File
, ModulePcdSet
, 1)
835 self
.GenerateReportDetail(File
, ModulePcdSet
, 2)
836 self
.GenerateReportDetail(File
, ModulePcdSet
)
839 # Generate report for PCD information
841 # This function generates report for separate module expression
842 # in a platform build.
844 # @param self The object pointer
845 # @param File The file object for report
846 # @param ModulePcdSet Set of all PCDs referenced by module or None for
847 # platform PCD report
848 # @param ReportySubType 0 means platform/module PCD report, 1 means Conditional
849 # directives section report, 2 means Unused Pcds section report
850 # @param DscOverridePcds Module DSC override PCDs set
852 def GenerateReportDetail(self
, File
, ModulePcdSet
, ReportSubType
= 0):
853 PcdDict
= self
.AllPcds
854 if ReportSubType
== 1:
855 PcdDict
= self
.ConditionalPcds
856 elif ReportSubType
== 2:
857 PcdDict
= self
.UnusedPcds
859 if ModulePcdSet
== None:
860 FileWrite(File
, gSectionStart
)
861 if ReportSubType
== 1:
862 FileWrite(File
, "Conditional Directives used by the build system")
863 elif ReportSubType
== 2:
864 FileWrite(File
, "PCDs not used by modules or in conditional directives")
866 FileWrite(File
, "Platform Configuration Database Report")
868 FileWrite(File
, " *B - PCD override in the build option")
869 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
870 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
871 if not ReportSubType
:
872 FileWrite(File
, " *M - Module scoped PCD override")
873 FileWrite(File
, gSectionSep
)
875 if not ReportSubType
and ModulePcdSet
:
877 # For module PCD sub-section
879 FileWrite(File
, gSubSectionStart
)
880 FileWrite(File
, TAB_BRG_PCD
)
881 FileWrite(File
, gSubSectionSep
)
885 # Group PCD by their token space GUID C Name
888 for Type
in PcdDict
[Key
]:
890 # Group PCD by their usage type
892 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
893 for Pcd
in PcdDict
[Key
][Type
]:
894 PcdTokenCName
= Pcd
.TokenCName
896 if GlobalData
.MixedPcd
:
897 for PcdKey
in GlobalData
.MixedPcd
:
898 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdKey
]:
899 PcdTokenCName
= PcdKey
[0]
901 if MixedPcdFlag
and not ModulePcdSet
:
904 # Get PCD default value and their override relationship
906 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
907 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
908 DscDefaultValue
= self
.FdfPcdSet
.get((Pcd
.TokenCName
, Key
), DscDefaultValue
)
909 InfDefaultValue
= None
911 PcdValue
= DecDefaultValue
913 PcdValue
= DscDefaultValue
914 if ModulePcdSet
!= None:
915 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
917 InfDefault
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
921 BuildOptionMatch
= False
922 if GlobalData
.BuildOptionPcd
:
923 for pcd
in GlobalData
.BuildOptionPcd
:
924 if (Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
) == (pcd
[0], pcd
[1]):
926 BuildOptionMatch
= True
930 if ModulePcdSet
== None:
936 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
937 PcdValueNumber
= int(PcdValue
.strip(), 0)
938 if DecDefaultValue
== None:
941 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
942 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
944 if InfDefaultValue
== None:
947 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
948 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
950 if DscDefaultValue
== None:
953 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
954 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
956 if DecDefaultValue
== None:
959 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
961 if InfDefaultValue
== None:
964 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
966 if DscDefaultValue
== None:
969 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
972 # Report PCD item according to their override relationship
974 if DecMatch
and InfMatch
:
975 FileWrite(File
, ' %-*s: %6s %10s = %-22s' % (self
.MaxLen
, PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
976 elif BuildOptionMatch
:
977 FileWrite(File
, ' *B %-*s: %6s %10s = %-22s' % (self
.MaxLen
, PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
980 if (Pcd
.TokenCName
, Key
) in self
.FdfPcdSet
:
981 FileWrite(File
, ' *F %-*s: %6s %10s = %-22s' % (self
.MaxLen
, PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
983 FileWrite(File
, ' *P %-*s: %6s %10s = %-22s' % (self
.MaxLen
, PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
985 FileWrite(File
, ' *M %-*s: %6s %10s = %-22s' % (self
.MaxLen
, PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
987 if TypeName
in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):
988 for SkuInfo
in Pcd
.SkuInfoList
.values():
989 if TypeName
in ('DYNHII', 'DEXHII'):
990 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
992 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
994 if not DscMatch
and DscDefaultValue
!= None:
995 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', DscDefaultValue
.strip()))
997 if not InfMatch
and InfDefaultValue
!= None:
998 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', InfDefaultValue
.strip()))
1000 if not DecMatch
and DecDefaultValue
!= None:
1001 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', DecDefaultValue
.strip()))
1003 if ModulePcdSet
== None:
1004 if not BuildOptionMatch
:
1005 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
1006 for ModulePath
in ModuleOverride
:
1007 ModuleDefault
= ModuleOverride
[ModulePath
]
1008 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
1009 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
1010 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
1012 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
1015 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 19, ModulePath
, ModuleDefault
.strip()))
1017 if ModulePcdSet
== None:
1018 FileWrite(File
, gSectionEnd
)
1020 if not ReportSubType
and ModulePcdSet
:
1021 FileWrite(File
, gSubSectionEnd
)
1026 # Reports platform and module Prediction information
1028 # This class reports the platform execution order prediction section and
1029 # module load fixed address prediction subsection in the build report file.
1031 class PredictionReport(object):
1033 # Constructor function for class PredictionReport
1035 # This constructor function generates PredictionReport object for the platform.
1037 # @param self: The object pointer
1038 # @param Wa Workspace context information
1040 def __init__(self
, Wa
):
1041 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
1042 self
._MapFileParsed
= False
1043 self
._EotToolInvoked
= False
1044 self
._FvDir
= Wa
.FvDir
1045 self
._EotDir
= Wa
.BuildDir
1046 self
._FfsEntryPoint
= {}
1048 self
._SourceList
= []
1049 self
.FixedMapDict
= {}
1054 # Collect all platform reference source files and GUID C Name
1056 for Pa
in Wa
.AutoGenObjectList
:
1057 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
1059 # BASE typed modules are EFI agnostic, so we need not scan
1060 # their source code to find PPI/Protocol produce or consume
1063 if Module
.ModuleType
== "BASE":
1066 # Add module referenced source files
1068 self
._SourceList
.append(str(Module
))
1070 for Source
in Module
.SourceFileList
:
1071 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
1072 self
._SourceList
.append(" " + str(Source
))
1073 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
1074 for IncludeFile
in IncludeList
.values():
1075 self
._SourceList
.append(" " + IncludeFile
)
1077 for Guid
in Module
.PpiList
:
1078 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
1079 for Guid
in Module
.ProtocolList
:
1080 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
1081 for Guid
in Module
.GuidList
:
1082 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
1084 if Module
.Guid
and not Module
.IsLibrary
:
1085 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
1086 if int(str(Module
.AutoGenVersion
), 0) >= 0x00010005:
1087 RealEntryPoint
= "_ModuleEntryPoint"
1089 RealEntryPoint
= EntryPoint
1090 if EntryPoint
== "_ModuleEntryPoint":
1091 CCFlags
= Module
.BuildOption
.get("CC", {}).get("FLAGS", "")
1092 Match
= gGlueLibEntryPoint
.search(CCFlags
)
1094 EntryPoint
= Match
.group(1)
1096 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
1100 # Collect platform firmware volume list as the input of EOT.
1104 for Fd
in Wa
.FdfProfile
.FdDict
:
1105 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
1106 if FdRegion
.RegionType
!= "FV":
1108 for FvName
in FdRegion
.RegionDataList
:
1109 if FvName
in self
._FvList
:
1111 self
._FvList
.append(FvName
)
1112 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1113 for Section
in Ffs
.SectionList
:
1115 for FvSection
in Section
.SectionList
:
1116 if FvSection
.FvName
in self
._FvList
:
1118 self
._FvList
.append(FvSection
.FvName
)
1119 except AttributeError:
1124 # Parse platform fixed address map files
1126 # This function parses the platform final fixed address map file to get
1127 # the database of predicted fixed address for module image base, entry point
1130 # @param self: The object pointer
1132 def _ParseMapFile(self
):
1133 if self
._MapFileParsed
:
1135 self
._MapFileParsed
= True
1136 if os
.path
.isfile(self
._MapFileName
):
1138 FileContents
= open(self
._MapFileName
).read()
1139 for Match
in gMapFileItemPattern
.finditer(FileContents
):
1140 AddressType
= Match
.group(1)
1141 BaseAddress
= Match
.group(2)
1142 EntryPoint
= Match
.group(3)
1143 Guid
= Match
.group(4).upper()
1144 List
= self
.FixedMapDict
.setdefault(Guid
, [])
1145 List
.append((AddressType
, BaseAddress
, "*I"))
1146 List
.append((AddressType
, EntryPoint
, "*E"))
1148 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
1151 # Invokes EOT tool to get the predicted the execution order.
1153 # This function invokes EOT tool to calculate the predicted dispatch order
1155 # @param self: The object pointer
1157 def _InvokeEotTool(self
):
1158 if self
._EotToolInvoked
:
1161 self
._EotToolInvoked
= True
1163 for FvName
in self
._FvList
:
1164 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
1165 if os
.path
.isfile(FvFile
):
1166 FvFileList
.append(FvFile
)
1168 if len(FvFileList
) == 0:
1171 # Write source file list and GUID file list to an intermediate file
1172 # as the input for EOT tool and dispatch List as the output file
1175 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
1176 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
1177 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
1179 TempFile
= open(SourceList
, "w+")
1180 for Item
in self
._SourceList
:
1181 FileWrite(TempFile
, Item
)
1183 TempFile
= open(GuidList
, "w+")
1184 for Key
in self
._GuidMap
:
1185 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
1189 from Eot
.Eot
import Eot
1192 # Invoke EOT tool and echo its runtime performance
1194 EotStartTime
= time
.time()
1195 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
1196 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
1197 EotEndTime
= time
.time()
1198 EotDuration
= time
.strftime("%H:%M:%S", time
.gmtime(int(round(EotEndTime
- EotStartTime
))))
1199 EdkLogger
.quiet("EOT run time: %s\n" % EotDuration
)
1202 # Parse the output of EOT tool
1204 for Line
in open(DispatchList
):
1205 if len(Line
.split()) < 4:
1207 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
1208 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
1209 if len(Symbol
) > self
.MaxLen
:
1210 self
.MaxLen
= len(Symbol
)
1211 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
1213 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1214 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1218 # Generate platform execution order report
1220 # This function generates the predicted module execution order.
1222 # @param self The object pointer
1223 # @param File The file object for report
1225 def _GenerateExecutionOrderReport(self
, File
):
1226 self
._InvokeEotTool
()
1227 if len(self
.ItemList
) == 0:
1229 FileWrite(File
, gSectionStart
)
1230 FileWrite(File
, "Execution Order Prediction")
1231 FileWrite(File
, "*P PEI phase")
1232 FileWrite(File
, "*D DXE phase")
1233 FileWrite(File
, "*E Module INF entry point name")
1234 FileWrite(File
, "*N Module notification function name")
1236 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
1237 FileWrite(File
, gSectionSep
)
1238 for Item
in self
.ItemList
:
1239 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
1241 FileWrite(File
, gSectionStart
)
1244 # Generate Fixed Address report.
1246 # This function generate the predicted fixed address report for a module
1247 # specified by Guid.
1249 # @param self The object pointer
1250 # @param File The file object for report
1251 # @param Guid The module Guid value.
1252 # @param NotifyList The list of all notify function in a module
1254 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
1255 self
._ParseMapFile
()
1256 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
1257 if not FixedAddressList
:
1260 FileWrite(File
, gSubSectionStart
)
1261 FileWrite(File
, "Fixed Address Prediction")
1262 FileWrite(File
, "*I Image Loading Address")
1263 FileWrite(File
, "*E Entry Point Address")
1264 FileWrite(File
, "*N Notification Function Address")
1265 FileWrite(File
, "*F Flash Address")
1266 FileWrite(File
, "*M Memory Address")
1267 FileWrite(File
, "*S SMM RAM Offset")
1268 FileWrite(File
, "TOM Top of Memory")
1270 FileWrite(File
, "Type Address Name")
1271 FileWrite(File
, gSubSectionSep
)
1272 for Item
in FixedAddressList
:
1277 Name
= "(Image Base)"
1278 elif Symbol
== "*E":
1279 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
1280 elif Symbol
in NotifyList
:
1288 elif "Memory" in Type
:
1294 Value
= "TOM" + Value
1296 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
1299 # Generate report for the prediction part
1301 # This function generate the predicted fixed address report for a module or
1302 # predicted module execution order for a platform.
1303 # If the input Guid is None, then, it generates the predicted module execution order;
1304 # otherwise it generated the module fixed loading address for the module specified by
1307 # @param self The object pointer
1308 # @param File The file object for report
1309 # @param Guid The module Guid value.
1311 def GenerateReport(self
, File
, Guid
):
1313 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1315 self
._GenerateExecutionOrderReport
(File
)
1318 # Reports FD region information
1320 # This class reports the FD subsection in the build report file.
1321 # It collects region information of platform flash device.
1322 # If the region is a firmware volume, it lists the set of modules
1323 # and its space information; otherwise, it only lists its region name,
1324 # base address and size in its sub-section header.
1325 # If there are nesting FVs, the nested FVs will list immediate after
1326 # this FD region subsection
1328 class FdRegionReport(object):
1330 # Discover all the nested FV name list.
1332 # This is an internal worker function to discover the all the nested FV information
1333 # in the parent firmware volume. It uses deep first search algorithm recursively to
1334 # find all the FV list name and append them to the list.
1336 # @param self The object pointer
1337 # @param FvName The name of current firmware file system
1338 # @param Wa Workspace context information
1340 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1341 FvDictKey
=FvName
.upper()
1342 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1343 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1344 for Section
in Ffs
.SectionList
:
1346 for FvSection
in Section
.SectionList
:
1347 if FvSection
.FvName
in self
.FvList
:
1349 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1350 self
.FvList
.append(FvSection
.FvName
)
1351 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1352 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1353 except AttributeError:
1357 # Constructor function for class FdRegionReport
1359 # This constructor function generates FdRegionReport object for a specified FdRegion.
1360 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1361 # volume list. This function also collects GUID map in order to dump module identification
1362 # in the final report.
1364 # @param self: The object pointer
1365 # @param FdRegion The current FdRegion object
1366 # @param Wa Workspace context information
1368 def __init__(self
, FdRegion
, Wa
):
1369 self
.Type
= FdRegion
.RegionType
1370 self
.BaseAddress
= FdRegion
.Offset
1371 self
.Size
= FdRegion
.Size
1375 self
._FvDir
= Wa
.FvDir
1378 # If the input FdRegion is not a firmware volume,
1381 if self
.Type
!= "FV":
1385 # Find all nested FVs in the FdRegion
1387 for FvName
in FdRegion
.RegionDataList
:
1388 if FvName
in self
.FvList
:
1390 self
.FvList
.append(FvName
)
1391 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1392 self
._DiscoverNestedFvList
(FvName
, Wa
)
1396 # Collect PCDs declared in DEC files.
1398 for Pa
in Wa
.AutoGenObjectList
:
1399 for Package
in Pa
.PackageList
:
1400 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1401 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1402 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1404 # Collect PCDs defined in DSC file
1406 for arch
in Wa
.ArchList
:
1407 Platform
= Wa
.BuildDatabase
[Wa
.MetaFile
, arch
]
1408 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
1409 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1410 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1413 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1415 self
._GuidsDb
["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"
1416 self
._GuidsDb
["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"
1418 # Add ACPI table storage file
1420 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1422 for Pa
in Wa
.AutoGenObjectList
:
1423 for ModuleKey
in Pa
.Platform
.Modules
:
1424 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1425 InfPath
= mws
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1426 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1429 # Collect the GUID map in the FV firmware volume
1431 for FvName
in self
.FvList
:
1432 FvDictKey
=FvName
.upper()
1433 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1434 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1437 # collect GUID map for binary EFI file in FDF file.
1439 Guid
= Ffs
.NameGuid
.upper()
1440 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1442 PcdTokenspace
= Match
.group(1)
1443 PcdToken
= Match
.group(2)
1444 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1445 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1446 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1447 for Section
in Ffs
.SectionList
:
1449 ModuleSectFile
= mws
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1450 self
._GuidsDb
[Guid
] = ModuleSectFile
1451 except AttributeError:
1453 except AttributeError:
1458 # Internal worker function to generate report for the FD region
1460 # This internal worker function to generate report for the FD region.
1461 # It the type is firmware volume, it lists offset and module identification.
1463 # @param self The object pointer
1464 # @param File The file object for report
1465 # @param Title The title for the FD subsection
1466 # @param BaseAddress The base address for the FD region
1467 # @param Size The size of the FD region
1468 # @param FvName The FV name if the FD region is a firmware volume
1470 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1471 FileWrite(File
, gSubSectionStart
)
1472 FileWrite(File
, Title
)
1473 FileWrite(File
, "Type: %s" % Type
)
1474 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1476 if self
.Type
== "FV":
1480 FvReportFileName
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv.txt")
1483 # Collect size info in the firmware volume.
1485 FvReport
= open(FvReportFileName
).read()
1486 Match
= gFvTotalSizePattern
.search(FvReport
)
1488 FvTotalSize
= int(Match
.group(1), 16)
1489 Match
= gFvTakenSizePattern
.search(FvReport
)
1491 FvTakenSize
= int(Match
.group(1), 16)
1492 FvFreeSize
= FvTotalSize
- FvTakenSize
1494 # Write size information to the report file.
1496 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1497 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1498 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1499 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1500 FileWrite(File
, "Offset Module")
1501 FileWrite(File
, gSubSectionSep
)
1503 # Write module offset and module identification to the report file.
1506 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1507 Guid
= Match
.group(2).upper()
1508 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1509 OffsetList
= OffsetInfo
.keys()
1511 for Offset
in OffsetList
:
1512 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1514 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
1516 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
1517 FileWrite(File
, gSubSectionEnd
)
1520 # Generate report for the FD region
1522 # This function generates report for the FD region.
1524 # @param self The object pointer
1525 # @param File The file object for report
1527 def GenerateReport(self
, File
):
1528 if (len(self
.FvList
) > 0):
1529 for FvItem
in self
.FvList
:
1530 Info
= self
.FvInfo
[FvItem
]
1531 self
._GenerateReport
(File
, Info
[0], "FV", Info
[1], Info
[2], FvItem
)
1533 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
1536 # Reports FD information
1538 # This class reports the FD section in the build report file.
1539 # It collects flash device information for a platform.
1541 class FdReport(object):
1543 # Constructor function for class FdReport
1545 # This constructor function generates FdReport object for a specified
1548 # @param self The object pointer
1549 # @param Fd The current Firmware device object
1550 # @param Wa Workspace context information
1552 def __init__(self
, Fd
, Wa
):
1553 self
.FdName
= Fd
.FdUiName
1554 self
.BaseAddress
= Fd
.BaseAddress
1556 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
1557 self
.FvPath
= os
.path
.join(Wa
.BuildDir
, "FV")
1558 self
.VpdFilePath
= os
.path
.join(self
.FvPath
, "%s.map" % Wa
.Platform
.VpdToolGuid
)
1559 self
.VPDBaseAddress
= 0
1561 self
.VPDInfoList
= []
1562 for index
, FdRegion
in enumerate(Fd
.RegionList
):
1563 if str(FdRegion
.RegionType
) is 'FILE' and Wa
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
1564 self
.VPDBaseAddress
= self
.FdRegionList
[index
].BaseAddress
1565 self
.VPDSize
= self
.FdRegionList
[index
].Size
1568 if os
.path
.isfile(self
.VpdFilePath
):
1569 fd
= open(self
.VpdFilePath
, "r")
1570 Lines
= fd
.readlines()
1573 if len(Line
) == 0 or Line
.startswith("#"):
1576 PcdName
, SkuId
, Offset
, Size
, Value
= Line
.split("#")[0].split("|")
1577 PcdName
, SkuId
, Offset
, Size
, Value
= PcdName
.strip(), SkuId
.strip(), Offset
.strip(), Size
.strip(), Value
.strip()
1578 if Offset
.lower().startswith('0x'):
1579 Offset
= '0x%08X' % (int(Offset
, 16) + self
.VPDBaseAddress
)
1581 Offset
= '0x%08X' % (int(Offset
, 10) + self
.VPDBaseAddress
)
1582 self
.VPDInfoList
.append("%s | %s | %s | %s | %s" % (PcdName
, SkuId
, Offset
, Size
, Value
))
1584 EdkLogger
.error("BuildReport", CODE_ERROR
, "Fail to parse VPD information file %s" % self
.VpdFilePath
)
1588 # Generate report for the firmware device.
1590 # This function generates report for the firmware device.
1592 # @param self The object pointer
1593 # @param File The file object for report
1595 def GenerateReport(self
, File
):
1596 FileWrite(File
, gSectionStart
)
1597 FileWrite(File
, "Firmware Device (FD)")
1598 FileWrite(File
, "FD Name: %s" % self
.FdName
)
1599 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
1600 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
1601 if len(self
.FdRegionList
) > 0:
1602 FileWrite(File
, gSectionSep
)
1603 for FdRegionItem
in self
.FdRegionList
:
1604 FdRegionItem
.GenerateReport(File
)
1606 if len(self
.VPDInfoList
) > 0:
1607 FileWrite(File
, gSubSectionStart
)
1608 FileWrite(File
, "FD VPD Region")
1609 FileWrite(File
, "Base Address: 0x%X" % self
.VPDBaseAddress
)
1610 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.VPDSize
, self
.VPDSize
/ 1024.0))
1611 FileWrite(File
, gSubSectionSep
)
1612 for item
in self
.VPDInfoList
:
1613 FileWrite(File
, item
)
1614 FileWrite(File
, gSubSectionEnd
)
1615 FileWrite(File
, gSectionEnd
)
1620 # Reports platform information
1622 # This class reports the whole platform information
1624 class PlatformReport(object):
1626 # Constructor function for class PlatformReport
1628 # This constructor function generates PlatformReport object a platform build.
1629 # It generates report for platform summary, flash, global PCDs and detailed
1630 # module information for modules involved in platform build.
1632 # @param self The object pointer
1633 # @param Wa Workspace context information
1634 # @param MaList The list of modules in the platform build
1636 def __init__(self
, Wa
, MaList
, ReportType
):
1637 self
._WorkspaceDir
= Wa
.WorkspaceDir
1638 self
.PlatformName
= Wa
.Name
1639 self
.PlatformDscPath
= Wa
.Platform
1640 self
.Architectures
= " ".join(Wa
.ArchList
)
1641 self
.ToolChain
= Wa
.ToolChain
1642 self
.Target
= Wa
.BuildTarget
1643 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
1644 self
.BuildEnvironment
= platform
.platform()
1646 self
.PcdReport
= None
1647 if "PCD" in ReportType
:
1648 self
.PcdReport
= PcdReport(Wa
)
1650 self
.FdReportList
= []
1651 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
== None:
1652 for Fd
in Wa
.FdfProfile
.FdDict
:
1653 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
1655 self
.PredictionReport
= None
1656 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
1657 self
.PredictionReport
= PredictionReport(Wa
)
1659 self
.DepexParser
= None
1660 if "DEPEX" in ReportType
:
1661 self
.DepexParser
= DepexParser(Wa
)
1663 self
.ModuleReportList
= []
1665 self
._IsModuleBuild
= True
1667 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
1669 self
._IsModuleBuild
= False
1670 for Pa
in Wa
.AutoGenObjectList
:
1671 ModuleAutoGenList
= []
1672 for ModuleKey
in Pa
.Platform
.Modules
:
1673 ModuleAutoGenList
.append(Pa
.Platform
.Modules
[ModuleKey
].M
)
1674 if GlobalData
.gFdfParser
!= None:
1675 if Pa
.Arch
in GlobalData
.gFdfParser
.Profile
.InfDict
:
1676 INFList
= GlobalData
.gFdfParser
.Profile
.InfDict
[Pa
.Arch
]
1677 for InfName
in INFList
:
1678 InfClass
= PathClass(NormPath(InfName
), Wa
.WorkspaceDir
, Pa
.Arch
)
1679 Ma
= ModuleAutoGen(Wa
, InfClass
, Pa
.BuildTarget
, Pa
.ToolChain
, Pa
.Arch
, Wa
.MetaFile
)
1682 if Ma
not in ModuleAutoGenList
:
1683 ModuleAutoGenList
.append(Ma
)
1684 for MGen
in ModuleAutoGenList
:
1685 self
.ModuleReportList
.append(ModuleReport(MGen
, ReportType
))
1690 # Generate report for the whole platform.
1692 # This function generates report for platform information.
1693 # It comprises of platform summary, global PCD, flash and
1694 # module list sections.
1696 # @param self The object pointer
1697 # @param File The file object for report
1698 # @param BuildDuration The total time to build the modules
1699 # @param ReportType The kind of report items in the final report file
1701 def GenerateReport(self
, File
, BuildDuration
, ReportType
):
1702 FileWrite(File
, "Platform Summary")
1703 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
1704 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
1705 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
1706 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
1707 FileWrite(File
, "Target: %s" % self
.Target
)
1708 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
1709 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
1710 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
1711 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
1713 if GlobalData
.MixedPcd
:
1714 FileWrite(File
, gSectionStart
)
1715 FileWrite(File
, "The following PCDs use different access methods:")
1716 FileWrite(File
, gSectionSep
)
1717 for PcdItem
in GlobalData
.MixedPcd
:
1718 FileWrite(File
, "%s.%s" % (str(PcdItem
[1]), str(PcdItem
[0])))
1719 FileWrite(File
, gSectionEnd
)
1721 if not self
._IsModuleBuild
:
1722 if "PCD" in ReportType
:
1723 self
.PcdReport
.GenerateReport(File
, None)
1725 if "FLASH" in ReportType
:
1726 for FdReportListItem
in self
.FdReportList
:
1727 FdReportListItem
.GenerateReport(File
)
1729 for ModuleReportItem
in self
.ModuleReportList
:
1730 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, self
.DepexParser
, ReportType
)
1732 if not self
._IsModuleBuild
:
1733 if "EXECUTION_ORDER" in ReportType
:
1734 self
.PredictionReport
.GenerateReport(File
, None)
1736 ## BuildReport class
1738 # This base class contain the routines to collect data and then
1739 # applies certain format to the output report
1741 class BuildReport(object):
1743 # Constructor function for class BuildReport
1745 # This constructor function generates BuildReport object a platform build.
1746 # It generates report for platform summary, flash, global PCDs and detailed
1747 # module information for modules involved in platform build.
1749 # @param self The object pointer
1750 # @param ReportFile The file name to save report file
1751 # @param ReportType The kind of report items in the final report file
1753 def __init__(self
, ReportFile
, ReportType
):
1754 self
.ReportFile
= ReportFile
1756 self
.ReportList
= []
1757 self
.ReportType
= []
1759 for ReportTypeItem
in ReportType
:
1760 if ReportTypeItem
not in self
.ReportType
:
1761 self
.ReportType
.append(ReportTypeItem
)
1763 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]
1765 # Adds platform report to the list
1767 # This function adds a platform report to the final report list.
1769 # @param self The object pointer
1770 # @param Wa Workspace context information
1771 # @param MaList The list of modules in the platform build
1773 def AddPlatformReport(self
, Wa
, MaList
=None):
1775 self
.ReportList
.append((Wa
, MaList
))
1778 # Generates the final report.
1780 # This function generates platform build report. It invokes GenerateReport()
1781 # method for every platform report in the list.
1783 # @param self The object pointer
1784 # @param BuildDuration The total time to build the modules
1786 def GenerateReport(self
, BuildDuration
):
1790 for (Wa
, MaList
) in self
.ReportList
:
1791 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, self
.ReportType
)
1792 Content
= FileLinesSplit(File
.getvalue(), gLineMaxLength
)
1793 SaveFileOnChange(self
.ReportFile
, Content
, True)
1794 EdkLogger
.quiet("Build report can be found at %s" % os
.path
.abspath(self
.ReportFile
))
1796 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
1798 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
1799 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1802 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1803 if __name__
== '__main__':