a. Supplemented file/class/function header comments
authorjwang36 <jwang36@7335b38e-4728-0410-8992-fb3ffe349368>
Wed, 31 Oct 2007 05:56:50 +0000 (05:56 +0000)
committerjwang36 <jwang36@7335b38e-4728-0410-8992-fb3ffe349368>
Wed, 31 Oct 2007 05:56:50 +0000 (05:56 +0000)
b. Changed WARN log level to be higher than INFO, i.e. WARN message will be printed out by default.
c. Added initial version of cache mechanism

git-svn-id: https://buildtools.tianocore.org/svn/buildtools/trunk/BaseTools@861 7335b38e-4728-0410-8992-fb3ffe349368

Source/Python/AutoGen/AutoGen.py
Source/Python/AutoGen/BuildInfo.py
Source/Python/AutoGen/GenDepex.py
Source/Python/AutoGen/GenMake.py
Source/Python/Common/BuildToolError.py
Source/Python/Common/EdkLogger.py
Source/Python/Common/Misc.py
Source/Python/build/build.py

index fa4f69e..2a788e4 100755 (executable)
@@ -256,9 +256,9 @@ class PlatformAutoGen:
             if A in self.BuildInfo and "MAKE" in self.BuildInfo[A].ToolPath:\r
                 Command += (self.BuildInfo[A].ToolPath["MAKE"],)\r
                 if "MAKE" in self.BuildInfo[A].ToolOption:\r
