a) Supported MAKE command in tools_def.txt
authorjwang36 <jwang36@7335b38e-4728-0410-8992-fb3ffe349368>
Thu, 11 Oct 2007 08:50:35 +0000 (08:50 +0000)
committerjwang36 <jwang36@7335b38e-4728-0410-8992-fb3ffe349368>
Thu, 11 Oct 2007 08:50:35 +0000 (08:50 +0000)
b) Cleaned several message strings
c) Solved hang issue when the build.exe is broken by Ctrl+C
d) Added more specific information for "-v" option of build.exe
e) Added "-v"/"-d"/"-q" option for GenFds.exe in makefile if build.exe is called with one of them.

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

Source/Python/AutoGen/AutoGen.py
Source/Python/AutoGen/GenMake.py
Source/Python/Common/EdkIIWorkspaceBuild.py
Source/Python/Common/EdkLogger.py
Source/Python/Common/ToolDefClassObject.py
Source/Python/build/build.py

index bb0f470..9e39eed 100755 (executable)
@@ -242,6 +242,24 @@ class PlatformAutoGen:
     def GetMakeFileDir(self):\r
         return os.path.join(self.WorkspaceDir, self.BuildInfo[self.ArchList[0]].MakeFileDir)\r
 \r
+    ## Return build command string\r
+    #\r
+    #   @retval     string  Build command string\r
+    #\r
+    def GetBuildCommand(self, Arch=None):\r
+        if Arch != None:\r
+            Arch = [Arch]\r
+        else:\r
+            Arch = self.ArchList\r
+        CommandString = ""\r
+        for A in Arch:\r
+            if A in self.BuildInfo and "MAKE" in self.BuildInfo[A].ToolPath:\r
+                CommandString = self.BuildInfo[A].ToolPath["MAKE"]\r
+                if "MAKE" in self.BuildInfo[A].ToolOption:\r
+                    CommandString = CommandString + " " + self.BuildInfo[A].ToolOption["MAKE"]\r
+                break\r
+        return CommandString\r
+\r
     ## Parse build_rule.txt in $(WORKSPACE)/Conf/build_rule.txt\r
     #\r
     #   @retval     BuildRule object\r
@@ -783,6 +801,13 @@ class ModuleAutoGen(object):
     def GetMakeFileDir(self):\r
         return os.path.join(self.WorkspaceDir, self.BuildInfo.MakeFileDir)\r
 \r
+    ## Return build command string\r
+    #\r
+    #   @retval     string  Build command string\r
+    #\r
+    def GetBuildCommand(self):\r
+        return self.PlatformAutoGen.GetBuildCommand(self.Arch)\r
+\r
     ## Get object list of all packages the module and its dependent libraries belong to\r
     #\r
     #   @retval     list    The list of package object\r
index cbcfe64..3981f6c 100755 (executable)
@@ -47,7 +47,7 @@ gMakefileHeader = '''#
 '''\r
 \r
 gLibraryMakeCommand = '''cd %(makedir)s\r
-\t$(MAKE) $(MAKE_FLAGS) %(target)s\r
+\t"$(MAKE)" $(MAKE_FLAGS) %(target)s\r
 \tcd $(MODULE_BUILD_DIR)'''\r
 \r
 gMakeType = ""\r
@@ -170,7 +170,6 @@ ${END}
 #\r
 ${BEGIN}${tool_code}_FLAGS = $(DEFAULT_${tool_code}_FLAGS) $(PLATFORM_${tool_code}_FLAGS) $(MODULE_${tool_code}_FLAGS)\r
 ${END}\r
-MAKE_FLAGS = /nologo\r
 \r
 #\r
 # ToolsPathMacro\r
@@ -279,7 +278,6 @@ ${END}
 #\r
 ${BEGIN}${tool_code}_FLAGS = $(DEFAULT_${tool_code}_FLAGS) $(PLATFORM_${tool_code}_FLAGS) $(MODULE_${tool_code}_FLAGS)\r
 ${END}\r
-MAKE_FLAGS = /nologo\r
 \r
 #\r
 # Tools Path Macro\r
@@ -368,7 +366,7 @@ init:
 #\r
 gen_libs:\r
 \t${BEGIN}cd $(BUILD_DIR)${separator}$(ARCH)${separator}${dependent_library_build_directory}\r
-\t$(MAKE) $(MAKE_FLAGS)\r
+\t"$(MAKE)" $(MAKE_FLAGS)\r
 \t${END}cd $(MODULE_BUILD_DIR)\r
 \r
 #\r
