]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/Python/build/build.py
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / BaseTools / Source / Python / build / build.py
old mode 100644 (file)
new mode 100755 (executable)
index 4aca280..51fb1f4
@@ -2,71 +2,71 @@
 # build a platform or a module\r
 #\r
 #  Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>\r
-#  Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
+#  Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR>\r
+#  Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>\r
+#  Copyright (c) 2020 - 2021, ARM Limited. All rights reserved.<BR>\r
 #\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
-#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 #\r
 \r
 ##\r
 # Import Modules\r
 #\r
-import Common.LongFilePathOs as os\r
-import re\r
-import StringIO\r
+from __future__ import print_function\r
+from __future__ import absolute_import\r
+import os.path as path\r
 import sys\r
+import os\r
+import re\r
 import glob\r
 import time\r
 import platform\r
 import traceback\r
-import encodings.ascii\r
-import itertools\r
 import multiprocessing\r
-\r
-from struct import *\r
-from threading import *\r
-from optparse import OptionParser\r
-from subprocess import *\r
+from threading import Thread,Event,BoundedSemaphore\r
+import threading\r
+from linecache import getlines\r
+from subprocess import Popen,PIPE, STDOUT\r
+from collections import OrderedDict, defaultdict\r
+\r
+from AutoGen.PlatformAutoGen import PlatformAutoGen\r
+from AutoGen.ModuleAutoGen import ModuleAutoGen\r
+from AutoGen.WorkspaceAutoGen import WorkspaceAutoGen\r
+from AutoGen.AutoGenWorker import AutoGenWorkerInProcess,AutoGenManager,\\r
+    LogAgent\r
+from AutoGen import GenMake\r
 from Common import Misc as Utils\r
 \r
-from Common.LongFilePathSupport import OpenLongFilePath as open\r
-from Common.LongFilePathSupport import LongFilePath\r
-from Common.TargetTxtClassObject import *\r
-from Common.ToolDefClassObject import *\r
-from Common.DataType import *\r
-from Common.BuildVersion import gBUILD_VERSION\r
-from AutoGen.AutoGen import *\r
-from Common.BuildToolError import *\r
-from Workspace.WorkspaceDatabase import *\r
+from Common.TargetTxtClassObject import TargetTxtDict\r
+from Common.ToolDefClassObject import ToolDefDict\r
+from buildoptions import MyOptionParser\r
+from Common.Misc import PathClass,SaveFileOnChange,RemoveDirectory\r
+from Common.StringUtils import NormPath\r
 from Common.MultipleWorkspace import MultipleWorkspace as mws\r
+from Common.BuildToolError import *\r
+from Common.DataType import *\r
+import Common.EdkLogger as EdkLogger\r
+\r
+from Workspace.WorkspaceDatabase import BuildDB\r
 \r
 from BuildReport import BuildReport\r
-from GenPatchPcdTable.GenPatchPcdTable import *\r
-from PatchPcdValue.PatchPcdValue import *\r
+from GenPatchPcdTable.GenPatchPcdTable import PeImageClass,parsePcdInfoFromMapFile\r
+from PatchPcdValue.PatchPcdValue import PatchBinaryFile\r
 \r
-import Common.EdkLogger\r
 import Common.GlobalData as GlobalData\r
-from GenFds.GenFds import GenFds\r
-\r
-from collections import OrderedDict\r
-\r
-# Version and Copyright\r
-VersionNumber = "0.60" + ' ' + gBUILD_VERSION\r
-__version__ = "%prog Version " + VersionNumber\r
-__copyright__ = "Copyright (c) 2007 - 2017, Intel Corporation  All rights reserved."\r
+from GenFds.GenFds import GenFds, GenFdsApi\r
+import multiprocessing as mp\r
+from multiprocessing import Manager\r
+from AutoGen.DataPipe import MemoryDataPipe\r
+from AutoGen.ModuleAutoGenHelper import WorkSpaceInfo, PlatformInfo\r
+from GenFds.FdfParser import FdfParser\r
+from AutoGen.IncludesAutoGen import IncludesAutoGen\r
+from GenFds.GenFds import resetFdsGlobalVariable\r
+from AutoGen.AutoGen import CalculatePriorityValue\r
 \r
 ## standard targets of build command\r
 gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']\r
 \r
-## build configuration file\r
-gBuildConfiguration = "target.txt"\r
-gToolsDefinition = "tools_def.txt"\r
-\r
 TemporaryTablePattern = re.compile(r'^_\d+_\d+_[a-fA-F0-9]+$')\r
 TmpTableDict = {}\r
 \r
@@ -76,7 +76,7 @@ TmpTableDict = {}
 #   Otherwise, False is returned\r
 #\r
 def IsToolInPath(tool):\r
-    if os.environ.has_key('PATHEXT'):\r
+    if 'PATHEXT' in os.environ:\r
         extns = os.environ['PATHEXT'].split(os.path.pathsep)\r
     else:\r
         extns = ('',)\r
@@ -105,81 +105,25 @@ def CheckEnvVariable():
 \r
     WorkspaceDir = os.path.normcase(os.path.normpath(os.environ["WORKSPACE"]))\r
     if not os.path.exists(WorkspaceDir):\r
-        EdkLogger.error("build", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData="%s" % WorkspaceDir)\r
+        EdkLogger.error("build", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData=WorkspaceDir)\r
     elif ' ' in WorkspaceDir:\r
         EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path",\r
                         ExtraData=WorkspaceDir)\r
     os.environ["WORKSPACE"] = WorkspaceDir\r
-    \r
+\r
     # set multiple workspace\r
     PackagesPath = os.getenv("PACKAGES_PATH")\r
     mws.setWs(WorkspaceDir, PackagesPath)\r
     if mws.PACKAGES_PATH:\r
         for Path in mws.PACKAGES_PATH:\r
             if not os.path.exists(Path):\r
-                EdkLogger.error("build", FILE_NOT_FOUND, "One Path in PACKAGES_PATH doesn't exist", ExtraData="%s" % Path)\r
+                EdkLogger.error("build", FILE_NOT_FOUND, "One Path in PACKAGES_PATH doesn't exist", ExtraData=Path)\r
             elif ' ' in Path:\r
                 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in PACKAGES_PATH", ExtraData=Path)\r
 \r
-    #\r
-    # Check EFI_SOURCE (Edk build convention). EDK_SOURCE will always point to ECP\r
-    #\r
-    if "ECP_SOURCE" not in os.environ:\r
-        os.environ["ECP_SOURCE"] = mws.join(WorkspaceDir, GlobalData.gEdkCompatibilityPkg)\r
-    if "EFI_SOURCE" not in os.environ:\r
-        os.environ["EFI_SOURCE"] = os.environ["ECP_SOURCE"]\r
-    if "EDK_SOURCE" not in os.environ:\r
-        os.environ["EDK_SOURCE"] = os.environ["ECP_SOURCE"]\r
 \r
-    #\r
-    # Unify case of characters on case-insensitive systems\r
-    #\r
-    EfiSourceDir = os.path.normcase(os.path.normpath(os.environ["EFI_SOURCE"]))\r
-    EdkSourceDir = os.path.normcase(os.path.normpath(os.environ["EDK_SOURCE"]))\r
-    EcpSourceDir = os.path.normcase(os.path.normpath(os.environ["ECP_SOURCE"]))\r
-\r
-    os.environ["EFI_SOURCE"] = EfiSourceDir\r
-    os.environ["EDK_SOURCE"] = EdkSourceDir\r
-    os.environ["ECP_SOURCE"] = EcpSourceDir\r
     os.environ["EDK_TOOLS_PATH"] = os.path.normcase(os.environ["EDK_TOOLS_PATH"])\r
 \r
-    if not os.path.exists(EcpSourceDir):\r
-        EdkLogger.verbose("ECP_SOURCE = %s doesn't exist. Edk modules could not be built." % EcpSourceDir)\r
-    elif ' ' in EcpSourceDir:\r
-        EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in ECP_SOURCE path",\r
-                        ExtraData=EcpSourceDir)\r
-    if not os.path.exists(EdkSourceDir):\r
-        if EdkSourceDir == EcpSourceDir:\r
-            EdkLogger.verbose("EDK_SOURCE = %s doesn't exist. Edk modules could not be built." % EdkSourceDir)\r
-        else:\r
-            EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE does not exist",\r
-                            ExtraData=EdkSourceDir)\r
-    elif ' ' in EdkSourceDir:\r
-        EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EDK_SOURCE path",\r
-                        ExtraData=EdkSourceDir)\r
-    if not os.path.exists(EfiSourceDir):\r
-        if EfiSourceDir == EcpSourceDir:\r
-            EdkLogger.verbose("EFI_SOURCE = %s doesn't exist. Edk modules could not be built." % EfiSourceDir)\r
-        else:\r
-            EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE does not exist",\r
-                            ExtraData=EfiSourceDir)\r
-    elif ' ' in EfiSourceDir:\r
-        EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EFI_SOURCE path",\r
-                        ExtraData=EfiSourceDir)\r
-\r
-    # check those variables on single workspace case\r
-    if not PackagesPath:\r
-        # change absolute path to relative path to WORKSPACE\r
-        if EfiSourceDir.upper().find(WorkspaceDir.upper()) != 0:\r
-            EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE is not under WORKSPACE",\r
-                            ExtraData="WORKSPACE = %s\n    EFI_SOURCE = %s" % (WorkspaceDir, EfiSourceDir))\r
-        if EdkSourceDir.upper().find(WorkspaceDir.upper()) != 0:\r
-            EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE is not under WORKSPACE",\r
-                            ExtraData="WORKSPACE = %s\n    EDK_SOURCE = %s" % (WorkspaceDir, EdkSourceDir))\r
-        if EcpSourceDir.upper().find(WorkspaceDir.upper()) != 0:\r
-            EdkLogger.error("build", PARAMETER_INVALID, "ECP_SOURCE is not under WORKSPACE",\r
-                            ExtraData="WORKSPACE = %s\n    ECP_SOURCE = %s" % (WorkspaceDir, EcpSourceDir))\r
-\r
     # check EDK_TOOLS_PATH\r
     if "EDK_TOOLS_PATH" not in os.environ:\r
         EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",\r
@@ -191,16 +135,10 @@ def CheckEnvVariable():
                         ExtraData="PATH")\r
 \r
     GlobalData.gWorkspace = WorkspaceDir\r
-    GlobalData.gEfiSource = EfiSourceDir\r
-    GlobalData.gEdkSource = EdkSourceDir\r
-    GlobalData.gEcpSource = EcpSourceDir\r
 \r
     GlobalData.gGlobalDefines["WORKSPACE"]  = WorkspaceDir\r
-    GlobalData.gGlobalDefines["EFI_SOURCE"] = EfiSourceDir\r
-    GlobalData.gGlobalDefines["EDK_SOURCE"] = EdkSourceDir\r
-    GlobalData.gGlobalDefines["ECP_SOURCE"] = EcpSourceDir\r
     GlobalData.gGlobalDefines["EDK_TOOLS_PATH"] = os.environ["EDK_TOOLS_PATH"]\r
-    \r
+\r
 ## Get normalized file path\r
 #\r
 # Convert the path to be local format, and remove the WORKSPACE path at the\r
@@ -238,34 +176,47 @@ def NormFile(FilePath, Workspace):
 # @param  To        The stream message put on\r
 # @param  ExitFlag  The flag used to indicate stopping reading\r
 #\r
-def ReadMessage(From, To, ExitFlag):\r
+def ReadMessage(From, To, ExitFlag,MemTo=None):\r
     while True:\r
         # read one line a time\r
         Line = From.readline()\r
         # empty string means "end"\r
-        if Line is not None and Line != "":\r
-            To(Line.rstrip())\r
+        if Line is not None and Line != b"":\r
+            LineStr = Line.rstrip().decode(encoding='utf-8', errors='ignore')\r
+            if MemTo is not None:\r
+                if "Note: including file:" ==  LineStr.lstrip()[:21]:\r
+                    MemTo.append(LineStr)\r
+                else:\r
+                    To(LineStr)\r
+                    MemTo.append(LineStr)\r
+            else:\r
+                To(LineStr)\r
         else:\r
             break\r
-        if ExitFlag.isSet():\r
+        if ExitFlag.is_set():\r
             break\r
 \r
+class MakeSubProc(Popen):\r
+    def __init__(self,*args, **argv):\r
+        super(MakeSubProc,self).__init__(*args, **argv)\r
+        self.ProcOut = []\r
+\r
 ## Launch an external program\r
 #\r
 # This method will call subprocess.Popen to execute an external program with\r
 # given options in specified directory. Because of the dead-lock issue during\r
-# redirecting output of the external program, threads are used to to do the\r
+# redirecting output of the external program, threads are used to do the\r
 # redirection work.\r
 #\r
 # @param  Command               A list or string containing the call of the program\r
 # @param  WorkingDir            The directory in which the program will be running\r
 #\r
-def LaunchCommand(Command, WorkingDir):\r
+def LaunchCommand(Command, WorkingDir,ModuleAuto = None):\r
     BeginTime = time.time()\r
     # if working directory doesn't exist, Popen() will raise an exception\r
     if not os.path.isdir(WorkingDir):\r
         EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=WorkingDir)\r
-    \r
+\r
     # Command is used as the first Argument in following Popen().\r
     # It could be a string or sequence. We find that if command is a string in following Popen(),\r
     # ubuntu may fail with an error message that the command is not found.\r
@@ -279,22 +230,17 @@ def LaunchCommand(Command, WorkingDir):
     EndOfProcedure = None\r
     try:\r
         # launch the command\r
-        Proc = Popen(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir, bufsize=-1, shell=True)\r
+        Proc = MakeSubProc(Command, stdout=PIPE, stderr=STDOUT, env=os.environ, cwd=WorkingDir, bufsize=-1, shell=True)\r
 \r
         # launch two threads to read the STDOUT and STDERR\r
         EndOfProcedure = Event()\r
         EndOfProcedure.clear()\r
         if Proc.stdout:\r
-            StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure))\r
-            StdOutThread.setName("STDOUT-Redirector")\r
-            StdOutThread.setDaemon(False)\r
+            StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure,Proc.ProcOut))\r
+            StdOutThread.name = "STDOUT-Redirector"\r
+            StdOutThread.daemon = False\r
             StdOutThread.start()\r
 \r
-        if Proc.stderr:\r
-            StdErrThread = Thread(target=ReadMessage, args=(Proc.stderr, EdkLogger.quiet, EndOfProcedure))\r
-            StdErrThread.setName("STDERR-Redirector")\r
-            StdErrThread.setDaemon(False)\r
-            StdErrThread.start()\r
 \r
         # waiting for program exit\r
         Proc.wait()\r
