]> 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
index 77b46341b5adb2a535a2538e15d40ef9ed6b5922..51fb1f433eb7878d3721e882a7ff8e19cfee4297 100755 (executable)
@@ -2,8 +2,9 @@
 # build a platform or a module\r
 #\r
 #  Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>\r
-#  Copyright (c) 2007 - 2019, 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
 #  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 #\r
@@ -24,9 +25,10 @@ import traceback
 import multiprocessing\r
 from threading import Thread,Event,BoundedSemaphore\r
 import threading\r
-from subprocess import Popen,PIPE\r
+from linecache import getlines\r
+from subprocess import Popen,PIPE, STDOUT\r
 from collections import OrderedDict, defaultdict\r
-from Common.buildoptions import BuildOption,BuildTarget\r
+\r
 from AutoGen.PlatformAutoGen import PlatformAutoGen\r
 from AutoGen.ModuleAutoGen import ModuleAutoGen\r
 from AutoGen.WorkspaceAutoGen import WorkspaceAutoGen\r
@@ -35,8 +37,9 @@ from AutoGen.AutoGenWorker import AutoGenWorkerInProcess,AutoGenManager,\
 from AutoGen import GenMake\r
 from Common import Misc as Utils\r
 \r
-from Common.TargetTxtClassObject import TargetTxt\r
-from Common.ToolDefClassObject import ToolDef\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
@@ -59,14 +62,11 @@ from AutoGen.ModuleAutoGenHelper import WorkSpaceInfo, PlatformInfo
 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
@@ -193,7 +193,7 @@ def ReadMessage(From, To, ExitFlag,MemTo=None):
                 To(LineStr)\r
         else:\r
             break\r
-        if ExitFlag.isSet():\r
+        if ExitFlag.is_set():\r
             break\r
 \r
 class MakeSubProc(Popen):\r
@@ -205,7 +205,7 @@ class MakeSubProc(Popen):
 #\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
@@ -230,22 +230,17 @@ def LaunchCommand(Command, WorkingDir,ModuleAuto = None):
     EndOfProcedure = None\r
     try:\r
         # launch the command\r
-        Proc = MakeSubProc(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,Proc.ProcOut))\r
-            StdOutThread.setName("STDOUT-Redirector")\r
-            StdOutThread.setDaemon(False)\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,Proc.ProcOut))\r
-            StdErrThread.setName("STDERR-Redirector")\r
-            StdErrThread.setDaemon(False)\r
-            StdErrThread.start()\r
 \r
         # waiting for program exit\r
         Proc.wait()\r
@@ -261,8 +256,6 @@ def LaunchCommand(Command, WorkingDir,ModuleAuto = None):
 \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
@@ -286,6 +279,7 @@ def LaunchCommand(Command, WorkingDir,ModuleAuto = None):
         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
@@ -435,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
@@ -458,7 +452,7 @@ 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
@@ -476,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
@@ -500,12 +494,12 @@ 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 as X:\r
@@ -533,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
@@ -549,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
@@ -646,7 +640,7 @@ class BuildTask:
             # 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
@@ -655,7 +649,7 @@ 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
@@ -669,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
@@ -738,11 +732,14 @@ class Build():
         self.ConfDirectory = BuildOptions.ConfDirectory\r
         self.SpawnMode      = True\r
         self.BuildReport    = BuildReport(BuildOptions.ReportFile, BuildOptions.ReportType)\r
-        self.TargetTxt      = TargetTxt\r
-        self.ToolDef        = ToolDef\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
@@ -823,8 +820,10 @@ class Build():
             EdkLogger.quiet("%-16s = %s" % ("POSTBUILD", self.Postbuild))\r
         if self.Prebuild:\r
             self.LaunchPrebuild()\r
-            self.TargetTxt = TargetTxt\r
-            self.ToolDef   = ToolDef\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
@@ -871,19 +870,65 @@ class Build():
 \r
                     PcdMa.CreateCodeFile(False)\r
                     PcdMa.CreateMakeFile(False,GenFfsList = DataPipe.Get("FfsCommand").get((PcdMa.MetaFile.Path, PcdMa.Arch),[]))\r
-\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
-            return rt, 0\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
@@ -905,6 +950,26 @@ class Build():
             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
@@ -930,23 +995,6 @@ class Build():
                 ToolChainFamily.append(ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool])\r
         self.ToolChainFamily = ToolChainFamily\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
         self.ThreadNumber   = ThreadNum()\r
     ## Initialize build configuration\r
     #\r
@@ -1125,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
@@ -1165,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
@@ -1212,7 +1260,7 @@ class Build():
             mqueue = mp.Queue()\r
             for m in AutoGenObject.GetAllModuleInfo:\r
                 mqueue.put(m)\r
-\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
@@ -1252,17 +1300,17 @@ 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
             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
@@ -1279,7 +1327,7 @@ class Build():
                 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, makefile)), 'pbuild']\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
@@ -1290,7 +1338,7 @@ class Build():
                 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, makefile)), 'pbuild']\r
+                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, self.MakeFileName)), 'pbuild']\r
                 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,LibAutoGen)\r
 \r
             DirList = []\r
@@ -1298,7 +1346,7 @@ class Build():
                 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, makefile)), 'pbuild']\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
@@ -1313,7 +1361,7 @@ class Build():
         # 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
@@ -1322,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
@@ -1414,6 +1462,9 @@ class Build():
         if Target == 'fds':\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
@@ -2041,10 +2092,10 @@ class Build():
             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,GenMake.BuildFile._FILE_NAME_[GenMake.gMakeType])):\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,GenMake.BuildFile._FILE_NAME_[GenMake.gMakeType])):\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
@@ -2129,6 +2180,9 @@ class Build():
             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
@@ -2163,6 +2217,7 @@ class Build():
             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
@@ -2264,7 +2319,6 @@ class Build():
                 #\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
@@ -2307,6 +2361,9 @@ class Build():
                         GenFdsStart = time.time()\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
@@ -2318,6 +2375,46 @@ class Build():
                     #\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,Wa):\r
@@ -2326,26 +2423,42 @@ class Build():
                 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.items():\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
@@ -2353,21 +2466,11 @@ class Build():
                         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
@@ -2445,9 +2548,15 @@ def LogBuildTime(Time):
     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
-        ThreadNumber = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]\r
+        TargetObj = TargetTxtDict()\r
+        ThreadNumber = TargetObj.Target.TargetTxtDictionary[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]\r
         if ThreadNumber == '':\r
             ThreadNumber = 0\r
         else:\r
@@ -2482,7 +2591,10 @@ def Main():
     #\r
     # Parse the options and args\r
     #\r
-    Option, Target = BuildOption, BuildTarget\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
@@ -2642,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
@@ -2674,4 +2787,3 @@ if __name__ == '__main__':
     ## 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