@@ -376,7 +374,7 @@ gen_libs:
 #\r
 gen_fds:\r
 \tcd $(BUILD_DIR)\r
-\t$(MAKE) $(MAKE_FLAGS) fds\r
+\t"$(MAKE)" $(MAKE_FLAGS) fds\r
 \tcd $(MODULE_BUILD_DIR)\r
 \r
 #\r
@@ -415,7 +413,7 @@ cleanpch:
 \r
 cleanlib:\r
 \t${BEGIN}cd $(BUILD_DIR)${separator}$(ARCH)${separator}${dependent_library_build_directory}\r
-\t$(MAKE) $(MAKE_FLAGS) cleanall\r
+\t"$(MAKE)" $(MAKE_FLAGS) cleanall\r
 \t${END}cd $(MODULE_BUILD_DIR)\r
 \r
 '''\r
@@ -437,7 +435,9 @@ PLATFORM_OUTPUT_DIR = ${platform_output_directory}
 #\r
 TOOLCHAIN_TAG = ${toolchain_tag}\r
 TARGET = ${build_target}\r
-MAKE_FLAGS = /nologo\r
+\r
+MAKE = ${make_path}\r
+MAKE_FLAGS = ${make_flag}\r
 \r
 #\r
 # Build Directory Macro Definition\r
@@ -477,7 +477,7 @@ fds: init build_fds
 #\r
 build_libraries:\r
 \t${BEGIN}cd $(WORKSPACE)${separator}${library_build_directory}\r
-\t$(MAKE) $(MAKE_FLAGS) pbuild\r
+\t"$(MAKE)" $(MAKE_FLAGS) pbuild\r
 \t${END}cd $(BUILD_DIR)\r
 \r
 #\r
@@ -485,7 +485,7 @@ build_libraries:
 #\r
 build_modules:\r
 \t${BEGIN}cd $(WORKSPACE)${separator}${module_build_directory}\r
-\t$(MAKE) $(MAKE_FLAGS) pbuild\r
+\t"$(MAKE)" $(MAKE_FLAGS) pbuild\r
 \t${END}cd $(BUILD_DIR)\r
 \r
 #\r
@@ -493,7 +493,7 @@ build_modules:
 #\r
 build_fds:\r
 \t-@echo Generating flash image, if any ...\r
-${BEGIN}\tGenFds -f ${fdf_file} -o $(BUILD_DIR) -t $(TOOLCHAIN_TAG) -b $(TARGET) -p ${active_platform} -a ${build_architecture_list}${END}${BEGIN} -r ${fd} ${END}${BEGIN} -i ${fv} ${END}\r
+${BEGIN}\tGenFds -f ${fdf_file} -o $(BUILD_DIR) -t $(TOOLCHAIN_TAG) -b $(TARGET) -p ${active_platform} -a ${build_architecture_list}${END}${BEGIN} -r ${fd} ${END}${BEGIN} -i ${fv} ${END} ${log_level}\r
 \r
 #\r
 # run command for emulator platform only\r
@@ -508,9 +508,9 @@ run:
 #\r
 clean:\r
 \t${BEGIN}cd $(WORKSPACE)${separator}${library_build_directory}\r
-\t$(MAKE) $(MAKE_FLAGS) clean\r
+\t"$(MAKE)" $(MAKE_FLAGS) clean\r
 \t${END}${BEGIN}cd $(WORKSPACE)${separator}${module_build_directory}\r
-\t$(MAKE) $(MAKE_FLAGS) clean\r
+\t"$(MAKE)" $(MAKE_FLAGS) clean\r
 \t${END}cd $(BUILD_DIR)\r
 \r
 #\r
@@ -525,7 +525,7 @@ cleanall:
 #\r
 cleanlib:\r
 \t${BEGIN}cd $(WORKSPACE)${separator}${library_build_directory}\r
-\t$(MAKE) $(MAKE_FLAGS) cleanall\r
+\t"$(MAKE)" $(MAKE_FLAGS) cleanall\r
 \t${END}cd $(BUILD_DIR)\r
 \r
 '''\r
@@ -634,6 +634,17 @@ class Makefile(object):
         else:\r
             FdfFileList = []\r
 \r
