]> git.proxmox.com Git - mirror_edk2.git/commitdiff
BaseTools: Enable Multiple Process AutoGen
authorFeng, Bob C <bob.c.feng@intel.com>
Tue, 30 Jul 2019 09:15:31 +0000 (17:15 +0800)
committerFeng, Bob C <bob.c.feng@intel.com>
Fri, 9 Aug 2019 15:15:53 +0000 (23:15 +0800)
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=1875

Assign the Module AutoGen tasks into multiple
sub process.

Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Bob Feng <bob.c.feng@intel.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
Tested-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Liming Gao <liming.gao@intel.com>
BaseTools/Source/Python/AutoGen/AutoGenWorker.py [new file with mode: 0644]
BaseTools/Source/Python/AutoGen/DataPipe.py
BaseTools/Source/Python/AutoGen/GenC.py
BaseTools/Source/Python/AutoGen/ModuleAutoGen.py
BaseTools/Source/Python/AutoGen/PlatformAutoGen.py
BaseTools/Source/Python/AutoGen/WorkspaceAutoGen.py
BaseTools/Source/Python/build/build.py

diff --git a/BaseTools/Source/Python/AutoGen/AutoGenWorker.py b/BaseTools/Source/Python/AutoGen/AutoGenWorker.py
new file mode 100644 (file)
index 0000000..6c6ef49
--- /dev/null
@@ -0,0 +1,191 @@
+## @file\r
+# Create makefile for MS nmake and GNU make\r
+#\r
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+from __future__ import absolute_import\r
+import multiprocessing as mp\r
+import threading\r
+from Common.Misc import PathClass\r
+from AutoGen.ModuleAutoGen import ModuleAutoGen\r
+from AutoGen.ModuleAutoGenHelper import WorkSpaceInfo,AutoGenInfo\r
+import Common.GlobalData as GlobalData\r
+import Common.EdkLogger as EdkLogger\r
+import os\r
+from Common.MultipleWorkspace import MultipleWorkspace as mws\r
+from AutoGen.AutoGen import AutoGen\r
+from Workspace.WorkspaceDatabase import BuildDB\r
+from queue import Empty\r
+import traceback\r
+import sys\r
+from AutoGen.DataPipe import MemoryDataPipe\r
+def clearQ(q):\r
+    try:\r
+        while True:\r
+            q.get_nowait()\r
+    except Empty:\r
+        pass\r
+class AutoGenManager(threading.Thread):\r
+    def __init__(self,autogen_workers, feedback_q,error_event):\r
+        super(AutoGenManager,self).__init__()\r
+        self.autogen_workers = autogen_workers\r
+        self.feedback_q = feedback_q\r
+        self.terminate = False\r
+        self.Status = True\r
+        self.error_event = error_event\r
+    def run(self):\r
+        try:\r
+            fin_num = 0\r
+            while True:\r
+                badnews = self.feedback_q.get()\r
+                if badnews is None:\r
+                    break\r
+                if badnews == "Done":\r
+                    fin_num += 1\r
+                else:\r
+                    self.Status = False\r
+                    self.TerminateWorkers()\r
+                if fin_num == len(self.autogen_workers):\r
+                    self.clearQueue()\r
+                    for w in self.autogen_workers:\r
+                        w.join()\r
+                    break\r
+        except Exception:\r
+            return\r
+\r
+    def clearQueue(self):\r
+        taskq = self.autogen_workers[0].module_queue\r
+        clearQ(taskq)\r
+        clearQ(self.feedback_q)\r
+\r
+    def TerminateWorkers(self):\r
+        self.error_event.set()\r
+    def kill(self):\r
+        self.feedback_q.put(None)\r
+class AutoGenWorkerInProcess(mp.Process):\r
+    def __init__(self,module_queue,data_pipe_file_path,feedback_q,file_lock,error_event):\r
+        mp.Process.__init__(self)\r
+        self.module_queue = module_queue\r
+        self.data_pipe_file_path =data_pipe_file_path\r
+        self.data_pipe = None\r
+        self.feedback_q = feedback_q\r
+        self.PlatformMetaFileSet = {}\r
+        self.file_lock = file_lock\r
+        self.error_event = error_event\r
+    def GetPlatformMetaFile(self,filepath,root):\r
+        try:\r
+            return self.PlatformMetaFileSet[(filepath,root)]\r
+        except:\r
+            self.PlatformMetaFileSet[(filepath,root)]  = filepath\r
+            return self.PlatformMetaFileSet[(filepath,root)]\r
+    def run(self):\r
+        try:\r
+            taskname = "Init"\r
+            with self.file_lock:\r
+                if not os.path.exists(self.data_pipe_file_path):\r
+                    self.feedback_q.put(taskname + ":" + "load data pipe %s failed." % self.data_pipe_file_path)\r
+                self.data_pipe = MemoryDataPipe()\r
+                self.data_pipe.load(self.data_pipe_file_path)\r
+            EdkLogger.Initialize()\r
+            loglevel = self.data_pipe.Get("LogLevel")\r
+            if not loglevel:\r
+                loglevel = EdkLogger.INFO\r
+            EdkLogger.SetLevel(loglevel)\r
+            logfile = self.data_pipe.Get("LogFile")\r
+            if logfile:\r
+                EdkLogger.SetLogFile(logfile)\r
+            target = self.data_pipe.Get("P_Info").get("Target")\r
+            toolchain = self.data_pipe.Get("P_Info").get("ToolChain")\r
+            archlist = self.data_pipe.Get("P_Info").get("ArchList")\r
+\r
+            active_p = self.data_pipe.Get("P_Info").get("ActivePlatform")\r
+            workspacedir = self.data_pipe.Get("P_Info").get("WorkspaceDir")\r
+            PackagesPath = os.getenv("PACKAGES_PATH")\r
+            mws.setWs(workspacedir, PackagesPath)\r
+            self.Wa = WorkSpaceInfo(\r
+                workspacedir,active_p,target,toolchain,archlist\r
+                )\r
+            self.Wa._SrcTimeStamp = self.data_pipe.Get("Workspace_timestamp")\r
+            GlobalData.gGlobalDefines = self.data_pipe.Get("G_defines")\r
+            GlobalData.gCommandLineDefines = self.data_pipe.Get("CL_defines")\r
+            os.environ._data = self.data_pipe.Get("Env_Var")\r
+            GlobalData.gWorkspace = workspacedir\r
+            GlobalData.gDisableIncludePathCheck = False\r
+            GlobalData.gFdfParser = self.data_pipe.Get("FdfParser")\r
+            GlobalData.gDatabasePath = self.data_pipe.Get("DatabasePath")\r
+            pcd_from_build_option = []\r
+            for pcd_tuple in self.data_pipe.Get("BuildOptPcd"):\r
+                pcd_id = ".".join((pcd_tuple[0],pcd_tuple[1]))\r
+                if pcd_tuple[2].strip():\r
+                    pcd_id = ".".join((pcd_id,pcd_tuple[2]))\r
+                pcd_from_build_option.append("=".join((pcd_id,pcd_tuple[3])))\r
+            GlobalData.BuildOptionPcd = pcd_from_build_option\r
+            module_count = 0\r
+            FfsCmd = self.data_pipe.Get("FfsCommand")\r
+            if FfsCmd is None:\r
+                FfsCmd = {}\r
+            PlatformMetaFile = self.GetPlatformMetaFile(self.data_pipe.Get("P_Info").get("ActivePlatform"),\r
+                                             self.data_pipe.Get("P_Info").get("WorkspaceDir"))\r
+            libConstPcd = self.data_pipe.Get("LibConstPcd")\r
+            Refes = self.data_pipe.Get("REFS")\r
+            while True:\r
+                if self.module_queue.empty():\r
+                    break\r
+                if self.error_event.is_set():\r
+                    break\r
+                module_count += 1\r
+                module_file,module_root,module_path,module_basename,module_originalpath,module_arch,IsLib = self.module_queue.get_nowait()\r
+                modulefullpath = os.path.join(module_root,module_file)\r
+                taskname = " : ".join((modulefullpath,module_arch))\r
+                module_metafile = PathClass(module_file,module_root)\r
+                if module_path:\r
+                    module_metafile.Path = module_path\r
+                if module_basename:\r
+                    module_metafile.BaseName = module_basename\r
+                if module_originalpath:\r
+                    module_metafile.OriginalPath = PathClass(module_originalpath,module_root)\r
+                arch = module_arch\r
+                target = self.data_pipe.Get("P_Info").get("Target")\r
+                toolchain = self.data_pipe.Get("P_Info").get("ToolChain")\r
+                Ma = ModuleAutoGen(self.Wa,module_metafile,target,toolchain,arch,PlatformMetaFile,self.data_pipe)\r
+                Ma.IsLibrary = IsLib\r
+                if IsLib:\r
+                    if (Ma.MetaFile.File,Ma.MetaFile.Root,Ma.Arch,Ma.MetaFile.Path) in libConstPcd:\r
+                        Ma.ConstPcd = libConstPcd[(Ma.MetaFile.File,Ma.MetaFile.Root,Ma.Arch,Ma.MetaFile.Path)]\r
+                    if (Ma.MetaFile.File,Ma.MetaFile.Root,Ma.Arch,Ma.MetaFile.Path) in Refes:\r
+                        Ma.ReferenceModules = Refes[(Ma.MetaFile.File,Ma.MetaFile.Root,Ma.Arch,Ma.MetaFile.Path)]\r
+                Ma.CreateCodeFile(False)\r
+                Ma.CreateMakeFile(False,GenFfsList=FfsCmd.get((Ma.MetaFile.File, Ma.Arch),[]))\r
+        except Empty:\r
+            pass\r
+        except:\r
+            traceback.print_exc(file=sys.stdout)\r
+            self.feedback_q.put(taskname)\r
+        finally:\r
+            self.feedback_q.put("Done")\r
+    def printStatus(self):\r
+        print("Processs ID: %d Run %d modules in AutoGen " % (os.getpid(),len(AutoGen.Cache())))\r
+        print("Processs ID: %d Run %d modules in AutoGenInfo " % (os.getpid(),len(AutoGenInfo.GetCache())))\r
+        groupobj = {}\r
+        for buildobj in BuildDB.BuildObject.GetCache().values():\r
+            if str(buildobj).lower().endswith("dec"):\r
+                try:\r
+                    groupobj['dec'].append(str(buildobj))\r
+                except:\r
+                    groupobj['dec'] = [str(buildobj)]\r
+            if str(buildobj).lower().endswith("dsc"):\r
+                try:\r
+                    groupobj['dsc'].append(str(buildobj))\r
+                except:\r
+                    groupobj['dsc'] = [str(buildobj)]\r
+\r
+            if str(buildobj).lower().endswith("inf"):\r
+                try:\r
+                    groupobj['inf'].append(str(buildobj))\r
+                except:\r
+                    groupobj['inf'] = [str(buildobj)]\r
+\r
+        print("Processs ID: %d Run %d pkg in WDB " % (os.getpid(),len(groupobj.get("dec",[]))))\r
+        print("Processs ID: %d Run %d pla in WDB " % (os.getpid(),len(groupobj.get("dsc",[]))))\r
+        print("Processs ID: %d Run %d inf in WDB " % (os.getpid(),len(groupobj.get("inf",[]))))\r
index 5bcc39bd380d13fca4baa4012b0292bdfe5d62a4..62992080567f1bbafc0947e6555d7cb1a4511225 100644 (file)
@@ -11,6 +11,7 @@ import Common.GlobalData as GlobalData
 import os\r
 import pickle\r
 from pickle import HIGHEST_PROTOCOL\r