@@ -304,18 +250,16 @@ def LaunchCommand(Command, WorkingDir):
         if EndOfProcedure is not None:\r
             EndOfProcedure.set()\r
         if Proc is None:\r
-            if type(Command) != type(""):\r
+            if not isinstance(Command, type("")):\r
                 Command = " ".join(Command)\r
             EdkLogger.error("build", COMMAND_FAILURE, "Failed to start command", ExtraData="%s [%s]" % (Command, WorkingDir))\r
 \r
     if Proc.stdout:\r
         StdOutThread.join()\r
-    if Proc.stderr:\r
-        StdErrThread.join()\r
 \r
     # check the return code of the program\r
     if Proc.returncode != 0:\r
-        if type(Command) != type(""):\r
+        if not isinstance(Command, type("")):\r
             Command = " ".join(Command)\r
         # print out the Response file and its content when make failure\r
         RespFile = os.path.join(WorkingDir, 'OUTPUT', 'respfilelist.txt')\r
@@ -326,6 +270,16 @@ def LaunchCommand(Command, WorkingDir):
             EdkLogger.info(RespContent)\r
 \r
         EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir))\r
+    if ModuleAuto:\r
+        iau = IncludesAutoGen(WorkingDir,ModuleAuto)\r
+        if ModuleAuto.ToolChainFamily == TAB_COMPILER_MSFT:\r
+            iau.CreateDepsFileForMsvc(Proc.ProcOut)\r
+        else:\r
+            iau.UpdateDepsFileforNonMsvc()\r
+        iau.UpdateDepsFileforTrim()\r
+        iau.CreateModuleDeps()\r
+        iau.CreateDepsInclude()\r
+        iau.CreateDepsTarget()\r
     return "%dms" % (int(round((time.time() - BeginTime) * 1000)))\r
 \r
 ## The smallest unit that can be built in multi-thread build mode\r
@@ -377,7 +331,8 @@ class BuildUnit:
     #   @param  Other       The other BuildUnit object compared to\r
     #\r
     def __eq__(self, Other):\r
-        return Other is not None and self.BuildObject == Other.BuildObject \\r
+        return Other and self.BuildObject == Other.BuildObject \\r
+                and Other.BuildObject \\r
                 and self.BuildObject.Arch == Other.BuildObject.Arch\r
 \r
     ## hash() method\r
@@ -407,9 +362,9 @@ class ModuleMakeUnit(BuildUnit):
     #   @param  Obj         The ModuleAutoGen object the build is working on\r
     #   @param  Target      The build target name, one of gSupportedTarget\r
     #\r
-    def __init__(self, Obj, Target):\r
-        Dependency = [ModuleMakeUnit(La, Target) for La in Obj.LibraryAutoGenList]\r
-        BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)\r
+    def __init__(self, Obj, BuildCommand,Target):\r
+        Dependency = [ModuleMakeUnit(La, BuildCommand,Target) for La in Obj.LibraryAutoGenList]\r
+        BuildUnit.__init__(self, Obj, BuildCommand, Target, Dependency, Obj.MakeFileDir)\r
         if Target in [None, "", "all"]:\r
             self.Target = "tbuild"\r
 \r
@@ -428,10 +383,10 @@ class PlatformMakeUnit(BuildUnit):
     #   @param  Obj         The PlatformAutoGen object the build is working on\r
     #   @param  Target      The build target name, one of gSupportedTarget\r
     #\r
-    def __init__(self, Obj, Target):\r
-        Dependency = [ModuleMakeUnit(Lib, Target) for Lib in self.BuildObject.LibraryAutoGenList]\r
-        Dependency.extend([ModuleMakeUnit(Mod, Target) for Mod in self.BuildObject.ModuleAutoGenList])\r
-        BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)\r
+    def __init__(self, Obj, BuildCommand, Target):\r
+        Dependency = [ModuleMakeUnit(Lib, BuildCommand, Target) for Lib in self.BuildObject.LibraryAutoGenList]\r
+        Dependency.extend([ModuleMakeUnit(Mod, BuildCommand,Target) for Mod in self.BuildObject.ModuleAutoGenList])\r
+        BuildUnit.__init__(self, Obj, BuildCommand, Target, Dependency, Obj.MakeFileDir)\r
 \r
 ## The class representing the task of a module build or platform build\r
 #\r
@@ -474,8 +429,8 @@ class BuildTask:
     @staticmethod\r
     def StartScheduler(MaxThreadNumber, ExitFlag):\r
         SchedulerThread = Thread(target=BuildTask.Scheduler, args=(MaxThreadNumber, ExitFlag))\r
-        SchedulerThread.setName("Build-Task-Scheduler")\r
-        SchedulerThread.setDaemon(False)\r
+        SchedulerThread.name = "Build-Task-Scheduler"\r
+        SchedulerThread.daemon = False\r
         SchedulerThread.start()\r
         # wait for the scheduler to be started, especially useful in Linux\r
         while not BuildTask.IsOnGoing():\r
@@ -497,13 +452,13 @@ class BuildTask:
             # indicated to do so, or there's error in running thread\r
             #\r
             while (len(BuildTask._PendingQueue) > 0 or len(BuildTask._ReadyQueue) > 0 \\r
-                   or not ExitFlag.isSet()) and not BuildTask._ErrorFlag.isSet():\r
+                   or not ExitFlag.is_set()) and not BuildTask._ErrorFlag.is_set():\r
                 EdkLogger.debug(EdkLogger.DEBUG_8, "Pending Queue (%d), Ready Queue (%d)"\r
                                 % (len(BuildTask._PendingQueue), len(BuildTask._ReadyQueue)))\r
 \r
                 # get all pending tasks\r
                 BuildTask._PendingQueueLock.acquire()\r
-                BuildObjectList = BuildTask._PendingQueue.keys()\r
+                BuildObjectList = list(BuildTask._PendingQueue.keys())\r
                 #\r
                 # check if their dependency is resolved, and if true, move them\r
                 # into ready queue\r
@@ -515,7 +470,7 @@ class BuildTask:
                 BuildTask._PendingQueueLock.release()\r
 \r
                 # launch build thread until the maximum number of threads is reached\r
-                while not BuildTask._ErrorFlag.isSet():\r
+                while not BuildTask._ErrorFlag.is_set():\r
                     # empty ready queue, do nothing further\r
                     if len(BuildTask._ReadyQueue) == 0:\r
                         break\r
@@ -524,8 +479,7 @@ class BuildTask:
                     BuildTask._Thread.acquire(True)\r
 \r
                     # start a new build thread\r
-                    Bo = BuildTask._ReadyQueue.keys()[0]\r
-                    Bt = BuildTask._ReadyQueue.pop(Bo)\r
+                    Bo, Bt = BuildTask._ReadyQueue.popitem()\r
 \r
                     # move into running queue\r
                     BuildTask._RunningQueueLock.acquire()\r
@@ -540,17 +494,17 @@ class BuildTask:
                 time.sleep(0.01)\r
 \r
             # wait for all running threads exit\r
-            if BuildTask._ErrorFlag.isSet():\r
+            if BuildTask._ErrorFlag.is_set():\r
                 EdkLogger.quiet("\nWaiting for all build threads exit...")\r
-            # while not BuildTask._ErrorFlag.isSet() and \\r
+            # while not BuildTask._ErrorFlag.is_set() and \\r
             while len(BuildTask._RunningQueue) > 0:\r
                 EdkLogger.verbose("Waiting for thread ending...(%d)" % len(BuildTask._RunningQueue))\r
-                EdkLogger.debug(EdkLogger.DEBUG_8, "Threads [%s]" % ", ".join([Th.getName() for Th in threading.enumerate()]))\r
+                EdkLogger.debug(EdkLogger.DEBUG_8, "Threads [%s]" % ", ".join(Th.name for Th in threading.enumerate()))\r
                 # avoid tense loop\r
                 time.sleep(0.1)\r
-        except BaseException, X:\r
+        except BaseException as X:\r
             #\r
-            # TRICK: hide the output of threads left runing, so that the user can\r
+            # TRICK: hide the output of threads left running, so that the user can\r
             #        catch the error message easily\r
             #\r
             EdkLogger.SetLevel(EdkLogger.ERROR)\r
@@ -573,7 +527,7 @@ class BuildTask:
     #\r
     @staticmethod\r
     def IsOnGoing():\r
-        return not BuildTask._SchedulerStopped.isSet()\r
+        return not BuildTask._SchedulerStopped.is_set()\r
 \r
     ## Abort the build\r
     @staticmethod\r
@@ -589,7 +543,7 @@ class BuildTask:
     #\r
     @staticmethod\r
     def HasError():\r
-        return BuildTask._ErrorFlag.isSet()\r
+        return BuildTask._ErrorFlag.is_set()\r
 \r
     ## Get error message in running thread\r
     #\r
@@ -661,7 +615,7 @@ class BuildTask:
     #\r
     def AddDependency(self, Dependency):\r
         for Dep in Dependency:\r
-            if not Dep.BuildObject.IsBinaryModule:\r
+            if not Dep.BuildObject.IsBinaryModule and not Dep.BuildObject.CanSkipbyCache(GlobalData.gModuleCacheHit):\r
                 self.DependencyList.append(BuildTask.New(Dep))    # BuildTask list\r
 \r
     ## The thread wrapper of LaunchCommand function\r
@@ -671,14 +625,22 @@ class BuildTask:
     #\r
     def _CommandThread(self, Command, WorkingDir):\r
         try:\r
-            self.BuildItem.BuildObject.BuildTime = LaunchCommand(Command, WorkingDir)\r
+            self.BuildItem.BuildObject.BuildTime = LaunchCommand(Command, WorkingDir,self.BuildItem.BuildObject)\r
             self.CompleteFlag = True\r
+\r
+            # Run hash operation post dependency to account for libs\r
+            # Run if --hash or --binary-destination\r
+            if GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:\r
+                self.BuildItem.BuildObject.GenModuleHash()\r
+            if GlobalData.gBinCacheDest:\r
+                self.BuildItem.BuildObject.GenCMakeHash()\r
+\r
         except:\r
             #\r
-            # TRICK: hide the output of threads left runing, so that the user can\r
+            # TRICK: hide the output of threads left running, so that the user can\r
             #        catch the error message easily\r
             #\r
-            if not BuildTask._ErrorFlag.isSet():\r
+            if not BuildTask._ErrorFlag.is_set():\r
                 GlobalData.gBuildingModule = "%s [%s, %s, %s]" % (str(self.BuildItem.BuildObject),\r
                                                                   self.BuildItem.BuildObject.Arch,\r
                                                                   self.BuildItem.BuildObject.ToolChain,\r
@@ -687,7 +649,8 @@ class BuildTask:
             EdkLogger.SetLevel(EdkLogger.ERROR)\r
             BuildTask._ErrorFlag.set()\r
             BuildTask._ErrorMessage = "%s broken\n    %s [%s]" % \\r
-                                      (threading.currentThread().getName(), Command, WorkingDir)\r
+                                      (threading.current_thread().name, Command, WorkingDir)\r
+\r
         # indicate there's a thread is available for another build task\r
         BuildTask._RunningQueueLock.acquire()\r
         BuildTask._RunningQueue.pop(self.BuildItem)\r
@@ -700,8 +663,8 @@ class BuildTask:
         EdkLogger.quiet("Building ... %s" % repr(self.BuildItem))\r
         Command = self.BuildItem.BuildCommand + [self.BuildItem.Target]\r
         self.BuildTread = Thread(target=self._CommandThread, args=(Command, self.BuildItem.WorkingDir))\r
-        self.BuildTread.setName("build thread")\r
-        self.BuildTread.setDaemon(False)\r
+        self.BuildTread.name = "build thread"\r
+        self.BuildTread.daemon = False\r
         self.BuildTread.start()\r
 \r
 ## The class contains the information related to EFI image\r
@@ -725,7 +688,7 @@ class PeImageInfo():
         self.OutputDir        = OutputDir\r
         self.DebugDir         = DebugDir\r
         self.Image            = ImageClass\r
-        self.Image.Size       = (self.Image.Size / 0x1000 + 1) * 0x1000\r
+        self.Image.Size       = (self.Image.Size // 0x1000 + 1) * 0x1000\r
 \r
 ## The class implementing the EDK2 build process\r
 #\r
@@ -747,7 +710,7 @@ class Build():
     #   @param  WorkspaceDir        The directory of workspace\r
     #   @param  BuildOptions        Build options passed from command line\r
     #\r
-    def __init__(self, Target, WorkspaceDir, BuildOptions):\r
+    def __init__(self, Target, WorkspaceDir, BuildOptions,log_q):\r
         self.WorkspaceDir   = WorkspaceDir\r
         self.Target         = Target\r
         self.PlatformFile   = BuildOptions.PlatformFile\r
@@ -760,7 +723,7 @@ class Build():
         self.FvList         = BuildOptions.FvImage\r
         self.CapList        = BuildOptions.CapName\r
         self.SilentMode     = BuildOptions.SilentMode\r
-        self.ThreadNumber   = BuildOptions.ThreadNumber\r
+        self.ThreadNumber   = 1\r
         self.SkipAutoGen    = BuildOptions.SkipAutoGen\r
         self.Reparse        = BuildOptions.Reparse\r
         self.SkuId          = BuildOptions.SkuId\r
@@ -769,18 +732,22 @@ class Build():
         self.ConfDirectory = BuildOptions.ConfDirectory\r
         self.SpawnMode      = True\r
         self.BuildReport    = BuildReport(BuildOptions.ReportFile, BuildOptions.ReportType)\r
-        self.TargetTxt      = TargetTxtClassObject()\r
-        self.ToolDef        = ToolDefClassObject()\r
         self.AutoGenTime    = 0\r
         self.MakeTime       = 0\r
         self.GenFdsTime     = 0\r
+        self.MakeFileName   = ""\r
+        TargetObj = TargetTxtDict()\r
+        ToolDefObj = ToolDefDict((os.path.join(os.getenv("WORKSPACE"),"Conf")))\r
+        self.TargetTxt = TargetObj.Target\r
+        self.ToolDef = ToolDefObj.ToolDef\r
         GlobalData.BuildOptionPcd     = BuildOptions.OptionPcd if BuildOptions.OptionPcd else []\r
         #Set global flag for build mode\r
         GlobalData.gIgnoreSource = BuildOptions.IgnoreSources\r
         GlobalData.gUseHashCache = BuildOptions.UseHashCache\r
         GlobalData.gBinCacheDest   = BuildOptions.BinCacheDest\r
         GlobalData.gBinCacheSource = BuildOptions.BinCacheSource\r
-        GlobalData.gEnableGenfdsMultiThread = BuildOptions.GenfdsMultiThread\r
+        GlobalData.gEnableGenfdsMultiThread = not BuildOptions.NoGenfdsMultiThread\r
+        GlobalData.gDisableIncludePathCheck = BuildOptions.DisableIncludePathCheck\r
 \r
         if GlobalData.gBinCacheDest and not GlobalData.gUseHashCache:\r
             EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-destination must be used together with --hash.")\r
@@ -809,27 +776,10 @@ class Build():
             if GlobalData.gBinCacheDest is not None:\r
                 EdkLogger.error("build", OPTION_VALUE_INVALID, ExtraData="Invalid value of option --binary-destination.")\r
 \r
-        if self.ConfDirectory:\r
-            # Get alternate Conf location, if it is absolute, then just use the absolute directory name\r
-            ConfDirectoryPath = os.path.normpath(self.ConfDirectory)\r
-\r
-            if not os.path.isabs(ConfDirectoryPath):\r
-                # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE\r
-                # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf\r
-                ConfDirectoryPath = mws.join(self.WorkspaceDir, ConfDirectoryPath)\r
-        else:\r
-            if "CONF_PATH" in os.environ:\r
-                ConfDirectoryPath = os.path.normcase(os.path.normpath(os.environ["CONF_PATH"]))\r
-            else:\r
-                # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf\r
-                ConfDirectoryPath = mws.join(self.WorkspaceDir, 'Conf')\r
-        GlobalData.gConfDirectory = ConfDirectoryPath\r
-        GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath))\r
-\r
-        if BuildOptions.DisableCache:\r
-            self.Db         = WorkspaceDatabase(":memory:")\r
-        else:\r
-            self.Db = WorkspaceDatabase(GlobalData.gDatabasePath, self.Reparse)\r
+        GlobalData.gDatabasePath = os.path.normpath(os.path.join(GlobalData.gConfDirectory, GlobalData.gDatabasePath))\r
+        if not os.path.exists(os.path.join(GlobalData.gConfDirectory, '.cache')):\r
+            os.makedirs(os.path.join(GlobalData.gConfDirectory, '.cache'))\r
+        self.Db = BuildDB\r
         self.BuildDatabase = self.Db.BuildObject\r
         self.Platform = None\r
         self.ToolChainFamily = None\r
