]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/Python/build/build.py
Sync EDKII BaseTools to BaseTools project r1903.
[mirror_edk2.git] / BaseTools / Source / Python / build / build.py
index 624d941b0ff1fd158379078faad24a6c7da42433..9705097606b8ae4836ce255d9e85735335d433a2 100644 (file)
-## @file
-# build a platform or a module
-#
-#  Copyright (c) 2007, Intel Corporation
-#
-#  All rights reserved. This program and the accompanying materials
-#  are licensed and made available under the terms and conditions of the BSD License
-#  which accompanies this distribution.  The full text of the license may be found at
-#  http://opensource.org/licenses/bsd-license.php
-#
-#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-#
-
-##
-# Import Modules
-#
-import os
-import re
-import sys
-import glob
-import time
-import platform
-import traceback
-
-from threading import *
-from optparse import OptionParser
-from subprocess import *
-from Common import Misc as Utils
-
-from Common.TargetTxtClassObject import *
-from Common.ToolDefClassObject import *
-from Common.DataType import *
-from AutoGen.AutoGen import *
-from Common.BuildToolError import *
-from Workspace.WorkspaceDatabase import *
-
-import Common.EdkLogger
-import Common.GlobalData as GlobalData
-
-# Version and Copyright
-VersionNumber = "0.5"
-__version__ = "%prog Version " + VersionNumber
-__copyright__ = "Copyright (c) 2007, Intel Corporation  All rights reserved."
-
-## standard targets of build command
-gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
-
-## build configuration file
-gBuildConfiguration = "Conf/target.txt"
-gBuildCacheDir = "Conf/.cache"
-gToolsDefinition = "Conf/tools_def.txt"
-
-## Check environment PATH variable to make sure the specified tool is found
-#
-#   If the tool is found in the PATH, then True is returned
-#   Otherwise, False is returned
-#
-def IsToolInPath(tool):
-    if os.environ.has_key('PATHEXT'):
-        extns = os.environ['PATHEXT'].split(os.path.pathsep)
-    else:
-        extns = ('',)
-    for pathDir in os.environ['PATH'].split(os.path.pathsep):
-        for ext in extns:
-            if os.path.exists(os.path.join(pathDir, tool + ext)):
-                return True
-    return False
-
-## Check environment variables
-#
-#  Check environment variables that must be set for build. Currently they are
-#
-#   WORKSPACE           The directory all packages/platforms start from
-#   EDK_TOOLS_PATH      The directory contains all tools needed by the build
-#   PATH                $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
-#
-#   If any of above environment variable is not set or has error, the build
-#   will be broken.
-#
-def CheckEnvVariable():
-    # check WORKSPACE
-    if "WORKSPACE" not in os.environ:
-        EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
-                        ExtraData="WORKSPACE")
-
-    WorkspaceDir = os.path.normcase(os.path.normpath(os.environ["WORKSPACE"]))
-    if not os.path.exists(WorkspaceDir):
-        EdkLogger.error("build", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData="%s" % WorkspaceDir)
-    elif ' ' in WorkspaceDir:
-        EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path",
-                        ExtraData=WorkspaceDir)
-    os.environ["WORKSPACE"] = WorkspaceDir
-
-    #
-    # Check EFI_SOURCE (R8 build convention). EDK_SOURCE will always point to ECP
-    #
-    os.environ["ECP_SOURCE"] = os.path.join(WorkspaceDir, GlobalData.gEdkCompatibilityPkg)
-    if "EFI_SOURCE" not in os.environ:
-        os.environ["EFI_SOURCE"] = os.environ["ECP_SOURCE"]
-    if "EDK_SOURCE" not in os.environ:
-        os.environ["EDK_SOURCE"] = os.environ["ECP_SOURCE"]
-
-    #
-    # Unify case of characters on case-insensitive systems
-    #
-    EfiSourceDir = os.path.normcase(os.path.normpath(os.environ["EFI_SOURCE"]))
-    EdkSourceDir = os.path.normcase(os.path.normpath(os.environ["EDK_SOURCE"]))
-    EcpSourceDir = os.path.normcase(os.path.normpath(os.environ["ECP_SOURCE"]))
-    os.environ["EFI_SOURCE"] = EfiSourceDir
-    os.environ["EDK_SOURCE"] = EdkSourceDir
-    os.environ["ECP_SOURCE"] = EcpSourceDir
-    os.environ["EDK_TOOLS_PATH"] = os.path.normcase(os.environ["EDK_TOOLS_PATH"])
-    
-    if not os.path.exists(EcpSourceDir):
-        EdkLogger.verbose("ECP_SOURCE = %s doesn't exist. R8 modules could not be built." % EcpSourceDir)
-    elif ' ' in EcpSourceDir:
-        EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in ECP_SOURCE path",
-                        ExtraData=EcpSourceDir)
-    if not os.path.exists(EdkSourceDir):
-        if EdkSourceDir == EcpSourceDir:
-            EdkLogger.verbose("EDK_SOURCE = %s doesn't exist. R8 modules could not be built." % EdkSourceDir)
-        else:
-            EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE does not exist",
-                            ExtraData=EdkSourceDir)
-    elif ' ' in EdkSourceDir:
-        EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EDK_SOURCE path",
-                        ExtraData=EdkSourceDir)
-    if not os.path.exists(EfiSourceDir):
-        if EfiSourceDir == EcpSourceDir:
-            EdkLogger.verbose("EFI_SOURCE = %s doesn't exist. R8 modules could not be built." % EfiSourceDir)
-        else:
-            EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE does not exist",
-                            ExtraData=EfiSourceDir)
-    elif ' ' in EfiSourceDir:
-        EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EFI_SOURCE path",
-                        ExtraData=EfiSourceDir)
-
-    # change absolute path to relative path to WORKSPACE
-    if EfiSourceDir.upper().find(WorkspaceDir.upper()) != 0:
-        EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE is not under WORKSPACE",
-                        ExtraData="WORKSPACE = %s\n    EFI_SOURCE = %s" % (WorkspaceDir, EfiSourceDir))
-    if EdkSourceDir.upper().find(WorkspaceDir.upper()) != 0:
-        EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE is not under WORKSPACE",
-                        ExtraData="WORKSPACE = %s\n    EDK_SOURCE = %s" % (WorkspaceDir, EdkSourceDir))
-    if EcpSourceDir.upper().find(WorkspaceDir.upper()) != 0:
-        EdkLogger.error("build", PARAMETER_INVALID, "ECP_SOURCE is not under WORKSPACE",
-                        ExtraData="WORKSPACE = %s\n    ECP_SOURCE = %s" % (WorkspaceDir, EcpSourceDir))
-
-    # check EDK_TOOLS_PATH
-    if "EDK_TOOLS_PATH" not in os.environ:
-        EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
-                        ExtraData="EDK_TOOLS_PATH")
-
-    # check PATH
-    if "PATH" not in os.environ:
-        EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
-                        ExtraData="PATH")
-
-    GlobalData.gWorkspace = WorkspaceDir
-    GlobalData.gEfiSource = EfiSourceDir
-    GlobalData.gEdkSource = EdkSourceDir
-    GlobalData.gEcpSource = EcpSourceDir
-
-## Get normalized file path
-#
-# Convert the path to be local format, and remove the WORKSPACE path at the
-# beginning if the file path is given in full path.
-#
-# @param  FilePath      File path to be normalized
-# @param  Workspace     Workspace path which the FilePath will be checked against
-#
-# @retval string        The normalized file path
-#
-def NormFile(FilePath, Workspace):
-    # check if the path is absolute or relative
-    if os.path.isabs(FilePath):
-        FileFullPath = os.path.normpath(FilePath)
-    else:
-        FileFullPath = os.path.normpath(os.path.join(Workspace, FilePath))
-
-    # check if the file path exists or not
-    if not os.path.isfile(FileFullPath):
-        EdkLogger.error("build", FILE_NOT_FOUND, ExtraData="\t%s (Please give file in absolute path or relative to WORKSPACE)"  % FileFullPath)
-
-    # remove workspace directory from the beginning part of the file path
-    if Workspace[-1] in ["\\", "/"]:
-        return FileFullPath[len(Workspace):]
-    else:
-        return FileFullPath[(len(Workspace) + 1):]
-
-## Get the output of an external program
-#
-# This is the entrance method of thread reading output of an external program and
-# putting them in STDOUT/STDERR of current program.
-#
-# @param  From      The stream message read from
-# @param  To        The stream message put on
-# @param  ExitFlag  The flag used to indicate stopping reading
-#
-def ReadMessage(From, To, ExitFlag):
-    while True:
-        # read one line a time
-        Line = From.readline()
-        # empty string means "end"
-        if Line != None and Line != "":
-            To(Line.rstrip())
-        else:
-            break
-        if ExitFlag.isSet():
-            break
-
-## Launch an external program
-#
-# This method will call subprocess.Popen to execute an external program with
-# given options in specified directory. Because of the dead-lock issue during
-# redirecting output of the external program, threads are used to to do the
-# redirection work.
-#
-# @param  Command               A list or string containing the call of the program
-# @param  WorkingDir            The directory in which the program will be running
-#
-def LaunchCommand(Command, WorkingDir):
-    # if working directory doesn't exist, Popen() will raise an exception
-    if not os.path.isdir(WorkingDir):
-        EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=WorkingDir)
-
-    Proc = None
-    EndOfProcedure = None
-    try:
-        # launch the command
-        Proc = Popen(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir, bufsize=-1)
-
-        # launch two threads to read the STDOUT and STDERR
-        EndOfProcedure = Event()
-        EndOfProcedure.clear()
-        if Proc.stdout:
-            StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure))
-            StdOutThread.setName("STDOUT-Redirector")
-            StdOutThread.setDaemon(False)
-            StdOutThread.start()
-
-        if Proc.stderr:
-            StdErrThread = Thread(target=ReadMessage, args=(Proc.stderr, EdkLogger.quiet, EndOfProcedure))
-            StdErrThread.setName("STDERR-Redirector")
-            StdErrThread.setDaemon(False)
-            StdErrThread.start()
-
-        # waiting for program exit
-        Proc.wait()
-    except: # in case of aborting
-        # terminate the threads redirecting the program output
-        if EndOfProcedure != None:
-            EndOfProcedure.set()
-        if Proc == None:
-            if type(Command) != type(""):
-                Command = " ".join(Command)
-            EdkLogger.error("build", COMMAND_FAILURE, "Failed to start command", ExtraData="%s [%s]" % (Command, WorkingDir))
-
-    if Proc.stdout:
-        StdOutThread.join()
-    if Proc.stderr:
-        StdErrThread.join()
-
-    # check the return code of the program
-    if Proc.returncode != 0:
-        if type(Command) != type(""):
-            Command = " ".join(Command)
-        EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir))
-
-## The smallest unit that can be built in multi-thread build mode
-#
-# This is the base class of build unit. The "Obj" parameter must provide
-# __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
-# missing build.
-#
-# Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
-#
-class BuildUnit:
-    ## The constructor
-    #
-    #   @param  self        The object pointer
-    #   @param  Obj         The object the build is working on
-    #   @param  Target      The build target name, one of gSupportedTarget
-    #   @param  Dependency  The BuildUnit(s) which must be completed in advance
-    #   @param  WorkingDir  The directory build command starts in
-    #
-    def __init__(self, Obj, BuildCommand, Target, Dependency, WorkingDir="."):
-        self.BuildObject = Obj
-        self.Dependency = Dependency
-        self.WorkingDir = WorkingDir
-        self.Target = Target
-        self.BuildCommand = BuildCommand
-        if BuildCommand == None or len(BuildCommand) == 0:
-            EdkLogger.error("build", OPTION_MISSING, "No build command found for",
-                            ExtraData=str(Obj))
-
-    ## str() method
-    #
-    #   It just returns the string representaion of self.BuildObject
-    #
-    #   @param  self        The object pointer
-    #
-    def __str__(self):
-        return str(self.BuildObject)
-
-    ## "==" operator method
-    #
-    #   It just compares self.BuildObject with "Other". So self.BuildObject must
-    #   provide its own __eq__() method.
-    #
-    #   @param  self        The object pointer
-    #   @param  Other       The other BuildUnit object compared to
-    #
-    def __eq__(self, Other):
-        return Other != None and self.BuildObject == Other.BuildObject \
-                and self.BuildObject.Arch == Other.BuildObject.Arch
-
-    ## hash() method
-    #
-    #   It just returns the hash value of self.BuildObject which must be hashable.
-    #
-    #   @param  self        The object pointer
-    #
-    def __hash__(self):
-        return hash(self.BuildObject) + hash(self.BuildObject.Arch)
-
-    def __repr__(self):
-        return repr(self.BuildObject)
-
-## The smallest module unit that can be built by nmake/make command in multi-thread build mode
-#
-# This class is for module build by nmake/make build system. The "Obj" parameter
-# must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
-# be make units missing build.
-#
-# Currently the "Obj" should be only ModuleAutoGen object.
-#
-class ModuleMakeUnit(BuildUnit):
-    ## The constructor
-    #
-    #   @param  self        The object pointer
-    #   @param  Obj         The ModuleAutoGen object the build is working on
-    #   @param  Target      The build target name, one of gSupportedTarget
-    #
-    def __init__(self, Obj, Target):
-        Dependency = [ModuleMakeUnit(La, Target) for La in Obj.LibraryAutoGenList]
-        BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)
-        if Target in [None, "", "all"]:
-            self.Target = "tbuild"
-
-## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
-#
-# This class is for platform build by nmake/make build system. The "Obj" parameter
-# must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
-# be make units missing build.
-#
-# Currently the "Obj" should be only PlatformAutoGen object.
-#
-class PlatformMakeUnit(BuildUnit):
-    ## The constructor
-    #
-    #   @param  self        The object pointer
-    #   @param  Obj         The PlatformAutoGen object the build is working on
-    #   @param  Target      The build target name, one of gSupportedTarget
-    #
-    def __init__(self, Obj, Target):
-        Dependency = [ModuleMakeUnit(Lib, Target) for Lib in self.BuildObject.LibraryAutoGenList]
-        Dependency.extend([ModuleMakeUnit(Mod, Target) for Mod in self.BuildObject.ModuleAutoGenList])
-        BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)
-
-## The class representing the task of a module build or platform build
-#
-# This class manages the build tasks in multi-thread build mode. Its jobs include
-# scheduling thread running, catching thread error, monitor the thread status, etc.
-#
-class BuildTask:
-    # queue for tasks waiting for schedule
-    _PendingQueue = sdict()
-    _PendingQueueLock = threading.Lock()
-
-    # queue for tasks ready for running
-    _ReadyQueue = sdict()
-    _ReadyQueueLock = threading.Lock()
-
-    # queue for run tasks
-    _RunningQueue = sdict()
-    _RunningQueueLock = threading.Lock()
-
-    # queue containing all build tasks, in case duplicate build
-    _TaskQueue = sdict()
-
-    # flag indicating error occurs in a running thread
-    _ErrorFlag = threading.Event()
-    _ErrorFlag.clear()
-    _ErrorMessage = ""
-
-    # BoundedSemaphore object used to control the number of running threads
-    _Thread = None
-
-    # flag indicating if the scheduler is started or not
-    _SchedulerStopped = threading.Event()
-    _SchedulerStopped.set()
-
-    ## Start the task scheduler thread
-    #
-    #   @param  MaxThreadNumber     The maximum thread number
-    #   @param  ExitFlag            Flag used to end the scheduler
-    #
-    @staticmethod
-    def StartScheduler(MaxThreadNumber, ExitFlag):
-        SchedulerThread = Thread(target=BuildTask.Scheduler, args=(MaxThreadNumber, ExitFlag))
-        SchedulerThread.setName("Build-Task-Scheduler")
-        SchedulerThread.setDaemon(False)
-        SchedulerThread.start()
-        # wait for the scheduler to be started, especially useful in Linux
-        while not BuildTask.IsOnGoing():
-            time.sleep(0.01)
-
-    ## Scheduler method
-    #
-    #   @param  MaxThreadNumber     The maximum thread number
-    #   @param  ExitFlag            Flag used to end the scheduler
-    #
-    @staticmethod
-    def Scheduler(MaxThreadNumber, ExitFlag):
-        BuildTask._SchedulerStopped.clear()
-        try:
-            # use BoundedSemaphore to control the maximum running threads
-            BuildTask._Thread = BoundedSemaphore(MaxThreadNumber)
-            #
-            # scheduling loop, which will exits when no pending/ready task and
-            # indicated to do so, or there's error in running thread
-            #
-            while (len(BuildTask._PendingQueue) > 0 or len(BuildTask._ReadyQueue) > 0 \
-                   or not ExitFlag.isSet()) and not BuildTask._ErrorFlag.isSet():
-                EdkLogger.debug(EdkLogger.DEBUG_8, "Pending Queue (%d), Ready Queue (%d)"
-                                % (len(BuildTask._PendingQueue), len(BuildTask._ReadyQueue)))
-
-                # get all pending tasks
-                BuildTask._PendingQueueLock.acquire()
-                BuildObjectList = BuildTask._PendingQueue.keys()
-                #
-                # check if their dependency is resolved, and if true, move them
-                # into ready queue
-                #
-                for BuildObject in BuildObjectList:
-                    Bt = BuildTask._PendingQueue[BuildObject]
-                    if Bt.IsReady():
-                        BuildTask._ReadyQueue[BuildObject] = BuildTask._PendingQueue.pop(BuildObject)
-                BuildTask._PendingQueueLock.release()
-
-                # launch build thread until the maximum number of threads is reached
-                while not BuildTask._ErrorFlag.isSet():
-                    # empty ready queue, do nothing further
-                    if len(BuildTask._ReadyQueue) == 0:
-                        break
-
-                    # wait for active thread(s) exit
-                    BuildTask._Thread.acquire(True)
-
-                    # start a new build thread
-                    Bo = BuildTask._ReadyQueue.keys()[0]
-                    Bt = BuildTask._ReadyQueue.pop(Bo)
-
-                    # move into running queue
-                    BuildTask._RunningQueueLock.acquire()
-                    BuildTask._RunningQueue[Bo] = Bt
-                    BuildTask._RunningQueueLock.release()
-
-                    Bt.Start()
-                    # avoid tense loop
-                    time.sleep(0.01)
-
-                # avoid tense loop
-                time.sleep(0.01)
-
-            # wait for all running threads exit
-            if BuildTask._ErrorFlag.isSet():
-                EdkLogger.quiet("\nWaiting for all build threads exit...")
-            # while not BuildTask._ErrorFlag.isSet() and \
-            while len(BuildTask._RunningQueue) > 0:
-                EdkLogger.verbose("Waiting for thread ending...(%d)" % len(BuildTask._RunningQueue))
-                EdkLogger.debug(EdkLogger.DEBUG_8, "Threads [%s]" % ", ".join([Th.getName() for Th in threading.enumerate()]))
-                # avoid tense loop
-                time.sleep(0.1)
-        except BaseException, X:
-            #
-            # TRICK: hide the output of threads left runing, so that the user can
-            #        catch the error message easily
-            #
-            EdkLogger.SetLevel(EdkLogger.ERROR)
-            BuildTask._ErrorFlag.set()
-            BuildTask._ErrorMessage = "build thread scheduler error\n\t%s" % str(X)
-
-        BuildTask._PendingQueue.clear()
-        BuildTask._ReadyQueue.clear()
-        BuildTask._RunningQueue.clear()
-        BuildTask._TaskQueue.clear()
-        BuildTask._SchedulerStopped.set()
-
-    ## Wait for all running method exit
-    #
-    @staticmethod
-    def WaitForComplete():
-        BuildTask._SchedulerStopped.wait()
-
-    ## Check if the scheduler is running or not
-    #
-    @staticmethod
-    def IsOnGoing():
-        return not BuildTask._SchedulerStopped.isSet()
-
-    ## Abort the build
-    @staticmethod
-    def Abort():
-        if BuildTask.IsOnGoing():
-            BuildTask._ErrorFlag.set()
-            BuildTask.WaitForComplete()
-
-    ## Check if there's error in running thread
-    #
-    #   Since the main thread cannot catch exceptions in other thread, we have to
-    #   use threading.Event to communicate this formation to main thread.
-    #
-    @staticmethod
-    def HasError():
-        return BuildTask._ErrorFlag.isSet()
-
-    ## Get error message in running thread
-    #
-    #   Since the main thread cannot catch exceptions in other thread, we have to
-    #   use a static variable to communicate this message to main thread.
-    #
-    @staticmethod
-    def GetErrorMessage():
-        return BuildTask._ErrorMessage
-
-    ## Factory method to create a BuildTask object
-    #
-    #   This method will check if a module is building or has been built. And if
-    #   true, just return the associated BuildTask object in the _TaskQueue. If
-    #   not, create and return a new BuildTask object. The new BuildTask object
-    #   will be appended to the _PendingQueue for scheduling later.
-    #
-    #   @param  BuildItem       A BuildUnit object representing a build object
-    #   @param  Dependency      The dependent build object of BuildItem
-    #
-    @staticmethod
-    def New(BuildItem, Dependency=None):
-        if BuildItem in BuildTask._TaskQueue:
-            Bt = BuildTask._TaskQueue[BuildItem]
-            return Bt
-
-        Bt = BuildTask()
-        Bt._Init(BuildItem, Dependency)
-        BuildTask._TaskQueue[BuildItem] = Bt
-
-        BuildTask._PendingQueueLock.acquire()
-        BuildTask._PendingQueue[BuildItem] = Bt
-        BuildTask._PendingQueueLock.release()
-
-        return Bt
-
-    ## The real constructor of BuildTask
-    #
-    #   @param  BuildItem       A BuildUnit object representing a build object
-    #   @param  Dependency      The dependent build object of BuildItem
-    #
-    def _Init(self, BuildItem, Dependency=None):
-        self.BuildItem = BuildItem
-
-        self.DependencyList = []
-        if Dependency == None:
-            Dependency = BuildItem.Dependency
-        else:
-            Dependency.extend(BuildItem.Dependency)
-        self.AddDependency(Dependency)
-        # flag indicating build completes, used to avoid unnecessary re-build
-        self.CompleteFlag = False
-
-    ## Check if all dependent build tasks are completed or not
-    #
-    def IsReady(self):
-        ReadyFlag = True
-        for Dep in self.DependencyList:
-            if Dep.CompleteFlag == True:
-                continue
-            ReadyFlag = False
-            break
-
-        return ReadyFlag
-
-    ## Add dependent build task
-    #
-    #   @param  Dependency      The list of dependent build objects
-    #
-    def AddDependency(self, Dependency):
-        for Dep in Dependency:
-            self.DependencyList.append(BuildTask.New(Dep))    # BuildTask list
-
-    ## The thread wrapper of LaunchCommand function
-    #
-    # @param  Command               A list or string contains the call of the command
-    # @param  WorkingDir            The directory in which the program will be running
-    #
-    def _CommandThread(self, Command, WorkingDir):
-        try:
-            LaunchCommand(Command, WorkingDir)
-            self.CompleteFlag = True
-        except:
-            #
-            # TRICK: hide the output of threads left runing, so that the user can
-            #        catch the error message easily
-            #
-            if not BuildTask._ErrorFlag.isSet():
-                GlobalData.gBuildingModule = "%s [%s, %s, %s]" % (str(self.BuildItem.BuildObject),
-                                                                  self.BuildItem.BuildObject.Arch,
-                                                                  self.BuildItem.BuildObject.ToolChain,
-                                                                  self.BuildItem.BuildObject.BuildTarget
-                                                                 )
-            EdkLogger.SetLevel(EdkLogger.ERROR)
-            BuildTask._ErrorFlag.set()
-            BuildTask._ErrorMessage = "%s broken\n    %s [%s]" % \
-                                      (threading.currentThread().getName(), Command, WorkingDir)
-        # indicate there's a thread is available for another build task
-        BuildTask._RunningQueueLock.acquire()
-        BuildTask._RunningQueue.pop(self.BuildItem)
-        BuildTask._RunningQueueLock.release()
-        BuildTask._Thread.release()
-
-    ## Start build task thread
-    #
-    def Start(self):
-        EdkLogger.quiet("Building ... %s" % repr(self.BuildItem))
-        Command = self.BuildItem.BuildCommand + [self.BuildItem.Target]
-        self.BuildTread = Thread(target=self._CommandThread, args=(Command, self.BuildItem.WorkingDir))
-        self.BuildTread.setName("build thread")
-        self.BuildTread.setDaemon(False)
-        self.BuildTread.start()
-
-## The class implementing the EDK2 build process
-#
-#   The build process includes:
-#       1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
-#       2. Parse DSC file of active platform
-#       3. Parse FDF file if any
-#       4. Establish build database, including parse all other files (module, package)
-#       5. Create AutoGen files (C code file, depex file, makefile) if necessary
-#       6. Call build command
-#
-class Build():
-    ## Constructor
-    #
-    # Constructor will load all necessary configurations, parse platform, modules
-    # and packages and the establish a database for AutoGen.
-    #
-    #   @param  Target              The build command target, one of gSupportedTarget
-    #   @param  WorkspaceDir        The directory of workspace
-    #   @param  Platform            The DSC file of active platform
-    #   @param  Module              The INF file of active module, if any
-    #   @param  Arch                The Arch list of platform or module
-    #   @param  ToolChain           The name list of toolchain
-    #   @param  BuildTarget         The "DEBUG" or "RELEASE" build
-    #   @param  FlashDefinition     The FDF file of active platform
-    #   @param  FdList=[]           The FD names to be individually built
-    #   @param  FvList=[]           The FV names to be individually built
-    #   @param  MakefileType        The type of makefile (for MSFT make or GNU make)
-    #   @param  SilentMode          Indicate multi-thread build mode
-    #   @param  ThreadNumber        The maximum number of thread if in multi-thread build mode
-    #   @param  SkipAutoGen         Skip AutoGen step
-    #   @param  Reparse             Re-parse all meta files
-    #   @param  SkuId               SKU id from command line
-    #
-    def __init__(self, Target, WorkspaceDir, Platform, Module, Arch, ToolChain,
-                 BuildTarget, FlashDefinition, FdList=[], FvList=[],
-                 MakefileType="nmake", SilentMode=False, ThreadNumber=2,
-                 SkipAutoGen=False, Reparse=False, SkuId=None, 
-                 ReportFile=None, ReportType=None):
-
-        self.WorkspaceDir = WorkspaceDir
-        self.Target         = Target
-        self.PlatformFile   = Platform
-        self.ModuleFile     = Module
-        self.ArchList       = Arch
-        self.ToolChainList  = ToolChain
-        self.BuildTargetList= BuildTarget
-        self.Fdf            = FlashDefinition
-        self.FdList         = FdList
-        self.FvList         = FvList
-        self.MakefileType   = MakefileType
-        self.SilentMode     = SilentMode
-        self.ThreadNumber   = ThreadNumber
-        self.SkipAutoGen    = SkipAutoGen
-        self.Reparse        = Reparse
-        self.SkuId          = SkuId
-        self.SpawnMode      = True
-        self.ReportFile     = ReportFile
-        if ReportType == None:
-          self.ReportType   = ['ALL']
-        else:
-          self.ReportType   = ReportType
-
-        self.TargetTxt      = TargetTxtClassObject()
-        self.ToolDef        = ToolDefClassObject()
-        self.Db             = WorkspaceDatabase(None, GlobalData.gGlobalDefines, self.Reparse)
-        #self.Db             = WorkspaceDatabase(None, {}, self.Reparse)
-        self.BuildDatabase  = self.Db.BuildObject
-        self.Platform       = None
-
-        # print dot charater during doing some time-consuming work
-        self.Progress = Utils.Progressor()
-
-        # parse target.txt, tools_def.txt, and platform file
-        #self.RestoreBuildData()
-        self.LoadConfiguration()
-        self.InitBuild()
-
-        # print current build environment and configuration
-        EdkLogger.quiet("%-24s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))
-        EdkLogger.quiet("%-24s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"]))
-        EdkLogger.quiet("%-24s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"]))
-        EdkLogger.quiet("%-24s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"]))
-        EdkLogger.quiet("%-24s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))
-
-        EdkLogger.info('\n%-24s = %s' % ("TARGET_ARCH", ' '.join(self.ArchList)))
-        EdkLogger.info('%-24s = %s' % ("TARGET", ' '.join(self.BuildTargetList)))
-        EdkLogger.info('%-24s = %s' % ("TOOL_CHAIN_TAG", ' '.join(self.ToolChainList)))
-
-        EdkLogger.info('\n%-24s = %s' % ("Active Platform", self.PlatformFile))
-
-        if self.Fdf != None and self.Fdf != "":
-            EdkLogger.info('%-24s = %s' % ("Flash Image Definition", self.Fdf))
-
-        if self.ModuleFile != None and self.ModuleFile != "":
-            EdkLogger.info('%-24s = %s' % ("Active Module", self.ModuleFile))
-
-        os.chdir(self.WorkspaceDir)
-        self.Progress.Start("\nProcessing meta-data")
-
-    ## Load configuration
-    #
-    #   This method will parse target.txt and get the build configurations.
-    #
-    def LoadConfiguration(self):
-        #
-        # Check target.txt and tools_def.txt and Init them
-        #
-        BuildConfigurationFile = os.path.normpath(os.path.join(self.WorkspaceDir, gBuildConfiguration))
-        if os.path.isfile(BuildConfigurationFile) == True:
-            StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)
-
-            ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]
-            if ToolDefinitionFile == '':
-                ToolDefinitionFile = gToolsDefinition
-            ToolDefinitionFile = os.path.normpath(os.path.join(self.WorkspaceDir, ToolDefinitionFile))
-            if os.path.isfile(ToolDefinitionFile) == True:
-                StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)
-            else:
-                EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)
-        else:
-            EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)
-
-        # if no ARCH given in command line, get it from target.txt
-        if self.ArchList == None or len(self.ArchList) == 0:
-            self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH]
-
-        # if no build target given in command line, get it from target.txt
-        if self.BuildTargetList == None or len(self.BuildTargetList) == 0:
-            self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]
-
-        # if no tool chain given in command line, get it from target.txt
-        if self.ToolChainList == None or len(self.ToolChainList) == 0:
-            self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]
-            if self.ToolChainList == None or len(self.ToolChainList) == 0:
-                EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")
-
-        # check if the tool chains are defined or not
-        NewToolChainList = []
-        for ToolChain in self.ToolChainList:
-            if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:
-                EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)
-            else:
-                NewToolChainList.append(ToolChain)
-        # if no tool chain available, break the build
-        if len(NewToolChainList) == 0:
-            EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
-                            ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))
-        else:
-            self.ToolChainList = NewToolChainList
-
-        if self.ThreadNumber == None:
-            self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]
-            if self.ThreadNumber == '':
-                self.ThreadNumber = 0
-            else:
-                self.ThreadNumber = int(self.ThreadNumber, 0)
-
-        if self.ThreadNumber == 0:
-            self.ThreadNumber = 1
-
-        if not self.PlatformFile:
-            PlatformFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM]
-            if not PlatformFile:
-                # Try to find one in current directory
-                WorkingDirectory = os.getcwd()
-                FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))
-                FileNum = len(FileList)
-                if FileNum >= 2:
-                    EdkLogger.error("build", OPTION_MISSING,
-                                    ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))
-                elif FileNum == 1:
-                    PlatformFile = FileList[0]
-                else:
-                    EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
-                                    ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")
-
-            self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)
-            ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)
-            if ErrorCode != 0:
-                EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
-
-    ## Initialize build configuration
-    #
-    #   This method will parse DSC file and merge the configurations from
-    #   command line and target.txt, then get the final build configurations.
-    #
-    def InitBuild(self):
-        ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc")
-        if ErrorCode != 0:
-            EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
-
-        # create metafile database
-        self.Db.InitDatabase()
-
-        # we need information in platform description file to determine how to build
-        self.Platform = self.BuildDatabase[self.PlatformFile, 'COMMON']
-        if not self.Fdf:
-            self.Fdf = self.Platform.FlashDefinition
-
-        if self.SkuId == None or self.SkuId == '':
-            self.SkuId = self.Platform.SkuName
-
-        # check FD/FV build target
-        if self.Fdf == None or self.Fdf == "":
-            if self.FdList != []:
-                EdkLogger.info("No flash definition file found. FD [%s] will be ignored." % " ".join(self.FdList))
-                self.FdList = []
-            if self.FvList != []:
-                EdkLogger.info("No flash definition file found. FV [%s] will be ignored." % " ".join(self.FvList))
-                self.FvList = []
-        else:
-            FdfParserObj = FdfParser(str(self.Fdf))
-            FdfParserObj.ParseFile()
-            for fvname in self.FvList:
-                if fvname.upper() not in FdfParserObj.Profile.FvDict.keys():
-                    EdkLogger.error("build", OPTION_VALUE_INVALID,
-                                    "No such an FV in FDF file: %s" % fvname)
-
-        #
-        # Merge Arch
-        #
-        if self.ArchList == None or len(self.ArchList) == 0:
-            ArchList = set(self.Platform.SupArchList)
-        else:
-            ArchList = set(self.ArchList) & set(self.Platform.SupArchList)
-        if len(ArchList) == 0:
-            EdkLogger.error("build", PARAMETER_INVALID,
-                            ExtraData = "Active platform supports [%s] only, but [%s] is given."
-                                        % (" ".join(self.Platform.SupArchList), " ".join(self.ArchList)))
-        elif len(ArchList) != len(self.ArchList):
-            SkippedArchList = set(self.ArchList).symmetric_difference(set(self.Platform.SupArchList))
-            EdkLogger.verbose("\nArch [%s] is ignored because active platform supports [%s] but [%s] is specified !"
-                           % (" ".join(SkippedArchList), " ".join(self.Platform.SupArchList), " ".join(self.ArchList)))
-        self.ArchList = tuple(ArchList)
-
-        # Merge build target
-        if self.BuildTargetList == None or len(self.BuildTargetList) == 0:
-            BuildTargetList = self.Platform.BuildTargets
-        else:
-            BuildTargetList = list(set(self.BuildTargetList) & set(self.Platform.BuildTargets))
-        if BuildTargetList == []:
-            EdkLogger.error("build", PARAMETER_INVALID, "Active platform only supports [%s], but [%s] is given"
-                                % (" ".join(self.Platform.BuildTargets), " ".join(self.BuildTargetList)))
-        self.BuildTargetList = BuildTargetList
-
-    ## Build a module or platform
-    #
-    # Create autogen code and makfile for a module or platform, and the launch
-    # "make" command to build it
-    #
-    #   @param  Target                      The target of build command
-    #   @param  Platform                    The platform file
-    #   @param  Module                      The module file
-    #   @param  BuildTarget                 The name of build target, one of "DEBUG", "RELEASE"
-    #   @param  ToolChain                   The name of toolchain to build
-    #   @param  Arch                        The arch of the module/platform
-    #   @param  CreateDepModuleCodeFile     Flag used to indicate creating code
-    #                                       for dependent modules/Libraries
-    #   @param  CreateDepModuleMakeFile     Flag used to indicate creating makefile
-    #                                       for dependent modules/Libraries
-    #
-    def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True):
-        if AutoGenObject == None:
-            return False
-
-        # skip file generation for cleanxxx targets, run and fds target
-        if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
-            # for target which must generate AutoGen code and makefile
-            if not self.SkipAutoGen or Target == 'genc':
-                self.Progress.Start("Generating code")
-                AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
-                self.Progress.Stop("done!")
-            if Target == "genc":
-                return True
-
-            if not self.SkipAutoGen or Target == 'genmake':
-                self.Progress.Start("Generating makefile")
-                AutoGenObject.CreateMakeFile(CreateDepsMakeFile)
-                self.Progress.Stop("done!")
-            if Target == "genmake":
-                return True
-        else:
-            # always recreate top/platform makefile when clean, just in case of inconsistency
-            AutoGenObject.CreateCodeFile(False)
-            AutoGenObject.CreateMakeFile(False)
-
-        if EdkLogger.GetLevel() == EdkLogger.QUIET:
-            EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
-
-        BuildCommand = AutoGenObject.BuildCommand
-        if BuildCommand == None or len(BuildCommand) == 0:
-            EdkLogger.error("build", OPTION_MISSING, ExtraData="No MAKE command found for [%s, %s, %s]" % Key)
-
-        BuildCommand = BuildCommand + [Target]
-        LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
-        if Target == 'cleanall':
-            try:
-                #os.rmdir(AutoGenObject.BuildDir)
-                RemoveDirectory(AutoGenObject.BuildDir, True)
-            except WindowsError, X:
-                EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
-        return True
-
-    ## Build active platform for different build targets and different tool chains
-    #
-    def _BuildPlatform(self):
-        for BuildTarget in self.BuildTargetList:
-            for ToolChain in self.ToolChainList:
-                Wa = WorkspaceAutoGen(
-                        self.WorkspaceDir,
-                        self.Platform,
-                        BuildTarget,
-                        ToolChain,
-                        self.ArchList,
-                        self.BuildDatabase,
-                        self.TargetTxt,
-                        self.ToolDef,
-                        self.Fdf,
-                        self.FdList,
-                        self.FvList,
-                        self.SkuId,
-                        self.ReportFile,
-                        self.ReportType
-                        )
-                self.Progress.Stop("done!")
-                self._Build(self.Target, Wa)
-
-    ## Build active module for different build targets, different tool chains and different archs
-    #
-    def _BuildModule(self):
-        for BuildTarget in self.BuildTargetList:
-            for ToolChain in self.ToolChainList:
-                #
-                # module build needs platform build information, so get platform
-                # AutoGen first
-                #
-                Wa = WorkspaceAutoGen(
-                        self.WorkspaceDir,
-                        self.Platform,
-                        BuildTarget,
-                        ToolChain,
-                        self.ArchList,
-                        self.BuildDatabase,
-                        self.TargetTxt,
-                        self.ToolDef,
-                        self.Fdf,
-                        self.FdList,
-                        self.FvList,
-                        self.SkuId,
-                        self.ReportFile,
-                        self.ReportType
-                        )
-                Wa.CreateMakeFile(False)
-                self.Progress.Stop("done!")
-                MaList = []
-                for Arch in self.ArchList:
-                    Ma = ModuleAutoGen(Wa, self.ModuleFile, BuildTarget, ToolChain, Arch, self.PlatformFile)
-                    if Ma == None: continue
-                    MaList.append(Ma)
-                    self._Build(self.Target, Ma)
-                if MaList == []:
-                    EdkLogger.error(
-                                'build',
-                                BUILD_ERROR,
-                                "Module for [%s] is not a component of active platform."\
-                                " Please make sure that the ARCH and inf file path are"\
-                                " given in the same as in [%s]" %\
-                                    (', '.join(self.ArchList), self.Platform),
-                                ExtraData=self.ModuleFile
-                                )
-
-    ## Build a platform in multi-thread mode
-    #
-    def _MultiThreadBuildPlatform(self):
-        for BuildTarget in self.BuildTargetList:
-            for ToolChain in self.ToolChainList:
-                Wa = WorkspaceAutoGen(
-                        self.WorkspaceDir,
-                        self.Platform,
-                        BuildTarget,
-                        ToolChain,
-                        self.ArchList,
-                        self.BuildDatabase,
-                        self.TargetTxt,
-                        self.ToolDef,
-                        self.Fdf,
-                        self.FdList,
-                        self.FvList,
-                        self.SkuId,
-                        self.ReportFile,
-                        self.ReportType
-                        )
-                Wa.CreateMakeFile(False)
-
-                # multi-thread exit flag
-                ExitFlag = threading.Event()
-                ExitFlag.clear()
-                for Arch in self.ArchList:
-                    Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
-                    if Pa == None:
-                        continue
-                    for Module in Pa.Platform.Modules:
-                        # Get ModuleAutoGen object to generate C code file and makefile
-                        Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
-                        if Ma == None:
-                            continue
-                        # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
-                        if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
-                            # for target which must generate AutoGen code and makefile
-                            if not self.SkipAutoGen or self.Target == 'genc':
-                                Ma.CreateCodeFile(True)
-                            if self.Target == "genc":
-                                continue
-
-                            if not self.SkipAutoGen or self.Target == 'genmake':
-                                Ma.CreateMakeFile(True)
-                            if self.Target == "genmake":
-                                continue
-                        self.Progress.Stop("done!")
-                        # Generate build task for the module
-                        Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))
-                        # Break build if any build thread has error
-                        if BuildTask.HasError():
-                            # we need a full version of makefile for platform
-                            ExitFlag.set()
-                            BuildTask.WaitForComplete()
-                            Pa.CreateMakeFile(False)
-                            EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
-                        # Start task scheduler
-                        if not BuildTask.IsOnGoing():
-                            BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
-
-                    # in case there's an interruption. we need a full version of makefile for platform
-                    Pa.CreateMakeFile(False)
-                    if BuildTask.HasError():
-                        EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
-
-                #
-                # All modules have been put in build tasks queue. Tell task scheduler
-                # to exit if all tasks are completed
-                #
-                ExitFlag.set()
-                BuildTask.WaitForComplete()
-
-                #
-                # Check for build error, and raise exception if one
-                # has been signaled.
-                #
-                if BuildTask.HasError():
-                    EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
-
-                # Generate FD image if there's a FDF file found
-                if self.Fdf != '' and self.Target in ["", "all", "fds"]:
-                    LaunchCommand(Wa.BuildCommand + ["fds"], Wa.MakeFileDir)
-
-    ## Generate GuidedSectionTools.txt in the FV directories.
-    #
-    def CreateGuidedSectionToolsFile(self):
-        for Arch in self.ArchList:
-            for BuildTarget in self.BuildTargetList:
-                for ToolChain in self.ToolChainList:
-                    FvDir = os.path.join(
-                                self.WorkspaceDir,
-                                self.Platform.OutputDirectory,
-                                '_'.join((BuildTarget, ToolChain)),
-                                'FV'
-                                )
-                    if not os.path.exists(FvDir):
-                        continue
-                    # Build up the list of supported architectures for this build
-                    prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)
-
-                    # Look through the tool definitions for GUIDed tools
-                    guidAttribs = []
-                    for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():
-                        if attrib.upper().endswith('_GUID'):
-                            split = attrib.split('_')
-                            thisPrefix = '_'.join(split[0:3]) + '_'
-                            if thisPrefix == prefix:
-                                guid = self.ToolDef.ToolsDefTxtDictionary[attrib]
-                                guid = guid.lower()
-                                toolName = split[3]
-                                path = '_'.join(split[0:4]) + '_PATH'
-                                path = self.ToolDef.ToolsDefTxtDictionary[path]
-                                path = self.GetFullPathOfTool(path)
-                                guidAttribs.append((guid, toolName, path))
-
-                    # Write out GuidedSecTools.txt
-                    toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')
-                    toolsFile = open(toolsFile, 'wt')
-                    for guidedSectionTool in guidAttribs:
-                        print >> toolsFile, ' '.join(guidedSectionTool)
-                    toolsFile.close()
-
-    ## Returns the full path of the tool.
-    #
-    def GetFullPathOfTool (self, tool):
-        if os.path.exists(tool):
-            return os.path.realpath(tool)
-        else:
-            # We need to search for the tool using the
-            # PATH environment variable.
-            for dirInPath in os.environ['PATH'].split(os.pathsep):
-                foundPath = os.path.join(dirInPath, tool)
-                if os.path.exists(foundPath):
-                    return os.path.realpath(foundPath)
-
-        # If the tool was not found in the path then we just return
-        # the input tool.
-        return tool
-
-    ## Launch the module or platform build
-    #
-    def Launch(self):
-        if self.ModuleFile == None or self.ModuleFile == "":
-            if not self.SpawnMode or self.Target not in ["", "all"]:
-                self.SpawnMode = False
-                self._BuildPlatform()
-            else:
-                self._MultiThreadBuildPlatform()
-            self.CreateGuidedSectionToolsFile()
-        else:
-            self.SpawnMode = False
-            self._BuildModule()
-
-    ## Do some clean-up works when error occurred
-    def Relinquish(self):
-        OldLogLevel = EdkLogger.GetLevel()
-        EdkLogger.SetLevel(EdkLogger.ERROR)
-        #self.DumpBuildData()
-        Utils.Progressor.Abort()
-        if self.SpawnMode == True:
-            BuildTask.Abort()
-        EdkLogger.SetLevel(OldLogLevel)
-
-    def DumpBuildData(self):
-        CacheDirectory = os.path.join(self.WorkspaceDir, gBuildCacheDir)
-        Utils.CreateDirectory(CacheDirectory)
-        Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))
-        Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))
-
-    def RestoreBuildData(self):
-        FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gFileTimeStampCache")
-        if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):
-            Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)
-            if Utils.gFileTimeStampCache == None:
-                Utils.gFileTimeStampCache = {}
-
-        FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gDependencyDatabase")
-        if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):
-            Utils.gDependencyDatabase = Utils.DataRestore(FilePath)
-            if Utils.gDependencyDatabase == None:
-                Utils.gDependencyDatabase = {}
-
-def ParseDefines(DefineList=[]):
-    DefineDict = {}
-    if DefineList != None:
-        for Define in DefineList:
-            DefineTokenList = Define.split("=", 1)
-            if len(DefineTokenList) == 1:
-                DefineDict[DefineTokenList[0]] = ""
-            else:
-                DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()
-    return DefineDict
-
-gParamCheck = []
-def SingleCheckCallback(option, opt_str, value, parser):
-    if option not in gParamCheck:
-        setattr(parser.values, option.dest, value)
-        gParamCheck.append(option)
-    else:
-        parser.error("Option %s only allows one instance in command line!" % option)
-
-## Parse command line options
-#
-# Using standard Python module optparse to parse command line option of this tool.
-#
-#   @retval Opt   A optparse.Values object containing the parsed options
-#   @retval Args  Target of build command
-#
-def MyOptionParser():
-    Parser = OptionParser(description=__copyright__,version=__version__,prog="build.exe",usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
-    Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32','X64','IPF','EBC','ARM'], dest="TargetArch",
-        help="ARCHS is one of list: IA32, X64, IPF, ARM or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.")
-    Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,
-        help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
-    Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,
-        help="Build the module specified by the INF file name argument.")
-    Parser.add_option("-b", "--buildtarget", action="append", type="choice", choices=['DEBUG','RELEASE'], dest="BuildTarget",
-        help="BuildTarget is one of list: DEBUG, RELEASE, which overrides target.txt's TARGET definition. To specify more TARGET, please repeat this option.")
-    Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",
-        help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
-    Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,
-        help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
-
-    Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,
-        help="Build the platform using multi-threaded compiler. The value overrides target.txt's MAX_CONCURRENT_THREAD_NUMBER. Less than 2 will disable multi-thread builds.")
-
-    Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,
-        help="The name of the FDF file to use, which overrides the setting in the DSC file.")
-    Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],
-        help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
-    Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],
-        help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
-
-    Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")
-    Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")
-
-    Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", help="Don't check case of file name.")
-
-    # Parser.add_option("-D", "--define", action="append", dest="Defines", metavar="NAME[=[VALUE]]",
-    #     help="Define global macro which can be used in DSC/DEC/INF files.")
-
-    Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")
-    Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")
-
-    Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",
-        help="Make use of silent mode of (n)make.")
-    Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
-    Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
-                                                                               "including library instances selected, final dependency expression, "\
-                                                                               "and warning messages, etc.")
-    Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
-    Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
-
-    Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")
-    Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['ALL','PCD',], dest="ReportType",
-        help="Flags that control the type of build report to generate.  Must be one of: [ALL, PCD].  To specify more than one flag, repeat this option on the command line.")
-
-    (Opt, Args)=Parser.parse_args()
-    return (Opt, Args)
-
-## Tool entrance method
-#
-# This method mainly dispatch specific methods per the command line options.
-# If no error found, return zero value so the caller of this tool can know
-# if it's executed successfully or not.
-#
-#   @retval 0     Tool was successful
-#   @retval 1     Tool failed
-#
-def Main():
-    StartTime = time.time()
-
-    # Initialize log system
-    EdkLogger.Initialize()
-
-    #
-    # Parse the options and args
-    #
-    (Option, Target) = MyOptionParser()
-    GlobalData.gOptions = Option
-    GlobalData.gCaseInsensitive = Option.CaseInsensitive
-
-    # Set log level
-    if Option.verbose != None:
-        EdkLogger.SetLevel(EdkLogger.VERBOSE)
-    elif Option.quiet != None:
-        EdkLogger.SetLevel(EdkLogger.QUIET)
-    elif Option.debug != None:
-        EdkLogger.SetLevel(Option.debug + 1)
-    else:
-        EdkLogger.SetLevel(EdkLogger.INFO)
-
-    if Option.LogFile != None:
-        EdkLogger.SetLogFile(Option.LogFile)
-
-    if Option.WarningAsError == True:
-        EdkLogger.SetWarningAsError()
-
-    if platform.platform().find("Windows") >= 0:
-        GlobalData.gIsWindows = True
-    else:
-        GlobalData.gIsWindows = False
-
-    EdkLogger.quiet(time.strftime("%H:%M:%S, %b.%d %Y ", time.localtime()) + "[%s]\n" % platform.platform())
-    ReturnCode = 0
-    MyBuild = None
-    try:
-        if len(Target) == 0:
-            Target = "all"
-        elif len(Target) >= 2:
-            EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",
-                            ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))
-        else:
-            Target = Target[0].lower()
-
-        if Target not in gSupportedTarget:
-            EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,
-                            ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))
-
-        GlobalData.gGlobalDefines = ParseDefines(Option.Macros)
-        #
-        # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
-        #
-        CheckEnvVariable()
-        Workspace = os.getenv("WORKSPACE")
-        #
-        # Get files real name in workspace dir
-        #
-        GlobalData.gAllFiles = Utils.DirCache(Workspace)
-
-        WorkingDirectory = os.getcwd()
-        if not Option.ModuleFile:
-            FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))
-            FileNum = len(FileList)
-            if FileNum >= 2:
-                EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),
-                                ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")
-            elif FileNum == 1:
-                Option.ModuleFile = NormFile(FileList[0], Workspace)
-
-        if Option.ModuleFile:
-            Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)
-            ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)
-            if ErrorCode != 0:
-                EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
-
-        if Option.PlatformFile != None:
-            Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)
-            ErrorCode, ErrorInfo = Option.PlatformFile.Validate(".dsc", False)
-            if ErrorCode != 0:
-                EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
-
-        if Option.FdfFile != None:
-            Option.FdfFile = PathClass(Option.FdfFile, Workspace)
-            ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)
-            if ErrorCode != 0:
-                EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
-
-        MyBuild = Build(Target, Workspace, Option.PlatformFile, Option.ModuleFile,
-                        Option.TargetArch, Option.ToolChain, Option.BuildTarget,
-                        Option.FdfFile, Option.RomImage, Option.FvImage,
-                        None, Option.SilentMode, Option.ThreadNumber,
-                        Option.SkipAutoGen, Option.Reparse, Option.SkuId, 
-                        Option.ReportFile, Option.ReportType)
-        MyBuild.Launch()
-        #MyBuild.DumpBuildData()
-    except FatalError, X:
-        if MyBuild != None:
-            # for multi-thread build exits safely
-            MyBuild.Relinquish()
-        if Option != None and Option.debug != None:
-            EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
-        ReturnCode = X.args[0]
-    except Warning, X:
-        # error from Fdf parser
-        if MyBuild != None:
-            # for multi-thread build exits safely
-            MyBuild.Relinquish()
-        if Option != None and Option.debug != None:
-            EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
-        else:
-            EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError = False)
-        ReturnCode = FORMAT_INVALID
-    except KeyboardInterrupt:
-        ReturnCode = ABORT_ERROR
-        if Option != None and Option.debug != None:
-            EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
-    except:
-        if MyBuild != None:
-            # for multi-thread build exits safely
-            MyBuild.Relinquish()
-
-        # try to get the meta-file from the object causing exception
-        Tb = sys.exc_info()[-1]
-        MetaFile = GlobalData.gProcessingFile
-        while Tb != None:
-            if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):
-                MetaFile = Tb.tb_frame.f_locals['self'].MetaFile
-            Tb = Tb.tb_next
-        EdkLogger.error(
-                    "\nbuild",
-                    CODE_ERROR,
-                    "Unknown fatal error when processing [%s]" % MetaFile,
-                    ExtraData="\n(Please send email to dev@buildtools.tianocore.org for help, attaching following call stack trace!)\n",
-                    RaiseError=False
-                    )
-        EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
-        ReturnCode = CODE_ERROR
-    finally:
-        Utils.Progressor.Abort()
-
-    if MyBuild != None:
-        MyBuild.Db.Close()
-
-    if ReturnCode == 0:
-        Conclusion = "Done"
-    elif ReturnCode == ABORT_ERROR:
-        Conclusion = "Aborted"
-    else:
-        Conclusion = "Failed"
-    FinishTime = time.time()
-    BuildDuration = time.strftime("%M:%S", time.gmtime(int(round(FinishTime - StartTime))))
-    EdkLogger.SetLevel(EdkLogger.QUIET)
-    EdkLogger.quiet("\n- %s -\n%s [%s]" % (Conclusion, time.strftime("%H:%M:%S, %b.%d %Y", time.localtime()), BuildDuration))
-
-    return ReturnCode
-
-if __name__ == '__main__':
-    r = Main()
-    ## 0-127 is a safe return range, and 1 is a standard default error
-    if r < 0 or r > 127: r = 1
-    sys.exit(r)
-
+## @file\r
+# build a platform or a module\r
+#\r
+#  Copyright (c) 2007 - 2010, Intel Corporation\r
+#\r
+#  All rights reserved. This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution.  The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+\r
+##\r
+# Import Modules\r
+#\r
+import os\r
+import re\r
+import StringIO\r
+import sys\r
+import glob\r
+import time\r
+import platform\r
+import traceback\r
+\r
+from struct import *\r
+from threading import *\r
+from optparse import OptionParser\r
+from subprocess import *\r
+from Common import Misc as Utils\r
+\r
+from Common.TargetTxtClassObject import *\r
+from Common.ToolDefClassObject import *\r
+from Common.DataType import *\r
+from AutoGen.AutoGen import *\r
+from Common.BuildToolError import *\r
+from Workspace.WorkspaceDatabase import *\r
+\r
+from BuildReport import BuildReport\r
+from GenPatchPcdTable.GenPatchPcdTable import *\r
+from PatchPcdValue.PatchPcdValue import *\r
+\r
+import Common.EdkLogger\r
+import Common.GlobalData as GlobalData\r
+\r
+# Version and Copyright\r
+VersionNumber = "0.5"\r
+__version__ = "%prog Version " + VersionNumber\r
+__copyright__ = "Copyright (c) 2007 - 2010, Intel Corporation  All rights reserved."\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 = "Conf/target.txt"\r
+gBuildCacheDir = "Conf/.cache"\r
+gToolsDefinition = "Conf/tools_def.txt"\r
+\r
+## Check environment PATH variable to make sure the specified tool is found\r
+#\r
+#   If the tool is found in the PATH, then True is returned\r
+#   Otherwise, False is returned\r
+#\r
+def IsToolInPath(tool):\r
+    if os.environ.has_key('PATHEXT'):\r
+        extns = os.environ['PATHEXT'].split(os.path.pathsep)\r
+    else:\r
+        extns = ('',)\r
+    for pathDir in os.environ['PATH'].split(os.path.pathsep):\r
+        for ext in extns:\r
+            if os.path.exists(os.path.join(pathDir, tool + ext)):\r
+                return True\r
+    return False\r
+\r
+## Check environment variables\r
+#\r
+#  Check environment variables that must be set for build. Currently they are\r
+#\r
+#   WORKSPACE           The directory all packages/platforms start from\r
+#   EDK_TOOLS_PATH      The directory contains all tools needed by the build\r
+#   PATH                $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH\r
+#\r
+#   If any of above environment variable is not set or has error, the build\r
+#   will be broken.\r
+#\r
+def CheckEnvVariable():\r
+    # check WORKSPACE\r
+    if "WORKSPACE" not in os.environ:\r
+        EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",\r
+                        ExtraData="WORKSPACE")\r
+\r
+    WorkspaceDir = os.path.normcase(os.path.normpath(os.environ["WORKSPACE"]))\r
+    if not os.path.exists(WorkspaceDir):\r
+        EdkLogger.error("build", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData="%s" % WorkspaceDir)\r
+    elif ' ' in WorkspaceDir:\r
+        EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path",\r
+                        ExtraData=WorkspaceDir)\r
+    os.environ["WORKSPACE"] = WorkspaceDir\r
+\r
+    #\r
+    # Check EFI_SOURCE (R8 build convention). EDK_SOURCE will always point to ECP\r
+    #\r
+    os.environ["ECP_SOURCE"] = os.path.join(WorkspaceDir, GlobalData.gEdkCompatibilityPkg)\r
+    if "EFI_SOURCE" not in os.environ:\r
+        os.environ["EFI_SOURCE"] = os.environ["ECP_SOURCE"]\r
+    if "EDK_SOURCE" not in os.environ:\r
+        os.environ["EDK_SOURCE"] = os.environ["ECP_SOURCE"]\r
+\r
+    #\r
+    # Unify case of characters on case-insensitive systems\r
+    #\r
+    EfiSourceDir = os.path.normcase(os.path.normpath(os.environ["EFI_SOURCE"]))\r
+    EdkSourceDir = os.path.normcase(os.path.normpath(os.environ["EDK_SOURCE"]))\r
+    EcpSourceDir = os.path.normcase(os.path.normpath(os.environ["ECP_SOURCE"]))\r
\r
+    os.environ["EFI_SOURCE"] = EfiSourceDir\r
+    os.environ["EDK_SOURCE"] = EdkSourceDir\r
+    os.environ["ECP_SOURCE"] = EcpSourceDir\r
+    os.environ["EDK_TOOLS_PATH"] = os.path.normcase(os.environ["EDK_TOOLS_PATH"])\r
+    \r
+    if not os.path.exists(EcpSourceDir):\r
+        EdkLogger.verbose("ECP_SOURCE = %s doesn't exist. R8 modules could not be built." % EcpSourceDir)\r
+    elif ' ' in EcpSourceDir:\r
+        EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in ECP_SOURCE path",\r
+                        ExtraData=EcpSourceDir)\r
+    if not os.path.exists(EdkSourceDir):\r
+        if EdkSourceDir == EcpSourceDir:\r
+            EdkLogger.verbose("EDK_SOURCE = %s doesn't exist. R8 modules could not be built." % EdkSourceDir)\r
+        else:\r
+            EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE does not exist",\r
+                            ExtraData=EdkSourceDir)\r
+    elif ' ' in EdkSourceDir:\r
+        EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EDK_SOURCE path",\r
+                        ExtraData=EdkSourceDir)\r
+    if not os.path.exists(EfiSourceDir):\r
+        if EfiSourceDir == EcpSourceDir:\r
+            EdkLogger.verbose("EFI_SOURCE = %s doesn't exist. R8 modules could not be built." % EfiSourceDir)\r
+        else:\r
+            EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE does not exist",\r
+                            ExtraData=EfiSourceDir)\r
+    elif ' ' in EfiSourceDir:\r
+        EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EFI_SOURCE path",\r
+                        ExtraData=EfiSourceDir)\r
+\r
+    # change absolute path to relative path to WORKSPACE\r
+    if EfiSourceDir.upper().find(WorkspaceDir.upper()) != 0:\r
+        EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE is not under WORKSPACE",\r
+                        ExtraData="WORKSPACE = %s\n    EFI_SOURCE = %s" % (WorkspaceDir, EfiSourceDir))\r
+    if EdkSourceDir.upper().find(WorkspaceDir.upper()) != 0:\r
+        EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE is not under WORKSPACE",\r
+                        ExtraData="WORKSPACE = %s\n    EDK_SOURCE = %s" % (WorkspaceDir, EdkSourceDir))\r
+    if EcpSourceDir.upper().find(WorkspaceDir.upper()) != 0:\r
+        EdkLogger.error("build", PARAMETER_INVALID, "ECP_SOURCE is not under WORKSPACE",\r
+                        ExtraData="WORKSPACE = %s\n    ECP_SOURCE = %s" % (WorkspaceDir, EcpSourceDir))\r
+\r
+    # check EDK_TOOLS_PATH\r
+    if "EDK_TOOLS_PATH" not in os.environ:\r
+        EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",\r
+                        ExtraData="EDK_TOOLS_PATH")\r
+\r
+    # check PATH\r
+    if "PATH" not in os.environ:\r
+        EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",\r
+                        ExtraData="PATH")\r
+\r
+    GlobalData.gWorkspace = WorkspaceDir\r
+    GlobalData.gEfiSource = EfiSourceDir\r
+    GlobalData.gEdkSource = EdkSourceDir\r
+    GlobalData.gEcpSource = EcpSourceDir\r
+\r
+## Get normalized file path\r
+#\r
+# Convert the path to be local format, and remove the WORKSPACE path at the\r
+# beginning if the file path is given in full path.\r
+#\r
+# @param  FilePath      File path to be normalized\r
+# @param  Workspace     Workspace path which the FilePath will be checked against\r
+#\r
+# @retval string        The normalized file path\r
+#\r
+def NormFile(FilePath, Workspace):\r
+    # check if the path is absolute or relative\r
+    if os.path.isabs(FilePath):\r
+        FileFullPath = os.path.normpath(FilePath)\r
+    else:\r
+        FileFullPath = os.path.normpath(os.path.join(Workspace, FilePath))\r
+\r
+    # check if the file path exists or not\r
+    if not os.path.isfile(FileFullPath):\r
+        EdkLogger.error("build", FILE_NOT_FOUND, ExtraData="\t%s (Please give file in absolute path or relative to WORKSPACE)"  % FileFullPath)\r
+\r
+    # remove workspace directory from the beginning part of the file path\r
+    if Workspace[-1] in ["\\", "/"]:\r
+        return FileFullPath[len(Workspace):]\r
+    else:\r
+        return FileFullPath[(len(Workspace) + 1):]\r
+\r
+## Get the output of an external program\r
+#\r
+# This is the entrance method of thread reading output of an external program and\r
+# putting them in STDOUT/STDERR of current program.\r
+#\r
+# @param  From      The stream message read from\r
+# @param  To        The stream message put on\r
+# @param  ExitFlag  The flag used to indicate stopping reading\r
+#\r
+def ReadMessage(From, To, ExitFlag):\r
+    while True:\r
+        # read one line a time\r
+        Line = From.readline()\r
+        # empty string means "end"\r
+        if Line != None and Line != "":\r
+            To(Line.rstrip())\r
+        else:\r
+            break\r
+        if ExitFlag.isSet():\r
+            break\r
+\r
+## Launch an external program\r
+#\r
+# This method will call subprocess.Popen to execute an external program with\r
+# given options in specified directory. Because of the dead-lock issue during\r
+# redirecting output of the external program, threads are used to to do the\r
+# redirection work.\r
+#\r
+# @param  Command               A list or string containing the call of the program\r
+# @param  WorkingDir            The directory in which the program will be running\r
+#\r
+def LaunchCommand(Command, WorkingDir):\r
+    # 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
+    Proc = None\r
+    EndOfProcedure = None\r
+    try:\r
+        # launch the command\r
+        Proc = Popen(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir, bufsize=-1)\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: # in case of aborting\r
+        # terminate the threads redirecting the program output\r
+        if EndOfProcedure != None:\r
+            EndOfProcedure.set()\r
+        if Proc == None:\r
+            if type(Command) != type(""):\r
+                Command = " ".join(Command)\r
+            EdkLogger.error("build", COMMAND_FAILURE, "Failed to start command", ExtraData="%s [%s]" % (Command, WorkingDir))\r
+\r
+    if Proc.stdout:\r
+        StdOutThread.join()\r
+    if Proc.stderr:\r
+        StdErrThread.join()\r
+\r
+    # check the return code of the program\r
+    if Proc.returncode != 0:\r
+        if type(Command) != type(""):\r
+            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
+# This is the base class of build unit. The "Obj" parameter must provide\r
+# __str__(), __eq__() and __hash__() methods. Otherwise there could be build units\r
+# missing build.\r
+#\r
+# Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.\r
+#\r
+class BuildUnit:\r
+    ## The constructor\r
+    #\r
+    #   @param  self        The object pointer\r
+    #   @param  Obj         The object the build is working on\r
+    #   @param  Target      The build target name, one of gSupportedTarget\r
+    #   @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, BuildCommand, Target, Dependency, WorkingDir="."):\r
+        self.BuildObject = Obj\r
+        self.Dependency = Dependency\r
+        self.WorkingDir = WorkingDir\r
+        self.Target = Target\r
+        self.BuildCommand = BuildCommand\r
+        if BuildCommand == None or len(BuildCommand) == 0:\r
+            EdkLogger.error("build", OPTION_MISSING, "No build command found for",\r
+                            ExtraData=str(Obj))\r
+\r
+    ## str() method\r
+    #\r
+    #   It just returns the string representaion of self.BuildObject\r
+    #\r
+    #   @param  self        The object pointer\r
+    #\r
+    def __str__(self):\r
+        return str(self.BuildObject)\r
+\r
+    ## "==" operator method\r
+    #\r
+    #   It just compares self.BuildObject with "Other". So self.BuildObject must\r
+    #   provide its own __eq__() method.\r
+    #\r
+    #   @param  self        The object pointer\r
+    #   @param  Other       The other BuildUnit object compared to\r
+    #\r
+    def __eq__(self, Other):\r
+        return Other != None and self.BuildObject == Other.BuildObject \\r
+                and self.BuildObject.Arch == Other.BuildObject.Arch\r
+\r
+    ## hash() method\r
+    #\r
+    #   It just returns the hash value of self.BuildObject which must be hashable.\r
+    #\r
+    #   @param  self        The object pointer\r
+    #\r
+    def __hash__(self):\r
+        return hash(self.BuildObject) + hash(self.BuildObject.Arch)\r
+\r
+    def __repr__(self):\r
+        return repr(self.BuildObject)\r
+\r
+## The smallest module unit that can be built by nmake/make command in multi-thread build mode\r
+#\r
+# This class is for module build by nmake/make build system. The "Obj" parameter\r
+# must provide __str__(), __eq__() and __hash__() methods. Otherwise there could\r
+# be make units missing build.\r
+#\r
+# Currently the "Obj" should be only ModuleAutoGen object.\r
+#\r
+class ModuleMakeUnit(BuildUnit):\r
+    ## The constructor\r
+    #\r
+    #   @param  self        The object pointer\r
+    #   @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
+        if Target in [None, "", "all"]:\r
+            self.Target = "tbuild"\r
+\r
+## The smallest platform unit that can be built by nmake/make command in multi-thread build mode\r
+#\r
+# This class is for platform build by nmake/make build system. The "Obj" parameter\r
+# must provide __str__(), __eq__() and __hash__() methods. Otherwise there could\r
+# be make units missing build.\r
+#\r
+# Currently the "Obj" should be only PlatformAutoGen object.\r
+#\r
+class PlatformMakeUnit(BuildUnit):\r
+    ## The constructor\r
+    #\r
+    #   @param  self        The object pointer\r
+    #   @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
+\r
+## The class representing the task of a module build or platform build\r
+#\r
+# This class manages the build tasks in multi-thread build mode. Its jobs include\r
+# scheduling thread running, catching thread error, monitor the thread status, etc.\r
+#\r
+class BuildTask:\r
+    # queue for tasks waiting for schedule\r
+    _PendingQueue = sdict()\r
+    _PendingQueueLock = threading.Lock()\r
+\r
+    # queue for tasks ready for running\r
+    _ReadyQueue = sdict()\r
+    _ReadyQueueLock = threading.Lock()\r
+\r
+    # queue for run tasks\r
+    _RunningQueue = sdict()\r
+    _RunningQueueLock = threading.Lock()\r
+\r
+    # queue containing all build tasks, in case duplicate build\r
+    _TaskQueue = sdict()\r
+\r
+    # flag indicating error occurs in a running thread\r
+    _ErrorFlag = threading.Event()\r
+    _ErrorFlag.clear()\r
+    _ErrorMessage = ""\r
+\r
+    # BoundedSemaphore object used to control the number of running threads\r
+    _Thread = None\r
+\r
+    # flag indicating if the scheduler is started or not\r
+    _SchedulerStopped = threading.Event()\r
+    _SchedulerStopped.set()\r
+\r
+    ## Start the task scheduler thread\r
+    #\r
+    #   @param  MaxThreadNumber     The maximum thread number\r
+    #   @param  ExitFlag            Flag used to end the scheduler\r
+    #\r
+    @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.start()\r
+        # wait for the scheduler to be started, especially useful in Linux\r
+        while not BuildTask.IsOnGoing():\r
+            time.sleep(0.01)\r
+\r
+    ## Scheduler method\r
+    #\r
+    #   @param  MaxThreadNumber     The maximum thread number\r
+    #   @param  ExitFlag            Flag used to end the scheduler\r
+    #\r
+    @staticmethod\r
+    def Scheduler(MaxThreadNumber, ExitFlag):\r
+        BuildTask._SchedulerStopped.clear()\r
+        try:\r
+            # use BoundedSemaphore to control the maximum running threads\r
+            BuildTask._Thread = BoundedSemaphore(MaxThreadNumber)\r
+            #\r
+            # scheduling loop, which will exits when no pending/ready task and\r
+            # 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
+                EdkLogger.debug(EdkLogger.DEBUG_8, "Pending Queue (%d), Ready Queue (%d)"\r
+                                % (len(BuildTask._PendingQueue), len(BuildTask._ReadyQueue)))\r
+\r
+                # get all pending tasks\r
+                BuildTask._PendingQueueLock.acquire()\r
+                BuildObjectList = BuildTask._PendingQueue.keys()\r
+                #\r
+                # check if their dependency is resolved, and if true, move them\r
+                # into ready queue\r
+                #\r
+                for BuildObject in BuildObjectList:\r
+                    Bt = BuildTask._PendingQueue[BuildObject]\r
+                    if Bt.IsReady():\r
+                        BuildTask._ReadyQueue[BuildObject] = BuildTask._PendingQueue.pop(BuildObject)\r
+                BuildTask._PendingQueueLock.release()\r
+\r
+                # launch build thread until the maximum number of threads is reached\r
+                while not BuildTask._ErrorFlag.isSet():\r
+                    # empty ready queue, do nothing further\r
+                    if len(BuildTask._ReadyQueue) == 0:\r
+                        break\r
+\r
+                    # wait for active thread(s) exit\r
+                    BuildTask._Thread.acquire(True)\r
+\r
+                    # start a new build thread\r
+                    Bo = BuildTask._ReadyQueue.keys()[0]\r
+                    Bt = BuildTask._ReadyQueue.pop(Bo)\r
+\r
+                    # move into running queue\r
+                    BuildTask._RunningQueueLock.acquire()\r
+                    BuildTask._RunningQueue[Bo] = Bt\r
+                    BuildTask._RunningQueueLock.release()\r
+\r
+                    Bt.Start()\r
+                    # avoid tense loop\r
+                    time.sleep(0.01)\r
+\r
+                # avoid tense loop\r
+                time.sleep(0.01)\r
+\r
+            # wait for all running threads exit\r
+            if BuildTask._ErrorFlag.isSet():\r
+                EdkLogger.quiet("\nWaiting for all build threads exit...")\r
+            # while not BuildTask._ErrorFlag.isSet() 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
+                # avoid tense loop\r
+                time.sleep(0.1)\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
+            #\r
+            EdkLogger.SetLevel(EdkLogger.ERROR)\r
+            BuildTask._ErrorFlag.set()\r
+            BuildTask._ErrorMessage = "build thread scheduler error\n\t%s" % str(X)\r
+\r
+        BuildTask._PendingQueue.clear()\r
+        BuildTask._ReadyQueue.clear()\r
+        BuildTask._RunningQueue.clear()\r
+        BuildTask._TaskQueue.clear()\r
+        BuildTask._SchedulerStopped.set()\r
+\r
+    ## Wait for all running method exit\r
+    #\r
+    @staticmethod\r
+    def WaitForComplete():\r
+        BuildTask._SchedulerStopped.wait()\r
+\r
+    ## Check if the scheduler is running or not\r
+    #\r
+    @staticmethod\r
+    def IsOnGoing():\r
+        return not BuildTask._SchedulerStopped.isSet()\r
+\r
+    ## Abort the build\r
+    @staticmethod\r
+    def Abort():\r
+        if BuildTask.IsOnGoing():\r
+            BuildTask._ErrorFlag.set()\r
+            BuildTask.WaitForComplete()\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
+    #   use threading.Event to communicate this formation to main thread.\r
+    #\r
+    @staticmethod\r
+    def HasError():\r
+        return BuildTask._ErrorFlag.isSet()\r
+\r
+    ## Get error message in running thread\r
+    #\r
+    #   Since the main thread cannot catch exceptions in other thread, we have to\r
+    #   use a static variable to communicate this message to main thread.\r
+    #\r
+    @staticmethod\r
+    def GetErrorMessage():\r
+        return BuildTask._ErrorMessage\r
+\r
+    ## Factory method to create a BuildTask object\r
+    #\r
+    #   This method will check if a module is building or has been built. And if\r
+    #   true, just return the associated BuildTask object in the _TaskQueue. If\r
+    #   not, create and return a new BuildTask object. The new BuildTask object\r
+    #   will be appended to the _PendingQueue for scheduling later.\r
+    #\r
+    #   @param  BuildItem       A BuildUnit object representing a build object\r
+    #   @param  Dependency      The dependent build object of BuildItem\r
+    #\r
+    @staticmethod\r
+    def New(BuildItem, Dependency=None):\r
+        if BuildItem in BuildTask._TaskQueue:\r
+            Bt = BuildTask._TaskQueue[BuildItem]\r
+            return Bt\r
+\r
+        Bt = BuildTask()\r
+        Bt._Init(BuildItem, Dependency)\r
+        BuildTask._TaskQueue[BuildItem] = Bt\r
+\r
+        BuildTask._PendingQueueLock.acquire()\r
+        BuildTask._PendingQueue[BuildItem] = Bt\r
+        BuildTask._PendingQueueLock.release()\r
+\r
+        return Bt\r
+\r
+    ## The real constructor of BuildTask\r
+    #\r
+    #   @param  BuildItem       A BuildUnit object representing a build object\r
+    #   @param  Dependency      The dependent build object of BuildItem\r
+    #\r
+    def _Init(self, BuildItem, Dependency=None):\r
+        self.BuildItem = BuildItem\r
+\r
+        self.DependencyList = []\r
+        if Dependency == None:\r
+            Dependency = BuildItem.Dependency\r
+        else:\r
+            Dependency.extend(BuildItem.Dependency)\r
+        self.AddDependency(Dependency)\r
+        # flag indicating build completes, used to avoid unnecessary re-build\r
+        self.CompleteFlag = False\r
+\r
+    ## Check if all dependent build tasks are completed or not\r
+    #\r
+    def IsReady(self):\r
+        ReadyFlag = True\r
+        for Dep in self.DependencyList:\r
+            if Dep.CompleteFlag == True:\r
+                continue\r
+            ReadyFlag = False\r
+            break\r
+\r
+        return ReadyFlag\r
+\r
+    ## Add dependent build task\r
+    #\r
+    #   @param  Dependency      The list of dependent build objects\r
+    #\r
+    def AddDependency(self, Dependency):\r
+        for Dep in Dependency:\r
+            self.DependencyList.append(BuildTask.New(Dep))    # BuildTask list\r
+\r
+    ## The thread wrapper of LaunchCommand function\r
+    #\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, Command, WorkingDir):\r
+        try:\r
+            LaunchCommand(Command, WorkingDir)\r
+            self.CompleteFlag = True\r
+        except:\r
+            #\r
+            # TRICK: hide the output of threads left runing, so that the user can\r
+            #        catch the error message easily\r
+            #\r
+            if not BuildTask._ErrorFlag.isSet():\r
+                GlobalData.gBuildingModule = "%s [%s, %s, %s]" % (str(self.BuildItem.BuildObject),\r
+                                                                  self.BuildItem.BuildObject.Arch,\r
+                                                                  self.BuildItem.BuildObject.ToolChain,\r
+                                                                  self.BuildItem.BuildObject.BuildTarget\r
+                                                                 )\r
+            EdkLogger.SetLevel(EdkLogger.ERROR)\r
+            BuildTask._ErrorFlag.set()\r
+            BuildTask._ErrorMessage = "%s broken\n    %s [%s]" % \\r
+                                      (threading.currentThread().getName(), Command, WorkingDir)\r
+        # indicate there's a thread is available for another build task\r
+        BuildTask._RunningQueueLock.acquire()\r
+        BuildTask._RunningQueue.pop(self.BuildItem)\r
+        BuildTask._RunningQueueLock.release()\r
+        BuildTask._Thread.release()\r
+\r
+    ## Start build task thread\r
+    #\r
+    def Start(self):\r
+        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.start()\r
+\r
+## The class contains the information related to EFI image\r
+#\r
+class PeImageInfo():\r
+    ## Constructor\r
+    #\r
+    # Constructor will load all required image information.\r
+    #\r
+    #   @param  BaseName          The full file path of image. \r
+    #   @param  Guid              The GUID for image.\r
+    #   @param  Arch              Arch of this image.\r
+    #   @param  OutpuDir          The output directory for image.\r
+    #   @param  ImageClass        PeImage Information\r
+    #\r
+    def __init__(self, BaseName, Guid, Arch, OutpuDir, ImageClass):\r
+        self.BaseName         = BaseName\r
+        self.Guid             = Guid\r
+        self.Arch             = Arch\r
+        self.OutpuDir         = OutpuDir\r
+        self.Image            = ImageClass\r
+        self.Image.Size       = (self.Image.Size / 0x1000 + 1) * 0x1000\r
+\r
+## The class implementing the EDK2 build process\r
+#\r
+#   The build process includes:\r
+#       1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf\r
+#       2. Parse DSC file of active platform\r
+#       3. Parse FDF file if any\r
+#       4. Establish build database, including parse all other files (module, package)\r
+#       5. Create AutoGen files (C code file, depex file, makefile) if necessary\r
+#       6. Call build command\r
+#\r
+class Build():\r
+    ## Constructor\r
+    #\r
+    # Constructor will load all necessary configurations, parse platform, modules\r
+    # and packages and the establish a database for AutoGen.\r
+    #\r
+    #   @param  Target              The build command target, one of gSupportedTarget\r
+    #   @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 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
+    #   @param  FvList=[]           The FV names to be individually built\r
+    #   @param  MakefileType        The type of makefile (for MSFT make or GNU make)\r
+    #   @param  SilentMode          Indicate multi-thread build mode\r
+    #   @param  ThreadNumber        The maximum number of thread if in multi-thread build mode\r
+    #   @param  SkipAutoGen         Skip AutoGen step\r
+    #   @param  Reparse             Re-parse all meta files\r
+    #   @param  SkuId               SKU id from command line\r
+    #\r
+    def __init__(self, Target, WorkspaceDir, Platform, Module, Arch, ToolChain,\r
+                 BuildTarget, FlashDefinition, FdList=[], FvList=[],\r
+                 MakefileType="nmake", SilentMode=False, ThreadNumber=2,\r
+                 SkipAutoGen=False, Reparse=False, SkuId=None, \r
+                 ReportFile=None, ReportType=None):\r
+\r
+        self.WorkspaceDir = WorkspaceDir\r
+        self.Target         = Target\r
+        self.PlatformFile   = Platform\r
+        self.ModuleFile     = Module\r
+        self.ArchList       = Arch\r
+        self.ToolChainList  = ToolChain\r
+        self.BuildTargetList= BuildTarget\r
+        self.Fdf            = FlashDefinition\r
+        self.FdList         = FdList\r
+        self.FvList         = FvList\r
+        self.MakefileType   = MakefileType\r
+        self.SilentMode     = SilentMode\r
+        self.ThreadNumber   = ThreadNumber\r
+        self.SkipAutoGen    = SkipAutoGen\r
+        self.Reparse        = Reparse\r
+        self.SkuId          = SkuId\r
+        self.SpawnMode      = True\r
+        self.BuildReport    = BuildReport(ReportFile, ReportType)\r
+        self.TargetTxt      = TargetTxtClassObject()\r
+        self.ToolDef        = ToolDefClassObject()\r
+        self.Db             = WorkspaceDatabase(None, GlobalData.gGlobalDefines, self.Reparse)\r
+        #self.Db             = WorkspaceDatabase(None, {}, self.Reparse)\r
+        self.BuildDatabase  = self.Db.BuildObject\r
+        self.Platform       = None\r
+        self.LoadFixAddress = 0\r
+\r
+        # print dot charater during doing some time-consuming work\r
+        self.Progress = Utils.Progressor()\r
+\r
+        # parse target.txt, tools_def.txt, and platform file\r
+        #self.RestoreBuildData()\r
+        self.LoadConfiguration()\r
+        self.InitBuild()\r
+\r
+        # print current build environment and configuration\r
+        EdkLogger.quiet("%-24s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))\r
+        EdkLogger.quiet("%-24s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"]))\r
+        EdkLogger.quiet("%-24s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"]))\r
+        EdkLogger.quiet("%-24s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"]))\r
+        EdkLogger.quiet("%-24s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))\r
+\r
+        EdkLogger.info('\n%-24s = %s' % ("TARGET_ARCH", ' '.join(self.ArchList)))\r
+        EdkLogger.info('%-24s = %s' % ("TARGET", ' '.join(self.BuildTargetList)))\r
+        EdkLogger.info('%-24s = %s' % ("TOOL_CHAIN_TAG", ' '.join(self.ToolChainList)))\r
+\r
+        EdkLogger.info('\n%-24s = %s' % ("Active Platform", self.PlatformFile))\r
+\r
+        if self.Fdf != None and self.Fdf != "":\r
+            EdkLogger.info('%-24s = %s' % ("Flash Image Definition", self.Fdf))\r
+\r
+        if self.ModuleFile != None and self.ModuleFile != "":\r
+            EdkLogger.info('%-24s = %s' % ("Active Module", self.ModuleFile))\r
+\r
+        os.chdir(self.WorkspaceDir)\r
+        self.Progress.Start("\nProcessing meta-data")\r
+\r
+    ## Load configuration\r
+    #\r
+    #   This method will parse target.txt and get the build configurations.\r
+    #\r
+    def LoadConfiguration(self):\r
+        #\r
+        # Check target.txt and tools_def.txt and Init them\r
+        #\r
+        BuildConfigurationFile = os.path.normpath(os.path.join(self.WorkspaceDir, gBuildConfiguration))\r
+        if os.path.isfile(BuildConfigurationFile) == True:\r
+            StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)\r
+\r
+            ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]\r
+            if ToolDefinitionFile == '':\r
+                ToolDefinitionFile = gToolsDefinition\r
+            ToolDefinitionFile = os.path.normpath(os.path.join(self.WorkspaceDir, ToolDefinitionFile))\r
+            if os.path.isfile(ToolDefinitionFile) == True:\r
+                StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)\r
+            else:\r
+                EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)\r
+        else:\r
+            EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)\r
+\r
+        # if no ARCH given in command line, get it from target.txt\r
+        if self.ArchList == None or len(self.ArchList) == 0:\r
+            self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH]\r
+\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
+\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 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:\r
+            self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]\r
+            if self.ThreadNumber == '':\r
+                self.ThreadNumber = 0\r
+            else:\r
+                self.ThreadNumber = int(self.ThreadNumber, 0)\r
+\r
+        if self.ThreadNumber == 0:\r
+            self.ThreadNumber = 1\r
+\r
+        if not self.PlatformFile:\r
+            PlatformFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM]\r
+            if not PlatformFile:\r
+                # Try to find one in current directory\r
+                WorkingDirectory = os.getcwd()\r
+                FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))\r
+                FileNum = len(FileList)\r
+                if FileNum >= 2:\r
+                    EdkLogger.error("build", OPTION_MISSING,\r
+                                    ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))\r
+                elif FileNum == 1:\r
+                    PlatformFile = FileList[0]\r
+                else:\r
+                    EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
+                                    ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")\r
+\r
+            self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)\r
+            ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)\r
+            if ErrorCode != 0:\r
+                EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
+\r
+    ## Initialize build configuration\r
+    #\r
+    #   This method will parse DSC file and merge the configurations from\r
+    #   command line and target.txt, then get the final build configurations.\r
+    #\r
+    def InitBuild(self):\r
+        ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc")\r
+        if ErrorCode != 0:\r
+            EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
+\r
+        # create metafile database\r
+        self.Db.InitDatabase()\r
+\r
+        # we need information in platform description file to determine how to build\r
+        self.Platform = self.BuildDatabase[self.PlatformFile, 'COMMON']\r
+        if not self.Fdf:\r
+            self.Fdf = self.Platform.FlashDefinition\r
+        \r
+        LoadFixAddressString = None\r
+        if TAB_FIX_LOAD_TOP_MEMORY_ADDRESS in GlobalData.gGlobalDefines:\r
+            LoadFixAddressString = GlobalData.gGlobalDefines[TAB_FIX_LOAD_TOP_MEMORY_ADDRESS]\r
+        else:\r
+            LoadFixAddressString = self.Platform.LoadFixAddress\r
+\r
+        if LoadFixAddressString != None and LoadFixAddressString != '':\r
+            try:\r
+                if LoadFixAddressString.upper().startswith('0X'):\r
+                    self.LoadFixAddress = int (LoadFixAddressString, 16)\r
+                else:\r
+                    self.LoadFixAddress = int (LoadFixAddressString)\r
+            except:
+                EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS %s is not valid dec or hex string" % (LoadFixAddressString))\r
+            if self.LoadFixAddress < 0:\r
+                EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is set to the invalid negative value %s" % (LoadFixAddressString))\r
+            if self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress % 0x1000 != 0:\r
+                EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is set to the invalid unaligned 4K value %s" % (LoadFixAddressString))\r
+\r
+        if self.SkuId == None or self.SkuId == '':\r
+            self.SkuId = self.Platform.SkuName\r
+\r
+        # check FD/FV build target\r
+        if self.Fdf == None or self.Fdf == "":\r
+            if self.FdList != []:\r
+                EdkLogger.info("No flash definition file found. FD [%s] will be ignored." % " ".join(self.FdList))\r
+                self.FdList = []\r
+            if self.FvList != []:\r
+                EdkLogger.info("No flash definition file found. FV [%s] will be ignored." % " ".join(self.FvList))\r
+                self.FvList = []\r
+        else:\r
+            FdfParserObj = FdfParser(str(self.Fdf))\r
+            FdfParserObj.ParseFile()\r
+            for fvname in self.FvList:\r
+                if fvname.upper() not in FdfParserObj.Profile.FvDict.keys():\r
+                    EdkLogger.error("build", OPTION_VALUE_INVALID,\r
+                                    "No such an FV in FDF file: %s" % fvname)\r
+\r
+        #\r
+        # Merge Arch\r
+        #\r
+        if self.ArchList == None or len(self.ArchList) == 0:\r
+            ArchList = set(self.Platform.SupArchList)\r
+        else:\r
+            ArchList = set(self.ArchList) & set(self.Platform.SupArchList)\r
+        if len(ArchList) == 0:\r
+            EdkLogger.error("build", PARAMETER_INVALID,\r
+                            ExtraData = "Active platform supports [%s] only, but [%s] is given."\r
+                                        % (" ".join(self.Platform.SupArchList), " ".join(self.ArchList)))\r
+        elif len(ArchList) != len(self.ArchList):\r
+            SkippedArchList = set(self.ArchList).symmetric_difference(set(self.Platform.SupArchList))\r
+            EdkLogger.verbose("\nArch [%s] is ignored because active platform supports [%s] but [%s] is specified !"\r
+                           % (" ".join(SkippedArchList), " ".join(self.Platform.SupArchList), " ".join(self.ArchList)))\r
+        self.ArchList = tuple(ArchList)\r
+\r
+        # Merge build target\r
+        if self.BuildTargetList == None or len(self.BuildTargetList) == 0:\r
+            BuildTargetList = self.Platform.BuildTargets\r
+        else:\r
+            BuildTargetList = list(set(self.BuildTargetList) & set(self.Platform.BuildTargets))\r
+        if BuildTargetList == []:\r
+            EdkLogger.error("build", PARAMETER_INVALID, "Active platform only supports [%s], but [%s] is given"\r
+                                % (" ".join(self.Platform.BuildTargets), " ".join(self.BuildTargetList)))\r
+        self.BuildTargetList = BuildTargetList\r
+\r
+    ## Build a module or platform\r
+    #\r
+    # Create autogen code and makfile for a module or platform, and the launch\r
+    # "make" command to build it\r
+    #\r
+    #   @param  Target                      The target of build command\r
+    #   @param  Platform                    The platform file\r
+    #   @param  Module                      The module file\r
+    #   @param  BuildTarget                 The name of build target, one of "DEBUG", "RELEASE"\r
+    #   @param  ToolChain                   The name of toolchain to build\r
+    #   @param  Arch                        The arch of the module/platform\r
+    #   @param  CreateDepModuleCodeFile     Flag used to indicate creating code\r
+    #                                       for dependent modules/Libraries\r
+    #   @param  CreateDepModuleMakeFile     Flag used to indicate creating makefile\r
+    #                                       for dependent modules/Libraries\r
+    #\r
+    def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True):\r
+        if AutoGenObject == None:\r
+            return False\r
+\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)\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
+            AutoGenObject.CreateCodeFile(False)\r
+            AutoGenObject.CreateMakeFile(False)\r
+\r
+        if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
+            EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
+\r
+        BuildCommand = AutoGenObject.BuildCommand\r
+        if BuildCommand == None or len(BuildCommand) == 0:\r
+            EdkLogger.error("build", OPTION_MISSING, ExtraData="No MAKE command found for [%s, %s, %s]" % Key)\r
+\r
+        BuildCommand = BuildCommand + [Target]\r
+        LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
+        if Target == 'cleanall':\r
+            try:\r
+                #os.rmdir(AutoGenObject.BuildDir)\r
+                RemoveDirectory(AutoGenObject.BuildDir, True)\r
+            except WindowsError, X:\r
+                EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
+        return True\r
+\r
+    ## Rebase module image and Get function address for the inpug module list.\r
+    #\r
+    def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):\r
+        if ModeIsSmm:\r
+            AddrIsOffset = False\r
+        InfFileNameList = ModuleList.keys()\r
+        #InfFileNameList.sort()\r
+        for InfFile in InfFileNameList:\r
+            sys.stdout.write (".")
+            sys.stdout.flush()
+            ModuleInfo = ModuleList[InfFile]\r
+            ModuleName = ModuleInfo.BaseName\r
+            ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
+            if not ModeIsSmm:\r
+                BaseAddress = BaseAddress - ModuleInfo.Image.Size\r
+                #\r
+                # Update Image to new BaseAddress by GenFw tool\r
+                #\r
+                LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleInfo.Image.FileName], ModuleInfo.OutpuDir)\r
+            else:\r
+                #\r
+                # Set new address to the section header only for SMM driver.\r
+                #\r
+                LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleInfo.Image.FileName], ModuleInfo.OutpuDir)\r
+            #\r
+            # Collect funtion address from Map file\r
+            #\r
+            ImageMapTable = ModuleInfo.Image.FileName.replace('.efi', '.map')\r
+            FunctionList = []\r
+            if os.path.exists(ImageMapTable):\r
+                OrigImageBaseAddress = 0\r
+                ImageMap = open (ImageMapTable, 'r')\r
+                for LinStr in ImageMap:\r
+                    if len (LinStr.strip()) == 0:\r
+                        continue\r
+                    #\r
+                    # Get the preferred address set on link time.\r
+                    #\r
+                    if LinStr.find ('Preferred load address is') != -1:\r
+                        StrList = LinStr.split()\r
+                        OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)\r
+\r
+                    StrList = LinStr.split()\r
+                    if len (StrList) > 4:\r
+                        if StrList[3] == 'f' or StrList[3] =='F':\r
+                            Name = StrList[1]\r
+                            RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress\r
+                            FunctionList.append ((Name, RelativeAddress))\r
+                            if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'):\r
+                                #\r
+                                # Get the real entry point address for IPF image.\r
+                                #\r
+                                ModuleInfo.Image.EntryPoint = RelativeAddress\r
+                ImageMap.close()\r
+            #\r
+            # Add general information.\r
+            #\r
+            if ModeIsSmm:\r
+                MapBuffer.write('\n\n%s (Fixed SMRAM Offset,   BaseAddress=0x%010X,  EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
+            elif AddrIsOffset:\r
+                MapBuffer.write('\n\n%s (Fixed Memory Offset,  BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))\r
+            else:\r
+                MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X,  EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
+            #\r
+            # Add guid and general seciton section.\r
+            #\r
+            TextSectionAddress = 0\r
+            DataSectionAddress = 0\r
+            for SectionHeader in ModuleInfo.Image.SectionHeaderList:\r
+                if SectionHeader[0] == '.text':\r
+                    TextSectionAddress = SectionHeader[1]\r
+                elif SectionHeader[0] in ['.data', '.sdata']:\r
+                    DataSectionAddress = SectionHeader[1]\r
+            if AddrIsOffset:\r
+                MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress))) \r
+            else:\r
+                MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress)) \r
+            #\r
+            # Add funtion address\r
+            #\r
+            for Function in FunctionList:\r
+                if AddrIsOffset:\r
+                    MapBuffer.write('  -0x%010X    %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))\r
+                else:\r
+                    MapBuffer.write('  0x%010X    %s\n' % (BaseAddress + Function[1], Function[0]))\r
+            ImageMap.close()\r
+\r
+            #\r
+            # for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
+            #\r
+            if ModeIsSmm:\r
+                BaseAddress = BaseAddress + ModuleInfo.Image.Size\r
+\r
+    ## Collect MAP information of all FVs\r
+    #\r
+    def _CollectFvMapBuffer (self, MapBuffer, Wa):\r
+        if self.Fdf != '':\r
+            # First get the XIP base address for FV map file.\r
+            for FvName in Wa.FdfProfile.FvDict.keys():\r
+                FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')\r
+                if not os.path.exists(FvMapBuffer):\r
+                    continue\r
+                FvMap = open (FvMapBuffer, 'r')\r
+                #skip FV size information\r
+                FvMap.readline()\r
+                FvMap.readline()\r
+                FvMap.readline()\r
+                FvMap.readline()\r
+                MapBuffer.write(FvMap.read())\r
+                FvMap.close()\r
+\r
+    ## Collect MAP information of all modules\r
+    #\r
+    def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):\r
+        sys.stdout.write ("Generate Load Module At Fix Address Map")
+        sys.stdout.flush()
+        PatchEfiImageList = []\r
+        PeiModuleList  = {}\r
+        BtModuleList   = {}\r
+        RtModuleList   = {}\r
+        SmmModuleList  = {}\r
+        PeiSize = 0\r
+        BtSize  = 0\r
+        RtSize  = 0\r
+        # reserve 4K size in SMRAM to make SMM module address not from 0.\r
+        SmmSize = 0x1000\r
+        IsIpfPlatform = False\r
+        if 'IPF' in self.ArchList:\r
+            IsIpfPlatform = True\r
+        for Module in ModuleList:\r
+            GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)\r
+            \r
+            OutputImageFile = ''\r
+            for ResultFile in Module.CodaTargetList:\r
+                if str(ResultFile.Target).endswith('.efi'):\r
+                    #\r
+                    # module list for PEI, DXE, RUNTIME and SMM\r
+                    #\r
+                    OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')\r
+                    ImageClass = PeImageClass (OutputImageFile)\r
+                    if not ImageClass.IsValid:\r
+                        EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)\r
+                    ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, ImageClass)\r
+                    if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER','PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']:\r
+                        PeiModuleList[Module.MetaFile] = ImageInfo\r
+                        PeiSize += ImageInfo.Image.Size\r
+                    elif Module.ModuleType in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']:\r
+                        BtModuleList[Module.MetaFile] = ImageInfo\r
+                        BtSize += ImageInfo.Image.Size\r
+                    elif Module.ModuleType in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']:\r
+                        RtModuleList[Module.MetaFile] = ImageInfo\r
+                        #IPF runtime driver needs to be at 2 page alignment.\r
+                        if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0:\r
+                            ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000\r
+                        RtSize += ImageInfo.Image.Size\r
+                    elif Module.ModuleType in ['SMM_CORE', 'DXE_SMM_DRIVER']:\r
+                        SmmModuleList[Module.MetaFile] = ImageInfo\r
+                        SmmSize += ImageInfo.Image.Size\r
+                        if Module.ModuleType == 'DXE_SMM_DRIVER':\r
+                            PiSpecVersion = 0
+                            if 'PI_SPECIFICATION_VERSION' in Module.Module.Specification:
+                                PiSpecVersion = Module.Module.Specification['PI_SPECIFICATION_VERSION']
+                            # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.\r
+                            if PiSpecVersion < 0x0001000A:\r
+                                BtModuleList[Module.MetaFile] = ImageInfo\r
+                                BtSize += ImageInfo.Image.Size\r
+                    break\r
+            #\r
+            # EFI image is final target.\r
+            # Check EFI image contains patchable FixAddress related PCDs.\r
+            #\r
+            if OutputImageFile != '':\r
+                ModuleIsPatch = False\r
+                for Pcd in Module.ModulePcdList:\r
+                    if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:\r
+                        ModuleIsPatch = True\r
+                        break\r
+                if not ModuleIsPatch:\r
+                    for Pcd in Module.LibraryPcdList:\r
+                        if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:\r
+                            ModuleIsPatch = True\r
+                            break\r
+                \r
+                if not ModuleIsPatch:\r
+                    continue\r
+                #\r
+                # Module includes the patchable load fix address PCDs.\r
+                # It will be fixed up later. \r
+                #\r
+                PatchEfiImageList.append (OutputImageFile)\r
+        \r
+        #\r
+        # Get Top Memory address\r
+        #\r
+        ReservedRuntimeMemorySize = 0\r
+        TopMemoryAddress = 0\r
+        if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:\r
+            TopMemoryAddress = 0\r
+        else:\r
+            TopMemoryAddress = self.LoadFixAddress\r
+            if TopMemoryAddress < RtSize + BtSize + PeiSize:\r
+                EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")\r
+            # Make IPF runtime driver at 2 page alignment.\r
+            if IsIpfPlatform:\r
+                ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000\r
+                RtSize = RtSize + ReservedRuntimeMemorySize\r
+\r
+        #\r
+        # Patch FixAddress related PCDs into EFI image\r
+        #\r
+        for EfiImage in PatchEfiImageList: \r
+            EfiImageMap = EfiImage.replace('.efi', '.map')\r
+            if not os.path.exists(EfiImageMap):\r
+                continue\r
+            #\r
+            # Get PCD offset in EFI image by GenPatchPcdTable function\r
+            #\r
+            PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage) 
+            #\r
+            # Patch real PCD value by PatchPcdValue tool\r
+            #\r
+            for PcdInfo in PcdTable:\r
+                ReturnValue = 0\r
+                if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:\r
+                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize/0x1000))\r
+                elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:\r
+                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize/0x1000))\r
+                elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:\r
+                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize/0x1000))\r
+                elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:\r
+                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize/0x1000))\r
+                if ReturnValue != 0:\r
+                    EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)\r
+        \r
+        MapBuffer.write('PEI_CODE_PAGE_NUMBER      = 0x%x\n' % (PeiSize/0x1000))\r
+        MapBuffer.write('BOOT_CODE_PAGE_NUMBER     = 0x%x\n' % (BtSize/0x1000))\r
+        MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER  = 0x%x\n' % (RtSize/0x1000))\r
+        if len (SmmModuleList) > 0:\r
+            MapBuffer.write('SMM_CODE_PAGE_NUMBER      = 0x%x\n' % (SmmSize/0x1000))\r
+        \r
+        PeiBaseAddr = TopMemoryAddress - RtSize - BtSize\r
+        BtBaseAddr  = TopMemoryAddress - RtSize\r
+        RtBaseAddr  = TopMemoryAddress - ReservedRuntimeMemorySize\r
+\r
+        self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)\r
+        self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)\r
+        self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)\r
+        self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset = False, ModeIsSmm = True)\r
+        MapBuffer.write('\n\n')\r
+        sys.stdout.write ("\n")
+        sys.stdout.flush()
+    \r
+    ## Save platform Map file\r
+    #\r
+    def _SaveMapFile (self, MapBuffer, Wa):\r
+        #\r
+        # Map file path is got.\r
+        #\r
+        MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')\r
+        #\r
+        # Save address map into MAP file.\r
+        #\r
+        SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)\r
+        MapBuffer.close()\r
+        sys.stdout.write ("\nLoad Module At Fix Address Map file saved to %s\n" %(MapFilePath))
+        sys.stdout.flush()
+\r
+    ## Build active platform for different build targets and different tool chains\r
+    #\r
+    def _BuildPlatform(self):\r
+        for BuildTarget in self.BuildTargetList:\r
+            for ToolChain in self.ToolChainList:\r
+                Wa = WorkspaceAutoGen(\r
+                        self.WorkspaceDir,\r
+                        self.Platform,\r
+                        BuildTarget,\r
+                        ToolChain,\r
+                        self.ArchList,\r
+                        self.BuildDatabase,\r
+                        self.TargetTxt,\r
+                        self.ToolDef,\r
+                        self.Fdf,\r
+                        self.FdList,\r
+                        self.FvList,\r
+                        self.SkuId\r
+                        )\r
+                self.BuildReport.AddPlatformReport(Wa)\r
+                self.Progress.Stop("done!")\r
+                self._Build(self.Target, Wa)\r
+                \r
+                # Create MAP file when Load Fix Address is enabled.\r
+                if self.Target in ["", "all", "fds"] and self.LoadFixAddress != 0:\r
+                    for Arch in self.ArchList:\r
+                        #\r
+                        # Check whether the set fix address is above 4G for 32bit image.\r
+                        #\r
+                        if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
+                            EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS can't be set to larger than or equal to 4G for the platorm with IA32 or ARM arch modules")\r
+                    #\r
+                    # Get Module List\r
+                    #\r
+                    ModuleList = []\r
+                    for Pa in Wa.AutoGenObjectList:\r
+                        for Ma in Pa.ModuleAutoGenList:\r
+                            if Ma == None:\r
+                                continue\r
+                            if not Ma.IsLibrary:\r
+                                ModuleList.append (Ma)\r
+\r
+                    MapBuffer = StringIO('')\r
+                    #\r
+                    # Rebase module to the preferred memory address before GenFds\r
+                    #\r
+                    self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
+                    if self.Fdf != '':\r
+                        #\r
+                        # create FDS again for the updated EFI image\r
+                        #\r
+                        self._Build("fds", Wa)\r
+                        #\r
+                        # Create MAP file for all platform FVs after GenFds.\r
+                        #\r
+                        self._CollectFvMapBuffer(MapBuffer, Wa)\r
+                    #\r
+                    # Save MAP buffer into MAP file.\r
+                    #\r
+                    self._SaveMapFile (MapBuffer, Wa)\r
+\r
+    ## Build active module for different build targets, different tool chains and different archs\r
+    #\r
+    def _BuildModule(self):\r
+        for BuildTarget in self.BuildTargetList:\r
+            for ToolChain in self.ToolChainList:\r
+                #\r
+                # module build needs platform build information, so get platform\r
+                # AutoGen first\r
+                #\r
+                Wa = WorkspaceAutoGen(\r
+                        self.WorkspaceDir,\r
+                        self.Platform,\r
+                        BuildTarget,\r
+                        ToolChain,\r
+                        self.ArchList,\r
+                        self.BuildDatabase,\r
+                        self.TargetTxt,\r
+                        self.ToolDef,\r
+                        self.Fdf,\r
+                        self.FdList,\r
+                        self.FvList,\r
+                        self.SkuId\r
+                        )\r
+                self.BuildReport.AddPlatformReport(Wa)\r
+                Wa.CreateMakeFile(False)\r
+                self.Progress.Stop("done!")\r
+                MaList = []\r
+                for Arch in self.ArchList:\r
+                    Ma = ModuleAutoGen(Wa, self.ModuleFile, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
+                    if Ma == None: continue\r
+                    MaList.append(Ma)\r
+                    self._Build(self.Target, Ma)\r
+                if MaList == []:\r
+                    EdkLogger.error(\r
+                                'build',\r
+                                BUILD_ERROR,\r
+                                "Module for [%s] is not a component of active platform."\\r
+                                " Please make sure that the ARCH and inf file path are"\\r
+                                " given in the same as in [%s]" %\\r
+                                    (', '.join(self.ArchList), self.Platform),\r
+                                ExtraData=self.ModuleFile\r
+                                )\r
+                # Create MAP file when Load Fix Address is enabled.\r
+                if self.LoadFixAddress != 0 and self.Target == "fds" and self.Fdf != '':\r
+                    for Arch in self.ArchList:\r
+                        #\r
+                        # Check whether the set fix address is above 4G for 32bit image.\r
+                        #\r
+                        if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
+                            EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS can't be set to larger than or equal to 4G for the platorm with IA32 or ARM arch modules")\r
+                    #\r
+                    # Get Module List\r
+                    #\r
+                    ModuleList = []\r
+                    for Pa in Wa.AutoGenObjectList:\r
+                        for Ma in Pa.ModuleAutoGenList:\r
+                            if Ma == None:\r
+                                continue\r
+                            if not Ma.IsLibrary:\r
+                                ModuleList.append (Ma)\r
+\r
+                    MapBuffer = StringIO('')\r
+                    #\r
+                    # Rebase module to the preferred memory address before GenFds\r
+                    #\r
+                    self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
+                    #\r
+                    # create FDS again for the updated EFI image\r
+                    #\r
+                    self._Build("fds", Wa)\r
+                    #\r
+                    # Create MAP file for all platform FVs after GenFds.\r
+                    #\r
+                    self._CollectFvMapBuffer(MapBuffer, Wa)\r
+                    #\r
+                    # Save MAP buffer into MAP file.\r
+                    #\r
+                    self._SaveMapFile (MapBuffer, Wa)\r
+\r
+    ## Build a platform in multi-thread mode\r
+    #\r
+    def _MultiThreadBuildPlatform(self):\r
+        for BuildTarget in self.BuildTargetList:\r
+            for ToolChain in self.ToolChainList:\r
+                Wa = WorkspaceAutoGen(\r
+                        self.WorkspaceDir,\r
+                        self.Platform,\r
+                        BuildTarget,\r
+                        ToolChain,\r
+                        self.ArchList,\r
+                        self.BuildDatabase,\r
+                        self.TargetTxt,\r
+                        self.ToolDef,\r
+                        self.Fdf,\r
+                        self.FdList,\r
+                        self.FvList,\r
+                        self.SkuId\r
+                        )\r
+                self.BuildReport.AddPlatformReport(Wa)\r
+                Wa.CreateMakeFile(False)\r
+\r
+                # multi-thread exit flag\r
+                ExitFlag = threading.Event()\r
+                ExitFlag.clear()\r
+                for Arch in self.ArchList:\r
+                    Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
+                    if Pa == None:\r
+                        continue\r
+                    for Module in Pa.Platform.Modules:\r
+                        # Get ModuleAutoGen object to generate C code file and makefile\r
+                        Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
+                        if Ma == None:\r
+                            continue\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
+                                Ma.CreateMakeFile(True)\r
+                            if self.Target == "genmake":\r
+                                continue\r
+                        self.Progress.Stop("done!")\r
+                        # Generate build task for the module\r
+                        Bt = BuildTask.New(ModuleMakeUnit(Ma, 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
+                            ExitFlag.set()\r
+                            BuildTask.WaitForComplete()\r
+                            Pa.CreateMakeFile(False)\r
+                            EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
+                        # Start task scheduler\r
+                        if not BuildTask.IsOnGoing():\r
+                            BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
+\r
+                    # in case there's an interruption. we need a full version of makefile for platform\r
+                    Pa.CreateMakeFile(False)\r
+                    if BuildTask.HasError():\r
+                        EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
+\r
+                #\r
+                # All modules have been put in build tasks queue. Tell task scheduler\r
+                # to exit if all tasks are completed\r
+                #\r
+                ExitFlag.set()\r
+                BuildTask.WaitForComplete()\r
+\r
+                #\r
+                # Check for build error, and raise exception if one\r
+                # has been signaled.\r
+                #\r
+                if BuildTask.HasError():\r
+                    EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
+\r
+                # Create MAP file when Load Fix Address is enabled.\r
+                if self.Target in ["", "all", "fds"] and self.LoadFixAddress != 0:\r
+                    for Arch in self.ArchList:\r
+                        #\r
+                        # Check whether the set fix address is above 4G for 32bit image.\r
+                        #\r
+                        if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
+                            EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS can't be set to larger than or equal to 4G for the platorm with IA32 or ARM arch modules")\r
+                    #\r
+                    # Get Module List\r
+                    #\r
+                    ModuleList = []\r
+                    for Pa in Wa.AutoGenObjectList:\r
+                        for Ma in Pa.ModuleAutoGenList:\r
+                            if Ma == None:\r
+                                continue\r
+                            if not Ma.IsLibrary:\r
+                                ModuleList.append (Ma)\r
+                    #\r
+                    # Rebase module to the preferred memory address before GenFds\r
+                    #\r
+                    MapBuffer = StringIO('')\r
+                    self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
+\r
+                # Generate FD image if there's a FDF file found\r
+                if self.Fdf != '' and self.Target in ["", "all", "fds"]:\r
+                    LaunchCommand(Wa.BuildCommand + ["fds"], Wa.MakeFileDir)\r
+\r
+                # Create MAP file for all platform FV after GenFds\r
+                if self.Target in ["", "all", "fds"] and self.LoadFixAddress != 0:\r
+                    if self.Fdf != '':\r
+                        #\r
+                        # Create MAP file for all platform FVs after GenFds.\r
+                        #\r
+                        self._CollectFvMapBuffer(MapBuffer, Wa)\r
+                    #\r
+                    # Save MAP buffer into MAP file.\r
+                    #\r
+                    self._SaveMapFile(MapBuffer, Wa)\r
+\r
+    ## Generate GuidedSectionTools.txt in the FV directories.\r
+    #\r
+    def CreateGuidedSectionToolsFile(self):\r
+        for Arch in self.ArchList:\r
+            for BuildTarget in self.BuildTargetList:\r
+                for ToolChain in self.ToolChainList:\r
+                    FvDir = os.path.join(\r
+                                self.WorkspaceDir,\r
+                                self.Platform.OutputDirectory,\r
+                                '_'.join((BuildTarget, ToolChain)),\r
+                                'FV'\r
+                                )\r
+                    if not os.path.exists(FvDir):\r
+                        continue\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
+                    guidAttribs = []\r
+                    for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():\r
+                        if attrib.upper().endswith('_GUID'):\r
+                            split = attrib.split('_')\r
+                            thisPrefix = '_'.join(split[0:3]) + '_'\r
+                            if thisPrefix == prefix:\r
+                                guid = self.ToolDef.ToolsDefTxtDictionary[attrib]\r
+                                guid = guid.lower()\r
+                                toolName = split[3]\r
+                                path = '_'.join(split[0:4]) + '_PATH'\r
+                                path = self.ToolDef.ToolsDefTxtDictionary[path]\r
+                                path = self.GetFullPathOfTool(path)\r
+                                guidAttribs.append((guid, toolName, path))\r
+\r
+                    # Write out GuidedSecTools.txt\r
+                    toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')\r
+                    toolsFile = open(toolsFile, 'wt')\r
+                    for guidedSectionTool in guidAttribs:\r
+                        print >> toolsFile, ' '.join(guidedSectionTool)\r
+                    toolsFile.close()\r
+\r
+    ## Returns the full path of the tool.\r
+    #\r
+    def GetFullPathOfTool (self, tool):\r
+        if os.path.exists(tool):\r
+            return os.path.realpath(tool)\r
+        else:\r
+            # We need to search for the tool using the\r
+            # PATH environment variable.\r
+            for dirInPath in os.environ['PATH'].split(os.pathsep):\r
+                foundPath = os.path.join(dirInPath, tool)\r
+                if os.path.exists(foundPath):\r
+                    return os.path.realpath(foundPath)\r
+\r
+        # If the tool was not found in the path then we just return\r
+        # the input tool.\r
+        return tool\r
+\r
+    ## Launch the module or platform build\r
+    #\r
+    def Launch(self):\r
+        if self.ModuleFile == None or self.ModuleFile == "":\r
+            if not self.SpawnMode or self.Target not in ["", "all"]:\r
+                self.SpawnMode = False\r
+                self._BuildPlatform()\r
+            else:\r
+                self._MultiThreadBuildPlatform()\r
+            self.CreateGuidedSectionToolsFile()\r
+        else:\r
+            self.SpawnMode = False\r
+            self._BuildModule()\r
+\r
+    ## Do some clean-up works when error occurred\r
+    def Relinquish(self):\r
+        OldLogLevel = EdkLogger.GetLevel()\r
+        EdkLogger.SetLevel(EdkLogger.ERROR)\r
+        #self.DumpBuildData()\r
+        Utils.Progressor.Abort()\r
+        if self.SpawnMode == True:\r
+            BuildTask.Abort()\r
+        EdkLogger.SetLevel(OldLogLevel)\r
+\r
+    def DumpBuildData(self):\r
+        CacheDirectory = os.path.join(self.WorkspaceDir, gBuildCacheDir)\r
+        Utils.CreateDirectory(CacheDirectory)\r
+        Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))\r
+        Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))\r
+\r
+    def RestoreBuildData(self):\r
+        FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gFileTimeStampCache")\r
+        if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):\r
+            Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)\r
+            if Utils.gFileTimeStampCache == None:\r
+                Utils.gFileTimeStampCache = {}\r
+\r
+        FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gDependencyDatabase")\r
+        if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):\r
+            Utils.gDependencyDatabase = Utils.DataRestore(FilePath)\r
+            if Utils.gDependencyDatabase == None:\r
+                Utils.gDependencyDatabase = {}\r
+\r
+def ParseDefines(DefineList=[]):\r
+    DefineDict = {}\r
+    if DefineList != None:\r
+        for Define in DefineList:\r
+            DefineTokenList = Define.split("=", 1)\r
+            if len(DefineTokenList) == 1:\r
+                DefineDict[DefineTokenList[0]] = ""\r
+            else:\r
+                DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()\r
+    return DefineDict\r
+\r
+gParamCheck = []\r
+def SingleCheckCallback(option, opt_str, value, parser):\r
+    if option not in gParamCheck:\r
+        setattr(parser.values, option.dest, value)\r
+        gParamCheck.append(option)\r
+    else:\r
+        parser.error("Option %s only allows one instance in command line!" % option)\r
+\r
+## Parse command line options\r
+#\r
+# Using standard Python module optparse to parse command line option of this tool.\r
+#\r
+#   @retval Opt   A optparse.Values object containing the parsed options\r
+#   @retval Args  Target of build command\r
+#\r
+def MyOptionParser():\r
+    Parser = OptionParser(description=__copyright__,version=__version__,prog="build.exe",usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")\r
+    Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32','X64','IPF','EBC','ARM'], dest="TargetArch",\r
+        help="ARCHS is one of list: IA32, X64, IPF, ARM or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.")\r
+    Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,\r
+        help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")\r
+    Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,\r
+        help="Build the module specified by the INF file name argument.")\r
+    Parser.add_option("-b", "--buildtarget", action="append", type="choice", choices=['DEBUG','RELEASE'], dest="BuildTarget",\r
+        help="BuildTarget is one of list: DEBUG, RELEASE, which overrides target.txt's TARGET definition. To specify more TARGET, please repeat this option.")\r
+    Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",\r
+        help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")\r
+    Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,\r
+        help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")\r
+\r
+    Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,\r
+        help="Build the platform using multi-threaded compiler. The value overrides target.txt's MAX_CONCURRENT_THREAD_NUMBER. Less than 2 will disable multi-thread builds.")\r
+\r
+    Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,\r
+        help="The name of the FDF file to use, which overrides the setting in the DSC file.")\r
+    Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],\r
+        help="The name of FD to be generated. The name must be from [FD] section in FDF file.")\r
+    Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],\r
+        help="The name of FV to be generated. The name must be from [FV] section in FDF file.")\r
+\r
+    Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")\r
+    Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")\r
+\r
+    Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", help="Don't check case of file name.")\r
+\r
+    # Parser.add_option("-D", "--define", action="append", dest="Defines", metavar="NAME[=[VALUE]]",\r
+    #     help="Define global macro which can be used in DSC/DEC/INF files.")\r
+\r
+    Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")\r
+    Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")\r
+\r
+    Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",\r
+        help="Make use of silent mode of (n)make.")\r
+    Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
+    Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\\r
+                                                                               "including library instances selected, final dependency expression, "\\r
+                                                                               "and warning messages, etc.")\r
+    Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
+    Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
+\r
+    Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")\r
+    Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD','LIBRARY','FLASH','DEPEX','BUILD_FLAGS','FIXED_ADDRESS', 'EXECUTION_ORDER'], dest="ReportType", default=[],\r
+        help="Flags that control the type of build report to generate.  Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, EXECUTION_ORDER].  "\\r
+             "To specify more than one flag, repeat this option on the command line and the default flag set is [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS]")\r
+\r
+    (Opt, Args)=Parser.parse_args()\r
+    return (Opt, Args)\r
+\r
+## Tool entrance method\r
+#\r
+# This method mainly dispatch specific methods per the command line options.\r
+# If no error found, return zero value so the caller of this tool can know\r
+# if it's executed successfully or not.\r
+#\r
+#   @retval 0     Tool was successful\r
+#   @retval 1     Tool failed\r
+#\r
+def Main():\r
+    StartTime = time.time()\r
+\r
+    # Initialize log system\r
+    EdkLogger.Initialize()\r
+\r
+    #\r
+    # Parse the options and args\r
+    #\r
+    (Option, Target) = MyOptionParser()\r
+    GlobalData.gOptions = Option\r
+    GlobalData.gCaseInsensitive = Option.CaseInsensitive\r
+\r
+    # Set log level\r
+    if Option.verbose != None:\r
+        EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
+    elif Option.quiet != None:\r
+        EdkLogger.SetLevel(EdkLogger.QUIET)\r
+    elif Option.debug != None:\r
+        EdkLogger.SetLevel(Option.debug + 1)\r
+    else:\r
+        EdkLogger.SetLevel(EdkLogger.INFO)\r
+\r
+    if Option.LogFile != None:\r
+        EdkLogger.SetLogFile(Option.LogFile)\r
+\r
+    if Option.WarningAsError == True:\r
+        EdkLogger.SetWarningAsError()\r
+\r
+    if platform.platform().find("Windows") >= 0:\r
+        GlobalData.gIsWindows = True\r
+    else:\r
+        GlobalData.gIsWindows = False\r
+\r
+    EdkLogger.quiet(time.strftime("%H:%M:%S, %b.%d %Y ", time.localtime()) + "[%s]\n" % platform.platform())\r
+    ReturnCode = 0\r
+    MyBuild = None\r
+    try:\r
+        if len(Target) == 0:\r
+            Target = "all"\r
+        elif len(Target) >= 2:\r
+            EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",\r
+                            ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))\r
+        else:\r
+            Target = Target[0].lower()\r
+\r
+        if Target not in gSupportedTarget:\r
+            EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,\r
+                            ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))\r
+\r
+        GlobalData.gGlobalDefines = ParseDefines(Option.Macros)\r
+        #\r
+        # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH\r
+        #\r
+        CheckEnvVariable()\r
+        Workspace = os.getenv("WORKSPACE")\r
+        #\r
+        # Get files real name in workspace dir\r
+        #\r
+        GlobalData.gAllFiles = Utils.DirCache(Workspace)\r
+\r
+        WorkingDirectory = os.getcwd()\r
+        if not Option.ModuleFile:\r
+            FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))\r
+            FileNum = len(FileList)\r
+            if FileNum >= 2:\r
+                EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),\r
+                                ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")\r
+            elif FileNum == 1:\r
+                Option.ModuleFile = NormFile(FileList[0], Workspace)\r
+\r
+        if Option.ModuleFile:\r
+            if os.path.isabs (Option.ModuleFile):\r
+                if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:\r
+                    Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)\r
+            Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)\r
+            ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)\r
+            if ErrorCode != 0:\r
+                EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
+\r
+        if Option.PlatformFile != None:\r
+            if os.path.isabs (Option.PlatformFile):\r
+                if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:\r
+                    Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)\r
+            Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)\r
+            ErrorCode, ErrorInfo = Option.PlatformFile.Validate(".dsc", False)\r
+            if ErrorCode != 0:\r
+                EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
+\r
+        if Option.FdfFile != None:\r
+            if os.path.isabs (Option.FdfFile):\r
+                if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:\r
+                    Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)\r
+            Option.FdfFile = PathClass(Option.FdfFile, Workspace)\r
+            ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)\r
+            if ErrorCode != 0:\r
+                EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
+\r
+        MyBuild = Build(Target, Workspace, Option.PlatformFile, Option.ModuleFile,\r
+                        Option.TargetArch, Option.ToolChain, Option.BuildTarget,\r
+                        Option.FdfFile, Option.RomImage, Option.FvImage,\r
+                        None, Option.SilentMode, Option.ThreadNumber,\r
+                        Option.SkipAutoGen, Option.Reparse, Option.SkuId, \r
+                        Option.ReportFile, Option.ReportType)\r
+        MyBuild.Launch()\r
+        #MyBuild.DumpBuildData()\r
+    except FatalError, X:\r
+        if MyBuild != None:\r
+            # for multi-thread build exits safely\r
+            MyBuild.Relinquish()\r
+        if Option != None and Option.debug != None:\r
+            EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
+        ReturnCode = X.args[0]\r
+    except Warning, X:\r
+        # error from Fdf parser\r
+        if MyBuild != None:\r
+            # for multi-thread build exits safely\r
+            MyBuild.Relinquish()\r
+        if Option != None and Option.debug != None:\r
+            EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
+        else:\r
+            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
+        ReturnCode = ABORT_ERROR\r
+        if Option != None and Option.debug != None:\r
+            EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
+    except:\r
+        if MyBuild != None:\r
+            # for multi-thread build exits safely\r
+            MyBuild.Relinquish()\r
+\r
+        # try to get the meta-file from the object causing exception\r
+        Tb = sys.exc_info()[-1]\r
+        MetaFile = GlobalData.gProcessingFile\r
+        while Tb != None:\r
+            if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):\r
+                MetaFile = Tb.tb_frame.f_locals['self'].MetaFile\r
+            Tb = Tb.tb_next\r
+        EdkLogger.error(\r
+                    "\nbuild",\r
+                    CODE_ERROR,\r
+                    "Unknown fatal error when processing [%s]" % MetaFile,\r
+                    ExtraData="\n(Please send email to edk2-buildtools-devel@lists.sourceforge.net for help, attaching following call stack trace!)\n",\r
+                    RaiseError=False\r
+                    )\r
+        EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
+        ReturnCode = CODE_ERROR\r
+    finally:\r
+        Utils.Progressor.Abort()\r
+\r
+    if ReturnCode == 0:\r
+        Conclusion = "Done"\r
+    elif ReturnCode == ABORT_ERROR:\r
+        Conclusion = "Aborted"\r
+    else:\r
+        Conclusion = "Failed"\r
+    FinishTime = time.time()\r
+    BuildDuration = time.strftime("%M:%S", time.gmtime(int(round(FinishTime - StartTime))))\r
+    if MyBuild != None:\r
+        MyBuild.BuildReport.GenerateReport(BuildDuration)\r
+        MyBuild.Db.Close()\r
+    EdkLogger.SetLevel(EdkLogger.QUIET)\r
+    EdkLogger.quiet("\n- %s -\n%s [%s]" % (Conclusion, time.strftime("%H:%M:%S, %b.%d %Y", time.localtime()), BuildDuration))\r
+\r
+    return ReturnCode\r
+\r
+if __name__ == '__main__':\r
+    r = Main()\r
+    ## 0-127 is a safe return range, and 1 is a standard default error\r
+    if r < 0 or r > 127: r = 1\r
+    sys.exit(r)\r
+\r