+        # pass log level to external program called in makefile, currently GenFds.exe\r
+        LogLevel = EdkLogger.GetLevel()\r
+        if LogLevel == EdkLogger.VERBOSE:\r
+            LogOption = "-v"\r
+        elif LogLevel <= EdkLogger.DEBUG_9:\r
+            LogOption = "-d %d" % (LogLevel - 1)\r
+        elif LogLevel == EdkLogger.QUIET:\r
+            LogOption = "-q"\r
+        else:\r
+            LogOption = ""\r
+\r
         MakefileName = gMakefileName[MakeType]\r
         MakefileTemplateDict = {\r
             "makefile_header"           : gMakefileHeader % MakefileName,\r
@@ -647,6 +658,8 @@ class Makefile(object):
 \r
             "toolchain_tag"             : PlatformInfo.ToolChain,\r
             "build_target"              : PlatformInfo.BuildTarget,\r
+            "make_path"                 : PlatformInfo.ToolPath["MAKE"],\r
+            "make_flag"                 : PlatformInfo.ToolOption["MAKE"],\r
             "build_architecture_list"   : ",".join(ArchList),\r
             "architecture"              : self.PlatformInfo.keys(),\r
             "separator"                 : Separator,\r
@@ -659,7 +672,8 @@ class Makefile(object):
             "fdf_file"                  : FdfFileList,\r
             "active_platform"           : PlatformInfo.WorkspaceDir + Separator + ActivePlatform.DescFilePath,\r
             "fd"                        : PlatformInfo.FdTargetList,\r
-            "fv"                        : PlatformInfo.FvTargetList\r
+            "fv"                        : PlatformInfo.FvTargetList,\r
+            "log_level"                 : LogOption,\r
         }\r
 \r
         self.PrepareDirectory()\r
index ccce1bc..7e92f73 100755 (executable)
@@ -553,7 +553,7 @@ class WorkspaceBuild(object):
                     EdkLogger.debug(EdkLogger.DEBUG_3, "%s for module type %s is not supported (%s)" % (Key + (LibraryPath,)))\r
                     continue\r
                 if LibraryPath == None or LibraryPath == "":\r
-                    EdkLogger.warn(None, "\tWARNING: Library instance for library class %s is not found" % LibraryClassName)\r
+                    EdkLogger.warn(None, "Library instance for library class %s is not found" % LibraryClassName)\r
                     continue\r
 \r
                 LibraryModule = ModuleDatabase[LibraryPath]\r
index 4f734e7..c5501aa 100644 (file)
@@ -172,6 +172,9 @@ def SetLevel(Level):
     _ErrorLogger.setLevel(Level)
     #_QuietLogger.setLevel(Level)
 
+def GetLevel():
+    return _InfoLogger.getEffectiveLevel()
+
 def SetWarningAsError():
     global _WarningAsError
     _WarningAsError = True
index 6c3f3ef..1d8fa91 100755 (executable)
@@ -64,7 +64,7 @@ class ToolDefClassObject(object):
             Value = NameValuePair[1].strip()\r
 \r
             if Name == "IDENTIFIER":\r
-                EdkLogger.verbose("Line %d: Found identifier statement, skipped: %s" % ((Index + 1), Value))\r
+                EdkLogger.debug(EdkLogger.DEBUG_9, "Line %d: Found identifier statement, skipped: %s" % ((Index + 1), Value))\r
                 continue\r
 \r
             MacroDefinition = gMacroDefPattern.findall(Name)\r
@@ -79,7 +79,7 @@ class ToolDefClassObject(object):
 \r
                 MacroName = MacroDefinition[0].strip()\r
                 self.MacroDictionary["DEF(%s)" % MacroName] = Value\r
-                EdkLogger.verbose("Line %d: Found macro: %s = %s" % ((Index + 1), MacroName, Value))\r
+                EdkLogger.debug(EdkLogger.DEBUG_9, "Line %d: Found macro: %s = %s" % ((Index + 1), MacroName, Value))\r
                 continue\r
 \r
             MacroReference = gMacroRefPattern.findall(Value)\r
index c284781..03814b7 100644 (file)
@@ -133,34 +133,38 @@ def ReadMessage(From, To, ExitFlag):
 # redirecting output of the external program, threads are used to to do the\r
 # redirection work.\r
 #\r
-# @param  CommandStringList     A list contains the calling of the program\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(CommandStringList, WorkingDir):\r
+def LaunchCommand(Command, WorkingDir):\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
-    # launch the command\r
-    Proc = Popen(CommandStringList, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir)\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.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
+    try:\r
+        # launch the command\r
+        Proc = Popen(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir)\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.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
+    except:\r
+        # prevent this method calling from aborting\r
+        pass\r
 \r
     # terminate the threads redirecting the program output\r
     EndOfProcedure.set()\r