@@ -839,7 +789,7 @@ class Build():
         self.HashSkipModules = []\r
         self.Db_Flag = False\r
         self.LaunchPrebuildFlag = False\r
-        self.PlatformBuildPath = os.path.join(GlobalData.gConfDirectory,'.cache', '.PlatformBuild')\r
+        self.PlatformBuildPath = os.path.join(GlobalData.gConfDirectory, '.cache', '.PlatformBuild')\r
         if BuildOptions.CommandLength:\r
             GlobalData.gCommandMaxLength = BuildOptions.CommandLength\r
 \r
@@ -848,16 +798,20 @@ class Build():
         # print current build environment and configuration\r
         EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))\r
         if "PACKAGES_PATH" in os.environ:\r
-            # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env. \r
+            # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.\r
             EdkLogger.quiet("%-16s = %s" % ("PACKAGES_PATH", os.path.normcase(os.path.normpath(os.environ["PACKAGES_PATH"]))))\r
-        EdkLogger.quiet("%-16s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"]))\r
-        EdkLogger.quiet("%-16s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"]))\r
-        EdkLogger.quiet("%-16s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"]))\r
         EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))\r
         if "EDK_TOOLS_BIN" in os.environ:\r
-            # Print the same path style with WORKSPACE env. \r
+            # Print the same path style with WORKSPACE env.\r
             EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os.path.normcase(os.path.normpath(os.environ["EDK_TOOLS_BIN"]))))\r
         EdkLogger.quiet("%-16s = %s" % ("CONF_PATH", GlobalData.gConfDirectory))\r
+        if "PYTHON3_ENABLE" in os.environ:\r
+            PYTHON3_ENABLE = os.environ["PYTHON3_ENABLE"]\r
+            if PYTHON3_ENABLE != "TRUE":\r
+                PYTHON3_ENABLE = "FALSE"\r
+            EdkLogger.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE))\r
+        if "PYTHON_COMMAND" in os.environ:\r
+            EdkLogger.quiet("%-16s = %s" % ("PYTHON_COMMAND", os.environ["PYTHON_COMMAND"]))\r
         self.InitPreBuild()\r
         self.InitPostBuild()\r
         if self.Prebuild:\r
@@ -866,52 +820,156 @@ class Build():
             EdkLogger.quiet("%-16s = %s" % ("POSTBUILD", self.Postbuild))\r
         if self.Prebuild:\r
             self.LaunchPrebuild()\r
-            self.TargetTxt = TargetTxtClassObject()\r
-            self.ToolDef   = ToolDefClassObject()\r
+            TargetObj = TargetTxtDict()\r
+            ToolDefObj = ToolDefDict((os.path.join(os.getenv("WORKSPACE"), "Conf")))\r
+            self.TargetTxt = TargetObj.Target\r
+            self.ToolDef = ToolDefObj.ToolDef\r
         if not (self.LaunchPrebuildFlag and os.path.exists(self.PlatformBuildPath)):\r
             self.InitBuild()\r
 \r
+        self.AutoGenMgr = None\r
         EdkLogger.info("")\r
         os.chdir(self.WorkspaceDir)\r
+        self.log_q = log_q\r
+        GlobalData.file_lock =  mp.Lock()\r
+        # Init cache data for local only\r
+        GlobalData.gPackageHashFile = dict()\r
+        GlobalData.gModulePreMakeCacheStatus = dict()\r
+        GlobalData.gModuleMakeCacheStatus = dict()\r
+        GlobalData.gHashChainStatus = dict()\r
+        GlobalData.gCMakeHashFile = dict()\r
+        GlobalData.gModuleHashFile = dict()\r
+        GlobalData.gFileHashDict = dict()\r
+        GlobalData.gModuleAllCacheStatus = set()\r
+        GlobalData.gModuleCacheHit = set()\r
+\r
+    def StartAutoGen(self,mqueue, DataPipe,SkipAutoGen,PcdMaList,cqueue):\r
+        try:\r
+            if SkipAutoGen:\r
+                return True,0\r
+            feedback_q = mp.Queue()\r
+            error_event = mp.Event()\r
+            FfsCmd = DataPipe.Get("FfsCommand")\r
+            if FfsCmd is None:\r
+                FfsCmd = {}\r
+            GlobalData.FfsCmd = FfsCmd\r
+            auto_workers = [AutoGenWorkerInProcess(mqueue,DataPipe.dump_file,feedback_q,GlobalData.file_lock,cqueue,self.log_q,error_event) for _ in range(self.ThreadNumber)]\r
+            self.AutoGenMgr = AutoGenManager(auto_workers,feedback_q,error_event)\r
+            self.AutoGenMgr.start()\r
+            for w in auto_workers:\r
+                w.start()\r
+            if PcdMaList is not None:\r
+                for PcdMa in PcdMaList:\r
+                    # SourceFileList calling sequence impact the makefile string sequence.\r
+                    # Create cached SourceFileList here to unify its calling sequence for both\r
+                    # CanSkipbyPreMakeCache and CreateCodeFile/CreateMakeFile.\r
+                    RetVal = PcdMa.SourceFileList\r
+                    # Force cache miss for PCD driver\r
+                    if GlobalData.gUseHashCache and not GlobalData.gBinCacheDest and self.Target in [None, "", "all"]:\r
+                        cqueue.put((PcdMa.MetaFile.Path, PcdMa.Arch, "PreMakeCache", False))\r
+\r
+                    PcdMa.CreateCodeFile(False)\r
+                    PcdMa.CreateMakeFile(False,GenFfsList = DataPipe.Get("FfsCommand").get((PcdMa.MetaFile.Path, PcdMa.Arch),[]))\r
+                    PcdMa.CreateAsBuiltInf()\r
+                    # Force cache miss for PCD driver\r
+                    if GlobalData.gBinCacheSource and self.Target in [None, "", "all"]:\r
+                        cqueue.put((PcdMa.MetaFile.Path, PcdMa.Arch, "MakeCache", False))\r
+\r
+            self.AutoGenMgr.join()\r
+            rt = self.AutoGenMgr.Status\r
+            err = 0\r
+            if not rt:\r
+                err = UNKNOWN_ERROR\r
+            return rt, err\r
+        except FatalError as e:\r
+            return False, e.args[0]\r
+        except:\r
+            return False, UNKNOWN_ERROR\r
+\r
+    ## Add TOOLCHAIN and FAMILY declared in DSC [BuildOptions] to ToolsDefTxtDatabase.\r
+    #\r
+    # Loop through the set of build targets, tool chains, and archs provided on either\r
+    # the command line or in target.txt to discover FAMILY and TOOLCHAIN delclarations\r
+    # in [BuildOptions] sections that may be within !if expressions that may use\r
+    # $(TARGET), $(TOOLCHAIN), $(TOOLCHAIN_TAG), or $(ARCH) operands.\r
+    #\r
+    def GetToolChainAndFamilyFromDsc (self, File):\r
+        SavedGlobalDefines = GlobalData.gGlobalDefines.copy()\r
+        for BuildTarget in self.BuildTargetList:\r
+            GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
+            for BuildToolChain in self.ToolChainList:\r
+                GlobalData.gGlobalDefines['TOOLCHAIN']      = BuildToolChain\r
+                GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = BuildToolChain\r
+                for BuildArch in self.ArchList:\r
+                    GlobalData.gGlobalDefines['ARCH'] = BuildArch\r
+                    dscobj = self.BuildDatabase[File, BuildArch]\r
+                    for KeyFamily, Key, KeyCodeBase in dscobj.BuildOptions:\r
+                        try:\r
+                            Target, ToolChain, Arch, Tool, Attr = Key.split('_')\r
+                        except:\r
+                            continue\r
+                        if ToolChain == TAB_STAR or Attr != TAB_TOD_DEFINES_FAMILY:\r
+                            continue\r
+                        try:\r
+                            Family = dscobj.BuildOptions[(KeyFamily, Key, KeyCodeBase)]\r
+                            Family = Family.strip().strip('=').strip()\r
+                        except:\r
+                            continue\r
+                        if TAB_TOD_DEFINES_FAMILY not in self.ToolDef.ToolsDefTxtDatabase:\r
+                            self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY] = {}\r
+                        if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY]:\r
+                            self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][ToolChain] = Family\r
+                        if TAB_TOD_DEFINES_BUILDRULEFAMILY not in self.ToolDef.ToolsDefTxtDatabase:\r
+                            self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY] = {}\r
+                        if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY]:\r
+                            self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][ToolChain] = Family\r
+                        if TAB_TOD_DEFINES_TOOL_CHAIN_TAG not in self.ToolDef.ToolsDefTxtDatabase:\r
+                            self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG] = []\r
+                        if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:\r
+                            self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG].append(ToolChain)\r
+        GlobalData.gGlobalDefines = SavedGlobalDefines\r
 \r
     ## Load configuration\r
     #\r
     #   This method will parse target.txt and get the build configurations.\r
     #\r
     def LoadConfiguration(self):\r
-        #\r
-        # Check target.txt and tools_def.txt and Init them\r
-        #\r
-        BuildConfigurationFile = os.path.normpath(os.path.join(GlobalData.gConfDirectory, gBuildConfiguration))\r
-        if os.path.isfile(BuildConfigurationFile) == True:\r
-            StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)\r
-\r
-            ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]\r
-            if ToolDefinitionFile == '':\r
-                ToolDefinitionFile = gToolsDefinition\r
-                ToolDefinitionFile = os.path.normpath(mws.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile))\r
-            if os.path.isfile(ToolDefinitionFile) == True:\r
-                StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)\r
-            else:\r
-                EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)\r
-        else:\r
-            EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)\r
 \r
         # if no ARCH given in command line, get it from target.txt\r
         if not self.ArchList:\r
-            self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH]\r
+            self.ArchList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET_ARCH]\r
         self.ArchList = tuple(self.ArchList)\r
 \r
         # if no build target given in command line, get it from target.txt\r
         if not self.BuildTargetList:\r
-            self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]\r
+            self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET]\r
 \r
         # if no tool chain given in command line, get it from target.txt\r
         if not self.ToolChainList:\r
-            self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]\r
+            self.ToolChainList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TOOL_CHAIN_TAG]\r
             if self.ToolChainList is None or len(self.ToolChainList) == 0:\r
                 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")\r
 \r
+        if not self.PlatformFile:\r
+            PlatformFile = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_ACTIVE_PLATFORM]\r
+            if not PlatformFile:\r
+                # Try to find one in current directory\r
+                WorkingDirectory = os.getcwd()\r
+                FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))\r
+                FileNum = len(FileList)\r
+                if FileNum >= 2:\r
+                    EdkLogger.error("build", OPTION_MISSING,\r
+                                    ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))\r
+                elif FileNum == 1:\r
+                    PlatformFile = FileList[0]\r
+                else:\r
+                    EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
+                                    ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")\r
+\r
+            self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)\r
+\r
+        self.GetToolChainAndFamilyFromDsc (self.PlatformFile)\r
+\r
         # check if the tool chains are defined or not\r
         NewToolChainList = []\r
         for ToolChain in self.ToolChainList:\r
@@ -932,42 +990,12 @@ class Build():
             if TAB_TOD_DEFINES_FAMILY not in ToolDefinition or Tool not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \\r
                or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool]:\r
                 EdkLogger.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool)\r
-                ToolChainFamily.append("MSFT")\r
+                ToolChainFamily.append(TAB_COMPILER_MSFT)\r
             else:\r
                 ToolChainFamily.append(ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool])\r
         self.ToolChainFamily = ToolChainFamily\r
 \r
-        if self.ThreadNumber is None:\r
-            self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]\r
-            if self.ThreadNumber == '':\r
-                self.ThreadNumber = 0\r
-            else:\r
-                self.ThreadNumber = int(self.ThreadNumber, 0)\r
-\r
-        if self.ThreadNumber == 0:\r
-            try:\r
-                self.ThreadNumber = multiprocessing.cpu_count()\r
-            except (ImportError, NotImplementedError):\r
-                self.ThreadNumber = 1\r
-\r
-        if not self.PlatformFile:\r
-            PlatformFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM]\r
-            if not PlatformFile:\r
-                # Try to find one in current directory\r
-                WorkingDirectory = os.getcwd()\r
-                FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))\r
-                FileNum = len(FileList)\r
-                if FileNum >= 2:\r
-                    EdkLogger.error("build", OPTION_MISSING,\r
-                                    ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))\r
-                elif FileNum == 1:\r
-                    PlatformFile = FileList[0]\r
-                else:\r
-                    EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
-                                    ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")\r
-\r
-            self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)\r
-\r
+        self.ThreadNumber   = ThreadNum()\r
     ## Initialize build configuration\r
     #\r
     #   This method will parse DSC file and merge the configurations from\r
