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 *
50 ## Pattern to extract contents in EDK DXS files
51 gDxsDependencyPattern
= re
.compile(r
"DEPENDENCY_START(.+)DEPENDENCY_END", re
.DOTALL
)
53 ## Pattern to find total FV total size, occupied size in flash report intermediate file
54 gFvTotalSizePattern
= re
.compile(r
"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
55 gFvTakenSizePattern
= re
.compile(r
"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
57 ## Pattern to find module size and time stamp in module summary report intermediate file
58 gModuleSizePattern
= re
.compile(r
"MODULE_SIZE = (\d+)")
59 gTimeStampPattern
= re
.compile(r
"TIME_STAMP = (\d+)")
61 ## Pattern to find GUID value in flash description files
62 gPcdGuidPattern
= re
.compile(r
"PCD\((\w+)[.](\w+)\)")
64 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
65 gOffsetGuidPattern
= re
.compile(r
"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
67 ## Pattern to find module base address and entry point in fixed flash map file
68 gModulePattern
= r
"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
69 gMapFileItemPattern
= re
.compile(gModulePattern
% {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
71 ## Pattern to find all module referenced header files in source files
72 gIncludePattern
= re
.compile(r
'#include\s*["<]([^">]+)[">]')
73 gIncludePattern2
= re
.compile(r
"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
75 ## Pattern to find the entry point for EDK module using EDKII Glue library
76 gGlueLibEntryPoint
= re
.compile(r
"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
78 ## Tags for MaxLength of line in report
81 ## Tags for end of line in report
84 ## Tags for section start, end and separator
85 gSectionStart
= ">" + "=" * (gLineMaxLength
- 2) + "<"
86 gSectionEnd
= "<" + "=" * (gLineMaxLength
- 2) + ">" + "\n"
87 gSectionSep
= "=" * gLineMaxLength
89 ## Tags for subsection start, end and separator
90 gSubSectionStart
= ">" + "-" * (gLineMaxLength
- 2) + "<"
91 gSubSectionEnd
= "<" + "-" * (gLineMaxLength
- 2) + ">"
92 gSubSectionSep
= "-" * gLineMaxLength
95 ## The look up table to map PCD type to pair of report display type and DEC type
97 TAB_PCDS_FIXED_AT_BUILD
: ('FIXED', TAB_PCDS_FIXED_AT_BUILD
),
98 TAB_PCDS_PATCHABLE_IN_MODULE
: ('PATCH', TAB_PCDS_PATCHABLE_IN_MODULE
),
99 TAB_PCDS_FEATURE_FLAG
: ('FLAG', TAB_PCDS_FEATURE_FLAG
),
100 TAB_PCDS_DYNAMIC
: ('DYN', TAB_PCDS_DYNAMIC
),
101 TAB_PCDS_DYNAMIC_HII
: ('DYNHII', TAB_PCDS_DYNAMIC
),
102 TAB_PCDS_DYNAMIC_VPD
: ('DYNVPD', TAB_PCDS_DYNAMIC
),
103 TAB_PCDS_DYNAMIC_EX
: ('DEX', TAB_PCDS_DYNAMIC_EX
),
104 TAB_PCDS_DYNAMIC_EX_HII
: ('DEXHII', TAB_PCDS_DYNAMIC_EX
),
105 TAB_PCDS_DYNAMIC_EX_VPD
: ('DEXVPD', TAB_PCDS_DYNAMIC_EX
),
108 ## The look up table to map module type to driver type
110 SUP_MODULE_SEC
: '0x3 (SECURITY_CORE)',
111 SUP_MODULE_PEI_CORE
: '0x4 (PEI_CORE)',
112 SUP_MODULE_PEIM
: '0x6 (PEIM)',
113 SUP_MODULE_DXE_CORE
: '0x5 (DXE_CORE)',
114 SUP_MODULE_DXE_DRIVER
: '0x7 (DRIVER)',
115 SUP_MODULE_DXE_SAL_DRIVER
: '0x7 (DRIVER)',
116 SUP_MODULE_DXE_SMM_DRIVER
: '0x7 (DRIVER)',
117 SUP_MODULE_DXE_RUNTIME_DRIVER
: '0x7 (DRIVER)',
118 SUP_MODULE_UEFI_DRIVER
: '0x7 (DRIVER)',
119 SUP_MODULE_UEFI_APPLICATION
: '0x9 (APPLICATION)',
120 SUP_MODULE_SMM_CORE
: '0xD (SMM_CORE)',
121 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
122 SUP_MODULE_MM_STANDALONE
: '0xE (MM_STANDALONE)',
123 SUP_MODULE_MM_CORE_STANDALONE
: '0xF (MM_CORE_STANDALONE)'
126 ## The look up table of the supported opcode in the dependency expression binaries
127 gOpCodeList
= ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
133 # Writes a string to the file object.
135 # This function writes a string to the file object and a new line is appended
136 # afterwards. It may optionally wraps the string for better readability.
138 # @File The file object to write
139 # @String The string to be written to the file
140 # @Wrapper Indicates whether to wrap the string
142 def FileWrite(File
, String
, Wrapper
=False):
144 String
= textwrap
.fill(String
, 120)
145 File
.write(String
+ gEndOfLine
)
147 def ByteArrayForamt(Value
):
151 if Value
.startswith('{') and Value
.endswith('}'):
153 ValueList
= Value
.split(',')
154 if len(ValueList
) >= SplitNum
:
158 Len
= len(ValueList
)/SplitNum
159 for i
, element
in enumerate(ValueList
):
160 ValueList
[i
] = '0x%02X' % int(element
.strip(), 16)
164 End
= min(SplitNum
*(Id
+1), len(ValueList
))
165 Str
= ','.join(ValueList
[SplitNum
*Id
: End
])
166 if End
== len(ValueList
):
168 ArrayList
.append(Str
)
172 ArrayList
.append(Str
)
175 ArrayList
= [Value
+ '}']
176 return IsByteArray
, ArrayList
179 # Find all the header file that the module source directly includes.
181 # This function scans source code to find all header files the module may
182 # include. This is not accurate but very effective to find all the header
183 # file the module might include with #include statement.
185 # @Source The source file name
186 # @IncludePathList The list of include path to find the source file.
187 # @IncludeFiles The dictionary of current found include files.
189 def FindIncludeFiles(Source
, IncludePathList
, IncludeFiles
):
190 FileContents
= open(Source
).read()
192 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
194 for Match
in gIncludePattern
.finditer(FileContents
):
195 FileName
= Match
.group(1).strip()
196 for Dir
in [os
.path
.dirname(Source
)] + IncludePathList
:
197 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
198 if os
.path
.exists(FullFileName
):
199 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
203 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
205 for Match
in gIncludePattern2
.finditer(FileContents
):
207 Type
= Match
.group(1)
208 if "ARCH_PROTOCOL" in Type
:
209 FileName
= "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
210 elif "PROTOCOL" in Type
:
211 FileName
= "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
213 FileName
= "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key
}
214 elif TAB_GUID
in Type
:
215 FileName
= "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key
}
218 for Dir
in IncludePathList
:
219 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
220 if os
.path
.exists(FullFileName
):
221 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
224 ## Split each lines in file
226 # This method is used to split the lines in file to make the length of each line
227 # less than MaxLength.
229 # @param Content The content of file
230 # @param MaxLength The Max Length of the line
232 def FileLinesSplit(Content
=None, MaxLength
=None):
233 ContentList
= Content
.split(TAB_LINE_BREAK
)
236 for Line
in ContentList
:
237 while len(Line
.rstrip()) > MaxLength
:
238 LineSpaceIndex
= Line
.rfind(TAB_SPACE_SPLIT
, 0, MaxLength
)
239 LineSlashIndex
= Line
.rfind(TAB_SLASH
, 0, MaxLength
)
240 LineBackSlashIndex
= Line
.rfind(TAB_BACK_SLASH
, 0, MaxLength
)
241 if max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
) > 0:
242 LineBreakIndex
= max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
)
244 LineBreakIndex
= MaxLength
245 NewContentList
.append(Line
[:LineBreakIndex
])
246 Line
= Line
[LineBreakIndex
:]
248 NewContentList
.append(Line
)
249 for NewLine
in NewContentList
:
250 NewContent
+= NewLine
+ TAB_LINE_BREAK
252 NewContent
= NewContent
.replace(TAB_LINE_BREAK
, gEndOfLine
).replace('\r\r\n', gEndOfLine
)
258 # Parse binary dependency expression section
260 # This utility class parses the dependency expression section and translate the readable
261 # GUID name and value.
263 class DepexParser(object):
265 # Constructor function for class DepexParser
267 # This constructor function collect GUID values so that the readable
268 # GUID name can be translated.
270 # @param self The object pointer
271 # @param Wa Workspace context information
273 def __init__(self
, Wa
):
275 for Pa
in Wa
.AutoGenObjectList
:
276 for Package
in Pa
.PackageList
:
277 for Protocol
in Package
.Protocols
:
278 GuidValue
= GuidStructureStringToGuidString(Package
.Protocols
[Protocol
])
279 self
._GuidDb
[GuidValue
.upper()] = Protocol
280 for Ppi
in Package
.Ppis
:
281 GuidValue
= GuidStructureStringToGuidString(Package
.Ppis
[Ppi
])
282 self
._GuidDb
[GuidValue
.upper()] = Ppi
283 for Guid
in Package
.Guids
:
284 GuidValue
= GuidStructureStringToGuidString(Package
.Guids
[Guid
])
285 self
._GuidDb
[GuidValue
.upper()] = Guid
286 for Ma
in Pa
.ModuleAutoGenList
:
287 for Pcd
in Ma
.FixedVoidTypePcds
:
288 PcdValue
= Ma
.FixedVoidTypePcds
[Pcd
]
289 if len(PcdValue
.split(',')) == 16:
290 GuidValue
= GuidStructureByteArrayToGuidString(PcdValue
)
291 self
._GuidDb
[GuidValue
.upper()] = Pcd
293 # Parse the binary dependency expression files.
295 # This function parses the binary dependency expression file and translate it
296 # to the instruction list.
298 # @param self The object pointer
299 # @param DepexFileName The file name of binary dependency expression file.
301 def ParseDepexFile(self
, DepexFileName
):
302 DepexFile
= open(DepexFileName
, "rb")
304 OpCode
= DepexFile
.read(1)
306 Statement
= gOpCodeList
[struct
.unpack("B", OpCode
)[0]]
307 if Statement
in ["BEFORE", "AFTER", "PUSH"]:
308 GuidValue
= "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
309 struct
.unpack(PACK_PATTERN_GUID
, DepexFile
.read(16))
310 GuidString
= self
._GuidDb
.get(GuidValue
, GuidValue
)
311 Statement
= "%s %s" % (Statement
, GuidString
)
312 DepexStatement
.append(Statement
)
313 OpCode
= DepexFile
.read(1)
315 return DepexStatement
318 # Reports library information
320 # This class reports the module library subsection in the build report file.
322 class LibraryReport(object):
324 # Constructor function for class LibraryReport
326 # This constructor function generates LibraryReport object for
329 # @param self The object pointer
330 # @param M Module context information
332 def __init__(self
, M
):
333 self
.LibraryList
= []
334 if int(str(M
.AutoGenVersion
), 0) >= 0x00010005:
335 self
._EdkIIModule
= True
337 self
._EdkIIModule
= False
339 for Lib
in M
.DependentLibraryList
:
340 LibInfPath
= str(Lib
)
341 LibClassList
= Lib
.LibraryClass
[0].LibraryClass
342 LibConstructorList
= Lib
.ConstructorList
343 LibDesstructorList
= Lib
.DestructorList
344 LibDepexList
= Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]
345 for LibAutoGen
in M
.LibraryAutoGenList
:
346 if LibInfPath
== LibAutoGen
.MetaFile
.Path
:
347 LibTime
= LibAutoGen
.BuildTime
349 self
.LibraryList
.append((LibInfPath
, LibClassList
, LibConstructorList
, LibDesstructorList
, LibDepexList
, LibTime
))
352 # Generate report for module library information
354 # This function generates report for the module library.
355 # If the module is EDKII style one, the additional library class, library
356 # constructor/destructor and dependency expression may also be reported.
358 # @param self The object pointer
359 # @param File The file object for report
361 def GenerateReport(self
, File
):
362 if len(self
.LibraryList
) > 0:
363 FileWrite(File
, gSubSectionStart
)
364 FileWrite(File
, TAB_BRG_LIBRARY
)
365 FileWrite(File
, gSubSectionSep
)
366 for LibraryItem
in self
.LibraryList
:
367 LibInfPath
= LibraryItem
[0]
368 FileWrite(File
, LibInfPath
)
371 # Report library class, library constructor and destructor for
372 # EDKII style module.
374 if self
._EdkIIModule
:
375 LibClass
= LibraryItem
[1]
377 LibConstructor
= " ".join(LibraryItem
[2])
379 EdkIILibInfo
+= " C = " + LibConstructor
380 LibDestructor
= " ".join(LibraryItem
[3])
382 EdkIILibInfo
+= " D = " + LibDestructor
383 LibDepex
= " ".join(LibraryItem
[4])
385 EdkIILibInfo
+= " Depex = " + LibDepex
387 EdkIILibInfo
+= " Time = " + LibraryItem
[5]
389 FileWrite(File
, "{%s: %s}" % (LibClass
, EdkIILibInfo
))
391 FileWrite(File
, "{%s}" % LibClass
)
393 FileWrite(File
, gSubSectionEnd
)
396 # Reports dependency expression information
398 # This class reports the module dependency expression subsection in the build report file.
400 class DepexReport(object):
402 # Constructor function for class DepexReport
404 # This constructor function generates DepexReport object for
405 # a module. If the module source contains the DXS file (usually EDK
406 # style module), it uses the dependency in DXS file; otherwise,
407 # it uses the dependency expression from its own INF [Depex] section
408 # and then merges with the ones from its dependent library INF.
410 # @param self The object pointer
411 # @param M Module context information
413 def __init__(self
, M
):
415 self
._DepexFileName
= os
.path
.join(M
.BuildDir
, "OUTPUT", M
.Module
.BaseName
+ ".depex")
416 ModuleType
= M
.ModuleType
418 ModuleType
= COMPONENT_TO_MODULE_MAP_DICT
.get(M
.ComponentType
, "")
420 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
]:
423 for Source
in M
.SourceFileList
:
424 if os
.path
.splitext(Source
.Path
)[1].lower() == ".dxs":
425 Match
= gDxsDependencyPattern
.search(open(Source
.Path
).read())
427 self
.Depex
= Match
.group(1).strip()
431 self
.Depex
= M
.DepexExpressionDict
.get(M
.ModuleType
, "")
432 self
.ModuleDepex
= " ".join(M
.Module
.DepexExpression
[M
.Arch
, M
.ModuleType
])
433 if not self
.ModuleDepex
:
434 self
.ModuleDepex
= "(None)"
437 for Lib
in M
.DependentLibraryList
:
438 LibDepex
= " ".join(Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]).strip()
440 LibDepexList
.append("(" + LibDepex
+ ")")
441 self
.LibraryDepex
= " AND ".join(LibDepexList
)
442 if not self
.LibraryDepex
:
443 self
.LibraryDepex
= "(None)"
447 # Generate report for module dependency expression information
449 # This function generates report for the module dependency expression.
451 # @param self The object pointer
452 # @param File The file object for report
453 # @param GlobalDepexParser The platform global Dependency expression parser object
455 def GenerateReport(self
, File
, GlobalDepexParser
):
458 FileWrite(File
, gSubSectionStart
)
459 if os
.path
.isfile(self
._DepexFileName
):
461 DepexStatements
= GlobalDepexParser
.ParseDepexFile(self
._DepexFileName
)
462 FileWrite(File
, "Final Dependency Expression (DEPEX) Instructions")
463 for DepexStatement
in DepexStatements
:
464 FileWrite(File
, " %s" % DepexStatement
)
465 FileWrite(File
, gSubSectionSep
)
467 EdkLogger
.warn(None, "Dependency expression file is corrupted", self
._DepexFileName
)
469 FileWrite(File
, "Dependency Expression (DEPEX) from %s" % self
.Source
)
471 if self
.Source
== "INF":
472 FileWrite(File
, self
.Depex
, True)
473 FileWrite(File
, gSubSectionSep
)
474 FileWrite(File
, "From Module INF: %s" % self
.ModuleDepex
, True)
475 FileWrite(File
, "From Library INF: %s" % self
.LibraryDepex
, True)
477 FileWrite(File
, self
.Depex
)
478 FileWrite(File
, gSubSectionEnd
)
481 # Reports dependency expression information
483 # This class reports the module build flags subsection in the build report file.
485 class BuildFlagsReport(object):
487 # Constructor function for class BuildFlagsReport
489 # This constructor function generates BuildFlagsReport object for
490 # a module. It reports the build tool chain tag and all relevant
491 # build flags to build the module.
493 # @param self The object pointer
494 # @param M Module context information
496 def __init__(self
, M
):
499 # Add build flags according to source file extension so that
500 # irrelevant ones can be filtered out.
502 for Source
in M
.SourceFileList
:
503 Ext
= os
.path
.splitext(Source
.File
)[1].lower()
504 if Ext
in [".c", ".cc", ".cpp"]:
505 BuildOptions
["CC"] = 1
506 elif Ext
in [".s", ".asm"]:
507 BuildOptions
["PP"] = 1
508 BuildOptions
["ASM"] = 1
509 elif Ext
in [".vfr"]:
510 BuildOptions
["VFRPP"] = 1
511 BuildOptions
["VFR"] = 1
512 elif Ext
in [".dxs"]:
513 BuildOptions
["APP"] = 1
514 BuildOptions
["CC"] = 1
515 elif Ext
in [".asl"]:
516 BuildOptions
["ASLPP"] = 1
517 BuildOptions
["ASL"] = 1
518 elif Ext
in [".aslc"]:
519 BuildOptions
["ASLCC"] = 1
520 BuildOptions
["ASLDLINK"] = 1
521 BuildOptions
["CC"] = 1
522 elif Ext
in [".asm16"]:
523 BuildOptions
["ASMLINK"] = 1
524 BuildOptions
["SLINK"] = 1
525 BuildOptions
["DLINK"] = 1
528 # Save module build flags.
530 self
.ToolChainTag
= M
.ToolChain
532 for Tool
in BuildOptions
:
533 self
.BuildFlags
[Tool
+ "_FLAGS"] = M
.BuildOption
.get(Tool
, {}).get("FLAGS", "")
536 # Generate report for module build flags information
538 # This function generates report for the module build flags expression.
540 # @param self The object pointer
541 # @param File The file object for report
543 def GenerateReport(self
, File
):
544 FileWrite(File
, gSubSectionStart
)
545 FileWrite(File
, "Build Flags")
546 FileWrite(File
, "Tool Chain Tag: %s" % self
.ToolChainTag
)
547 for Tool
in self
.BuildFlags
:
548 FileWrite(File
, gSubSectionSep
)
549 FileWrite(File
, "%s = %s" % (Tool
, self
.BuildFlags
[Tool
]), True)
551 FileWrite(File
, gSubSectionEnd
)
555 # Reports individual module information
557 # This class reports the module section in the build report file.
558 # It comprises of module summary, module PCD, library, dependency expression,
559 # build flags sections.
561 class ModuleReport(object):
563 # Constructor function for class ModuleReport
565 # This constructor function generates ModuleReport object for
566 # a separate module in a platform build.
568 # @param self The object pointer
569 # @param M Module context information
570 # @param ReportType The kind of report items in the final report file
572 def __init__(self
, M
, ReportType
):
573 self
.ModuleName
= M
.Module
.BaseName
574 self
.ModuleInfPath
= M
.MetaFile
.File
575 self
.FileGuid
= M
.Guid
577 self
.BuildTimeStamp
= None
581 ModuleType
= M
.ModuleType
583 ModuleType
= COMPONENT_TO_MODULE_MAP_DICT
.get(M
.ComponentType
, "")
585 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
587 if ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
588 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
589 if int(PiSpec
, 0) >= 0x0001000A:
590 ModuleType
= "SMM_DRIVER"
591 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "0x2 (FREE_FORM)")
592 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
593 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
594 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
595 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
596 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
597 self
.BuildTime
= M
.BuildTime
599 self
._BuildDir
= M
.BuildDir
600 self
.ModulePcdSet
= {}
601 if "PCD" in ReportType
:
603 # Collect all module used PCD set: module INF referenced directly or indirectly.
604 # It also saves module INF default values of them in case they exist.
606 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
607 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
609 self
.LibraryReport
= None
610 if "LIBRARY" in ReportType
:
611 self
.LibraryReport
= LibraryReport(M
)
613 self
.DepexReport
= None
614 if "DEPEX" in ReportType
:
615 self
.DepexReport
= DepexReport(M
)
617 if "BUILD_FLAGS" in ReportType
:
618 self
.BuildFlagsReport
= BuildFlagsReport(M
)
622 # Generate report for module information
624 # This function generates report for separate module expression
625 # in a platform build.
627 # @param self The object pointer
628 # @param File The file object for report
629 # @param GlobalPcdReport The platform global PCD report object
630 # @param GlobalPredictionReport The platform global Prediction report object
631 # @param GlobalDepexParser The platform global Dependency expression parser object
632 # @param ReportType The kind of report items in the final report file
634 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, GlobalDepexParser
, ReportType
):
635 FileWrite(File
, gSectionStart
)
637 FwReportFileName
= os
.path
.join(self
._BuildDir
, "DEBUG", self
.ModuleName
+ ".txt")
638 if os
.path
.isfile(FwReportFileName
):
640 FileContents
= open(FwReportFileName
).read()
641 Match
= gModuleSizePattern
.search(FileContents
)
643 self
.Size
= int(Match
.group(1))
645 Match
= gTimeStampPattern
.search(FileContents
)
647 self
.BuildTimeStamp
= datetime
.fromtimestamp(int(Match
.group(1)))
649 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
651 if "HASH" in ReportType
:
652 OutputDir
= os
.path
.join(self
._BuildDir
, "OUTPUT")
653 DefaultEFIfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ ".efi")
654 if os
.path
.isfile(DefaultEFIfile
):
655 Tempfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ "_hash.tmp")
656 # rebase the efi image since its base address may not zero
657 cmd
= ["GenFw", "--rebase", str(0), "-o", Tempfile
, DefaultEFIfile
]
659 PopenObject
= subprocess
.Popen(' '.join(cmd
), stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
660 except Exception as X
:
661 EdkLogger
.error("GenFw", COMMAND_FAILURE
, ExtraData
="%s: %s" % (str(X
), cmd
[0]))
662 EndOfProcedure
= threading
.Event()
663 EndOfProcedure
.clear()
664 if PopenObject
.stderr
:
665 StdErrThread
= threading
.Thread(target
=ReadMessage
, args
=(PopenObject
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
666 StdErrThread
.setName("STDERR-Redirector")
667 StdErrThread
.setDaemon(False)
669 # waiting for program exit
671 if PopenObject
.stderr
:
673 if PopenObject
.returncode
!= 0:
674 EdkLogger
.error("GenFw", COMMAND_FAILURE
, "Failed to generate firmware hash image for %s" % (DefaultEFIfile
))
675 if os
.path
.isfile(Tempfile
):
676 self
.Hash
= hashlib
.sha1()
677 buf
= open(Tempfile
, 'rb').read()
678 if self
.Hash
.update(buf
):
679 self
.Hash
= self
.Hash
.update(buf
)
680 self
.Hash
= self
.Hash
.hexdigest()
683 FileWrite(File
, "Module Summary")
684 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
685 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
686 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
688 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
690 FileWrite(File
, "SHA1 HASH: %s *%s" % (self
.Hash
, self
.ModuleName
+ ".efi"))
691 if self
.BuildTimeStamp
:
692 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
694 FileWrite(File
, "Module Build Time: %s" % self
.BuildTime
)
696 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
697 if self
.UefiSpecVersion
:
698 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
699 if self
.PiSpecVersion
:
700 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
702 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
704 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
705 if self
.PciClassCode
:
706 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
708 FileWrite(File
, gSectionSep
)
710 if "PCD" in ReportType
:
711 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
)
713 if "LIBRARY" in ReportType
:
714 self
.LibraryReport
.GenerateReport(File
)
716 if "DEPEX" in ReportType
:
717 self
.DepexReport
.GenerateReport(File
, GlobalDepexParser
)
719 if "BUILD_FLAGS" in ReportType
:
720 self
.BuildFlagsReport
.GenerateReport(File
)
722 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
723 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
725 FileWrite(File
, gSectionEnd
)
727 def ReadMessage(From
, To
, ExitFlag
):
729 # read one line a time
730 Line
= From
.readline()
731 # empty string means "end"
732 if Line
is not None and Line
!= "":
740 # Reports platform and module PCD information
742 # This class reports the platform PCD section and module PCD subsection
743 # in the build report file.
745 class PcdReport(object):
747 # Constructor function for class PcdReport
749 # This constructor function generates PcdReport object a platform build.
750 # It collects the whole PCD database from platform DSC files, platform
751 # flash description file and package DEC files.
753 # @param self The object pointer
754 # @param Wa Workspace context information
756 def __init__(self
, Wa
):
759 self
.ConditionalPcds
= {}
763 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
767 self
.DefaultStoreSingle
= True
768 self
.SkuSingle
= True
769 if GlobalData
.gDefaultStores
and len(GlobalData
.gDefaultStores
) > 1:
770 self
.DefaultStoreSingle
= False
771 if GlobalData
.gSkuids
and len(GlobalData
.gSkuids
) > 1:
772 self
.SkuSingle
= False
774 self
.ModulePcdOverride
= {}
775 for Pa
in Wa
.AutoGenObjectList
:
778 # Collect all platform referenced PCDs and grouped them by PCD token space
781 for Pcd
in Pa
.AllPcdList
:
782 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
783 if Pcd
not in PcdList
:
785 if len(Pcd
.TokenCName
) > self
.MaxLen
:
786 self
.MaxLen
= len(Pcd
.TokenCName
)
788 # Collect the PCD defined in DSC/FDF file, but not used in module
790 UnusedPcdFullList
= []
791 for item
in Pa
.Platform
.Pcds
:
792 Pcd
= Pa
.Platform
.Pcds
[item
]
794 # check the Pcd in FDF file, whether it is used in module first
795 for T
in PCD_TYPE_LIST
:
796 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(T
, [])
802 for package
in Pa
.PackageList
:
803 for T
in PCD_TYPE_LIST
:
804 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
) in package
.Pcds
:
807 if not Pcd
.DatumType
:
808 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
)].DatumType
812 if not Pcd
.DatumType
:
814 # Try to remove Hii and Vpd suffix
815 if PcdType
.startswith(TAB_PCDS_DYNAMIC_EX
):
816 PcdType
= TAB_PCDS_DYNAMIC_EX
817 elif PcdType
.startswith(TAB_PCDS_DYNAMIC
):
818 PcdType
= TAB_PCDS_DYNAMIC
819 for package
in Pa
.PackageList
:
820 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
) in package
.Pcds
:
821 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
)].DatumType
824 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
825 UnusedPcdList
= self
.UnusedPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
826 if Pcd
in UnusedPcdList
:
827 UnusedPcdList
.remove(Pcd
)
828 if Pcd
not in PcdList
and Pcd
not in UnusedPcdFullList
:
829 UnusedPcdFullList
.append(Pcd
)
830 if len(Pcd
.TokenCName
) > self
.MaxLen
:
831 self
.MaxLen
= len(Pcd
.TokenCName
)
833 if GlobalData
.gConditionalPcds
:
834 for PcdItem
in GlobalData
.gConditionalPcds
:
836 (TokenSpaceGuidCName
, TokenCName
) = PcdItem
.split('.')
837 if (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
838 Pcd
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)]
839 PcdList
= self
.ConditionalPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
840 if Pcd
not in PcdList
:
844 if UnusedPcdFullList
:
845 for Pcd
in UnusedPcdFullList
:
846 if Pcd
.TokenSpaceGuidCName
+ '.' + Pcd
.TokenCName
in GlobalData
.gConditionalPcds
:
848 UnusedPcdList
.append(Pcd
)
850 for Pcd
in UnusedPcdList
:
851 PcdList
= self
.UnusedPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
852 if Pcd
not in PcdList
:
855 for Module
in Pa
.Platform
.Modules
.values():
857 # Collect module override PCDs
859 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
860 TokenCName
= ModulePcd
.TokenCName
861 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
862 ModuleDefault
= ModulePcd
.DefaultValue
863 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
864 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
868 # Collect PCD DEC default value.
870 self
.DecPcdDefault
= {}
872 for Pa
in Wa
.AutoGenObjectList
:
873 for Package
in Pa
.PackageList
:
874 Guids
= Package
.Guids
875 self
._GuidDict
.update(Guids
)
876 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
877 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
878 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
880 # Collect PCDs defined in DSC common section
882 self
.DscPcdDefault
= {}
883 for Pa
in Wa
.AutoGenObjectList
:
884 for (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
885 DscDefaultValue
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DscDefaultValue
887 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
889 def GenerateReport(self
, File
, ModulePcdSet
):
891 if self
.ConditionalPcds
:
892 self
.GenerateReportDetail(File
, ModulePcdSet
, 1)
895 for Token
in self
.UnusedPcds
:
896 TokenDict
= self
.UnusedPcds
[Token
]
897 for Type
in TokenDict
:
904 self
.GenerateReportDetail(File
, ModulePcdSet
, 2)
905 self
.GenerateReportDetail(File
, ModulePcdSet
)
908 # Generate report for PCD information
910 # This function generates report for separate module expression
911 # in a platform build.
913 # @param self The object pointer
914 # @param File The file object for report
915 # @param ModulePcdSet Set of all PCDs referenced by module or None for
916 # platform PCD report
917 # @param ReportySubType 0 means platform/module PCD report, 1 means Conditional
918 # directives section report, 2 means Unused Pcds section report
919 # @param DscOverridePcds Module DSC override PCDs set
921 def GenerateReportDetail(self
, File
, ModulePcdSet
, ReportSubType
= 0):
922 PcdDict
= self
.AllPcds
923 if ReportSubType
== 1:
924 PcdDict
= self
.ConditionalPcds
925 elif ReportSubType
== 2:
926 PcdDict
= self
.UnusedPcds
929 FileWrite(File
, gSectionStart
)
930 if ReportSubType
== 1:
931 FileWrite(File
, "Conditional Directives used by the build system")
932 elif ReportSubType
== 2:
933 FileWrite(File
, "PCDs not used by modules or in conditional directives")
935 FileWrite(File
, "Platform Configuration Database Report")
937 FileWrite(File
, " *B - PCD override in the build option")
938 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
939 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
940 if not ReportSubType
:
941 FileWrite(File
, " *M - Module scoped PCD override")
942 FileWrite(File
, gSectionSep
)
944 if not ReportSubType
and ModulePcdSet
:
946 # For module PCD sub-section
948 FileWrite(File
, gSubSectionStart
)
949 FileWrite(File
, TAB_BRG_PCD
)
950 FileWrite(File
, gSubSectionSep
)
954 for Type
in PcdDict
[Key
]:
955 for Pcd
in PcdDict
[Key
][Type
]:
956 AllPcdDict
[Key
][(Pcd
.TokenCName
, Type
)] = Pcd
957 for Key
in sorted(AllPcdDict
):
959 # Group PCD by their token space GUID C Name
962 for PcdTokenCName
, Type
in sorted(AllPcdDict
[Key
]):
964 # Group PCD by their usage type
966 Pcd
= AllPcdDict
[Key
][(PcdTokenCName
, Type
)]
967 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
969 if GlobalData
.MixedPcd
:
970 for PcdKey
in GlobalData
.MixedPcd
:
971 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdKey
]:
972 PcdTokenCName
= PcdKey
[0]
974 if MixedPcdFlag
and not ModulePcdSet
:
977 # Get PCD default value and their override relationship
979 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
980 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
981 DscDefaultValBak
= DscDefaultValue
983 for (CName
, Guid
, Field
) in self
.FdfPcdSet
:
984 if CName
== PcdTokenCName
and Guid
== Key
:
985 DscDefaultValue
= self
.FdfPcdSet
[(CName
, Guid
, Field
)]
987 if DscDefaultValue
!= DscDefaultValBak
:
989 DscDefaultValue
= ValueExpressionEx(DscDefaultValue
, Pcd
.DatumType
, self
._GuidDict
)(True)
990 except BadExpression
as DscDefaultValue
:
991 EdkLogger
.error('BuildReport', FORMAT_INVALID
, "PCD Value: %s, Type: %s" %(DscDefaultValue
, Pcd
.DatumType
))
993 InfDefaultValue
= None
995 PcdValue
= DecDefaultValue
997 PcdValue
= DscDefaultValue
998 #The DefaultValue of StructurePcd already be the latest, no need to update.
999 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1000 Pcd
.DefaultValue
= PcdValue
1001 if ModulePcdSet
is not None:
1002 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
1004 InfDefaultValue
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
1005 #The DefaultValue of StructurePcd already be the latest, no need to update.
1006 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1007 Pcd
.DefaultValue
= PcdValue
1010 InfDefaultValue
= ValueExpressionEx(InfDefaultValue
, Pcd
.DatumType
, self
._GuidDict
)(True)
1011 except BadExpression
as InfDefaultValue
:
1012 EdkLogger
.error('BuildReport', FORMAT_INVALID
, "PCD Value: %s, Type: %s" % (InfDefaultValue
, Pcd
.DatumType
))
1013 if InfDefaultValue
== "":
1014 InfDefaultValue
= None
1016 BuildOptionMatch
= False
1017 if GlobalData
.BuildOptionPcd
:
1018 for pcd
in GlobalData
.BuildOptionPcd
:
1019 if (Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
) == (pcd
[0], pcd
[1]):
1023 #The DefaultValue of StructurePcd already be the latest, no need to update.
1024 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1025 Pcd
.DefaultValue
= PcdValue
1026 BuildOptionMatch
= True
1030 if ModulePcdSet
is None:
1032 FileWrite(File
, Key
)
1036 if Pcd
.DatumType
in TAB_PCD_NUMERIC_TYPES
:
1037 PcdValueNumber
= int(PcdValue
.strip(), 0)
1038 if DecDefaultValue
is None:
1041 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
1042 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
1044 if InfDefaultValue
is None:
1047 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
1048 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
1050 if DscDefaultValue
is None:
1053 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
1054 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
1056 if DecDefaultValue
is None:
1059 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
1061 if InfDefaultValue
is None:
1064 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
1066 if DscDefaultValue
is None:
1069 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
1072 if self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1074 if TypeName
in ('DYNVPD', 'DEXVPD'):
1075 SkuInfoList
= Pcd
.SkuInfoList
1076 Pcd
= GlobalData
.gStructurePcd
[self
.Arch
][(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
)]
1077 Pcd
.DatumType
= Pcd
.StructName
1078 if TypeName
in ('DYNVPD', 'DEXVPD'):
1079 Pcd
.SkuInfoList
= SkuInfoList
1080 if Pcd
.PcdValueFromComm
or Pcd
.PcdFieldValueFromComm
:
1081 BuildOptionMatch
= True
1083 elif Pcd
.PcdValueFromFdf
or Pcd
.PcdFieldValueFromFdf
:
1084 DscDefaultValue
= True
1087 elif Pcd
.SkuOverrideValues
:
1089 if Pcd
.DefaultFromDSC
:
1093 for item
in Pcd
.SkuOverrideValues
:
1094 DictLen
+= len(Pcd
.SkuOverrideValues
[item
])
1098 if not Pcd
.SkuInfoList
:
1099 OverrideValues
= Pcd
.SkuOverrideValues
1101 for Data
in OverrideValues
.values():
1102 Struct
= list(Data
.values())
1104 DscOverride
= self
.ParseStruct(Struct
[0])
1107 SkuList
= sorted(Pcd
.SkuInfoList
.keys())
1109 SkuInfo
= Pcd
.SkuInfoList
[Sku
]
1110 if TypeName
in ('DYNHII', 'DEXHII'):
1111 if SkuInfo
.DefaultStoreDict
:
1112 DefaultStoreList
= sorted(SkuInfo
.DefaultStoreDict
.keys())
1113 for DefaultStore
in DefaultStoreList
:
1114 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1115 DscOverride
= self
.ParseStruct(OverrideValues
[DefaultStore
])
1119 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1121 Keys
= list(OverrideValues
.keys())
1122 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[Keys
[0]])
1123 DscOverride
= self
.ParseStruct(OverrideFieldStruct
)
1127 DscDefaultValue
= True
1133 DscDefaultValue
= True
1138 # Report PCD item according to their override relationship
1140 if Pcd
.DatumType
== 'BOOLEAN':
1142 DscDefaultValue
= str(int(DscDefaultValue
, 0))
1144 DecDefaultValue
= str(int(DecDefaultValue
, 0))
1146 InfDefaultValue
= str(int(InfDefaultValue
, 0))
1147 if Pcd
.DefaultValue
:
1148 Pcd
.DefaultValue
= str(int(Pcd
.DefaultValue
, 0))
1150 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, ' ')
1151 elif InfDefaultValue
and InfMatch
:
1152 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*M')
1153 elif BuildOptionMatch
:
1154 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*B')
1156 if DscDefaultValue
and DscMatch
:
1157 if (Pcd
.TokenCName
, Key
, Field
) in self
.FdfPcdSet
:
1158 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*F')
1160 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*P')
1162 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*M')
1164 if ModulePcdSet
is None:
1167 if not TypeName
in ('PATCH', 'FLAG', 'FIXED'):
1169 if not BuildOptionMatch
:
1170 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
1171 for ModulePath
in ModuleOverride
:
1172 ModuleDefault
= ModuleOverride
[ModulePath
]
1173 if Pcd
.DatumType
in TAB_PCD_NUMERIC_TYPES
:
1174 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
1175 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
1176 if Pcd
.DatumType
== 'BOOLEAN':
1177 ModuleDefault
= str(ModulePcdDefaultValueNumber
)
1179 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
1182 IsByteArray
, ArrayList
= ByteArrayForamt(ModuleDefault
.strip())
1184 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 15, ModulePath
, '{'))
1185 for Array
in ArrayList
:
1186 FileWrite(File
, Array
)
1188 Value
= ModuleDefault
.strip()
1189 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1190 if Value
.startswith(('0x', '0X')):
1191 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1193 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1194 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 15, ModulePath
, Value
))
1196 if ModulePcdSet
is None:
1197 FileWrite(File
, gSectionEnd
)
1199 if not ReportSubType
and ModulePcdSet
:
1200 FileWrite(File
, gSubSectionEnd
)
1202 def ParseStruct(self
, struct
):
1203 HasDscOverride
= False
1205 for _
, Values
in struct
.items():
1206 if Values
[1] and Values
[1].endswith('.dsc'):
1207 HasDscOverride
= True
1209 return HasDscOverride
1211 def PrintPcdDefault(self
, File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
):
1212 if not DscMatch
and DscDefaultValue
is not None:
1213 Value
= DscDefaultValue
.strip()
1214 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1216 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', "{"))
1217 for Array
in ArrayList
:
1218 FileWrite(File
, Array
)
1220 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1221 if Value
.startswith(('0x', '0X')):
1222 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1224 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1225 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', Value
))
1226 if not InfMatch
and InfDefaultValue
is not None:
1227 Value
= InfDefaultValue
.strip()
1228 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1230 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', "{"))
1231 for Array
in ArrayList
:
1232 FileWrite(File
, Array
)
1234 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1235 if Value
.startswith(('0x', '0X')):
1236 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1238 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1239 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', Value
))
1241 if not DecMatch
and DecDefaultValue
is not None:
1242 Value
= DecDefaultValue
.strip()
1243 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1245 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', "{"))
1246 for Array
in ArrayList
:
1247 FileWrite(File
, Array
)
1249 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1250 if Value
.startswith(('0x', '0X')):
1251 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1253 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1254 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', Value
))
1256 self
.PrintStructureInfo(File
, Pcd
.DefaultValues
)
1257 if DecMatch
and IsStructure
:
1258 self
.PrintStructureInfo(File
, Pcd
.DefaultValues
)
1260 def PrintPcdValue(self
, File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, Flag
= ' '):
1261 if not Pcd
.SkuInfoList
:
1262 Value
= Pcd
.DefaultValue
1263 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1265 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
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 : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1276 FiledOverrideFlag
= False
1277 OverrideValues
= Pcd
.SkuOverrideValues
1279 for Data
in OverrideValues
.values():
1280 Struct
= list(Data
.values())
1282 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, Struct
[0])
1283 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1284 FiledOverrideFlag
= True
1286 if not FiledOverrideFlag
and (Pcd
.PcdFieldValueFromComm
or Pcd
.PcdFieldValueFromFdf
):
1287 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, {})
1288 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1289 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1292 SkuList
= sorted(Pcd
.SkuInfoList
.keys())
1294 SkuInfo
= Pcd
.SkuInfoList
[Sku
]
1295 SkuIdName
= SkuInfo
.SkuIdName
1296 if TypeName
in ('DYNHII', 'DEXHII'):
1297 if SkuInfo
.DefaultStoreDict
:
1298 DefaultStoreList
= sorted(SkuInfo
.DefaultStoreDict
.keys())
1299 for DefaultStore
in DefaultStoreList
:
1300 Value
= SkuInfo
.DefaultStoreDict
[DefaultStore
]
1301 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1302 if Pcd
.DatumType
== 'BOOLEAN':
1303 Value
= str(int(Value
, 0))
1307 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1308 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1309 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1310 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '{'))
1311 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1312 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', '{'))
1314 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', '{'))
1315 for Array
in ArrayList
:
1316 FileWrite(File
, Array
)
1318 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1319 if Value
.startswith(('0x', '0X')):
1320 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1322 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1323 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1324 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1325 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1326 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1327 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1328 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', Value
))
1330 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', Value
))
1333 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1334 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1335 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1336 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '{'))
1337 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1338 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', '{'))
1340 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', '{'))
1341 for Array
in ArrayList
:
1342 FileWrite(File
, Array
)
1344 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1345 if Value
.startswith(('0x', '0X')):
1346 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1348 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1349 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1350 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1351 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1352 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1353 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1354 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', Value
))
1356 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', Value
))
1357 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
1359 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1360 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[DefaultStore
])
1361 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1362 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1364 Value
= SkuInfo
.DefaultValue
1365 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1366 if Pcd
.DatumType
== 'BOOLEAN':
1367 Value
= str(int(Value
, 0))
1372 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', "{"))
1374 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', "{"))
1375 for Array
in ArrayList
:
1376 FileWrite(File
, Array
)
1378 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1379 if Value
.startswith(('0x', '0X')):
1380 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1382 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1384 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1386 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1390 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', "{"))
1392 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', "{"))
1393 for Array
in ArrayList
:
1394 FileWrite(File
, Array
)
1396 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1397 if Value
.startswith(('0x', '0X')):
1398 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1400 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1402 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1404 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1405 if TypeName
in ('DYNVPD', 'DEXVPD'):
1406 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
1407 VPDPcdItem
= (Pcd
.TokenSpaceGuidCName
+ '.' + PcdTokenCName
, SkuIdName
, SkuInfo
.VpdOffset
, Pcd
.MaxDatumSize
, SkuInfo
.DefaultValue
)
1408 if VPDPcdItem
not in VPDPcdList
:
1409 VPDPcdList
.append(VPDPcdItem
)
1411 FiledOverrideFlag
= False
1412 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1414 Keys
= OverrideValues
.keys()
1415 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[Keys
[0]])
1416 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1417 FiledOverrideFlag
= True
1418 if not FiledOverrideFlag
and (Pcd
.PcdFieldValueFromComm
or Pcd
.PcdFieldValueFromFdf
):
1419 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, {})
1420 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1421 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1423 def OverrideFieldValue(self
, Pcd
, OverrideStruct
):
1424 OverrideFieldStruct
= collections
.OrderedDict()
1426 for Key
, Values
in OverrideStruct
.items():
1427 if Values
[1] and Values
[1].endswith('.dsc'):
1428 OverrideFieldStruct
[Key
] = Values
1429 if Pcd
.PcdFieldValueFromFdf
:
1430 for Key
, Values
in Pcd
.PcdFieldValueFromFdf
.items():
1431 if Key
in OverrideFieldStruct
and Values
[0] == OverrideFieldStruct
[Key
][0]:
1433 OverrideFieldStruct
[Key
] = Values
1434 if Pcd
.PcdFieldValueFromComm
:
1435 for Key
, Values
in Pcd
.PcdFieldValueFromComm
.items():
1436 if Key
in OverrideFieldStruct
and Values
[0] == OverrideFieldStruct
[Key
][0]:
1438 OverrideFieldStruct
[Key
] = Values
1439 return OverrideFieldStruct
1441 def PrintStructureInfo(self
, File
, Struct
):
1442 for Key
, Value
in sorted(Struct
.items(), key
=lambda x
: x
[0]):
1443 if Value
[1] and 'build command options' in Value
[1]:
1444 FileWrite(File
, ' *B %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1445 elif Value
[1] and Value
[1].endswith('.fdf'):
1446 FileWrite(File
, ' *F %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1448 FileWrite(File
, ' %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1450 def StrtoHex(self
, value
):
1452 value
= hex(int(value
))
1455 if value
.startswith("L\"") and value
.endswith("\""):
1457 for ch
in value
[2:-1]:
1458 valuelist
.append(hex(ord(ch
)))
1459 valuelist
.append('0x00')
1461 elif value
.startswith("\"") and value
.endswith("\""):
1462 return hex(ord(value
[1:-1]))
1463 elif value
.startswith("{") and value
.endswith("}"):
1465 if ',' not in value
:
1467 for ch
in value
[1:-1].split(','):
1469 if ch
.startswith('0x') or ch
.startswith('0X'):
1470 valuelist
.append(ch
)
1473 valuelist
.append(hex(int(ch
.strip())))
1480 def IsStructurePcd(self
, PcdToken
, PcdTokenSpaceGuid
):
1481 if GlobalData
.gStructurePcd
and (self
.Arch
in GlobalData
.gStructurePcd
) and ((PcdToken
, PcdTokenSpaceGuid
) in GlobalData
.gStructurePcd
[self
.Arch
]):
1487 # Reports platform and module Prediction information
1489 # This class reports the platform execution order prediction section and
1490 # module load fixed address prediction subsection in the build report file.
1492 class PredictionReport(object):
1494 # Constructor function for class PredictionReport
1496 # This constructor function generates PredictionReport object for the platform.
1498 # @param self: The object pointer
1499 # @param Wa Workspace context information
1501 def __init__(self
, Wa
):
1502 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
1503 self
._MapFileParsed
= False
1504 self
._EotToolInvoked
= False
1505 self
._FvDir
= Wa
.FvDir
1506 self
._EotDir
= Wa
.BuildDir
1507 self
._FfsEntryPoint
= {}
1509 self
._SourceList
= []
1510 self
.FixedMapDict
= {}
1515 # Collect all platform reference source files and GUID C Name
1517 for Pa
in Wa
.AutoGenObjectList
:
1518 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
1520 # BASE typed modules are EFI agnostic, so we need not scan
1521 # their source code to find PPI/Protocol produce or consume
1524 if Module
.ModuleType
== SUP_MODULE_BASE
:
1527 # Add module referenced source files
1529 self
._SourceList
.append(str(Module
))
1531 for Source
in Module
.SourceFileList
:
1532 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
1533 self
._SourceList
.append(" " + str(Source
))
1534 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
1535 for IncludeFile
in IncludeList
.values():
1536 self
._SourceList
.append(" " + IncludeFile
)
1538 for Guid
in Module
.PpiList
:
1539 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
1540 for Guid
in Module
.ProtocolList
:
1541 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
1542 for Guid
in Module
.GuidList
:
1543 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
1545 if Module
.Guid
and not Module
.IsLibrary
:
1546 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
1547 if int(str(Module
.AutoGenVersion
), 0) >= 0x00010005:
1548 RealEntryPoint
= "_ModuleEntryPoint"
1550 RealEntryPoint
= EntryPoint
1551 if EntryPoint
== "_ModuleEntryPoint":
1552 CCFlags
= Module
.BuildOption
.get("CC", {}).get("FLAGS", "")
1553 Match
= gGlueLibEntryPoint
.search(CCFlags
)
1555 EntryPoint
= Match
.group(1)
1557 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
1561 # Collect platform firmware volume list as the input of EOT.
1565 for Fd
in Wa
.FdfProfile
.FdDict
:
1566 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
1567 if FdRegion
.RegionType
!= BINARY_FILE_TYPE_FV
:
1569 for FvName
in FdRegion
.RegionDataList
:
1570 if FvName
in self
._FvList
:
1572 self
._FvList
.append(FvName
)
1573 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1574 for Section
in Ffs
.SectionList
:
1576 for FvSection
in Section
.SectionList
:
1577 if FvSection
.FvName
in self
._FvList
:
1579 self
._FvList
.append(FvSection
.FvName
)
1580 except AttributeError:
1585 # Parse platform fixed address map files
1587 # This function parses the platform final fixed address map file to get
1588 # the database of predicted fixed address for module image base, entry point
1591 # @param self: The object pointer
1593 def _ParseMapFile(self
):
1594 if self
._MapFileParsed
:
1596 self
._MapFileParsed
= True
1597 if os
.path
.isfile(self
._MapFileName
):
1599 FileContents
= open(self
._MapFileName
).read()
1600 for Match
in gMapFileItemPattern
.finditer(FileContents
):
1601 AddressType
= Match
.group(1)
1602 BaseAddress
= Match
.group(2)
1603 EntryPoint
= Match
.group(3)
1604 Guid
= Match
.group(4).upper()
1605 List
= self
.FixedMapDict
.setdefault(Guid
, [])
1606 List
.append((AddressType
, BaseAddress
, "*I"))
1607 List
.append((AddressType
, EntryPoint
, "*E"))
1609 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
1612 # Invokes EOT tool to get the predicted the execution order.
1614 # This function invokes EOT tool to calculate the predicted dispatch order
1616 # @param self: The object pointer
1618 def _InvokeEotTool(self
):
1619 if self
._EotToolInvoked
:
1622 self
._EotToolInvoked
= True
1624 for FvName
in self
._FvList
:
1625 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
1626 if os
.path
.isfile(FvFile
):
1627 FvFileList
.append(FvFile
)
1629 if len(FvFileList
) == 0:
1632 # Write source file list and GUID file list to an intermediate file
1633 # as the input for EOT tool and dispatch List as the output file
1636 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
1637 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
1638 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
1640 TempFile
= open(SourceList
, "w+")
1641 for Item
in self
._SourceList
:
1642 FileWrite(TempFile
, Item
)
1644 TempFile
= open(GuidList
, "w+")
1645 for Key
in self
._GuidMap
:
1646 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
1650 from Eot
.EotMain
import Eot
1653 # Invoke EOT tool and echo its runtime performance
1655 EotStartTime
= time
.time()
1656 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
1657 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
1658 EotEndTime
= time
.time()
1659 EotDuration
= time
.strftime("%H:%M:%S", time
.gmtime(int(round(EotEndTime
- EotStartTime
))))
1660 EdkLogger
.quiet("EOT run time: %s\n" % EotDuration
)
1663 # Parse the output of EOT tool
1665 for Line
in open(DispatchList
):
1666 if len(Line
.split()) < 4:
1668 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
1669 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
1670 if len(Symbol
) > self
.MaxLen
:
1671 self
.MaxLen
= len(Symbol
)
1672 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
1674 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1675 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1679 # Generate platform execution order report
1681 # This function generates the predicted module execution order.
1683 # @param self The object pointer
1684 # @param File The file object for report
1686 def _GenerateExecutionOrderReport(self
, File
):
1687 self
._InvokeEotTool
()
1688 if len(self
.ItemList
) == 0:
1690 FileWrite(File
, gSectionStart
)
1691 FileWrite(File
, "Execution Order Prediction")
1692 FileWrite(File
, "*P PEI phase")
1693 FileWrite(File
, "*D DXE phase")
1694 FileWrite(File
, "*E Module INF entry point name")
1695 FileWrite(File
, "*N Module notification function name")
1697 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
1698 FileWrite(File
, gSectionSep
)
1699 for Item
in self
.ItemList
:
1700 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
1702 FileWrite(File
, gSectionStart
)
1705 # Generate Fixed Address report.
1707 # This function generate the predicted fixed address report for a module
1708 # specified by Guid.
1710 # @param self The object pointer
1711 # @param File The file object for report
1712 # @param Guid The module Guid value.
1713 # @param NotifyList The list of all notify function in a module
1715 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
1716 self
._ParseMapFile
()
1717 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
1718 if not FixedAddressList
:
1721 FileWrite(File
, gSubSectionStart
)
1722 FileWrite(File
, "Fixed Address Prediction")
1723 FileWrite(File
, "*I Image Loading Address")
1724 FileWrite(File
, "*E Entry Point Address")
1725 FileWrite(File
, "*N Notification Function Address")
1726 FileWrite(File
, "*F Flash Address")
1727 FileWrite(File
, "*M Memory Address")
1728 FileWrite(File
, "*S SMM RAM Offset")
1729 FileWrite(File
, "TOM Top of Memory")
1731 FileWrite(File
, "Type Address Name")
1732 FileWrite(File
, gSubSectionSep
)
1733 for Item
in FixedAddressList
:
1738 Name
= "(Image Base)"
1739 elif Symbol
== "*E":
1740 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
1741 elif Symbol
in NotifyList
:
1749 elif "Memory" in Type
:
1755 Value
= "TOM" + Value
1757 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
1760 # Generate report for the prediction part
1762 # This function generate the predicted fixed address report for a module or
1763 # predicted module execution order for a platform.
1764 # If the input Guid is None, then, it generates the predicted module execution order;
1765 # otherwise it generated the module fixed loading address for the module specified by
1768 # @param self The object pointer
1769 # @param File The file object for report
1770 # @param Guid The module Guid value.
1772 def GenerateReport(self
, File
, Guid
):
1774 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1776 self
._GenerateExecutionOrderReport
(File
)
1779 # Reports FD region information
1781 # This class reports the FD subsection in the build report file.
1782 # It collects region information of platform flash device.
1783 # If the region is a firmware volume, it lists the set of modules
1784 # and its space information; otherwise, it only lists its region name,
1785 # base address and size in its sub-section header.
1786 # If there are nesting FVs, the nested FVs will list immediate after
1787 # this FD region subsection
1789 class FdRegionReport(object):
1791 # Discover all the nested FV name list.
1793 # This is an internal worker function to discover the all the nested FV information
1794 # in the parent firmware volume. It uses deep first search algorithm recursively to
1795 # find all the FV list name and append them to the list.
1797 # @param self The object pointer
1798 # @param FvName The name of current firmware file system
1799 # @param Wa Workspace context information
1801 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1802 FvDictKey
=FvName
.upper()
1803 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1804 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1805 for Section
in Ffs
.SectionList
:
1807 for FvSection
in Section
.SectionList
:
1808 if FvSection
.FvName
in self
.FvList
:
1810 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1811 self
.FvList
.append(FvSection
.FvName
)
1812 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1813 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1814 except AttributeError:
1818 # Constructor function for class FdRegionReport
1820 # This constructor function generates FdRegionReport object for a specified FdRegion.
1821 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1822 # volume list. This function also collects GUID map in order to dump module identification
1823 # in the final report.
1825 # @param self: The object pointer
1826 # @param FdRegion The current FdRegion object
1827 # @param Wa Workspace context information
1829 def __init__(self
, FdRegion
, Wa
):
1830 self
.Type
= FdRegion
.RegionType
1831 self
.BaseAddress
= FdRegion
.Offset
1832 self
.Size
= FdRegion
.Size
1836 self
._FvDir
= Wa
.FvDir
1837 self
._WorkspaceDir
= Wa
.WorkspaceDir
1840 # If the input FdRegion is not a firmware volume,
1843 if self
.Type
!= BINARY_FILE_TYPE_FV
:
1847 # Find all nested FVs in the FdRegion
1849 for FvName
in FdRegion
.RegionDataList
:
1850 if FvName
in self
.FvList
:
1852 self
.FvList
.append(FvName
)
1853 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1854 self
._DiscoverNestedFvList
(FvName
, Wa
)
1858 # Collect PCDs declared in DEC files.
1860 for Pa
in Wa
.AutoGenObjectList
:
1861 for Package
in Pa
.PackageList
:
1862 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1863 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1864 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1866 # Collect PCDs defined in DSC file
1868 for Pa
in Wa
.AutoGenObjectList
:
1869 for (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
1870 DscDefaultValue
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1871 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1874 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1876 self
._GuidsDb
["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"
1877 self
._GuidsDb
["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"
1879 # Add ACPI table storage file
1881 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1883 for Pa
in Wa
.AutoGenObjectList
:
1884 for ModuleKey
in Pa
.Platform
.Modules
:
1885 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1886 InfPath
= mws
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1887 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1890 # Collect the GUID map in the FV firmware volume
1892 for FvName
in self
.FvList
:
1893 FvDictKey
=FvName
.upper()
1894 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1895 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1898 # collect GUID map for binary EFI file in FDF file.
1900 Guid
= Ffs
.NameGuid
.upper()
1901 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1903 PcdTokenspace
= Match
.group(1)
1904 PcdToken
= Match
.group(2)
1905 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1906 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1907 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1908 for Section
in Ffs
.SectionList
:
1910 ModuleSectFile
= mws
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1911 self
._GuidsDb
[Guid
] = ModuleSectFile
1912 except AttributeError:
1914 except AttributeError:
1919 # Internal worker function to generate report for the FD region
1921 # This internal worker function to generate report for the FD region.
1922 # It the type is firmware volume, it lists offset and module identification.
1924 # @param self The object pointer
1925 # @param File The file object for report
1926 # @param Title The title for the FD subsection
1927 # @param BaseAddress The base address for the FD region
1928 # @param Size The size of the FD region
1929 # @param FvName The FV name if the FD region is a firmware volume
1931 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1932 FileWrite(File
, gSubSectionStart
)
1933 FileWrite(File
, Title
)
1934 FileWrite(File
, "Type: %s" % Type
)
1935 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1937 if self
.Type
== BINARY_FILE_TYPE_FV
:
1941 if FvName
.upper().endswith('.FV'):
1942 FileExt
= FvName
+ ".txt"
1944 FileExt
= FvName
+ ".Fv.txt"
1946 if not os
.path
.isfile(FileExt
):
1947 FvReportFileName
= mws
.join(self
._WorkspaceDir
, FileExt
)
1948 if not os
.path
.isfile(FvReportFileName
):
1949 FvReportFileName
= os
.path
.join(self
._FvDir
, FileExt
)
1952 # Collect size info in the firmware volume.
1954 FvReport
= open(FvReportFileName
).read()
1955 Match
= gFvTotalSizePattern
.search(FvReport
)
1957 FvTotalSize
= int(Match
.group(1), 16)
1958 Match
= gFvTakenSizePattern
.search(FvReport
)
1960 FvTakenSize
= int(Match
.group(1), 16)
1961 FvFreeSize
= FvTotalSize
- FvTakenSize
1963 # Write size information to the report file.
1965 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1966 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1967 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1968 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1969 FileWrite(File
, "Offset Module")
1970 FileWrite(File
, gSubSectionSep
)
1972 # Write module offset and module identification to the report file.
1975 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1976 Guid
= Match
.group(2).upper()
1977 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1978 OffsetList
= sorted(OffsetInfo
.keys())
1979 for Offset
in OffsetList
:
1980 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1982 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
1984 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
1985 FileWrite(File
, gSubSectionEnd
)
1988 # Generate report for the FD region
1990 # This function generates report for the FD region.
1992 # @param self The object pointer
1993 # @param File The file object for report
1995 def GenerateReport(self
, File
):
1996 if (len(self
.FvList
) > 0):
1997 for FvItem
in self
.FvList
:
1998 Info
= self
.FvInfo
[FvItem
]
1999 self
._GenerateReport
(File
, Info
[0], TAB_FV_DIRECTORY
, Info
[1], Info
[2], FvItem
)
2001 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
2004 # Reports FD information
2006 # This class reports the FD section in the build report file.
2007 # It collects flash device information for a platform.
2009 class FdReport(object):
2011 # Constructor function for class FdReport
2013 # This constructor function generates FdReport object for a specified
2016 # @param self The object pointer
2017 # @param Fd The current Firmware device object
2018 # @param Wa Workspace context information
2020 def __init__(self
, Fd
, Wa
):
2021 self
.FdName
= Fd
.FdUiName
2022 self
.BaseAddress
= Fd
.BaseAddress
2024 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
2025 self
.FvPath
= os
.path
.join(Wa
.BuildDir
, TAB_FV_DIRECTORY
)
2026 self
.VPDBaseAddress
= 0
2028 for index
, FdRegion
in enumerate(Fd
.RegionList
):
2029 if str(FdRegion
.RegionType
) is 'FILE' and Wa
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
2030 self
.VPDBaseAddress
= self
.FdRegionList
[index
].BaseAddress
2031 self
.VPDSize
= self
.FdRegionList
[index
].Size
2035 # Generate report for the firmware device.
2037 # This function generates report for the firmware device.
2039 # @param self The object pointer
2040 # @param File The file object for report
2042 def GenerateReport(self
, File
):
2043 FileWrite(File
, gSectionStart
)
2044 FileWrite(File
, "Firmware Device (FD)")
2045 FileWrite(File
, "FD Name: %s" % self
.FdName
)
2046 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
2047 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
2048 if len(self
.FdRegionList
) > 0:
2049 FileWrite(File
, gSectionSep
)
2050 for FdRegionItem
in self
.FdRegionList
:
2051 FdRegionItem
.GenerateReport(File
)
2054 VPDPcdList
.sort(key
=lambda x
: int(x
[2], 0))
2055 FileWrite(File
, gSubSectionStart
)
2056 FileWrite(File
, "FD VPD Region")
2057 FileWrite(File
, "Base Address: 0x%X" % self
.VPDBaseAddress
)
2058 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.VPDSize
, self
.VPDSize
/ 1024.0))
2059 FileWrite(File
, gSubSectionSep
)
2060 for item
in VPDPcdList
:
2061 # Add BaseAddress for offset
2062 Offset
= '0x%08X' % (int(item
[2], 16) + self
.VPDBaseAddress
)
2063 IsByteArray
, ArrayList
= ByteArrayForamt(item
[-1])
2065 if len(GlobalData
.gSkuids
) == 1 :
2066 Skuinfo
= GlobalData
.gSkuids
[0]
2068 FileWrite(File
, "%s | %s | %s | %s | %s" % (item
[0], Skuinfo
, Offset
, item
[3], '{'))
2069 for Array
in ArrayList
:
2070 FileWrite(File
, Array
)
2072 FileWrite(File
, "%s | %s | %s | %s | %s" % (item
[0], Skuinfo
, Offset
, item
[3], item
[-1]))
2073 FileWrite(File
, gSubSectionEnd
)
2074 FileWrite(File
, gSectionEnd
)
2079 # Reports platform information
2081 # This class reports the whole platform information
2083 class PlatformReport(object):
2085 # Constructor function for class PlatformReport
2087 # This constructor function generates PlatformReport object a platform build.
2088 # It generates report for platform summary, flash, global PCDs and detailed
2089 # module information for modules involved in platform build.
2091 # @param self The object pointer
2092 # @param Wa Workspace context information
2093 # @param MaList The list of modules in the platform build
2095 def __init__(self
, Wa
, MaList
, ReportType
):
2096 self
._WorkspaceDir
= Wa
.WorkspaceDir
2097 self
.PlatformName
= Wa
.Name
2098 self
.PlatformDscPath
= Wa
.Platform
2099 self
.Architectures
= " ".join(Wa
.ArchList
)
2100 self
.ToolChain
= Wa
.ToolChain
2101 self
.Target
= Wa
.BuildTarget
2102 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
2103 self
.BuildEnvironment
= platform
.platform()
2105 self
.PcdReport
= None
2106 if "PCD" in ReportType
:
2107 self
.PcdReport
= PcdReport(Wa
)
2109 self
.FdReportList
= []
2110 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
is None:
2111 for Fd
in Wa
.FdfProfile
.FdDict
:
2112 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
2114 self
.PredictionReport
= None
2115 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
2116 self
.PredictionReport
= PredictionReport(Wa
)
2118 self
.DepexParser
= None
2119 if "DEPEX" in ReportType
:
2120 self
.DepexParser
= DepexParser(Wa
)
2122 self
.ModuleReportList
= []
2123 if MaList
is not None:
2124 self
._IsModuleBuild
= True
2126 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
2128 self
._IsModuleBuild
= False
2129 for Pa
in Wa
.AutoGenObjectList
:
2130 ModuleAutoGenList
= []
2131 for ModuleKey
in Pa
.Platform
.Modules
:
2132 ModuleAutoGenList
.append(Pa
.Platform
.Modules
[ModuleKey
].M
)
2133 if GlobalData
.gFdfParser
is not None:
2134 if Pa
.Arch
in GlobalData
.gFdfParser
.Profile
.InfDict
:
2135 INFList
= GlobalData
.gFdfParser
.Profile
.InfDict
[Pa
.Arch
]
2136 for InfName
in INFList
:
2137 InfClass
= PathClass(NormPath(InfName
), Wa
.WorkspaceDir
, Pa
.Arch
)
2138 Ma
= ModuleAutoGen(Wa
, InfClass
, Pa
.BuildTarget
, Pa
.ToolChain
, Pa
.Arch
, Wa
.MetaFile
)
2141 if Ma
not in ModuleAutoGenList
:
2142 ModuleAutoGenList
.append(Ma
)
2143 for MGen
in ModuleAutoGenList
:
2144 self
.ModuleReportList
.append(ModuleReport(MGen
, ReportType
))
2149 # Generate report for the whole platform.
2151 # This function generates report for platform information.
2152 # It comprises of platform summary, global PCD, flash and
2153 # module list sections.
2155 # @param self The object pointer
2156 # @param File The file object for report
2157 # @param BuildDuration The total time to build the modules
2158 # @param AutoGenTime The total time of AutoGen Phase
2159 # @param MakeTime The total time of Make Phase
2160 # @param GenFdsTime The total time of GenFds Phase
2161 # @param ReportType The kind of report items in the final report file
2163 def GenerateReport(self
, File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, ReportType
):
2164 FileWrite(File
, "Platform Summary")
2165 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
2166 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
2167 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
2168 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
2169 FileWrite(File
, "Target: %s" % self
.Target
)
2170 if GlobalData
.gSkuids
:
2171 FileWrite(File
, "SKUID: %s" % " ".join(GlobalData
.gSkuids
))
2172 if GlobalData
.gDefaultStores
:
2173 FileWrite(File
, "DefaultStore: %s" % " ".join(GlobalData
.gDefaultStores
))
2174 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
2175 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
2176 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
2178 FileWrite(File
, "AutoGen Duration: %s" % AutoGenTime
)
2180 FileWrite(File
, "Make Duration: %s" % MakeTime
)
2182 FileWrite(File
, "GenFds Duration: %s" % GenFdsTime
)
2183 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
2185 if GlobalData
.MixedPcd
:
2186 FileWrite(File
, gSectionStart
)
2187 FileWrite(File
, "The following PCDs use different access methods:")
2188 FileWrite(File
, gSectionSep
)
2189 for PcdItem
in GlobalData
.MixedPcd
:
2190 FileWrite(File
, "%s.%s" % (str(PcdItem
[1]), str(PcdItem
[0])))
2191 FileWrite(File
, gSectionEnd
)
2193 if not self
._IsModuleBuild
:
2194 if "PCD" in ReportType
:
2195 self
.PcdReport
.GenerateReport(File
, None)
2197 if "FLASH" in ReportType
:
2198 for FdReportListItem
in self
.FdReportList
:
2199 FdReportListItem
.GenerateReport(File
)
2201 for ModuleReportItem
in self
.ModuleReportList
:
2202 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, self
.DepexParser
, ReportType
)
2204 if not self
._IsModuleBuild
:
2205 if "EXECUTION_ORDER" in ReportType
:
2206 self
.PredictionReport
.GenerateReport(File
, None)
2208 ## BuildReport class
2210 # This base class contain the routines to collect data and then
2211 # applies certain format to the output report
2213 class BuildReport(object):
2215 # Constructor function for class BuildReport
2217 # This constructor function generates BuildReport object a platform build.
2218 # It generates report for platform summary, flash, global PCDs and detailed
2219 # module information for modules involved in platform build.
2221 # @param self The object pointer
2222 # @param ReportFile The file name to save report file
2223 # @param ReportType The kind of report items in the final report file
2225 def __init__(self
, ReportFile
, ReportType
):
2226 self
.ReportFile
= ReportFile
2228 self
.ReportList
= []
2229 self
.ReportType
= []
2231 for ReportTypeItem
in ReportType
:
2232 if ReportTypeItem
not in self
.ReportType
:
2233 self
.ReportType
.append(ReportTypeItem
)
2235 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]
2237 # Adds platform report to the list
2239 # This function adds a platform report to the final report list.
2241 # @param self The object pointer
2242 # @param Wa Workspace context information
2243 # @param MaList The list of modules in the platform build
2245 def AddPlatformReport(self
, Wa
, MaList
=None):
2247 self
.ReportList
.append((Wa
, MaList
))
2250 # Generates the final report.
2252 # This function generates platform build report. It invokes GenerateReport()
2253 # method for every platform report in the list.
2255 # @param self The object pointer
2256 # @param BuildDuration The total time to build the modules
2257 # @param AutoGenTime The total time of AutoGen phase
2258 # @param MakeTime The total time of Make phase
2259 # @param GenFdsTime The total time of GenFds phase
2261 def GenerateReport(self
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
):
2265 for (Wa
, MaList
) in self
.ReportList
:
2266 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, self
.ReportType
)
2267 Content
= FileLinesSplit(File
.getvalue(), gLineMaxLength
)
2268 SaveFileOnChange(self
.ReportFile
, Content
, True)
2269 EdkLogger
.quiet("Build report can be found at %s" % os
.path
.abspath(self
.ReportFile
))
2271 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
2273 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
2274 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
2277 # This acts like the main() function for the script, unless it is 'import'ed into another script.
2278 if __name__
== '__main__':