Add part of build report generation features: PCD, Library, DEPEX, etc. (The build...
[efi/basetools/.git] / Source / Python / build / BuildReport.py
1 ## @file
2 # Routines for generating build report.
3
4 # This module contains the functionality to generate build report after
5 # build all target completes successfully. 
6 #
7 # Copyright (c) 2010, Intel Corporation
8 # All rights reserved. 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
12 #
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.
15 #
16
17 ## Import Modules
18 #
19 import os
20 import re
21 import platform
22 import textwrap
23 from Common import EdkLogger
24 from Common.BuildToolError import FILE_OPEN_FAILURE
25 from Common.BuildToolError import FILE_WRITE_FAILURE
26
27
28 ## Pattern to extract contents in EDK DXS files
29 gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)
30
31 ## Pattern to find total FV total size, occupied size in flash report intermediate file
32 gFvTotalSizePattern = re.compile(r"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
33 gFvTakenSizePattern = re.compile(r"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
34
35 ## Pattern to find GUID value in flash description files
36 gPcdGuidPattern = re.compile(r"PCD\((\w+)[.](\w+)\)")
37
38 ## Pattern to collect offset, GUID value pair in the flash report intermediate file 
39 gOffsetGuidPattern = re.compile(r"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
40
41 ## Tags for section start, end and separator
42 gSectionStart = ">" + "=" * 118 + "<"
43 gSectionEnd = "<" + "=" * 118 + ">" + "\n"
44 gSectionSep = "=" * 120
45
46 ## Tags for subsection start, end and separator
47 gSubSectionStart = ">" + "-" * 118 + "<"
48 gSubSectionEnd = "<" + "-" * 118 + ">"
49 gSubSectionSep = "-" * 120
50
51 ## The look up table to map PCD type to pair of report display type and DEC type
52 gPcdTypeMap = {
53   'FixedAtBuild'     : ('FIXED',  'FixedAtBuild'),
54   'PatchableInModule': ('PATCH',  'PatchableInModule'),
55   'FeatureFlag'      : ('FLAG',   'FeatureFlag'),
56   'Dynamic'          : ('DYN',    'Dynamic'),
57   'DynamicHii'       : ('DYNHII', 'Dynamic'),
58   'DynamicVpd'       : ('DYNVPD', 'Dynamic'),
59   'DynamicEx'        : ('DEX',    'Dynamic'),
60   'DynamicExHii'     : ('DEXHII', 'Dynamic'),
61   'DynamicExVpd'     : ('DEXVPD', 'Dynamic'),
62   }
63
64 ##
65 # Writes a string to the file object.
66
67 # This function writes a string to the file object and a new line is appended 
68 # afterwards. It may optionally wraps the string for better readability.   
69 #
70 # @File                      The file object to write
71 # @String                    The string to be written to the file
72 # @Wrapper                   Indicates whether to wrap the string
73 #
74 def FileWrite(File, String, Wrapper=False):
75     if Wrapper:
76         String = textwrap.fill(String, 120)
77     File.write(String + "\n")
78
79
80 ##
81 # Reports library information
82 #
83 # This class reports the module library subsection in the build report file.
84 #     
85 class LibraryReport(object):
86     ##
87     # Constructor function for class LibraryReport
88     #
89     # This constructor function generates LibraryReport object for 
90     # a module.
91     #
92     # @param self            The object pointer
93     # @param M               Module context information
94     #
95     def __init__(self, M):
96         self.LibraryList = []
97         if int(str(M.AutoGenVersion), 0) >= 0x00010005:
98             self._EdkIIModule = True
99         else:
100             self._EdkIIModule = False
101                
102         for Lib in M.DependentLibraryList:
103             LibInfPath = str(Lib)
104             LibClassList = Lib.LibraryClass[0].LibraryClass
105             LibConstructorList = Lib.ConstructorList
106             LibDesstructorList = Lib.DestructorList
107             LibDepexList = Lib.DepexExpression[M.Arch, M.ModuleType]
108             self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList))
109     
110     ##
111     # Generate report for module library information
112     #
113     # This function generates report for the module library.
114     # If the module is EDKII style one, the additional library class, library
115     # constructor/destructor and dependency expression may also be reported.  
116     #
117     # @param self            The object pointer
118     # @param File            The file object for report
119     #
120     def GenerateReport(self, File):
121         FileWrite(File, gSubSectionStart)
122         FileWrite(File, "Library")
123         if len(self.LibraryList) > 0:
124             FileWrite(File, gSubSectionSep)
125             for LibraryItem in self.LibraryList:
126                 LibInfPath = LibraryItem[0]
127                 FileWrite(File, LibInfPath)
128                 
129                 #
130                 # Report library class, library constructor and destructor for
131                 # EDKII style module.
132                 #
133                 if self._EdkIIModule:
134                     LibClass = LibraryItem[1]
135                     EdkIILibInfo = ""
136                     LibConstructor = " ".join(LibraryItem[2])
137                     if LibConstructor:
138                         EdkIILibInfo += " C = " + LibConstructor
139                     LibDestructor = " ".join(LibraryItem[3])
140                     if LibDestructor:
141                         EdkIILibInfo += " D = " + LibConstructor
142                     LibDepex = " ".join(LibraryItem[3])
143                     if LibDepex:
144                         EdkIILibInfo += " Depex = " + LibDepex
145                     if EdkIILibInfo:
146                         FileWrite(File, "{%s: %s}" % (LibClass, EdkIILibInfo))
147                     else:
148                         FileWrite(File, "{%s}" % LibClass)
149         
150         FileWrite(File, gSubSectionEnd)
151
152 ##
153 # Reports dependency expression information
154 #
155 # This class reports the module dependency expression subsection in the build report file.
156 #             
157 class DepexReport(object):
158     ##
159     # Constructor function for class DepexReport
160     #
161     # This constructor function generates DepexReport object for 
162     # a module. If the module source contains the DXS file (usually EDK
163     # style module), it uses the dependency in DXS file; otherwise,
164     # it uses the dependency expression from its own INF [Depex] section
165     # and then merges with the ones from its dependent library INF.
166     #
167     # @param self            The object pointer
168     # @param M               Module context information
169     #
170     def __init__(self, M):
171         for Source in M.SourceFileList:
172             if os.path.splitext(Source.Path)[1].lower() == ".dxs":
173                 Match = gDxsDependencyPattern.search(open(Source.Path).read())
174                 if Match:
175                     self.Depex = Match.group(1).strip()
176                     self.Source = "DXS"
177                     break
178         else:
179             self.Depex = M.DepexExpressionList[M.ModuleType]
180             self.ModuleDepex = " ".join(M.Module.DepexExpression[M.Arch, M.ModuleType])
181             if not self.ModuleDepex:
182                 self.ModuleDepex = "TRUE"
183             
184             LibDepexList = []
185             for Lib in M.DependentLibraryList:
186                 LibDepex = " ".join(Lib.DepexExpression[M.Arch, M.ModuleType]).strip()
187                 if LibDepex != "":                         
188                     if " " in LibDepex:
189                         LibDepex = "(" + LibDepex + ")"
190                     LibDepexList.append(LibDepex)
191             self.LibraryDepex = " AND ".join(LibDepexList)
192             if not self.LibraryDepex:
193                 self.LibraryDepex = "(None)"
194             self.Source = "INF"
195     
196     ##
197     # Generate report for module dependency expression information
198     #
199     # This function generates report for the module dependency expression.
200     #
201     # @param self            The object pointer
202     # @param File            The file object for report
203     #
204     def GenerateReport(self, File):
205         FileWrite(File, gSubSectionStart)
206         FileWrite(File, "Dependency Expression (DEPEX) from %s" % self.Source)
207         
208         if self.Source == "INF":
209             FileWrite(File, "%s" % self.Depex, True)
210             FileWrite(File, gSubSectionSep)
211             FileWrite(File, "From Module INF:  %s" % self.ModuleDepex, True)
212             FileWrite(File, "From Library INF: %s" % self.LibraryDepex, True)
213         else:
214             FileWrite(File, "%s" % self.Depex)
215         FileWrite(File, gSubSectionEnd)
216
217 ##
218 # Reports dependency expression information
219 #
220 # This class reports the module build flags subsection in the build report file.
221 #                     
222 class BuildFlagsReport(object):
223     ##
224     # Constructor function for class BuildFlagsReport
225     #
226     # This constructor function generates BuildFlagsReport object for 
227     # a module. It reports the build tool chain tag and all relevant 
228     # build flags to build the module.
229     #
230     # @param self            The object pointer
231     # @param M               Module context information
232     #
233     def __init__(self, M):
234         BuildOptions = {}
235         #
236         # Add build flags according to source file extension so that
237         # irrelevant ones can be filtered out. 
238         #
239         for Source in M.SourceFileList:
240             Ext = os.path.splitext(Source.File)[1].lower()
241             if Ext in [".c", ".cc", ".cpp"]:
242                 BuildOptions["CC"] = 1
243             elif Ext in [".s", ".asm"]:
244                 BuildOptions["PP"] = 1
245                 BuildOptions["ASM"] = 1
246             elif Ext in [".vfr"]:
247                 BuildOptions["VFRPP"] = 1
248                 BuildOptions["VFR"] = 1
249             elif Ext in [".dxs"]:
250                 BuildOptions["APP"] = 1
251                 BuildOptions["CC"] = 1
252             elif Ext in [".asl"]:
253                 BuildOptions["ASLPP"] = 1
254                 BuildOptions["ASL"] = 1
255             elif Ext in [".aslc"]:
256                 BuildOptions["ASLCC"] = 1
257                 BuildOptions["ASLDLINK"] = 1
258                 BuildOptions["CC"] = 1
259             elif Ext in [".asm16"]:
260                 BuildOptions["ASMLINK"] = 1
261             BuildOptions["SLINK"] = 1
262             BuildOptions["DLINK"] = 1
263         
264         #
265         # Save module build flags.
266         #
267         self.ToolChainTag = M.ToolChain
268         self.BuildFlags = {}
269         for Tool in BuildOptions:
270             self.BuildFlags[Tool + "_FLAGS"] = M.BuildOption.get(Tool, {}).get("FLAGS", "")
271
272     ##
273     # Generate report for module build flags information
274     #
275     # This function generates report for the module build flags expression.
276     #
277     # @param self            The object pointer
278     # @param File            The file object for report
279     #
280     def GenerateReport(self, File):
281         FileWrite(File, gSubSectionStart)
282         FileWrite(File, "Build Flags")
283         FileWrite(File, "Tool Chain Tag: %s" % self.ToolChainTag)
284         for Tool in self.BuildFlags:
285             FileWrite(File, gSubSectionSep)
286             FileWrite(File, "%s = %s" % (Tool, self.BuildFlags[Tool]), True)
287         
288         FileWrite(File, gSubSectionEnd)
289                        
290 ##
291 # Reports individual module information
292 #
293 # This class reports the module section in the build report file. 
294 # It comprises of module summary, module PCD, library, dependency expression,
295 # build flags sections.  
296 #        
297 class ModuleReport(object):
298     ##
299     # Constructor function for class ModuleReport
300     #
301     # This constructor function generates ModuleReport object for 
302     # a separate module in a platform build.  
303     #
304     # @param self            The object pointer
305     # @param M               Module context information
306     # @param DscOverridePcds Module DSC override PCD information
307     # @param ReportType      The kind of report items in the final report file
308     #
309     def __init__(self, M, DscOverridePcds, ReportType):
310         self.ModuleName = M.Module.BaseName
311         self.ModuleInfPath = M.MetaFile.File
312         self.FileGuid = M.Guid
313         self.Size = 0
314         self.BuildTimeStamp = ""
315         self.DriverType = ""
316         self.UefiSpecVersion = M.Module.Specification.get("UEFI_SPECIFICATION_VERSION", "")
317         self.PiSpecVersion = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "")
318         self.PciDeviceId = M.Module.Defines.get("PCI_DEVICE_ID", "")
319         self.PciVendorId = M.Module.Defines.get("PCI_VENDOR_ID", "")
320         self.PciClassCode = M.Module.Defines.get("PCI_CLASS_CODE", "")
321   
322         self.ModulePcdSet = {}
323         self.ModuleDscOverridePcds = {}
324         if "PCD" in ReportType:
325             #
326             # Collect all module used PCD set: module INF referenced directly or indirectly.
327             # It also saves module INF default values of them in case they exist.
328             #
329             for Pcd in M.ModulePcdList + M.LibraryPcdList:
330                 self.ModulePcdSet.setdefault((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Type), Pcd.InfDefaultValue)
331             
332             #
333             # Collect module DSC override PCD set for report
334             #
335             for (PcdTokenCName, PcdTokenSpaceGuidCName) in DscOverridePcds:
336                 Pcd = DscOverridePcds[(PcdTokenCName, PcdTokenSpaceGuidCName)]
337                 self.ModuleDscOverridePcds.setdefault((PcdTokenCName, PcdTokenSpaceGuidCName), Pcd.DefaultValue)
338         
339         self.LibraryReport = None
340         if "LIBRARY" in ReportType:
341             self.LibraryReport = LibraryReport(M)
342         
343         self.DepexReport = None
344         if "DEPEX" in ReportType:
345             self.DepexReport = DepexReport(M)
346         
347         if "BUILD_FLAGS" in ReportType:
348             self.BuildFlagsReport = BuildFlagsReport(M)
349     
350     ##
351     # Generate report for module information
352     #
353     # This function generates report for separate module expression
354     # in a platform build.
355     #
356     # @param self            The object pointer
357     # @param File            The file object for report
358     # @param GlobalPcdReport The platform global PCD class object
359     # @param ReportType      The kind of report items in the final report file
360     #
361     def GenerateReport(self, File, GlobalPcdReport, ReportType):
362         FileWrite(File, gSectionStart)
363         
364         FileWrite(File, "Module Summary")
365         FileWrite(File, "Module Name:          %s" % self.ModuleName)
366         FileWrite(File, "Module INF Path:      %s" % self.ModuleInfPath)
367         FileWrite(File, "File GUID:            %s" % self.FileGuid)
368         if self.Size:
369             FileWrite(File, "Size:                 %s" % self.Size)
370         if self.BuildTimeStamp:
371             FileWrite(File, "Build Time Stamp:     %s" % self.BuildTimeStamp)
372         if self.DriverType:
373             FileWrite(File, "Driver Type:          %s" % self.DriverType)
374         if self.UefiSpecVersion:
375             FileWrite(File, "UEFI Spec Version:    %s" % self.DriverType)
376         if self.PiSpecVersion:
377             FileWrite(File, "PI Spec Version:      %s" % self.PiSpecVersion)
378         if self.PciDeviceId:
379             FileWrite(File, "PCI Device ID:        %s" % self.PciDeviceId)
380         if self.PciVendorId:
381             FileWrite(File, "PCI Vendor ID:        %s" % self.PciVendorId)
382         if self.PciClassCode:
383             FileWrite(File, "PCI Class Code:       %s" % self.PciClassCode)
384         
385         FileWrite(File, gSectionSep)   
386         
387         if "PCD" in ReportType:
388             GlobalPcdReport.GenerateReport(File, self.ModulePcdSet, self.ModuleDscOverridePcds)
389         
390         if "LIBRARY" in ReportType:
391             self.LibraryReport.GenerateReport(File)
392         
393         if "DEPEX" in ReportType:
394             self.DepexReport.GenerateReport(File)
395         
396         if "BUILD_FLAGS" in ReportType:
397             self.BuildFlagsReport.GenerateReport(File)
398         
399         FileWrite(File, gSectionEnd)
400
401 ##
402 # Reports platform and module PCD information
403 #
404 # This class reports the platform PCD section and module PCD subsection
405 # in the build report file.
406 #     
407 class PcdReport(object):
408     ##
409     # Constructor function for class PcdReport
410     #
411     # This constructor function generates PcdReport object a platform build.
412     # It collects the whole PCD database from platform DSC files, platform
413     # flash description file and package DEC files.
414     #
415     # @param self            The object pointer
416     # @param Wa              Workspace context information
417     #
418     def __init__(self, Wa):
419         self.AllPcds = {}
420         self.MaxLen = 0
421         self.FdfPcdSet = Wa.FdfProfile.PcdDict
422
423         self.DecPcdDefault = {}
424         self.ModulePcdOverride = {}
425         for Pa in Wa.AutoGenObjectList:
426             #
427             # Collect all platform referenced PCDs and grouped them by PCD token space
428             # GUID C Names
429             #
430             for Pcd in Pa.AllPcdList:
431                 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
432                 if Pcd not in PcdList:
433                     PcdList.append(Pcd)
434                 if len(Pcd.TokenCName) > self.MaxLen:
435                     self.MaxLen = len(Pcd.TokenCName)
436             
437             for ModuleKey in Pa.Platform.Modules:
438                 #
439                 # Collect PCD DEC default value.
440                 #   
441                 Module = Pa.Platform.Modules[ModuleKey]
442                 for Package in Module.M.Module.Packages:
443                     for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:
444                         DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue
445                         self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue)
446                 #
447                 # Collect module override PCDs
448                 #
449                 for ModulePcd in Module.M.ModulePcdList + Module.M.LibraryPcdList:
450                     TokenCName = ModulePcd.TokenCName
451                     TokenSpaceGuid = ModulePcd.TokenSpaceGuidCName
452                     ModuleDefault = ModulePcd.DefaultValue
453                     ModulePath = os.path.basename(Module.M.MetaFile.File)
454                     self.ModulePcdOverride.setdefault((TokenCName, TokenSpaceGuid), []).append((ModuleDefault, ModulePath))
455
456         #
457         # Collect PCDs defined in DSC common section
458         #
459         self.DscPcdDefault = {}
460         for Platform in Wa.BuildDatabase.WorkspaceDb.PlatformList:
461             for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds:
462                 DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue
463                 self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue
464     
465     ##
466     # Generate report for PCD information
467     #
468     # This function generates report for separate module expression
469     # in a platform build.
470     #
471     # @param self            The object pointer
472     # @param File            The file object for report
473     # @param ModulePcdSet    Set of all PCDs referenced by module or None for
474     #                        platform PCD report
475     # @param DscOverridePcds Module DSC override PCDs set
476     #
477     def GenerateReport(self, File, ModulePcdSet, DscOverridePcds):
478         if ModulePcdSet == None:
479             #
480             # For platform global PCD section
481             #
482             FileWrite(File, gSectionStart)
483             FileWrite(File, "Platform Configuration Database Report")
484             FileWrite(File, "  *P  - Platform scoped PCD override in DSC file")
485             FileWrite(File, "  *F  - Platform scoped PCD override in FDF file")
486             FileWrite(File, "  *M  - Module scoped PCD override in DSC file")
487             FileWrite(File, gSectionSep)
488         else:
489             #
490             # For module PCD sub-section
491             #
492             FileWrite(File, gSubSectionStart)
493             FileWrite(File, "PCD")
494             FileWrite(File, gSubSectionSep)
495
496         for Key in self.AllPcds:
497             #
498             # Group PCD by their token space GUID C Name
499             #
500             First = True
501             for Type in self.AllPcds[Key]:
502                 #
503                 # Group PCD by their usage type
504                 #
505                 TypeName, DecType = gPcdTypeMap.get(Type, ("", Type))
506                 for Pcd in self.AllPcds[Key][Type]:
507                     #
508                     # Get PCD default value and their override relationship
509                     #
510                     InfDefaultValue = None
511                     if ModulePcdSet != None:
512                         if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type) not in ModulePcdSet:
513                             continue
514                         InfDefault = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]
515                         if InfDefault == "":
516                             InfDefault = None
517                     if First:
518                         if ModulePcdSet == None:
519                             FileWrite(File, "")
520                         FileWrite(File, Key)
521                         First = False
522                     DecDefaultValue = self.DecPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, DecType))
523                     DscDefaultValue = self.DscPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))
524                     DscModuleOverrideValue = DscOverridePcds.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))
525                           
526                     if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
527                         PcdDefaultValueNumber = int(Pcd.DefaultValue.strip(), 0)
528                         if DecDefaultValue == None:
529                             DecMatch = True
530                         else:
531                             DecDefaultValueNumber = int(DecDefaultValue.strip(), 0)
532                             DecMatch = (DecDefaultValueNumber == PcdDefaultValueNumber)
533                   
534                         if InfDefaultValue == None:
535                             InfMatch = True
536                         else:
537                             InfDefaultValueNumber = int(InfDefaultValue.strip(), 0)
538                             InfMatch = (InfDefaultValueNumber == PcdDefaultValueNumber)
539                                 
540                         if DscDefaultValue == None:
541                             DscMatch = True
542                         else:
543                             DscDefaultValueNumber = int(DscDefaultValue.strip(), 0)
544                             DscMatch = (DscDefaultValueNumber == PcdDefaultValueNumber)
545                     else:
546                         if DecDefaultValue == None:
547                             DecMatch = True
548                         else:
549                             DecMatch = (DecDefaultValue == Pcd.DefaultValue)
550                   
551                         if InfDefaultValue == None:
552                             InfMatch = True
553                         else:
554                             InfMatch = (InfDefaultValue == Pcd.DefaultValue)
555                             
556                         if DscDefaultValue == None:
557                             DscMatch = True
558                         else:
559                             DscMatch = (DscDefaultValue == Pcd.DefaultValue)
560                     
561                     #
562                     # Report PCD item according to their override relationship
563                     #        
564                     if DecMatch and InfMatch:
565                         FileWrite(File, '    %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', Pcd.DefaultValue))
566                     else:
567                         if DscMatch and DscModuleOverrideValue == None:
568                             if (Pcd.TokenCName, Key) in self.FdfPcdSet:
569                                 FileWrite(File, ' *F %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', Pcd.DefaultValue))
570                             else:
571                                 FileWrite(File, ' *P %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', Pcd.DefaultValue))
572                         else:
573                             FileWrite(File, ' *M %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', Pcd.DefaultValue))
574                             if DscDefaultValue != None:
575                                 FileWrite(File, '    %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', DscDefaultValue))
576                         
577                         if InfDefaultValue != None:
578                             FileWrite(File, '    %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', InfDefaultValue))
579                         
580                         if DecDefaultValue != None and not DecMatch:
581                             FileWrite(File, '    %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', DecDefaultValue))
582
583                     if ModulePcdSet == None:
584                         for (ModuleDefault, ModulePath) in self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), []):
585                             if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
586                                 ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0)
587                                 Match = (ModulePcdDefaultValueNumber == PcdDefaultValueNumber)
588                             else:
589                                 Match = (ModuleDefault == Pcd.DefaultValue)
590                             if Match:
591                                 continue
592                             FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 19, ModulePath, ModuleDefault))
593         
594         if ModulePcdSet == None:
595             FileWrite(File, gSectionEnd)
596         else:
597             FileWrite(File, gSubSectionEnd)     
598
599
600 ##
601 # Reports platform information
602 #
603 # This class reports the whole platform information 
604 #     
605 class PlatformReport(object):
606     ##
607     # Constructor function for class PlatformReport
608     #
609     # This constructor function generates PlatformReport object a platform build.
610     # It generates report for platform summary, flash, global PCDs and detailed
611     # module information for modules involved in platform build.
612     #
613     # @param self            The object pointer
614     # @param Wa              Workspace context information
615     #
616     def __init__(self, Wa, ReportType):
617         self._WorkspaceDir = Wa.WorkspaceDir
618         self.PlatformName = Wa.Name
619         self.PlatformDscPath = Wa.Platform
620         self.Architectures = " ".join(Wa.ArchList)
621         self.ToolChain = Wa.ToolChain
622         self.Target = Wa.BuildTarget
623         self.OutputPath = os.path.join(Wa.WorkspaceDir, Wa.OutputDir)
624         self.BuildEnvironment = platform.platform()
625         
626         self.PcdReport = None
627         if "PCD" in ReportType:
628             self.PcdReport = PcdReport(Wa)
629
630         self.ModuleReportList = []
631         for Pa in Wa.AutoGenObjectList:
632             for ModuleKey in Pa.Platform.Modules:
633                 for Platform in Wa.BuildDatabase.WorkspaceDb.PlatformList:
634                     if ModuleKey in Platform.Modules:
635                         DscOverridePcds = Platform.Modules[ModuleKey].Pcds
636                         break
637                 else:
638                     DscOverridePcds = {}
639                 self.ModuleReportList.append(ModuleReport(Pa.Platform.Modules[ModuleKey].M, DscOverridePcds, ReportType))
640  
641     ##
642     # Generate report for the whole platform.
643     #
644     # This function generates report for platform information.
645     # It comprises of platform summary, global PCD, flash and 
646     # module list sections.
647     #
648     # @param self            The object pointer
649     # @param File            The file object for report
650     # @param BuildDuration   The total time to build the modules
651     # @param ReportType      The kind of report items in the final report file
652     #
653     def GenerateReport(self, File, BuildDuration, ReportType):
654         FileWrite(File, "Platform Summary")
655         FileWrite(File, "Platform Name:        %s" % self.PlatformName)
656         FileWrite(File, "Platform DSC Path:    %s" % self.PlatformDscPath)
657         FileWrite(File, "Platform DSC Path:    %s" % self.Architectures)
658         FileWrite(File, "Tool Chain:           %s" % self.ToolChain)
659         FileWrite(File, "Target:               %s" % self.Target)
660         FileWrite(File, "Output Path:          %s" % self.OutputPath)
661         FileWrite(File, "Build Environment:    %s" % self.BuildEnvironment)
662         FileWrite(File, "Build Duration:       %s" % BuildDuration)
663         FileWrite(File, "Report Content:       %s" % ", ".join(ReportType))
664  
665         if "PCD" in ReportType:
666             self.PcdReport.GenerateReport(File, None, {})
667             
668        
669         for ModuleReportItem in self.ModuleReportList:
670             ModuleReportItem.GenerateReport(File, self.PcdReport, ReportType)
671         
672
673 ## BuildReport class
674 #
675 #  This base class contain the routines to collect data and then
676 #  applies certain format to the output report 
677 #
678 class BuildReport(object):
679     ##
680     # Constructor function for class BuildReport
681     #
682     # This constructor function generates BuildReport object a platform build.
683     # It generates report for platform summary, flash, global PCDs and detailed
684     # module information for modules involved in platform build.
685     #
686     # @param self            The object pointer
687     # @param ReportFile      The file name to save report file
688     # @param ReportType      The kind of report items in the final report file
689     #
690     def __init__(self, ReportFile, ReportType):
691         self.ReportFile = ReportFile
692         if ReportFile:
693             self.ReportList = []
694             if ReportType == None or "ALL" in ReportType:
695                 self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "FLASH", "PREDICTION"]
696             else:
697                 for ReportTypeItem in ReportType:
698                     if ReportTypeItem not in self.ReportType:
699                         self.ReportType.append(ReportTypeItem)
700     
701     ##
702     # Adds platform report to the list
703     #
704     # This function adds a platform report to the final report list.
705     #
706     # @param self            The object pointer
707     # @param Wa              Workspace context information
708     #           
709     def AddPlatformReport(self, Wa):
710         if self.ReportFile:
711             self.ReportList.append(PlatformReport(Wa, self.ReportType))
712
713     ##
714     # Generates the final report.
715     #
716     # This function generates platform build report. It invokes GenerateReport()
717     # method for every platform report in the list.
718     #
719     # @param self            The object pointer
720     # @param BuildDuration   The total time to build the modules
721     # 
722     def GenerateReport(self, BuildDuration):
723         if self.ReportFile:
724             try:
725                 File = open(self.ReportFile, "w+")
726             except IOError:
727                 EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=self.ReportFile)
728             try:
729                 for Report in self.ReportList:
730                     Report.GenerateReport(File, BuildDuration, self.ReportType) 
731             except IOError:
732                 EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile)
733             File.close()
734         
735 # This acts like the main() function for the script, unless it is 'import'ed into another script.
736 if __name__ == '__main__':
737     pass
738