@@ -982,9 +1010,6 @@ class Build():
         if ErrorCode != 0:\r
             EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
 \r
-        # create metafile database\r
-        if not self.Db_Flag:\r
-            self.Db.InitDatabase()\r
 \r
     def InitPreBuild(self):\r
         self.LoadConfiguration()\r
@@ -1000,12 +1025,11 @@ class Build():
             GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = self.ToolChainList[0]\r
         if self.ToolChainFamily:\r
             GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[0]\r
-        if 'PREBUILD' in GlobalData.gCommandLineDefines.keys():\r
+        if 'PREBUILD' in GlobalData.gCommandLineDefines:\r
             self.Prebuild   = GlobalData.gCommandLineDefines.get('PREBUILD')\r
         else:\r
-            self.Db.InitDatabase()\r
             self.Db_Flag = True\r
-            Platform = self.Db._MapPlatform(str(self.PlatformFile))\r
+            Platform = self.Db.MapPlatform(str(self.PlatformFile))\r
             self.Prebuild = str(Platform.Prebuild)\r
         if self.Prebuild:\r
             PrebuildList = []\r
@@ -1041,10 +1065,10 @@ class Build():
             self.Prebuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)\r
 \r
     def InitPostBuild(self):\r
-        if 'POSTBUILD' in GlobalData.gCommandLineDefines.keys():\r
+        if 'POSTBUILD' in GlobalData.gCommandLineDefines:\r
             self.Postbuild = GlobalData.gCommandLineDefines.get('POSTBUILD')\r
         else:\r
-            Platform = self.Db._MapPlatform(str(self.PlatformFile))\r
+            Platform = self.Db.MapPlatform(str(self.PlatformFile))\r
             self.Postbuild = str(Platform.Postbuild)\r
         if self.Postbuild:\r
             PostbuildList = []\r
@@ -1132,7 +1156,7 @@ class Build():
             # and preserve them for the rest of the main build step, because the child process environment will\r
             # evaporate as soon as it exits, we cannot get it in build step.\r
             #\r
-            PrebuildEnvFile = os.path.join(GlobalData.gConfDirectory,'.cache','.PrebuildEnv')\r
+            PrebuildEnvFile = os.path.join(GlobalData.gConfDirectory, '.cache', '.PrebuildEnv')\r
             if os.path.isfile(PrebuildEnvFile):\r
                 os.remove(PrebuildEnvFile)\r
             if os.path.isfile(self.PlatformBuildPath):\r
@@ -1149,14 +1173,14 @@ class Build():
             EndOfProcedure.clear()\r
             if Process.stdout:\r
                 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))\r
-                StdOutThread.setName("STDOUT-Redirector")\r
-                StdOutThread.setDaemon(False)\r
+                StdOutThread.name = "STDOUT-Redirector"\r
+                StdOutThread.daemon = False\r
                 StdOutThread.start()\r
 \r
             if Process.stderr:\r
                 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))\r
-                StdErrThread.setName("STDERR-Redirector")\r
-                StdErrThread.setDaemon(False)\r
+                StdErrThread.name = "STDERR-Redirector"\r
+                StdErrThread.daemon = False\r
                 StdErrThread.start()\r
             # waiting for program exit\r
             Process.wait()\r
@@ -1172,9 +1196,8 @@ class Build():
                 f = open(PrebuildEnvFile)\r
                 envs = f.readlines()\r
                 f.close()\r
-                envs = itertools.imap(lambda l: l.split('=',1), envs)\r
-                envs = itertools.ifilter(lambda l: len(l) == 2, envs)\r
-                envs = itertools.imap(lambda l: [i.strip() for i in l], envs)\r
+                envs = [l.split("=", 1) for l in envs ]\r
+                envs = [[I.strip() for I in item] for item in envs if len(item) == 2]\r
                 os.environ.update(dict(envs))\r
             EdkLogger.info("\n- Prebuild Done -\n")\r
 \r
@@ -1190,14 +1213,14 @@ class Build():
             EndOfProcedure.clear()\r
             if Process.stdout:\r
                 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))\r
-                StdOutThread.setName("STDOUT-Redirector")\r
-                StdOutThread.setDaemon(False)\r
+                StdOutThread.name = "STDOUT-Redirector"\r
+                StdOutThread.daemon = False\r
                 StdOutThread.start()\r
 \r
             if Process.stderr:\r
                 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))\r
-                StdErrThread.setName("STDERR-Redirector")\r
-                StdErrThread.setDaemon(False)\r
+                StdErrThread.name = "STDERR-Redirector"\r
+                StdErrThread.daemon = False\r
                 StdErrThread.start()\r
             # waiting for program exit\r
             Process.wait()\r
@@ -1209,6 +1232,7 @@ class Build():
             if Process.returncode != 0 :\r
                 EdkLogger.error("Postbuild", POSTBUILD_ERROR, 'Postbuild process is not success!')\r
             EdkLogger.info("\n- Postbuild Done -\n")\r
+\r
     ## Build a module or platform\r
     #\r
     # Create autogen code and makefile for a module or platform, and the launch\r
@@ -1225,30 +1249,45 @@ class Build():
     #   @param  CreateDepModuleMakeFile     Flag used to indicate creating makefile\r
     #                                       for dependent modules/Libraries\r
     #\r
-    def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False, FfsCommand={}):\r
+    def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False, FfsCommand=None, PcdMaList=None):\r
         if AutoGenObject is None:\r
             return False\r
-\r
+        if FfsCommand is None:\r
+            FfsCommand = {}\r
         # skip file generation for cleanxxx targets, run and fds target\r
         if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
             # for target which must generate AutoGen code and makefile\r
-            if not self.SkipAutoGen or Target == 'genc':\r
-                self.Progress.Start("Generating code")\r
-                AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
-                self.Progress.Stop("done!")\r
-            if Target == "genc":\r
-                return True\r
-\r
-            if not self.SkipAutoGen or Target == 'genmake':\r
-                self.Progress.Start("Generating makefile")\r
-                AutoGenObject.CreateMakeFile(CreateDepsMakeFile, FfsCommand)\r
-                self.Progress.Stop("done!")\r
-            if Target == "genmake":\r
-                return True\r
-        else:\r
-            # always recreate top/platform makefile when clean, just in case of inconsistency\r
+            mqueue = mp.Queue()\r
+            for m in AutoGenObject.GetAllModuleInfo:\r
+                mqueue.put(m)\r
+            mqueue.put((None,None,None,None,None,None,None))\r
+            AutoGenObject.DataPipe.DataContainer = {"CommandTarget": self.Target}\r
+            AutoGenObject.DataPipe.DataContainer = {"Workspace_timestamp": AutoGenObject.Workspace._SrcTimeStamp}\r
+            AutoGenObject.CreateLibModuelDirs()\r
+            AutoGenObject.DataPipe.DataContainer = {"LibraryBuildDirectoryList":AutoGenObject.LibraryBuildDirectoryList}\r
+            AutoGenObject.DataPipe.DataContainer = {"ModuleBuildDirectoryList":AutoGenObject.ModuleBuildDirectoryList}\r
+            AutoGenObject.DataPipe.DataContainer = {"FdsCommandDict": AutoGenObject.Workspace.GenFdsCommandDict}\r
+            self.Progress.Start("Generating makefile and code")\r
+            data_pipe_file = os.path.join(AutoGenObject.BuildDir, "GlobalVar_%s_%s.bin" % (str(AutoGenObject.Guid),AutoGenObject.Arch))\r
+            AutoGenObject.DataPipe.dump(data_pipe_file)\r
+            cqueue = mp.Queue()\r
+            autogen_rt,errorcode = self.StartAutoGen(mqueue, AutoGenObject.DataPipe, self.SkipAutoGen, PcdMaList, cqueue)\r
+            AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt")\r
+            with open(AutoGenIdFile,"w") as fw:\r
+                fw.write("Arch=%s\n" % "|".join((AutoGenObject.Workspace.ArchList)))\r
+                fw.write("BuildDir=%s\n" % AutoGenObject.Workspace.BuildDir)\r
+                fw.write("PlatformGuid=%s\n" % str(AutoGenObject.Guid))\r
+            self.Progress.Stop("done!")\r
+            if not autogen_rt:\r
+                self.AutoGenMgr.TerminateWorkers()\r
+                self.AutoGenMgr.join(1)\r
+                raise FatalError(errorcode)\r
             AutoGenObject.CreateCodeFile(False)\r
             AutoGenObject.CreateMakeFile(False)\r
+        else:\r
+            # always recreate top/platform makefile when clean, just in case of inconsistency\r
+            AutoGenObject.CreateCodeFile(True)\r
+            AutoGenObject.CreateMakeFile(True)\r
 \r
         if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
             EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
@@ -1261,45 +1300,68 @@ class Build():
                                 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
                             ExtraData=str(AutoGenObject))\r
 \r
-        makefile = GenMake.BuildFile(AutoGenObject)._FILE_NAME_[GenMake.gMakeType]\r
-\r
         # run\r
         if Target == 'run':\r
-            RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))\r
-            Command = '.\SecMain'\r
-            os.chdir(RunDir)\r
-            LaunchCommand(Command, RunDir)\r
             return True\r
 \r
+        # Fetch the MakeFileName.\r
+        self.MakeFileName = AutoGenObject.MakeFileName\r
+\r
         # build modules\r
         if BuildModule:\r
             BuildCommand = BuildCommand + [Target]\r
             LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
-            self.CreateAsBuiltInf()\r
+            if GlobalData.gBinCacheDest:\r
+                self.GenDestCache()\r
+            elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:\r
+                # Only for --hash\r
+                # Update PreMakeCacheChain files\r
+                self.GenLocalPreMakeCache()\r
+            self.BuildModules = []\r
             return True\r
 \r
         # build library\r
         if Target == 'libraries':\r
-            for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
-                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']\r
-                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
+            DirList = []\r
+            for Lib in AutoGenObject.LibraryAutoGenList:\r
+                if not Lib.IsBinaryModule:\r
+                    DirList.append((os.path.join(AutoGenObject.BuildDir, Lib.BuildDir),Lib))\r
+            for Lib, LibAutoGen in DirList:\r
+                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, self.MakeFileName)), 'pbuild']\r
+                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,LibAutoGen)\r
             return True\r
 \r
         # build module\r
         if Target == 'modules':\r
-            for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
-                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']\r
-                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
-            for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
-                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']\r
-                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
+            DirList = []\r
+            for Lib in AutoGenObject.LibraryAutoGenList:\r
+                if not Lib.IsBinaryModule:\r
+                    DirList.append((os.path.join(AutoGenObject.BuildDir, Lib.BuildDir),Lib))\r
+            for Lib, LibAutoGen in DirList:\r
+                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, self.MakeFileName)), 'pbuild']\r
+                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,LibAutoGen)\r
+\r
+            DirList = []\r
+            for ModuleAutoGen in AutoGenObject.ModuleAutoGenList:\r
+                if not ModuleAutoGen.IsBinaryModule:\r
+                    DirList.append((os.path.join(AutoGenObject.BuildDir, ModuleAutoGen.BuildDir),ModuleAutoGen))\r
+            for Mod,ModAutoGen in DirList:\r
+                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, self.MakeFileName)), 'pbuild']\r
+                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,ModAutoGen)\r
             self.CreateAsBuiltInf()\r
+            if GlobalData.gBinCacheDest:\r
+                self.GenDestCache()\r
+            elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:\r
+                # Only for --hash\r
+                # Update PreMakeCacheChain files\r
+                self.GenLocalPreMakeCache()\r
+            self.BuildModules = []\r
             return True\r
 \r
         # cleanlib\r
         if Target == 'cleanlib':\r
             for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
-                LibMakefile = os.path.normpath(os.path.join(Lib, makefile))\r
+                LibMakefile = os.path.normpath(os.path.join(Lib, self.MakeFileName))\r
                 if os.path.exists(LibMakefile):\r
                     NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
                     LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
@@ -1308,12 +1370,12 @@ class Build():
         # clean\r
         if Target == 'clean':\r
             for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
-                ModMakefile = os.path.normpath(os.path.join(Mod, makefile))\r
+                ModMakefile = os.path.normpath(os.path.join(Mod, self.MakeFileName))\r
                 if os.path.exists(ModMakefile):\r
                     NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']\r
                     LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
             for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
-                LibMakefile = os.path.normpath(os.path.join(Lib, makefile))\r
+                LibMakefile = os.path.normpath(os.path.join(Lib, self.MakeFileName))\r
                 if os.path.exists(LibMakefile):\r
                     NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
                     LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
@@ -1324,7 +1386,7 @@ class Build():
             try:\r
                 #os.rmdir(AutoGenObject.BuildDir)\r
                 RemoveDirectory(AutoGenObject.BuildDir, True)\r
-            except WindowsError, X:\r
+            except WindowsError as X:\r
                 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
         return True\r
 \r
@@ -1367,8 +1429,8 @@ class Build():
                 return True\r
         else:\r
             # always recreate top/platform makefile when clean, just in case of inconsistency\r
-            AutoGenObject.CreateCodeFile(False)\r
-            AutoGenObject.CreateMakeFile(False)\r
+            AutoGenObject.CreateCodeFile(True)\r
+            AutoGenObject.CreateMakeFile(True)\r
 \r
         if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
             EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
@@ -1387,19 +1449,26 @@ class Build():
                 BuildCommand = BuildCommand + [Target]\r
             AutoGenObject.BuildTime = LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
             self.CreateAsBuiltInf()\r
+            if GlobalData.gBinCacheDest:\r
+                self.GenDestCache()\r
+            elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:\r
+                # Only for --hash\r
+                # Update PreMakeCacheChain files\r
+                self.GenLocalPreMakeCache()\r
+            self.BuildModules = []\r
             return True\r
 \r
         # genfds\r
         if Target == 'fds':\r
-            LaunchCommand(AutoGenObject.GenFdsCommand, AutoGenObject.MakeFileDir)\r
+            if GenFdsApi(AutoGenObject.GenFdsCommandDict, self.Db):\r
+                EdkLogger.error("build", COMMAND_FAILURE)\r
+            Threshold = self.GetFreeSizeThreshold()\r
+            if Threshold:\r
+                self.CheckFreeSizeThreshold(Threshold, AutoGenObject.FvDir)\r
             return True\r
 \r
         # run\r
         if Target == 'run':\r
-            RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))\r
-            Command = '.\SecMain'\r
-            os.chdir(RunDir)\r
-            LaunchCommand(Command, RunDir)\r
             return True\r
 \r
         # build library\r
