# This module contains the functionality to generate build report after\r
# build all target completes successfully.\r
#\r
-# Copyright (c) 2010, Intel Corporation\r
-# All rights reserved. This program and the accompanying materials\r
+# Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
# are licensed and made available under the terms and conditions of the BSD License\r
# which accompanies this distribution. The full text of the license may be found at\r
# http://opensource.org/licenses/bsd-license.php\r
\r
## Import Modules\r
#\r
-import os\r
+import Common.LongFilePathOs as os\r
import re\r
import platform\r
import textwrap\r
import traceback\r
import sys\r
+import time\r
+import struct\r
from datetime import datetime\r
+from StringIO import StringIO\r
from Common import EdkLogger\r
+from Common.Misc import SaveFileOnChange\r
from Common.Misc import GuidStructureByteArrayToGuidString\r
from Common.Misc import GuidStructureStringToGuidString\r
from Common.InfClassObject import gComponentType2ModuleType\r
-from Common.BuildToolError import FILE_OPEN_FAILURE\r
from Common.BuildToolError import FILE_WRITE_FAILURE\r
from Common.BuildToolError import CODE_ERROR\r
-\r
+from Common.DataType import TAB_LINE_BREAK\r
+from Common.DataType import TAB_DEPEX\r
+from Common.DataType import TAB_SLASH\r
+from Common.DataType import TAB_SPACE_SPLIT\r
+from Common.DataType import TAB_BRG_PCD\r
+from Common.DataType import TAB_BRG_LIBRARY\r
+from Common.DataType import TAB_BACK_SLASH\r
+from Common.LongFilePathSupport import OpenLongFilePath as open\r
+from Common.MultipleWorkspace import MultipleWorkspace as mws\r
\r
## Pattern to extract contents in EDK DXS files\r
gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)\r
## Pattern to find the entry point for EDK module using EDKII Glue library\r
gGlueLibEntryPoint = re.compile(r"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")\r
\r
+## Tags for MaxLength of line in report\r
+gLineMaxLength = 120\r
+\r
+## Tags for end of line in report\r
+gEndOfLine = "\r\n"\r
+\r
## Tags for section start, end and separator\r
-gSectionStart = ">" + "=" * 118 + "<"\r
-gSectionEnd = "<" + "=" * 118 + ">" + "\n"\r
-gSectionSep = "=" * 120\r
+gSectionStart = ">" + "=" * (gLineMaxLength-2) + "<"\r
+gSectionEnd = "<" + "=" * (gLineMaxLength-2) + ">" + "\n"\r
+gSectionSep = "=" * gLineMaxLength\r
\r
## Tags for subsection start, end and separator\r
-gSubSectionStart = ">" + "-" * 118 + "<"\r
-gSubSectionEnd = "<" + "-" * 118 + ">"\r
-gSubSectionSep = "-" * 120\r
+gSubSectionStart = ">" + "-" * (gLineMaxLength-2) + "<"\r
+gSubSectionEnd = "<" + "-" * (gLineMaxLength-2) + ">"\r
+gSubSectionSep = "-" * gLineMaxLength\r
+\r
\r
## The look up table to map PCD type to pair of report display type and DEC type\r
gPcdTypeMap = {\r
'Dynamic' : ('DYN', 'Dynamic'),\r
'DynamicHii' : ('DYNHII', 'Dynamic'),\r
'DynamicVpd' : ('DYNVPD', 'Dynamic'),\r
- 'DynamicEx' : ('DEX', 'Dynamic'),\r
- 'DynamicExHii' : ('DEXHII', 'Dynamic'),\r
- 'DynamicExVpd' : ('DEXVPD', 'Dynamic'),\r
+ 'DynamicEx' : ('DEX', 'DynamicEx'),\r
+ 'DynamicExHii' : ('DEXHII', 'DynamicEx'),\r
+ 'DynamicExVpd' : ('DEXVPD', 'DynamicEx'),\r
}\r
\r
## The look up table to map module type to driver type\r
'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers\r
}\r
\r
+## The look up table of the supported opcode in the dependency expression binaries\r
+gOpCodeList = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]\r
+\r
##\r
# Writes a string to the file object.\r
#\r
def FileWrite(File, String, Wrapper=False):\r
if Wrapper:\r
String = textwrap.fill(String, 120)\r
- File.write(String + "\r\n")\r
+ File.write(String + gEndOfLine)\r
\r
##\r
# Find all the header file that the module source directly includes.\r
IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName\r
break\r
\r
+## Split each lines in file\r
+#\r
+# This method is used to split the lines in file to make the length of each line \r
+# less than MaxLength.\r
+#\r
+# @param Content The content of file\r
+# @param MaxLength The Max Length of the line\r
+#\r
+def FileLinesSplit(Content=None, MaxLength=None):\r
+ ContentList = Content.split(TAB_LINE_BREAK)\r
+ NewContent = ''\r
+ NewContentList = []\r
+ for Line in ContentList:\r
+ while len(Line.rstrip()) > MaxLength:\r
+ LineSpaceIndex = Line.rfind(TAB_SPACE_SPLIT, 0, MaxLength)\r
+ LineSlashIndex = Line.rfind(TAB_SLASH, 0, MaxLength)\r
+ LineBackSlashIndex = Line.rfind(TAB_BACK_SLASH, 0, MaxLength)\r
+ if max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex) > 0:\r
+ LineBreakIndex = max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex)\r
+ else:\r
+ LineBreakIndex = MaxLength\r
+ NewContentList.append(Line[:LineBreakIndex])\r
+ Line = Line[LineBreakIndex:]\r
+ if Line:\r
+ NewContentList.append(Line)\r
+ for NewLine in NewContentList:\r
+ NewContent += NewLine + TAB_LINE_BREAK\r
+ \r
+ NewContent = NewContent.replace(TAB_LINE_BREAK, gEndOfLine).replace('\r\r\n', gEndOfLine)\r
+ return NewContent\r
+ \r
+ \r
+ \r
+##\r
+# Parse binary dependency expression section\r
+#\r
+# This utility class parses the dependency expression section and translate the readable\r
+# GUID name and value.\r
+#\r
+class DepexParser(object):\r
+ ##\r
+ # Constructor function for class DepexParser\r
+ #\r
+ # This constructor function collect GUID values so that the readable\r
+ # GUID name can be translated.\r
+ #\r
+ # @param self The object pointer\r
+ # @param Wa Workspace context information\r
+ #\r
+ def __init__(self, Wa):\r
+ self._GuidDb = {}\r
+ for Pa in Wa.AutoGenObjectList:\r
+ for Package in Pa.PackageList: \r
+ for Protocol in Package.Protocols:\r
+ GuidValue = GuidStructureStringToGuidString(Package.Protocols[Protocol])\r
+ self._GuidDb[GuidValue.upper()] = Protocol\r
+ for Ppi in Package.Ppis:\r
+ GuidValue = GuidStructureStringToGuidString(Package.Ppis[Ppi])\r
+ self._GuidDb[GuidValue.upper()] = Ppi\r
+ for Guid in Package.Guids:\r
+ GuidValue = GuidStructureStringToGuidString(Package.Guids[Guid])\r
+ self._GuidDb[GuidValue.upper()] = Guid\r
+ \r
+ ##\r
+ # Parse the binary dependency expression files.\r
+ # \r
+ # This function parses the binary dependency expression file and translate it\r
+ # to the instruction list.\r
+ #\r
+ # @param self The object pointer\r
+ # @param DepexFileName The file name of binary dependency expression file.\r
+ #\r
+ def ParseDepexFile(self, DepexFileName):\r
+ DepexFile = open(DepexFileName, "rb")\r
+ DepexStatement = []\r
+ OpCode = DepexFile.read(1)\r
+ while OpCode:\r
+ Statement = gOpCodeList[struct.unpack("B", OpCode)[0]]\r
+ if Statement in ["BEFORE", "AFTER", "PUSH"]:\r
+ GuidValue = "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \\r
+ struct.unpack("=LHHBBBBBBBB", DepexFile.read(16))\r
+ GuidString = self._GuidDb.get(GuidValue, GuidValue)\r
+ Statement = "%s %s" % (Statement, GuidString)\r
+ DepexStatement.append(Statement)\r
+ OpCode = DepexFile.read(1) \r
+ \r
+ return DepexStatement\r
+ \r
##\r
# Reports library information\r
#\r
#\r
def GenerateReport(self, File):\r
FileWrite(File, gSubSectionStart)\r
- FileWrite(File, "Library")\r
+ FileWrite(File, TAB_BRG_LIBRARY)\r
if len(self.LibraryList) > 0:\r
FileWrite(File, gSubSectionSep)\r
for LibraryItem in self.LibraryList:\r
EdkIILibInfo += " C = " + LibConstructor\r
LibDestructor = " ".join(LibraryItem[3])\r
if LibDestructor:\r
- EdkIILibInfo += " D = " + LibConstructor\r
+ EdkIILibInfo += " D = " + LibDestructor\r
LibDepex = " ".join(LibraryItem[4])\r
if LibDepex:\r
EdkIILibInfo += " Depex = " + LibDepex\r
#\r
def __init__(self, M):\r
self.Depex = ""\r
+ self._DepexFileName = os.path.join(M.BuildDir, "OUTPUT", M.Module.BaseName + ".depex") \r
ModuleType = M.ModuleType\r
if not ModuleType:\r
ModuleType = gComponentType2ModuleType.get(M.ComponentType, "")\r
- if ModuleType in ["SEC", "PEI_CORE", "DXE_CORE"]:\r
+\r
+ if ModuleType in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "UEFI_APPLICATION"]:\r
return\r
\r
for Source in M.SourceFileList:\r
#\r
# This function generates report for the module dependency expression.\r
#\r
- # @param self The object pointer\r
- # @param File The file object for report\r
+ # @param self The object pointer\r
+ # @param File The file object for report\r
+ # @param GlobalDepexParser The platform global Dependency expression parser object\r
#\r
- def GenerateReport(self, File):\r
+ def GenerateReport(self, File, GlobalDepexParser):\r
if not self.Depex:\r
+ FileWrite(File, gSubSectionStart)\r
+ FileWrite(File, TAB_DEPEX)\r
+ FileWrite(File, gSubSectionEnd)\r
return\r
- \r
FileWrite(File, gSubSectionStart)\r
+ if os.path.isfile(self._DepexFileName):\r
+ try:\r
+ DepexStatements = GlobalDepexParser.ParseDepexFile(self._DepexFileName)\r
+ FileWrite(File, "Final Dependency Expression (DEPEX) Instructions")\r
+ for DepexStatement in DepexStatements:\r
+ FileWrite(File, " %s" % DepexStatement)\r
+ FileWrite(File, gSubSectionSep)\r
+ except:\r
+ EdkLogger.warn(None, "Dependency expression file is corrupted", self._DepexFileName)\r
+ \r
FileWrite(File, "Dependency Expression (DEPEX) from %s" % self.Source)\r
\r
if self.Source == "INF":\r
self.Size = 0\r
self.BuildTimeStamp = None\r
self.DriverType = ""\r
- ModuleType = M.ModuleType\r
- if not ModuleType:\r
- ModuleType = gComponentType2ModuleType.get(M.ComponentType, "")\r
- #\r
- # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"\r
- #\r
- if ModuleType == "DXE_SMM_DRIVER":\r
- PiSpec = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000")\r
- if int(PiSpec, 0) >= 0x0001000A:\r
- ModuleType = "SMM_DRIVER"\r
- self.DriverType = gDriverTypeMap.get(ModuleType, "")\r
+ if not M.IsLibrary:\r
+ ModuleType = M.ModuleType\r
+ if not ModuleType:\r
+ ModuleType = gComponentType2ModuleType.get(M.ComponentType, "")\r
+ #\r
+ # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"\r
+ #\r
+ if ModuleType == "DXE_SMM_DRIVER":\r
+ PiSpec = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000")\r
+ if int(PiSpec, 0) >= 0x0001000A:\r
+ ModuleType = "SMM_DRIVER"\r
+ self.DriverType = gDriverTypeMap.get(ModuleType, "0x2 (FREE_FORM)")\r
self.UefiSpecVersion = M.Module.Specification.get("UEFI_SPECIFICATION_VERSION", "")\r
self.PiSpecVersion = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "")\r
self.PciDeviceId = M.Module.Defines.get("PCI_DEVICE_ID", "")\r
# This function generates report for separate module expression\r
# in a platform build.\r
#\r
- # @param self The object pointer\r
- # @param File The file object for report\r
- # @param GlobalPcdReport The platform global PCD class object\r
- # @param ReportType The kind of report items in the final report file\r
+ # @param self The object pointer\r
+ # @param File The file object for report\r
+ # @param GlobalPcdReport The platform global PCD report object\r
+ # @param GlobalPredictionReport The platform global Prediction report object\r
+ # @param GlobalDepexParser The platform global Dependency expression parser object\r
+ # @param ReportType The kind of report items in the final report file\r
#\r
- def GenerateReport(self, File, GlobalPcdReport, GlobalPredictionReport, ReportType):\r
+ def GenerateReport(self, File, GlobalPcdReport, GlobalPredictionReport, GlobalDepexParser, ReportType):\r
FileWrite(File, gSectionStart)\r
\r
FwReportFileName = os.path.join(self._BuildDir, "DEBUG", self.ModuleName + ".txt")\r
self.LibraryReport.GenerateReport(File)\r
\r
if "DEPEX" in ReportType:\r
- self.DepexReport.GenerateReport(File)\r
+ self.DepexReport.GenerateReport(File, GlobalDepexParser)\r
\r
if "BUILD_FLAGS" in ReportType:\r
self.BuildFlagsReport.GenerateReport(File)\r
# Collect PCD DEC default value.\r
#\r
self.DecPcdDefault = {}\r
- for Package in Wa.BuildDatabase.WorkspaceDb.PackageList:\r
- for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
- DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
- self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue)\r
+ for Pa in Wa.AutoGenObjectList:\r
+ for Package in Pa.PackageList:\r
+ for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
+ DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
+ self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue)\r
#\r
# Collect PCDs defined in DSC common section\r
#\r
self.DscPcdDefault = {}\r
- for Platform in Wa.BuildDatabase.WorkspaceDb.PlatformList:\r
+ for Arch in Wa.ArchList:\r
+ Platform = Wa.BuildDatabase[Wa.MetaFile, Arch, Wa.BuildTarget, Wa.ToolChain]\r
for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds:\r
DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue\r
- self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue\r
+ if DscDefaultValue:\r
+ self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue\r
\r
##\r
# Generate report for PCD information\r
FileWrite(File, "Platform Configuration Database Report")\r
FileWrite(File, " *P - Platform scoped PCD override in DSC file")\r
FileWrite(File, " *F - Platform scoped PCD override in FDF file")\r
- FileWrite(File, " *M - Module scoped PCD override in DSC file")\r
+ FileWrite(File, " *M - Module scoped PCD override")\r
FileWrite(File, gSectionSep)\r
else:\r
#\r
# For module PCD sub-section\r
#\r
FileWrite(File, gSubSectionStart)\r
- FileWrite(File, "PCD")\r
+ FileWrite(File, TAB_BRG_PCD)\r
FileWrite(File, gSubSectionSep)\r
\r
for Key in self.AllPcds:\r
if DecDefaultValue == None:\r
DecMatch = True\r
else:\r
- DecMatch = (DecDefaultValue == PcdValue)\r
+ DecMatch = (DecDefaultValue.strip() == PcdValue.strip())\r
\r
if InfDefaultValue == None:\r
InfMatch = True\r
else:\r
- InfMatch = (InfDefaultValue == PcdValue)\r
+ InfMatch = (InfDefaultValue.strip() == PcdValue.strip())\r
\r
if DscDefaultValue == None:\r
DscMatch = True\r
else:\r
- DscMatch = (DscDefaultValue == PcdValue)\r
+ DscMatch = (DscDefaultValue.strip() == PcdValue.strip())\r
\r
#\r
# Report PCD item according to their override relationship\r
#\r
if DecMatch and InfMatch:\r
- FileWrite(File, ' %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue))\r
+ FileWrite(File, ' %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))\r
else:\r
if DscMatch:\r
if (Pcd.TokenCName, Key) in self.FdfPcdSet:\r
- FileWrite(File, ' *F %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue))\r
+ FileWrite(File, ' *F %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))\r
else:\r
- FileWrite(File, ' *P %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue))\r
+ FileWrite(File, ' *P %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))\r
else:\r
- FileWrite(File, ' *M %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue))\r
+ FileWrite(File, ' *M %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))\r
\r
if TypeName in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):\r
for SkuInfo in Pcd.SkuInfoList.values():\r
FileWrite(File, '%*s' % (self.MaxLen + 4, SkuInfo.VpdOffset))\r
\r
if not DscMatch and DscDefaultValue != None:\r
- FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', DscDefaultValue))\r
+ FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', DscDefaultValue.strip()))\r
\r
if not InfMatch and InfDefaultValue != None:\r
- FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', InfDefaultValue))\r
+ FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', InfDefaultValue.strip()))\r
\r
if not DecMatch and DecDefaultValue != None:\r
- FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', DecDefaultValue))\r
+ FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', DecDefaultValue.strip()))\r
\r
if ModulePcdSet == None:\r
ModuleOverride = self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), {})\r
ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0)\r
Match = (ModulePcdDefaultValueNumber == PcdValueNumber)\r
else:\r
- Match = (ModuleDefault == PcdValue)\r
+ Match = (ModuleDefault.strip() == PcdValue.strip())\r
if Match:\r
continue\r
- FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 19, ModulePath, ModuleDefault))\r
+ FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 19, ModulePath, ModuleDefault.strip()))\r
\r
if ModulePcdSet == None:\r
FileWrite(File, gSectionEnd)\r
for Pa in Wa.AutoGenObjectList:\r
for Module in Pa.LibraryAutoGenList + Pa.ModuleAutoGenList:\r
#\r
+ # BASE typed modules are EFI agnostic, so we need not scan\r
+ # their source code to find PPI/Protocol produce or consume\r
+ # information.\r
+ #\r
+ if Module.ModuleType == "BASE":\r
+ continue\r
+ #\r
# Add module referenced source files\r
#\r
self._SourceList.append(str(Module))\r
\r
try:\r
from Eot.Eot import Eot\r
+\r
#\r
- # Invoke EOT tool\r
+ # Invoke EOT tool and echo its runtime performance\r
#\r
+ EotStartTime = time.time()\r
Eot(CommandLineOption=False, SourceFileList=SourceList, GuidList=GuidList,\r
FvFileList=' '.join(FvFileList), Dispatch=DispatchList, IsInit=True)\r
-\r
+ EotEndTime = time.time()\r
+ EotDuration = time.strftime("%H:%M:%S", time.gmtime(int(round(EotEndTime - EotStartTime))))\r
+ EdkLogger.quiet("EOT run time: %s\n" % EotDuration)\r
+ \r
#\r
# Parse the output of EOT tool\r
#\r
self._DiscoverNestedFvList(FvName, Wa)\r
\r
PlatformPcds = {}\r
- \r
#\r
# Collect PCDs declared in DEC files.\r
+ # \r
+ for Pa in Wa.AutoGenObjectList:\r
+ for Package in Pa.PackageList:\r
+ for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
+ DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
+ PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue\r
#\r
- for Package in Wa.BuildDatabase.WorkspaceDb.PackageList:\r
- for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
- DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
- PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue\r
- #\r
- # Collect PCDs defined in DSC common section\r
+ # Collect PCDs defined in DSC file\r
#\r
- for Platform in Wa.BuildDatabase.WorkspaceDb.PlatformList:\r
+ for arch in Wa.ArchList:\r
+ Platform = Wa.BuildDatabase[Wa.MetaFile, arch]\r
for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds:\r
DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue\r
PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue\r
for Pa in Wa.AutoGenObjectList:\r
for ModuleKey in Pa.Platform.Modules:\r
M = Pa.Platform.Modules[ModuleKey].M\r
- InfPath = os.path.join(Wa.WorkspaceDir, M.MetaFile.File)\r
+ InfPath = mws.join(Wa.WorkspaceDir, M.MetaFile.File)\r
self._GuidsDb[M.Guid.upper()] = "%s (%s)" % (M.Module.BaseName, InfPath)\r
\r
#\r
Guid = GuidStructureByteArrayToGuidString(GuidValue).upper()\r
for Section in Ffs.SectionList:\r
try:\r
- ModuleSectFile = os.path.join(Wa.WorkspaceDir, Section.SectFileName)\r
+ ModuleSectFile = mws.join(Wa.WorkspaceDir, Section.SectFileName)\r
self._GuidsDb[Guid] = ModuleSectFile\r
except AttributeError:\r
pass\r
FvTotalSize = 0\r
FvTakenSize = 0\r
FvFreeSize = 0\r
- FvReportFileName = os.path.join(self._FvDir, FvName + ".fv.txt")\r
+ FvReportFileName = os.path.join(self._FvDir, FvName + ".Fv.txt")\r
try:\r
#\r
# Collect size info in the firmware volume.\r
#\r
# @param self The object pointer\r
# @param Wa Workspace context information\r
+ # @param MaList The list of modules in the platform build\r
#\r
- def __init__(self, Wa, ReportType):\r
+ def __init__(self, Wa, MaList, ReportType):\r
self._WorkspaceDir = Wa.WorkspaceDir\r
self.PlatformName = Wa.Name\r
self.PlatformDscPath = Wa.Platform\r
self.PcdReport = PcdReport(Wa)\r
\r
self.FdReportList = []\r
- if "FLASH" in ReportType and Wa.FdfProfile:\r
+ if "FLASH" in ReportType and Wa.FdfProfile and MaList == None:\r
for Fd in Wa.FdfProfile.FdDict:\r
self.FdReportList.append(FdReport(Wa.FdfProfile.FdDict[Fd], Wa))\r
\r
if "FIXED_ADDRESS" in ReportType or "EXECUTION_ORDER" in ReportType:\r
self.PredictionReport = PredictionReport(Wa)\r
\r
+ self.DepexParser = None\r
+ if "DEPEX" in ReportType:\r
+ self.DepexParser = DepexParser(Wa)\r
+ \r
self.ModuleReportList = []\r
- for Pa in Wa.AutoGenObjectList:\r
- for ModuleKey in Pa.Platform.Modules:\r
- self.ModuleReportList.append(ModuleReport(Pa.Platform.Modules[ModuleKey].M, ReportType))\r
+ if MaList != None:\r
+ self._IsModuleBuild = True\r
+ for Ma in MaList:\r
+ self.ModuleReportList.append(ModuleReport(Ma, ReportType))\r
+ else:\r
+ self._IsModuleBuild = False\r
+ for Pa in Wa.AutoGenObjectList:\r
+ for ModuleKey in Pa.Platform.Modules:\r
+ self.ModuleReportList.append(ModuleReport(Pa.Platform.Modules[ModuleKey].M, ReportType))\r
\r
\r
\r
FileWrite(File, "Build Duration: %s" % BuildDuration)\r
FileWrite(File, "Report Content: %s" % ", ".join(ReportType))\r
\r
- if "PCD" in ReportType:\r
- self.PcdReport.GenerateReport(File, None)\r
-\r
- if "FLASH" in ReportType:\r
- for FdReportListItem in self.FdReportList:\r
- FdReportListItem.GenerateReport(File)\r
+ if not self._IsModuleBuild:\r
+ if "PCD" in ReportType:\r
+ self.PcdReport.GenerateReport(File, None)\r
+ \r
+ if "FLASH" in ReportType:\r
+ for FdReportListItem in self.FdReportList:\r
+ FdReportListItem.GenerateReport(File)\r
\r
for ModuleReportItem in self.ModuleReportList:\r
- ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, ReportType)\r
+ ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, self.DepexParser, ReportType)\r
\r
- if "EXECUTION_ORDER" in ReportType:\r
- self.PredictionReport.GenerateReport(File, None)\r
+ if not self._IsModuleBuild:\r
+ if "EXECUTION_ORDER" in ReportType:\r
+ self.PredictionReport.GenerateReport(File, None)\r
\r
## BuildReport class\r
#\r
#\r
# @param self The object pointer\r
# @param Wa Workspace context information\r
+ # @param MaList The list of modules in the platform build\r
#\r
- def AddPlatformReport(self, Wa):\r
+ def AddPlatformReport(self, Wa, MaList=None):\r
if self.ReportFile:\r
- self.ReportList.append(Wa)\r
+ self.ReportList.append((Wa, MaList))\r
\r
##\r
# Generates the final report.\r
def GenerateReport(self, BuildDuration):\r
if self.ReportFile:\r
try:\r
- File = open(self.ReportFile, "w+")\r
- except IOError:\r
- EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=self.ReportFile)\r
- try:\r
- for Wa in self.ReportList:\r
- PlatformReport(Wa, self.ReportType).GenerateReport(File, BuildDuration, self.ReportType)\r
- EdkLogger.quiet("Report successfully saved to %s" % os.path.abspath(self.ReportFile))\r
+ File = StringIO('')\r
+ for (Wa, MaList) in self.ReportList:\r
+ PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, self.ReportType)\r
+ Content = FileLinesSplit(File.getvalue(), gLineMaxLength)\r
+ SaveFileOnChange(self.ReportFile, Content, True)\r
+ EdkLogger.quiet("Build report can be found at %s" % os.path.abspath(self.ReportFile))\r
except IOError:\r
EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile)\r
except:\r
EdkLogger.error("BuildReport", CODE_ERROR, "Unknown fatal error when generating build report", ExtraData=self.ReportFile, RaiseError=False)\r
EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))\r
File.close()\r
-\r
+ \r
# This acts like the main() function for the script, unless it is 'import'ed into another script.\r
if __name__ == '__main__':\r
pass\r