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 # This program and the accompanying materials
9 # are licensed and made available under the terms and conditions of the BSD License
10 # which accompanies this distribution. The full text of the license may be found at
11 # http://opensource.org/licenses/bsd-license.php
13 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 import Common
.LongFilePathOs
as os
30 from datetime
import datetime
31 from io
import BytesIO
32 from Common
import EdkLogger
33 from Common
.Misc
import SaveFileOnChange
34 from Common
.Misc
import GuidStructureByteArrayToGuidString
35 from Common
.Misc
import GuidStructureStringToGuidString
36 from Common
.BuildToolError
import FILE_WRITE_FAILURE
37 from Common
.BuildToolError
import CODE_ERROR
38 from Common
.BuildToolError
import COMMAND_FAILURE
39 from Common
.BuildToolError
import FORMAT_INVALID
40 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
41 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
42 import Common
.GlobalData
as GlobalData
43 from AutoGen
.AutoGen
import ModuleAutoGen
44 from Common
.Misc
import PathClass
45 from Common
.StringUtils
import NormPath
46 from Common
.DataType
import *
48 from Common
.Expression
import *
49 from GenFds
.AprioriSection
import DXE_APRIORI_GUID
, PEI_APRIORI_GUID
51 ## Pattern to extract contents in EDK DXS files
52 gDxsDependencyPattern
= re
.compile(r
"DEPENDENCY_START(.+)DEPENDENCY_END", re
.DOTALL
)
54 ## Pattern to find total FV total size, occupied size in flash report intermediate file
55 gFvTotalSizePattern
= re
.compile(r
"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
56 gFvTakenSizePattern
= re
.compile(r
"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
58 ## Pattern to find module size and time stamp in module summary report intermediate file
59 gModuleSizePattern
= re
.compile(r
"MODULE_SIZE = (\d+)")
60 gTimeStampPattern
= re
.compile(r
"TIME_STAMP = (\d+)")
62 ## Pattern to find GUID value in flash description files
63 gPcdGuidPattern
= re
.compile(r
"PCD\((\w+)[.](\w+)\)")
65 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
66 gOffsetGuidPattern
= re
.compile(r
"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
68 ## Pattern to find module base address and entry point in fixed flash map file
69 gModulePattern
= r
"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
70 gMapFileItemPattern
= re
.compile(gModulePattern
% {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
72 ## Pattern to find all module referenced header files in source files
73 gIncludePattern
= re
.compile(r
'#include\s*["<]([^">]+)[">]')
74 gIncludePattern2
= re
.compile(r
"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
76 ## Pattern to find the entry point for EDK module using EDKII Glue library
77 gGlueLibEntryPoint
= re
.compile(r
"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
79 ## Tags for MaxLength of line in report
82 ## Tags for end of line in report
85 ## Tags for section start, end and separator
86 gSectionStart
= ">" + "=" * (gLineMaxLength
- 2) + "<"
87 gSectionEnd
= "<" + "=" * (gLineMaxLength
- 2) + ">" + "\n"
88 gSectionSep
= "=" * gLineMaxLength
90 ## Tags for subsection start, end and separator
91 gSubSectionStart
= ">" + "-" * (gLineMaxLength
- 2) + "<"
92 gSubSectionEnd
= "<" + "-" * (gLineMaxLength
- 2) + ">"
93 gSubSectionSep
= "-" * gLineMaxLength
96 ## The look up table to map PCD type to pair of report display type and DEC type
98 TAB_PCDS_FIXED_AT_BUILD
: ('FIXED', TAB_PCDS_FIXED_AT_BUILD
),
99 TAB_PCDS_PATCHABLE_IN_MODULE
: ('PATCH', TAB_PCDS_PATCHABLE_IN_MODULE
),
100 TAB_PCDS_FEATURE_FLAG
: ('FLAG', TAB_PCDS_FEATURE_FLAG
),
101 TAB_PCDS_DYNAMIC
: ('DYN', TAB_PCDS_DYNAMIC
),
102 TAB_PCDS_DYNAMIC_HII
: ('DYNHII', TAB_PCDS_DYNAMIC
),
103 TAB_PCDS_DYNAMIC_VPD
: ('DYNVPD', TAB_PCDS_DYNAMIC
),
104 TAB_PCDS_DYNAMIC_EX
: ('DEX', TAB_PCDS_DYNAMIC_EX
),
105 TAB_PCDS_DYNAMIC_EX_HII
: ('DEXHII', TAB_PCDS_DYNAMIC_EX
),
106 TAB_PCDS_DYNAMIC_EX_VPD
: ('DEXVPD', TAB_PCDS_DYNAMIC_EX
),
109 ## The look up table to map module type to driver type
111 SUP_MODULE_SEC
: '0x3 (SECURITY_CORE)',
112 SUP_MODULE_PEI_CORE
: '0x4 (PEI_CORE)',
113 SUP_MODULE_PEIM
: '0x6 (PEIM)',
114 SUP_MODULE_DXE_CORE
: '0x5 (DXE_CORE)',
115 SUP_MODULE_DXE_DRIVER
: '0x7 (DRIVER)',
116 SUP_MODULE_DXE_SAL_DRIVER
: '0x7 (DRIVER)',
117 SUP_MODULE_DXE_SMM_DRIVER
: '0x7 (DRIVER)',
118 SUP_MODULE_DXE_RUNTIME_DRIVER
: '0x7 (DRIVER)',
119 SUP_MODULE_UEFI_DRIVER
: '0x7 (DRIVER)',
120 SUP_MODULE_UEFI_APPLICATION
: '0x9 (APPLICATION)',
121 SUP_MODULE_SMM_CORE
: '0xD (SMM_CORE)',
122 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
123 SUP_MODULE_MM_STANDALONE
: '0xE (MM_STANDALONE)',
124 SUP_MODULE_MM_CORE_STANDALONE
: '0xF (MM_CORE_STANDALONE)'
127 ## The look up table of the supported opcode in the dependency expression binaries
128 gOpCodeList
= ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
134 # Writes a string to the file object.
136 # This function writes a string to the file object and a new line is appended
137 # afterwards. It may optionally wraps the string for better readability.
139 # @File The file object to write
140 # @String The string to be written to the file
141 # @Wrapper Indicates whether to wrap the string
143 def FileWrite(File
, String
, Wrapper
=False):
145 String
= textwrap
.fill(String
, 120)
146 File
.write(String
+ gEndOfLine
)
148 def ByteArrayForamt(Value
):
152 if Value
.startswith('{') and Value
.endswith('}'):
154 ValueList
= Value
.split(',')
155 if len(ValueList
) >= SplitNum
:
159 Len
= len(ValueList
)/SplitNum
160 for i
, element
in enumerate(ValueList
):
161 ValueList
[i
] = '0x%02X' % int(element
.strip(), 16)
165 End
= min(SplitNum
*(Id
+1), len(ValueList
))
166 Str
= ','.join(ValueList
[SplitNum
*Id
: End
])
167 if End
== len(ValueList
):
169 ArrayList
.append(Str
)
173 ArrayList
.append(Str
)
176 ArrayList
= [Value
+ '}']
177 return IsByteArray
, ArrayList
180 # Find all the header file that the module source directly includes.
182 # This function scans source code to find all header files the module may
183 # include. This is not accurate but very effective to find all the header
184 # file the module might include with #include statement.
186 # @Source The source file name
187 # @IncludePathList The list of include path to find the source file.
188 # @IncludeFiles The dictionary of current found include files.
190 def FindIncludeFiles(Source
, IncludePathList
, IncludeFiles
):
191 FileContents
= open(Source
).read()
193 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
195 for Match
in gIncludePattern
.finditer(FileContents
):
196 FileName
= Match
.group(1).strip()
197 for Dir
in [os
.path
.dirname(Source
)] + IncludePathList
:
198 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
199 if os
.path
.exists(FullFileName
):
200 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
204 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
206 for Match
in gIncludePattern2
.finditer(FileContents
):
208 Type
= Match
.group(1)
209 if "ARCH_PROTOCOL" in Type
:
210 FileName
= "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
211 elif "PROTOCOL" in Type
:
212 FileName
= "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
214 FileName
= "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key
}
215 elif TAB_GUID
in Type
:
216 FileName
= "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key
}
219 for Dir
in IncludePathList
:
220 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
221 if os
.path
.exists(FullFileName
):
222 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
225 ## Split each lines in file
227 # This method is used to split the lines in file to make the length of each line
228 # less than MaxLength.
230 # @param Content The content of file
231 # @param MaxLength The Max Length of the line
233 def FileLinesSplit(Content
=None, MaxLength
=None):
234 ContentList
= Content
.split(TAB_LINE_BREAK
)
237 for Line
in ContentList
:
238 while len(Line
.rstrip()) > MaxLength
:
239 LineSpaceIndex
= Line
.rfind(TAB_SPACE_SPLIT
, 0, MaxLength
)
240 LineSlashIndex
= Line
.rfind(TAB_SLASH
, 0, MaxLength
)
241 LineBackSlashIndex
= Line
.rfind(TAB_BACK_SLASH
, 0, MaxLength
)
242 if max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
) > 0:
243 LineBreakIndex
= max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
)
245 LineBreakIndex
= MaxLength
246 NewContentList
.append(Line
[:LineBreakIndex
])
247 Line
= Line
[LineBreakIndex
:]
249 NewContentList
.append(Line
)
250 for NewLine
in NewContentList
:
251 NewContent
+= NewLine
+ TAB_LINE_BREAK
253 NewContent
= NewContent
.replace(TAB_LINE_BREAK
, gEndOfLine
).replace('\r\r\n', gEndOfLine
)
259 # Parse binary dependency expression section
261 # This utility class parses the dependency expression section and translate the readable
262 # GUID name and value.
264 class DepexParser(object):
266 # Constructor function for class DepexParser
268 # This constructor function collect GUID values so that the readable
269 # GUID name can be translated.
271 # @param self The object pointer
272 # @param Wa Workspace context information
274 def __init__(self
, Wa
):
276 for Pa
in Wa
.AutoGenObjectList
:
277 for Package
in Pa
.PackageList
:
278 for Protocol
in Package
.Protocols
:
279 GuidValue
= GuidStructureStringToGuidString(Package
.Protocols
[Protocol
])
280 self
._GuidDb
[GuidValue
.upper()] = Protocol
281 for Ppi
in Package
.Ppis
:
282 GuidValue
= GuidStructureStringToGuidString(Package
.Ppis
[Ppi
])
283 self
._GuidDb
[GuidValue
.upper()] = Ppi
284 for Guid
in Package
.Guids
:
285 GuidValue
= GuidStructureStringToGuidString(Package
.Guids
[Guid
])
286 self
._GuidDb
[GuidValue
.upper()] = Guid
287 for Ma
in Pa
.ModuleAutoGenList
:
288 for Pcd
in Ma
.FixedVoidTypePcds
:
289 PcdValue
= Ma
.FixedVoidTypePcds
[Pcd
]
290 if len(PcdValue
.split(',')) == 16:
291 GuidValue
= GuidStructureByteArrayToGuidString(PcdValue
)
292 self
._GuidDb
[GuidValue
.upper()] = Pcd
294 # Parse the binary dependency expression files.
296 # This function parses the binary dependency expression file and translate it
297 # to the instruction list.
299 # @param self The object pointer
300 # @param DepexFileName The file name of binary dependency expression file.
302 def ParseDepexFile(self
, DepexFileName
):
303 DepexFile
= open(DepexFileName
, "rb")
305 OpCode
= DepexFile
.read(1)
307 Statement
= gOpCodeList
[struct
.unpack("B", OpCode
)[0]]
308 if Statement
in ["BEFORE", "AFTER", "PUSH"]:
309 GuidValue
= "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
310 struct
.unpack(PACK_PATTERN_GUID
, DepexFile
.read(16))
311 GuidString
= self
._GuidDb
.get(GuidValue
, GuidValue
)
312 Statement
= "%s %s" % (Statement
, GuidString
)
313 DepexStatement
.append(Statement
)
314 OpCode
= DepexFile
.read(1)
316 return DepexStatement
319 # Reports library information
321 # This class reports the module library subsection in the build report file.
323 class LibraryReport(object):
325 # Constructor function for class LibraryReport
327 # This constructor function generates LibraryReport object for
330 # @param self The object pointer
331 # @param M Module context information
333 def __init__(self
, M
):
334 self
.LibraryList
= []
335 if int(str(M
.AutoGenVersion
), 0) >= 0x00010005:
336 self
._EdkIIModule
= True
338 self
._EdkIIModule
= False
340 for Lib
in M
.DependentLibraryList
:
341 LibInfPath
= str(Lib
)
342 LibClassList
= Lib
.LibraryClass
[0].LibraryClass
343 LibConstructorList
= Lib
.ConstructorList
344 LibDesstructorList
= Lib
.DestructorList
345 LibDepexList
= Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]
346 for LibAutoGen
in M
.LibraryAutoGenList
:
347 if LibInfPath
== LibAutoGen
.MetaFile
.Path
:
348 LibTime
= LibAutoGen
.BuildTime
350 self
.LibraryList
.append((LibInfPath
, LibClassList
, LibConstructorList
, LibDesstructorList
, LibDepexList
, LibTime
))
353 # Generate report for module library information
355 # This function generates report for the module library.
356 # If the module is EDKII style one, the additional library class, library
357 # constructor/destructor and dependency expression may also be reported.
359 # @param self The object pointer
360 # @param File The file object for report
362 def GenerateReport(self
, File
):
363 if len(self
.LibraryList
) > 0:
364 FileWrite(File
, gSubSectionStart
)
365 FileWrite(File
, TAB_BRG_LIBRARY
)
366 FileWrite(File
, gSubSectionSep
)
367 for LibraryItem
in self
.LibraryList
:
368 LibInfPath
= LibraryItem
[0]
369 FileWrite(File
, LibInfPath
)
372 # Report library class, library constructor and destructor for
373 # EDKII style module.
375 if self
._EdkIIModule
:
376 LibClass
= LibraryItem
[1]
378 LibConstructor
= " ".join(LibraryItem
[2])
380 EdkIILibInfo
+= " C = " + LibConstructor
381 LibDestructor
= " ".join(LibraryItem
[3])
383 EdkIILibInfo
+= " D = " + LibDestructor
384 LibDepex
= " ".join(LibraryItem
[4])
386 EdkIILibInfo
+= " Depex = " + LibDepex
388 EdkIILibInfo
+= " Time = " + LibraryItem
[5]
390 FileWrite(File
, "{%s: %s}" % (LibClass
, EdkIILibInfo
))
392 FileWrite(File
, "{%s}" % LibClass
)
394 FileWrite(File
, gSubSectionEnd
)
397 # Reports dependency expression information
399 # This class reports the module dependency expression subsection in the build report file.
401 class DepexReport(object):
403 # Constructor function for class DepexReport
405 # This constructor function generates DepexReport object for
406 # a module. If the module source contains the DXS file (usually EDK
407 # style module), it uses the dependency in DXS file; otherwise,
408 # it uses the dependency expression from its own INF [Depex] section
409 # and then merges with the ones from its dependent library INF.
411 # @param self The object pointer
412 # @param M Module context information
414 def __init__(self
, M
):
416 self
._DepexFileName
= os
.path
.join(M
.BuildDir
, "OUTPUT", M
.Module
.BaseName
+ ".depex")
417 ModuleType
= M
.ModuleType
419 ModuleType
= COMPONENT_TO_MODULE_MAP_DICT
.get(M
.ComponentType
, "")
421 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
]:
424 for Source
in M
.SourceFileList
:
425 if os
.path
.splitext(Source
.Path
)[1].lower() == ".dxs":
426 Match
= gDxsDependencyPattern
.search(open(Source
.Path
).read())
428 self
.Depex
= Match
.group(1).strip()
432 self
.Depex
= M
.DepexExpressionDict
.get(M
.ModuleType
, "")
433 self
.ModuleDepex
= " ".join(M
.Module
.DepexExpression
[M
.Arch
, M
.ModuleType
])
434 if not self
.ModuleDepex
:
435 self
.ModuleDepex
= "(None)"
438 for Lib
in M
.DependentLibraryList
:
439 LibDepex
= " ".join(Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]).strip()
441 LibDepexList
.append("(" + LibDepex
+ ")")
442 self
.LibraryDepex
= " AND ".join(LibDepexList
)
443 if not self
.LibraryDepex
:
444 self
.LibraryDepex
= "(None)"
448 # Generate report for module dependency expression information
450 # This function generates report for the module dependency expression.
452 # @param self The object pointer
453 # @param File The file object for report
454 # @param GlobalDepexParser The platform global Dependency expression parser object
456 def GenerateReport(self
, File
, GlobalDepexParser
):
459 FileWrite(File
, gSubSectionStart
)
460 if os
.path
.isfile(self
._DepexFileName
):
462 DepexStatements
= GlobalDepexParser
.ParseDepexFile(self
._DepexFileName
)
463 FileWrite(File
, "Final Dependency Expression (DEPEX) Instructions")
464 for DepexStatement
in DepexStatements
:
465 FileWrite(File
, " %s" % DepexStatement
)
466 FileWrite(File
, gSubSectionSep
)
468 EdkLogger
.warn(None, "Dependency expression file is corrupted", self
._DepexFileName
)
470 FileWrite(File
, "Dependency Expression (DEPEX) from %s" % self
.Source
)
472 if self
.Source
== "INF":
473 FileWrite(File
, self
.Depex
, True)
474 FileWrite(File
, gSubSectionSep
)
475 FileWrite(File
, "From Module INF: %s" % self
.ModuleDepex
, True)
476 FileWrite(File
, "From Library INF: %s" % self
.LibraryDepex
, True)
478 FileWrite(File
, self
.Depex
)
479 FileWrite(File
, gSubSectionEnd
)
482 # Reports dependency expression information
484 # This class reports the module build flags subsection in the build report file.
486 class BuildFlagsReport(object):
488 # Constructor function for class BuildFlagsReport
490 # This constructor function generates BuildFlagsReport object for
491 # a module. It reports the build tool chain tag and all relevant
492 # build flags to build the module.
494 # @param self The object pointer
495 # @param M Module context information
497 def __init__(self
, M
):
500 # Add build flags according to source file extension so that
501 # irrelevant ones can be filtered out.
503 for Source
in M
.SourceFileList
:
504 Ext
= os
.path
.splitext(Source
.File
)[1].lower()
505 if Ext
in [".c", ".cc", ".cpp"]:
506 BuildOptions
["CC"] = 1
507 elif Ext
in [".s", ".asm"]:
508 BuildOptions
["PP"] = 1
509 BuildOptions
["ASM"] = 1
510 elif Ext
in [".vfr"]:
511 BuildOptions
["VFRPP"] = 1
512 BuildOptions
["VFR"] = 1
513 elif Ext
in [".dxs"]:
514 BuildOptions
["APP"] = 1
515 BuildOptions
["CC"] = 1
516 elif Ext
in [".asl"]:
517 BuildOptions
["ASLPP"] = 1
518 BuildOptions
["ASL"] = 1
519 elif Ext
in [".aslc"]:
520 BuildOptions
["ASLCC"] = 1
521 BuildOptions
["ASLDLINK"] = 1
522 BuildOptions
["CC"] = 1
523 elif Ext
in [".asm16"]:
524 BuildOptions
["ASMLINK"] = 1
525 BuildOptions
["SLINK"] = 1
526 BuildOptions
["DLINK"] = 1
529 # Save module build flags.
531 self
.ToolChainTag
= M
.ToolChain
533 for Tool
in BuildOptions
:
534 self
.BuildFlags
[Tool
+ "_FLAGS"] = M
.BuildOption
.get(Tool
, {}).get("FLAGS", "")
537 # Generate report for module build flags information
539 # This function generates report for the module build flags expression.
541 # @param self The object pointer
542 # @param File The file object for report
544 def GenerateReport(self
, File
):
545 FileWrite(File
, gSubSectionStart
)
546 FileWrite(File
, "Build Flags")
547 FileWrite(File
, "Tool Chain Tag: %s" % self
.ToolChainTag
)
548 for Tool
in self
.BuildFlags
:
549 FileWrite(File
, gSubSectionSep
)
550 FileWrite(File
, "%s = %s" % (Tool
, self
.BuildFlags
[Tool
]), True)
552 FileWrite(File
, gSubSectionEnd
)
556 # Reports individual module information
558 # This class reports the module section in the build report file.
559 # It comprises of module summary, module PCD, library, dependency expression,
560 # build flags sections.
562 class ModuleReport(object):
564 # Constructor function for class ModuleReport
566 # This constructor function generates ModuleReport object for
567 # a separate module in a platform build.
569 # @param self The object pointer
570 # @param M Module context information
571 # @param ReportType The kind of report items in the final report file
573 def __init__(self
, M
, ReportType
):
574 self
.ModuleName
= M
.Module
.BaseName
575 self
.ModuleInfPath
= M
.MetaFile
.File
576 self
.FileGuid
= M
.Guid
578 self
.BuildTimeStamp
= None
582 ModuleType
= M
.ModuleType
584 ModuleType
= COMPONENT_TO_MODULE_MAP_DICT
.get(M
.ComponentType
, "")
586 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
588 if ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
589 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
590 if int(PiSpec
, 0) >= 0x0001000A:
591 ModuleType
= "SMM_DRIVER"
592 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "0x2 (FREE_FORM)")
593 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
594 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
595 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
596 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
597 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
598 self
.BuildTime
= M
.BuildTime
600 self
._BuildDir
= M
.BuildDir
601 self
.ModulePcdSet
= {}
602 if "PCD" in ReportType
:
604 # Collect all module used PCD set: module INF referenced directly or indirectly.
605 # It also saves module INF default values of them in case they exist.
607 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
608 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
610 self
.LibraryReport
= None
611 if "LIBRARY" in ReportType
:
612 self
.LibraryReport
= LibraryReport(M
)
614 self
.DepexReport
= None
615 if "DEPEX" in ReportType
:
616 self
.DepexReport
= DepexReport(M
)
618 if "BUILD_FLAGS" in ReportType
:
619 self
.BuildFlagsReport
= BuildFlagsReport(M
)
623 # Generate report for module information
625 # This function generates report for separate module expression
626 # in a platform build.
628 # @param self The object pointer
629 # @param File The file object for report
630 # @param GlobalPcdReport The platform global PCD report object
631 # @param GlobalPredictionReport The platform global Prediction report object
632 # @param GlobalDepexParser The platform global Dependency expression parser object
633 # @param ReportType The kind of report items in the final report file
635 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, GlobalDepexParser
, ReportType
):
636 FileWrite(File
, gSectionStart
)
638 FwReportFileName
= os
.path
.join(self
._BuildDir
, "DEBUG", self
.ModuleName
+ ".txt")
639 if os
.path
.isfile(FwReportFileName
):
641 FileContents
= open(FwReportFileName
).read()
642 Match
= gModuleSizePattern
.search(FileContents
)
644 self
.Size
= int(Match
.group(1))
646 Match
= gTimeStampPattern
.search(FileContents
)
648 self
.BuildTimeStamp
= datetime
.fromtimestamp(int(Match
.group(1)))
650 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
652 if "HASH" in ReportType
:
653 OutputDir
= os
.path
.join(self
._BuildDir
, "OUTPUT")
654 DefaultEFIfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ ".efi")
655 if os
.path
.isfile(DefaultEFIfile
):
656 Tempfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ "_hash.tmp")
657 # rebase the efi image since its base address may not zero
658 cmd
= ["GenFw", "--rebase", str(0), "-o", Tempfile
, DefaultEFIfile
]
660 PopenObject
= subprocess
.Popen(' '.join(cmd
), stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
661 except Exception as X
:
662 EdkLogger
.error("GenFw", COMMAND_FAILURE
, ExtraData
="%s: %s" % (str(X
), cmd
[0]))
663 EndOfProcedure
= threading
.Event()
664 EndOfProcedure
.clear()
665 if PopenObject
.stderr
:
666 StdErrThread
= threading
.Thread(target
=ReadMessage
, args
=(PopenObject
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
667 StdErrThread
.setName("STDERR-Redirector")
668 StdErrThread
.setDaemon(False)
670 # waiting for program exit
672 if PopenObject
.stderr
:
674 if PopenObject
.returncode
!= 0:
675 EdkLogger
.error("GenFw", COMMAND_FAILURE
, "Failed to generate firmware hash image for %s" % (DefaultEFIfile
))
676 if os
.path
.isfile(Tempfile
):
677 self
.Hash
= hashlib
.sha1()
678 buf
= open(Tempfile
, 'rb').read()
679 if self
.Hash
.update(buf
):
680 self
.Hash
= self
.Hash
.update(buf
)
681 self
.Hash
= self
.Hash
.hexdigest()
684 FileWrite(File
, "Module Summary")
685 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
686 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
687 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
689 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
691 FileWrite(File
, "SHA1 HASH: %s *%s" % (self
.Hash
, self
.ModuleName
+ ".efi"))
692 if self
.BuildTimeStamp
:
693 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
695 FileWrite(File
, "Module Build Time: %s" % self
.BuildTime
)
697 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
698 if self
.UefiSpecVersion
:
699 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
700 if self
.PiSpecVersion
:
701 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
703 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
705 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
706 if self
.PciClassCode
:
707 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
709 FileWrite(File
, gSectionSep
)
711 if "PCD" in ReportType
:
712 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
)
714 if "LIBRARY" in ReportType
:
715 self
.LibraryReport
.GenerateReport(File
)
717 if "DEPEX" in ReportType
:
718 self
.DepexReport
.GenerateReport(File
, GlobalDepexParser
)
720 if "BUILD_FLAGS" in ReportType
:
721 self
.BuildFlagsReport
.GenerateReport(File
)
723 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
724 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
726 FileWrite(File
, gSectionEnd
)
728 def ReadMessage(From
, To
, ExitFlag
):
730 # read one line a time
731 Line
= From
.readline()
732 # empty string means "end"
733 if Line
is not None and Line
!= "":
741 # Reports platform and module PCD information
743 # This class reports the platform PCD section and module PCD subsection
744 # in the build report file.
746 class PcdReport(object):
748 # Constructor function for class PcdReport
750 # This constructor function generates PcdReport object a platform build.
751 # It collects the whole PCD database from platform DSC files, platform
752 # flash description file and package DEC files.
754 # @param self The object pointer
755 # @param Wa Workspace context information
757 def __init__(self
, Wa
):
760 self
.ConditionalPcds
= {}
764 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
768 self
.DefaultStoreSingle
= True
769 self
.SkuSingle
= True
770 if GlobalData
.gDefaultStores
and len(GlobalData
.gDefaultStores
) > 1:
771 self
.DefaultStoreSingle
= False
772 if GlobalData
.gSkuids
and len(GlobalData
.gSkuids
) > 1:
773 self
.SkuSingle
= False
775 self
.ModulePcdOverride
= {}
776 for Pa
in Wa
.AutoGenObjectList
:
779 # Collect all platform referenced PCDs and grouped them by PCD token space
782 for Pcd
in Pa
.AllPcdList
:
783 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
784 if Pcd
not in PcdList
:
786 if len(Pcd
.TokenCName
) > self
.MaxLen
:
787 self
.MaxLen
= len(Pcd
.TokenCName
)
789 # Collect the PCD defined in DSC/FDF file, but not used in module
791 UnusedPcdFullList
= []
792 for item
in Pa
.Platform
.Pcds
:
793 Pcd
= Pa
.Platform
.Pcds
[item
]
795 # check the Pcd in FDF file, whether it is used in module first
796 for T
in PCD_TYPE_LIST
:
797 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(T
, [])
803 for package
in Pa
.PackageList
:
804 for T
in PCD_TYPE_LIST
:
805 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
) in package
.Pcds
:
808 if not Pcd
.DatumType
:
809 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
)].DatumType
813 if not Pcd
.DatumType
:
815 # Try to remove Hii and Vpd suffix
816 if PcdType
.startswith(TAB_PCDS_DYNAMIC_EX
):
817 PcdType
= TAB_PCDS_DYNAMIC_EX
818 elif PcdType
.startswith(TAB_PCDS_DYNAMIC
):
819 PcdType
= TAB_PCDS_DYNAMIC
820 for package
in Pa
.PackageList
:
821 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
) in package
.Pcds
:
822 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
)].DatumType
825 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
826 UnusedPcdList
= self
.UnusedPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
827 if Pcd
in UnusedPcdList
:
828 UnusedPcdList
.remove(Pcd
)
829 if Pcd
not in PcdList
and Pcd
not in UnusedPcdFullList
:
830 UnusedPcdFullList
.append(Pcd
)
831 if len(Pcd
.TokenCName
) > self
.MaxLen
:
832 self
.MaxLen
= len(Pcd
.TokenCName
)
834 if GlobalData
.gConditionalPcds
:
835 for PcdItem
in GlobalData
.gConditionalPcds
:
837 (TokenSpaceGuidCName
, TokenCName
) = PcdItem
.split('.')
838 if (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
839 Pcd
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)]
840 PcdList
= self
.ConditionalPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
841 if Pcd
not in PcdList
:
845 if UnusedPcdFullList
:
846 for Pcd
in UnusedPcdFullList
:
847 if Pcd
.TokenSpaceGuidCName
+ '.' + Pcd
.TokenCName
in GlobalData
.gConditionalPcds
:
849 UnusedPcdList
.append(Pcd
)
851 for Pcd
in UnusedPcdList
:
852 PcdList
= self
.UnusedPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
853 if Pcd
not in PcdList
:
856 for Module
in Pa
.Platform
.Modules
.values():
858 # Collect module override PCDs
860 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
861 TokenCName
= ModulePcd
.TokenCName
862 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
863 ModuleDefault
= ModulePcd
.DefaultValue
864 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
865 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
869 # Collect PCD DEC default value.
871 self
.DecPcdDefault
= {}
873 for Pa
in Wa
.AutoGenObjectList
:
874 for Package
in Pa
.PackageList
:
875 Guids
= Package
.Guids
876 self
._GuidDict
.update(Guids
)
877 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
878 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
879 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
881 # Collect PCDs defined in DSC common section
883 self
.DscPcdDefault
= {}
884 for Pa
in Wa
.AutoGenObjectList
:
885 for (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
886 DscDefaultValue
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DscDefaultValue
888 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
890 def GenerateReport(self
, File
, ModulePcdSet
):
892 if self
.ConditionalPcds
:
893 self
.GenerateReportDetail(File
, ModulePcdSet
, 1)
896 for Token
in self
.UnusedPcds
:
897 TokenDict
= self
.UnusedPcds
[Token
]
898 for Type
in TokenDict
:
905 self
.GenerateReportDetail(File
, ModulePcdSet
, 2)
906 self
.GenerateReportDetail(File
, ModulePcdSet
)
909 # Generate report for PCD information
911 # This function generates report for separate module expression
912 # in a platform build.
914 # @param self The object pointer
915 # @param File The file object for report
916 # @param ModulePcdSet Set of all PCDs referenced by module or None for
917 # platform PCD report
918 # @param ReportySubType 0 means platform/module PCD report, 1 means Conditional
919 # directives section report, 2 means Unused Pcds section report
920 # @param DscOverridePcds Module DSC override PCDs set
922 def GenerateReportDetail(self
, File
, ModulePcdSet
, ReportSubType
= 0):
923 PcdDict
= self
.AllPcds
924 if ReportSubType
== 1:
925 PcdDict
= self
.ConditionalPcds
926 elif ReportSubType
== 2:
927 PcdDict
= self
.UnusedPcds
930 FileWrite(File
, gSectionStart
)
931 if ReportSubType
== 1:
932 FileWrite(File
, "Conditional Directives used by the build system")
933 elif ReportSubType
== 2:
934 FileWrite(File
, "PCDs not used by modules or in conditional directives")
936 FileWrite(File
, "Platform Configuration Database Report")
938 FileWrite(File
, " *B - PCD override in the build option")
939 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
940 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
941 if not ReportSubType
:
942 FileWrite(File
, " *M - Module scoped PCD override")
943 FileWrite(File
, gSectionSep
)
945 if not ReportSubType
and ModulePcdSet
:
947 # For module PCD sub-section
949 FileWrite(File
, gSubSectionStart
)
950 FileWrite(File
, TAB_BRG_PCD
)
951 FileWrite(File
, gSubSectionSep
)
955 for Type
in PcdDict
[Key
]:
956 for Pcd
in PcdDict
[Key
][Type
]:
957 AllPcdDict
[Key
][(Pcd
.TokenCName
, Type
)] = Pcd
958 for Key
in sorted(AllPcdDict
):
960 # Group PCD by their token space GUID C Name
963 for PcdTokenCName
, Type
in sorted(AllPcdDict
[Key
]):
965 # Group PCD by their usage type
967 Pcd
= AllPcdDict
[Key
][(PcdTokenCName
, Type
)]
968 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
970 if GlobalData
.MixedPcd
:
971 for PcdKey
in GlobalData
.MixedPcd
:
972 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdKey
]:
973 PcdTokenCName
= PcdKey
[0]
975 if MixedPcdFlag
and not ModulePcdSet
:
978 # Get PCD default value and their override relationship
980 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
981 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
982 DscDefaultValBak
= DscDefaultValue
984 for (CName
, Guid
, Field
) in self
.FdfPcdSet
:
985 if CName
== PcdTokenCName
and Guid
== Key
:
986 DscDefaultValue
= self
.FdfPcdSet
[(CName
, Guid
, Field
)]
988 if DscDefaultValue
!= DscDefaultValBak
:
990 DscDefaultValue
= ValueExpressionEx(DscDefaultValue
, Pcd
.DatumType
, self
._GuidDict
)(True)
991 except BadExpression
as DscDefaultValue
:
992 EdkLogger
.error('BuildReport', FORMAT_INVALID
, "PCD Value: %s, Type: %s" %(DscDefaultValue
, Pcd
.DatumType
))
994 InfDefaultValue
= None
996 PcdValue
= DecDefaultValue
998 PcdValue
= DscDefaultValue
999 #The DefaultValue of StructurePcd already be the latest, no need to update.
1000 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1001 Pcd
.DefaultValue
= PcdValue
1002 if ModulePcdSet
is not None:
1003 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
1005 InfDefaultValue
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
1006 #The DefaultValue of StructurePcd already be the latest, no need to update.
1007 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1008 Pcd
.DefaultValue
= PcdValue
1011 InfDefaultValue
= ValueExpressionEx(InfDefaultValue
, Pcd
.DatumType
, self
._GuidDict
)(True)
1012 except BadExpression
as InfDefaultValue
:
1013 EdkLogger
.error('BuildReport', FORMAT_INVALID
, "PCD Value: %s, Type: %s" % (InfDefaultValue
, Pcd
.DatumType
))
1014 if InfDefaultValue
== "":
1015 InfDefaultValue
= None
1017 BuildOptionMatch
= False
1018 if GlobalData
.BuildOptionPcd
:
1019 for pcd
in GlobalData
.BuildOptionPcd
:
1020 if (Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
) == (pcd
[0], pcd
[1]):
1024 #The DefaultValue of StructurePcd already be the latest, no need to update.
1025 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1026 Pcd
.DefaultValue
= PcdValue
1027 BuildOptionMatch
= True
1031 if ModulePcdSet
is None:
1033 FileWrite(File
, Key
)
1037 if Pcd
.DatumType
in TAB_PCD_NUMERIC_TYPES
:
1038 PcdValueNumber
= int(PcdValue
.strip(), 0)
1039 if DecDefaultValue
is None:
1042 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
1043 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
1045 if InfDefaultValue
is None:
1048 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
1049 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
1051 if DscDefaultValue
is None:
1054 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
1055 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
1057 if DecDefaultValue
is None:
1060 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
1062 if InfDefaultValue
is None:
1065 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
1067 if DscDefaultValue
is None:
1070 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
1073 if self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1075 if TypeName
in ('DYNVPD', 'DEXVPD'):
1076 SkuInfoList
= Pcd
.SkuInfoList
1077 Pcd
= GlobalData
.gStructurePcd
[self
.Arch
][(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
)]
1078 Pcd
.DatumType
= Pcd
.StructName
1079 if TypeName
in ('DYNVPD', 'DEXVPD'):
1080 Pcd
.SkuInfoList
= SkuInfoList
1081 if Pcd
.PcdValueFromComm
or Pcd
.PcdFieldValueFromComm
:
1082 BuildOptionMatch
= True
1084 elif Pcd
.PcdValueFromFdf
or Pcd
.PcdFieldValueFromFdf
:
1085 DscDefaultValue
= True
1088 elif Pcd
.SkuOverrideValues
:
1090 if Pcd
.DefaultFromDSC
:
1094 for item
in Pcd
.SkuOverrideValues
:
1095 DictLen
+= len(Pcd
.SkuOverrideValues
[item
])
1099 if not Pcd
.SkuInfoList
:
1100 OverrideValues
= Pcd
.SkuOverrideValues
1102 for Data
in OverrideValues
.values():
1103 Struct
= list(Data
.values())
1105 DscOverride
= self
.ParseStruct(Struct
[0])
1108 SkuList
= sorted(Pcd
.SkuInfoList
.keys())
1110 SkuInfo
= Pcd
.SkuInfoList
[Sku
]
1111 if TypeName
in ('DYNHII', 'DEXHII'):
1112 if SkuInfo
.DefaultStoreDict
:
1113 DefaultStoreList
= sorted(SkuInfo
.DefaultStoreDict
.keys())
1114 for DefaultStore
in DefaultStoreList
:
1115 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1116 DscOverride
= self
.ParseStruct(OverrideValues
[DefaultStore
])
1120 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1122 Keys
= list(OverrideValues
.keys())
1123 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[Keys
[0]])
1124 DscOverride
= self
.ParseStruct(OverrideFieldStruct
)
1128 DscDefaultValue
= True
1134 DscDefaultValue
= True
1139 # Report PCD item according to their override relationship
1141 if Pcd
.DatumType
== 'BOOLEAN':
1143 DscDefaultValue
= str(int(DscDefaultValue
, 0))
1145 DecDefaultValue
= str(int(DecDefaultValue
, 0))
1147 InfDefaultValue
= str(int(InfDefaultValue
, 0))
1148 if Pcd
.DefaultValue
:
1149 Pcd
.DefaultValue
= str(int(Pcd
.DefaultValue
, 0))
1151 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, ' ')
1152 elif InfDefaultValue
and InfMatch
:
1153 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*M')
1154 elif BuildOptionMatch
:
1155 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*B')
1157 if DscDefaultValue
and DscMatch
:
1158 if (Pcd
.TokenCName
, Key
, Field
) in self
.FdfPcdSet
:
1159 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*F')
1161 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*P')
1163 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*M')
1165 if ModulePcdSet
is None:
1168 if not TypeName
in ('PATCH', 'FLAG', 'FIXED'):
1170 if not BuildOptionMatch
:
1171 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
1172 for ModulePath
in ModuleOverride
:
1173 ModuleDefault
= ModuleOverride
[ModulePath
]
1174 if Pcd
.DatumType
in TAB_PCD_NUMERIC_TYPES
:
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 struct
.items():
1207 if Values
[1] and Values
[1].endswith('.dsc'):
1208 HasDscOverride
= True
1210 return HasDscOverride
1212 def PrintPcdDefault(self
, File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
):
1213 if not DscMatch
and DscDefaultValue
is not None:
1214 Value
= DscDefaultValue
.strip()
1215 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1217 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', "{"))
1218 for Array
in ArrayList
:
1219 FileWrite(File
, Array
)
1221 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1222 if Value
.startswith(('0x', '0X')):
1223 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1225 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1226 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', Value
))
1227 if not InfMatch
and InfDefaultValue
is not None:
1228 Value
= InfDefaultValue
.strip()
1229 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1231 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', "{"))
1232 for Array
in ArrayList
:
1233 FileWrite(File
, Array
)
1235 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1236 if Value
.startswith(('0x', '0X')):
1237 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1239 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1240 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', Value
))
1242 if not DecMatch
and DecDefaultValue
is not None:
1243 Value
= DecDefaultValue
.strip()
1244 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1246 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', "{"))
1247 for Array
in ArrayList
:
1248 FileWrite(File
, Array
)
1250 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1251 if Value
.startswith(('0x', '0X')):
1252 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1254 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1255 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', Value
))
1257 self
.PrintStructureInfo(File
, Pcd
.DefaultValues
)
1258 if DecMatch
and IsStructure
:
1259 self
.PrintStructureInfo(File
, Pcd
.DefaultValues
)
1261 def PrintPcdValue(self
, File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, Flag
= ' '):
1262 if not Pcd
.SkuInfoList
:
1263 Value
= Pcd
.DefaultValue
1264 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1266 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1267 for Array
in ArrayList
:
1268 FileWrite(File
, Array
)
1270 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1271 if Value
.startswith(('0x', '0X')):
1272 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1274 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1275 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1277 FiledOverrideFlag
= False
1278 OverrideValues
= Pcd
.SkuOverrideValues
1280 for Data
in OverrideValues
.values():
1281 Struct
= list(Data
.values())
1283 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, Struct
[0])
1284 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1285 FiledOverrideFlag
= True
1287 if not FiledOverrideFlag
and (Pcd
.PcdFieldValueFromComm
or Pcd
.PcdFieldValueFromFdf
):
1288 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, {})
1289 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1290 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1293 SkuList
= sorted(Pcd
.SkuInfoList
.keys())
1295 SkuInfo
= Pcd
.SkuInfoList
[Sku
]
1296 SkuIdName
= SkuInfo
.SkuIdName
1297 if TypeName
in ('DYNHII', 'DEXHII'):
1298 if SkuInfo
.DefaultStoreDict
:
1299 DefaultStoreList
= sorted(SkuInfo
.DefaultStoreDict
.keys())
1300 for DefaultStore
in DefaultStoreList
:
1301 Value
= SkuInfo
.DefaultStoreDict
[DefaultStore
]
1302 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1303 if Pcd
.DatumType
== 'BOOLEAN':
1304 Value
= str(int(Value
, 0))
1308 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1309 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1310 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1311 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '{'))
1312 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1313 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', '{'))
1315 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', '{'))
1316 for Array
in ArrayList
:
1317 FileWrite(File
, Array
)
1319 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1320 if Value
.startswith(('0x', '0X')):
1321 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1323 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1324 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1325 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1326 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1327 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1328 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1329 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', Value
))
1331 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', Value
))
1334 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1335 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1336 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1337 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '{'))
1338 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1339 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', '{'))
1341 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', '{'))
1342 for Array
in ArrayList
:
1343 FileWrite(File
, Array
)
1345 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1346 if Value
.startswith(('0x', '0X')):
1347 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1349 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1350 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1351 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1352 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1353 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1354 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1355 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', Value
))
1357 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', Value
))
1358 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
1360 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1361 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[DefaultStore
])
1362 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1363 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1365 Value
= SkuInfo
.DefaultValue
1366 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1367 if Pcd
.DatumType
== 'BOOLEAN':
1368 Value
= str(int(Value
, 0))
1373 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', "{"))
1375 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', "{"))
1376 for Array
in ArrayList
:
1377 FileWrite(File
, Array
)
1379 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1380 if Value
.startswith(('0x', '0X')):
1381 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1383 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1385 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1387 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1391 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', "{"))
1393 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', "{"))
1394 for Array
in ArrayList
:
1395 FileWrite(File
, Array
)
1397 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1398 if Value
.startswith(('0x', '0X')):
1399 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1401 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1403 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1405 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1406 if TypeName
in ('DYNVPD', 'DEXVPD'):
1407 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
1408 VPDPcdItem
= (Pcd
.TokenSpaceGuidCName
+ '.' + PcdTokenCName
, SkuIdName
, SkuInfo
.VpdOffset
, Pcd
.MaxDatumSize
, SkuInfo
.DefaultValue
)
1409 if VPDPcdItem
not in VPDPcdList
:
1410 VPDPcdList
.append(VPDPcdItem
)
1412 FiledOverrideFlag
= False
1413 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1415 Keys
= OverrideValues
.keys()
1416 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[Keys
[0]])
1417 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1418 FiledOverrideFlag
= True
1419 if not FiledOverrideFlag
and (Pcd
.PcdFieldValueFromComm
or Pcd
.PcdFieldValueFromFdf
):
1420 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, {})
1421 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1422 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1424 def OverrideFieldValue(self
, Pcd
, OverrideStruct
):
1425 OverrideFieldStruct
= collections
.OrderedDict()
1427 for _
, Values
in OverrideStruct
.items():
1428 for Key
,value
in Values
.items():
1429 if value
[1] and value
[1].endswith('.dsc'):
1430 OverrideFieldStruct
[Key
] = value
1431 if Pcd
.PcdFieldValueFromFdf
:
1432 for Key
, Values
in Pcd
.PcdFieldValueFromFdf
.items():
1433 if Key
in OverrideFieldStruct
and Values
[0] == OverrideFieldStruct
[Key
][0]:
1435 OverrideFieldStruct
[Key
] = Values
1436 if Pcd
.PcdFieldValueFromComm
:
1437 for Key
, Values
in Pcd
.PcdFieldValueFromComm
.items():
1438 if Key
in OverrideFieldStruct
and Values
[0] == OverrideFieldStruct
[Key
][0]:
1440 OverrideFieldStruct
[Key
] = Values
1441 return OverrideFieldStruct
1443 def PrintStructureInfo(self
, File
, Struct
):
1444 for Key
, Value
in sorted(Struct
.items(), key
=lambda x
: x
[0]):
1445 if Value
[1] and 'build command options' in Value
[1]:
1446 FileWrite(File
, ' *B %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1447 elif Value
[1] and Value
[1].endswith('.fdf'):
1448 FileWrite(File
, ' *F %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1450 FileWrite(File
, ' %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1452 def StrtoHex(self
, value
):
1454 value
= hex(int(value
))
1457 if value
.startswith("L\"") and value
.endswith("\""):
1459 for ch
in value
[2:-1]:
1460 valuelist
.append(hex(ord(ch
)))
1461 valuelist
.append('0x00')
1463 elif value
.startswith("\"") and value
.endswith("\""):
1464 return hex(ord(value
[1:-1]))
1465 elif value
.startswith("{") and value
.endswith("}"):
1467 if ',' not in value
:
1469 for ch
in value
[1:-1].split(','):
1471 if ch
.startswith('0x') or ch
.startswith('0X'):
1472 valuelist
.append(ch
)
1475 valuelist
.append(hex(int(ch
.strip())))
1482 def IsStructurePcd(self
, PcdToken
, PcdTokenSpaceGuid
):
1483 if GlobalData
.gStructurePcd
and (self
.Arch
in GlobalData
.gStructurePcd
) and ((PcdToken
, PcdTokenSpaceGuid
) in GlobalData
.gStructurePcd
[self
.Arch
]):
1489 # Reports platform and module Prediction information
1491 # This class reports the platform execution order prediction section and
1492 # module load fixed address prediction subsection in the build report file.
1494 class PredictionReport(object):
1496 # Constructor function for class PredictionReport
1498 # This constructor function generates PredictionReport object for the platform.
1500 # @param self: The object pointer
1501 # @param Wa Workspace context information
1503 def __init__(self
, Wa
):
1504 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
1505 self
._MapFileParsed
= False
1506 self
._EotToolInvoked
= False
1507 self
._FvDir
= Wa
.FvDir
1508 self
._EotDir
= Wa
.BuildDir
1509 self
._FfsEntryPoint
= {}
1511 self
._SourceList
= []
1512 self
.FixedMapDict
= {}
1517 # Collect all platform reference source files and GUID C Name
1519 for Pa
in Wa
.AutoGenObjectList
:
1520 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
1522 # BASE typed modules are EFI agnostic, so we need not scan
1523 # their source code to find PPI/Protocol produce or consume
1526 if Module
.ModuleType
== SUP_MODULE_BASE
:
1529 # Add module referenced source files
1531 self
._SourceList
.append(str(Module
))
1533 for Source
in Module
.SourceFileList
:
1534 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
1535 self
._SourceList
.append(" " + str(Source
))
1536 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
1537 for IncludeFile
in IncludeList
.values():
1538 self
._SourceList
.append(" " + IncludeFile
)
1540 for Guid
in Module
.PpiList
:
1541 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
1542 for Guid
in Module
.ProtocolList
:
1543 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
1544 for Guid
in Module
.GuidList
:
1545 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
1547 if Module
.Guid
and not Module
.IsLibrary
:
1548 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
1549 if int(str(Module
.AutoGenVersion
), 0) >= 0x00010005:
1550 RealEntryPoint
= "_ModuleEntryPoint"
1552 RealEntryPoint
= EntryPoint
1553 if EntryPoint
== "_ModuleEntryPoint":
1554 CCFlags
= Module
.BuildOption
.get("CC", {}).get("FLAGS", "")
1555 Match
= gGlueLibEntryPoint
.search(CCFlags
)
1557 EntryPoint
= Match
.group(1)
1559 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
1563 # Collect platform firmware volume list as the input of EOT.
1567 for Fd
in Wa
.FdfProfile
.FdDict
:
1568 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
1569 if FdRegion
.RegionType
!= BINARY_FILE_TYPE_FV
:
1571 for FvName
in FdRegion
.RegionDataList
:
1572 if FvName
in self
._FvList
:
1574 self
._FvList
.append(FvName
)
1575 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1576 for Section
in Ffs
.SectionList
:
1578 for FvSection
in Section
.SectionList
:
1579 if FvSection
.FvName
in self
._FvList
:
1581 self
._FvList
.append(FvSection
.FvName
)
1582 except AttributeError:
1587 # Parse platform fixed address map files
1589 # This function parses the platform final fixed address map file to get
1590 # the database of predicted fixed address for module image base, entry point
1593 # @param self: The object pointer
1595 def _ParseMapFile(self
):
1596 if self
._MapFileParsed
:
1598 self
._MapFileParsed
= True
1599 if os
.path
.isfile(self
._MapFileName
):
1601 FileContents
= open(self
._MapFileName
).read()
1602 for Match
in gMapFileItemPattern
.finditer(FileContents
):
1603 AddressType
= Match
.group(1)
1604 BaseAddress
= Match
.group(2)
1605 EntryPoint
= Match
.group(3)
1606 Guid
= Match
.group(4).upper()
1607 List
= self
.FixedMapDict
.setdefault(Guid
, [])
1608 List
.append((AddressType
, BaseAddress
, "*I"))
1609 List
.append((AddressType
, EntryPoint
, "*E"))
1611 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
1614 # Invokes EOT tool to get the predicted the execution order.
1616 # This function invokes EOT tool to calculate the predicted dispatch order
1618 # @param self: The object pointer
1620 def _InvokeEotTool(self
):
1621 if self
._EotToolInvoked
:
1624 self
._EotToolInvoked
= True
1626 for FvName
in self
._FvList
:
1627 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
1628 if os
.path
.isfile(FvFile
):
1629 FvFileList
.append(FvFile
)
1631 if len(FvFileList
) == 0:
1634 # Write source file list and GUID file list to an intermediate file
1635 # as the input for EOT tool and dispatch List as the output file
1638 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
1639 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
1640 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
1642 TempFile
= open(SourceList
, "w+")
1643 for Item
in self
._SourceList
:
1644 FileWrite(TempFile
, Item
)
1646 TempFile
= open(GuidList
, "w+")
1647 for Key
in self
._GuidMap
:
1648 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
1652 from Eot
.EotMain
import Eot
1655 # Invoke EOT tool and echo its runtime performance
1657 EotStartTime
= time
.time()
1658 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
1659 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
1660 EotEndTime
= time
.time()
1661 EotDuration
= time
.strftime("%H:%M:%S", time
.gmtime(int(round(EotEndTime
- EotStartTime
))))
1662 EdkLogger
.quiet("EOT run time: %s\n" % EotDuration
)
1665 # Parse the output of EOT tool
1667 for Line
in open(DispatchList
):
1668 if len(Line
.split()) < 4:
1670 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
1671 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
1672 if len(Symbol
) > self
.MaxLen
:
1673 self
.MaxLen
= len(Symbol
)
1674 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
1676 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1677 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1681 # Generate platform execution order report
1683 # This function generates the predicted module execution order.
1685 # @param self The object pointer
1686 # @param File The file object for report
1688 def _GenerateExecutionOrderReport(self
, File
):
1689 self
._InvokeEotTool
()
1690 if len(self
.ItemList
) == 0:
1692 FileWrite(File
, gSectionStart
)
1693 FileWrite(File
, "Execution Order Prediction")
1694 FileWrite(File
, "*P PEI phase")
1695 FileWrite(File
, "*D DXE phase")
1696 FileWrite(File
, "*E Module INF entry point name")
1697 FileWrite(File
, "*N Module notification function name")
1699 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
1700 FileWrite(File
, gSectionSep
)
1701 for Item
in self
.ItemList
:
1702 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
1704 FileWrite(File
, gSectionStart
)
1707 # Generate Fixed Address report.
1709 # This function generate the predicted fixed address report for a module
1710 # specified by Guid.
1712 # @param self The object pointer
1713 # @param File The file object for report
1714 # @param Guid The module Guid value.
1715 # @param NotifyList The list of all notify function in a module
1717 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
1718 self
._ParseMapFile
()
1719 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
1720 if not FixedAddressList
:
1723 FileWrite(File
, gSubSectionStart
)
1724 FileWrite(File
, "Fixed Address Prediction")
1725 FileWrite(File
, "*I Image Loading Address")
1726 FileWrite(File
, "*E Entry Point Address")
1727 FileWrite(File
, "*N Notification Function Address")
1728 FileWrite(File
, "*F Flash Address")
1729 FileWrite(File
, "*M Memory Address")
1730 FileWrite(File
, "*S SMM RAM Offset")
1731 FileWrite(File
, "TOM Top of Memory")
1733 FileWrite(File
, "Type Address Name")
1734 FileWrite(File
, gSubSectionSep
)
1735 for Item
in FixedAddressList
:
1740 Name
= "(Image Base)"
1741 elif Symbol
== "*E":
1742 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
1743 elif Symbol
in NotifyList
:
1751 elif "Memory" in Type
:
1757 Value
= "TOM" + Value
1759 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
1762 # Generate report for the prediction part
1764 # This function generate the predicted fixed address report for a module or
1765 # predicted module execution order for a platform.
1766 # If the input Guid is None, then, it generates the predicted module execution order;
1767 # otherwise it generated the module fixed loading address for the module specified by
1770 # @param self The object pointer
1771 # @param File The file object for report
1772 # @param Guid The module Guid value.
1774 def GenerateReport(self
, File
, Guid
):
1776 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1778 self
._GenerateExecutionOrderReport
(File
)
1781 # Reports FD region information
1783 # This class reports the FD subsection in the build report file.
1784 # It collects region information of platform flash device.
1785 # If the region is a firmware volume, it lists the set of modules
1786 # and its space information; otherwise, it only lists its region name,
1787 # base address and size in its sub-section header.
1788 # If there are nesting FVs, the nested FVs will list immediate after
1789 # this FD region subsection
1791 class FdRegionReport(object):
1793 # Discover all the nested FV name list.
1795 # This is an internal worker function to discover the all the nested FV information
1796 # in the parent firmware volume. It uses deep first search algorithm recursively to
1797 # find all the FV list name and append them to the list.
1799 # @param self The object pointer
1800 # @param FvName The name of current firmware file system
1801 # @param Wa Workspace context information
1803 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1804 FvDictKey
=FvName
.upper()
1805 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1806 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1807 for Section
in Ffs
.SectionList
:
1809 for FvSection
in Section
.SectionList
:
1810 if FvSection
.FvName
in self
.FvList
:
1812 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1813 self
.FvList
.append(FvSection
.FvName
)
1814 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1815 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1816 except AttributeError:
1820 # Constructor function for class FdRegionReport
1822 # This constructor function generates FdRegionReport object for a specified FdRegion.
1823 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1824 # volume list. This function also collects GUID map in order to dump module identification
1825 # in the final report.
1827 # @param self: The object pointer
1828 # @param FdRegion The current FdRegion object
1829 # @param Wa Workspace context information
1831 def __init__(self
, FdRegion
, Wa
):
1832 self
.Type
= FdRegion
.RegionType
1833 self
.BaseAddress
= FdRegion
.Offset
1834 self
.Size
= FdRegion
.Size
1838 self
._FvDir
= Wa
.FvDir
1839 self
._WorkspaceDir
= Wa
.WorkspaceDir
1842 # If the input FdRegion is not a firmware volume,
1845 if self
.Type
!= BINARY_FILE_TYPE_FV
:
1849 # Find all nested FVs in the FdRegion
1851 for FvName
in FdRegion
.RegionDataList
:
1852 if FvName
in self
.FvList
:
1854 self
.FvList
.append(FvName
)
1855 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1856 self
._DiscoverNestedFvList
(FvName
, Wa
)
1860 # Collect PCDs declared in DEC files.
1862 for Pa
in Wa
.AutoGenObjectList
:
1863 for Package
in Pa
.PackageList
:
1864 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1865 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1866 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1868 # Collect PCDs defined in DSC file
1870 for Pa
in Wa
.AutoGenObjectList
:
1871 for (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
1872 DscDefaultValue
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1873 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1876 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1878 self
._GuidsDb
[PEI_APRIORI_GUID
] = "PEI Apriori"
1879 self
._GuidsDb
[DXE_APRIORI_GUID
] = "DXE Apriori"
1881 # Add ACPI table storage file
1883 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1885 for Pa
in Wa
.AutoGenObjectList
:
1886 for ModuleKey
in Pa
.Platform
.Modules
:
1887 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1888 InfPath
= mws
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1889 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1892 # Collect the GUID map in the FV firmware volume
1894 for FvName
in self
.FvList
:
1895 FvDictKey
=FvName
.upper()
1896 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1897 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1900 # collect GUID map for binary EFI file in FDF file.
1902 Guid
= Ffs
.NameGuid
.upper()
1903 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1905 PcdTokenspace
= Match
.group(1)
1906 PcdToken
= Match
.group(2)
1907 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1908 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1909 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1910 for Section
in Ffs
.SectionList
:
1912 ModuleSectFile
= mws
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1913 self
._GuidsDb
[Guid
] = ModuleSectFile
1914 except AttributeError:
1916 except AttributeError:
1921 # Internal worker function to generate report for the FD region
1923 # This internal worker function to generate report for the FD region.
1924 # It the type is firmware volume, it lists offset and module identification.
1926 # @param self The object pointer
1927 # @param File The file object for report
1928 # @param Title The title for the FD subsection
1929 # @param BaseAddress The base address for the FD region
1930 # @param Size The size of the FD region
1931 # @param FvName The FV name if the FD region is a firmware volume
1933 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1934 FileWrite(File
, gSubSectionStart
)
1935 FileWrite(File
, Title
)
1936 FileWrite(File
, "Type: %s" % Type
)
1937 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1939 if self
.Type
== BINARY_FILE_TYPE_FV
:
1943 if FvName
.upper().endswith('.FV'):
1944 FileExt
= FvName
+ ".txt"
1946 FileExt
= FvName
+ ".Fv.txt"
1948 if not os
.path
.isfile(FileExt
):
1949 FvReportFileName
= mws
.join(self
._WorkspaceDir
, FileExt
)
1950 if not os
.path
.isfile(FvReportFileName
):
1951 FvReportFileName
= os
.path
.join(self
._FvDir
, FileExt
)
1954 # Collect size info in the firmware volume.
1956 FvReport
= open(FvReportFileName
).read()
1957 Match
= gFvTotalSizePattern
.search(FvReport
)
1959 FvTotalSize
= int(Match
.group(1), 16)
1960 Match
= gFvTakenSizePattern
.search(FvReport
)
1962 FvTakenSize
= int(Match
.group(1), 16)
1963 FvFreeSize
= FvTotalSize
- FvTakenSize
1965 # Write size information to the report file.
1967 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1968 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1969 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1970 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1971 FileWrite(File
, "Offset Module")
1972 FileWrite(File
, gSubSectionSep
)
1974 # Write module offset and module identification to the report file.
1977 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1978 Guid
= Match
.group(2).upper()
1979 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1980 OffsetList
= sorted(OffsetInfo
.keys())
1981 for Offset
in OffsetList
:
1982 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1984 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
1986 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
1987 FileWrite(File
, gSubSectionEnd
)
1990 # Generate report for the FD region
1992 # This function generates report for the FD region.
1994 # @param self The object pointer
1995 # @param File The file object for report
1997 def GenerateReport(self
, File
):
1998 if (len(self
.FvList
) > 0):
1999 for FvItem
in self
.FvList
:
2000 Info
= self
.FvInfo
[FvItem
]
2001 self
._GenerateReport
(File
, Info
[0], TAB_FV_DIRECTORY
, Info
[1], Info
[2], FvItem
)
2003 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
2006 # Reports FD information
2008 # This class reports the FD section in the build report file.
2009 # It collects flash device information for a platform.
2011 class FdReport(object):
2013 # Constructor function for class FdReport
2015 # This constructor function generates FdReport object for a specified
2018 # @param self The object pointer
2019 # @param Fd The current Firmware device object
2020 # @param Wa Workspace context information
2022 def __init__(self
, Fd
, Wa
):
2023 self
.FdName
= Fd
.FdUiName
2024 self
.BaseAddress
= Fd
.BaseAddress
2026 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
2027 self
.FvPath
= os
.path
.join(Wa
.BuildDir
, TAB_FV_DIRECTORY
)
2028 self
.VPDBaseAddress
= 0
2030 for index
, FdRegion
in enumerate(Fd
.RegionList
):
2031 if str(FdRegion
.RegionType
) is 'FILE' and Wa
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
2032 self
.VPDBaseAddress
= self
.FdRegionList
[index
].BaseAddress
2033 self
.VPDSize
= self
.FdRegionList
[index
].Size
2037 # Generate report for the firmware device.
2039 # This function generates report for the firmware device.
2041 # @param self The object pointer
2042 # @param File The file object for report
2044 def GenerateReport(self
, File
):
2045 FileWrite(File
, gSectionStart
)
2046 FileWrite(File
, "Firmware Device (FD)")
2047 FileWrite(File
, "FD Name: %s" % self
.FdName
)
2048 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
2049 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
2050 if len(self
.FdRegionList
) > 0:
2051 FileWrite(File
, gSectionSep
)
2052 for FdRegionItem
in self
.FdRegionList
:
2053 FdRegionItem
.GenerateReport(File
)
2056 VPDPcdList
.sort(key
=lambda x
: int(x
[2], 0))
2057 FileWrite(File
, gSubSectionStart
)
2058 FileWrite(File
, "FD VPD Region")
2059 FileWrite(File
, "Base Address: 0x%X" % self
.VPDBaseAddress
)
2060 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.VPDSize
, self
.VPDSize
/ 1024.0))
2061 FileWrite(File
, gSubSectionSep
)
2062 for item
in VPDPcdList
:
2063 # Add BaseAddress for offset
2064 Offset
= '0x%08X' % (int(item
[2], 16) + self
.VPDBaseAddress
)
2065 IsByteArray
, ArrayList
= ByteArrayForamt(item
[-1])
2067 if len(GlobalData
.gSkuids
) == 1 :
2068 Skuinfo
= GlobalData
.gSkuids
[0]
2070 FileWrite(File
, "%s | %s | %s | %s | %s" % (item
[0], Skuinfo
, Offset
, item
[3], '{'))
2071 for Array
in ArrayList
:
2072 FileWrite(File
, Array
)
2074 FileWrite(File
, "%s | %s | %s | %s | %s" % (item
[0], Skuinfo
, Offset
, item
[3], item
[-1]))
2075 FileWrite(File
, gSubSectionEnd
)
2076 FileWrite(File
, gSectionEnd
)
2081 # Reports platform information
2083 # This class reports the whole platform information
2085 class PlatformReport(object):
2087 # Constructor function for class PlatformReport
2089 # This constructor function generates PlatformReport object a platform build.
2090 # It generates report for platform summary, flash, global PCDs and detailed
2091 # module information for modules involved in platform build.
2093 # @param self The object pointer
2094 # @param Wa Workspace context information
2095 # @param MaList The list of modules in the platform build
2097 def __init__(self
, Wa
, MaList
, ReportType
):
2098 self
._WorkspaceDir
= Wa
.WorkspaceDir
2099 self
.PlatformName
= Wa
.Name
2100 self
.PlatformDscPath
= Wa
.Platform
2101 self
.Architectures
= " ".join(Wa
.ArchList
)
2102 self
.ToolChain
= Wa
.ToolChain
2103 self
.Target
= Wa
.BuildTarget
2104 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
2105 self
.BuildEnvironment
= platform
.platform()
2107 self
.PcdReport
= None
2108 if "PCD" in ReportType
:
2109 self
.PcdReport
= PcdReport(Wa
)
2111 self
.FdReportList
= []
2112 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
is None:
2113 for Fd
in Wa
.FdfProfile
.FdDict
:
2114 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
2116 self
.PredictionReport
= None
2117 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
2118 self
.PredictionReport
= PredictionReport(Wa
)
2120 self
.DepexParser
= None
2121 if "DEPEX" in ReportType
:
2122 self
.DepexParser
= DepexParser(Wa
)
2124 self
.ModuleReportList
= []
2125 if MaList
is not None:
2126 self
._IsModuleBuild
= True
2128 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
2130 self
._IsModuleBuild
= False
2131 for Pa
in Wa
.AutoGenObjectList
:
2132 ModuleAutoGenList
= []
2133 for ModuleKey
in Pa
.Platform
.Modules
:
2134 ModuleAutoGenList
.append(Pa
.Platform
.Modules
[ModuleKey
].M
)
2135 if GlobalData
.gFdfParser
is not None:
2136 if Pa
.Arch
in GlobalData
.gFdfParser
.Profile
.InfDict
:
2137 INFList
= GlobalData
.gFdfParser
.Profile
.InfDict
[Pa
.Arch
]
2138 for InfName
in INFList
:
2139 InfClass
= PathClass(NormPath(InfName
), Wa
.WorkspaceDir
, Pa
.Arch
)
2140 Ma
= ModuleAutoGen(Wa
, InfClass
, Pa
.BuildTarget
, Pa
.ToolChain
, Pa
.Arch
, Wa
.MetaFile
)
2143 if Ma
not in ModuleAutoGenList
:
2144 ModuleAutoGenList
.append(Ma
)
2145 for MGen
in ModuleAutoGenList
:
2146 self
.ModuleReportList
.append(ModuleReport(MGen
, ReportType
))
2151 # Generate report for the whole platform.
2153 # This function generates report for platform information.
2154 # It comprises of platform summary, global PCD, flash and
2155 # module list sections.
2157 # @param self The object pointer
2158 # @param File The file object for report
2159 # @param BuildDuration The total time to build the modules
2160 # @param AutoGenTime The total time of AutoGen Phase
2161 # @param MakeTime The total time of Make Phase
2162 # @param GenFdsTime The total time of GenFds Phase
2163 # @param ReportType The kind of report items in the final report file
2165 def GenerateReport(self
, File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, ReportType
):
2166 FileWrite(File
, "Platform Summary")
2167 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
2168 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
2169 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
2170 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
2171 FileWrite(File
, "Target: %s" % self
.Target
)
2172 if GlobalData
.gSkuids
:
2173 FileWrite(File
, "SKUID: %s" % " ".join(GlobalData
.gSkuids
))
2174 if GlobalData
.gDefaultStores
:
2175 FileWrite(File
, "DefaultStore: %s" % " ".join(GlobalData
.gDefaultStores
))
2176 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
2177 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
2178 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
2180 FileWrite(File
, "AutoGen Duration: %s" % AutoGenTime
)
2182 FileWrite(File
, "Make Duration: %s" % MakeTime
)
2184 FileWrite(File
, "GenFds Duration: %s" % GenFdsTime
)
2185 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
2187 if GlobalData
.MixedPcd
:
2188 FileWrite(File
, gSectionStart
)
2189 FileWrite(File
, "The following PCDs use different access methods:")
2190 FileWrite(File
, gSectionSep
)
2191 for PcdItem
in GlobalData
.MixedPcd
:
2192 FileWrite(File
, "%s.%s" % (str(PcdItem
[1]), str(PcdItem
[0])))
2193 FileWrite(File
, gSectionEnd
)
2195 if not self
._IsModuleBuild
:
2196 if "PCD" in ReportType
:
2197 self
.PcdReport
.GenerateReport(File
, None)
2199 if "FLASH" in ReportType
:
2200 for FdReportListItem
in self
.FdReportList
:
2201 FdReportListItem
.GenerateReport(File
)
2203 for ModuleReportItem
in self
.ModuleReportList
:
2204 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, self
.DepexParser
, ReportType
)
2206 if not self
._IsModuleBuild
:
2207 if "EXECUTION_ORDER" in ReportType
:
2208 self
.PredictionReport
.GenerateReport(File
, None)
2210 ## BuildReport class
2212 # This base class contain the routines to collect data and then
2213 # applies certain format to the output report
2215 class BuildReport(object):
2217 # Constructor function for class BuildReport
2219 # This constructor function generates BuildReport object a platform build.
2220 # It generates report for platform summary, flash, global PCDs and detailed
2221 # module information for modules involved in platform build.
2223 # @param self The object pointer
2224 # @param ReportFile The file name to save report file
2225 # @param ReportType The kind of report items in the final report file
2227 def __init__(self
, ReportFile
, ReportType
):
2228 self
.ReportFile
= ReportFile
2230 self
.ReportList
= []
2231 self
.ReportType
= []
2233 for ReportTypeItem
in ReportType
:
2234 if ReportTypeItem
not in self
.ReportType
:
2235 self
.ReportType
.append(ReportTypeItem
)
2237 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]
2239 # Adds platform report to the list
2241 # This function adds a platform report to the final report list.
2243 # @param self The object pointer
2244 # @param Wa Workspace context information
2245 # @param MaList The list of modules in the platform build
2247 def AddPlatformReport(self
, Wa
, MaList
=None):
2249 self
.ReportList
.append((Wa
, MaList
))
2252 # Generates the final report.
2254 # This function generates platform build report. It invokes GenerateReport()
2255 # method for every platform report in the list.
2257 # @param self The object pointer
2258 # @param BuildDuration The total time to build the modules
2259 # @param AutoGenTime The total time of AutoGen phase
2260 # @param MakeTime The total time of Make phase
2261 # @param GenFdsTime The total time of GenFds phase
2263 def GenerateReport(self
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
):
2267 for (Wa
, MaList
) in self
.ReportList
:
2268 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, self
.ReportType
)
2269 Content
= FileLinesSplit(File
.getvalue(), gLineMaxLength
)
2270 SaveFileOnChange(self
.ReportFile
, Content
, True)
2271 EdkLogger
.quiet("Build report can be found at %s" % os
.path
.abspath(self
.ReportFile
))
2273 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
2275 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
2276 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
2279 # This acts like the main() function for the script, unless it is 'import'ed into another script.
2280 if __name__
== '__main__':