@@ -1414,7 +1483,7 @@ class Build():
             try:\r
                 #os.rmdir(AutoGenObject.BuildDir)\r
                 RemoveDirectory(AutoGenObject.BuildDir, True)\r
-            except WindowsError, X:\r
+            except WindowsError as X:\r
                 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
         return True\r
 \r
@@ -1423,9 +1492,7 @@ class Build():
     def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):\r
         if ModeIsSmm:\r
             AddrIsOffset = False\r
-        InfFileNameList = ModuleList.keys()\r
-        #InfFileNameList.sort()\r
-        for InfFile in InfFileNameList:\r
+        for InfFile in ModuleList:\r
             sys.stdout.write (".")\r
             sys.stdout.flush()\r
             ModuleInfo = ModuleList[InfFile]\r
@@ -1447,7 +1514,7 @@ class Build():
                 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
                 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
             #\r
-            # Collect funtion address from Map file\r
+            # Collect function address from Map file\r
             #\r
             ImageMapTable = ModuleOutputImage.replace('.efi', '.map')\r
             FunctionList = []\r
@@ -1470,21 +1537,17 @@ class Build():
                             Name = StrList[1]\r
                             RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress\r
                             FunctionList.append ((Name, RelativeAddress))\r
-                            if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'):\r
-                                #\r
-                                # Get the real entry point address for IPF image.\r
-                                #\r
-                                ModuleInfo.Image.EntryPoint = RelativeAddress\r
+\r
                 ImageMap.close()\r
             #\r
             # Add general information.\r
             #\r
             if ModeIsSmm:\r
-                MapBuffer.write('\n\n%s (Fixed SMRAM Offset,   BaseAddress=0x%010X,  EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
+                MapBuffer.append('\n\n%s (Fixed SMRAM Offset,   BaseAddress=0x%010X,  EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
             elif AddrIsOffset:\r
-                MapBuffer.write('\n\n%s (Fixed Memory Offset,  BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))\r
+                MapBuffer.append('\n\n%s (Fixed Memory Offset,  BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))\r
             else:\r
-                MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X,  EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
+                MapBuffer.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X,  EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
             #\r
             # Add guid and general seciton section.\r
             #\r
@@ -1496,21 +1559,21 @@ class Build():
                 elif SectionHeader[0] in ['.data', '.sdata']:\r
                     DataSectionAddress = SectionHeader[1]\r
             if AddrIsOffset:\r
-                MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))\r
+                MapBuffer.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))\r
             else:\r
-                MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))\r
+                MapBuffer.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))\r
             #\r
             # Add debug image full path.\r
             #\r
-            MapBuffer.write('(IMAGE=%s)\n\n' % (ModuleDebugImage))\r
+            MapBuffer.append('(IMAGE=%s)\n\n' % (ModuleDebugImage))\r
             #\r
-            # Add funtion address\r
+            # Add function address\r
             #\r
             for Function in FunctionList:\r
                 if AddrIsOffset:\r
-                    MapBuffer.write('  -0x%010X    %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))\r
+                    MapBuffer.append('  -0x%010X    %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))\r
                 else:\r
-                    MapBuffer.write('  0x%010X    %s\n' % (BaseAddress + Function[1], Function[0]))\r
+                    MapBuffer.append('  0x%010X    %s\n' % (BaseAddress + Function[1], Function[0]))\r
             ImageMap.close()\r
 \r
             #\r
@@ -1525,8 +1588,8 @@ class Build():
         if self.Fdf:\r
             # First get the XIP base address for FV map file.\r
             GuidPattern = re.compile("[-a-fA-F0-9]+")\r
-            GuidName = re.compile("\(GUID=[-a-fA-F0-9]+")\r
-            for FvName in Wa.FdfProfile.FvDict.keys():\r
+            GuidName = re.compile(r"\(GUID=[-a-fA-F0-9]+")\r
+            for FvName in Wa.FdfProfile.FvDict:\r
                 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')\r
                 if not os.path.exists(FvMapBuffer):\r
                     continue\r
@@ -1545,7 +1608,7 @@ class Build():
                         GuidString = MatchGuid.group()\r
                         if GuidString.upper() in ModuleList:\r
                             Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)\r
-                    MapBuffer.write('%s' % (Line))\r
+                    MapBuffer.append(Line)\r
                     #\r
                     # Add the debug image full path.\r
                     #\r
@@ -1553,7 +1616,7 @@ class Build():
                     if MatchGuid is not None:\r
                         GuidString = MatchGuid.group().split("=")[1]\r
                         if GuidString.upper() in ModuleList:\r
-                            MapBuffer.write('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))\r
+                            MapBuffer.append('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))\r
 \r
                 FvMap.close()\r
 \r
@@ -1572,9 +1635,6 @@ class Build():
         RtSize  = 0\r
         # reserve 4K size in SMRAM to make SMM module address not from 0.\r
         SmmSize = 0x1000\r
-        IsIpfPlatform = False\r
-        if 'IPF' in self.ArchList:\r
-            IsIpfPlatform = True\r
         for ModuleGuid in ModuleList:\r
             Module = ModuleList[ModuleGuid]\r
             GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)\r
@@ -1590,25 +1650,20 @@ class Build():
                     if not ImageClass.IsValid:\r
                         EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)\r
                     ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)\r
-                    if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER', 'PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']:\r
+                    if Module.ModuleType in [SUP_MODULE_PEI_CORE, SUP_MODULE_PEIM, EDK_COMPONENT_TYPE_COMBINED_PEIM_DRIVER, EDK_COMPONENT_TYPE_PIC_PEIM, EDK_COMPONENT_TYPE_RELOCATABLE_PEIM, SUP_MODULE_DXE_CORE]:\r
                         PeiModuleList[Module.MetaFile] = ImageInfo\r
                         PeiSize += ImageInfo.Image.Size\r
-                    elif Module.ModuleType in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']:\r
+                    elif Module.ModuleType in [EDK_COMPONENT_TYPE_BS_DRIVER, SUP_MODULE_DXE_DRIVER, SUP_MODULE_UEFI_DRIVER]:\r
                         BtModuleList[Module.MetaFile] = ImageInfo\r
                         BtSize += ImageInfo.Image.Size\r
-                    elif Module.ModuleType in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']:\r
+                    elif Module.ModuleType in [SUP_MODULE_DXE_RUNTIME_DRIVER, EDK_COMPONENT_TYPE_RT_DRIVER, SUP_MODULE_DXE_SAL_DRIVER, EDK_COMPONENT_TYPE_SAL_RT_DRIVER]:\r
                         RtModuleList[Module.MetaFile] = ImageInfo\r
-                        #IPF runtime driver needs to be at 2 page alignment.\r
-                        if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0:\r
-                            ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000\r
                         RtSize += ImageInfo.Image.Size\r
-                    elif Module.ModuleType in ['SMM_CORE', 'DXE_SMM_DRIVER', 'MM_STANDALONE', 'MM_CORE_STANDALONE']:\r
+                    elif Module.ModuleType in [SUP_MODULE_SMM_CORE, SUP_MODULE_DXE_SMM_DRIVER, SUP_MODULE_MM_STANDALONE, SUP_MODULE_MM_CORE_STANDALONE]:\r
                         SmmModuleList[Module.MetaFile] = ImageInfo\r
                         SmmSize += ImageInfo.Image.Size\r
-                        if Module.ModuleType == 'DXE_SMM_DRIVER':\r
-                            PiSpecVersion = '0x00000000'\r
-                            if 'PI_SPECIFICATION_VERSION' in Module.Module.Specification:\r
-                                PiSpecVersion = Module.Module.Specification['PI_SPECIFICATION_VERSION']\r
+                        if Module.ModuleType == SUP_MODULE_DXE_SMM_DRIVER:\r
+                            PiSpecVersion = Module.Module.Specification.get('PI_SPECIFICATION_VERSION', '0x00000000')\r
                             # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.\r
                             if int(PiSpecVersion, 16) < 0x0001000A:\r
                                 BtModuleList[Module.MetaFile] = ImageInfo\r
@@ -1621,12 +1676,12 @@ class Build():
             if OutputImageFile != '':\r
                 ModuleIsPatch = False\r
                 for Pcd in Module.ModulePcdList:\r
-                    if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:\r
+                    if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:\r
                         ModuleIsPatch = True\r
                         break\r
                 if not ModuleIsPatch:\r
                     for Pcd in Module.LibraryPcdList:\r
-                        if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:\r
+                        if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:\r
                             ModuleIsPatch = True\r
                             break\r
 \r
@@ -1649,10 +1704,6 @@ class Build():
             TopMemoryAddress = self.LoadFixAddress\r
             if TopMemoryAddress < RtSize + BtSize + PeiSize:\r
                 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")\r
-            # Make IPF runtime driver at 2 page alignment.\r
-            if IsIpfPlatform:\r
-                ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000\r
-                RtSize = RtSize + ReservedRuntimeMemorySize\r
 \r
         #\r
         # Patch FixAddress related PCDs into EFI image\r
@@ -1671,21 +1722,21 @@ class Build():
             for PcdInfo in PcdTable:\r
                 ReturnValue = 0\r
                 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:\r
-                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize / 0x1000))\r
+                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize // 0x1000))\r
                 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:\r
-                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize / 0x1000))\r
+                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize // 0x1000))\r
                 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:\r
-                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize / 0x1000))\r
+                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize // 0x1000))\r
                 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:\r
-                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize / 0x1000))\r
+                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize // 0x1000))\r
                 if ReturnValue != 0:\r
                     EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)\r
 \r
-        MapBuffer.write('PEI_CODE_PAGE_NUMBER      = 0x%x\n' % (PeiSize / 0x1000))\r
-        MapBuffer.write('BOOT_CODE_PAGE_NUMBER     = 0x%x\n' % (BtSize / 0x1000))\r
-        MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER  = 0x%x\n' % (RtSize / 0x1000))\r
+        MapBuffer.append('PEI_CODE_PAGE_NUMBER      = 0x%x\n' % (PeiSize // 0x1000))\r
+        MapBuffer.append('BOOT_CODE_PAGE_NUMBER     = 0x%x\n' % (BtSize // 0x1000))\r
+        MapBuffer.append('RUNTIME_CODE_PAGE_NUMBER  = 0x%x\n' % (RtSize // 0x1000))\r
         if len (SmmModuleList) > 0:\r
-            MapBuffer.write('SMM_CODE_PAGE_NUMBER      = 0x%x\n' % (SmmSize / 0x1000))\r
+            MapBuffer.append('SMM_CODE_PAGE_NUMBER      = 0x%x\n' % (SmmSize // 0x1000))\r
 \r
         PeiBaseAddr = TopMemoryAddress - RtSize - BtSize\r
         BtBaseAddr  = TopMemoryAddress - RtSize\r
@@ -1695,7 +1746,7 @@ class Build():
         self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)\r
         self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)\r
         self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset=False, ModeIsSmm=True)\r
-        MapBuffer.write('\n\n')\r
+        MapBuffer.append('\n\n')\r
         sys.stdout.write ("\n")\r
         sys.stdout.flush()\r
 \r
@@ -1709,8 +1760,7 @@ class Build():
         #\r
         # Save address map into MAP file.\r
         #\r
-        SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)\r
-        MapBuffer.close()\r
+        SaveFileOnChange(MapFilePath, ''.join(MapBuffer), False)\r
         if self.LoadFixAddress != 0:\r
             sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath))\r
         sys.stdout.flush()\r
@@ -1752,18 +1802,25 @@ class Build():
                 # Add ffs build to makefile\r
                 CmdListDict = {}\r
                 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
-                    CmdListDict = self._GenFfsCmd()\r
+                    CmdListDict = self._GenFfsCmd(Wa.ArchList)\r
 \r
                 for Arch in Wa.ArchList:\r
+                    PcdMaList    = []\r
                     GlobalData.gGlobalDefines['ARCH'] = Arch\r
                     Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
                     for Module in Pa.Platform.Modules:\r
                         # Get ModuleAutoGen object to generate C code file and makefile\r
-                        Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
+                        Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)\r
                         if Ma is None:\r
                             continue\r
+                        if Ma.PcdIsDriver:\r
+                            Ma.PlatformInfo = Pa\r
+                            Ma.Workspace = Wa\r
+                            PcdMaList.append(Ma)\r
                         self.BuildModules.append(Ma)\r
-                    self._BuildPa(self.Target, Pa, FfsCommand=CmdListDict)\r
+                    Pa.DataPipe.DataContainer = {"FfsCommand":CmdListDict}\r
+                    Pa.DataPipe.DataContainer = {"Workspace_timestamp": Wa._SrcTimeStamp}\r
+                    self._BuildPa(self.Target, Pa, FfsCommand=CmdListDict,PcdMaList=PcdMaList)\r
 \r
                 # Create MAP file when Load Fix Address is enabled.\r
                 if self.Target in ["", "all", "fds"]:\r
@@ -1785,7 +1842,7 @@ class Build():
                             if not Ma.IsLibrary:\r
                                 ModuleList[Ma.Guid.upper()] = Ma\r
 \r
-                    MapBuffer = StringIO('')\r
+                    MapBuffer = []\r
                     if self.LoadFixAddress != 0:\r
                         #\r
                         # Rebase module to the preferred memory address before GenFds\r
@@ -1804,6 +1861,7 @@ class Build():
                     # Save MAP buffer into MAP file.\r
                     #\r
                     self._SaveMapFile (MapBuffer, Wa)\r
+                self.CreateGuidedSectionToolsFile(Wa)\r
 \r
     ## Build active module for different build targets, different tool chains and different archs\r
     #\r
@@ -1845,7 +1903,11 @@ class Build():
                 # Add ffs build to makefile\r
                 CmdListDict = None\r
                 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
-                    CmdListDict = self._GenFfsCmd()\r
+                    CmdListDict = self._GenFfsCmd(Wa.ArchList)\r
+\r
+                GlobalData.file_lock = mp.Lock()\r
+                GlobalData.FfsCmd = CmdListDict\r
+\r
                 self.Progress.Stop("done!")\r
                 MaList = []\r
                 ExitFlag = threading.Event()\r
@@ -1857,12 +1919,20 @@ class Build():
                     Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
                     for Module in Pa.Platform.Modules:\r
                         if self.ModuleFile.Dir == Module.Dir and self.ModuleFile.Name == Module.Name:\r
-                            Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
-                            if Ma is None: continue\r
-                            MaList.append(Ma)\r
-                            if Ma.CanSkipbyHash():\r
-                                self.HashSkipModules.append(Ma)\r
+                            Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)\r
+                            if Ma is None:\r
                                 continue\r
