]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/build/BuildReport.py
Revert the change in r19137.
[mirror_edk2.git] / BaseTools / Source / Python / build / BuildReport.py
CommitLineData
52302d4d
LG
1## @file\r
2# Routines for generating build report.\r
3#\r
4# This module contains the functionality to generate build report after\r
5# build all target completes successfully.\r
6#\r
1be2ed90 7# Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
40d841f6 8# This program and the accompanying materials\r
52302d4d
LG
9# are licensed and made available under the terms and conditions of the BSD License\r
10# which accompanies this distribution. The full text of the license may be found at\r
11# http://opensource.org/licenses/bsd-license.php\r
12#\r
13# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15#\r
16\r
17## Import Modules\r
18#\r
1be2ed90 19import Common.LongFilePathOs as os\r
52302d4d
LG
20import re\r
21import platform\r
22import textwrap\r
23import traceback\r
24import sys\r
40d841f6 25import time\r
e56468c0 26import struct\r
52302d4d 27from datetime import datetime\r
40d841f6 28from StringIO import StringIO\r
52302d4d 29from Common import EdkLogger\r
40d841f6 30from Common.Misc import SaveFileOnChange\r
52302d4d
LG
31from Common.Misc import GuidStructureByteArrayToGuidString\r
32from Common.Misc import GuidStructureStringToGuidString\r
33from Common.InfClassObject import gComponentType2ModuleType\r
52302d4d
LG
34from Common.BuildToolError import FILE_WRITE_FAILURE\r
35from Common.BuildToolError import CODE_ERROR\r
64b2609f
LG
36from Common.DataType import TAB_LINE_BREAK\r
37from Common.DataType import TAB_DEPEX\r
38from Common.DataType import TAB_SLASH\r
39from Common.DataType import TAB_SPACE_SPLIT\r
40from Common.DataType import TAB_BRG_PCD\r
41from Common.DataType import TAB_BRG_LIBRARY\r
25918452 42from Common.DataType import TAB_BACK_SLASH\r
1be2ed90 43from Common.LongFilePathSupport import OpenLongFilePath as open\r
05cc51ad 44from Common.MultipleWorkspace import MultipleWorkspace as mws\r
52302d4d
LG
45\r
46## Pattern to extract contents in EDK DXS files\r
47gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)\r
48\r
49## Pattern to find total FV total size, occupied size in flash report intermediate file\r
50gFvTotalSizePattern = re.compile(r"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")\r
51gFvTakenSizePattern = re.compile(r"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")\r
52\r
53## Pattern to find module size and time stamp in module summary report intermediate file\r
54gModuleSizePattern = re.compile(r"MODULE_SIZE = (\d+)")\r
55gTimeStampPattern = re.compile(r"TIME_STAMP = (\d+)")\r
56\r
57## Pattern to find GUID value in flash description files\r
58gPcdGuidPattern = re.compile(r"PCD\((\w+)[.](\w+)\)")\r
59\r
60## Pattern to collect offset, GUID value pair in the flash report intermediate file\r
61gOffsetGuidPattern = re.compile(r"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")\r
62\r
63## Pattern to find module base address and entry point in fixed flash map file\r
64gModulePattern = r"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"\r
65gMapFileItemPattern = re.compile(gModulePattern % {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})\r
66\r
67## Pattern to find all module referenced header files in source files\r
68gIncludePattern = re.compile(r'#include\s*["<]([^">]+)[">]')\r
69gIncludePattern2 = re.compile(r"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")\r
70\r
71## Pattern to find the entry point for EDK module using EDKII Glue library\r
72gGlueLibEntryPoint = re.compile(r"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")\r
73\r
64b2609f
LG
74## Tags for MaxLength of line in report\r
75gLineMaxLength = 120\r
76\r
4afd3d04
LG
77## Tags for end of line in report\r
78gEndOfLine = "\r\n"\r
79\r
52302d4d 80## Tags for section start, end and separator\r
47fea6af
YZ
81gSectionStart = ">" + "=" * (gLineMaxLength - 2) + "<"\r
82gSectionEnd = "<" + "=" * (gLineMaxLength - 2) + ">" + "\n"\r
64b2609f 83gSectionSep = "=" * gLineMaxLength\r
52302d4d
LG
84\r
85## Tags for subsection start, end and separator\r
47fea6af
YZ
86gSubSectionStart = ">" + "-" * (gLineMaxLength - 2) + "<"\r
87gSubSectionEnd = "<" + "-" * (gLineMaxLength - 2) + ">"\r
64b2609f
LG
88gSubSectionSep = "-" * gLineMaxLength\r
89\r
52302d4d
LG
90\r
91## The look up table to map PCD type to pair of report display type and DEC type\r
92gPcdTypeMap = {\r
93 'FixedAtBuild' : ('FIXED', 'FixedAtBuild'),\r
94 'PatchableInModule': ('PATCH', 'PatchableInModule'),\r
95 'FeatureFlag' : ('FLAG', 'FeatureFlag'),\r
96 'Dynamic' : ('DYN', 'Dynamic'),\r
97 'DynamicHii' : ('DYNHII', 'Dynamic'),\r
98 'DynamicVpd' : ('DYNVPD', 'Dynamic'),\r
4afd3d04
LG
99 'DynamicEx' : ('DEX', 'DynamicEx'),\r
100 'DynamicExHii' : ('DEXHII', 'DynamicEx'),\r
101 'DynamicExVpd' : ('DEXVPD', 'DynamicEx'),\r
52302d4d
LG
102 }\r
103\r
104## The look up table to map module type to driver type\r
105gDriverTypeMap = {\r
106 'SEC' : '0x3 (SECURITY_CORE)',\r
107 'PEI_CORE' : '0x4 (PEI_CORE)',\r
108 'PEIM' : '0x6 (PEIM)',\r
109 'DXE_CORE' : '0x5 (DXE_CORE)',\r
110 'DXE_DRIVER' : '0x7 (DRIVER)',\r
111 'DXE_SAL_DRIVER' : '0x7 (DRIVER)',\r
112 'DXE_SMM_DRIVER' : '0x7 (DRIVER)',\r
113 'DXE_RUNTIME_DRIVER': '0x7 (DRIVER)',\r
114 'UEFI_DRIVER' : '0x7 (DRIVER)',\r
115 'UEFI_APPLICATION' : '0x9 (APPLICATION)',\r
116 'SMM_CORE' : '0xD (SMM_CORE)',\r
117 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers\r
118 }\r
119\r
e56468c0 120## The look up table of the supported opcode in the dependency expression binaries\r
121gOpCodeList = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]\r
122\r
52302d4d
LG
123##\r
124# Writes a string to the file object.\r
125#\r
126# This function writes a string to the file object and a new line is appended\r
127# afterwards. It may optionally wraps the string for better readability.\r
128#\r
129# @File The file object to write\r
130# @String The string to be written to the file\r
131# @Wrapper Indicates whether to wrap the string\r
132#\r
133def FileWrite(File, String, Wrapper=False):\r
134 if Wrapper:\r
135 String = textwrap.fill(String, 120)\r
4afd3d04 136 File.write(String + gEndOfLine)\r
52302d4d
LG
137\r
138##\r
139# Find all the header file that the module source directly includes.\r
140#\r
141# This function scans source code to find all header files the module may\r
142# include. This is not accurate but very effective to find all the header\r
143# file the module might include with #include statement.\r
144#\r
145# @Source The source file name\r
146# @IncludePathList The list of include path to find the source file.\r
147# @IncludeFiles The dictionary of current found include files.\r
148#\r
149def FindIncludeFiles(Source, IncludePathList, IncludeFiles):\r
150 FileContents = open(Source).read()\r
151 #\r
152 # Find header files with pattern #include "XXX.h" or #include <XXX.h>\r
153 #\r
154 for Match in gIncludePattern.finditer(FileContents):\r
155 FileName = Match.group(1).strip()\r
156 for Dir in [os.path.dirname(Source)] + IncludePathList:\r
157 FullFileName = os.path.normpath(os.path.join(Dir, FileName))\r
158 if os.path.exists(FullFileName):\r
159 IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName\r
160 break\r
161\r
162 #\r
163 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)\r
164 #\r
165 for Match in gIncludePattern2.finditer(FileContents):\r
166 Key = Match.group(2)\r
167 Type = Match.group(1)\r
168 if "ARCH_PROTOCOL" in Type:\r
169 FileName = "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
170 elif "PROTOCOL" in Type:\r
171 FileName = "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
172 elif "PPI" in Type:\r
173 FileName = "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
174 elif "GUID" in Type:\r
175 FileName = "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
176 else:\r
177 continue\r
178 for Dir in IncludePathList:\r
179 FullFileName = os.path.normpath(os.path.join(Dir, FileName))\r
180 if os.path.exists(FullFileName):\r
181 IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName\r
182 break\r
183\r
64b2609f
LG
184## Split each lines in file\r
185#\r
186# This method is used to split the lines in file to make the length of each line \r
187# less than MaxLength.\r
188#\r
189# @param Content The content of file\r
190# @param MaxLength The Max Length of the line\r
191#\r
192def FileLinesSplit(Content=None, MaxLength=None):\r
193 ContentList = Content.split(TAB_LINE_BREAK)\r
194 NewContent = ''\r
195 NewContentList = []\r
196 for Line in ContentList:\r
197 while len(Line.rstrip()) > MaxLength:\r
198 LineSpaceIndex = Line.rfind(TAB_SPACE_SPLIT, 0, MaxLength)\r
199 LineSlashIndex = Line.rfind(TAB_SLASH, 0, MaxLength)\r
25918452
LG
200 LineBackSlashIndex = Line.rfind(TAB_BACK_SLASH, 0, MaxLength)\r
201 if max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex) > 0:\r
202 LineBreakIndex = max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex)\r
203 else:\r
204 LineBreakIndex = MaxLength\r
64b2609f
LG
205 NewContentList.append(Line[:LineBreakIndex])\r
206 Line = Line[LineBreakIndex:]\r
207 if Line:\r
208 NewContentList.append(Line)\r
209 for NewLine in NewContentList:\r
210 NewContent += NewLine + TAB_LINE_BREAK\r
4afd3d04
LG
211 \r
212 NewContent = NewContent.replace(TAB_LINE_BREAK, gEndOfLine).replace('\r\r\n', gEndOfLine)\r
64b2609f
LG
213 return NewContent\r
214 \r
215 \r
216 \r
e56468c0 217##\r
218# Parse binary dependency expression section\r
219#\r
220# This utility class parses the dependency expression section and translate the readable\r
221# GUID name and value.\r
222#\r
223class DepexParser(object):\r
224 ##\r
225 # Constructor function for class DepexParser\r
226 #\r
227 # This constructor function collect GUID values so that the readable\r
228 # GUID name can be translated.\r
229 #\r
230 # @param self The object pointer\r
231 # @param Wa Workspace context information\r
232 #\r
233 def __init__(self, Wa):\r
234 self._GuidDb = {}\r
0d2711a6 235 for Pa in Wa.AutoGenObjectList:\r
47fea6af 236 for Package in Pa.PackageList:\r
0d2711a6
LG
237 for Protocol in Package.Protocols:\r
238 GuidValue = GuidStructureStringToGuidString(Package.Protocols[Protocol])\r
239 self._GuidDb[GuidValue.upper()] = Protocol\r
240 for Ppi in Package.Ppis:\r
241 GuidValue = GuidStructureStringToGuidString(Package.Ppis[Ppi])\r
242 self._GuidDb[GuidValue.upper()] = Ppi\r
243 for Guid in Package.Guids:\r
244 GuidValue = GuidStructureStringToGuidString(Package.Guids[Guid])\r
245 self._GuidDb[GuidValue.upper()] = Guid\r
e56468c0 246 \r
247 ##\r
248 # Parse the binary dependency expression files.\r
249 # \r
250 # This function parses the binary dependency expression file and translate it\r
251 # to the instruction list.\r
252 #\r
253 # @param self The object pointer\r
254 # @param DepexFileName The file name of binary dependency expression file.\r
255 #\r
256 def ParseDepexFile(self, DepexFileName):\r
257 DepexFile = open(DepexFileName, "rb")\r
258 DepexStatement = []\r
259 OpCode = DepexFile.read(1)\r
260 while OpCode:\r
261 Statement = gOpCodeList[struct.unpack("B", OpCode)[0]]\r
262 if Statement in ["BEFORE", "AFTER", "PUSH"]:\r
263 GuidValue = "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \\r
2bc3256c 264 struct.unpack("=LHHBBBBBBBB", DepexFile.read(16))\r
e56468c0 265 GuidString = self._GuidDb.get(GuidValue, GuidValue)\r
266 Statement = "%s %s" % (Statement, GuidString)\r
267 DepexStatement.append(Statement)\r
47fea6af
YZ
268 OpCode = DepexFile.read(1)\r
269\r
e56468c0 270 return DepexStatement\r
271 \r
52302d4d
LG
272##\r
273# Reports library information\r
274#\r
275# This class reports the module library subsection in the build report file.\r
276#\r
277class LibraryReport(object):\r
278 ##\r
279 # Constructor function for class LibraryReport\r
280 #\r
281 # This constructor function generates LibraryReport object for\r
282 # a module.\r
283 #\r
284 # @param self The object pointer\r
285 # @param M Module context information\r
286 #\r
287 def __init__(self, M):\r
288 self.LibraryList = []\r
289 if int(str(M.AutoGenVersion), 0) >= 0x00010005:\r
290 self._EdkIIModule = True\r
291 else:\r
292 self._EdkIIModule = False\r
293\r
294 for Lib in M.DependentLibraryList:\r
295 LibInfPath = str(Lib)\r
296 LibClassList = Lib.LibraryClass[0].LibraryClass\r
297 LibConstructorList = Lib.ConstructorList\r
298 LibDesstructorList = Lib.DestructorList\r
299 LibDepexList = Lib.DepexExpression[M.Arch, M.ModuleType]\r
300 self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList))\r
301\r
302 ##\r
303 # Generate report for module library information\r
304 #\r
305 # This function generates report for the module library.\r
306 # If the module is EDKII style one, the additional library class, library\r
307 # constructor/destructor and dependency expression may also be reported.\r
308 #\r
309 # @param self The object pointer\r
310 # @param File The file object for report\r
311 #\r
312 def GenerateReport(self, File):\r
313 FileWrite(File, gSubSectionStart)\r
64b2609f 314 FileWrite(File, TAB_BRG_LIBRARY)\r
52302d4d
LG
315 if len(self.LibraryList) > 0:\r
316 FileWrite(File, gSubSectionSep)\r
317 for LibraryItem in self.LibraryList:\r
318 LibInfPath = LibraryItem[0]\r
319 FileWrite(File, LibInfPath)\r
320\r
321 #\r
322 # Report library class, library constructor and destructor for\r
323 # EDKII style module.\r
324 #\r
325 if self._EdkIIModule:\r
326 LibClass = LibraryItem[1]\r
327 EdkIILibInfo = ""\r
328 LibConstructor = " ".join(LibraryItem[2])\r
329 if LibConstructor:\r
330 EdkIILibInfo += " C = " + LibConstructor\r
331 LibDestructor = " ".join(LibraryItem[3])\r
332 if LibDestructor:\r
636f2be6 333 EdkIILibInfo += " D = " + LibDestructor\r
52302d4d
LG
334 LibDepex = " ".join(LibraryItem[4])\r
335 if LibDepex:\r
336 EdkIILibInfo += " Depex = " + LibDepex\r
337 if EdkIILibInfo:\r
338 FileWrite(File, "{%s: %s}" % (LibClass, EdkIILibInfo))\r
339 else:\r
340 FileWrite(File, "{%s}" % LibClass)\r
341\r
342 FileWrite(File, gSubSectionEnd)\r
343\r
344##\r
345# Reports dependency expression information\r
346#\r
347# This class reports the module dependency expression subsection in the build report file.\r
348#\r
349class DepexReport(object):\r
350 ##\r
351 # Constructor function for class DepexReport\r
352 #\r
353 # This constructor function generates DepexReport object for\r
354 # a module. If the module source contains the DXS file (usually EDK\r
355 # style module), it uses the dependency in DXS file; otherwise,\r
356 # it uses the dependency expression from its own INF [Depex] section\r
357 # and then merges with the ones from its dependent library INF.\r
358 #\r
359 # @param self The object pointer\r
360 # @param M Module context information\r
361 #\r
362 def __init__(self, M):\r
363 self.Depex = ""\r
47fea6af 364 self._DepexFileName = os.path.join(M.BuildDir, "OUTPUT", M.Module.BaseName + ".depex")\r
52302d4d
LG
365 ModuleType = M.ModuleType\r
366 if not ModuleType:\r
367 ModuleType = gComponentType2ModuleType.get(M.ComponentType, "")\r
636f2be6
LG
368\r
369 if ModuleType in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "UEFI_APPLICATION"]:\r
52302d4d
LG
370 return\r
371 \r
372 for Source in M.SourceFileList:\r
373 if os.path.splitext(Source.Path)[1].lower() == ".dxs":\r
374 Match = gDxsDependencyPattern.search(open(Source.Path).read())\r
375 if Match:\r
376 self.Depex = Match.group(1).strip()\r
377 self.Source = "DXS"\r
378 break\r
379 else:\r
380 self.Depex = M.DepexExpressionList.get(M.ModuleType, "")\r
381 self.ModuleDepex = " ".join(M.Module.DepexExpression[M.Arch, M.ModuleType])\r
382 if not self.ModuleDepex:\r
383 self.ModuleDepex = "(None)"\r
384\r
385 LibDepexList = []\r
386 for Lib in M.DependentLibraryList:\r
387 LibDepex = " ".join(Lib.DepexExpression[M.Arch, M.ModuleType]).strip()\r
388 if LibDepex != "":\r
389 LibDepexList.append("(" + LibDepex + ")")\r
390 self.LibraryDepex = " AND ".join(LibDepexList)\r
391 if not self.LibraryDepex:\r
392 self.LibraryDepex = "(None)"\r
393 self.Source = "INF"\r
394\r
395 ##\r
396 # Generate report for module dependency expression information\r
397 #\r
398 # This function generates report for the module dependency expression.\r
399 #\r
e56468c0 400 # @param self The object pointer\r
401 # @param File The file object for report\r
402 # @param GlobalDepexParser The platform global Dependency expression parser object\r
52302d4d 403 #\r
e56468c0 404 def GenerateReport(self, File, GlobalDepexParser):\r
52302d4d 405 if not self.Depex:\r
64b2609f
LG
406 FileWrite(File, gSubSectionStart)\r
407 FileWrite(File, TAB_DEPEX)\r
408 FileWrite(File, gSubSectionEnd)\r
52302d4d 409 return\r
52302d4d 410 FileWrite(File, gSubSectionStart)\r
e56468c0 411 if os.path.isfile(self._DepexFileName):\r
412 try:\r
413 DepexStatements = GlobalDepexParser.ParseDepexFile(self._DepexFileName)\r
414 FileWrite(File, "Final Dependency Expression (DEPEX) Instructions")\r
415 for DepexStatement in DepexStatements:\r
416 FileWrite(File, " %s" % DepexStatement)\r
417 FileWrite(File, gSubSectionSep)\r
418 except:\r
419 EdkLogger.warn(None, "Dependency expression file is corrupted", self._DepexFileName)\r
420 \r
52302d4d
LG
421 FileWrite(File, "Dependency Expression (DEPEX) from %s" % self.Source)\r
422\r
423 if self.Source == "INF":\r
424 FileWrite(File, "%s" % self.Depex, True)\r
425 FileWrite(File, gSubSectionSep)\r
426 FileWrite(File, "From Module INF: %s" % self.ModuleDepex, True)\r
427 FileWrite(File, "From Library INF: %s" % self.LibraryDepex, True)\r
428 else:\r
429 FileWrite(File, "%s" % self.Depex)\r
430 FileWrite(File, gSubSectionEnd)\r
431\r
432##\r
433# Reports dependency expression information\r
434#\r
435# This class reports the module build flags subsection in the build report file.\r
436#\r
437class BuildFlagsReport(object):\r
438 ##\r
439 # Constructor function for class BuildFlagsReport\r
440 #\r
441 # This constructor function generates BuildFlagsReport object for\r
442 # a module. It reports the build tool chain tag and all relevant\r
443 # build flags to build the module.\r
444 #\r
445 # @param self The object pointer\r
446 # @param M Module context information\r
447 #\r
448 def __init__(self, M):\r
449 BuildOptions = {}\r
450 #\r
451 # Add build flags according to source file extension so that\r
452 # irrelevant ones can be filtered out.\r
453 #\r
454 for Source in M.SourceFileList:\r
455 Ext = os.path.splitext(Source.File)[1].lower()\r
456 if Ext in [".c", ".cc", ".cpp"]:\r
457 BuildOptions["CC"] = 1\r
458 elif Ext in [".s", ".asm"]:\r
459 BuildOptions["PP"] = 1\r
460 BuildOptions["ASM"] = 1\r
461 elif Ext in [".vfr"]:\r
462 BuildOptions["VFRPP"] = 1\r
463 BuildOptions["VFR"] = 1\r
464 elif Ext in [".dxs"]:\r
465 BuildOptions["APP"] = 1\r
466 BuildOptions["CC"] = 1\r
467 elif Ext in [".asl"]:\r
468 BuildOptions["ASLPP"] = 1\r
469 BuildOptions["ASL"] = 1\r
470 elif Ext in [".aslc"]:\r
471 BuildOptions["ASLCC"] = 1\r
472 BuildOptions["ASLDLINK"] = 1\r
473 BuildOptions["CC"] = 1\r
474 elif Ext in [".asm16"]:\r
475 BuildOptions["ASMLINK"] = 1\r
476 BuildOptions["SLINK"] = 1\r
477 BuildOptions["DLINK"] = 1\r
478\r
479 #\r
480 # Save module build flags.\r
481 #\r
482 self.ToolChainTag = M.ToolChain\r
483 self.BuildFlags = {}\r
484 for Tool in BuildOptions:\r
485 self.BuildFlags[Tool + "_FLAGS"] = M.BuildOption.get(Tool, {}).get("FLAGS", "")\r
486\r
487 ##\r
488 # Generate report for module build flags information\r
489 #\r
490 # This function generates report for the module build flags expression.\r
491 #\r
492 # @param self The object pointer\r
493 # @param File The file object for report\r
494 #\r
495 def GenerateReport(self, File):\r
496 FileWrite(File, gSubSectionStart)\r
497 FileWrite(File, "Build Flags")\r
498 FileWrite(File, "Tool Chain Tag: %s" % self.ToolChainTag)\r
499 for Tool in self.BuildFlags:\r
500 FileWrite(File, gSubSectionSep)\r
501 FileWrite(File, "%s = %s" % (Tool, self.BuildFlags[Tool]), True)\r
502\r
503 FileWrite(File, gSubSectionEnd)\r
504\r
505\r
506##\r
507# Reports individual module information\r
508#\r
509# This class reports the module section in the build report file.\r
510# It comprises of module summary, module PCD, library, dependency expression,\r
511# build flags sections.\r
512#\r
513class ModuleReport(object):\r
514 ##\r
515 # Constructor function for class ModuleReport\r
516 #\r
517 # This constructor function generates ModuleReport object for\r
518 # a separate module in a platform build.\r
519 #\r
520 # @param self The object pointer\r
521 # @param M Module context information\r
522 # @param ReportType The kind of report items in the final report file\r
523 #\r
524 def __init__(self, M, ReportType):\r
525 self.ModuleName = M.Module.BaseName\r
526 self.ModuleInfPath = M.MetaFile.File\r
527 self.FileGuid = M.Guid\r
528 self.Size = 0\r
529 self.BuildTimeStamp = None\r
530 self.DriverType = ""\r
636f2be6
LG
531 if not M.IsLibrary:\r
532 ModuleType = M.ModuleType\r
533 if not ModuleType:\r
534 ModuleType = gComponentType2ModuleType.get(M.ComponentType, "")\r
535 #\r
536 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"\r
537 #\r
538 if ModuleType == "DXE_SMM_DRIVER":\r
47fea6af 539 PiSpec = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000")\r
0d2711a6 540 if int(PiSpec, 0) >= 0x0001000A:\r
636f2be6
LG
541 ModuleType = "SMM_DRIVER"\r
542 self.DriverType = gDriverTypeMap.get(ModuleType, "0x2 (FREE_FORM)")\r
52302d4d
LG
543 self.UefiSpecVersion = M.Module.Specification.get("UEFI_SPECIFICATION_VERSION", "")\r
544 self.PiSpecVersion = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "")\r
545 self.PciDeviceId = M.Module.Defines.get("PCI_DEVICE_ID", "")\r
546 self.PciVendorId = M.Module.Defines.get("PCI_VENDOR_ID", "")\r
547 self.PciClassCode = M.Module.Defines.get("PCI_CLASS_CODE", "")\r
548\r
549 self._BuildDir = M.BuildDir\r
550 self.ModulePcdSet = {}\r
551 if "PCD" in ReportType:\r
552 #\r
553 # Collect all module used PCD set: module INF referenced directly or indirectly.\r
554 # It also saves module INF default values of them in case they exist.\r
555 #\r
556 for Pcd in M.ModulePcdList + M.LibraryPcdList:\r
557 self.ModulePcdSet.setdefault((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Type), (Pcd.InfDefaultValue, Pcd.DefaultValue))\r
558\r
559 self.LibraryReport = None\r
560 if "LIBRARY" in ReportType:\r
561 self.LibraryReport = LibraryReport(M)\r
562\r
563 self.DepexReport = None\r
564 if "DEPEX" in ReportType:\r
565 self.DepexReport = DepexReport(M)\r
566\r
567 if "BUILD_FLAGS" in ReportType:\r
568 self.BuildFlagsReport = BuildFlagsReport(M)\r
569\r
570\r
571 ##\r
572 # Generate report for module information\r
573 #\r
574 # This function generates report for separate module expression\r
575 # in a platform build.\r
576 #\r
e56468c0 577 # @param self The object pointer\r
578 # @param File The file object for report\r
579 # @param GlobalPcdReport The platform global PCD report object\r
580 # @param GlobalPredictionReport The platform global Prediction report object\r
581 # @param GlobalDepexParser The platform global Dependency expression parser object\r
582 # @param ReportType The kind of report items in the final report file\r
52302d4d 583 #\r
e56468c0 584 def GenerateReport(self, File, GlobalPcdReport, GlobalPredictionReport, GlobalDepexParser, ReportType):\r
52302d4d
LG
585 FileWrite(File, gSectionStart)\r
586\r
587 FwReportFileName = os.path.join(self._BuildDir, "DEBUG", self.ModuleName + ".txt")\r
588 if os.path.isfile(FwReportFileName):\r
589 try:\r
590 FileContents = open(FwReportFileName).read()\r
591 Match = gModuleSizePattern.search(FileContents)\r
592 if Match:\r
593 self.Size = int(Match.group(1))\r
594\r
595 Match = gTimeStampPattern.search(FileContents)\r
596 if Match:\r
597 self.BuildTimeStamp = datetime.fromtimestamp(int(Match.group(1)))\r
598 except IOError:\r
599 EdkLogger.warn(None, "Fail to read report file", FwReportFileName)\r
600\r
601 FileWrite(File, "Module Summary")\r
602 FileWrite(File, "Module Name: %s" % self.ModuleName)\r
603 FileWrite(File, "Module INF Path: %s" % self.ModuleInfPath)\r
604 FileWrite(File, "File GUID: %s" % self.FileGuid)\r
605 if self.Size:\r
606 FileWrite(File, "Size: 0x%X (%.2fK)" % (self.Size, self.Size / 1024.0))\r
607 if self.BuildTimeStamp:\r
608 FileWrite(File, "Build Time Stamp: %s" % self.BuildTimeStamp)\r
609 if self.DriverType:\r
610 FileWrite(File, "Driver Type: %s" % self.DriverType)\r
611 if self.UefiSpecVersion:\r
612 FileWrite(File, "UEFI Spec Version: %s" % self.UefiSpecVersion)\r
613 if self.PiSpecVersion:\r
614 FileWrite(File, "PI Spec Version: %s" % self.PiSpecVersion)\r
615 if self.PciDeviceId:\r
616 FileWrite(File, "PCI Device ID: %s" % self.PciDeviceId)\r
617 if self.PciVendorId:\r
618 FileWrite(File, "PCI Vendor ID: %s" % self.PciVendorId)\r
619 if self.PciClassCode:\r
620 FileWrite(File, "PCI Class Code: %s" % self.PciClassCode)\r
621\r
622 FileWrite(File, gSectionSep)\r
623\r
624 if "PCD" in ReportType:\r
625 GlobalPcdReport.GenerateReport(File, self.ModulePcdSet)\r
626\r
627 if "LIBRARY" in ReportType:\r
628 self.LibraryReport.GenerateReport(File)\r
629\r
630 if "DEPEX" in ReportType:\r
e56468c0 631 self.DepexReport.GenerateReport(File, GlobalDepexParser)\r
52302d4d
LG
632\r
633 if "BUILD_FLAGS" in ReportType:\r
634 self.BuildFlagsReport.GenerateReport(File)\r
635\r
636 if "FIXED_ADDRESS" in ReportType and self.FileGuid:\r
637 GlobalPredictionReport.GenerateReport(File, self.FileGuid)\r
638\r
639 FileWrite(File, gSectionEnd)\r
640\r
641##\r
642# Reports platform and module PCD information\r
643#\r
644# This class reports the platform PCD section and module PCD subsection\r
645# in the build report file.\r
646#\r
647class PcdReport(object):\r
648 ##\r
649 # Constructor function for class PcdReport\r
650 #\r
651 # This constructor function generates PcdReport object a platform build.\r
652 # It collects the whole PCD database from platform DSC files, platform\r
653 # flash description file and package DEC files.\r
654 #\r
655 # @param self The object pointer\r
656 # @param Wa Workspace context information\r
657 #\r
658 def __init__(self, Wa):\r
659 self.AllPcds = {}\r
660 self.MaxLen = 0\r
661 if Wa.FdfProfile:\r
662 self.FdfPcdSet = Wa.FdfProfile.PcdDict\r
663 else:\r
664 self.FdfPcdSet = {}\r
665\r
666 self.ModulePcdOverride = {}\r
667 for Pa in Wa.AutoGenObjectList:\r
668 #\r
669 # Collect all platform referenced PCDs and grouped them by PCD token space\r
670 # GUID C Names\r
671 #\r
672 for Pcd in Pa.AllPcdList:\r
673 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
674 if Pcd not in PcdList:\r
675 PcdList.append(Pcd)\r
676 if len(Pcd.TokenCName) > self.MaxLen:\r
677 self.MaxLen = len(Pcd.TokenCName)\r
678\r
679 for Module in Pa.Platform.Modules.values():\r
680 #\r
681 # Collect module override PCDs\r
682 #\r
683 for ModulePcd in Module.M.ModulePcdList + Module.M.LibraryPcdList:\r
684 TokenCName = ModulePcd.TokenCName\r
685 TokenSpaceGuid = ModulePcd.TokenSpaceGuidCName\r
686 ModuleDefault = ModulePcd.DefaultValue\r
687 ModulePath = os.path.basename(Module.M.MetaFile.File)\r
688 self.ModulePcdOverride.setdefault((TokenCName, TokenSpaceGuid), {})[ModulePath] = ModuleDefault\r
689\r
690\r
691 #\r
692 # Collect PCD DEC default value.\r
693 #\r
694 self.DecPcdDefault = {}\r
0d2711a6
LG
695 for Pa in Wa.AutoGenObjectList:\r
696 for Package in Pa.PackageList:\r
697 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
698 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
699 self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue)\r
52302d4d
LG
700 #\r
701 # Collect PCDs defined in DSC common section\r
702 #\r
703 self.DscPcdDefault = {}\r
4afd3d04
LG
704 for Arch in Wa.ArchList:\r
705 Platform = Wa.BuildDatabase[Wa.MetaFile, Arch, Wa.BuildTarget, Wa.ToolChain]\r
52302d4d
LG
706 for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds:\r
707 DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue\r
40d841f6
LG
708 if DscDefaultValue:\r
709 self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue\r
52302d4d
LG
710\r
711 ##\r
712 # Generate report for PCD information\r
713 #\r
714 # This function generates report for separate module expression\r
715 # in a platform build.\r
716 #\r
717 # @param self The object pointer\r
718 # @param File The file object for report\r
719 # @param ModulePcdSet Set of all PCDs referenced by module or None for\r
720 # platform PCD report\r
721 # @param DscOverridePcds Module DSC override PCDs set\r
722 #\r
723 def GenerateReport(self, File, ModulePcdSet):\r
724 if ModulePcdSet == None:\r
725 #\r
726 # For platform global PCD section\r
727 #\r
728 FileWrite(File, gSectionStart)\r
729 FileWrite(File, "Platform Configuration Database Report")\r
730 FileWrite(File, " *P - Platform scoped PCD override in DSC file")\r
731 FileWrite(File, " *F - Platform scoped PCD override in FDF file")\r
79714906 732 FileWrite(File, " *M - Module scoped PCD override")\r
52302d4d
LG
733 FileWrite(File, gSectionSep)\r
734 else:\r
735 #\r
736 # For module PCD sub-section\r
737 #\r
738 FileWrite(File, gSubSectionStart)\r
64b2609f 739 FileWrite(File, TAB_BRG_PCD)\r
52302d4d
LG
740 FileWrite(File, gSubSectionSep)\r
741\r
742 for Key in self.AllPcds:\r
743 #\r
744 # Group PCD by their token space GUID C Name\r
745 #\r
746 First = True\r
747 for Type in self.AllPcds[Key]:\r
748 #\r
749 # Group PCD by their usage type\r
750 #\r
751 TypeName, DecType = gPcdTypeMap.get(Type, ("", Type))\r
752 for Pcd in self.AllPcds[Key][Type]:\r
753 #\r
754 # Get PCD default value and their override relationship\r
755 #\r
756 DecDefaultValue = self.DecPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, DecType))\r
757 DscDefaultValue = self.DscPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))\r
758 DscDefaultValue = self.FdfPcdSet.get((Pcd.TokenCName, Key), DscDefaultValue)\r
759 InfDefaultValue = None\r
760 \r
761 PcdValue = DecDefaultValue\r
762 if DscDefaultValue:\r
763 PcdValue = DscDefaultValue\r
764 if ModulePcdSet != None:\r
765 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type) not in ModulePcdSet:\r
766 continue\r
767 InfDefault, PcdValue = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]\r
768 if InfDefault == "":\r
769 InfDefault = None\r
770 if First:\r
771 if ModulePcdSet == None:\r
772 FileWrite(File, "")\r
773 FileWrite(File, Key)\r
774 First = False\r
775\r
776\r
777 if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):\r
778 PcdValueNumber = int(PcdValue.strip(), 0)\r
779 if DecDefaultValue == None:\r
780 DecMatch = True\r
781 else:\r
782 DecDefaultValueNumber = int(DecDefaultValue.strip(), 0)\r
783 DecMatch = (DecDefaultValueNumber == PcdValueNumber)\r
784\r
785 if InfDefaultValue == None:\r
786 InfMatch = True\r
787 else:\r
788 InfDefaultValueNumber = int(InfDefaultValue.strip(), 0)\r
789 InfMatch = (InfDefaultValueNumber == PcdValueNumber)\r
790\r
791 if DscDefaultValue == None:\r
792 DscMatch = True\r
793 else:\r
794 DscDefaultValueNumber = int(DscDefaultValue.strip(), 0)\r
795 DscMatch = (DscDefaultValueNumber == PcdValueNumber)\r
796 else:\r
797 if DecDefaultValue == None:\r
798 DecMatch = True\r
799 else:\r
d5d56f1b 800 DecMatch = (DecDefaultValue.strip() == PcdValue.strip())\r
52302d4d
LG
801\r
802 if InfDefaultValue == None:\r
803 InfMatch = True\r
804 else:\r
d5d56f1b 805 InfMatch = (InfDefaultValue.strip() == PcdValue.strip())\r
52302d4d
LG
806\r
807 if DscDefaultValue == None:\r
808 DscMatch = True\r
809 else:\r
d5d56f1b 810 DscMatch = (DscDefaultValue.strip() == PcdValue.strip())\r
52302d4d
LG
811\r
812 #\r
813 # Report PCD item according to their override relationship\r
814 #\r
815 if DecMatch and InfMatch:\r
47fea6af 816 FileWrite(File, ' %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
52302d4d
LG
817 else:\r
818 if DscMatch:\r
819 if (Pcd.TokenCName, Key) in self.FdfPcdSet:\r
47fea6af 820 FileWrite(File, ' *F %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
52302d4d 821 else:\r
47fea6af 822 FileWrite(File, ' *P %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
52302d4d 823 else:\r
47fea6af
YZ
824 FileWrite(File, ' *M %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
825\r
52302d4d
LG
826 if TypeName in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):\r
827 for SkuInfo in Pcd.SkuInfoList.values():\r
828 if TypeName in ('DYNHII', 'DEXHII'):\r
47fea6af 829 FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset))\r
52302d4d
LG
830 else:\r
831 FileWrite(File, '%*s' % (self.MaxLen + 4, SkuInfo.VpdOffset))\r
832 \r
833 if not DscMatch and DscDefaultValue != None:\r
d5d56f1b 834 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', DscDefaultValue.strip()))\r
52302d4d
LG
835\r
836 if not InfMatch and InfDefaultValue != None:\r
d5d56f1b 837 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', InfDefaultValue.strip()))\r
52302d4d
LG
838\r
839 if not DecMatch and DecDefaultValue != None:\r
d5d56f1b 840 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', DecDefaultValue.strip()))\r
52302d4d
LG
841\r
842 if ModulePcdSet == None:\r
843 ModuleOverride = self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), {})\r
844 for ModulePath in ModuleOverride:\r
845 ModuleDefault = ModuleOverride[ModulePath]\r
846 if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):\r
847 ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0)\r
848 Match = (ModulePcdDefaultValueNumber == PcdValueNumber)\r
849 else:\r
d5d56f1b 850 Match = (ModuleDefault.strip() == PcdValue.strip())\r
52302d4d
LG
851 if Match:\r
852 continue\r
d5d56f1b 853 FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 19, ModulePath, ModuleDefault.strip()))\r
52302d4d
LG
854\r
855 if ModulePcdSet == None:\r
856 FileWrite(File, gSectionEnd)\r
857 else:\r
858 FileWrite(File, gSubSectionEnd)\r
859\r
860\r
861\r
862##\r
863# Reports platform and module Prediction information\r
864#\r
865# This class reports the platform execution order prediction section and\r
866# module load fixed address prediction subsection in the build report file.\r
867#\r
868class PredictionReport(object):\r
869 ##\r
870 # Constructor function for class PredictionReport\r
871 #\r
872 # This constructor function generates PredictionReport object for the platform.\r
873 #\r
874 # @param self: The object pointer\r
875 # @param Wa Workspace context information\r
876 #\r
877 def __init__(self, Wa):\r
878 self._MapFileName = os.path.join(Wa.BuildDir, Wa.Name + ".map")\r
879 self._MapFileParsed = False\r
880 self._EotToolInvoked = False\r
881 self._FvDir = Wa.FvDir\r
882 self._EotDir = Wa.BuildDir\r
883 self._FfsEntryPoint = {}\r
884 self._GuidMap = {}\r
885 self._SourceList = []\r
886 self.FixedMapDict = {}\r
887 self.ItemList = []\r
888 self.MaxLen = 0\r
889\r
890 #\r
891 # Collect all platform reference source files and GUID C Name\r
892 #\r
893 for Pa in Wa.AutoGenObjectList:\r
894 for Module in Pa.LibraryAutoGenList + Pa.ModuleAutoGenList:\r
895 #\r
40d841f6
LG
896 # BASE typed modules are EFI agnostic, so we need not scan\r
897 # their source code to find PPI/Protocol produce or consume\r
898 # information.\r
899 #\r
900 if Module.ModuleType == "BASE":\r
901 continue\r
902 #\r
52302d4d
LG
903 # Add module referenced source files\r
904 #\r
905 self._SourceList.append(str(Module))\r
906 IncludeList = {}\r
907 for Source in Module.SourceFileList:\r
908 if os.path.splitext(str(Source))[1].lower() == ".c":\r
909 self._SourceList.append(" " + str(Source))\r
910 FindIncludeFiles(Source.Path, Module.IncludePathList, IncludeList)\r
911 for IncludeFile in IncludeList.values():\r
912 self._SourceList.append(" " + IncludeFile)\r
913\r
914 for Guid in Module.PpiList:\r
915 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.PpiList[Guid])\r
916 for Guid in Module.ProtocolList:\r
917 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.ProtocolList[Guid])\r
918 for Guid in Module.GuidList:\r
919 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.GuidList[Guid])\r
920\r
921 if Module.Guid and not Module.IsLibrary:\r
922 EntryPoint = " ".join(Module.Module.ModuleEntryPointList)\r
923 if int(str(Module.AutoGenVersion), 0) >= 0x00010005:\r
924 RealEntryPoint = "_ModuleEntryPoint"\r
925 else:\r
926 RealEntryPoint = EntryPoint\r
927 if EntryPoint == "_ModuleEntryPoint":\r
928 CCFlags = Module.BuildOption.get("CC", {}).get("FLAGS", "")\r
929 Match = gGlueLibEntryPoint.search(CCFlags)\r
930 if Match:\r
931 EntryPoint = Match.group(1)\r
932\r
933 self._FfsEntryPoint[Module.Guid.upper()] = (EntryPoint, RealEntryPoint)\r
934\r
935\r
936 #\r
937 # Collect platform firmware volume list as the input of EOT.\r
938 #\r
939 self._FvList = []\r
940 if Wa.FdfProfile:\r
941 for Fd in Wa.FdfProfile.FdDict:\r
942 for FdRegion in Wa.FdfProfile.FdDict[Fd].RegionList:\r
943 if FdRegion.RegionType != "FV":\r
944 continue\r
945 for FvName in FdRegion.RegionDataList:\r
946 if FvName in self._FvList:\r
947 continue\r
948 self._FvList.append(FvName)\r
949 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
950 for Section in Ffs.SectionList:\r
951 try:\r
952 for FvSection in Section.SectionList:\r
953 if FvSection.FvName in self._FvList:\r
954 continue\r
955 self._FvList.append(FvSection.FvName)\r
956 except AttributeError:\r
957 pass\r
958\r
959\r
960 ##\r
961 # Parse platform fixed address map files\r
962 #\r
963 # This function parses the platform final fixed address map file to get\r
964 # the database of predicted fixed address for module image base, entry point\r
965 # etc.\r
966 #\r
967 # @param self: The object pointer\r
968 #\r
969 def _ParseMapFile(self):\r
970 if self._MapFileParsed:\r
971 return\r
972 self._MapFileParsed = True\r
973 if os.path.isfile(self._MapFileName):\r
974 try:\r
975 FileContents = open(self._MapFileName).read()\r
976 for Match in gMapFileItemPattern.finditer(FileContents):\r
977 AddressType = Match.group(1)\r
978 BaseAddress = Match.group(2)\r
979 EntryPoint = Match.group(3)\r
980 Guid = Match.group(4).upper()\r
981 List = self.FixedMapDict.setdefault(Guid, [])\r
982 List.append((AddressType, BaseAddress, "*I"))\r
983 List.append((AddressType, EntryPoint, "*E"))\r
984 except:\r
985 EdkLogger.warn(None, "Cannot open file to read", self._MapFileName)\r
986\r
987 ##\r
988 # Invokes EOT tool to get the predicted the execution order.\r
989 #\r
990 # This function invokes EOT tool to calculate the predicted dispatch order\r
991 #\r
992 # @param self: The object pointer\r
993 #\r
994 def _InvokeEotTool(self):\r
995 if self._EotToolInvoked:\r
996 return\r
997\r
998 self._EotToolInvoked = True\r
999 FvFileList = []\r
1000 for FvName in self._FvList:\r
1001 FvFile = os.path.join(self._FvDir, FvName + ".Fv")\r
1002 if os.path.isfile(FvFile):\r
1003 FvFileList.append(FvFile)\r
1004\r
1005 if len(FvFileList) == 0:\r
1006 return\r
1007 #\r
1008 # Write source file list and GUID file list to an intermediate file\r
1009 # as the input for EOT tool and dispatch List as the output file\r
1010 # from EOT tool.\r
1011 #\r
1012 SourceList = os.path.join(self._EotDir, "SourceFile.txt")\r
1013 GuidList = os.path.join(self._EotDir, "GuidList.txt")\r
1014 DispatchList = os.path.join(self._EotDir, "Dispatch.txt")\r
1015\r
1016 TempFile = open(SourceList, "w+")\r
1017 for Item in self._SourceList:\r
1018 FileWrite(TempFile, Item)\r
1019 TempFile.close()\r
1020 TempFile = open(GuidList, "w+")\r
1021 for Key in self._GuidMap:\r
1022 FileWrite(TempFile, "%s %s" % (Key, self._GuidMap[Key]))\r
1023 TempFile.close()\r
1024\r
1025 try:\r
1026 from Eot.Eot import Eot\r
40d841f6 1027\r
52302d4d 1028 #\r
40d841f6 1029 # Invoke EOT tool and echo its runtime performance\r
52302d4d 1030 #\r
40d841f6 1031 EotStartTime = time.time()\r
52302d4d
LG
1032 Eot(CommandLineOption=False, SourceFileList=SourceList, GuidList=GuidList,\r
1033 FvFileList=' '.join(FvFileList), Dispatch=DispatchList, IsInit=True)\r
40d841f6
LG
1034 EotEndTime = time.time()\r
1035 EotDuration = time.strftime("%H:%M:%S", time.gmtime(int(round(EotEndTime - EotStartTime))))\r
1036 EdkLogger.quiet("EOT run time: %s\n" % EotDuration)\r
1037 \r
52302d4d
LG
1038 #\r
1039 # Parse the output of EOT tool\r
1040 #\r
1041 for Line in open(DispatchList):\r
1042 if len(Line.split()) < 4:\r
1043 continue\r
1044 (Guid, Phase, FfsName, FilePath) = Line.split()\r
1045 Symbol = self._FfsEntryPoint.get(Guid, [FfsName, ""])[0]\r
1046 if len(Symbol) > self.MaxLen:\r
1047 self.MaxLen = len(Symbol)\r
1048 self.ItemList.append((Phase, Symbol, FilePath))\r
1049 except:\r
1050 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))\r
1051 EdkLogger.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")\r
1052\r
1053\r
1054 ##\r
1055 # Generate platform execution order report\r
1056 #\r
1057 # This function generates the predicted module execution order.\r
1058 #\r
1059 # @param self The object pointer\r
1060 # @param File The file object for report\r
1061 #\r
1062 def _GenerateExecutionOrderReport(self, File):\r
1063 self._InvokeEotTool()\r
1064 if len(self.ItemList) == 0:\r
1065 return\r
1066 FileWrite(File, gSectionStart)\r
1067 FileWrite(File, "Execution Order Prediction")\r
1068 FileWrite(File, "*P PEI phase")\r
1069 FileWrite(File, "*D DXE phase")\r
1070 FileWrite(File, "*E Module INF entry point name")\r
1071 FileWrite(File, "*N Module notification function name")\r
1072\r
1073 FileWrite(File, "Type %-*s %s" % (self.MaxLen, "Symbol", "Module INF Path"))\r
1074 FileWrite(File, gSectionSep)\r
1075 for Item in self.ItemList:\r
1076 FileWrite(File, "*%sE %-*s %s" % (Item[0], self.MaxLen, Item[1], Item[2]))\r
1077\r
1078 FileWrite(File, gSectionStart)\r
1079\r
1080 ##\r
1081 # Generate Fixed Address report.\r
1082 #\r
1083 # This function generate the predicted fixed address report for a module\r
1084 # specified by Guid.\r
1085 #\r
1086 # @param self The object pointer\r
1087 # @param File The file object for report\r
1088 # @param Guid The module Guid value.\r
1089 # @param NotifyList The list of all notify function in a module\r
1090 #\r
1091 def _GenerateFixedAddressReport(self, File, Guid, NotifyList):\r
1092 self._ParseMapFile()\r
1093 FixedAddressList = self.FixedMapDict.get(Guid)\r
1094 if not FixedAddressList:\r
1095 return\r
1096\r
1097 FileWrite(File, gSubSectionStart)\r
1098 FileWrite(File, "Fixed Address Prediction")\r
1099 FileWrite(File, "*I Image Loading Address")\r
1100 FileWrite(File, "*E Entry Point Address")\r
1101 FileWrite(File, "*N Notification Function Address")\r
1102 FileWrite(File, "*F Flash Address")\r
1103 FileWrite(File, "*M Memory Address")\r
1104 FileWrite(File, "*S SMM RAM Offset")\r
1105 FileWrite(File, "TOM Top of Memory")\r
1106\r
1107 FileWrite(File, "Type Address Name")\r
1108 FileWrite(File, gSubSectionSep)\r
1109 for Item in FixedAddressList:\r
1110 Type = Item[0]\r
1111 Value = Item[1]\r
1112 Symbol = Item[2]\r
1113 if Symbol == "*I":\r
1114 Name = "(Image Base)"\r
1115 elif Symbol == "*E":\r
1116 Name = self._FfsEntryPoint.get(Guid, ["", "_ModuleEntryPoint"])[1]\r
1117 elif Symbol in NotifyList:\r
1118 Name = Symbol\r
1119 Symbol = "*N"\r
1120 else:\r
1121 continue\r
1122\r
1123 if "Flash" in Type:\r
1124 Symbol += "F"\r
1125 elif "Memory" in Type:\r
1126 Symbol += "M"\r
1127 else:\r
1128 Symbol += "S"\r
1129\r
1130 if Value[0] == "-":\r
1131 Value = "TOM" + Value\r
1132\r
1133 FileWrite(File, "%s %-16s %s" % (Symbol, Value, Name))\r
1134\r
1135 ##\r
1136 # Generate report for the prediction part\r
1137 #\r
1138 # This function generate the predicted fixed address report for a module or\r
1139 # predicted module execution order for a platform.\r
1140 # If the input Guid is None, then, it generates the predicted module execution order;\r
1141 # otherwise it generated the module fixed loading address for the module specified by\r
1142 # Guid.\r
1143 #\r
1144 # @param self The object pointer\r
1145 # @param File The file object for report\r
1146 # @param Guid The module Guid value.\r
1147 #\r
1148 def GenerateReport(self, File, Guid):\r
1149 if Guid:\r
1150 self._GenerateFixedAddressReport(File, Guid.upper(), [])\r
1151 else:\r
1152 self._GenerateExecutionOrderReport(File)\r
1153\r
1154##\r
1155# Reports FD region information\r
1156#\r
1157# This class reports the FD subsection in the build report file.\r
1158# It collects region information of platform flash device.\r
1159# If the region is a firmware volume, it lists the set of modules\r
1160# and its space information; otherwise, it only lists its region name,\r
1161# base address and size in its sub-section header.\r
1162# If there are nesting FVs, the nested FVs will list immediate after\r
1163# this FD region subsection\r
1164#\r
1165class FdRegionReport(object):\r
1166 ##\r
1167 # Discover all the nested FV name list.\r
1168 #\r
1169 # This is an internal worker function to discover the all the nested FV information\r
1170 # in the parent firmware volume. It uses deep first search algorithm recursively to\r
1171 # find all the FV list name and append them to the list.\r
1172 #\r
1173 # @param self The object pointer\r
1174 # @param FvName The name of current firmware file system\r
1175 # @param Wa Workspace context information\r
1176 #\r
1177 def _DiscoverNestedFvList(self, FvName, Wa):\r
1178 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
1179 for Section in Ffs.SectionList:\r
1180 try:\r
1181 for FvSection in Section.SectionList:\r
1182 if FvSection.FvName in self.FvList:\r
1183 continue\r
1184 self._GuidsDb[Ffs.NameGuid.upper()] = FvSection.FvName\r
1185 self.FvList.append(FvSection.FvName)\r
1186 self.FvInfo[FvSection.FvName] = ("Nested FV", 0, 0)\r
1187 self._DiscoverNestedFvList(FvSection.FvName, Wa)\r
1188 except AttributeError:\r
1189 pass\r
1190\r
1191 ##\r
1192 # Constructor function for class FdRegionReport\r
1193 #\r
1194 # This constructor function generates FdRegionReport object for a specified FdRegion.\r
1195 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware\r
1196 # volume list. This function also collects GUID map in order to dump module identification\r
1197 # in the final report.\r
1198 #\r
1199 # @param self: The object pointer\r
1200 # @param FdRegion The current FdRegion object\r
1201 # @param Wa Workspace context information\r
1202 #\r
1203 def __init__(self, FdRegion, Wa):\r
1204 self.Type = FdRegion.RegionType\r
1205 self.BaseAddress = FdRegion.Offset\r
1206 self.Size = FdRegion.Size\r
1207 self.FvList = []\r
1208 self.FvInfo = {}\r
1209 self._GuidsDb = {}\r
1210 self._FvDir = Wa.FvDir\r
1211\r
1212 #\r
1213 # If the input FdRegion is not a firmware volume,\r
1214 # we are done.\r
1215 #\r
1216 if self.Type != "FV":\r
1217 return\r
1218\r
1219 #\r
1220 # Find all nested FVs in the FdRegion\r
1221 #\r
1222 for FvName in FdRegion.RegionDataList:\r
1223 if FvName in self.FvList:\r
1224 continue\r
1225 self.FvList.append(FvName)\r
1226 self.FvInfo[FvName] = ("Fd Region", self.BaseAddress, self.Size)\r
1227 self._DiscoverNestedFvList(FvName, Wa)\r
1228\r
1229 PlatformPcds = {}\r
52302d4d
LG
1230 #\r
1231 # Collect PCDs declared in DEC files.\r
0d2711a6
LG
1232 # \r
1233 for Pa in Wa.AutoGenObjectList:\r
1234 for Package in Pa.PackageList:\r
1235 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
1236 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
1237 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue\r
52302d4d 1238 #\r
af9785a9 1239 # Collect PCDs defined in DSC file\r
52302d4d 1240 #\r
af9785a9
YZ
1241 for arch in Wa.ArchList:\r
1242 Platform = Wa.BuildDatabase[Wa.MetaFile, arch]\r
1243 for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds:\r
1244 DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue\r
1245 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue\r
52302d4d
LG
1246\r
1247 #\r
1248 # Add PEI and DXE a priori files GUIDs defined in PI specification.\r
1249 #\r
1250 self._GuidsDb["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"\r
1251 self._GuidsDb["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"\r
1252 #\r
1253 # Add ACPI table storage file\r
1254 #\r
1255 self._GuidsDb["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"\r
1256\r
1257 for Pa in Wa.AutoGenObjectList:\r
1258 for ModuleKey in Pa.Platform.Modules:\r
1259 M = Pa.Platform.Modules[ModuleKey].M\r
05cc51ad 1260 InfPath = mws.join(Wa.WorkspaceDir, M.MetaFile.File)\r
52302d4d
LG
1261 self._GuidsDb[M.Guid.upper()] = "%s (%s)" % (M.Module.BaseName, InfPath)\r
1262\r
1263 #\r
1264 # Collect the GUID map in the FV firmware volume\r
1265 #\r
1266 for FvName in self.FvList:\r
1267 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
1268 try:\r
1269 #\r
1270 # collect GUID map for binary EFI file in FDF file.\r
1271 #\r
1272 Guid = Ffs.NameGuid.upper()\r
1273 Match = gPcdGuidPattern.match(Ffs.NameGuid)\r
1274 if Match:\r
1275 PcdTokenspace = Match.group(1)\r
1276 PcdToken = Match.group(2)\r
1277 if (PcdToken, PcdTokenspace) in PlatformPcds:\r
1278 GuidValue = PlatformPcds[(PcdToken, PcdTokenspace)]\r
1279 Guid = GuidStructureByteArrayToGuidString(GuidValue).upper()\r
1280 for Section in Ffs.SectionList:\r
1281 try:\r
05cc51ad 1282 ModuleSectFile = mws.join(Wa.WorkspaceDir, Section.SectFileName)\r
52302d4d
LG
1283 self._GuidsDb[Guid] = ModuleSectFile\r
1284 except AttributeError:\r
1285 pass\r
1286 except AttributeError:\r
1287 pass\r
1288\r
1289\r
1290 ##\r
1291 # Internal worker function to generate report for the FD region\r
1292 #\r
1293 # This internal worker function to generate report for the FD region.\r
1294 # It the type is firmware volume, it lists offset and module identification.\r
1295 #\r
1296 # @param self The object pointer\r
1297 # @param File The file object for report\r
1298 # @param Title The title for the FD subsection\r
1299 # @param BaseAddress The base address for the FD region\r
1300 # @param Size The size of the FD region\r
1301 # @param FvName The FV name if the FD region is a firmware volume\r
1302 #\r
1303 def _GenerateReport(self, File, Title, Type, BaseAddress, Size=0, FvName=None):\r
1304 FileWrite(File, gSubSectionStart)\r
1305 FileWrite(File, Title)\r
1306 FileWrite(File, "Type: %s" % Type)\r
1307 FileWrite(File, "Base Address: 0x%X" % BaseAddress)\r
1308\r
1309 if self.Type == "FV":\r
1310 FvTotalSize = 0\r
1311 FvTakenSize = 0\r
1312 FvFreeSize = 0\r
b36d134f 1313 FvReportFileName = os.path.join(self._FvDir, FvName + ".Fv.txt")\r
52302d4d
LG
1314 try:\r
1315 #\r
1316 # Collect size info in the firmware volume.\r
1317 #\r
1318 FvReport = open(FvReportFileName).read()\r
1319 Match = gFvTotalSizePattern.search(FvReport)\r
1320 if Match:\r
1321 FvTotalSize = int(Match.group(1), 16)\r
1322 Match = gFvTakenSizePattern.search(FvReport)\r
1323 if Match:\r
1324 FvTakenSize = int(Match.group(1), 16)\r
1325 FvFreeSize = FvTotalSize - FvTakenSize\r
1326 #\r
1327 # Write size information to the report file.\r
1328 #\r
1329 FileWrite(File, "Size: 0x%X (%.0fK)" % (FvTotalSize, FvTotalSize / 1024.0))\r
1330 FileWrite(File, "Fv Name: %s (%.1f%% Full)" % (FvName, FvTakenSize * 100.0 / FvTotalSize))\r
1331 FileWrite(File, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize, FvTakenSize / 1024.0))\r
1332 FileWrite(File, "Free Size: 0x%X (%.0fK)" % (FvFreeSize, FvFreeSize / 1024.0))\r
1333 FileWrite(File, "Offset Module")\r
1334 FileWrite(File, gSubSectionSep)\r
1335 #\r
1336 # Write module offset and module identification to the report file.\r
1337 #\r
1338 OffsetInfo = {}\r
1339 for Match in gOffsetGuidPattern.finditer(FvReport):\r
1340 Guid = Match.group(2).upper()\r
1341 OffsetInfo[Match.group(1)] = self._GuidsDb.get(Guid, Guid)\r
1342 OffsetList = OffsetInfo.keys()\r
1343 OffsetList.sort()\r
1344 for Offset in OffsetList:\r
1345 FileWrite (File, "%s %s" % (Offset, OffsetInfo[Offset]))\r
1346 except IOError:\r
1347 EdkLogger.warn(None, "Fail to read report file", FvReportFileName)\r
1348 else:\r
1349 FileWrite(File, "Size: 0x%X (%.0fK)" % (Size, Size / 1024.0))\r
1350 FileWrite(File, gSubSectionEnd)\r
1351\r
1352 ##\r
1353 # Generate report for the FD region\r
1354 #\r
1355 # This function generates report for the FD region.\r
1356 #\r
1357 # @param self The object pointer\r
1358 # @param File The file object for report\r
1359 #\r
1360 def GenerateReport(self, File):\r
1361 if (len(self.FvList) > 0):\r
1362 for FvItem in self.FvList:\r
1363 Info = self.FvInfo[FvItem]\r
1364 self._GenerateReport(File, Info[0], "FV", Info[1], Info[2], FvItem)\r
1365 else:\r
1366 self._GenerateReport(File, "FD Region", self.Type, self.BaseAddress, self.Size)\r
1367\r
1368##\r
1369# Reports FD information\r
1370#\r
1371# This class reports the FD section in the build report file.\r
1372# It collects flash device information for a platform.\r
1373#\r
1374class FdReport(object):\r
1375 ##\r
1376 # Constructor function for class FdReport\r
1377 #\r
1378 # This constructor function generates FdReport object for a specified\r
1379 # firmware device.\r
1380 #\r
1381 # @param self The object pointer\r
1382 # @param Fd The current Firmware device object\r
1383 # @param Wa Workspace context information\r
1384 #\r
1385 def __init__(self, Fd, Wa):\r
1386 self.FdName = Fd.FdUiName\r
1387 self.BaseAddress = Fd.BaseAddress\r
1388 self.Size = Fd.Size\r
1389 self.FdRegionList = [FdRegionReport(FdRegion, Wa) for FdRegion in Fd.RegionList]\r
fb3d2279
YZ
1390 self.FvPath = os.path.join(Wa.BuildDir, "FV")\r
1391 self.VpdFilePath = os.path.join(self.FvPath, "%s.map" % Wa.Platform.VpdToolGuid)\r
1392 VpdPcdToken = 'gEfiMdeModulePkgTokenSpaceGuid'\r
1393 VpdPcdName = 'PcdVpdBaseAddress'\r
1394 self.VPDInfoList = []\r
1395 for index, FdRegion in enumerate(Fd.RegionList):\r
1396 if (VpdPcdName, VpdPcdToken) == FdRegion.PcdOffset:\r
1397 self.VPDBaseAddress = self.FdRegionList[index].BaseAddress\r
1398 self.VPDSize = self.FdRegionList[index].Size\r
1399 break\r
1400\r
1401 if os.path.isfile(self.VpdFilePath):\r
1402 fd = open(self.VpdFilePath, "r")\r
1403 Lines = fd.readlines()\r
1404 for Line in Lines:\r
1405 Line = Line.strip()\r
1406 if len(Line) == 0 or Line.startswith("#"):\r
1407 continue\r
1408 try:\r
1409 PcdName, SkuId, Offset, Size, Value = Line.split("#")[0].split("|")\r
1410 PcdName, SkuId, Offset, Size, Value = PcdName.strip(), SkuId.strip(), Offset.strip(), Size.strip(), Value.strip()\r
1411 Offset = '0x%08X' % (int(Offset, 16) + self.VPDBaseAddress)\r
1412 self.VPDInfoList.append("%s | %s | %s | %s | %s" % (PcdName, SkuId, Offset, Size, Value))\r
1413 except:\r
1414 EdkLogger.error("BuildReport", CODE_ERROR, "Fail to parse VPD information file %s" % self.VpdFilePath)\r
1415 fd.close()\r
52302d4d
LG
1416\r
1417 ##\r
1418 # Generate report for the firmware device.\r
1419 #\r
1420 # This function generates report for the firmware device.\r
1421 #\r
1422 # @param self The object pointer\r
1423 # @param File The file object for report\r
1424 #\r
1425 def GenerateReport(self, File):\r
1426 FileWrite(File, gSectionStart)\r
1427 FileWrite(File, "Firmware Device (FD)")\r
1428 FileWrite(File, "FD Name: %s" % self.FdName)\r
1429 FileWrite(File, "Base Address: %s" % self.BaseAddress)\r
1430 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.Size, self.Size / 1024.0))\r
1431 if len(self.FdRegionList) > 0:\r
1432 FileWrite(File, gSectionSep)\r
1433 for FdRegionItem in self.FdRegionList:\r
1434 FdRegionItem.GenerateReport(File)\r
1435\r
fb3d2279
YZ
1436 if len(self.VPDInfoList) > 0:\r
1437 FileWrite(File, gSubSectionStart)\r
1438 FileWrite(File, "FD VPD Region")\r
1439 FileWrite(File, "Base Address: 0x%X" % self.VPDBaseAddress)\r
1440 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.VPDSize, self.VPDSize / 1024.0))\r
1441 FileWrite(File, gSubSectionSep)\r
1442 for item in self.VPDInfoList:\r
1443 FileWrite(File, item)\r
1444 FileWrite(File, gSubSectionEnd)\r
52302d4d
LG
1445 FileWrite(File, gSectionEnd)\r
1446\r
1447\r
1448\r
1449##\r
1450# Reports platform information\r
1451#\r
1452# This class reports the whole platform information\r
1453#\r
1454class PlatformReport(object):\r
1455 ##\r
1456 # Constructor function for class PlatformReport\r
1457 #\r
1458 # This constructor function generates PlatformReport object a platform build.\r
1459 # It generates report for platform summary, flash, global PCDs and detailed\r
1460 # module information for modules involved in platform build.\r
1461 #\r
1462 # @param self The object pointer\r
1463 # @param Wa Workspace context information\r
d5d56f1b 1464 # @param MaList The list of modules in the platform build\r
52302d4d 1465 #\r
d5d56f1b 1466 def __init__(self, Wa, MaList, ReportType):\r
52302d4d
LG
1467 self._WorkspaceDir = Wa.WorkspaceDir\r
1468 self.PlatformName = Wa.Name\r
1469 self.PlatformDscPath = Wa.Platform\r
1470 self.Architectures = " ".join(Wa.ArchList)\r
1471 self.ToolChain = Wa.ToolChain\r
1472 self.Target = Wa.BuildTarget\r
1473 self.OutputPath = os.path.join(Wa.WorkspaceDir, Wa.OutputDir)\r
1474 self.BuildEnvironment = platform.platform()\r
1475\r
1476 self.PcdReport = None\r
1477 if "PCD" in ReportType:\r
1478 self.PcdReport = PcdReport(Wa)\r
1479\r
1480 self.FdReportList = []\r
d5d56f1b 1481 if "FLASH" in ReportType and Wa.FdfProfile and MaList == None:\r
52302d4d
LG
1482 for Fd in Wa.FdfProfile.FdDict:\r
1483 self.FdReportList.append(FdReport(Wa.FdfProfile.FdDict[Fd], Wa))\r
1484\r
1485 self.PredictionReport = None\r
1486 if "FIXED_ADDRESS" in ReportType or "EXECUTION_ORDER" in ReportType:\r
1487 self.PredictionReport = PredictionReport(Wa)\r
1488\r
e56468c0 1489 self.DepexParser = None\r
1490 if "DEPEX" in ReportType:\r
1491 self.DepexParser = DepexParser(Wa)\r
1492 \r
52302d4d 1493 self.ModuleReportList = []\r
d5d56f1b 1494 if MaList != None:\r
636f2be6 1495 self._IsModuleBuild = True\r
d5d56f1b
LG
1496 for Ma in MaList:\r
1497 self.ModuleReportList.append(ModuleReport(Ma, ReportType))\r
1498 else:\r
636f2be6 1499 self._IsModuleBuild = False\r
d5d56f1b
LG
1500 for Pa in Wa.AutoGenObjectList:\r
1501 for ModuleKey in Pa.Platform.Modules:\r
1502 self.ModuleReportList.append(ModuleReport(Pa.Platform.Modules[ModuleKey].M, ReportType))\r
52302d4d
LG
1503\r
1504\r
1505\r
1506 ##\r
1507 # Generate report for the whole platform.\r
1508 #\r
1509 # This function generates report for platform information.\r
1510 # It comprises of platform summary, global PCD, flash and\r
1511 # module list sections.\r
1512 #\r
1513 # @param self The object pointer\r
1514 # @param File The file object for report\r
1515 # @param BuildDuration The total time to build the modules\r
1516 # @param ReportType The kind of report items in the final report file\r
1517 #\r
1518 def GenerateReport(self, File, BuildDuration, ReportType):\r
1519 FileWrite(File, "Platform Summary")\r
1520 FileWrite(File, "Platform Name: %s" % self.PlatformName)\r
1521 FileWrite(File, "Platform DSC Path: %s" % self.PlatformDscPath)\r
1522 FileWrite(File, "Architectures: %s" % self.Architectures)\r
1523 FileWrite(File, "Tool Chain: %s" % self.ToolChain)\r
1524 FileWrite(File, "Target: %s" % self.Target)\r
1525 FileWrite(File, "Output Path: %s" % self.OutputPath)\r
1526 FileWrite(File, "Build Environment: %s" % self.BuildEnvironment)\r
1527 FileWrite(File, "Build Duration: %s" % BuildDuration)\r
1528 FileWrite(File, "Report Content: %s" % ", ".join(ReportType))\r
1529\r
636f2be6
LG
1530 if not self._IsModuleBuild:\r
1531 if "PCD" in ReportType:\r
1532 self.PcdReport.GenerateReport(File, None)\r
1533 \r
1534 if "FLASH" in ReportType:\r
1535 for FdReportListItem in self.FdReportList:\r
1536 FdReportListItem.GenerateReport(File)\r
52302d4d
LG
1537\r
1538 for ModuleReportItem in self.ModuleReportList:\r
e56468c0 1539 ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, self.DepexParser, ReportType)\r
52302d4d 1540\r
636f2be6
LG
1541 if not self._IsModuleBuild:\r
1542 if "EXECUTION_ORDER" in ReportType:\r
1543 self.PredictionReport.GenerateReport(File, None)\r
52302d4d
LG
1544\r
1545## BuildReport class\r
1546#\r
1547# This base class contain the routines to collect data and then\r
1548# applies certain format to the output report\r
1549#\r
1550class BuildReport(object):\r
1551 ##\r
1552 # Constructor function for class BuildReport\r
1553 #\r
1554 # This constructor function generates BuildReport object a platform build.\r
1555 # It generates report for platform summary, flash, global PCDs and detailed\r
1556 # module information for modules involved in platform build.\r
1557 #\r
1558 # @param self The object pointer\r
1559 # @param ReportFile The file name to save report file\r
1560 # @param ReportType The kind of report items in the final report file\r
1561 #\r
1562 def __init__(self, ReportFile, ReportType):\r
1563 self.ReportFile = ReportFile\r
1564 if ReportFile:\r
1565 self.ReportList = []\r
1566 self.ReportType = []\r
1567 if ReportType: \r
1568 for ReportTypeItem in ReportType:\r
1569 if ReportTypeItem not in self.ReportType:\r
1570 self.ReportType.append(ReportTypeItem)\r
1571 else:\r
1572 self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "FLASH", "FIXED_ADDRESS"]\r
1573 ##\r
1574 # Adds platform report to the list\r
1575 #\r
1576 # This function adds a platform report to the final report list.\r
1577 #\r
1578 # @param self The object pointer\r
1579 # @param Wa Workspace context information\r
d5d56f1b 1580 # @param MaList The list of modules in the platform build\r
52302d4d 1581 #\r
d5d56f1b 1582 def AddPlatformReport(self, Wa, MaList=None):\r
52302d4d 1583 if self.ReportFile:\r
d5d56f1b 1584 self.ReportList.append((Wa, MaList))\r
52302d4d
LG
1585\r
1586 ##\r
1587 # Generates the final report.\r
1588 #\r
1589 # This function generates platform build report. It invokes GenerateReport()\r
1590 # method for every platform report in the list.\r
1591 #\r
1592 # @param self The object pointer\r
1593 # @param BuildDuration The total time to build the modules\r
1594 #\r
1595 def GenerateReport(self, BuildDuration):\r
1596 if self.ReportFile:\r
1597 try:\r
40d841f6 1598 File = StringIO('')\r
d5d56f1b
LG
1599 for (Wa, MaList) in self.ReportList:\r
1600 PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, self.ReportType)\r
64b2609f
LG
1601 Content = FileLinesSplit(File.getvalue(), gLineMaxLength)\r
1602 SaveFileOnChange(self.ReportFile, Content, True)\r
40d841f6 1603 EdkLogger.quiet("Build report can be found at %s" % os.path.abspath(self.ReportFile))\r
52302d4d
LG
1604 except IOError:\r
1605 EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile)\r
1606 except:\r
1607 EdkLogger.error("BuildReport", CODE_ERROR, "Unknown fatal error when generating build report", ExtraData=self.ReportFile, RaiseError=False)\r
1608 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))\r
1609 File.close()\r
636f2be6 1610 \r
52302d4d
LG
1611# This acts like the main() function for the script, unless it is 'import'ed into another script.\r
1612if __name__ == '__main__':\r
1613 pass\r
1614\r