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
.ModuleAutoGen
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*Type=\w+\)\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
.ModuleArch
= M
.Arch
562 self
.FileGuid
= M
.Guid
564 self
.BuildTimeStamp
= None
568 ModuleType
= M
.ModuleType
570 ModuleType
= COMPONENT_TO_MODULE_MAP_DICT
.get(M
.ComponentType
, "")
572 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
574 if ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
575 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
576 if int(PiSpec
, 0) >= 0x0001000A:
577 ModuleType
= "SMM_DRIVER"
578 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "0x2 (FREE_FORM)")
579 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
580 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
581 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
582 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
583 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
584 self
.BuildTime
= M
.BuildTime
586 self
._BuildDir
= M
.BuildDir
587 self
.ModulePcdSet
= {}
588 if "PCD" in ReportType
:
590 # Collect all module used PCD set: module INF referenced directly or indirectly.
591 # It also saves module INF default values of them in case they exist.
593 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
594 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
596 self
.LibraryReport
= None
597 if "LIBRARY" in ReportType
:
598 self
.LibraryReport
= LibraryReport(M
)
600 self
.DepexReport
= None
601 if "DEPEX" in ReportType
:
602 self
.DepexReport
= DepexReport(M
)
604 if "BUILD_FLAGS" in ReportType
:
605 self
.BuildFlagsReport
= BuildFlagsReport(M
)
609 # Generate report for module information
611 # This function generates report for separate module expression
612 # in a platform build.
614 # @param self The object pointer
615 # @param File The file object for report
616 # @param GlobalPcdReport The platform global PCD report object
617 # @param GlobalPredictionReport The platform global Prediction report object
618 # @param GlobalDepexParser The platform global Dependency expression parser object
619 # @param ReportType The kind of report items in the final report file
621 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, GlobalDepexParser
, ReportType
):
622 FileWrite(File
, gSectionStart
)
624 FwReportFileName
= os
.path
.join(self
._BuildDir
, "OUTPUT", self
.ModuleName
+ ".txt")
625 if os
.path
.isfile(FwReportFileName
):
627 FileContents
= open(FwReportFileName
).read()
628 Match
= gModuleSizePattern
.search(FileContents
)
630 self
.Size
= int(Match
.group(1))
632 Match
= gTimeStampPattern
.search(FileContents
)
634 self
.BuildTimeStamp
= datetime
.utcfromtimestamp(int(Match
.group(1)))
636 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
638 if "HASH" in ReportType
:
639 OutputDir
= os
.path
.join(self
._BuildDir
, "OUTPUT")
640 DefaultEFIfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ ".efi")
641 if os
.path
.isfile(DefaultEFIfile
):
642 Tempfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ "_hash.tmp")
643 # rebase the efi image since its base address may not zero
644 cmd
= ["GenFw", "--rebase", str(0), "-o", Tempfile
, DefaultEFIfile
]
646 PopenObject
= subprocess
.Popen(' '.join(cmd
), stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
647 except Exception as X
:
648 EdkLogger
.error("GenFw", COMMAND_FAILURE
, ExtraData
="%s: %s" % (str(X
), cmd
[0]))
649 EndOfProcedure
= threading
.Event()
650 EndOfProcedure
.clear()
651 if PopenObject
.stderr
:
652 StdErrThread
= threading
.Thread(target
=ReadMessage
, args
=(PopenObject
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
653 StdErrThread
.setName("STDERR-Redirector")
654 StdErrThread
.setDaemon(False)
656 # waiting for program exit
658 if PopenObject
.stderr
:
660 if PopenObject
.returncode
!= 0:
661 EdkLogger
.error("GenFw", COMMAND_FAILURE
, "Failed to generate firmware hash image for %s" % (DefaultEFIfile
))
662 if os
.path
.isfile(Tempfile
):
663 self
.Hash
= hashlib
.sha1()
664 buf
= open(Tempfile
, 'rb').read()
665 if self
.Hash
.update(buf
):
666 self
.Hash
= self
.Hash
.update(buf
)
667 self
.Hash
= self
.Hash
.hexdigest()
670 FileWrite(File
, "Module Summary")
671 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
672 FileWrite(File
, "Module Arch: %s" % self
.ModuleArch
)
673 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
674 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
676 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
678 FileWrite(File
, "SHA1 HASH: %s *%s" % (self
.Hash
, self
.ModuleName
+ ".efi"))
679 if self
.BuildTimeStamp
:
680 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
682 FileWrite(File
, "Module Build Time: %s" % self
.BuildTime
)
684 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
685 if self
.UefiSpecVersion
:
686 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
687 if self
.PiSpecVersion
:
688 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
690 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
692 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
693 if self
.PciClassCode
:
694 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
696 FileWrite(File
, gSectionSep
)
698 if "PCD" in ReportType
:
699 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
,self
.FileGuid
)
701 if "LIBRARY" in ReportType
:
702 self
.LibraryReport
.GenerateReport(File
)
704 if "DEPEX" in ReportType
:
705 self
.DepexReport
.GenerateReport(File
, GlobalDepexParser
)
707 if "BUILD_FLAGS" in ReportType
:
708 self
.BuildFlagsReport
.GenerateReport(File
)
710 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
711 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
713 FileWrite(File
, gSectionEnd
)
715 def ReadMessage(From
, To
, ExitFlag
):
717 # read one line a time
718 Line
= From
.readline()
719 # empty string means "end"
720 if Line
is not None and Line
!= b
"":
721 To(Line
.rstrip().decode(encoding
='utf-8', errors
='ignore'))
728 # Reports platform and module PCD information
730 # This class reports the platform PCD section and module PCD subsection
731 # in the build report file.
733 class PcdReport(object):
735 # Constructor function for class PcdReport
737 # This constructor function generates PcdReport object a platform build.
738 # It collects the whole PCD database from platform DSC files, platform
739 # flash description file and package DEC files.
741 # @param self The object pointer
742 # @param Wa Workspace context information
744 def __init__(self
, Wa
):
747 self
.ConditionalPcds
= {}
751 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
755 self
.DefaultStoreSingle
= True
756 self
.SkuSingle
= True
757 if GlobalData
.gDefaultStores
and len(GlobalData
.gDefaultStores
) > 1:
758 self
.DefaultStoreSingle
= False
759 if GlobalData
.gSkuids
and len(GlobalData
.gSkuids
) > 1:
760 self
.SkuSingle
= False
762 self
.ModulePcdOverride
= {}
763 for Pa
in Wa
.AutoGenObjectList
:
766 # Collect all platform referenced PCDs and grouped them by PCD token space
769 for Pcd
in Pa
.AllPcdList
:
770 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
771 if Pcd
not in PcdList
:
773 if len(Pcd
.TokenCName
) > self
.MaxLen
:
774 self
.MaxLen
= len(Pcd
.TokenCName
)
776 # Collect the PCD defined in DSC/FDF file, but not used in module
778 UnusedPcdFullList
= []
779 StructPcdDict
= GlobalData
.gStructurePcd
.get(self
.Arch
, collections
.OrderedDict())
780 for Name
, Guid
in StructPcdDict
:
781 if (Name
, Guid
) not in Pa
.Platform
.Pcds
:
782 Pcd
= StructPcdDict
[(Name
, Guid
)]
783 PcdList
= self
.AllPcds
.setdefault(Guid
, {}).setdefault(Pcd
.Type
, [])
784 if Pcd
not in PcdList
and Pcd
not in UnusedPcdFullList
:
785 UnusedPcdFullList
.append(Pcd
)
786 for item
in Pa
.Platform
.Pcds
:
787 Pcd
= Pa
.Platform
.Pcds
[item
]
789 # check the Pcd in FDF file, whether it is used in module first
790 for T
in PCD_TYPE_LIST
:
791 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(T
, [])
797 for package
in Pa
.PackageList
:
798 for T
in PCD_TYPE_LIST
:
799 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
) in package
.Pcds
:
802 if not Pcd
.DatumType
:
803 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
)].DatumType
807 if not Pcd
.DatumType
:
809 # Try to remove Hii and Vpd suffix
810 if PcdType
.startswith(TAB_PCDS_DYNAMIC_EX
):
811 PcdType
= TAB_PCDS_DYNAMIC_EX
812 elif PcdType
.startswith(TAB_PCDS_DYNAMIC
):
813 PcdType
= TAB_PCDS_DYNAMIC
814 for package
in Pa
.PackageList
:
815 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
) in package
.Pcds
:
816 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
)].DatumType
819 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
820 UnusedPcdList
= self
.UnusedPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
821 if Pcd
in UnusedPcdList
:
822 UnusedPcdList
.remove(Pcd
)
823 if Pcd
not in PcdList
and Pcd
not in UnusedPcdFullList
:
824 UnusedPcdFullList
.append(Pcd
)
825 if len(Pcd
.TokenCName
) > self
.MaxLen
:
826 self
.MaxLen
= len(Pcd
.TokenCName
)
828 if GlobalData
.gConditionalPcds
:
829 for PcdItem
in GlobalData
.gConditionalPcds
:
831 (TokenSpaceGuidCName
, TokenCName
) = PcdItem
.split('.')
832 if (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
833 Pcd
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)]
834 PcdList
= self
.ConditionalPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
835 if Pcd
not in PcdList
:
839 if UnusedPcdFullList
:
840 for Pcd
in UnusedPcdFullList
:
841 if Pcd
.TokenSpaceGuidCName
+ '.' + Pcd
.TokenCName
in GlobalData
.gConditionalPcds
:
843 UnusedPcdList
.append(Pcd
)
845 for Pcd
in UnusedPcdList
:
846 PcdList
= self
.UnusedPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
847 if Pcd
not in PcdList
:
850 for Module
in Pa
.Platform
.Modules
.values():
852 # Collect module override PCDs
854 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
855 TokenCName
= ModulePcd
.TokenCName
856 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
857 ModuleDefault
= ModulePcd
.DefaultValue
858 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
859 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
863 # Collect PCD DEC default value.
865 self
.DecPcdDefault
= {}
867 for Pa
in Wa
.AutoGenObjectList
:
868 for Package
in Pa
.PackageList
:
869 Guids
= Package
.Guids
870 self
._GuidDict
.update(Guids
)
871 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
872 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
873 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
875 # Collect PCDs defined in DSC common section
877 self
.DscPcdDefault
= {}
878 for Pa
in Wa
.AutoGenObjectList
:
879 for (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
880 DscDefaultValue
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DscDefaultValue
882 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
884 def GenerateReport(self
, File
, ModulePcdSet
,ModuleGuid
=None):
886 if self
.ConditionalPcds
:
887 self
.GenerateReportDetail(File
, ModulePcdSet
, 1)
890 for Token
in self
.UnusedPcds
:
891 TokenDict
= self
.UnusedPcds
[Token
]
892 for Type
in TokenDict
:
899 self
.GenerateReportDetail(File
, ModulePcdSet
, 2)
900 self
.GenerateReportDetail(File
, ModulePcdSet
,ModuleGuid
= ModuleGuid
)
903 # Generate report for PCD information
905 # This function generates report for separate module expression
906 # in a platform build.
908 # @param self The object pointer
909 # @param File The file object for report
910 # @param ModulePcdSet Set of all PCDs referenced by module or None for
911 # platform PCD report
912 # @param ReportySubType 0 means platform/module PCD report, 1 means Conditional
913 # directives section report, 2 means Unused Pcds section report
914 # @param DscOverridePcds Module DSC override PCDs set
916 def GenerateReportDetail(self
, File
, ModulePcdSet
, ReportSubType
= 0,ModuleGuid
=None):
917 PcdDict
= self
.AllPcds
918 if ReportSubType
== 1:
919 PcdDict
= self
.ConditionalPcds
920 elif ReportSubType
== 2:
921 PcdDict
= self
.UnusedPcds
924 FileWrite(File
, gSectionStart
)
925 if ReportSubType
== 1:
926 FileWrite(File
, "Conditional Directives used by the build system")
927 elif ReportSubType
== 2:
928 FileWrite(File
, "PCDs not used by modules or in conditional directives")
930 FileWrite(File
, "Platform Configuration Database Report")
932 FileWrite(File
, " *B - PCD override in the build option")
933 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
934 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
935 if not ReportSubType
:
936 FileWrite(File
, " *M - Module scoped PCD override")
937 FileWrite(File
, gSectionSep
)
939 if not ReportSubType
and ModulePcdSet
:
941 # For module PCD sub-section
943 FileWrite(File
, gSubSectionStart
)
944 FileWrite(File
, TAB_BRG_PCD
)
945 FileWrite(File
, gSubSectionSep
)
949 for Type
in PcdDict
[Key
]:
950 for Pcd
in PcdDict
[Key
][Type
]:
951 AllPcdDict
[Key
][(Pcd
.TokenCName
, Type
)] = Pcd
952 for Key
in sorted(AllPcdDict
):
954 # Group PCD by their token space GUID C Name
957 for PcdTokenCName
, Type
in sorted(AllPcdDict
[Key
]):
959 # Group PCD by their usage type
961 Pcd
= AllPcdDict
[Key
][(PcdTokenCName
, Type
)]
962 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
964 if GlobalData
.MixedPcd
:
965 for PcdKey
in GlobalData
.MixedPcd
:
966 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdKey
]:
967 PcdTokenCName
= PcdKey
[0]
969 if MixedPcdFlag
and not ModulePcdSet
:
972 # Get PCD default value and their override relationship
974 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
975 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
976 DscDefaultValBak
= DscDefaultValue
978 for (CName
, Guid
, Field
) in self
.FdfPcdSet
:
979 if CName
== PcdTokenCName
and Guid
== Key
:
980 DscDefaultValue
= self
.FdfPcdSet
[(CName
, Guid
, Field
)]
982 if DscDefaultValue
!= DscDefaultValBak
:
984 DscDefaultValue
= ValueExpressionEx(DscDefaultValue
, Pcd
.DatumType
, self
._GuidDict
)(True)
985 except BadExpression
as DscDefaultValue
:
986 EdkLogger
.error('BuildReport', FORMAT_INVALID
, "PCD Value: %s, Type: %s" %(DscDefaultValue
, Pcd
.DatumType
))
988 InfDefaultValue
= None
990 PcdValue
= DecDefaultValue
992 PcdValue
= DscDefaultValue
993 #The DefaultValue of StructurePcd already be the latest, no need to update.
994 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
995 Pcd
.DefaultValue
= PcdValue
996 PcdComponentValue
= None
997 if ModulePcdSet
is not None:
998 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
1000 InfDefaultValue
, PcdComponentValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
1001 PcdValue
= PcdComponentValue
1002 #The DefaultValue of StructurePcd already be the latest, no need to update.
1003 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1004 Pcd
.DefaultValue
= PcdValue
1007 InfDefaultValue
= ValueExpressionEx(InfDefaultValue
, Pcd
.DatumType
, self
._GuidDict
)(True)
1008 except BadExpression
as InfDefaultValue
:
1009 EdkLogger
.error('BuildReport', FORMAT_INVALID
, "PCD Value: %s, Type: %s" % (InfDefaultValue
, Pcd
.DatumType
))
1010 if InfDefaultValue
== "":
1011 InfDefaultValue
= None
1013 BuildOptionMatch
= False
1014 if GlobalData
.BuildOptionPcd
:
1015 for pcd
in GlobalData
.BuildOptionPcd
:
1016 if (Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
) == (pcd
[0], pcd
[1]):
1020 #The DefaultValue of StructurePcd already be the latest, no need to update.
1021 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1022 Pcd
.DefaultValue
= PcdValue
1023 BuildOptionMatch
= True
1027 if ModulePcdSet
is None:
1029 FileWrite(File
, Key
)
1033 if Pcd
.DatumType
in TAB_PCD_NUMERIC_TYPES
:
1034 if PcdValue
.startswith('0') and not PcdValue
.lower().startswith('0x') and \
1035 len(PcdValue
) > 1 and PcdValue
.lstrip('0'):
1036 PcdValue
= PcdValue
.lstrip('0')
1037 PcdValueNumber
= int(PcdValue
.strip(), 0)
1038 if DecDefaultValue
is None:
1041 if DecDefaultValue
.startswith('0') and not DecDefaultValue
.lower().startswith('0x') and \
1042 len(DecDefaultValue
) > 1 and DecDefaultValue
.lstrip('0'):
1043 DecDefaultValue
= DecDefaultValue
.lstrip('0')
1044 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
1045 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
1047 if InfDefaultValue
is None:
1050 if InfDefaultValue
.startswith('0') and not InfDefaultValue
.lower().startswith('0x') and \
1051 len(InfDefaultValue
) > 1 and InfDefaultValue
.lstrip('0'):
1052 InfDefaultValue
= InfDefaultValue
.lstrip('0')
1053 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
1054 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
1056 if DscDefaultValue
is None:
1059 if DscDefaultValue
.startswith('0') and not DscDefaultValue
.lower().startswith('0x') and \
1060 len(DscDefaultValue
) > 1 and DscDefaultValue
.lstrip('0'):
1061 DscDefaultValue
= DscDefaultValue
.lstrip('0')
1062 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
1063 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
1065 if DecDefaultValue
is None:
1068 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
1070 if InfDefaultValue
is None:
1073 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
1075 if DscDefaultValue
is None:
1078 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
1081 if self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1083 if TypeName
in ('DYNVPD', 'DEXVPD'):
1084 SkuInfoList
= Pcd
.SkuInfoList
1085 Pcd
= GlobalData
.gStructurePcd
[self
.Arch
][(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
)]
1086 if ModulePcdSet
and ModulePcdSet
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
)):
1087 InfDefaultValue
, PcdComponentValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
1088 DscDefaultValBak
= Pcd
.DefaultValue
1089 Pcd
.DefaultValue
= PcdComponentValue
1091 Pcd
.DatumType
= Pcd
.StructName
1092 if TypeName
in ('DYNVPD', 'DEXVPD'):
1093 Pcd
.SkuInfoList
= SkuInfoList
1094 if Pcd
.PcdValueFromComm
or Pcd
.PcdFieldValueFromComm
:
1095 BuildOptionMatch
= True
1097 elif Pcd
.PcdValueFromFdf
or Pcd
.PcdFieldValueFromFdf
:
1098 DscDefaultValue
= True
1102 if Pcd
.Type
in PCD_DYNAMIC_TYPE_SET | PCD_DYNAMIC_EX_TYPE_SET
:
1104 if Pcd
.DefaultFromDSC
:
1108 for item
in Pcd
.SkuOverrideValues
:
1109 DictLen
+= len(Pcd
.SkuOverrideValues
[item
])
1113 if not Pcd
.SkuInfoList
:
1114 OverrideValues
= Pcd
.SkuOverrideValues
1116 for Data
in OverrideValues
.values():
1117 Struct
= list(Data
.values())
1119 DscOverride
= self
.ParseStruct(Struct
[0])
1122 SkuList
= sorted(Pcd
.SkuInfoList
.keys())
1124 SkuInfo
= Pcd
.SkuInfoList
[Sku
]
1125 if SkuInfo
.DefaultStoreDict
:
1126 DefaultStoreList
= sorted(SkuInfo
.DefaultStoreDict
.keys())
1127 for DefaultStore
in DefaultStoreList
:
1128 OverrideValues
= Pcd
.SkuOverrideValues
.get(Sku
)
1130 DscOverride
= self
.ParseStruct(OverrideValues
[DefaultStore
])
1136 DscDefaultValue
= True
1142 if Pcd
.DscRawValue
or (ModuleGuid
and ModuleGuid
.replace("-","S") in Pcd
.PcdValueFromComponents
):
1143 DscDefaultValue
= True
1147 DscDefaultValue
= False
1151 # Report PCD item according to their override relationship
1153 if Pcd
.DatumType
== 'BOOLEAN':
1155 DscDefaultValue
= str(int(DscDefaultValue
, 0))
1157 DecDefaultValue
= str(int(DecDefaultValue
, 0))
1159 InfDefaultValue
= str(int(InfDefaultValue
, 0))
1160 if Pcd
.DefaultValue
:
1161 Pcd
.DefaultValue
= str(int(Pcd
.DefaultValue
, 0))
1163 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, ' ')
1164 elif InfDefaultValue
and InfMatch
:
1165 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*M')
1166 elif BuildOptionMatch
:
1167 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*B')
1169 if PcdComponentValue
:
1170 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, PcdComponentValue
, DecMatch
, DecDefaultValue
, '*M', ModuleGuid
)
1171 elif DscDefaultValue
and DscMatch
:
1172 if (Pcd
.TokenCName
, Key
, Field
) in self
.FdfPcdSet
:
1173 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*F')
1175 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*P')
1178 if ModulePcdSet
is None:
1181 if not TypeName
in ('PATCH', 'FLAG', 'FIXED'):
1183 if not BuildOptionMatch
:
1184 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
1185 for ModulePath
in ModuleOverride
:
1186 ModuleDefault
= ModuleOverride
[ModulePath
]
1187 if Pcd
.DatumType
in TAB_PCD_NUMERIC_TYPES
:
1188 if ModuleDefault
.startswith('0') and not ModuleDefault
.lower().startswith('0x') and \
1189 len(ModuleDefault
) > 1 and ModuleDefault
.lstrip('0'):
1190 ModuleDefault
= ModuleDefault
.lstrip('0')
1191 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
1192 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
1193 if Pcd
.DatumType
== 'BOOLEAN':
1194 ModuleDefault
= str(ModulePcdDefaultValueNumber
)
1196 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
1199 IsByteArray
, ArrayList
= ByteArrayForamt(ModuleDefault
.strip())
1201 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 15, ModulePath
, '{'))
1202 for Array
in ArrayList
:
1203 FileWrite(File
, Array
)
1205 Value
= ModuleDefault
.strip()
1206 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1207 if Value
.startswith(('0x', '0X')):
1208 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1210 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1211 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 15, ModulePath
, Value
))
1213 if ModulePcdSet
is None:
1214 FileWrite(File
, gSectionEnd
)
1216 if not ReportSubType
and ModulePcdSet
:
1217 FileWrite(File
, gSubSectionEnd
)
1219 def ParseStruct(self
, struct
):
1220 HasDscOverride
= False
1222 for _
, Values
in list(struct
.items()):
1223 for Key
, value
in Values
.items():
1224 if value
[1] and value
[1].endswith('.dsc'):
1225 HasDscOverride
= True
1227 if HasDscOverride
== True:
1229 return HasDscOverride
1231 def PrintPcdDefault(self
, File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
):
1232 if not DscMatch
and DscDefaultValue
is not None:
1233 Value
= DscDefaultValue
.strip()
1234 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1236 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', "{"))
1237 for Array
in ArrayList
:
1238 FileWrite(File
, Array
)
1240 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1241 if Value
.startswith(('0x', '0X')):
1242 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1244 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1245 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', Value
))
1246 if not InfMatch
and InfDefaultValue
is not None:
1247 Value
= InfDefaultValue
.strip()
1248 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1250 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', "{"))
1251 for Array
in ArrayList
:
1252 FileWrite(File
, Array
)
1254 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1255 if Value
.startswith(('0x', '0X')):
1256 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1258 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1259 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', Value
))
1261 if not DecMatch
and DecDefaultValue
is not None:
1262 Value
= DecDefaultValue
.strip()
1263 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1265 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', "{"))
1266 for Array
in ArrayList
:
1267 FileWrite(File
, Array
)
1269 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1270 if Value
.startswith(('0x', '0X')):
1271 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1273 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1274 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', Value
))
1276 for filedvalues
in Pcd
.DefaultValues
.values():
1277 self
.PrintStructureInfo(File
, filedvalues
)
1278 if DecMatch
and IsStructure
:
1279 for filedvalues
in Pcd
.DefaultValues
.values():
1280 self
.PrintStructureInfo(File
, filedvalues
)
1282 def PrintPcdValue(self
, File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, Flag
= ' ',ModuleGuid
=None):
1283 if not Pcd
.SkuInfoList
:
1284 Value
= Pcd
.DefaultValue
1285 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1287 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1288 for Array
in ArrayList
:
1289 FileWrite(File
, Array
)
1291 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1292 if Value
.startswith('0') and not Value
.lower().startswith('0x') and len(Value
) > 1 and Value
.lstrip('0'):
1293 Value
= Value
.lstrip('0')
1294 if Value
.startswith(('0x', '0X')):
1295 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1297 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1298 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1300 FiledOverrideFlag
= False
1301 if (Pcd
.TokenCName
,Pcd
.TokenSpaceGuidCName
) in GlobalData
.gPcdSkuOverrides
:
1302 OverrideValues
= GlobalData
.gPcdSkuOverrides
[(Pcd
.TokenCName
,Pcd
.TokenSpaceGuidCName
)]
1304 OverrideValues
= Pcd
.SkuOverrideValues
1305 FieldOverrideValues
= None
1307 for Data
in OverrideValues
.values():
1308 Struct
= list(Data
.values())
1310 FieldOverrideValues
= Struct
[0]
1311 FiledOverrideFlag
= True
1313 if Pcd
.PcdFiledValueFromDscComponent
and ModuleGuid
and ModuleGuid
.replace("-","S") in Pcd
.PcdFiledValueFromDscComponent
:
1314 FieldOverrideValues
= Pcd
.PcdFiledValueFromDscComponent
[ModuleGuid
.replace("-","S")]
1315 if FieldOverrideValues
:
1316 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, FieldOverrideValues
)
1317 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1319 if not FiledOverrideFlag
and (Pcd
.PcdFieldValueFromComm
or Pcd
.PcdFieldValueFromFdf
):
1320 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, {})
1321 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1322 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1325 SkuList
= sorted(Pcd
.SkuInfoList
.keys())
1327 SkuInfo
= Pcd
.SkuInfoList
[Sku
]
1328 SkuIdName
= SkuInfo
.SkuIdName
1329 if TypeName
in ('DYNHII', 'DEXHII'):
1330 if SkuInfo
.DefaultStoreDict
:
1331 DefaultStoreList
= sorted(SkuInfo
.DefaultStoreDict
.keys())
1332 for DefaultStore
in DefaultStoreList
:
1333 Value
= SkuInfo
.DefaultStoreDict
[DefaultStore
]
1334 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1335 if Pcd
.DatumType
== 'BOOLEAN':
1336 Value
= str(int(Value
, 0))
1340 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1341 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1342 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1343 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '{'))
1344 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1345 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', '{'))
1347 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', '{'))
1348 for Array
in ArrayList
:
1349 FileWrite(File
, Array
)
1351 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1352 if Value
.startswith(('0x', '0X')):
1353 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1355 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1356 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1357 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1358 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1359 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1360 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1361 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', Value
))
1363 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', Value
))
1366 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1367 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1368 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1369 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '{'))
1370 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1371 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', '{'))
1373 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', '{'))
1374 for Array
in ArrayList
:
1375 FileWrite(File
, Array
)
1377 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1378 if Value
.startswith(('0x', '0X')):
1379 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1381 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1382 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1383 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1384 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1385 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1386 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1387 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', Value
))
1389 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', Value
))
1390 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
1392 OverrideValues
= Pcd
.SkuOverrideValues
.get(Sku
)
1394 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[DefaultStore
])
1395 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1396 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1398 Value
= SkuInfo
.DefaultValue
1399 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1400 if Pcd
.DatumType
== 'BOOLEAN':
1401 Value
= str(int(Value
, 0))
1406 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', "{"))
1408 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', "{"))
1409 for Array
in ArrayList
:
1410 FileWrite(File
, Array
)
1412 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1413 if Value
.startswith(('0x', '0X')):
1414 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1416 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1418 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1420 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1424 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', "{"))
1426 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', "{"))
1427 for Array
in ArrayList
:
1428 FileWrite(File
, Array
)
1430 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1431 if Value
.startswith(('0x', '0X')):
1432 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1434 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1436 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1438 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1439 if TypeName
in ('DYNVPD', 'DEXVPD'):
1440 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
1441 VPDPcdItem
= (Pcd
.TokenSpaceGuidCName
+ '.' + PcdTokenCName
, SkuIdName
, SkuInfo
.VpdOffset
, Pcd
.MaxDatumSize
, SkuInfo
.DefaultValue
)
1442 if VPDPcdItem
not in VPDPcdList
:
1443 PcdGuidList
= self
.UnusedPcds
.get(Pcd
.TokenSpaceGuidCName
)
1445 PcdList
= PcdGuidList
.get(Pcd
.Type
)
1447 VPDPcdList
.append(VPDPcdItem
)
1448 for VpdPcd
in PcdList
:
1449 if PcdTokenCName
== VpdPcd
.TokenCName
:
1452 VPDPcdList
.append(VPDPcdItem
)
1454 FiledOverrideFlag
= False
1455 OverrideValues
= Pcd
.SkuOverrideValues
.get(Sku
)
1457 Keys
= list(OverrideValues
.keys())
1458 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[Keys
[0]])
1459 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1460 FiledOverrideFlag
= True
1461 if not FiledOverrideFlag
and (Pcd
.PcdFieldValueFromComm
or Pcd
.PcdFieldValueFromFdf
):
1462 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, {})
1463 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1464 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1466 def OverrideFieldValue(self
, Pcd
, OverrideStruct
):
1467 OverrideFieldStruct
= collections
.OrderedDict()
1469 for _
, Values
in OverrideStruct
.items():
1470 for Key
,value
in Values
.items():
1471 if value
[1] and value
[1].endswith('.dsc'):
1472 OverrideFieldStruct
[Key
] = value
1473 if Pcd
.PcdFieldValueFromFdf
:
1474 for Key
, Values
in Pcd
.PcdFieldValueFromFdf
.items():
1475 if Key
in OverrideFieldStruct
and Values
[0] == OverrideFieldStruct
[Key
][0]:
1477 OverrideFieldStruct
[Key
] = Values
1478 if Pcd
.PcdFieldValueFromComm
:
1479 for Key
, Values
in Pcd
.PcdFieldValueFromComm
.items():
1480 if Key
in OverrideFieldStruct
and Values
[0] == OverrideFieldStruct
[Key
][0]:
1482 OverrideFieldStruct
[Key
] = Values
1483 return OverrideFieldStruct
1485 def PrintStructureInfo(self
, File
, Struct
):
1486 for Key
, Value
in sorted(Struct
.items(), key
=lambda x
: x
[0]):
1487 if Value
[1] and 'build command options' in Value
[1]:
1488 FileWrite(File
, ' *B %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1489 elif Value
[1] and Value
[1].endswith('.fdf'):
1490 FileWrite(File
, ' *F %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1492 FileWrite(File
, ' %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1494 def StrtoHex(self
, value
):
1496 value
= hex(int(value
))
1499 if value
.startswith("L\"") and value
.endswith("\""):
1501 for ch
in value
[2:-1]:
1502 valuelist
.append(hex(ord(ch
)))
1503 valuelist
.append('0x00')
1505 elif value
.startswith("\"") and value
.endswith("\""):
1506 return hex(ord(value
[1:-1]))
1507 elif value
.startswith("{") and value
.endswith("}"):
1509 if ',' not in value
:
1511 for ch
in value
[1:-1].split(','):
1513 if ch
.startswith('0x') or ch
.startswith('0X'):
1514 valuelist
.append(ch
)
1517 valuelist
.append(hex(int(ch
.strip())))
1524 def IsStructurePcd(self
, PcdToken
, PcdTokenSpaceGuid
):
1525 if GlobalData
.gStructurePcd
and (self
.Arch
in GlobalData
.gStructurePcd
) and ((PcdToken
, PcdTokenSpaceGuid
) in GlobalData
.gStructurePcd
[self
.Arch
]):
1531 # Reports platform and module Prediction information
1533 # This class reports the platform execution order prediction section and
1534 # module load fixed address prediction subsection in the build report file.
1536 class PredictionReport(object):
1538 # Constructor function for class PredictionReport
1540 # This constructor function generates PredictionReport object for the platform.
1542 # @param self: The object pointer
1543 # @param Wa Workspace context information
1545 def __init__(self
, Wa
):
1546 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
1547 self
._MapFileParsed
= False
1548 self
._EotToolInvoked
= False
1549 self
._FvDir
= Wa
.FvDir
1550 self
._EotDir
= Wa
.BuildDir
1551 self
._FfsEntryPoint
= {}
1553 self
._SourceList
= []
1554 self
.FixedMapDict
= {}
1559 # Collect all platform reference source files and GUID C Name
1561 for Pa
in Wa
.AutoGenObjectList
:
1562 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
1564 # BASE typed modules are EFI agnostic, so we need not scan
1565 # their source code to find PPI/Protocol produce or consume
1568 if Module
.ModuleType
== SUP_MODULE_BASE
:
1571 # Add module referenced source files
1573 self
._SourceList
.append(str(Module
))
1575 for Source
in Module
.SourceFileList
:
1576 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
1577 self
._SourceList
.append(" " + str(Source
))
1578 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
1579 for IncludeFile
in IncludeList
.values():
1580 self
._SourceList
.append(" " + IncludeFile
)
1582 for Guid
in Module
.PpiList
:
1583 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
1584 for Guid
in Module
.ProtocolList
:
1585 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
1586 for Guid
in Module
.GuidList
:
1587 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
1589 if Module
.Guid
and not Module
.IsLibrary
:
1590 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
1592 RealEntryPoint
= "_ModuleEntryPoint"
1594 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
1598 # Collect platform firmware volume list as the input of EOT.
1602 for Fd
in Wa
.FdfProfile
.FdDict
:
1603 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
1604 if FdRegion
.RegionType
!= BINARY_FILE_TYPE_FV
:
1606 for FvName
in FdRegion
.RegionDataList
:
1607 if FvName
in self
._FvList
:
1609 self
._FvList
.append(FvName
)
1610 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1611 for Section
in Ffs
.SectionList
:
1613 for FvSection
in Section
.SectionList
:
1614 if FvSection
.FvName
in self
._FvList
:
1616 self
._FvList
.append(FvSection
.FvName
)
1617 except AttributeError:
1622 # Parse platform fixed address map files
1624 # This function parses the platform final fixed address map file to get
1625 # the database of predicted fixed address for module image base, entry point
1628 # @param self: The object pointer
1630 def _ParseMapFile(self
):
1631 if self
._MapFileParsed
:
1633 self
._MapFileParsed
= True
1634 if os
.path
.isfile(self
._MapFileName
):
1636 FileContents
= open(self
._MapFileName
).read()
1637 for Match
in gMapFileItemPattern
.finditer(FileContents
):
1638 AddressType
= Match
.group(1)
1639 BaseAddress
= Match
.group(2)
1640 EntryPoint
= Match
.group(3)
1641 Guid
= Match
.group(4).upper()
1642 List
= self
.FixedMapDict
.setdefault(Guid
, [])
1643 List
.append((AddressType
, BaseAddress
, "*I"))
1644 List
.append((AddressType
, EntryPoint
, "*E"))
1646 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
1649 # Invokes EOT tool to get the predicted the execution order.
1651 # This function invokes EOT tool to calculate the predicted dispatch order
1653 # @param self: The object pointer
1655 def _InvokeEotTool(self
):
1656 if self
._EotToolInvoked
:
1659 self
._EotToolInvoked
= True
1661 for FvName
in self
._FvList
:
1662 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
1663 if os
.path
.isfile(FvFile
):
1664 FvFileList
.append(FvFile
)
1666 if len(FvFileList
) == 0:
1669 # Write source file list and GUID file list to an intermediate file
1670 # as the input for EOT tool and dispatch List as the output file
1673 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
1674 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
1675 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
1678 for Item
in self
._SourceList
:
1679 FileWrite(TempFile
, Item
)
1680 SaveFileOnChange(SourceList
, "".join(TempFile
), False)
1682 for Key
in self
._GuidMap
:
1683 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
1684 SaveFileOnChange(GuidList
, "".join(TempFile
), False)
1687 from Eot
.EotMain
import Eot
1690 # Invoke EOT tool and echo its runtime performance
1692 EotStartTime
= time
.time()
1693 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
1694 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
1695 EotEndTime
= time
.time()
1696 EotDuration
= time
.strftime("%H:%M:%S", time
.gmtime(int(round(EotEndTime
- EotStartTime
))))
1697 EdkLogger
.quiet("EOT run time: %s\n" % EotDuration
)
1700 # Parse the output of EOT tool
1702 for Line
in open(DispatchList
):
1703 if len(Line
.split()) < 4:
1705 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
1706 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
1707 if len(Symbol
) > self
.MaxLen
:
1708 self
.MaxLen
= len(Symbol
)
1709 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
1711 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1712 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1716 # Generate platform execution order report
1718 # This function generates the predicted module execution order.
1720 # @param self The object pointer
1721 # @param File The file object for report
1723 def _GenerateExecutionOrderReport(self
, File
):
1724 self
._InvokeEotTool
()
1725 if len(self
.ItemList
) == 0:
1727 FileWrite(File
, gSectionStart
)
1728 FileWrite(File
, "Execution Order Prediction")
1729 FileWrite(File
, "*P PEI phase")
1730 FileWrite(File
, "*D DXE phase")
1731 FileWrite(File
, "*E Module INF entry point name")
1732 FileWrite(File
, "*N Module notification function name")
1734 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
1735 FileWrite(File
, gSectionSep
)
1736 for Item
in self
.ItemList
:
1737 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
1739 FileWrite(File
, gSectionStart
)
1742 # Generate Fixed Address report.
1744 # This function generate the predicted fixed address report for a module
1745 # specified by Guid.
1747 # @param self The object pointer
1748 # @param File The file object for report
1749 # @param Guid The module Guid value.
1750 # @param NotifyList The list of all notify function in a module
1752 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
1753 self
._ParseMapFile
()
1754 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
1755 if not FixedAddressList
:
1758 FileWrite(File
, gSubSectionStart
)
1759 FileWrite(File
, "Fixed Address Prediction")
1760 FileWrite(File
, "*I Image Loading Address")
1761 FileWrite(File
, "*E Entry Point Address")
1762 FileWrite(File
, "*N Notification Function Address")
1763 FileWrite(File
, "*F Flash Address")
1764 FileWrite(File
, "*M Memory Address")
1765 FileWrite(File
, "*S SMM RAM Offset")
1766 FileWrite(File
, "TOM Top of Memory")
1768 FileWrite(File
, "Type Address Name")
1769 FileWrite(File
, gSubSectionSep
)
1770 for Item
in FixedAddressList
:
1775 Name
= "(Image Base)"
1776 elif Symbol
== "*E":
1777 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
1778 elif Symbol
in NotifyList
:
1786 elif "Memory" in Type
:
1792 Value
= "TOM" + Value
1794 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
1797 # Generate report for the prediction part
1799 # This function generate the predicted fixed address report for a module or
1800 # predicted module execution order for a platform.
1801 # If the input Guid is None, then, it generates the predicted module execution order;
1802 # otherwise it generated the module fixed loading address for the module specified by
1805 # @param self The object pointer
1806 # @param File The file object for report
1807 # @param Guid The module Guid value.
1809 def GenerateReport(self
, File
, Guid
):
1811 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1813 self
._GenerateExecutionOrderReport
(File
)
1816 # Reports FD region information
1818 # This class reports the FD subsection in the build report file.
1819 # It collects region information of platform flash device.
1820 # If the region is a firmware volume, it lists the set of modules
1821 # and its space information; otherwise, it only lists its region name,
1822 # base address and size in its sub-section header.
1823 # If there are nesting FVs, the nested FVs will list immediate after
1824 # this FD region subsection
1826 class FdRegionReport(object):
1828 # Discover all the nested FV name list.
1830 # This is an internal worker function to discover the all the nested FV information
1831 # in the parent firmware volume. It uses deep first search algorithm recursively to
1832 # find all the FV list name and append them to the list.
1834 # @param self The object pointer
1835 # @param FvName The name of current firmware file system
1836 # @param Wa Workspace context information
1838 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1839 FvDictKey
=FvName
.upper()
1840 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1841 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1842 for Section
in Ffs
.SectionList
:
1844 for FvSection
in Section
.SectionList
:
1845 if FvSection
.FvName
in self
.FvList
:
1847 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1848 self
.FvList
.append(FvSection
.FvName
)
1849 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1850 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1851 except AttributeError:
1855 # Constructor function for class FdRegionReport
1857 # This constructor function generates FdRegionReport object for a specified FdRegion.
1858 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1859 # volume list. This function also collects GUID map in order to dump module identification
1860 # in the final report.
1862 # @param self: The object pointer
1863 # @param FdRegion The current FdRegion object
1864 # @param Wa Workspace context information
1866 def __init__(self
, FdRegion
, Wa
):
1867 self
.Type
= FdRegion
.RegionType
1868 self
.BaseAddress
= FdRegion
.Offset
1869 self
.Size
= FdRegion
.Size
1873 self
._FvDir
= Wa
.FvDir
1874 self
._WorkspaceDir
= Wa
.WorkspaceDir
1877 # If the input FdRegion is not a firmware volume,
1880 if self
.Type
!= BINARY_FILE_TYPE_FV
:
1884 # Find all nested FVs in the FdRegion
1886 for FvName
in FdRegion
.RegionDataList
:
1887 if FvName
in self
.FvList
:
1889 self
.FvList
.append(FvName
)
1890 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1891 self
._DiscoverNestedFvList
(FvName
, Wa
)
1895 # Collect PCDs declared in DEC files.
1897 for Pa
in Wa
.AutoGenObjectList
:
1898 for Package
in Pa
.PackageList
:
1899 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1900 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1901 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1903 # Collect PCDs defined in DSC file
1905 for Pa
in Wa
.AutoGenObjectList
:
1906 for (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
1907 DscDefaultValue
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1908 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1911 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1913 self
._GuidsDb
[PEI_APRIORI_GUID
] = "PEI Apriori"
1914 self
._GuidsDb
[DXE_APRIORI_GUID
] = "DXE Apriori"
1916 # Add ACPI table storage file
1918 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1920 for Pa
in Wa
.AutoGenObjectList
:
1921 for ModuleKey
in Pa
.Platform
.Modules
:
1922 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1923 InfPath
= mws
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1924 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1927 # Collect the GUID map in the FV firmware volume
1929 for FvName
in self
.FvList
:
1930 FvDictKey
=FvName
.upper()
1931 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1932 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1935 # collect GUID map for binary EFI file in FDF file.
1937 Guid
= Ffs
.NameGuid
.upper()
1938 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1940 PcdTokenspace
= Match
.group(1)
1941 PcdToken
= Match
.group(2)
1942 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1943 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1944 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1945 for Section
in Ffs
.SectionList
:
1947 ModuleSectFile
= mws
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1948 self
._GuidsDb
[Guid
] = ModuleSectFile
1949 except AttributeError:
1951 except AttributeError:
1956 # Internal worker function to generate report for the FD region
1958 # This internal worker function to generate report for the FD region.
1959 # It the type is firmware volume, it lists offset and module identification.
1961 # @param self The object pointer
1962 # @param File The file object for report
1963 # @param Title The title for the FD subsection
1964 # @param BaseAddress The base address for the FD region
1965 # @param Size The size of the FD region
1966 # @param FvName The FV name if the FD region is a firmware volume
1968 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1969 FileWrite(File
, gSubSectionStart
)
1970 FileWrite(File
, Title
)
1971 FileWrite(File
, "Type: %s" % Type
)
1972 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1974 if self
.Type
== BINARY_FILE_TYPE_FV
:
1978 if FvName
.upper().endswith('.FV'):
1979 FileExt
= FvName
+ ".txt"
1981 FileExt
= FvName
+ ".Fv.txt"
1983 if not os
.path
.isfile(FileExt
):
1984 FvReportFileName
= mws
.join(self
._WorkspaceDir
, FileExt
)
1985 if not os
.path
.isfile(FvReportFileName
):
1986 FvReportFileName
= os
.path
.join(self
._FvDir
, FileExt
)
1989 # Collect size info in the firmware volume.
1991 FvReport
= open(FvReportFileName
).read()
1992 Match
= gFvTotalSizePattern
.search(FvReport
)
1994 FvTotalSize
= int(Match
.group(1), 16)
1995 Match
= gFvTakenSizePattern
.search(FvReport
)
1997 FvTakenSize
= int(Match
.group(1), 16)
1998 FvFreeSize
= FvTotalSize
- FvTakenSize
2000 # Write size information to the report file.
2002 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
2003 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
2004 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
2005 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
2006 FileWrite(File
, "Offset Module")
2007 FileWrite(File
, gSubSectionSep
)
2009 # Write module offset and module identification to the report file.
2012 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
2013 Guid
= Match
.group(2).upper()
2014 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
2015 OffsetList
= sorted(OffsetInfo
.keys())
2016 for Offset
in OffsetList
:
2017 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
2019 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
2021 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
2022 FileWrite(File
, gSubSectionEnd
)
2025 # Generate report for the FD region
2027 # This function generates report for the FD region.
2029 # @param self The object pointer
2030 # @param File The file object for report
2032 def GenerateReport(self
, File
):
2033 if (len(self
.FvList
) > 0):
2034 for FvItem
in self
.FvList
:
2035 Info
= self
.FvInfo
[FvItem
]
2036 self
._GenerateReport
(File
, Info
[0], TAB_FV_DIRECTORY
, Info
[1], Info
[2], FvItem
)
2038 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
2041 # Reports FD information
2043 # This class reports the FD section in the build report file.
2044 # It collects flash device information for a platform.
2046 class FdReport(object):
2048 # Constructor function for class FdReport
2050 # This constructor function generates FdReport object for a specified
2053 # @param self The object pointer
2054 # @param Fd The current Firmware device object
2055 # @param Wa Workspace context information
2057 def __init__(self
, Fd
, Wa
):
2058 self
.FdName
= Fd
.FdUiName
2059 self
.BaseAddress
= Fd
.BaseAddress
2061 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
2062 self
.FvPath
= os
.path
.join(Wa
.BuildDir
, TAB_FV_DIRECTORY
)
2063 self
.VPDBaseAddress
= 0
2065 for index
, FdRegion
in enumerate(Fd
.RegionList
):
2066 if str(FdRegion
.RegionType
) == 'FILE' and Wa
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
2067 self
.VPDBaseAddress
= self
.FdRegionList
[index
].BaseAddress
2068 self
.VPDSize
= self
.FdRegionList
[index
].Size
2072 # Generate report for the firmware device.
2074 # This function generates report for the firmware device.
2076 # @param self The object pointer
2077 # @param File The file object for report
2079 def GenerateReport(self
, File
):
2080 FileWrite(File
, gSectionStart
)
2081 FileWrite(File
, "Firmware Device (FD)")
2082 FileWrite(File
, "FD Name: %s" % self
.FdName
)
2083 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
2084 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
2085 if len(self
.FdRegionList
) > 0:
2086 FileWrite(File
, gSectionSep
)
2087 for FdRegionItem
in self
.FdRegionList
:
2088 FdRegionItem
.GenerateReport(File
)
2091 VPDPcdList
.sort(key
=lambda x
: int(x
[2], 0))
2092 FileWrite(File
, gSubSectionStart
)
2093 FileWrite(File
, "FD VPD Region")
2094 FileWrite(File
, "Base Address: 0x%X" % self
.VPDBaseAddress
)
2095 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.VPDSize
, self
.VPDSize
/ 1024.0))
2096 FileWrite(File
, gSubSectionSep
)
2097 for item
in VPDPcdList
:
2098 # Add BaseAddress for offset
2099 Offset
= '0x%08X' % (int(item
[2], 16) + self
.VPDBaseAddress
)
2100 IsByteArray
, ArrayList
= ByteArrayForamt(item
[-1])
2102 if len(GlobalData
.gSkuids
) == 1 :
2103 Skuinfo
= GlobalData
.gSkuids
[0]
2105 FileWrite(File
, "%s | %s | %s | %s | %s" % (item
[0], Skuinfo
, Offset
, item
[3], '{'))
2106 for Array
in ArrayList
:
2107 FileWrite(File
, Array
)
2109 FileWrite(File
, "%s | %s | %s | %s | %s" % (item
[0], Skuinfo
, Offset
, item
[3], item
[-1]))
2110 FileWrite(File
, gSubSectionEnd
)
2111 FileWrite(File
, gSectionEnd
)
2116 # Reports platform information
2118 # This class reports the whole platform information
2120 class PlatformReport(object):
2122 # Constructor function for class PlatformReport
2124 # This constructor function generates PlatformReport object a platform build.
2125 # It generates report for platform summary, flash, global PCDs and detailed
2126 # module information for modules involved in platform build.
2128 # @param self The object pointer
2129 # @param Wa Workspace context information
2130 # @param MaList The list of modules in the platform build
2132 def __init__(self
, Wa
, MaList
, ReportType
):
2133 self
._WorkspaceDir
= Wa
.WorkspaceDir
2134 self
.PlatformName
= Wa
.Name
2135 self
.PlatformDscPath
= Wa
.Platform
2136 self
.Architectures
= " ".join(Wa
.ArchList
)
2137 self
.ToolChain
= Wa
.ToolChain
2138 self
.Target
= Wa
.BuildTarget
2139 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
2140 self
.BuildEnvironment
= platform
.platform()
2142 self
.PcdReport
= None
2143 if "PCD" in ReportType
:
2144 self
.PcdReport
= PcdReport(Wa
)
2146 self
.FdReportList
= []
2147 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
is None:
2148 for Fd
in Wa
.FdfProfile
.FdDict
:
2149 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
2151 self
.PredictionReport
= None
2152 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
2153 self
.PredictionReport
= PredictionReport(Wa
)
2155 self
.DepexParser
= None
2156 if "DEPEX" in ReportType
:
2157 self
.DepexParser
= DepexParser(Wa
)
2159 self
.ModuleReportList
= []
2160 if MaList
is not None:
2161 self
._IsModuleBuild
= True
2163 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
2165 self
._IsModuleBuild
= False
2166 for Pa
in Wa
.AutoGenObjectList
:
2167 ModuleAutoGenList
= []
2168 for ModuleKey
in Pa
.Platform
.Modules
:
2169 ModuleAutoGenList
.append(Pa
.Platform
.Modules
[ModuleKey
].M
)
2170 if GlobalData
.gFdfParser
is not None:
2171 if Pa
.Arch
in GlobalData
.gFdfParser
.Profile
.InfDict
:
2172 INFList
= GlobalData
.gFdfParser
.Profile
.InfDict
[Pa
.Arch
]
2173 for InfName
in INFList
:
2174 InfClass
= PathClass(NormPath(InfName
), Wa
.WorkspaceDir
, Pa
.Arch
)
2175 Ma
= ModuleAutoGen(Wa
, InfClass
, Pa
.BuildTarget
, Pa
.ToolChain
, Pa
.Arch
, Wa
.MetaFile
, Pa
.DataPipe
)
2178 if Ma
not in ModuleAutoGenList
:
2179 ModuleAutoGenList
.append(Ma
)
2180 for MGen
in ModuleAutoGenList
:
2181 self
.ModuleReportList
.append(ModuleReport(MGen
, ReportType
))
2186 # Generate report for the whole platform.
2188 # This function generates report for platform information.
2189 # It comprises of platform summary, global PCD, flash and
2190 # module list sections.
2192 # @param self The object pointer
2193 # @param File The file object for report
2194 # @param BuildDuration The total time to build the modules
2195 # @param AutoGenTime The total time of AutoGen Phase
2196 # @param MakeTime The total time of Make Phase
2197 # @param GenFdsTime The total time of GenFds Phase
2198 # @param ReportType The kind of report items in the final report file
2200 def GenerateReport(self
, File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, ReportType
):
2201 FileWrite(File
, "Platform Summary")
2202 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
2203 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
2204 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
2205 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
2206 FileWrite(File
, "Target: %s" % self
.Target
)
2207 if GlobalData
.gSkuids
:
2208 FileWrite(File
, "SKUID: %s" % " ".join(GlobalData
.gSkuids
))
2209 if GlobalData
.gDefaultStores
:
2210 FileWrite(File
, "DefaultStore: %s" % " ".join(GlobalData
.gDefaultStores
))
2211 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
2212 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
2213 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
2215 FileWrite(File
, "AutoGen Duration: %s" % AutoGenTime
)
2217 FileWrite(File
, "Make Duration: %s" % MakeTime
)
2219 FileWrite(File
, "GenFds Duration: %s" % GenFdsTime
)
2220 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
2222 if GlobalData
.MixedPcd
:
2223 FileWrite(File
, gSectionStart
)
2224 FileWrite(File
, "The following PCDs use different access methods:")
2225 FileWrite(File
, gSectionSep
)
2226 for PcdItem
in GlobalData
.MixedPcd
:
2227 FileWrite(File
, "%s.%s" % (str(PcdItem
[1]), str(PcdItem
[0])))
2228 FileWrite(File
, gSectionEnd
)
2230 if not self
._IsModuleBuild
:
2231 if "PCD" in ReportType
:
2232 self
.PcdReport
.GenerateReport(File
, None)
2234 if "FLASH" in ReportType
:
2235 for FdReportListItem
in self
.FdReportList
:
2236 FdReportListItem
.GenerateReport(File
)
2238 for ModuleReportItem
in self
.ModuleReportList
:
2239 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, self
.DepexParser
, ReportType
)
2241 if not self
._IsModuleBuild
:
2242 if "EXECUTION_ORDER" in ReportType
:
2243 self
.PredictionReport
.GenerateReport(File
, None)
2245 ## BuildReport class
2247 # This base class contain the routines to collect data and then
2248 # applies certain format to the output report
2250 class BuildReport(object):
2252 # Constructor function for class BuildReport
2254 # This constructor function generates BuildReport object a platform build.
2255 # It generates report for platform summary, flash, global PCDs and detailed
2256 # module information for modules involved in platform build.
2258 # @param self The object pointer
2259 # @param ReportFile The file name to save report file
2260 # @param ReportType The kind of report items in the final report file
2262 def __init__(self
, ReportFile
, ReportType
):
2263 self
.ReportFile
= ReportFile
2265 self
.ReportList
= []
2266 self
.ReportType
= []
2268 for ReportTypeItem
in ReportType
:
2269 if ReportTypeItem
not in self
.ReportType
:
2270 self
.ReportType
.append(ReportTypeItem
)
2272 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]
2274 # Adds platform report to the list
2276 # This function adds a platform report to the final report list.
2278 # @param self The object pointer
2279 # @param Wa Workspace context information
2280 # @param MaList The list of modules in the platform build
2282 def AddPlatformReport(self
, Wa
, MaList
=None):
2284 self
.ReportList
.append((Wa
, MaList
))
2287 # Generates the final report.
2289 # This function generates platform build report. It invokes GenerateReport()
2290 # method for every platform report in the list.
2292 # @param self The object pointer
2293 # @param BuildDuration The total time to build the modules
2294 # @param AutoGenTime The total time of AutoGen phase
2295 # @param MakeTime The total time of Make phase
2296 # @param GenFdsTime The total time of GenFds phase
2298 def GenerateReport(self
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
):
2302 for (Wa
, MaList
) in self
.ReportList
:
2303 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, self
.ReportType
)
2304 Content
= FileLinesSplit(''.join(File
), gLineMaxLength
)
2305 SaveFileOnChange(self
.ReportFile
, Content
, False)
2306 EdkLogger
.quiet("Build report can be found at %s" % os
.path
.abspath(self
.ReportFile
))
2308 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
2310 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
2311 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
2313 # This acts like the main() function for the script, unless it is 'import'ed into another script.
2314 if __name__
== '__main__':