+                            if Ma.PcdIsDriver:\r
+                                Ma.PlatformInfo = Pa\r
+                                Ma.Workspace = Wa\r
+                            MaList.append(Ma)\r
+\r
+                            if GlobalData.gUseHashCache and not GlobalData.gBinCacheDest and self.Target in [None, "", "all"]:\r
+                                if Ma.CanSkipbyPreMakeCache():\r
+                                    continue\r
+                                else:\r
+                                    self.PreMakeCacheMiss.add(Ma)\r
+\r
                             # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'\r
                             if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
                                 # for target which must generate AutoGen code and makefile\r
@@ -1874,20 +1944,27 @@ class Build():
                                     return True\r
                                 if not self.SkipAutoGen or self.Target == 'genmake':\r
                                     self.Progress.Start("Generating makefile")\r
-                                    if CmdListDict and self.Fdf and (Module.File, Arch) in CmdListDict:\r
-                                        Ma.CreateMakeFile(True, CmdListDict[Module.File, Arch])\r
-                                        del CmdListDict[Module.File, Arch]\r
+                                    if CmdListDict and self.Fdf and (Module.Path, Arch) in CmdListDict:\r
+                                        Ma.CreateMakeFile(True, CmdListDict[Module.Path, Arch])\r
+                                        del CmdListDict[Module.Path, Arch]\r
                                     else:\r
                                         Ma.CreateMakeFile(True)\r
                                     self.Progress.Stop("done!")\r
                                 if self.Target == "genmake":\r
                                     return True\r
+\r
+                                if GlobalData.gBinCacheSource and self.Target in [None, "", "all"]:\r
+                                    if Ma.CanSkipbyMakeCache():\r
+                                        continue\r
+                                    else:\r
+                                        self.MakeCacheMiss.add(Ma)\r
+\r
                             self.BuildModules.append(Ma)\r
                     self.AutoGenTime += int(round((time.time() - AutoGenStart)))\r
                     MakeStart = time.time()\r
                     for Ma in self.BuildModules:\r
                         if not Ma.IsBinaryModule:\r
-                            Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))\r
+                            Bt = BuildTask.New(ModuleMakeUnit(Ma, Pa.BuildCommand,self.Target))\r
                         # Break build if any build thread has error\r
                         if BuildTask.HasError():\r
                             # we need a full version of makefile for platform\r
@@ -1909,6 +1986,13 @@ class Build():
                 ExitFlag.set()\r
                 BuildTask.WaitForComplete()\r
                 self.CreateAsBuiltInf()\r
+                if GlobalData.gBinCacheDest:\r
+                    self.GenDestCache()\r
+                elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:\r
+                    # Only for --hash\r
+                    # Update PreMakeCacheChain files\r
+                    self.GenLocalPreMakeCache()\r
+                self.BuildModules = []\r
                 self.MakeTime += int(round((time.time() - MakeContiue)))\r
                 if BuildTask.HasError():\r
                     EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
@@ -1943,7 +2027,7 @@ class Build():
                             if not Ma.IsLibrary:\r
                                 ModuleList[Ma.Guid.upper()] = Ma\r
 \r
-                    MapBuffer = StringIO('')\r
+                    MapBuffer = []\r
                     if self.LoadFixAddress != 0:\r
                         #\r
                         # Rebase module to the preferred memory address before GenFds\r
@@ -1964,111 +2048,252 @@ class Build():
                     #\r
                     self._SaveMapFile (MapBuffer, Wa)\r
 \r
-    def _GenFfsCmd(self):\r
-        CmdListDict = {}\r
-        GenFfsDict = GenFds.GenFfsMakefile('', GlobalData.gFdfParser, self, self.ArchList, GlobalData)\r
+    def _GenFfsCmd(self,ArchList):\r
+        # convert dictionary of Cmd:(Inf,Arch)\r
+        # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...\r
+        CmdSetDict = defaultdict(set)\r
+        GenFfsDict = GenFds.GenFfsMakefile('', GlobalData.gFdfParser, self, ArchList, GlobalData)\r
         for Cmd in GenFfsDict:\r
             tmpInf, tmpArch = GenFfsDict[Cmd]\r
-            if (tmpInf, tmpArch) not in CmdListDict.keys():\r
-                CmdListDict[tmpInf, tmpArch] = [Cmd]\r
-            else:\r
-                CmdListDict[tmpInf, tmpArch].append(Cmd)\r
-        return CmdListDict\r
+            CmdSetDict[tmpInf, tmpArch].add(Cmd)\r
+        return CmdSetDict\r
+    def VerifyAutoGenFiles(self):\r
+        AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt")\r
+        try:\r
+            with open(AutoGenIdFile) as fd:\r
+                lines = fd.readlines()\r
+        except:\r
+            return None\r
+        for line in lines:\r
+            if "Arch" in line:\r
+                ArchList = line.strip().split("=")[1].split("|")\r
+            if "BuildDir" in line:\r
+                BuildDir = line.split("=")[1].strip()\r
+            if "PlatformGuid" in line:\r
+                PlatformGuid = line.split("=")[1].strip()\r
+        GlobalVarList = []\r
+        for arch in ArchList:\r
+            global_var = os.path.join(BuildDir, "GlobalVar_%s_%s.bin" % (str(PlatformGuid),arch))\r
+            if not os.path.exists(global_var):\r
+                return None\r
+            GlobalVarList.append(global_var)\r
+        for global_var in GlobalVarList:\r
+            data_pipe = MemoryDataPipe()\r
+            data_pipe.load(global_var)\r
+            target = data_pipe.Get("P_Info").get("Target")\r
+            toolchain = data_pipe.Get("P_Info").get("ToolChain")\r
+            archlist = data_pipe.Get("P_Info").get("ArchList")\r
+            Arch = data_pipe.Get("P_Info").get("Arch")\r
+            active_p = data_pipe.Get("P_Info").get("ActivePlatform")\r
+            workspacedir = data_pipe.Get("P_Info").get("WorkspaceDir")\r
+            PackagesPath = os.getenv("PACKAGES_PATH")\r
+            mws.setWs(workspacedir, PackagesPath)\r
+            LibraryBuildDirectoryList = data_pipe.Get("LibraryBuildDirectoryList")\r
+            ModuleBuildDirectoryList = data_pipe.Get("ModuleBuildDirectoryList")\r
+\r
+            for m_build_dir in LibraryBuildDirectoryList:\r
+                if not os.path.exists(os.path.join(m_build_dir,self.MakeFileName)):\r
+                    return None\r
+            for m_build_dir in ModuleBuildDirectoryList:\r
+                if not os.path.exists(os.path.join(m_build_dir,self.MakeFileName)):\r
+                    return None\r
+            Wa = WorkSpaceInfo(\r
+                workspacedir,active_p,target,toolchain,archlist\r
+                )\r
+            Pa = PlatformInfo(Wa, active_p, target, toolchain, Arch,data_pipe)\r
+            Wa.AutoGenObjectList.append(Pa)\r
+        return Wa\r
+    def SetupMakeSetting(self,Wa):\r
+        BuildModules = []\r
+        for Pa in Wa.AutoGenObjectList:\r
+            for m in Pa._MbList:\r
+                ma = ModuleAutoGen(Wa,m.MetaFile, Pa.BuildTarget, Wa.ToolChain, Pa.Arch, Pa.MetaFile,Pa.DataPipe)\r
+                BuildModules.append(ma)\r
+        fdf_file = Wa.FlashDefinition\r
+        if fdf_file:\r
+            Fdf = FdfParser(fdf_file.Path)\r
+            Fdf.ParseFile()\r
+            GlobalData.gFdfParser = Fdf\r
+            if Fdf.CurrentFdName and Fdf.CurrentFdName in Fdf.Profile.FdDict:\r
+                FdDict = Fdf.Profile.FdDict[Fdf.CurrentFdName]\r
+                for FdRegion in FdDict.RegionList:\r
+                    if str(FdRegion.RegionType) == 'FILE' and self.Platform.VpdToolGuid in str(FdRegion.RegionDataList):\r
+                        if int(FdRegion.Offset) % 8 != 0:\r
+                            EdkLogger.error("build", FORMAT_INVALID, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion.Offset))\r
+            Wa.FdfProfile = Fdf.Profile\r
+            self.Fdf = Fdf\r
+        else:\r
+            self.Fdf = None\r
+        return BuildModules\r
 \r
     ## Build a platform in multi-thread mode\r
     #\r
+    def PerformAutoGen(self,BuildTarget,ToolChain):\r
+        WorkspaceAutoGenTime = time.time()\r
+        Wa = WorkspaceAutoGen(\r
+                self.WorkspaceDir,\r
+                self.PlatformFile,\r
+                BuildTarget,\r
+                ToolChain,\r
+                self.ArchList,\r
+                self.BuildDatabase,\r
+                self.TargetTxt,\r
+                self.ToolDef,\r
+                self.Fdf,\r
+                self.FdList,\r
+                self.FvList,\r
+                self.CapList,\r
+                self.SkuId,\r
+                self.UniFlag,\r
+                self.Progress\r
+                )\r
+        self.Fdf = Wa.FdfFile\r
+        self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
+        self.BuildReport.AddPlatformReport(Wa)\r
+        Wa.CreateMakeFile(False)\r
+\r
+        # Add ffs build to makefile\r
+        CmdListDict = {}\r
+        if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
+            CmdListDict = self._GenFfsCmd(Wa.ArchList)\r
+\r
+        self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))\r
+        BuildModules = []\r
+        for Arch in Wa.ArchList:\r
+            PcdMaList    = []\r
+            AutoGenStart = time.time()\r
+            GlobalData.gGlobalDefines['ARCH'] = Arch\r
+            Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
+            if Pa is None:\r
+                continue\r
+            ModuleList = []\r
+            for Inf in Pa.Platform.Modules:\r
+                ModuleList.append(Inf)\r
+            # Add the INF only list in FDF\r
+            if GlobalData.gFdfParser is not None:\r
+                for InfName in GlobalData.gFdfParser.Profile.InfList:\r
+                    Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)\r
+                    if Inf in Pa.Platform.Modules:\r
+                        continue\r
+                    ModuleList.append(Inf)\r
+            Pa.DataPipe.DataContainer = {"FfsCommand":CmdListDict}\r
+            Pa.DataPipe.DataContainer = {"Workspace_timestamp": Wa._SrcTimeStamp}\r
+            Pa.DataPipe.DataContainer = {"CommandTarget": self.Target}\r
+            Pa.CreateLibModuelDirs()\r
+            # Fetch the MakeFileName.\r
+            self.MakeFileName = Pa.MakeFileName\r
+\r
+            Pa.DataPipe.DataContainer = {"LibraryBuildDirectoryList":Pa.LibraryBuildDirectoryList}\r
+            Pa.DataPipe.DataContainer = {"ModuleBuildDirectoryList":Pa.ModuleBuildDirectoryList}\r
+            Pa.DataPipe.DataContainer = {"FdsCommandDict": Wa.GenFdsCommandDict}\r
+            # Prepare the cache share data for multiprocessing\r
+            Pa.DataPipe.DataContainer = {"gPlatformHashFile":GlobalData.gPlatformHashFile}\r
+            ModuleCodaFile = {}\r
+            for ma in Pa.ModuleAutoGenList:\r
+                ModuleCodaFile[(ma.MetaFile.File,ma.MetaFile.Root,ma.Arch,ma.MetaFile.Path)] = [item.Target for item in ma.CodaTargetList]\r
+            Pa.DataPipe.DataContainer = {"ModuleCodaFile":ModuleCodaFile}\r
+            # ModuleList contains all driver modules only\r
+            for Module in ModuleList:\r
+                # Get ModuleAutoGen object to generate C code file and makefile\r
+                Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)\r
+                if Ma is None:\r
+                    continue\r
+                if Ma.PcdIsDriver:\r
+                    Ma.PlatformInfo = Pa\r
+                    Ma.Workspace = Wa\r
+                    PcdMaList.append(Ma)\r
+                self.AllDrivers.add(Ma)\r
+                self.AllModules.add(Ma)\r
+\r
+            mqueue = mp.Queue()\r
+            cqueue = mp.Queue()\r
+            for m in Pa.GetAllModuleInfo:\r
+                mqueue.put(m)\r
+                module_file,module_root,module_path,module_basename,\\r
+                    module_originalpath,module_arch,IsLib = m\r
+                Ma = ModuleAutoGen(Wa, PathClass(module_path, Wa), BuildTarget,\\r
+                                  ToolChain, Arch, self.PlatformFile,Pa.DataPipe)\r
+                self.AllModules.add(Ma)\r
+            data_pipe_file = os.path.join(Pa.BuildDir, "GlobalVar_%s_%s.bin" % (str(Pa.Guid),Pa.Arch))\r
+            Pa.DataPipe.dump(data_pipe_file)\r
+\r
+            mqueue.put((None,None,None,None,None,None,None))\r
+            autogen_rt, errorcode = self.StartAutoGen(mqueue, Pa.DataPipe, self.SkipAutoGen, PcdMaList, cqueue)\r
+\r
+            if not autogen_rt:\r
+                self.AutoGenMgr.TerminateWorkers()\r
+                self.AutoGenMgr.join(1)\r
+                raise FatalError(errorcode)\r
+\r
+            if GlobalData.gUseHashCache:\r
+                for item in GlobalData.gModuleAllCacheStatus:\r
+                    (MetaFilePath, Arch, CacheStr, Status) = item\r
+                    Ma = ModuleAutoGen(Wa, PathClass(MetaFilePath, Wa), BuildTarget,\\r
+                                      ToolChain, Arch, self.PlatformFile,Pa.DataPipe)\r
+                    if CacheStr == "PreMakeCache" and Status == False:\r
+                        self.PreMakeCacheMiss.add(Ma)\r
+                    if CacheStr == "PreMakeCache" and Status == True:\r
+                        self.PreMakeCacheHit.add(Ma)\r
+                        GlobalData.gModuleCacheHit.add(Ma)\r
+                    if CacheStr == "MakeCache" and Status == False:\r
+                        self.MakeCacheMiss.add(Ma)\r
+                    if CacheStr == "MakeCache" and Status == True:\r
+                        self.MakeCacheHit.add(Ma)\r
+                        GlobalData.gModuleCacheHit.add(Ma)\r
+            self.AutoGenTime += int(round((time.time() - AutoGenStart)))\r
+        AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt")\r
+        with open(AutoGenIdFile,"w") as fw:\r
+            fw.write("Arch=%s\n" % "|".join((Wa.ArchList)))\r
+            fw.write("BuildDir=%s\n" % Wa.BuildDir)\r
+            fw.write("PlatformGuid=%s\n" % str(Wa.AutoGenObjectList[0].Guid))\r
+\r
+        if GlobalData.gBinCacheSource:\r
+            BuildModules.extend(self.MakeCacheMiss)\r
+        elif GlobalData.gUseHashCache and not GlobalData.gBinCacheDest:\r
+            BuildModules.extend(self.PreMakeCacheMiss)\r
+        else:\r
+            BuildModules.extend(self.AllDrivers)\r
+\r
+        self.Progress.Stop("done!")\r
+        return Wa, BuildModules\r
+\r
     def _MultiThreadBuildPlatform(self):\r
         SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)\r
         for BuildTarget in self.BuildTargetList:\r
             GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
             index = 0\r
             for ToolChain in self.ToolChainList:\r