@@ -171,7 +175,9 @@ def LaunchCommand(CommandStringList, WorkingDir):
 \r
     # check the return code of the program\r
     if Proc.returncode != 0:\r
-        EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (" ".join(CommandStringList), WorkingDir))\r
+        if type(Command) != type(""):\r
+            Command = " ".join(Command)\r
+        EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir))\r
 \r
 ## The smallest unit that can be built in multi-thread build mode\r
 #\r
@@ -190,11 +196,12 @@ class BuildUnit:
     #   @param  Dependency  The BuildUnit(s) which must be completed in advance\r
     #   @param  WorkingDir  The directory build command starts in\r
     #\r
-    def __init__(self, Obj, Target, Dependency, WorkingDir="."):\r
+    def __init__(self, Obj, BuildComamnd, Target, Dependency, WorkingDir="."):\r
         self.BuildObject = Obj\r
         self.Dependency = Dependency\r
         self.WorkingDir = WorkingDir\r
         self.Target = Target\r
+        self.BuildCommand = BuildComamnd\r
 \r
     ## str() method\r
     #\r
@@ -242,7 +249,7 @@ class ModuleMakeUnit(BuildUnit):
     #\r
     def __init__(self, Obj, Target):\r
         Dependency = [ModuleMakeUnit(La, Target) for La in Obj.BuildInfo.LibraryAutoGenList]\r
-        BuildUnit.__init__(self, Obj, Target, Dependency, Obj.GetMakeFileDir())\r
+        BuildUnit.__init__(self, Obj, Obj.GetBuildCommand(), Target, Dependency, Obj.GetMakeFileDir())\r
         if Target in [None, "", "all"]:\r
             self.Target = "pbuild"\r
 \r
@@ -264,7 +271,7 @@ class PlatformMakeUnit(BuildUnit):
     def __init__(self, Obj, Target):\r
         Dependency = [ModuleMakeUnit(Lib, Target) for Lib in self.BuildObject.BuildInfo.LibraryAutoGenList]\r
         Dependency.extend([ModuleMakeUnit(Mod, Target) for Mod in self.BuildObject.BuildInfo.ModuleAutoGenList])\r
-        BuildUnit.__init__(self, Obj, Target, Dependency, Obj.GetMakeFileDir())\r
+        BuildUnit.__init__(self, Obj, Obj.GetBuildCommand(), Target, Dependency, Obj.GetMakeFileDir())\r
 \r
 ## The class representing the task of a module build or platform build\r
 #\r
@@ -373,7 +380,7 @@ class BuildTask:
                 time.sleep(0.1)\r
             BuildTask._CompleteFlag.set()\r
             BuildTask._SchedulerStarted = False\r
-        except Exception, e:\r
+        except BaseException, X:\r
             #\r
             # TRICK: hide the output of threads left runing, so that the user can\r
             #        catch the error message easily\r
@@ -396,6 +403,12 @@ class BuildTask:
     def IsOnGoing():\r
         return BuildTask._SchedulerStarted\r
 \r
+    ## Abort the build\r
+    @staticmethod\r
+    def Abort():\r
+        BuildTask._ErrorFlag.set()\r
+        BuildTask._CompleteFlag.wait()\r
+\r
     ## Check if there's error in running thread\r
     #\r
     #   Since the main thread cannot catch exceptions in other thread, we have to\r
@@ -479,14 +492,14 @@ class BuildTask:
 \r
     ## The thread wrapper of LaunchCommand function\r
     #\r
-    # @param  CommandStringList     A list contains the calling of the program\r
+    # @param  Command               A list or string contains the call of the command\r
     # @param  WorkingDir            The directory in which the program will be running\r
     #\r
-    def _CommandThread(self, CommandStringList, WorkingDir):\r
+    def _CommandThread(self, Command, WorkingDir):\r
         try:\r
-            LaunchCommand(CommandStringList, WorkingDir)\r
+            LaunchCommand(Command, WorkingDir)\r
             self.CompleteFlag = True\r
-        except Exception, e:\r
+        except Exception, X:\r
             #\r
             # TRICK: hide the output of threads left runing, so that the user can\r
             #        catch the error message easily\r
@@ -494,20 +507,15 @@ class BuildTask:
             EdkLogger.SetLevel(EdkLogger.QUIET)\r
             BuildTask._ErrorFlag.set()\r
             BuildTask._ErrorMessage = "%s broken\n    %s [%s]" % \\r