-                    newOption = self.BuildInfo[A].ToolOption["MAKE"].strip()\r
-                    if newOption != '':\r
-                      Command += (newOption,)\r
+                    NewOption = self.BuildInfo[A].ToolOption["MAKE"].strip()\r
+                    if NewOption != '':\r
+                      Command += (NewOption,)\r
                 break\r
         if len(Command) == 0:\r
             EdkLogger.error("AutoGen", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!")\r
@@ -949,7 +949,7 @@ class ModuleAutoGen(object):
             # no command, no build\r
             if RuleObject == None or RuleObject.CommandList == []:\r
                 Buildable = False\r
-                EdkLogger.warn(None, "No rule or command defined for building [%s], ignore file [%s]" % (FileType, SourceFile))\r
+                EdkLogger.verbose("No rule or command defined for building [%s], ignore file [%s]" % (FileType, SourceFile))\r
                 continue\r
 \r
             BuildFileList.append([SourceFile, FileType, RuleObject])\r
index 762ded3..d7dc052 100644 (file)
 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #
 
+## Base class of build information
+# 
+#   BuildInfo defines basic operations which are needed for it to be used as KEY
+# in dictionary. This should be used for derivation only.
+# 
 class BuildInfo(object):
-    def __init__(self, rawobj):
-        self._Key = rawobj.DescFilePath
-
+    ## Constructor
+    #
+    #   @param  MetaInfo    The raw information the build information will be 
+    #                       extracted from
+    # 
+    def __init__(self, MetaInfo):
+        self._Key = str(MetaInfo)
+
+    ## str() operator
     def __str__(self):
         return self._Key
 
+    ## "==" operator
     def __eq__(self, other):
         return self._Key == str(other)
 
+    ## hash() operator
     def __hash__(self):
         return hash(self._Key)
 
+## Build information of a module
+# 
+#   ModuleBuildInfo class is intended to gather build information for a module.
+# The input "Module" ojbect must support str() operation.
+# 
 class ModuleBuildInfo(BuildInfo):
-    def __init__(self, module):
-        BuildInfo.__init__(self, module)
-        self.Module     = module
-
-        self.Name       = module.BaseName
-        self.Guid       = module.Guid
-        self.Version    = module.Version
-        self.ModuleType = module.ModuleType
+    ## Constructor
+    #
+    #   @param  Module  The ModuleBuildClassObject object
+    # 
+    def __init__(self, Module):
+        BuildInfo.__init__(self, Module)
+        self.Module     = Module
+
+        self.Name       = Module.BaseName
+        self.Guid       = Module.Guid
+        self.Version    = Module.Version
+        self.ModuleType = Module.ModuleType
 
         self.PlatformInfo = None
         self.PackageInfo = None
@@ -78,24 +100,42 @@ class ModuleBuildInfo(BuildInfo):
         self.MacroList = []
         self.DepexList = []
 
+## Build information of a package
+# 
+#   PackageBuildInfo class is intended to gather build information for a package.
+# The input "Package" ojbect must support str() operation.
+# 
 class PackageBuildInfo(BuildInfo):
-    def __init__(self, package):
-        BuildInfo.__init__(self, package)
-        self.Package    = package
-        self.Name       = package.PackageName
-        self.Guid       = package.Guid
-        self.Version    = package.Version
+    ## Constructor
+    #
+    #   @param  Package     The PackageBuildClassObject object
+    # 
+    def __init__(self, Package):
+        BuildInfo.__init__(self, Package)
+        self.Package    = Package
+        self.Name       = Package.PackageName
+        self.Guid       = Package.Guid
+        self.Version    = Package.Version
 
         self.SourceDir = ""
         self.IncludePathList = []
 
+## Build information of a platform
+# 
+#   PlatformBuildInfo class is intended to gather build information for a platform.
+# The input "Platform" ojbect must support str() operation.
+# 
 class PlatformBuildInfo(BuildInfo):
-    def __init__(self, platform):
-        BuildInfo.__init__(self, platform)
-        self.Platform   = platform
-        self.Name       = platform.PlatformName
-        self.Guid       = platform.Guid
-        self.Version    = platform.Version
+    ## Constructor
+    #
+    #   @param  Platform    The PlatformBuildClassObject object
+    # 
+    def __init__(self, Platform):
+        BuildInfo.__init__(self, Platform)
+        self.Platform   = Platform
+        self.Name       = Platform.PlatformName
+        self.Guid       = Platform.Guid
+        self.Version    = Platform.Version
 
         self.ArchList = []
         self.ToolChain = ""
@@ -121,10 +161,11 @@ class PlatformBuildInfo(BuildInfo):
         self.NonDynamicPcdList = [] # [(TokenCName1, TokenSpaceGuidCName1), (TokenCName2, TokenSpaceGuidCName2), ...]
 
         self.ToolPath = {}          # toolcode : tool path
-        self.ToolDllPath = {}    # toolcode : lib path
+        self.ToolDllPath = {}       # toolcode : lib path
         self.ToolStaticLib = {}     # toolcode : lib path
         self.ToolChainFamily = {}   # toolcode : tool chain family
         self.BuildOption = {}       # toolcode : option
         self.OutputFlag = {}        # toolcode : output flag
-        self.IncludeFlag = {}        # toolcode : include flag
-        self.ToolOption = {}
+        self.IncludeFlag = {}       # toolcode : include flag
+        self.ToolOption = {}        # toolcode : tool option string
+
index a27c4c3..1b71492 100644 (file)
@@ -21,6 +21,7 @@ from Common.EdkIIWorkspace import CreateDirectory
 from Common.BuildToolError import *\r
 from Common.Misc import SaveFileOnChange\r
 \r
+## Mapping between module type and EFI phase\r
 gType2Phase = {\r
     "BASE"              :   None,\r
     "SEC"               :   "PEI",\r
@@ -35,6 +36,11 @@ gType2Phase = {
     "UEFI_APPLICATION"  :   "DXE",\r
 }\r
 \r
+## Convert dependency expression string into EFI internal representation\r
+# \r
+#   DependencyExpression class is used to parse dependency expression string and\r
+# convert it into its binary form.\r
+# \r
 class DependencyExpression:\r
 \r
     OpcodePriority = {\r
@@ -71,12 +77,13 @@ class DependencyExpression:
         }\r
     }\r
 \r
+    # all supported op code\r
     SupportedOpcode = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]\r
