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 - 2018, Intel Corporation. All rights reserved.<BR>
8 # SPDX-License-Identifier: BSD-2-Clause-Patent
13 import Common
.LongFilePathOs
as os
24 from datetime
import datetime
25 from io
import BytesIO
26 from Common
import EdkLogger
27 from Common
.Misc
import SaveFileOnChange
28 from Common
.Misc
import GuidStructureByteArrayToGuidString
29 from Common
.Misc
import GuidStructureStringToGuidString
30 from Common
.BuildToolError
import FILE_WRITE_FAILURE
31 from Common
.BuildToolError
import CODE_ERROR
32 from Common
.BuildToolError
import COMMAND_FAILURE
33 from Common
.BuildToolError
import FORMAT_INVALID
34 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
35 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
36 import Common
.GlobalData
as GlobalData
37 from AutoGen
.AutoGen
import ModuleAutoGen
38 from Common
.Misc
import PathClass
39 from Common
.StringUtils
import NormPath
40 from Common
.DataType
import *
42 from Common
.Expression
import *
43 from GenFds
.AprioriSection
import DXE_APRIORI_GUID
, PEI_APRIORI_GUID
45 ## Pattern to extract contents in EDK DXS files
46 gDxsDependencyPattern
= re
.compile(r
"DEPENDENCY_START(.+)DEPENDENCY_END", re
.DOTALL
)
48 ## Pattern to find total FV total size, occupied size in flash report intermediate file
49 gFvTotalSizePattern
= re
.compile(r
"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
50 gFvTakenSizePattern
= re
.compile(r
"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
52 ## Pattern to find module size and time stamp in module summary report intermediate file
53 gModuleSizePattern
= re
.compile(r
"MODULE_SIZE = (\d+)")
54 gTimeStampPattern
= re
.compile(r
"TIME_STAMP = (\d+)")
56 ## Pattern to find GUID value in flash description files
57 gPcdGuidPattern
= re
.compile(r
"PCD\((\w+)[.](\w+)\)")
59 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
60 gOffsetGuidPattern
= re
.compile(r
"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
62 ## Pattern to find module base address and entry point in fixed flash map file
63 gModulePattern
= r
"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
64 gMapFileItemPattern
= re
.compile(gModulePattern
% {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
66 ## Pattern to find all module referenced header files in source files
67 gIncludePattern
= re
.compile(r
'#include\s*["<]([^">]+)[">]')
68 gIncludePattern2
= re
.compile(r
"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
70 ## Pattern to find the entry point for EDK module using EDKII Glue library
71 gGlueLibEntryPoint
= re
.compile(r
"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
73 ## Tags for MaxLength of line in report
76 ## Tags for end of line in report
79 ## Tags for section start, end and separator
80 gSectionStart
= ">" + "=" * (gLineMaxLength
- 2) + "<"
81 gSectionEnd
= "<" + "=" * (gLineMaxLength
- 2) + ">" + "\n"
82 gSectionSep
= "=" * gLineMaxLength
84 ## Tags for subsection start, end and separator
85 gSubSectionStart
= ">" + "-" * (gLineMaxLength
- 2) + "<"
86 gSubSectionEnd
= "<" + "-" * (gLineMaxLength
- 2) + ">"
87 gSubSectionSep
= "-" * gLineMaxLength
90 ## The look up table to map PCD type to pair of report display type and DEC type
92 TAB_PCDS_FIXED_AT_BUILD
: ('FIXED', TAB_PCDS_FIXED_AT_BUILD
),
93 TAB_PCDS_PATCHABLE_IN_MODULE
: ('PATCH', TAB_PCDS_PATCHABLE_IN_MODULE
),
94 TAB_PCDS_FEATURE_FLAG
: ('FLAG', TAB_PCDS_FEATURE_FLAG
),
95 TAB_PCDS_DYNAMIC
: ('DYN', TAB_PCDS_DYNAMIC
),
96 TAB_PCDS_DYNAMIC_HII
: ('DYNHII', TAB_PCDS_DYNAMIC
),
97 TAB_PCDS_DYNAMIC_VPD
: ('DYNVPD', TAB_PCDS_DYNAMIC
),
98 TAB_PCDS_DYNAMIC_EX
: ('DEX', TAB_PCDS_DYNAMIC_EX
),
99 TAB_PCDS_DYNAMIC_EX_HII
: ('DEXHII', TAB_PCDS_DYNAMIC_EX
),
100 TAB_PCDS_DYNAMIC_EX_VPD
: ('DEXVPD', TAB_PCDS_DYNAMIC_EX
),
103 ## The look up table to map module type to driver type
105 SUP_MODULE_SEC
: '0x3 (SECURITY_CORE)',
106 SUP_MODULE_PEI_CORE
: '0x4 (PEI_CORE)',
107 SUP_MODULE_PEIM
: '0x6 (PEIM)',
108 SUP_MODULE_DXE_CORE
: '0x5 (DXE_CORE)',
109 SUP_MODULE_DXE_DRIVER
: '0x7 (DRIVER)',
110 SUP_MODULE_DXE_SAL_DRIVER
: '0x7 (DRIVER)',
111 SUP_MODULE_DXE_SMM_DRIVER
: '0x7 (DRIVER)',
112 SUP_MODULE_DXE_RUNTIME_DRIVER
: '0x7 (DRIVER)',
113 SUP_MODULE_UEFI_DRIVER
: '0x7 (DRIVER)',
114 SUP_MODULE_UEFI_APPLICATION
: '0x9 (APPLICATION)',
115 SUP_MODULE_SMM_CORE
: '0xD (SMM_CORE)',
116 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
117 SUP_MODULE_MM_STANDALONE
: '0xE (MM_STANDALONE)',
118 SUP_MODULE_MM_CORE_STANDALONE
: '0xF (MM_CORE_STANDALONE)'
121 ## The look up table of the supported opcode in the dependency expression binaries
122 gOpCodeList
= ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
128 # Writes a string to the file object.
130 # This function writes a string to the file object and a new line is appended
131 # afterwards. It may optionally wraps the string for better readability.
133 # @File The file object to write
134 # @String The string to be written to the file
135 # @Wrapper Indicates whether to wrap the string
137 def FileWrite(File
, String
, Wrapper
=False):
139 String
= textwrap
.fill(String
, 120)
140 File
.append(String
+ gEndOfLine
)
142 def ByteArrayForamt(Value
):
146 if Value
.startswith('{') and Value
.endswith('}') and not Value
.startswith("{CODE("):
148 ValueList
= Value
.split(',')
149 if len(ValueList
) >= SplitNum
:
153 Len
= len(ValueList
)/SplitNum
154 for i
, element
in enumerate(ValueList
):
155 ValueList
[i
] = '0x%02X' % int(element
.strip(), 16)
159 End
= min(SplitNum
*(Id
+1), len(ValueList
))
160 Str
= ','.join(ValueList
[SplitNum
*Id
: End
])
161 if End
== len(ValueList
):
163 ArrayList
.append(Str
)
167 ArrayList
.append(Str
)
170 ArrayList
= [Value
+ '}']
171 return IsByteArray
, ArrayList
174 # Find all the header file that the module source directly includes.
176 # This function scans source code to find all header files the module may
177 # include. This is not accurate but very effective to find all the header
178 # file the module might include with #include statement.
180 # @Source The source file name
181 # @IncludePathList The list of include path to find the source file.
182 # @IncludeFiles The dictionary of current found include files.
184 def FindIncludeFiles(Source
, IncludePathList
, IncludeFiles
):
185 FileContents
= open(Source
).read()
187 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
189 for Match
in gIncludePattern
.finditer(FileContents
):
190 FileName
= Match
.group(1).strip()
191 for Dir
in [os
.path
.dirname(Source
)] + IncludePathList
:
192 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
193 if os
.path
.exists(FullFileName
):
194 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
198 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
200 for Match
in gIncludePattern2
.finditer(FileContents
):
202 Type
= Match
.group(1)
203 if "ARCH_PROTOCOL" in Type
:
204 FileName
= "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
205 elif "PROTOCOL" in Type
:
206 FileName
= "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
208 FileName
= "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key
}
209 elif TAB_GUID
in Type
:
210 FileName
= "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key
}
213 for Dir
in IncludePathList
:
214 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
215 if os
.path
.exists(FullFileName
):
216 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
219 ## Split each lines in file
221 # This method is used to split the lines in file to make the length of each line
222 # less than MaxLength.
224 # @param Content The content of file
225 # @param MaxLength The Max Length of the line
227 def FileLinesSplit(Content
=None, MaxLength
=None):
228 ContentList
= Content
.split(TAB_LINE_BREAK
)
231 for Line
in ContentList
:
232 while len(Line
.rstrip()) > MaxLength
:
233 LineSpaceIndex
= Line
.rfind(TAB_SPACE_SPLIT
, 0, MaxLength
)
234 LineSlashIndex
= Line
.rfind(TAB_SLASH
, 0, MaxLength
)
235 LineBackSlashIndex
= Line
.rfind(TAB_BACK_SLASH
, 0, MaxLength
)
236 if max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
) > 0:
237 LineBreakIndex
= max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
)
239 LineBreakIndex
= MaxLength
240 NewContentList
.append(Line
[:LineBreakIndex
])
241 Line
= Line
[LineBreakIndex
:]
243 NewContentList
.append(Line
)
244 for NewLine
in NewContentList
:
245 NewContent
+= NewLine
+ TAB_LINE_BREAK
247 NewContent
= NewContent
.replace(gEndOfLine
, TAB_LINE_BREAK
).replace('\r\r\n', gEndOfLine
)
253 # Parse binary dependency expression section
255 # This utility class parses the dependency expression section and translate the readable
256 # GUID name and value.
258 class DepexParser(object):
260 # Constructor function for class DepexParser
262 # This constructor function collect GUID values so that the readable
263 # GUID name can be translated.
265 # @param self The object pointer
266 # @param Wa Workspace context information
268 def __init__(self
, Wa
):
270 for Pa
in Wa
.AutoGenObjectList
:
271 for Package
in Pa
.PackageList
:
272 for Protocol
in Package
.Protocols
:
273 GuidValue
= GuidStructureStringToGuidString(Package
.Protocols
[Protocol
])
274 self
._GuidDb
[GuidValue
.upper()] = Protocol
275 for Ppi
in Package
.Ppis
:
276 GuidValue
= GuidStructureStringToGuidString(Package
.Ppis
[Ppi
])
277 self
._GuidDb
[GuidValue
.upper()] = Ppi
278 for Guid
in Package
.Guids
:
279 GuidValue
= GuidStructureStringToGuidString(Package
.Guids
[Guid
])
280 self
._GuidDb
[GuidValue
.upper()] = Guid
281 for Ma
in Pa
.ModuleAutoGenList
:
282 for Pcd
in Ma
.FixedVoidTypePcds
:
283 PcdValue
= Ma
.FixedVoidTypePcds
[Pcd
]
284 if len(PcdValue
.split(',')) == 16:
285 GuidValue
= GuidStructureByteArrayToGuidString(PcdValue
)
286 self
._GuidDb
[GuidValue
.upper()] = Pcd
288 # Parse the binary dependency expression files.
290 # This function parses the binary dependency expression file and translate it
291 # to the instruction list.
293 # @param self The object pointer
294 # @param DepexFileName The file name of binary dependency expression file.
296 def ParseDepexFile(self
, DepexFileName
):
297 DepexFile
= open(DepexFileName
, "rb")
299 OpCode
= DepexFile
.read(1)
301 Statement
= gOpCodeList
[struct
.unpack("B", OpCode
)[0]]
302 if Statement
in ["BEFORE", "AFTER", "PUSH"]:
303 GuidValue
= "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
304 struct
.unpack(PACK_PATTERN_GUID
, DepexFile
.read(16))
305 GuidString
= self
._GuidDb
.get(GuidValue
, GuidValue
)
306 Statement
= "%s %s" % (Statement
, GuidString
)
307 DepexStatement
.append(Statement
)
308 OpCode
= DepexFile
.read(1)
310 return DepexStatement
313 # Reports library information
315 # This class reports the module library subsection in the build report file.
317 class LibraryReport(object):
319 # Constructor function for class LibraryReport
321 # This constructor function generates LibraryReport object for
324 # @param self The object pointer
325 # @param M Module context information
327 def __init__(self
, M
):
328 self
.LibraryList
= []
330 for Lib
in M
.DependentLibraryList
:
331 LibInfPath
= str(Lib
)
332 LibClassList
= Lib
.LibraryClass
[0].LibraryClass
333 LibConstructorList
= Lib
.ConstructorList
334 LibDesstructorList
= Lib
.DestructorList
335 LibDepexList
= Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]
336 for LibAutoGen
in M
.LibraryAutoGenList
:
337 if LibInfPath
== LibAutoGen
.MetaFile
.Path
:
338 LibTime
= LibAutoGen
.BuildTime
340 self
.LibraryList
.append((LibInfPath
, LibClassList
, LibConstructorList
, LibDesstructorList
, LibDepexList
, LibTime
))
343 # Generate report for module library information
345 # This function generates report for the module library.
346 # If the module is EDKII style one, the additional library class, library
347 # constructor/destructor and dependency expression may also be reported.
349 # @param self The object pointer
350 # @param File The file object for report
352 def GenerateReport(self
, File
):
353 if len(self
.LibraryList
) > 0:
354 FileWrite(File
, gSubSectionStart
)
355 FileWrite(File
, TAB_BRG_LIBRARY
)
356 FileWrite(File
, gSubSectionSep
)
357 for LibraryItem
in self
.LibraryList
:
358 LibInfPath
= LibraryItem
[0]
359 FileWrite(File
, LibInfPath
)
361 LibClass
= LibraryItem
[1]
363 LibConstructor
= " ".join(LibraryItem
[2])
365 EdkIILibInfo
+= " C = " + LibConstructor
366 LibDestructor
= " ".join(LibraryItem
[3])
368 EdkIILibInfo
+= " D = " + LibDestructor
369 LibDepex
= " ".join(LibraryItem
[4])
371 EdkIILibInfo
+= " Depex = " + LibDepex
373 EdkIILibInfo
+= " Time = " + LibraryItem
[5]
375 FileWrite(File
, "{%s: %s}" % (LibClass
, EdkIILibInfo
))
377 FileWrite(File
, "{%s}" % LibClass
)
379 FileWrite(File
, gSubSectionEnd
)
382 # Reports dependency expression information
384 # This class reports the module dependency expression subsection in the build report file.
386 class DepexReport(object):
388 # Constructor function for class DepexReport
390 # This constructor function generates DepexReport object for
391 # a module. If the module source contains the DXS file (usually EDK
392 # style module), it uses the dependency in DXS file; otherwise,
393 # it uses the dependency expression from its own INF [Depex] section
394 # and then merges with the ones from its dependent library INF.
396 # @param self The object pointer
397 # @param M Module context information
399 def __init__(self
, M
):
401 self
._DepexFileName
= os
.path
.join(M
.BuildDir
, "OUTPUT", M
.Module
.BaseName
+ ".depex")
402 ModuleType
= M
.ModuleType
404 ModuleType
= COMPONENT_TO_MODULE_MAP_DICT
.get(M
.ComponentType
, "")
406 if ModuleType
in [SUP_MODULE_SEC
, SUP_MODULE_PEI_CORE
, SUP_MODULE_DXE_CORE
, SUP_MODULE_SMM_CORE
, SUP_MODULE_MM_CORE_STANDALONE
, SUP_MODULE_UEFI_APPLICATION
]:
409 for Source
in M
.SourceFileList
:
410 if os
.path
.splitext(Source
.Path
)[1].lower() == ".dxs":
411 Match
= gDxsDependencyPattern
.search(open(Source
.Path
).read())
413 self
.Depex
= Match
.group(1).strip()
417 self
.Depex
= M
.DepexExpressionDict
.get(M
.ModuleType
, "")
418 self
.ModuleDepex
= " ".join(M
.Module
.DepexExpression
[M
.Arch
, M
.ModuleType
])
419 if not self
.ModuleDepex
:
420 self
.ModuleDepex
= "(None)"
423 for Lib
in M
.DependentLibraryList
:
424 LibDepex
= " ".join(Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]).strip()
426 LibDepexList
.append("(" + LibDepex
+ ")")
427 self
.LibraryDepex
= " AND ".join(LibDepexList
)
428 if not self
.LibraryDepex
:
429 self
.LibraryDepex
= "(None)"
433 # Generate report for module dependency expression information
435 # This function generates report for the module dependency expression.
437 # @param self The object pointer
438 # @param File The file object for report
439 # @param GlobalDepexParser The platform global Dependency expression parser object
441 def GenerateReport(self
, File
, GlobalDepexParser
):
444 FileWrite(File
, gSubSectionStart
)
445 if os
.path
.isfile(self
._DepexFileName
):
447 DepexStatements
= GlobalDepexParser
.ParseDepexFile(self
._DepexFileName
)
448 FileWrite(File
, "Final Dependency Expression (DEPEX) Instructions")
449 for DepexStatement
in DepexStatements
:
450 FileWrite(File
, " %s" % DepexStatement
)
451 FileWrite(File
, gSubSectionSep
)
453 EdkLogger
.warn(None, "Dependency expression file is corrupted", self
._DepexFileName
)
455 FileWrite(File
, "Dependency Expression (DEPEX) from %s" % self
.Source
)
457 if self
.Source
== "INF":
458 FileWrite(File
, self
.Depex
, True)
459 FileWrite(File
, gSubSectionSep
)
460 FileWrite(File
, "From Module INF: %s" % self
.ModuleDepex
, True)
461 FileWrite(File
, "From Library INF: %s" % self
.LibraryDepex
, True)
463 FileWrite(File
, self
.Depex
)
464 FileWrite(File
, gSubSectionEnd
)
467 # Reports dependency expression information
469 # This class reports the module build flags subsection in the build report file.
471 class BuildFlagsReport(object):
473 # Constructor function for class BuildFlagsReport
475 # This constructor function generates BuildFlagsReport object for
476 # a module. It reports the build tool chain tag and all relevant
477 # build flags to build the module.
479 # @param self The object pointer
480 # @param M Module context information
482 def __init__(self
, M
):
485 # Add build flags according to source file extension so that
486 # irrelevant ones can be filtered out.
488 for Source
in M
.SourceFileList
:
489 Ext
= os
.path
.splitext(Source
.File
)[1].lower()
490 if Ext
in [".c", ".cc", ".cpp"]:
491 BuildOptions
["CC"] = 1
492 elif Ext
in [".s", ".asm"]:
493 BuildOptions
["PP"] = 1
494 BuildOptions
["ASM"] = 1
495 elif Ext
in [".vfr"]:
496 BuildOptions
["VFRPP"] = 1
497 BuildOptions
["VFR"] = 1
498 elif Ext
in [".dxs"]:
499 BuildOptions
["APP"] = 1
500 BuildOptions
["CC"] = 1
501 elif Ext
in [".asl"]:
502 BuildOptions
["ASLPP"] = 1
503 BuildOptions
["ASL"] = 1
504 elif Ext
in [".aslc"]:
505 BuildOptions
["ASLCC"] = 1
506 BuildOptions
["ASLDLINK"] = 1
507 BuildOptions
["CC"] = 1
508 elif Ext
in [".asm16"]:
509 BuildOptions
["ASMLINK"] = 1
510 BuildOptions
["SLINK"] = 1
511 BuildOptions
["DLINK"] = 1
514 # Save module build flags.
516 self
.ToolChainTag
= M
.ToolChain
518 for Tool
in BuildOptions
:
519 self
.BuildFlags
[Tool
+ "_FLAGS"] = M
.BuildOption
.get(Tool
, {}).get("FLAGS", "")
522 # Generate report for module build flags information
524 # This function generates report for the module build flags expression.
526 # @param self The object pointer
527 # @param File The file object for report
529 def GenerateReport(self
, File
):
530 FileWrite(File
, gSubSectionStart
)
531 FileWrite(File
, "Build Flags")
532 FileWrite(File
, "Tool Chain Tag: %s" % self
.ToolChainTag
)
533 for Tool
in self
.BuildFlags
:
534 FileWrite(File
, gSubSectionSep
)
535 FileWrite(File
, "%s = %s" % (Tool
, self
.BuildFlags
[Tool
]), True)
537 FileWrite(File
, gSubSectionEnd
)
541 # Reports individual module information
543 # This class reports the module section in the build report file.
544 # It comprises of module summary, module PCD, library, dependency expression,
545 # build flags sections.
547 class ModuleReport(object):
549 # Constructor function for class ModuleReport
551 # This constructor function generates ModuleReport object for
552 # a separate module in a platform build.
554 # @param self The object pointer
555 # @param M Module context information
556 # @param ReportType The kind of report items in the final report file
558 def __init__(self
, M
, ReportType
):
559 self
.ModuleName
= M
.Module
.BaseName
560 self
.ModuleInfPath
= M
.MetaFile
.File
561 self
.FileGuid
= M
.Guid
563 self
.BuildTimeStamp
= None
567 ModuleType
= M
.ModuleType
569 ModuleType
= COMPONENT_TO_MODULE_MAP_DICT
.get(M
.ComponentType
, "")
571 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
573 if ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
574 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
575 if int(PiSpec
, 0) >= 0x0001000A:
576 ModuleType
= "SMM_DRIVER"
577 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "0x2 (FREE_FORM)")
578 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
579 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
580 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
581 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
582 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
583 self
.BuildTime
= M
.BuildTime
585 self
._BuildDir
= M
.BuildDir
586 self
.ModulePcdSet
= {}
587 if "PCD" in ReportType
:
589 # Collect all module used PCD set: module INF referenced directly or indirectly.
590 # It also saves module INF default values of them in case they exist.
592 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
593 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
595 self
.LibraryReport
= None
596 if "LIBRARY" in ReportType
:
597 self
.LibraryReport
= LibraryReport(M
)
599 self
.DepexReport
= None
600 if "DEPEX" in ReportType
:
601 self
.DepexReport
= DepexReport(M
)
603 if "BUILD_FLAGS" in ReportType
:
604 self
.BuildFlagsReport
= BuildFlagsReport(M
)
608 # Generate report for module information
610 # This function generates report for separate module expression
611 # in a platform build.
613 # @param self The object pointer
614 # @param File The file object for report
615 # @param GlobalPcdReport The platform global PCD report object
616 # @param GlobalPredictionReport The platform global Prediction report object
617 # @param GlobalDepexParser The platform global Dependency expression parser object
618 # @param ReportType The kind of report items in the final report file
620 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, GlobalDepexParser
, ReportType
):
621 FileWrite(File
, gSectionStart
)
623 FwReportFileName
= os
.path
.join(self
._BuildDir
, "OUTPUT", self
.ModuleName
+ ".txt")
624 if os
.path
.isfile(FwReportFileName
):
626 FileContents
= open(FwReportFileName
).read()
627 Match
= gModuleSizePattern
.search(FileContents
)
629 self
.Size
= int(Match
.group(1))
631 Match
= gTimeStampPattern
.search(FileContents
)
633 self
.BuildTimeStamp
= datetime
.utcfromtimestamp(int(Match
.group(1)))
635 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
637 if "HASH" in ReportType
:
638 OutputDir
= os
.path
.join(self
._BuildDir
, "OUTPUT")
639 DefaultEFIfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ ".efi")
640 if os
.path
.isfile(DefaultEFIfile
):
641 Tempfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ "_hash.tmp")
642 # rebase the efi image since its base address may not zero
643 cmd
= ["GenFw", "--rebase", str(0), "-o", Tempfile
, DefaultEFIfile
]
645 PopenObject
= subprocess
.Popen(' '.join(cmd
), stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
646 except Exception as X
:
647 EdkLogger
.error("GenFw", COMMAND_FAILURE
, ExtraData
="%s: %s" % (str(X
), cmd
[0]))
648 EndOfProcedure
= threading
.Event()
649 EndOfProcedure
.clear()
650 if PopenObject
.stderr
:
651 StdErrThread
= threading
.Thread(target
=ReadMessage
, args
=(PopenObject
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
652 StdErrThread
.setName("STDERR-Redirector")
653 StdErrThread
.setDaemon(False)
655 # waiting for program exit
657 if PopenObject
.stderr
:
659 if PopenObject
.returncode
!= 0:
660 EdkLogger
.error("GenFw", COMMAND_FAILURE
, "Failed to generate firmware hash image for %s" % (DefaultEFIfile
))
661 if os
.path
.isfile(Tempfile
):
662 self
.Hash
= hashlib
.sha1()
663 buf
= open(Tempfile
, 'rb').read()
664 if self
.Hash
.update(buf
):
665 self
.Hash
= self
.Hash
.update(buf
)
666 self
.Hash
= self
.Hash
.hexdigest()
669 FileWrite(File
, "Module Summary")
670 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
671 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
672 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
674 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
676 FileWrite(File
, "SHA1 HASH: %s *%s" % (self
.Hash
, self
.ModuleName
+ ".efi"))
677 if self
.BuildTimeStamp
:
678 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
680 FileWrite(File
, "Module Build Time: %s" % self
.BuildTime
)
682 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
683 if self
.UefiSpecVersion
:
684 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
685 if self
.PiSpecVersion
:
686 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
688 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
690 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
691 if self
.PciClassCode
:
692 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
694 FileWrite(File
, gSectionSep
)
696 if "PCD" in ReportType
:
697 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
)
699 if "LIBRARY" in ReportType
:
700 self
.LibraryReport
.GenerateReport(File
)
702 if "DEPEX" in ReportType
:
703 self
.DepexReport
.GenerateReport(File
, GlobalDepexParser
)
705 if "BUILD_FLAGS" in ReportType
:
706 self
.BuildFlagsReport
.GenerateReport(File
)
708 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
709 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
711 FileWrite(File
, gSectionEnd
)
713 def ReadMessage(From
, To
, ExitFlag
):
715 # read one line a time
716 Line
= From
.readline()
717 # empty string means "end"
718 if Line
is not None and Line
!= b
"":
719 To(Line
.rstrip().decode(encoding
='utf-8', errors
='ignore'))
726 # Reports platform and module PCD information
728 # This class reports the platform PCD section and module PCD subsection
729 # in the build report file.
731 class PcdReport(object):
733 # Constructor function for class PcdReport
735 # This constructor function generates PcdReport object a platform build.
736 # It collects the whole PCD database from platform DSC files, platform
737 # flash description file and package DEC files.
739 # @param self The object pointer
740 # @param Wa Workspace context information
742 def __init__(self
, Wa
):
745 self
.ConditionalPcds
= {}
749 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
753 self
.DefaultStoreSingle
= True
754 self
.SkuSingle
= True
755 if GlobalData
.gDefaultStores
and len(GlobalData
.gDefaultStores
) > 1:
756 self
.DefaultStoreSingle
= False
757 if GlobalData
.gSkuids
and len(GlobalData
.gSkuids
) > 1:
758 self
.SkuSingle
= False
760 self
.ModulePcdOverride
= {}
761 for Pa
in Wa
.AutoGenObjectList
:
764 # Collect all platform referenced PCDs and grouped them by PCD token space
767 for Pcd
in Pa
.AllPcdList
:
768 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
769 if Pcd
not in PcdList
:
771 if len(Pcd
.TokenCName
) > self
.MaxLen
:
772 self
.MaxLen
= len(Pcd
.TokenCName
)
774 # Collect the PCD defined in DSC/FDF file, but not used in module
776 UnusedPcdFullList
= []
777 StructPcdDict
= GlobalData
.gStructurePcd
.get(self
.Arch
, collections
.OrderedDict())
778 for Name
, Guid
in StructPcdDict
:
779 if (Name
, Guid
) not in Pa
.Platform
.Pcds
:
780 Pcd
= StructPcdDict
[(Name
, Guid
)]
781 PcdList
= self
.AllPcds
.setdefault(Guid
, {}).setdefault(Pcd
.Type
, [])
782 if Pcd
not in PcdList
and Pcd
not in UnusedPcdFullList
:
783 UnusedPcdFullList
.append(Pcd
)
784 for item
in Pa
.Platform
.Pcds
:
785 Pcd
= Pa
.Platform
.Pcds
[item
]
787 # check the Pcd in FDF file, whether it is used in module first
788 for T
in PCD_TYPE_LIST
:
789 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(T
, [])
795 for package
in Pa
.PackageList
:
796 for T
in PCD_TYPE_LIST
:
797 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
) in package
.Pcds
:
800 if not Pcd
.DatumType
:
801 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
)].DatumType
805 if not Pcd
.DatumType
:
807 # Try to remove Hii and Vpd suffix
808 if PcdType
.startswith(TAB_PCDS_DYNAMIC_EX
):
809 PcdType
= TAB_PCDS_DYNAMIC_EX
810 elif PcdType
.startswith(TAB_PCDS_DYNAMIC
):
811 PcdType
= TAB_PCDS_DYNAMIC
812 for package
in Pa
.PackageList
:
813 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
) in package
.Pcds
:
814 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
)].DatumType
817 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
818 UnusedPcdList
= self
.UnusedPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
819 if Pcd
in UnusedPcdList
:
820 UnusedPcdList
.remove(Pcd
)
821 if Pcd
not in PcdList
and Pcd
not in UnusedPcdFullList
:
822 UnusedPcdFullList
.append(Pcd
)
823 if len(Pcd
.TokenCName
) > self
.MaxLen
:
824 self
.MaxLen
= len(Pcd
.TokenCName
)
826 if GlobalData
.gConditionalPcds
:
827 for PcdItem
in GlobalData
.gConditionalPcds
:
829 (TokenSpaceGuidCName
, TokenCName
) = PcdItem
.split('.')
830 if (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
831 Pcd
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)]
832 PcdList
= self
.ConditionalPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
833 if Pcd
not in PcdList
:
837 if UnusedPcdFullList
:
838 for Pcd
in UnusedPcdFullList
:
839 if Pcd
.TokenSpaceGuidCName
+ '.' + Pcd
.TokenCName
in GlobalData
.gConditionalPcds
:
841 UnusedPcdList
.append(Pcd
)
843 for Pcd
in UnusedPcdList
:
844 PcdList
= self
.UnusedPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
845 if Pcd
not in PcdList
:
848 for Module
in Pa
.Platform
.Modules
.values():
850 # Collect module override PCDs
852 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
853 TokenCName
= ModulePcd
.TokenCName
854 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
855 ModuleDefault
= ModulePcd
.DefaultValue
856 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
857 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
861 # Collect PCD DEC default value.
863 self
.DecPcdDefault
= {}
865 for Pa
in Wa
.AutoGenObjectList
:
866 for Package
in Pa
.PackageList
:
867 Guids
= Package
.Guids
868 self
._GuidDict
.update(Guids
)
869 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
870 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
871 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
873 # Collect PCDs defined in DSC common section
875 self
.DscPcdDefault
= {}
876 for Pa
in Wa
.AutoGenObjectList
:
877 for (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
878 DscDefaultValue
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DscDefaultValue
880 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
882 def GenerateReport(self
, File
, ModulePcdSet
):
884 if self
.ConditionalPcds
:
885 self
.GenerateReportDetail(File
, ModulePcdSet
, 1)
888 for Token
in self
.UnusedPcds
:
889 TokenDict
= self
.UnusedPcds
[Token
]
890 for Type
in TokenDict
:
897 self
.GenerateReportDetail(File
, ModulePcdSet
, 2)
898 self
.GenerateReportDetail(File
, ModulePcdSet
)
901 # Generate report for PCD information
903 # This function generates report for separate module expression
904 # in a platform build.
906 # @param self The object pointer
907 # @param File The file object for report
908 # @param ModulePcdSet Set of all PCDs referenced by module or None for
909 # platform PCD report
910 # @param ReportySubType 0 means platform/module PCD report, 1 means Conditional
911 # directives section report, 2 means Unused Pcds section report
912 # @param DscOverridePcds Module DSC override PCDs set
914 def GenerateReportDetail(self
, File
, ModulePcdSet
, ReportSubType
= 0):
915 PcdDict
= self
.AllPcds
916 if ReportSubType
== 1:
917 PcdDict
= self
.ConditionalPcds
918 elif ReportSubType
== 2:
919 PcdDict
= self
.UnusedPcds
922 FileWrite(File
, gSectionStart
)
923 if ReportSubType
== 1:
924 FileWrite(File
, "Conditional Directives used by the build system")
925 elif ReportSubType
== 2:
926 FileWrite(File
, "PCDs not used by modules or in conditional directives")
928 FileWrite(File
, "Platform Configuration Database Report")
930 FileWrite(File
, " *B - PCD override in the build option")
931 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
932 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
933 if not ReportSubType
:
934 FileWrite(File
, " *M - Module scoped PCD override")
935 FileWrite(File
, gSectionSep
)
937 if not ReportSubType
and ModulePcdSet
:
939 # For module PCD sub-section
941 FileWrite(File
, gSubSectionStart
)
942 FileWrite(File
, TAB_BRG_PCD
)
943 FileWrite(File
, gSubSectionSep
)
947 for Type
in PcdDict
[Key
]:
948 for Pcd
in PcdDict
[Key
][Type
]:
949 AllPcdDict
[Key
][(Pcd
.TokenCName
, Type
)] = Pcd
950 for Key
in sorted(AllPcdDict
):
952 # Group PCD by their token space GUID C Name
955 for PcdTokenCName
, Type
in sorted(AllPcdDict
[Key
]):
957 # Group PCD by their usage type
959 Pcd
= AllPcdDict
[Key
][(PcdTokenCName
, Type
)]
960 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
962 if GlobalData
.MixedPcd
:
963 for PcdKey
in GlobalData
.MixedPcd
:
964 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdKey
]:
965 PcdTokenCName
= PcdKey
[0]
967 if MixedPcdFlag
and not ModulePcdSet
:
970 # Get PCD default value and their override relationship
972 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
973 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
974 DscDefaultValBak
= DscDefaultValue
976 for (CName
, Guid
, Field
) in self
.FdfPcdSet
:
977 if CName
== PcdTokenCName
and Guid
== Key
:
978 DscDefaultValue
= self
.FdfPcdSet
[(CName
, Guid
, Field
)]
980 if DscDefaultValue
!= DscDefaultValBak
:
982 DscDefaultValue
= ValueExpressionEx(DscDefaultValue
, Pcd
.DatumType
, self
._GuidDict
)(True)
983 except BadExpression
as DscDefaultValue
:
984 EdkLogger
.error('BuildReport', FORMAT_INVALID
, "PCD Value: %s, Type: %s" %(DscDefaultValue
, Pcd
.DatumType
))
986 InfDefaultValue
= None
988 PcdValue
= DecDefaultValue
990 PcdValue
= DscDefaultValue
991 #The DefaultValue of StructurePcd already be the latest, no need to update.
992 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
993 Pcd
.DefaultValue
= PcdValue
994 if ModulePcdSet
is not None:
995 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
997 InfDefaultValue
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
998 #The DefaultValue of StructurePcd already be the latest, no need to update.
999 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1000 Pcd
.DefaultValue
= PcdValue
1003 InfDefaultValue
= ValueExpressionEx(InfDefaultValue
, Pcd
.DatumType
, self
._GuidDict
)(True)
1004 except BadExpression
as InfDefaultValue
:
1005 EdkLogger
.error('BuildReport', FORMAT_INVALID
, "PCD Value: %s, Type: %s" % (InfDefaultValue
, Pcd
.DatumType
))
1006 if InfDefaultValue
== "":
1007 InfDefaultValue
= None
1009 BuildOptionMatch
= False
1010 if GlobalData
.BuildOptionPcd
:
1011 for pcd
in GlobalData
.BuildOptionPcd
:
1012 if (Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
) == (pcd
[0], pcd
[1]):
1016 #The DefaultValue of StructurePcd already be the latest, no need to update.
1017 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1018 Pcd
.DefaultValue
= PcdValue
1019 BuildOptionMatch
= True
1023 if ModulePcdSet
is None:
1025 FileWrite(File
, Key
)
1029 if Pcd
.DatumType
in TAB_PCD_NUMERIC_TYPES
:
1030 if PcdValue
.startswith('0') and not PcdValue
.lower().startswith('0x') and \
1031 len(PcdValue
) > 1 and PcdValue
.lstrip('0'):
1032 PcdValue
= PcdValue
.lstrip('0')
1033 PcdValueNumber
= int(PcdValue
.strip(), 0)
1034 if DecDefaultValue
is None:
1037 if DecDefaultValue
.startswith('0') and not DecDefaultValue
.lower().startswith('0x') and \
1038 len(DecDefaultValue
) > 1 and DecDefaultValue
.lstrip('0'):
1039 DecDefaultValue
= DecDefaultValue
.lstrip('0')
1040 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
1041 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
1043 if InfDefaultValue
is None:
1046 if InfDefaultValue
.startswith('0') and not InfDefaultValue
.lower().startswith('0x') and \
1047 len(InfDefaultValue
) > 1 and InfDefaultValue
.lstrip('0'):
1048 InfDefaultValue
= InfDefaultValue
.lstrip('0')
1049 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
1050 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
1052 if DscDefaultValue
is None:
1055 if DscDefaultValue
.startswith('0') and not DscDefaultValue
.lower().startswith('0x') and \
1056 len(DscDefaultValue
) > 1 and DscDefaultValue
.lstrip('0'):
1057 DscDefaultValue
= DscDefaultValue
.lstrip('0')
1058 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
1059 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
1061 if DecDefaultValue
is None:
1064 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
1066 if InfDefaultValue
is None:
1069 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
1071 if DscDefaultValue
is None:
1074 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
1077 if self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1079 if TypeName
in ('DYNVPD', 'DEXVPD'):
1080 SkuInfoList
= Pcd
.SkuInfoList
1081 Pcd
= GlobalData
.gStructurePcd
[self
.Arch
][(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
)]
1082 Pcd
.DatumType
= Pcd
.StructName
1083 if TypeName
in ('DYNVPD', 'DEXVPD'):
1084 Pcd
.SkuInfoList
= SkuInfoList
1085 if Pcd
.PcdValueFromComm
or Pcd
.PcdFieldValueFromComm
:
1086 BuildOptionMatch
= True
1088 elif Pcd
.PcdValueFromFdf
or Pcd
.PcdFieldValueFromFdf
:
1089 DscDefaultValue
= True
1092 elif Pcd
.SkuOverrideValues
:
1094 if Pcd
.DefaultFromDSC
:
1098 for item
in Pcd
.SkuOverrideValues
:
1099 DictLen
+= len(Pcd
.SkuOverrideValues
[item
])
1103 if not Pcd
.SkuInfoList
:
1104 OverrideValues
= Pcd
.SkuOverrideValues
1106 for Data
in OverrideValues
.values():
1107 Struct
= list(Data
.values())
1109 DscOverride
= self
.ParseStruct(Struct
[0])
1112 SkuList
= sorted(Pcd
.SkuInfoList
.keys())
1114 SkuInfo
= Pcd
.SkuInfoList
[Sku
]
1115 if SkuInfo
.DefaultStoreDict
:
1116 DefaultStoreList
= sorted(SkuInfo
.DefaultStoreDict
.keys())
1117 for DefaultStore
in DefaultStoreList
:
1118 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1119 DscOverride
= self
.ParseStruct(OverrideValues
[DefaultStore
])
1125 DscDefaultValue
= True
1131 DscDefaultValue
= True
1136 # Report PCD item according to their override relationship
1138 if Pcd
.DatumType
== 'BOOLEAN':
1140 DscDefaultValue
= str(int(DscDefaultValue
, 0))
1142 DecDefaultValue
= str(int(DecDefaultValue
, 0))
1144 InfDefaultValue
= str(int(InfDefaultValue
, 0))
1145 if Pcd
.DefaultValue
:
1146 Pcd
.DefaultValue
= str(int(Pcd
.DefaultValue
, 0))
1148 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, ' ')
1149 elif InfDefaultValue
and InfMatch
:
1150 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*M')
1151 elif BuildOptionMatch
:
1152 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*B')
1154 if DscDefaultValue
and DscMatch
:
1155 if (Pcd
.TokenCName
, Key
, Field
) in self
.FdfPcdSet
:
1156 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*F')
1158 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*P')
1160 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*M')
1162 if ModulePcdSet
is None:
1165 if not TypeName
in ('PATCH', 'FLAG', 'FIXED'):
1167 if not BuildOptionMatch
:
1168 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
1169 for ModulePath
in ModuleOverride
:
1170 ModuleDefault
= ModuleOverride
[ModulePath
]
1171 if Pcd
.DatumType
in TAB_PCD_NUMERIC_TYPES
:
1172 if ModuleDefault
.startswith('0') and not ModuleDefault
.lower().startswith('0x') and \
1173 len(ModuleDefault
) > 1 and ModuleDefault
.lstrip('0'):
1174 ModuleDefault
= ModuleDefault
.lstrip('0')
1175 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
1176 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
1177 if Pcd
.DatumType
== 'BOOLEAN':
1178 ModuleDefault
= str(ModulePcdDefaultValueNumber
)
1180 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
1183 IsByteArray
, ArrayList
= ByteArrayForamt(ModuleDefault
.strip())
1185 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 15, ModulePath
, '{'))
1186 for Array
in ArrayList
:
1187 FileWrite(File
, Array
)
1189 Value
= ModuleDefault
.strip()
1190 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1191 if Value
.startswith(('0x', '0X')):
1192 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1194 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1195 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 15, ModulePath
, Value
))
1197 if ModulePcdSet
is None:
1198 FileWrite(File
, gSectionEnd
)
1200 if not ReportSubType
and ModulePcdSet
:
1201 FileWrite(File
, gSubSectionEnd
)
1203 def ParseStruct(self
, struct
):
1204 HasDscOverride
= False
1206 for _
, Values
in list(struct
.items()):
1207 for Key
, value
in Values
.items():
1208 if value
[1] and value
[1].endswith('.dsc'):
1209 HasDscOverride
= True
1211 if HasDscOverride
== True:
1213 return HasDscOverride
1215 def PrintPcdDefault(self
, File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
):
1216 if not DscMatch
and DscDefaultValue
is not None:
1217 Value
= DscDefaultValue
.strip()
1218 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1220 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', "{"))
1221 for Array
in ArrayList
:
1222 FileWrite(File
, Array
)
1224 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1225 if Value
.startswith(('0x', '0X')):
1226 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1228 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1229 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', Value
))
1230 if not InfMatch
and InfDefaultValue
is not None:
1231 Value
= InfDefaultValue
.strip()
1232 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1234 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', "{"))
1235 for Array
in ArrayList
:
1236 FileWrite(File
, Array
)
1238 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1239 if Value
.startswith(('0x', '0X')):
1240 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1242 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1243 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', Value
))
1245 if not DecMatch
and DecDefaultValue
is not None:
1246 Value
= DecDefaultValue
.strip()
1247 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1249 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', "{"))
1250 for Array
in ArrayList
:
1251 FileWrite(File
, Array
)
1253 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1254 if Value
.startswith(('0x', '0X')):
1255 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1257 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1258 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', Value
))
1260 for filedvalues
in Pcd
.DefaultValues
.values():
1261 self
.PrintStructureInfo(File
, filedvalues
)
1262 if DecMatch
and IsStructure
:
1263 for filedvalues
in Pcd
.DefaultValues
.values():
1264 self
.PrintStructureInfo(File
, filedvalues
)
1266 def PrintPcdValue(self
, File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, Flag
= ' '):
1267 if not Pcd
.SkuInfoList
:
1268 Value
= Pcd
.DefaultValue
1269 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1271 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1272 for Array
in ArrayList
:
1273 FileWrite(File
, Array
)
1275 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1276 if Value
.startswith('0') and not Value
.lower().startswith('0x') and len(Value
) > 1 and Value
.lstrip('0'):
1277 Value
= Value
.lstrip('0')
1278 if Value
.startswith(('0x', '0X')):
1279 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1281 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1282 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1284 FiledOverrideFlag
= False
1285 if (Pcd
.TokenCName
,Pcd
.TokenSpaceGuidCName
) in GlobalData
.gPcdSkuOverrides
:
1286 OverrideValues
= GlobalData
.gPcdSkuOverrides
[(Pcd
.TokenCName
,Pcd
.TokenSpaceGuidCName
)]
1288 OverrideValues
= Pcd
.SkuOverrideValues
1290 for Data
in OverrideValues
.values():
1291 Struct
= list(Data
.values())
1293 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, Struct
[0])
1294 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1295 FiledOverrideFlag
= True
1297 if not FiledOverrideFlag
and (Pcd
.PcdFieldValueFromComm
or Pcd
.PcdFieldValueFromFdf
):
1298 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, {})
1299 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1300 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1303 SkuList
= sorted(Pcd
.SkuInfoList
.keys())
1305 SkuInfo
= Pcd
.SkuInfoList
[Sku
]
1306 SkuIdName
= SkuInfo
.SkuIdName
1307 if TypeName
in ('DYNHII', 'DEXHII'):
1308 if SkuInfo
.DefaultStoreDict
:
1309 DefaultStoreList
= sorted(SkuInfo
.DefaultStoreDict
.keys())
1310 for DefaultStore
in DefaultStoreList
:
1311 Value
= SkuInfo
.DefaultStoreDict
[DefaultStore
]
1312 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1313 if Pcd
.DatumType
== 'BOOLEAN':
1314 Value
= str(int(Value
, 0))
1318 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1319 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1320 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1321 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '{'))
1322 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1323 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', '{'))
1325 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', '{'))
1326 for Array
in ArrayList
:
1327 FileWrite(File
, Array
)
1329 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1330 if Value
.startswith(('0x', '0X')):
1331 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1333 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1334 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1335 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1336 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1337 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1338 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1339 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', Value
))
1341 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', Value
))
1344 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1345 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1346 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1347 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '{'))
1348 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1349 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', '{'))
1351 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', '{'))
1352 for Array
in ArrayList
:
1353 FileWrite(File
, Array
)
1355 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1356 if Value
.startswith(('0x', '0X')):
1357 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1359 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1360 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1361 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1362 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1363 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1364 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1365 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', Value
))
1367 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', Value
))
1368 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
1370 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1371 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[DefaultStore
])
1372 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1373 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1375 Value
= SkuInfo
.DefaultValue
1376 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1377 if Pcd
.DatumType
== 'BOOLEAN':
1378 Value
= str(int(Value
, 0))
1383 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', "{"))
1385 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', "{"))
1386 for Array
in ArrayList
:
1387 FileWrite(File
, Array
)
1389 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1390 if Value
.startswith(('0x', '0X')):
1391 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1393 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1395 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1397 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1401 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', "{"))
1403 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', "{"))
1404 for Array
in ArrayList
:
1405 FileWrite(File
, Array
)
1407 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1408 if Value
.startswith(('0x', '0X')):
1409 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1411 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1413 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1415 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1416 if TypeName
in ('DYNVPD', 'DEXVPD'):
1417 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
1418 VPDPcdItem
= (Pcd
.TokenSpaceGuidCName
+ '.' + PcdTokenCName
, SkuIdName
, SkuInfo
.VpdOffset
, Pcd
.MaxDatumSize
, SkuInfo
.DefaultValue
)
1419 if VPDPcdItem
not in VPDPcdList
:
1420 VPDPcdList
.append(VPDPcdItem
)
1422 FiledOverrideFlag
= False
1423 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1425 Keys
= list(OverrideValues
.keys())
1426 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[Keys
[0]])
1427 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1428 FiledOverrideFlag
= True
1429 if not FiledOverrideFlag
and (Pcd
.PcdFieldValueFromComm
or Pcd
.PcdFieldValueFromFdf
):
1430 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, {})
1431 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1432 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1434 def OverrideFieldValue(self
, Pcd
, OverrideStruct
):
1435 OverrideFieldStruct
= collections
.OrderedDict()
1437 for _
, Values
in OverrideStruct
.items():
1438 for Key
,value
in Values
.items():
1439 if value
[1] and value
[1].endswith('.dsc'):
1440 OverrideFieldStruct
[Key
] = value
1441 if Pcd
.PcdFieldValueFromFdf
:
1442 for Key
, Values
in Pcd
.PcdFieldValueFromFdf
.items():
1443 if Key
in OverrideFieldStruct
and Values
[0] == OverrideFieldStruct
[Key
][0]:
1445 OverrideFieldStruct
[Key
] = Values
1446 if Pcd
.PcdFieldValueFromComm
:
1447 for Key
, Values
in Pcd
.PcdFieldValueFromComm
.items():
1448 if Key
in OverrideFieldStruct
and Values
[0] == OverrideFieldStruct
[Key
][0]:
1450 OverrideFieldStruct
[Key
] = Values
1451 return OverrideFieldStruct
1453 def PrintStructureInfo(self
, File
, Struct
):
1454 for Key
, Value
in sorted(Struct
.items(), key
=lambda x
: x
[0]):
1455 if Value
[1] and 'build command options' in Value
[1]:
1456 FileWrite(File
, ' *B %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1457 elif Value
[1] and Value
[1].endswith('.fdf'):
1458 FileWrite(File
, ' *F %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1460 FileWrite(File
, ' %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1462 def StrtoHex(self
, value
):
1464 value
= hex(int(value
))
1467 if value
.startswith("L\"") and value
.endswith("\""):
1469 for ch
in value
[2:-1]:
1470 valuelist
.append(hex(ord(ch
)))
1471 valuelist
.append('0x00')
1473 elif value
.startswith("\"") and value
.endswith("\""):
1474 return hex(ord(value
[1:-1]))
1475 elif value
.startswith("{") and value
.endswith("}"):
1477 if ',' not in value
:
1479 for ch
in value
[1:-1].split(','):
1481 if ch
.startswith('0x') or ch
.startswith('0X'):
1482 valuelist
.append(ch
)
1485 valuelist
.append(hex(int(ch
.strip())))
1492 def IsStructurePcd(self
, PcdToken
, PcdTokenSpaceGuid
):
1493 if GlobalData
.gStructurePcd
and (self
.Arch
in GlobalData
.gStructurePcd
) and ((PcdToken
, PcdTokenSpaceGuid
) in GlobalData
.gStructurePcd
[self
.Arch
]):
1499 # Reports platform and module Prediction information
1501 # This class reports the platform execution order prediction section and
1502 # module load fixed address prediction subsection in the build report file.
1504 class PredictionReport(object):
1506 # Constructor function for class PredictionReport
1508 # This constructor function generates PredictionReport object for the platform.
1510 # @param self: The object pointer
1511 # @param Wa Workspace context information
1513 def __init__(self
, Wa
):
1514 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
1515 self
._MapFileParsed
= False
1516 self
._EotToolInvoked
= False
1517 self
._FvDir
= Wa
.FvDir
1518 self
._EotDir
= Wa
.BuildDir
1519 self
._FfsEntryPoint
= {}
1521 self
._SourceList
= []
1522 self
.FixedMapDict
= {}
1527 # Collect all platform reference source files and GUID C Name
1529 for Pa
in Wa
.AutoGenObjectList
:
1530 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
1532 # BASE typed modules are EFI agnostic, so we need not scan
1533 # their source code to find PPI/Protocol produce or consume
1536 if Module
.ModuleType
== SUP_MODULE_BASE
:
1539 # Add module referenced source files
1541 self
._SourceList
.append(str(Module
))
1543 for Source
in Module
.SourceFileList
:
1544 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
1545 self
._SourceList
.append(" " + str(Source
))
1546 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
1547 for IncludeFile
in IncludeList
.values():
1548 self
._SourceList
.append(" " + IncludeFile
)
1550 for Guid
in Module
.PpiList
:
1551 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
1552 for Guid
in Module
.ProtocolList
:
1553 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
1554 for Guid
in Module
.GuidList
:
1555 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
1557 if Module
.Guid
and not Module
.IsLibrary
:
1558 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
1560 RealEntryPoint
= "_ModuleEntryPoint"
1562 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
1566 # Collect platform firmware volume list as the input of EOT.
1570 for Fd
in Wa
.FdfProfile
.FdDict
:
1571 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
1572 if FdRegion
.RegionType
!= BINARY_FILE_TYPE_FV
:
1574 for FvName
in FdRegion
.RegionDataList
:
1575 if FvName
in self
._FvList
:
1577 self
._FvList
.append(FvName
)
1578 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1579 for Section
in Ffs
.SectionList
:
1581 for FvSection
in Section
.SectionList
:
1582 if FvSection
.FvName
in self
._FvList
:
1584 self
._FvList
.append(FvSection
.FvName
)
1585 except AttributeError:
1590 # Parse platform fixed address map files
1592 # This function parses the platform final fixed address map file to get
1593 # the database of predicted fixed address for module image base, entry point
1596 # @param self: The object pointer
1598 def _ParseMapFile(self
):
1599 if self
._MapFileParsed
:
1601 self
._MapFileParsed
= True
1602 if os
.path
.isfile(self
._MapFileName
):
1604 FileContents
= open(self
._MapFileName
).read()
1605 for Match
in gMapFileItemPattern
.finditer(FileContents
):
1606 AddressType
= Match
.group(1)
1607 BaseAddress
= Match
.group(2)
1608 EntryPoint
= Match
.group(3)
1609 Guid
= Match
.group(4).upper()
1610 List
= self
.FixedMapDict
.setdefault(Guid
, [])
1611 List
.append((AddressType
, BaseAddress
, "*I"))
1612 List
.append((AddressType
, EntryPoint
, "*E"))
1614 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
1617 # Invokes EOT tool to get the predicted the execution order.
1619 # This function invokes EOT tool to calculate the predicted dispatch order
1621 # @param self: The object pointer
1623 def _InvokeEotTool(self
):
1624 if self
._EotToolInvoked
:
1627 self
._EotToolInvoked
= True
1629 for FvName
in self
._FvList
:
1630 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
1631 if os
.path
.isfile(FvFile
):
1632 FvFileList
.append(FvFile
)
1634 if len(FvFileList
) == 0:
1637 # Write source file list and GUID file list to an intermediate file
1638 # as the input for EOT tool and dispatch List as the output file
1641 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
1642 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
1643 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
1646 for Item
in self
._SourceList
:
1647 FileWrite(TempFile
, Item
)
1648 SaveFileOnChange(SourceList
, "".join(TempFile
), False)
1650 for Key
in self
._GuidMap
:
1651 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
1652 SaveFileOnChange(GuidList
, "".join(TempFile
), False)
1655 from Eot
.EotMain
import Eot
1658 # Invoke EOT tool and echo its runtime performance
1660 EotStartTime
= time
.time()
1661 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
1662 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
1663 EotEndTime
= time
.time()
1664 EotDuration
= time
.strftime("%H:%M:%S", time
.gmtime(int(round(EotEndTime
- EotStartTime
))))
1665 EdkLogger
.quiet("EOT run time: %s\n" % EotDuration
)
1668 # Parse the output of EOT tool
1670 for Line
in open(DispatchList
):
1671 if len(Line
.split()) < 4:
1673 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
1674 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
1675 if len(Symbol
) > self
.MaxLen
:
1676 self
.MaxLen
= len(Symbol
)
1677 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
1679 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1680 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1684 # Generate platform execution order report
1686 # This function generates the predicted module execution order.
1688 # @param self The object pointer
1689 # @param File The file object for report
1691 def _GenerateExecutionOrderReport(self
, File
):
1692 self
._InvokeEotTool
()
1693 if len(self
.ItemList
) == 0:
1695 FileWrite(File
, gSectionStart
)
1696 FileWrite(File
, "Execution Order Prediction")
1697 FileWrite(File
, "*P PEI phase")
1698 FileWrite(File
, "*D DXE phase")
1699 FileWrite(File
, "*E Module INF entry point name")
1700 FileWrite(File
, "*N Module notification function name")
1702 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
1703 FileWrite(File
, gSectionSep
)
1704 for Item
in self
.ItemList
:
1705 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
1707 FileWrite(File
, gSectionStart
)
1710 # Generate Fixed Address report.
1712 # This function generate the predicted fixed address report for a module
1713 # specified by Guid.
1715 # @param self The object pointer
1716 # @param File The file object for report
1717 # @param Guid The module Guid value.
1718 # @param NotifyList The list of all notify function in a module
1720 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
1721 self
._ParseMapFile
()
1722 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
1723 if not FixedAddressList
:
1726 FileWrite(File
, gSubSectionStart
)
1727 FileWrite(File
, "Fixed Address Prediction")
1728 FileWrite(File
, "*I Image Loading Address")
1729 FileWrite(File
, "*E Entry Point Address")
1730 FileWrite(File
, "*N Notification Function Address")
1731 FileWrite(File
, "*F Flash Address")
1732 FileWrite(File
, "*M Memory Address")
1733 FileWrite(File
, "*S SMM RAM Offset")
1734 FileWrite(File
, "TOM Top of Memory")
1736 FileWrite(File
, "Type Address Name")
1737 FileWrite(File
, gSubSectionSep
)
1738 for Item
in FixedAddressList
:
1743 Name
= "(Image Base)"
1744 elif Symbol
== "*E":
1745 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
1746 elif Symbol
in NotifyList
:
1754 elif "Memory" in Type
:
1760 Value
= "TOM" + Value
1762 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
1765 # Generate report for the prediction part
1767 # This function generate the predicted fixed address report for a module or
1768 # predicted module execution order for a platform.
1769 # If the input Guid is None, then, it generates the predicted module execution order;
1770 # otherwise it generated the module fixed loading address for the module specified by
1773 # @param self The object pointer
1774 # @param File The file object for report
1775 # @param Guid The module Guid value.
1777 def GenerateReport(self
, File
, Guid
):
1779 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1781 self
._GenerateExecutionOrderReport
(File
)
1784 # Reports FD region information
1786 # This class reports the FD subsection in the build report file.
1787 # It collects region information of platform flash device.
1788 # If the region is a firmware volume, it lists the set of modules
1789 # and its space information; otherwise, it only lists its region name,
1790 # base address and size in its sub-section header.
1791 # If there are nesting FVs, the nested FVs will list immediate after
1792 # this FD region subsection
1794 class FdRegionReport(object):
1796 # Discover all the nested FV name list.
1798 # This is an internal worker function to discover the all the nested FV information
1799 # in the parent firmware volume. It uses deep first search algorithm recursively to
1800 # find all the FV list name and append them to the list.
1802 # @param self The object pointer
1803 # @param FvName The name of current firmware file system
1804 # @param Wa Workspace context information
1806 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1807 FvDictKey
=FvName
.upper()
1808 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1809 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1810 for Section
in Ffs
.SectionList
:
1812 for FvSection
in Section
.SectionList
:
1813 if FvSection
.FvName
in self
.FvList
:
1815 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1816 self
.FvList
.append(FvSection
.FvName
)
1817 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1818 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1819 except AttributeError:
1823 # Constructor function for class FdRegionReport
1825 # This constructor function generates FdRegionReport object for a specified FdRegion.
1826 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1827 # volume list. This function also collects GUID map in order to dump module identification
1828 # in the final report.
1830 # @param self: The object pointer
1831 # @param FdRegion The current FdRegion object
1832 # @param Wa Workspace context information
1834 def __init__(self
, FdRegion
, Wa
):
1835 self
.Type
= FdRegion
.RegionType
1836 self
.BaseAddress
= FdRegion
.Offset
1837 self
.Size
= FdRegion
.Size
1841 self
._FvDir
= Wa
.FvDir
1842 self
._WorkspaceDir
= Wa
.WorkspaceDir
1845 # If the input FdRegion is not a firmware volume,
1848 if self
.Type
!= BINARY_FILE_TYPE_FV
:
1852 # Find all nested FVs in the FdRegion
1854 for FvName
in FdRegion
.RegionDataList
:
1855 if FvName
in self
.FvList
:
1857 self
.FvList
.append(FvName
)
1858 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1859 self
._DiscoverNestedFvList
(FvName
, Wa
)
1863 # Collect PCDs declared in DEC files.
1865 for Pa
in Wa
.AutoGenObjectList
:
1866 for Package
in Pa
.PackageList
:
1867 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1868 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1869 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1871 # Collect PCDs defined in DSC file
1873 for Pa
in Wa
.AutoGenObjectList
:
1874 for (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
1875 DscDefaultValue
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1876 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1879 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1881 self
._GuidsDb
[PEI_APRIORI_GUID
] = "PEI Apriori"
1882 self
._GuidsDb
[DXE_APRIORI_GUID
] = "DXE Apriori"
1884 # Add ACPI table storage file
1886 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1888 for Pa
in Wa
.AutoGenObjectList
:
1889 for ModuleKey
in Pa
.Platform
.Modules
:
1890 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1891 InfPath
= mws
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1892 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1895 # Collect the GUID map in the FV firmware volume
1897 for FvName
in self
.FvList
:
1898 FvDictKey
=FvName
.upper()
1899 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1900 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1903 # collect GUID map for binary EFI file in FDF file.
1905 Guid
= Ffs
.NameGuid
.upper()
1906 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1908 PcdTokenspace
= Match
.group(1)
1909 PcdToken
= Match
.group(2)
1910 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1911 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1912 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1913 for Section
in Ffs
.SectionList
:
1915 ModuleSectFile
= mws
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1916 self
._GuidsDb
[Guid
] = ModuleSectFile
1917 except AttributeError:
1919 except AttributeError:
1924 # Internal worker function to generate report for the FD region
1926 # This internal worker function to generate report for the FD region.
1927 # It the type is firmware volume, it lists offset and module identification.
1929 # @param self The object pointer
1930 # @param File The file object for report
1931 # @param Title The title for the FD subsection
1932 # @param BaseAddress The base address for the FD region
1933 # @param Size The size of the FD region
1934 # @param FvName The FV name if the FD region is a firmware volume
1936 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1937 FileWrite(File
, gSubSectionStart
)
1938 FileWrite(File
, Title
)
1939 FileWrite(File
, "Type: %s" % Type
)
1940 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1942 if self
.Type
== BINARY_FILE_TYPE_FV
:
1946 if FvName
.upper().endswith('.FV'):
1947 FileExt
= FvName
+ ".txt"
1949 FileExt
= FvName
+ ".Fv.txt"
1951 if not os
.path
.isfile(FileExt
):
1952 FvReportFileName
= mws
.join(self
._WorkspaceDir
, FileExt
)
1953 if not os
.path
.isfile(FvReportFileName
):
1954 FvReportFileName
= os
.path
.join(self
._FvDir
, FileExt
)
1957 # Collect size info in the firmware volume.
1959 FvReport
= open(FvReportFileName
).read()
1960 Match
= gFvTotalSizePattern
.search(FvReport
)
1962 FvTotalSize
= int(Match
.group(1), 16)
1963 Match
= gFvTakenSizePattern
.search(FvReport
)
1965 FvTakenSize
= int(Match
.group(1), 16)
1966 FvFreeSize
= FvTotalSize
- FvTakenSize
1968 # Write size information to the report file.
1970 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1971 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1972 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1973 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1974 FileWrite(File
, "Offset Module")
1975 FileWrite(File
, gSubSectionSep
)
1977 # Write module offset and module identification to the report file.
1980 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1981 Guid
= Match
.group(2).upper()
1982 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1983 OffsetList
= sorted(OffsetInfo
.keys())
1984 for Offset
in OffsetList
:
1985 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1987 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
1989 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
1990 FileWrite(File
, gSubSectionEnd
)
1993 # Generate report for the FD region
1995 # This function generates report for the FD region.
1997 # @param self The object pointer
1998 # @param File The file object for report
2000 def GenerateReport(self
, File
):
2001 if (len(self
.FvList
) > 0):
2002 for FvItem
in self
.FvList
:
2003 Info
= self
.FvInfo
[FvItem
]
2004 self
._GenerateReport
(File
, Info
[0], TAB_FV_DIRECTORY
, Info
[1], Info
[2], FvItem
)
2006 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
2009 # Reports FD information
2011 # This class reports the FD section in the build report file.
2012 # It collects flash device information for a platform.
2014 class FdReport(object):
2016 # Constructor function for class FdReport
2018 # This constructor function generates FdReport object for a specified
2021 # @param self The object pointer
2022 # @param Fd The current Firmware device object
2023 # @param Wa Workspace context information
2025 def __init__(self
, Fd
, Wa
):
2026 self
.FdName
= Fd
.FdUiName
2027 self
.BaseAddress
= Fd
.BaseAddress
2029 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
2030 self
.FvPath
= os
.path
.join(Wa
.BuildDir
, TAB_FV_DIRECTORY
)
2031 self
.VPDBaseAddress
= 0
2033 for index
, FdRegion
in enumerate(Fd
.RegionList
):
2034 if str(FdRegion
.RegionType
) is 'FILE' and Wa
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
2035 self
.VPDBaseAddress
= self
.FdRegionList
[index
].BaseAddress
2036 self
.VPDSize
= self
.FdRegionList
[index
].Size
2040 # Generate report for the firmware device.
2042 # This function generates report for the firmware device.
2044 # @param self The object pointer
2045 # @param File The file object for report
2047 def GenerateReport(self
, File
):
2048 FileWrite(File
, gSectionStart
)
2049 FileWrite(File
, "Firmware Device (FD)")
2050 FileWrite(File
, "FD Name: %s" % self
.FdName
)
2051 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
2052 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
2053 if len(self
.FdRegionList
) > 0:
2054 FileWrite(File
, gSectionSep
)
2055 for FdRegionItem
in self
.FdRegionList
:
2056 FdRegionItem
.GenerateReport(File
)
2059 VPDPcdList
.sort(key
=lambda x
: int(x
[2], 0))
2060 FileWrite(File
, gSubSectionStart
)
2061 FileWrite(File
, "FD VPD Region")
2062 FileWrite(File
, "Base Address: 0x%X" % self
.VPDBaseAddress
)
2063 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.VPDSize
, self
.VPDSize
/ 1024.0))
2064 FileWrite(File
, gSubSectionSep
)
2065 for item
in VPDPcdList
:
2066 # Add BaseAddress for offset
2067 Offset
= '0x%08X' % (int(item
[2], 16) + self
.VPDBaseAddress
)
2068 IsByteArray
, ArrayList
= ByteArrayForamt(item
[-1])
2070 if len(GlobalData
.gSkuids
) == 1 :
2071 Skuinfo
= GlobalData
.gSkuids
[0]
2073 FileWrite(File
, "%s | %s | %s | %s | %s" % (item
[0], Skuinfo
, Offset
, item
[3], '{'))
2074 for Array
in ArrayList
:
2075 FileWrite(File
, Array
)
2077 FileWrite(File
, "%s | %s | %s | %s | %s" % (item
[0], Skuinfo
, Offset
, item
[3], item
[-1]))
2078 FileWrite(File
, gSubSectionEnd
)
2079 FileWrite(File
, gSectionEnd
)
2084 # Reports platform information
2086 # This class reports the whole platform information
2088 class PlatformReport(object):
2090 # Constructor function for class PlatformReport
2092 # This constructor function generates PlatformReport object a platform build.
2093 # It generates report for platform summary, flash, global PCDs and detailed
2094 # module information for modules involved in platform build.
2096 # @param self The object pointer
2097 # @param Wa Workspace context information
2098 # @param MaList The list of modules in the platform build
2100 def __init__(self
, Wa
, MaList
, ReportType
):
2101 self
._WorkspaceDir
= Wa
.WorkspaceDir
2102 self
.PlatformName
= Wa
.Name
2103 self
.PlatformDscPath
= Wa
.Platform
2104 self
.Architectures
= " ".join(Wa
.ArchList
)
2105 self
.ToolChain
= Wa
.ToolChain
2106 self
.Target
= Wa
.BuildTarget
2107 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
2108 self
.BuildEnvironment
= platform
.platform()
2110 self
.PcdReport
= None
2111 if "PCD" in ReportType
:
2112 self
.PcdReport
= PcdReport(Wa
)
2114 self
.FdReportList
= []
2115 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
is None:
2116 for Fd
in Wa
.FdfProfile
.FdDict
:
2117 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
2119 self
.PredictionReport
= None
2120 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
2121 self
.PredictionReport
= PredictionReport(Wa
)
2123 self
.DepexParser
= None
2124 if "DEPEX" in ReportType
:
2125 self
.DepexParser
= DepexParser(Wa
)
2127 self
.ModuleReportList
= []
2128 if MaList
is not None:
2129 self
._IsModuleBuild
= True
2131 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
2133 self
._IsModuleBuild
= False
2134 for Pa
in Wa
.AutoGenObjectList
:
2135 ModuleAutoGenList
= []
2136 for ModuleKey
in Pa
.Platform
.Modules
:
2137 ModuleAutoGenList
.append(Pa
.Platform
.Modules
[ModuleKey
].M
)
2138 if GlobalData
.gFdfParser
is not None:
2139 if Pa
.Arch
in GlobalData
.gFdfParser
.Profile
.InfDict
:
2140 INFList
= GlobalData
.gFdfParser
.Profile
.InfDict
[Pa
.Arch
]
2141 for InfName
in INFList
:
2142 InfClass
= PathClass(NormPath(InfName
), Wa
.WorkspaceDir
, Pa
.Arch
)
2143 Ma
= ModuleAutoGen(Wa
, InfClass
, Pa
.BuildTarget
, Pa
.ToolChain
, Pa
.Arch
, Wa
.MetaFile
)
2146 if Ma
not in ModuleAutoGenList
:
2147 ModuleAutoGenList
.append(Ma
)
2148 for MGen
in ModuleAutoGenList
:
2149 self
.ModuleReportList
.append(ModuleReport(MGen
, ReportType
))
2154 # Generate report for the whole platform.
2156 # This function generates report for platform information.
2157 # It comprises of platform summary, global PCD, flash and
2158 # module list sections.
2160 # @param self The object pointer
2161 # @param File The file object for report
2162 # @param BuildDuration The total time to build the modules
2163 # @param AutoGenTime The total time of AutoGen Phase
2164 # @param MakeTime The total time of Make Phase
2165 # @param GenFdsTime The total time of GenFds Phase
2166 # @param ReportType The kind of report items in the final report file
2168 def GenerateReport(self
, File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, ReportType
):
2169 FileWrite(File
, "Platform Summary")
2170 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
2171 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
2172 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
2173 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
2174 FileWrite(File
, "Target: %s" % self
.Target
)
2175 if GlobalData
.gSkuids
:
2176 FileWrite(File
, "SKUID: %s" % " ".join(GlobalData
.gSkuids
))
2177 if GlobalData
.gDefaultStores
:
2178 FileWrite(File
, "DefaultStore: %s" % " ".join(GlobalData
.gDefaultStores
))
2179 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
2180 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
2181 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
2183 FileWrite(File
, "AutoGen Duration: %s" % AutoGenTime
)
2185 FileWrite(File
, "Make Duration: %s" % MakeTime
)
2187 FileWrite(File
, "GenFds Duration: %s" % GenFdsTime
)
2188 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
2190 if GlobalData
.MixedPcd
:
2191 FileWrite(File
, gSectionStart
)
2192 FileWrite(File
, "The following PCDs use different access methods:")
2193 FileWrite(File
, gSectionSep
)
2194 for PcdItem
in GlobalData
.MixedPcd
:
2195 FileWrite(File
, "%s.%s" % (str(PcdItem
[1]), str(PcdItem
[0])))
2196 FileWrite(File
, gSectionEnd
)
2198 if not self
._IsModuleBuild
:
2199 if "PCD" in ReportType
:
2200 self
.PcdReport
.GenerateReport(File
, None)
2202 if "FLASH" in ReportType
:
2203 for FdReportListItem
in self
.FdReportList
:
2204 FdReportListItem
.GenerateReport(File
)
2206 for ModuleReportItem
in self
.ModuleReportList
:
2207 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, self
.DepexParser
, ReportType
)
2209 if not self
._IsModuleBuild
:
2210 if "EXECUTION_ORDER" in ReportType
:
2211 self
.PredictionReport
.GenerateReport(File
, None)
2213 ## BuildReport class
2215 # This base class contain the routines to collect data and then
2216 # applies certain format to the output report
2218 class BuildReport(object):
2220 # Constructor function for class BuildReport
2222 # This constructor function generates BuildReport object a platform build.
2223 # It generates report for platform summary, flash, global PCDs and detailed
2224 # module information for modules involved in platform build.
2226 # @param self The object pointer
2227 # @param ReportFile The file name to save report file
2228 # @param ReportType The kind of report items in the final report file
2230 def __init__(self
, ReportFile
, ReportType
):
2231 self
.ReportFile
= ReportFile
2233 self
.ReportList
= []
2234 self
.ReportType
= []
2236 for ReportTypeItem
in ReportType
:
2237 if ReportTypeItem
not in self
.ReportType
:
2238 self
.ReportType
.append(ReportTypeItem
)
2240 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]
2242 # Adds platform report to the list
2244 # This function adds a platform report to the final report list.
2246 # @param self The object pointer
2247 # @param Wa Workspace context information
2248 # @param MaList The list of modules in the platform build
2250 def AddPlatformReport(self
, Wa
, MaList
=None):
2252 self
.ReportList
.append((Wa
, MaList
))
2255 # Generates the final report.
2257 # This function generates platform build report. It invokes GenerateReport()
2258 # method for every platform report in the list.
2260 # @param self The object pointer
2261 # @param BuildDuration The total time to build the modules
2262 # @param AutoGenTime The total time of AutoGen phase
2263 # @param MakeTime The total time of Make phase
2264 # @param GenFdsTime The total time of GenFds phase
2266 def GenerateReport(self
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
):
2270 for (Wa
, MaList
) in self
.ReportList
:
2271 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, self
.ReportType
)
2272 Content
= FileLinesSplit(''.join(File
), gLineMaxLength
)
2273 SaveFileOnChange(self
.ReportFile
, Content
, False)
2274 EdkLogger
.quiet("Build report can be found at %s" % os
.path
.abspath(self
.ReportFile
))
2276 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
2278 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
2279 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
2281 # This acts like the main() function for the script, unless it is 'import'ed into another script.
2282 if __name__
== '__main__':