-                                      (threading.currentThread().getName(),\r
-                                       " ".join(CommandStringList), WorkingDir)\r
+                                      (threading.currentThread().getName(), Command, WorkingDir)\r
         # indicate there's a thread is available for another build task\r
         BuildTask._Thread.release()\r
 \r
     ## Start build task thread\r
     #\r
     def Start(self):\r
-        if sys.platform in ["win32", "win64"]:\r
-            CommandList = ["nmake", "/nologo", self.BuildItem.Target]\r
-        else:\r
-            CommandList = ["make", self.BuildItem.Target]\r
-\r
-        self.BuildTread = Thread(target=self._CommandThread, args=(CommandList, self.BuildItem.WorkingDir))\r
+        Command = self.BuildItem.BuildCommand + " " + self.BuildItem.Target\r
+        self.BuildTread = Thread(target=self._CommandThread, args=(Command, self.BuildItem.WorkingDir))\r
         self.BuildTread.setName("Command-Thread")\r
         self.BuildTread.setDaemon(False)\r
         self.BuildTread.start()\r
@@ -532,8 +540,8 @@ class Build():
     #   @param  WorkspaceDir        The directory of workspace\r
     #   @param  Platform            The DSC file of active platform\r
     #   @param  Module              The INF file of active module, if any\r
-    #   @param  Arch                The Arch of platform or module\r
-    #   @param  ToolChain           The name of toolchain\r
+    #   @param  Arch                The Arch list of platform or module\r
+    #   @param  ToolChain           The name list of toolchain\r
     #   @param  BuildTarget         The "DEBUG" or "RELEASE" build\r
     #   @param  FlashDefinition     The FDF file of active platform\r
     #   @param  FdList=[]           The FD names to be individually built\r
@@ -571,9 +579,9 @@ class Build():
         try:\r
             self.LoadConfiguration()\r
             self.InitBuild()\r
-        except Exception, E:\r
-            self.Progress.Stop()\r
-            raise E\r
+        except BaseException, X:\r
+            self.Progress.Stop("")\r
+            raise\r
         self.Progress.Stop("done!")\r
 \r
         # print current build environment and configuration\r
@@ -614,11 +622,11 @@ class Build():
             self.Ewb.GenBuildDatabase(PcdSet)\r
             self.Platform = self.Ewb.Build[self.ArchList[0]].PlatformDatabase[self.PlatformFile]\r
 \r
-        except Exception, X:\r
-            self.Progress.Stop()\r
+        except BaseException, X:\r
+            self.Progress.Stop("")\r
             if isinstance(X, Warning):\r
                 EdkLogger.error(X.ToolName, BUILD_ERROR, X.message, X.FileName, X.LineNumber, RaiseError = False)\r
-            raise X\r
+            raise\r
         self.Progress.Stop("done!")\r
 \r
     ## Load configuration\r
@@ -643,21 +651,37 @@ class Build():
             EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)\r
 \r
         # if no ARCH given in command line, get it from target.txt\r
-        if self.ArchList == None or self.ArchList == []:\r
+        if self.ArchList == None or len(self.ArchList) == 0:\r
             self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH]\r
-            if self.ArchList == []:\r
+            if len(self.ArchList) == 0:\r
                 self.ArchList = ARCH_LIST\r
 \r
-        if self.BuildTargetList == None or self.BuildTargetList == []:\r
+        # if no build target given in command line, get it from target.txt\r
+        if self.BuildTargetList == None or len(self.BuildTargetList) == 0:\r
             self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]\r
-            if self.BuildTargetList == None or self.BuildTargetList == []:\r
+            if self.BuildTargetList == None or len(self.BuildTargetList) == 0:\r
                 self.BuildTargetList = ['DEBUG', 'RELEASE']\r
 \r
-        if self.ToolChainList == None or self.ToolChainList == []:\r
+        # if no tool chain given in command line, get it from target.txt\r
+        if self.ToolChainList == None or len(self.ToolChainList) == 0:\r
             self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]\r