+from Common import EdkLogger\r
 \r
 class PCD_DATA():\r
     def __init__(self,TokenCName,TokenSpaceGuidCName,Type,DatumType,SkuInfoList,DefaultValue,\r
@@ -34,6 +35,7 @@ class DataPipe(object):
     def __init__(self, BuildDir=None):\r
         self.data_container = {}\r
         self.BuildDir = BuildDir\r
+        self.dump_file = ""\r
 \r
 class MemoryDataPipe(DataPipe):\r
 \r
@@ -41,6 +43,7 @@ class MemoryDataPipe(DataPipe):
         return self.data_container.get(key)\r
 \r
     def dump(self,file_path):\r
+        self.dump_file = file_path\r
         with open(file_path,'wb') as fd:\r
             pickle.dump(self.data_container,fd,pickle.HIGHEST_PROTOCOL)\r
 \r
@@ -71,7 +74,7 @@ class MemoryDataPipe(DataPipe):
         for m in PlatformInfo.Platform.Modules:\r
             m_pcds =  PlatformInfo.Platform.Modules[m].Pcds\r
             if m_pcds:\r
-                ModulePcds[(m.File,m.Root)] = [PCD_DATA(\r
+                ModulePcds[(m.File,m.Root,m.Arch)] = [PCD_DATA(\r
             pcd.TokenCName,pcd.TokenSpaceGuidCName,pcd.Type,\r
             pcd.DatumType,pcd.SkuInfoList,pcd.DefaultValue,\r
             pcd.MaxDatumSize,pcd.UserDefinedDefaultStoresFlag,pcd.validateranges,\r
@@ -83,11 +86,18 @@ class MemoryDataPipe(DataPipe):
 \r
         #Module's Library Instance\r
         ModuleLibs = {}\r
+        libModules = {}\r
         for m in PlatformInfo.Platform.Modules:\r
             module_obj = BuildDB.BuildObject[m,PlatformInfo.Arch,PlatformInfo.BuildTarget,PlatformInfo.ToolChain]\r
             Libs = GetModuleLibInstances(module_obj, PlatformInfo.Platform, BuildDB.BuildObject, PlatformInfo.Arch,PlatformInfo.BuildTarget,PlatformInfo.ToolChain)\r
-            ModuleLibs[(m.File,m.Root,module_obj.Arch)] = [(l.MetaFile.File,l.MetaFile.Root,l.Arch) for l in Libs]\r
+            for lib in Libs:\r
+                try:\r
+                    libModules[(lib.MetaFile.File,lib.MetaFile.Root,lib.Arch,lib.MetaFile.Path)].append((m.File,m.Root,module_obj.Arch,m.Path))\r
+                except:\r
+                    libModules[(lib.MetaFile.File,lib.MetaFile.Root,lib.Arch,lib.MetaFile.Path)] = [(m.File,m.Root,module_obj.Arch,m.Path)]\r
+            ModuleLibs[(m.File,m.Root,module_obj.Arch,m.Path)] = [(l.MetaFile.File,l.MetaFile.Root,l.Arch,l.MetaFile.Path) for l in Libs]\r
         self.DataContainer = {"DEPS":ModuleLibs}\r
+        self.DataContainer = {"REFS":libModules}\r
 \r
         #Platform BuildOptions\r
 \r
@@ -143,5 +153,8 @@ class MemoryDataPipe(DataPipe):
 \r
         self.DataContainer = {"GuidDict": PlatformInfo.Platform._GuidDict}\r
 \r
+        self.DataContainer = {"DatabasePath":GlobalData.gDatabasePath}\r
         self.DataContainer = {"FdfParser": True if GlobalData.gFdfParser else False}\r
 \r
+        self.DataContainer = {"LogLevel": EdkLogger.GetLevel()}\r
+        self.DataContainer = {"LogFile": GlobalData.gOptions.LogFile if GlobalData.gOptions.LogFile is not None else ""}\r
index 4c3f4e3e55aed569dc6c9bfa4a893a629dc4ff73..910c8fe3706c1fe97231e87862e37bfad6ee3652 100644 (file)
@@ -1472,8 +1472,8 @@ def CreateModuleEntryPointCode(Info, AutoGenC, AutoGenH):
 \r
     if Info.ModuleType in [SUP_MODULE_PEI_CORE, SUP_MODULE_DXE_CORE, SUP_MODULE_SMM_CORE, SUP_MODULE_MM_CORE_STANDALONE]:\r
         if Info.SourceFileList:\r
-          if NumEntryPoints != 1:\r
-              EdkLogger.error(\r
+            if NumEntryPoints != 1:\r
+                EdkLogger.error(\r
                   "build",\r
                   AUTOGEN_ERROR,\r
                   '%s must have exactly one entry point' % Info.ModuleType,\r
index d19c03862094910172fe0d38e5b2d4fafe3379f4..ed6822334e935b5fe28e1d0c52479e23092a7de5 100644 (file)
@@ -1686,6 +1686,7 @@ class ModuleAutoGen(AutoGen):
         if not self.IsLibrary and CreateLibraryMakeFile:\r
             for LibraryAutoGen in self.LibraryAutoGenList:\r
                 LibraryAutoGen.CreateMakeFile()\r
+\r
         # Don't enable if hash feature enabled, CanSkip uses timestamps to determine build skipping\r
         if not GlobalData.gUseHashCache and self.CanSkip():\r
             return\r
@@ -1729,7 +1730,6 @@ class ModuleAutoGen(AutoGen):
         if not self.IsLibrary and CreateLibraryCodeFile:\r
             for LibraryAutoGen in self.LibraryAutoGenList:\r
                 LibraryAutoGen.CreateCodeFile()\r
-\r
         # Don't enable if hash feature enabled, CanSkip uses timestamps to determine build skipping\r
         if not GlobalData.gUseHashCache and self.CanSkip():\r
             return\r
index 6c947eca2b57b15fd3546f511e451b46537a76f7..4abfc6c29d1b803e23c91d76280c252fa6fa29f7 100644 (file)
@@ -133,6 +133,12 @@ class PlatformAutoGen(AutoGen):
         self.DataPipe.FillData(self)\r
 \r
         return True\r
+    def FillData_LibConstPcd(self):\r
+        libConstPcd = {}\r
+        for LibAuto in self.LibraryAutoGenList:\r
+            if LibAuto.ConstPcd:\r
+                libConstPcd[(LibAuto.MetaFile.File,LibAuto.MetaFile.Root,LibAuto.Arch,LibAuto.MetaFile.Path)] = LibAuto.ConstPcd\r
+        self.DataPipe.DataContainer = {"LibConstPcd":libConstPcd}\r
     ## hash() operator of PlatformAutoGen\r
     #\r
     #  The platform file path and arch string will be used to represent\r
@@ -162,7 +168,7 @@ class PlatformAutoGen(AutoGen):
             return\r
 \r
         for Ma in self.ModuleAutoGenList:\r
-            Ma.CreateCodeFile(True)\r
+            Ma.CreateCodeFile(CreateModuleCodeFile)\r
 \r
     ## Generate Fds Command\r
     @cached_property\r
@@ -179,9 +185,9 @@ class PlatformAutoGen(AutoGen):
             for Ma in self._MaList:\r
                 key = (Ma.MetaFile.File, self.Arch)\r
                 if key in FfsCommand:\r
-                    Ma.CreateMakeFile(True, FfsCommand[key])\r
+                    Ma.CreateMakeFile(CreateModuleMakeFile, FfsCommand[key])\r
                 else:\r
-                    Ma.CreateMakeFile(True)\r
+                    Ma.CreateMakeFile(CreateModuleMakeFile)\r
 \r
         # no need to create makefile for the platform more than once\r
         if self.IsMakeFileCreated:\r
@@ -1086,10 +1092,10 @@ class PlatformAutoGen(AutoGen):
                 Libs = GetModuleLibInstances(module_obj, self.Platform, self.BuildDatabase, self.Arch,self.BuildTarget,self.ToolChain)\r
             else:\r
                 Libs = []\r
-            ModuleLibs.update( set([(l.MetaFile.File,l.MetaFile.Root,l.Arch,True) for l in Libs]))\r
+            ModuleLibs.update( set([(l.MetaFile.File,l.MetaFile.Root,l.MetaFile.Path,l.MetaFile.BaseName,l.MetaFile.OriginalPath,l.Arch,True) for l in Libs]))\r
             if WithoutPcd and module_obj.PcdIsDriver:\r
                 continue\r
-            ModuleLibs.add((m.File,m.Root,module_obj.Arch,False))\r
+            ModuleLibs.add((m.File,m.Root,m.Path,m.BaseName,m.OriginalPath,module_obj.Arch,bool(module_obj.LibraryClass)))\r
 \r
         return ModuleLibs\r
 \r
index 22a7d996fd3bef780753a98f4e0a18319f81c03b..ea0d8f8bfbbed9d82588105b9b5b919893a09bcd 100644 (file)
@@ -113,6 +113,8 @@ class WorkspaceAutoGen(AutoGen):
         self.ProcessMixedPcd()\r
         self.VerifyPcdsFromFDF()\r
         self.CollectAllPcds()\r
+        for Pa in self.AutoGenObjectList:\r
+            Pa.FillData_LibConstPcd()\r
         self.GeneratePkgLevelHash()\r
         #\r
         # Check PCDs token value conflict in each DEC file.\r
@@ -881,7 +883,7 @@ class WorkspaceAutoGen(AutoGen):
         if not CreateDepsMakeFile:\r
             return\r
         for Pa in self.AutoGenObjectList:\r
-            Pa.CreateMakeFile(True)\r
+            Pa.CreateMakeFile(CreateDepsMakeFile)\r
 \r
     ## Create autogen code for platform and modules\r
     #\r
@@ -895,7 +897,7 @@ class WorkspaceAutoGen(AutoGen):
         if not CreateDepsCodeFile:\r
             return\r
         for Pa in self.AutoGenObjectList:\r
-            Pa.CreateCodeFile(True)\r
+            Pa.CreateCodeFile(CreateDepsCodeFile)\r
 \r
     ## Create AsBuilt INF file the platform\r
     #\r
index 3d083f4eaade6239f8b1df766f0fa4b288f05770..af1be8d281361ff32fd32b6a701cb88f92331bb6 100644 (file)
@@ -30,6 +30,7 @@ from optparse import OptionParser
 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
 from AutoGen import GenMake\r
 from Common import Misc as Utils\r
 \r
@@ -50,7 +51,7 @@ from PatchPcdValue.PatchPcdValue import PatchBinaryFile
 \r
 import Common.GlobalData as GlobalData\r
 from GenFds.GenFds import GenFds, GenFdsApi\r
-\r
+import multiprocessing as mp\r
 \r
 # Version and Copyright\r
 VersionNumber = "0.60" + ' ' + gBUILD_VERSION\r
@@ -343,9 +344,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
@@ -364,10 +365,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
@@ -824,8 +825,31 @@ class Build():
         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
+    def StartAutoGen(self,mqueue, DataPipe,SkipAutoGen,PcdMaList):\r
+        try:\r
+            if SkipAutoGen:\r
+                return True,0\r
+            feedback_q = mp.Queue()\r
+            file_lock = mp.Lock()\r
+            error_event = mp.Event()\r
+            auto_workers = [AutoGenWorkerInProcess(mqueue,DataPipe.dump_file,feedback_q,file_lock,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
+                    PcdMa.CreateCodeFile(False)\r
+                    PcdMa.CreateMakeFile(False,GenFfsList = DataPipe.Get("FfsCommand").get((PcdMa.MetaFile.File, PcdMa.Arch),[]))\r
+\r
+            self.AutoGenMgr.join()\r
+            rt = self.AutoGenMgr.Status\r
+            return rt, 0\r
+        except Exception as e:\r
+            return False,e.errcode\r
 \r
     ## Load configuration\r
     #\r
@@ -1190,30 +1214,34 @@ 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
+\r
+            AutoGenObject.DataPipe.DataContainer = {"FfsCommand":FfsCommand}\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
+            autogen_rt,errorcode = self.StartAutoGen(mqueue, AutoGenObject.DataPipe, self.SkipAutoGen, PcdMaList)\r
+            self.Progress.Stop("done!")\r
+            if not autogen_rt:\r
+                self.AutoGenMgr.TerminateWorkers()\r
+                self.AutoGenMgr.join(0.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
@@ -1334,8 +1362,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
@@ -1713,9 +1741,10 @@ class Build():
                             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
+                    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
@@ -1850,7 +1879,7 @@ class Build():
                     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
@@ -1980,7 +2009,7 @@ class Build():
                 Wa.CreateMakeFile(False)\r
 \r
                 # Add ffs build to makefile\r
-                CmdListDict = None\r
+                CmdListDict = {}\r
                 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
                     CmdListDict = self._GenFfsCmd(Wa.ArchList)\r
 \r
@@ -1988,6 +2017,7 @@ class Build():
                 ExitFlag = threading.Event()\r
                 ExitFlag.clear()\r
                 self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))\r
+                self.BuildModules = []\r
                 for Arch in Wa.ArchList:\r
                     PcdMaList    = []\r
                     AutoGenStart = time.time()\r
@@ -2005,6 +2035,8 @@ class Build():
                             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
                     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
@@ -2013,6 +2045,7 @@ class Build():
                             continue\r
                         if Ma.PcdIsDriver:\r
                             Ma.PlatformInfo = Pa\r
+                            Ma.Workspace = Wa\r
                             PcdMaList.append(Ma)\r
                         if Ma.CanSkipbyHash():\r
                             self.HashSkipModules.append(Ma)\r
@@ -2024,34 +2057,32 @@ class Build():
                                 EdkLogger.quiet("cache miss: %s[%s]" % (Ma.MetaFile.Path, Ma.Arch))\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
 \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
                         # Initialize all modules in tracking to 'FAIL'\r
                         if Ma.Arch not in GlobalData.gModuleBuildTracking:\r
                             GlobalData.gModuleBuildTracking[Ma.Arch] = dict()\r
                         if Ma not in GlobalData.gModuleBuildTracking[Ma.Arch]:\r
                             GlobalData.gModuleBuildTracking[Ma.Arch][Ma] = 'FAIL'\r
+                    mqueue = mp.Queue()\r
+                    for m in Pa.GetAllModuleInfo:\r
+                        mqueue.put(m)\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
+                    autogen_rt, errorcode = self.StartAutoGen(mqueue, Pa.DataPipe, self.SkipAutoGen, PcdMaList)\r
                     self.Progress.Stop("done!")\r
                     self.AutoGenTime += int(round((time.time() - AutoGenStart)))\r
+                    if not autogen_rt:\r
+                        self.AutoGenMgr.TerminateWorkers()\r
+                        self.AutoGenMgr.join(0.1)\r
+                        raise FatalError(errorcode)\r
+                for Arch in Wa.ArchList:\r
                     MakeStart = time.time()\r
                     for Ma in 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
@@ -2498,6 +2529,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
@@ -2554,6 +2589,10 @@ def Main():
     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