-                WorkspaceAutoGenTime = time.time()\r
+                resetFdsGlobalVariable()\r
                 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
                 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
                 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
                 index += 1\r
-                Wa = WorkspaceAutoGen(\r
-                        self.WorkspaceDir,\r
-                        self.PlatformFile,\r
-                        BuildTarget,\r
-                        ToolChain,\r
-                        self.ArchList,\r
-                        self.BuildDatabase,\r
-                        self.TargetTxt,\r
-                        self.ToolDef,\r
-                        self.Fdf,\r
-                        self.FdList,\r
-                        self.FvList,\r
-                        self.CapList,\r
-                        self.SkuId,\r
-                        self.UniFlag,\r
-                        self.Progress\r
-                        )\r
-                self.Fdf = Wa.FdfFile\r
-                self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
-                self.BuildReport.AddPlatformReport(Wa)\r
-                Wa.CreateMakeFile(False)\r
-\r
-                # Add ffs build to makefile\r
-                CmdListDict = None\r
-                if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
-                    CmdListDict = self._GenFfsCmd()\r
-\r
-                # multi-thread exit flag\r
                 ExitFlag = threading.Event()\r
                 ExitFlag.clear()\r
-                self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))\r
-                for Arch in Wa.ArchList:\r
-                    AutoGenStart = time.time()\r
-                    GlobalData.gGlobalDefines['ARCH'] = Arch\r
-                    Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
-                    if Pa is None:\r
-                        continue\r
-                    ModuleList = []\r
-                    for Inf in Pa.Platform.Modules:\r
-                        ModuleList.append(Inf)\r
-                    # Add the INF only list in FDF\r
-                    if GlobalData.gFdfParser is not None:\r
-                        for InfName in GlobalData.gFdfParser.Profile.InfList:\r
-                            Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)\r
-                            if Inf in Pa.Platform.Modules:\r
-                                continue\r
-                            ModuleList.append(Inf)\r
-                    for Module in ModuleList:\r
-                        # Get ModuleAutoGen object to generate C code file and makefile\r
-                        Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
-                        \r
-                        if Ma is None:\r
-                            continue\r
-                        if Ma.CanSkipbyHash():\r
-                            self.HashSkipModules.append(Ma)\r
-                            continue\r
+                if self.SkipAutoGen:\r
+                    Wa = self.VerifyAutoGenFiles()\r
+                    if Wa is None:\r
+                        self.SkipAutoGen = False\r
+                        Wa, self.BuildModules = self.PerformAutoGen(BuildTarget,ToolChain)\r
+                    else:\r
+                        GlobalData.gAutoGenPhase = True\r
+                        self.BuildModules = self.SetupMakeSetting(Wa)\r
+                else:\r
+                    Wa, self.BuildModules = self.PerformAutoGen(BuildTarget,ToolChain)\r
+                Pa = Wa.AutoGenObjectList[0]\r
+                GlobalData.gAutoGenPhase = False\r
 \r
-                        # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'\r
-                        if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
-                            # for target which must generate AutoGen code and makefile\r
-                            if not self.SkipAutoGen or self.Target == 'genc':\r
-                                Ma.CreateCodeFile(True)\r
-                            if self.Target == "genc":\r
-                                continue\r
+                if GlobalData.gBinCacheSource:\r
+                    EdkLogger.quiet("[cache Summary]: Total module num: %s" % len(self.AllModules))\r
+                    EdkLogger.quiet("[cache Summary]: PreMakecache miss num: %s " % len(self.PreMakeCacheMiss))\r
+                    EdkLogger.quiet("[cache Summary]: Makecache miss num: %s " % len(self.MakeCacheMiss))\r
 \r
-                            if not self.SkipAutoGen or self.Target == 'genmake':\r
-                                if CmdListDict and self.Fdf and (Module.File, Arch) in CmdListDict:\r
-                                    Ma.CreateMakeFile(True, CmdListDict[Module.File, Arch])\r
-                                    del CmdListDict[Module.File, Arch]\r
-                                else:\r
-                                    Ma.CreateMakeFile(True)\r
-                            if self.Target == "genmake":\r
-                                continue\r
-                        self.BuildModules.append(Ma)\r
-                    self.Progress.Stop("done!")\r
-                    self.AutoGenTime += int(round((time.time() - AutoGenStart)))\r
+                for Arch in Wa.ArchList:\r
                     MakeStart = time.time()\r
-                    for Ma in self.BuildModules:\r
+                    for Ma in set(self.BuildModules):\r
                         # Generate build task for the module\r
                         if not Ma.IsBinaryModule:\r
-                            Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))\r
+                            Bt = BuildTask.New(ModuleMakeUnit(Ma, Pa.BuildCommand,self.Target))\r
                         # Break build if any build thread has error\r
                         if BuildTask.HasError():\r
                             # we need a full version of makefile for platform\r
@@ -2081,27 +2306,30 @@ class Build():
                             BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
 \r
                     # in case there's an interruption. we need a full version of makefile for platform\r
-                    Pa.CreateMakeFile(False)\r
+\r
                     if BuildTask.HasError():\r
                         EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
                     self.MakeTime += int(round((time.time() - MakeStart)))\r
 \r
                 MakeContiue = time.time()\r
                 #\r
-                # Save temp tables to a TmpTableDict.\r
-                #\r
-                for Key in Wa.BuildDatabase._CACHE_:\r
-                    if Wa.BuildDatabase._CACHE_[Key]._RawData and Wa.BuildDatabase._CACHE_[Key]._RawData._Table and Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table:\r
-                        if TemporaryTablePattern.match(Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table):\r
-                            TmpTableDict[Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table] = Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Cur\r
-                #\r
                 #\r
                 # All modules have been put in build tasks queue. Tell task scheduler\r
                 # to exit if all tasks are completed\r
                 #\r
                 ExitFlag.set()\r
                 BuildTask.WaitForComplete()\r
-                self.CreateAsBuiltInf()\r
+                if GlobalData.gBinCacheDest:\r
+                    self.GenDestCache()\r
+                elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:\r
+                    # Only for --hash\r
+                    # Update PreMakeCacheChain files\r
+                    self.GenLocalPreMakeCache()\r
+                #\r
+                # Get Module List\r
+                #\r
+                ModuleList = {ma.Guid.upper(): ma for ma in self.BuildModules}\r
+                self.BuildModules = []\r
                 self.MakeTime += int(round((time.time() - MakeContiue)))\r
                 #\r
                 # Check for build error, and raise exception if one\r
@@ -2118,20 +2346,11 @@ class Build():
                         #\r
                         if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
                             EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS can't be set to larger than or equal to 4G for the platorm with IA32 or ARM arch modules")\r
-                    #\r
-                    # Get Module List\r
-                    #\r
-                    ModuleList = {}\r
-                    for Pa in Wa.AutoGenObjectList:\r
-                        for Ma in Pa.ModuleAutoGenList:\r
-                            if Ma is None:\r
-                                continue\r
-                            if not Ma.IsLibrary:\r
-                                ModuleList[Ma.Guid.upper()] = Ma\r
+\r
                     #\r
                     # Rebase module to the preferred memory address before GenFds\r
                     #\r
-                    MapBuffer = StringIO('')\r
+                    MapBuffer = []\r
                     if self.LoadFixAddress != 0:\r
                         self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
 \r
@@ -2140,7 +2359,11 @@ class Build():
                         # Generate FD image if there's a FDF file found\r
                         #\r
                         GenFdsStart = time.time()\r
-                        LaunchCommand(Wa.GenFdsCommand, os.getcwd())\r
+                        if GenFdsApi(Wa.GenFdsCommandDict, self.Db):\r
+                            EdkLogger.error("build", COMMAND_FAILURE)\r
+                        Threshold = self.GetFreeSizeThreshold()\r
+                        if Threshold:\r
+                            self.CheckFreeSizeThreshold(Threshold, Wa.FvDir)\r
 \r
                         #\r
                         # Create MAP file for all platform FVs after GenFds.\r
@@ -2151,129 +2374,150 @@ class Build():
                     # Save MAP buffer into MAP file.\r
                     #\r
                     self._SaveMapFile(MapBuffer, Wa)\r
+                self.CreateGuidedSectionToolsFile(Wa)\r
+\r
+    ## GetFreeSizeThreshold()\r
+    #\r
+    #   @retval int             Threshold value\r
+    #\r
+    def GetFreeSizeThreshold(self):\r
+        Threshold = None\r
+        Threshold_Str = GlobalData.gCommandLineDefines.get('FV_SPARE_SPACE_THRESHOLD')\r
+        if Threshold_Str:\r
+            try:\r
+                if Threshold_Str.lower().startswith('0x'):\r
+                    Threshold = int(Threshold_Str, 16)\r
+                else:\r
+                    Threshold = int(Threshold_Str)\r
+            except:\r
+                EdkLogger.warn("build", 'incorrect value for FV_SPARE_SPACE_THRESHOLD %s.Only decimal or hex format is allowed.' % Threshold_Str)\r
+        return Threshold\r
+\r
+    def CheckFreeSizeThreshold(self, Threshold=None, FvDir=None):\r
+        if not isinstance(Threshold, int):\r
+            return\r
+        if not isinstance(FvDir, str) or not FvDir:\r
+            return\r
+        FdfParserObject = GlobalData.gFdfParser\r
+        FvRegionNameList = [FvName for FvName in FdfParserObject.Profile.FvDict if FdfParserObject.Profile.FvDict[FvName].FvRegionInFD]\r
+        for FvName in FdfParserObject.Profile.FvDict:\r
+            if FvName in FvRegionNameList:\r
+                FvSpaceInfoFileName = os.path.join(FvDir, FvName.upper() + '.Fv.map')\r
+                if os.path.exists(FvSpaceInfoFileName):\r
+                    FileLinesList = getlines(FvSpaceInfoFileName)\r
+                    for Line in FileLinesList:\r
+                        NameValue = Line.split('=')\r
+                        if len(NameValue) == 2 and NameValue[0].strip() == 'EFI_FV_SPACE_SIZE':\r
+                            FreeSizeValue = int(NameValue[1].strip(), 0)\r
+                            if FreeSizeValue < Threshold:\r
+                                EdkLogger.error("build", FV_FREESIZE_ERROR,\r
+                                                '%s FV free space %d is not enough to meet with the required spare space %d set by -D FV_SPARE_SPACE_THRESHOLD option.' % (\r
+                                                    FvName, FreeSizeValue, Threshold))\r
+                            break\r
 \r
     ## Generate GuidedSectionTools.txt in the FV directories.\r
     #\r
-    def CreateGuidedSectionToolsFile(self):\r
+    def CreateGuidedSectionToolsFile(self,Wa):\r
         for BuildTarget in self.BuildTargetList:\r
             for ToolChain in self.ToolChainList:\r
-                Wa = WorkspaceAutoGen(\r
-                        self.WorkspaceDir,\r
-                        self.PlatformFile,\r
-                        BuildTarget,\r
-                        ToolChain,\r
-                        self.ArchList,\r
-                        self.BuildDatabase,\r
-                        self.TargetTxt,\r
-                        self.ToolDef,\r
-                        self.Fdf,\r
-                        self.FdList,\r
-                        self.FvList,\r
-                        self.CapList,\r
-                        self.SkuId,\r
-                        self.UniFlag\r
-                        )\r
                 FvDir = Wa.FvDir\r
                 if not os.path.exists(FvDir):\r
                     continue\r
-\r
                 for Arch in self.ArchList:\r
-                    # Build up the list of supported architectures for this build\r
-                    prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)\r
-\r
-                    # Look through the tool definitions for GUIDed tools\r
+                    guidList = []\r
+                    tooldefguidList = []\r
                     guidAttribs = []\r
-                    for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():\r
-                        if attrib.upper().endswith('_GUID'):\r
-                            split = attrib.split('_')\r
-                            thisPrefix = '_'.join(split[0:3]) + '_'\r
-                            if thisPrefix == prefix:\r
-                                guid = self.ToolDef.ToolsDefTxtDictionary[attrib]\r
-                                guid = guid.lower()\r
-                                toolName = split[3]\r
-                                path = '_'.join(split[0:4]) + '_PATH'\r
-                                path = self.ToolDef.ToolsDefTxtDictionary[path]\r
-                                path = self.GetFullPathOfTool(path)\r
-                                guidAttribs.append((guid, toolName, path))\r
-\r
+                    for Platform in Wa.AutoGenObjectList:\r
+                        if Platform.BuildTarget != BuildTarget:\r
+                            continue\r
+                        if Platform.ToolChain != ToolChain:\r
+                            continue\r
+                        if Platform.Arch != Arch:\r
+                            continue\r
+                        if hasattr (Platform, 'BuildOption'):\r
+                            for Tool in Platform.BuildOption:\r
+                                if 'GUID' in Platform.BuildOption[Tool]:\r
+                                    if 'PATH' in Platform.BuildOption[Tool]:\r
+                                        value = Platform.BuildOption[Tool]['GUID']\r
+                                        if value in guidList:\r
+                                            EdkLogger.error("build", FORMAT_INVALID, "Duplicate GUID value %s used with Tool %s in DSC [BuildOptions]." % (value, Tool))\r
+                                        path = Platform.BuildOption[Tool]['PATH']\r
+                                        guidList.append(value)\r
+                                        guidAttribs.append((value, Tool, path))\r
+                        for Tool in Platform.ToolDefinition:\r
+                            if 'GUID' in Platform.ToolDefinition[Tool]:\r
+                                if 'PATH' in Platform.ToolDefinition[Tool]:\r
+                                    value = Platform.ToolDefinition[Tool]['GUID']\r
+                                    if value in tooldefguidList:\r
+                                        EdkLogger.error("build", FORMAT_INVALID, "Duplicate GUID value %s used with Tool %s in tools_def.txt." % (value, Tool))\r
+                                    tooldefguidList.append(value)\r
+                                    if value in guidList:\r
+                                        # Already added by platform\r
+                                        continue\r
+                                    path = Platform.ToolDefinition[Tool]['PATH']\r
+                                    guidList.append(value)\r
+                                    guidAttribs.append((value, Tool, path))\r
+                    # Sort by GuidTool name\r
+                    guidAttribs = sorted (guidAttribs, key=lambda x: x[1])\r
                     # Write out GuidedSecTools.txt\r
                     toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')\r
                     toolsFile = open(toolsFile, 'wt')\r
                     for guidedSectionTool in guidAttribs:\r