-            if self.ToolChainList == None or self.ToolChainList == []:\r
+            if self.ToolChainList == 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
+        # check if the tool chains are defined or not\r
+        NewToolChainList = []\r
+        for ToolChain in self.ToolChainList:\r
+            if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:\r
+                EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)\r
+            else:\r
+                NewToolChainList.append(ToolChain)\r
+        # if no tool chain available, break the build\r
+        if len(NewToolChainList) == 0:\r
+            EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
+                            ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))\r
+        else:\r
+            self.ToolChainList = NewToolChainList\r
+\r
         if self.ThreadNumber == None or self.ThreadNumber == "":\r
             self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]\r
             if self.ThreadNumber == '':\r
@@ -744,19 +768,6 @@ class Build():
 \r
         self.Ewb = Wb\r
 \r
-    ## System independent command launcher\r
-    #\r
-    #   @param  Target      Target of build command, one of gSupportedTarget\r
-    #   @param  WorkingDir  The directory the command starts from\r
-    #\r
-    def LaunchBuildCommand(self, Target, WorkingDir):\r
-        if sys.platform in ["win32", "win64"]:\r
-            # in Windows, use "nmake" from Visual Studio\r
-            LaunchCommand(["nmake", "/nologo", Target], WorkingDir)\r
-        else:\r
-            # in Linux or Mac, use GNU "make"\r
-            LaunchCommand(["make", Target], WorkingDir)\r
-\r
     ## Build a module or platform\r
     #\r
     # Create autogen code and makfile for a module or platform, and the launch\r
@@ -819,7 +830,12 @@ class Build():
                                                     ToolChain, Arch, False)\r
 \r
         EdkLogger.info("")\r
-        self.LaunchBuildCommand(Target, os.path.join(self.WorkspaceDir, AutoGenResult.GetMakeFileDir()))\r
+        BuildCommand = AutoGenResult.GetBuildCommand()\r
+        if BuildCommand == None or BuildCommand == "":\r
+            EdkLogger.error("build", OPTION_MISSING, ExtraData="No MAKE command found for [%s, %s, %s]" % Key)\r
+\r
+        BuildCommand = "%s %s" % (BuildCommand, Target)\r
+        LaunchCommand(BuildCommand, os.path.join(self.WorkspaceDir, AutoGenResult.GetMakeFileDir()))\r
 \r
     ## Build active platform for different build targets and different tool chains\r
     #\r
@@ -901,7 +917,7 @@ class Build():
 \r
                 # Generate FD image if there's a FDF file found\r
                 if self.Fdf != '' and self.Target in ["", "all", "fds"]:\r
-                    self.LaunchBuildCommand("fds", Pa.GetMakeFileDir())\r
+                    self.LaunchBuildCommand(Pa.GetBuildCommand() + " fds", Pa.GetMakeFileDir())\r
 \r
     ## Launch the module or platform build\r
     #\r
@@ -915,9 +931,14 @@ class Build():
                     self._MultiThreadBuildPlatform()\r
             else:\r
                 self._BuildModule()\r
-        except Exception, E:\r
-            self.Progress.Stop()\r
-            raise E\r
+        except BaseException, X:\r
+            self.Progress.Stop("")\r
+            raise\r
+\r
+    ## Do some clean-up works when error occurred\r
+    def Relinquish(self):\r
+        if self.SpawnMode == True:\r
+            BuildTask.Abort()\r
 \r
 ## Parse command line options\r
 #\r
@@ -955,7 +976,9 @@ def MyOptionParser():
     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="Putlog in specified file as well as on console.")\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
+    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
 \r
     (Opt, Args)=Parser.parse_args()\r
@@ -1002,6 +1025,7 @@ def Main():
 \r
     EdkLogger.quiet(time.strftime("%H:%M:%S, %b.%d %Y ", time.localtime()) + "[00:00]" + "\n")\r
     ReturnCode = 0\r
+    MyBuild = None\r
     try:\r
         #\r
         # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH\r
@@ -1030,12 +1054,16 @@ def Main():
                         Option.ToolChain, Option.BuildTarget, Option.FdfFile, Option.RomImage, Option.FvImage,\r
                         Option.MakefileType, Option.SpawnMode, Option.ThreadNumber)\r
         MyBuild.Launch()\r
-    except Exception, e:\r
+    except BaseException, X:\r
+        if MyBuild != None:\r
+            # for multi-thread build exits safely\r
+            MyBuild.Relinquish()\r
+\r
         EdkLogger.quiet("")\r
         if Option != None and Option.debug != None:\r
             EdkLogger.quiet(traceback.format_exc())\r
         else:\r
-            EdkLogger.quiet(e)\r
+            EdkLogger.quiet(str(X))\r
         ReturnCode = 1\r
 \r
     FinishTime = time.clock()\r