-\r
+    # op code that should not be the last one\r
     NonEndingOpcode = ["AND", "OR"]\r
-\r
+    # op code must not present at the same time\r
     ExclusiveOpcode = ["BEFORE", "AFTER"]\r
-\r
+    # op code that should be the first one if it presents\r
     AboveAllOpcode = ["SOR"]\r
 \r
     #\r
@@ -84,13 +91,18 @@ class DependencyExpression:
     #\r
     TokenPattern = re.compile("(\(|\)|\{[^{}]+\{[^{}]+\}[ ]*\}|\w+)")\r
 \r
-    def __init__(self, expression, mtype):\r
-        self.Phase = gType2Phase[mtype]\r
-        if type(expression) == type([]):\r
-            self.ExpressionString = " ".join(expression)\r
-            self.TokenList = expression\r
+    ## Constructor\r
+    # \r
+    #   @param  Expression  The list or string of dependency expression\r
+    #   @param  ModuleType  The type of the module using the dependency expression\r
+    # \r
+    def __init__(self, Expression, ModuleType):\r
+        self.Phase = gType2Phase[ModuleType]\r
+        if type(Expression) == type([]):\r
+            self.ExpressionString = " ".join(Expression)\r
+            self.TokenList = Expression\r
         else:\r
-            self.ExpressionString = expression\r
+            self.ExpressionString = Expression\r
             self.GetExpressionTokenList()\r
 \r
         self.PostfixNotation = []\r
@@ -99,9 +111,11 @@ class DependencyExpression:
         self.GetPostfixNotation()\r
         self.ValidateOpcode()\r
 \r
+    ## Split the expression string into token list\r
     def GetExpressionTokenList(self):\r
         self.TokenList = self.TokenPattern.findall(self.ExpressionString)\r
 \r
+    ## Convert token list into postfix notation\r
     def GetPostfixNotation(self):\r
         Stack = []\r
         for Token in self.TokenList:\r
@@ -130,6 +144,7 @@ class DependencyExpression:
             self.PostfixNotation.append(Stack.pop())\r
         self.PostfixNotation.append("END")\r
 \r
+    ## Validate the dependency expression\r
     def ValidateOpcode(self):\r
         for Op in self.AboveAllOpcode:\r
             if Op in self.OpcodeList and Op != self.OpcodeList[0]:\r
@@ -140,6 +155,12 @@ class DependencyExpression:
         if self.TokenList[-1] in self.NonEndingOpcode:\r
             EdkLogger.error("DepexParser", PARSER_ERROR, "Extra %s at the end of the dependency expression" % self.TokenList[-1])\r
 \r
+    ## Convert a GUID value in C structure format into its binary form\r
+    #\r
+    #   @param  Guid    The GUID value in C structure format\r
+    # \r
+    #   @retval array   The byte array representing the GUID value\r
+    # \r
     def GetGuidValue(self, Guid):\r
         GuidValueString = Guid.replace("{", "").replace("}", "").replace(" ", "")\r
         GuidValueList = GuidValueString.split(",")\r
@@ -147,6 +168,13 @@ class DependencyExpression:
             EdkLogger.error("DepexParser", PARSER_ERROR, "Invalid GUID value string or opcode: %s" % Guid)\r
         return pack("1I2H8B", *(int(value, 16) for value in GuidValueList))\r
 \r
+    ## Save the binary form of dependency expression in file\r
+    #\r
+    #   @param  File    The path of file. If None is given, put the data on console\r
+    # \r
+    #   @retval True    If the file doesn't exist or file is changed\r
+    #   @retval False   If file exists and is not changed.\r
+    # \r
     def Generate(self, File=None):\r
         Buffer = StringIO()\r
         for Item in self.PostfixNotation:\r