-                        print >> toolsFile, ' '.join(guidedSectionTool)\r
+                        print(' '.join(guidedSectionTool), file=toolsFile)\r
                     toolsFile.close()\r
 \r
-    ## Returns the full path of the tool.\r
+    ## Returns the real path of the tool.\r
     #\r
-    def GetFullPathOfTool (self, tool):\r
+    def GetRealPathOfTool (self, tool):\r
         if os.path.exists(tool):\r
             return os.path.realpath(tool)\r
-        else:\r
-            # We need to search for the tool using the\r
-            # PATH environment variable.\r
-            for dirInPath in os.environ['PATH'].split(os.pathsep):\r
-                foundPath = os.path.join(dirInPath, tool)\r
-                if os.path.exists(foundPath):\r
-                    return os.path.realpath(foundPath)\r
-\r
-        # If the tool was not found in the path then we just return\r
-        # the input tool.\r
         return tool\r
 \r
     ## Launch the module or platform build\r
     #\r
     def Launch(self):\r
+        self.AllDrivers = set()\r
+        self.AllModules = set()\r
+        self.PreMakeCacheMiss = set()\r
+        self.PreMakeCacheHit = set()\r
+        self.MakeCacheMiss = set()\r
+        self.MakeCacheHit = set()\r
         if not self.ModuleFile:\r
             if not self.SpawnMode or self.Target not in ["", "all"]:\r
                 self.SpawnMode = False\r
                 self._BuildPlatform()\r
             else:\r
                 self._MultiThreadBuildPlatform()\r
-            self.CreateGuidedSectionToolsFile()\r
         else:\r
             self.SpawnMode = False\r
             self._BuildModule()\r
 \r
         if self.Target == 'cleanall':\r
-            self.Db.Close()\r
             RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)\r
 \r
     def CreateAsBuiltInf(self):\r
         for Module in self.BuildModules:\r
             Module.CreateAsBuiltInf()\r
-        for Module in self.HashSkipModules:\r
-            Module.CreateAsBuiltInf(True)\r
-        self.BuildModules = []\r
-        self.HashSkipModules = []\r
+\r
+    def GenDestCache(self):\r
+        for Module in self.AllModules:\r
+            Module.GenPreMakefileHashList()\r
+            Module.GenMakefileHashList()\r
+            Module.CopyModuleToCache()\r
+\r
+    def GenLocalPreMakeCache(self):\r
+        for Module in self.PreMakeCacheMiss:\r
+            Module.GenPreMakefileHashList()\r
+\r
     ## Do some clean-up works when error occurred\r
     def Relinquish(self):\r
         OldLogLevel = EdkLogger.GetLevel()\r
         EdkLogger.SetLevel(EdkLogger.ERROR)\r
-        #self.DumpBuildData()\r
         Utils.Progressor.Abort()\r
         if self.SpawnMode == True:\r
             BuildTask.Abort()\r
         EdkLogger.SetLevel(OldLogLevel)\r
 \r
-    def DumpBuildData(self):\r
-        CacheDirectory = os.path.dirname(GlobalData.gDatabasePath)\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(os.path.dirname(GlobalData.gDatabasePath), "gFileTimeStampCache")\r
-        if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):\r
-            Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)\r
-            if Utils.gFileTimeStampCache is None:\r
-                Utils.gFileTimeStampCache = {}\r
-\r
-        FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gDependencyDatabase")\r
-        if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):\r
-            Utils.gDependencyDatabase = Utils.DataRestore(FilePath)\r
-            if Utils.gDependencyDatabase is None:\r
-                Utils.gDependencyDatabase = {}\r
-\r
 def ParseDefines(DefineList=[]):\r
     DefineDict = {}\r
     if DefineList is not None:\r
@@ -2290,13 +2534,7 @@ def ParseDefines(DefineList=[]):
                 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()\r
     return DefineDict\r
 \r
-gParamCheck = []\r
-def SingleCheckCallback(option, opt_str, value, parser):\r
-    if option not in gParamCheck:\r
-        setattr(parser.values, option.dest, value)\r
-        gParamCheck.append(option)\r
-    else:\r
-        parser.error("Option %s only allows one instance in command line!" % option)\r
+\r
 \r
 def LogBuildTime(Time):\r
     if Time:\r
@@ -2309,79 +2547,27 @@ def LogBuildTime(Time):
         return TimeDurStr\r
     else:\r
         return None\r
+def ThreadNum():\r
+    OptionParser = MyOptionParser()\r
+    if not OptionParser.BuildOption and not OptionParser.BuildTarget:\r
+        OptionParser.GetOption()\r
+    BuildOption, BuildTarget = OptionParser.BuildOption, OptionParser.BuildTarget\r
+    ThreadNumber = BuildOption.ThreadNumber\r
+    GlobalData.gCmdConfDir = BuildOption.ConfDirectory\r
+    if ThreadNumber is None:\r
+        TargetObj = TargetTxtDict()\r
+        ThreadNumber = TargetObj.Target.TargetTxtDictionary[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]\r
+        if ThreadNumber == '':\r
+            ThreadNumber = 0\r
+        else:\r
+            ThreadNumber = int(ThreadNumber, 0)\r
 \r
-## Parse command line options\r
-#\r
-# Using standard Python module optparse to parse command line option of this tool.\r
-#\r
-#   @retval Opt   A optparse.Values object containing the parsed options\r
-#   @retval Args  Target of build command\r
-#\r
-def MyOptionParser():\r
-    Parser = OptionParser(description=__copyright__, version=__version__, prog="build.exe", usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")\r
-    Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32', 'X64', 'IPF', 'EBC', 'ARM', 'AARCH64'], dest="TargetArch",\r
-        help="ARCHS is one of list: IA32, X64, IPF, ARM, AARCH64 or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.")\r
-    Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,\r
-        help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")\r
-    Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,\r
-        help="Build the module specified by the INF file name argument.")\r
-    Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",\r
-                      action="append")\r
-    Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",\r
-        help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")\r
-    Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,\r
-        help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")\r
-\r
-    Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,\r
-        help="Build the platform using multi-threaded compiler. The value overrides target.txt's MAX_CONCURRENT_THREAD_NUMBER. When value is set to 0, tool automatically detect number of "\\r
-             "processor threads, set value to 1 means disable multi-thread build, and set value to more than 1 means user specify the threads number to build.")\r
-\r
-    Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,\r
-        help="The name of the FDF file to use, which overrides the setting in the DSC file.")\r
-    Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],\r
-        help="The name of FD to be generated. The name must be from [FD] section in FDF file.")\r
-    Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],\r
-        help="The name of FV to be generated. The name must be from [FV] section in FDF file.")\r
-    Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],\r
-        help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")\r
-    Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")\r
-    Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")\r
-\r
-    Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.")\r
-\r
-    Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")\r
-    Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")\r
-\r
-    Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",\r
-        help="Make use of silent mode of (n)make.")\r
-    Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
-    Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\\r
-                                                                               "including library instances selected, final dependency expression, "\\r
-                                                                               "and warning messages, etc.")\r
-    Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
-    Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
-\r
-    Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")\r
-    Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD','LIBRARY','FLASH','DEPEX','BUILD_FLAGS','FIXED_ADDRESS','HASH','EXECUTION_ORDER'], dest="ReportType", default=[],\r
-        help="Flags that control the type of build report to generate.  Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, HASH, EXECUTION_ORDER].  "\\r
-             "To specify more than one flag, repeat this option on the command line and the default flag set is [PCD, LIBRARY, FLASH, DEPEX, HASH, BUILD_FLAGS, FIXED_ADDRESS]")\r
-    Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",\r
-        help="Specify the specific option to parse EDK UNI file. Must be one of: [-c, -s]. -c is for EDK framework UNI file, and -s is for EDK UEFI UNI file. "\\r
-             "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\\r
-             "will override the setting in [BuildOptions] section of platform DSC.")\r
-    Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism")\r
-    Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")\r
-    Parser.add_option("--check-usage", action="store_true", dest="CheckUsage", default=False, help="Check usage content of entries listed in INF file.")\r
-    Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")\r
-    Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")\r
-    Parser.add_option("-l", "--cmd-len", action="store", type="int", dest="CommandLength", help="Specify the maximum line length of build command. Default is 4096.")\r
-    Parser.add_option("--hash", action="store_true", dest="UseHashCache", default=False, help="Enable hash-based caching during build process.")\r
-    Parser.add_option("--binary-destination", action="store", type="string", dest="BinCacheDest", help="Generate a cache of binary files in the specified directory.")\r
-    Parser.add_option("--binary-source", action="store", type="string", dest="BinCacheSource", help="Consume a cache of binary files from the specified directory.")\r
-    Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=False, help="Enable GenFds multi thread to generate ffs file.")\r
-    (Opt, Args) = Parser.parse_args()\r
-    return (Opt, Args)\r
-\r
+    if ThreadNumber == 0:\r
+        try:\r
+            ThreadNumber = multiprocessing.cpu_count()\r
+        except (ImportError, NotImplementedError):\r
+            ThreadNumber = 1\r
+    return ThreadNumber\r
 ## Tool entrance method\r
 #\r
 # This method mainly dispatch specific methods per the command line options.\r
@@ -2391,34 +2577,45 @@ def MyOptionParser():
 #   @retval 0     Tool was successful\r
 #   @retval 1     Tool failed\r
 #\r
+LogQMaxSize = ThreadNum() * 10\r
 def Main():\r
     StartTime = time.time()\r
 \r
+    #\r
+    # Create a log Queue\r
+    #\r
+    LogQ = mp.Queue(LogQMaxSize)\r
     # Initialize log system\r
-    EdkLogger.Initialize()\r
+    EdkLogger.LogClientInitialize(LogQ)\r
     GlobalData.gCommand = sys.argv[1:]\r
     #\r
     # Parse the options and args\r
     #\r
-    (Option, Target) = MyOptionParser()\r
+    OptionParser = MyOptionParser()\r
+    if not OptionParser.BuildOption and not OptionParser.BuildTarget:\r
+        OptionParser.GetOption()\r
+    Option, Target = OptionParser.BuildOption, OptionParser.BuildTarget\r
     GlobalData.gOptions = Option\r
     GlobalData.gCaseInsensitive = Option.CaseInsensitive\r
 \r
     # Set log level\r
+    LogLevel = EdkLogger.INFO\r
     if Option.verbose is not None:\r
         EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
+        LogLevel = EdkLogger.VERBOSE\r
     elif Option.quiet is not None:\r
         EdkLogger.SetLevel(EdkLogger.QUIET)\r
+        LogLevel = EdkLogger.QUIET\r
     elif Option.debug is not None:\r
         EdkLogger.SetLevel(Option.debug + 1)\r
+        LogLevel = Option.debug + 1\r
     else:\r
         EdkLogger.SetLevel(EdkLogger.INFO)\r
 \r
-    if Option.LogFile is not None:\r
-        EdkLogger.SetLogFile(Option.LogFile)\r
-\r
     if Option.WarningAsError == True:\r
         EdkLogger.SetWarningAsError()\r
+    Log_Agent = LogAgent(LogQ,LogLevel,Option.LogFile)\r
+    Log_Agent.start()\r
 \r
     if platform.platform().find("Windows") >= 0:\r
         GlobalData.gIsWindows = True\r
@@ -2492,27 +2689,23 @@ def Main():
         if Option.Flag is not None and Option.Flag not in ['-c', '-s']:\r
             EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")\r
 \r
-        MyBuild = Build(Target, Workspace, Option)\r
+        MyBuild = Build(Target, Workspace, Option,LogQ)\r
         GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)\r
         if not (MyBuild.LaunchPrebuildFlag and os.path.exists(MyBuild.PlatformBuildPath)):\r
             MyBuild.Launch()\r
-        # Drop temp tables to avoid database locked.\r
-        for TmpTableName in TmpTableDict:\r
-            SqlCommand = """drop table IF EXISTS %s""" % TmpTableName\r
-            TmpTableDict[TmpTableName].execute(SqlCommand)\r
-        #MyBuild.DumpBuildData()\r
+\r
         #\r
         # All job done, no error found and no exception raised\r
         #\r
         BuildError = False\r
-    except FatalError, X:\r
+    except FatalError as X:\r
         if MyBuild is not None:\r
             # for multi-thread build exits safely\r
             MyBuild.Relinquish()\r
         if Option is not None and Option.debug is not None:\r
             EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
         ReturnCode = X.args[0]\r
-    except Warning, X:\r
+    except Warning as X:\r
         # error from Fdf parser\r
         if MyBuild is not None:\r
             # for multi-thread build exits safely\r
@@ -2523,6 +2716,10 @@ def Main():
             EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)\r
         ReturnCode = FORMAT_INVALID\r
     except KeyboardInterrupt:\r
+        if MyBuild is not None:\r
+\r
+            # for multi-thread build exits safely\r
+            MyBuild.Relinquish()\r
         ReturnCode = ABORT_ERROR\r
         if Option is not None and Option.debug is not None:\r
             EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
@@ -2542,7 +2739,7 @@ def Main():
                     "\nbuild",\r
                     CODE_ERROR,\r
                     "Unknown fatal error when processing [%s]" % MetaFile,\r
-                    ExtraData="\n(Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!)\n",\r
+                    ExtraData="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR,\r
                     RaiseError=False\r
                     )\r
         EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
@@ -2557,6 +2754,7 @@ def Main():
             Conclusion = "Done"\r
         except:\r
             Conclusion = "Failed"\r
+            ReturnCode = POSTBUILD_ERROR\r
     elif ReturnCode == ABORT_ERROR:\r
         Conclusion = "Aborted"\r
     else:\r
@@ -2571,16 +2769,21 @@ def Main():
     if MyBuild is not None:\r
         if not BuildError:\r
             MyBuild.BuildReport.GenerateReport(BuildDurationStr, LogBuildTime(MyBuild.AutoGenTime), LogBuildTime(MyBuild.MakeTime), LogBuildTime(MyBuild.GenFdsTime))\r
-        MyBuild.Db.Close()\r
+\r
     EdkLogger.SetLevel(EdkLogger.QUIET)\r
     EdkLogger.quiet("\n- %s -" % Conclusion)\r
     EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))\r
     EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)\r
+    Log_Agent.kill()\r
+    Log_Agent.join()\r
     return ReturnCode\r
 \r
 if __name__ == '__main__':\r
+    try:\r
+        mp.set_start_method('spawn')\r
+    except:\r
+        pass\r
     r = Main()\r
     ## 0-127 is a safe return range, and 1 is a standard default error\r
     if r < 0 or r > 127: r = 1\r
     sys.exit(r)\r
-\r