@@ -171,6 +199,10 @@ __version__ = "%prog Version " + versionNumber
 __copyright__ = "Copyright (c) 2007, Intel Corporation  All rights reserved."\r
 __usage__ = "%prog [options] [dependency_expression_file]"\r
 \r
+## Parse command line options\r
+#\r
+#   @retval OptionParser\r
+# \r
 def GetOptions():\r
     from optparse import OptionParser\r
 \r
@@ -192,6 +224,11 @@ def GetOptions():
     return Parser.parse_args()\r
 \r
 \r
+## Entrance method\r
+#\r
+# @retval 0     Tool was successful\r
+# @retval 1     Tool failed\r
+#\r
 def Main():\r
     Option, Input = GetOptions()\r
     if Option.ModuleType == None or Option.ModuleType not in gType2Phase:\r
@@ -222,3 +259,4 @@ def Main():
 \r
 if __name__ == '__main__':\r
     sys.exit(Main())\r
+\r
index 998bfeb..b87f414 100755 (executable)
@@ -472,16 +472,14 @@ fds: init build_fds
 # Build all libraries:\r
 #\r
 build_libraries:\r
-\t${BEGIN}\r
-\tcd $(WORKSPACE)${separator}${library_build_directory} && "$(MAKE)" $(MAKE_FLAGS) pbuild\r
+${BEGIN}\tcd $(WORKSPACE)${separator}${library_build_directory} && "$(MAKE)" $(MAKE_FLAGS) pbuild\r
 \t${END}cd $(BUILD_DIR)\r
 \r
 #\r
 # Build all modules:\r
 #\r
 build_modules:\r
-\t${BEGIN}echo Building module $(WORKSPACE)${separator}${module_build_directory}\r
-\tcd $(WORKSPACE)${separator}${module_build_directory} && "$(MAKE)" $(MAKE_FLAGS) pbuild\r
+${BEGIN}\tcd $(WORKSPACE)${separator}${module_build_directory} && "$(MAKE)" $(MAKE_FLAGS) pbuild\r
 \t${END}cd $(BUILD_DIR)\r
 \r
 #\r
index bbc228f..5aacd5d 100755 (executable)
@@ -72,6 +72,7 @@ GENFDS_ERROR = 0xF003
 MIGRATION_ERROR = 0xF010
 UNKNOWN_ERROR = 0xFFFF
 
+## Error message of each error code
 gErrorMessage = {
     FILE_NOT_FOUND          :   "File/directory not found",
     FILE_OPEN_FAILURE       :   "File open failure",
@@ -130,6 +131,7 @@ gErrorMessage = {
     UNKNOWN_ERROR           :   "Unknown error",
 }
 
+## Exception indicating a fatal error
 class FatalError(Exception):
     pass
 
index c5501aa..6e23e9f 100644 (file)
@@ -1,7 +1,22 @@
+## @file
+# This file implements the log mechanism for Python tools.
+#
+# Copyright (c) 2007, Intel Corporation
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+
+## Import modules
 import sys, os, logging
 import traceback
 from  Common.BuildToolError import *
 
+## Log level constants
 DEBUG_0 = 1
 DEBUG_1 = 2
 DEBUG_2 = 3
@@ -13,13 +28,19 @@ DEBUG_7 = 8
 DEBUG_8 = 9
 DEBUG_9 = 10
 VERBOSE = 15
-WARN    = VERBOSE
 INFO    = 20
+WARN    = 30
 QUIET   = 40
 ERROR   = 50
 
+# For validation purpose
 _LogLevels = [DEBUG_0, DEBUG_1, DEBUG_2, DEBUG_3, DEBUG_4, DEBUG_5, DEBUG_6, DEBUG_7, DEBUG_8, DEBUG_9, VERBOSE, WARN, INFO, ERROR, QUIET]
 
+#
+# Since we use different format to log different levels of message into differen
+# place (stdout or stderr), we have to use different "Logger" object to do this.
+# 
+# For DEBUG level (All DEBUG_0~9 are applicable)
 _DebugLogger = logging.getLogger("tool_debug")
 _DebugLogger.setLevel(INFO)
 _DebugChannel = logging.StreamHandler(sys.stdout)
@@ -27,20 +48,7 @@ _DebugFormatter = logging.Formatter("[%(asctime)s.%(msecs)d]: %(message)s", date
 _DebugChannel.setFormatter(_DebugFormatter)
 _DebugLogger.addHandler(_DebugChannel)
 
-##_VerboseLogger = logging.getLogger("tool_verbose")
-##_VerboseLogger.setLevel(INFO)
-##_VerboseChannel = logging.StreamHandler(sys.stdout)
-##_VerboseFormatter = logging.Formatter("%(message)s")
-##_VerboseChannel.setFormatter(_VerboseFormatter)
-##_VerboseLogger.addHandler(_VerboseChannel)
-##
-##_WarnLogger = logging.getLogger("tool_warn")
-##_WarnLogger.setLevel(INFO)
-##_WarnChannel = logging.StreamHandler(sys.stdout)
-##_WarnFormatter = logging.Formatter("%(message)s")
-##_WarnChannel.setFormatter(_WarnFormatter)
-##_WarnLogger.addHandler(_WarnChannel)
-
+# For VERBOSE, INFO, WARN level
 _InfoLogger = logging.getLogger("tool_info")
 _InfoLogger.setLevel(INFO)
 _InfoChannel = logging.StreamHandler(sys.stdout)
@@ -48,6 +56,7 @@ _InfoFormatter = logging.Formatter("%(message)s")
 _InfoChannel.setFormatter(_InfoFormatter)
 _InfoLogger.addHandler(_InfoChannel)
 
+# For ERROR level
 _ErrorLogger = logging.getLogger("tool_error")
 _ErrorLogger.setLevel(INFO)
 _ErrorCh = logging.StreamHandler(sys.stderr)
@@ -55,21 +64,32 @@ _ErrorFormatter = logging.Formatter("%(message)s")
 _ErrorCh.setFormatter(_ErrorFormatter)
 _ErrorLogger.addHandler(_ErrorCh)
 
+# String templates for ERROR/WARN/DEBUG log message
 _ErrorMessageTemplate = '\n%(tool)s...\n%(file)s(%(line)s): error %(errorcode)X: %(msg)s\n    %(extra)s'
 _ErrorMessageTemplateWithoutFile = '\n%(tool)s...\n : error %(errorcode)04X: %(msg)s\n    %(extra)s'
 _WarningMessageTemplate = '%(tool)s...\n%(file)s(%(line)s): warning: %(msg)s'
 _WarningMessageTemplateWithoutFile = '%(tool)s: : warning: %(msg)s'
 _DebugMessageTemplate = '%(file)s(%(line)s): debug: %(msg)s'
 
+# 
+# Flag used to take WARN as ERROR. 
+# By default, only ERROR message will break the tools execution.
+# 
 _WarningAsError = False
 
-
+## Log debug message
+# 
+#   @param  Level       DEBUG level (DEBUG0~9)
+#   @param  Message     Debug information
+#   @param  ExtraData   More information associated with "Message"
+# 
 def debug(Level, Message, ExtraData=None):
     if _DebugLogger.getEffectiveLevel() > Level:
         return
     if Level > DEBUG_9:
         return
 
+    # Find out the caller method information
     CallerStack = traceback.extract_stack()[-2]
     TemplateDict = {
         "file"      : CallerStack[0],
@@ -84,9 +104,24 @@ def debug(Level, Message, ExtraData=None):
 
     _DebugLogger.log(Level, LogText)
 
+## Log verbose message
+# 
+#   @param  Message     Verbose information
+# 
 def verbose(Message):
     return _InfoLogger.log(VERBOSE, Message)
 
+## Log warning message
+#
+#   Warning messages are those which might be wrong but won't fail the tool.
+# 
+#   @param  ToolName    The name of the tool. If not given, the name of caller
+#                       method will be used.
+#   @param  Message     Warning information
+#   @param  File        The name of file which caused the warning.
+#   @param  Line        The line number in the "File" which caused the warning.
+#   @param  ExtraData   More information associated with "Message"
+# 
 def warn(ToolName, Message, File=None, Line=None, ExtraData=None):
     if _InfoLogger.getEffectiveLevel() > WARN:
         return
@@ -117,11 +152,29 @@ def warn(ToolName, Message, File=None, Line=None, ExtraData=None):
 
     _InfoLogger.log(WARN, LogText)
 
+    # Raise an execption if indicated
     if _WarningAsError == True:
         raise FatalError("%s failed by warning!" % ToolName)
 
+## Log INFO message
 info    = _InfoLogger.info
 
+## Log ERROR message
+#
+#   Once an error messages is logged, the tool's execution will be broken by raising
+# an execption. If you don't want to break the execution later, you can give
+# "RaiseError" with "False" value.
+# 
+#   @param  ToolName    The name of the tool. If not given, the name of caller
+#                       method will be used.
+#   @param  ErrorCode   The error code
+#   @param  Message     Warning information
+#   @param  File        The name of file which caused the error.
+#   @param  Line        The line number in the "File" which caused the warning.
+#   @param  ExtraData   More information associated with "Message"
+#   @param  RaiseError  Raise an exception to break the tool's executuion if 
+#                       it's True. This is the default behavior.
+# 
 def error(ToolName, ErrorCode, Message=None, File=None, Line=None, ExtraData=None, RaiseError=True):
     # if no tool name given, use caller's source file name as tool name
     if ToolName == None or ToolName == "":
@@ -159,26 +212,33 @@ def error(ToolName, ErrorCode, Message=None, File=None, Line=None, ExtraData=Non
     if RaiseError:
         raise FatalError("%s failed!" % ToolName)
 
+# Log information which should be always put out
 quiet   = _ErrorLogger.error
 
+## Set log level
+#
+#   @param  Level   One of log level in _LogLevel
 def SetLevel(Level):
     if Level not in _LogLevels:
-        info("Not supported log level (%d)" % Level)
+        info("Not supported log level (%d). Use default level instead." % Level)
         Level = INFO
     _DebugLogger.setLevel(Level)
-    #_VerboseLogger.setLevel(Level)
     _InfoLogger.setLevel(Level)
-    #_WarnLogger.setLevel(Level)
     _ErrorLogger.setLevel(Level)
-    #_QuietLogger.setLevel(Level)
 
+## Get current log level
 def GetLevel():
     return _InfoLogger.getEffectiveLevel()
 
+## Raise up warning as error
 def SetWarningAsError():
     global _WarningAsError
     _WarningAsError = True
 
+## Specify a file to store the log message as well as put on console
+#
+#   @param  LogFile     The file path used to store the log message
+# 
 def SetLogFile(LogFile):
     if os.path.exists(LogFile):
         os.remove(LogFile)
@@ -187,14 +247,6 @@ def SetLogFile(LogFile):
     _Ch.setFormatter(_DebugFormatter)
     _DebugLogger.addHandler(_Ch)
 
-    #_Ch = logging.FileHandler(LogFile)
-    #_Ch.setFormatter(_VerboseFormatter)
-    #_VerboseLogger.addHandler(_Ch)
-
-    #_Ch = logging.FileHandler(LogFile)
-    #_Ch.setFormatter(_WarnFormatter)
-    #_WarnLogger.addHandler(_Ch)
-
     _Ch= logging.FileHandler(LogFile)
     _Ch.setFormatter(_InfoFormatter)
     _InfoLogger.addHandler(_Ch)
@@ -203,10 +255,6 @@ def SetLogFile(LogFile):
     _Ch.setFormatter(_ErrorFormatter)
     _ErrorLogger.addHandler(_Ch)
 
-    #
-    #_ch = logging.FileHandler(log)
-    #_ch.setFormatter(_quiet_formatter)
-    #_QuietLogger.addHandler(_ch)
-
 if __name__ == '__main__':
     pass
+
index a79793b..0546ab9 100755 (executable)
@@ -23,10 +23,16 @@ import time
 import re\r
 import cPickle\r
 \r
-from Common.BuildToolError import *\r
+from Common import EdkLogger as EdkLogger\r
+from BuildToolError import *\r
 \r
+## Regular expression used to find out place holders in string template\r
 gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE|re.UNICODE)\r
+\r
+## Dictionary used to store file time stamp for quick re-access\r
 gFileTimeStampCache = {}    # {file path : file time stamp}\r
+\r
+## Dictionary used to store dependencies of files\r
 gDependencyDatabase = {}    # arch : {file path : [dependent files list]}\r
 \r
 ## callback routine for processing variable option\r
@@ -168,7 +174,7 @@ def IsChanged(File):
 #   @retval     True            If the file content is changed and the file is renewed\r
 #   @retval     False           If the file content is the same\r
 #\r
-def SaveFileOnChange(File, Content, IsBinaryFile=False):\r
+def SaveFileOnChange(File, Content, IsBinaryFile=True):\r
     if IsBinaryFile:\r
         BinaryFlag = 'b'\r
     else:\r
@@ -176,7 +182,8 @@ def SaveFileOnChange(File, Content, IsBinaryFile=False):
     Fd = None\r
     if os.path.exists(File):\r
         Fd = open(File, "r"+BinaryFlag)\r
-        if Content == Fd.read():\r
+        FileSize = os.fstat(Fd.fileno()).st_size\r
+        if len(Content) == FileSize and Content == Fd.read():\r
             Fd.close()\r
             return False\r
         Fd.close()\r
@@ -191,13 +198,13 @@ def SaveFileOnChange(File, Content, IsBinaryFile=False):
 #   @param      Data    The object to be stored in file\r
 #   @param      File    The path of file to store the object\r
 #\r
-def ObjectDump(Data, File):\r
+def DataDump(Data, File):\r
     Fd = None\r
     try:\r
-        Fd = open(File, 'w')\r
-        cPickle.dump(Data, Fd)\r
+        Fd = open(File, 'wb')\r
+        cPickle.dump(Data, Fd, cPickle.HIGHEST_PROTOCOL)\r
     except:\r
-        EdkLogger.error("", FILE_OPEN_FAILURE, ExtraData=File)\r
+        EdkLogger.error("", FILE_OPEN_FAILURE, ExtraData=File, RaiseError=False)\r
     finally:\r
         if Fd != None:\r
             Fd.close()\r
@@ -209,13 +216,19 @@ def ObjectDump(Data, File):
 #   @retval     object  A python object\r
 #   @retval     None    If failure in file operation\r
 #\r
-def ObjectRestore(File):\r
+def DataRestore(File):\r
+    Data = None\r
+    Fd = None\r
     try:\r
-        Fd = open(File, 'r')\r
-        return cPickle.load(Fd)\r
+        Fd = open(File, 'rb')\r
+        Data = cPickle.load(Fd)\r
     except Exception, e:\r
         EdkLogger.verbose("Failed to open [%s]" % File)\r
-        return None\r
+        Data = None\r
+    finally:\r
+        if Fd != None:\r
+            Fd.close()\r
+    return Data\r
 \r
 ## A string template class\r
 #\r
@@ -453,9 +466,3 @@ class sdict(dict):
         self.__delitem__(key)\r
         return key, value\r
 \r
-#\r
-#if gFileTimeStampCache == {} and os.path.exists(".TsCache"):\r
-#    gFileTimeStampCache = ObjectRestore(".TsCache")\r
-#\r
-#if gDependencyDatabase == {} and os.path.exists(".DepCache"):\r
-#    gDependencyDatabase = ObjectRestore(".DepCache")\r
index b48eb57..3c0ab1c 100644 (file)
@@ -24,6 +24,7 @@ import traceback
 from threading import *\r
 from optparse import OptionParser\r
 from subprocess import *\r
+from Common import Misc as Utils\r
 \r
 from Common.TargetTxtClassObject import *\r
 from Common.ToolDefClassObject import *\r
@@ -32,7 +33,7 @@ from Common.DataType import *
 from AutoGen.AutoGen import *\r
 from GenFds.FdfParser import *\r
 from Common.BuildToolError import *\r
-from Common.Misc import *\r
+#from Common.Misc import *\r
 import Common.EdkLogger\r
 \r
 # Version and Copyright\r
@@ -45,6 +46,7 @@ gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'cl
 \r
 ## build configuration file\r
 gBuildConfiguration = "Conf/target.txt"\r
+gBuildCacheDir = "Conf/.cache"\r
 \r
 ## Check environment variables\r
 #\r
@@ -586,11 +588,15 @@ class Build():
         self.ToolDef      = ToolDefClassObject()\r
 \r
         # print dot charater during doing some time-consuming work\r
-        self.Progress = Progressor()\r
+        self.Progress = Utils.Progressor()\r
 \r
         # parse target.txt, tools_def.txt, and platform file\r
         self.Progress.Start("Loading build configuration")\r
+        self.RestoreBuildData()\r
         self.LoadConfiguration()\r
+        self.Progress.Stop("done!")\r
+\r
+        self.Progress.Start("Parsing platform/modules/packages")\r
         self.InitBuild()\r
         self.Progress.Stop("done!")\r
 \r
@@ -949,10 +955,30 @@ class Build():
 \r
     ## Do some clean-up works when error occurred\r
     def Relinquish(self):\r
-        Progressor.Abort()\r
+        self.DumpBuildData()\r
+        Utils.Progressor.Abort()\r
         if self.SpawnMode == True:\r
             BuildTask.Abort()\r
 \r
+    def DumpBuildData(self):\r
+        CacheDirectory = os.path.join(self.WorkspaceDir, gBuildCacheDir)\r
+        Utils.CreateDirectory(CacheDirectory)\r
+        Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))\r
+        Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))\r
+\r
+    def RestoreBuildData(self):\r
+        FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gFileTimeStampCache")\r
+        if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):\r
+            Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)\r
+            if Utils.gFileTimeStampCache == None:\r
+                Utils.gFileTimeStampCache = {}\r
+        \r
+        FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gDependencyDatabase")\r
+        if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):\r
+            Utils.gDependencyDatabase = Utils.DataRestore(FilePath)\r
+            if Utils.gDependencyDatabase == None:\r
+                Utils.gDependencyDatabase = {}\r
+\r
 ## Parse command line options\r
 #\r
 # Using standard Python module optparse to parse command line option of this tool.\r
@@ -1067,6 +1093,7 @@ def Main():
                         Option.ToolChain, Option.BuildTarget, Option.FdfFile, Option.RomImage, Option.FvImage,\r
                         Option.MakefileType, Option.SpawnMode, Option.ThreadNumber)\r
         MyBuild.Launch()\r
+        MyBuild.DumpBuildData()\r
     except BaseException, X:\r
         if MyBuild != None:\r
             # for multi-thread build exits safely\r
@@ -1078,7 +1105,7 @@ def Main():
             EdkLogger.quiet(str(X))\r
         ReturnCode = 1\r
     finally:\r
-        Progressor.Abort()\r
+        Utils.Progressor.Abort()\r
 \r
     FinishTime = time.clock()\r
     BuildDuration = time.strftime("%M:%S", time.gmtime(int(round(FinishTime - StartTime))))\r