Home | History | Annotate | Download | only in build
      1 ## @file

      2 # build a platform or a module

      3 #

      4 #  Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>

      5 #  Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>

      6 #

      7 #  This program and the accompanying materials

      8 #  are licensed and made available under the terms and conditions of the BSD License

      9 #  which accompanies this distribution.  The full text of the license may be found at

     10 #  http://opensource.org/licenses/bsd-license.php

     11 #

     12 #  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

     13 #  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

     14 #

     15 
     16 ##

     17 # Import Modules

     18 #

     19 import Common.LongFilePathOs as os
     20 import re
     21 import StringIO
     22 import sys
     23 import glob
     24 import time
     25 import platform
     26 import traceback
     27 import encodings.ascii
     28 import itertools
     29 
     30 from struct import *
     31 from threading import *
     32 from optparse import OptionParser
     33 from subprocess import *
     34 from Common import Misc as Utils
     35 
     36 from Common.LongFilePathSupport import OpenLongFilePath as open
     37 from Common.LongFilePathSupport import LongFilePath
     38 from Common.TargetTxtClassObject import *
     39 from Common.ToolDefClassObject import *
     40 from Common.DataType import *
     41 from Common.BuildVersion import gBUILD_VERSION
     42 from AutoGen.AutoGen import *
     43 from Common.BuildToolError import *
     44 from Workspace.WorkspaceDatabase import *
     45 from Common.MultipleWorkspace import MultipleWorkspace as mws
     46 
     47 from BuildReport import BuildReport
     48 from GenPatchPcdTable.GenPatchPcdTable import *
     49 from PatchPcdValue.PatchPcdValue import *
     50 
     51 import Common.EdkLogger
     52 import Common.GlobalData as GlobalData
     53 
     54 # Version and Copyright

     55 VersionNumber = "0.60" + ' ' + gBUILD_VERSION
     56 __version__ = "%prog Version " + VersionNumber
     57 __copyright__ = "Copyright (c) 2007 - 2016, Intel Corporation  All rights reserved."
     58 
     59 ## standard targets of build command

     60 gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
     61 
     62 ## build configuration file

     63 gBuildConfiguration = "target.txt"
     64 gToolsDefinition = "tools_def.txt"
     65 
     66 TemporaryTablePattern = re.compile(r'^_\d+_\d+_[a-fA-F0-9]+$')
     67 TmpTableDict = {}
     68 
     69 ## Check environment PATH variable to make sure the specified tool is found

     70 #

     71 #   If the tool is found in the PATH, then True is returned

     72 #   Otherwise, False is returned

     73 #

     74 def IsToolInPath(tool):
     75     if os.environ.has_key('PATHEXT'):
     76         extns = os.environ['PATHEXT'].split(os.path.pathsep)
     77     else:
     78         extns = ('',)
     79     for pathDir in os.environ['PATH'].split(os.path.pathsep):
     80         for ext in extns:
     81             if os.path.exists(os.path.join(pathDir, tool + ext)):
     82                 return True
     83     return False
     84 
     85 ## Check environment variables

     86 #

     87 #  Check environment variables that must be set for build. Currently they are

     88 #

     89 #   WORKSPACE           The directory all packages/platforms start from

     90 #   EDK_TOOLS_PATH      The directory contains all tools needed by the build

     91 #   PATH                $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH

     92 #

     93 #   If any of above environment variable is not set or has error, the build

     94 #   will be broken.

     95 #

     96 def CheckEnvVariable():
     97     # check WORKSPACE

     98     if "WORKSPACE" not in os.environ:
     99         EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
    100                         ExtraData="WORKSPACE")
    101 
    102     WorkspaceDir = os.path.normcase(os.path.normpath(os.environ["WORKSPACE"]))
    103     if not os.path.exists(WorkspaceDir):
    104         EdkLogger.error("build", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData="%s" % WorkspaceDir)
    105     elif ' ' in WorkspaceDir:
    106         EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path",
    107                         ExtraData=WorkspaceDir)
    108     os.environ["WORKSPACE"] = WorkspaceDir
    109     
    110     # set multiple workspace

    111     PackagesPath = os.getenv("PACKAGES_PATH")
    112     mws.setWs(WorkspaceDir, PackagesPath)
    113     if mws.PACKAGES_PATH:
    114         for Path in mws.PACKAGES_PATH:
    115             if not os.path.exists(Path):
    116                 EdkLogger.error("build", FILE_NOT_FOUND, "One Path in PACKAGES_PATH doesn't exist", ExtraData="%s" % Path)
    117             elif ' ' in Path:
    118                 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in PACKAGES_PATH", ExtraData=Path)
    119 
    120     #

    121     # Check EFI_SOURCE (Edk build convention). EDK_SOURCE will always point to ECP

    122     #

    123     if "ECP_SOURCE" not in os.environ:
    124         os.environ["ECP_SOURCE"] = mws.join(WorkspaceDir, GlobalData.gEdkCompatibilityPkg)
    125     if "EFI_SOURCE" not in os.environ:
    126         os.environ["EFI_SOURCE"] = os.environ["ECP_SOURCE"]
    127     if "EDK_SOURCE" not in os.environ:
    128         os.environ["EDK_SOURCE"] = os.environ["ECP_SOURCE"]
    129 
    130     #

    131     # Unify case of characters on case-insensitive systems

    132     #

    133     EfiSourceDir = os.path.normcase(os.path.normpath(os.environ["EFI_SOURCE"]))
    134     EdkSourceDir = os.path.normcase(os.path.normpath(os.environ["EDK_SOURCE"]))
    135     EcpSourceDir = os.path.normcase(os.path.normpath(os.environ["ECP_SOURCE"]))
    136 
    137     os.environ["EFI_SOURCE"] = EfiSourceDir
    138     os.environ["EDK_SOURCE"] = EdkSourceDir
    139     os.environ["ECP_SOURCE"] = EcpSourceDir
    140     os.environ["EDK_TOOLS_PATH"] = os.path.normcase(os.environ["EDK_TOOLS_PATH"])
    141 
    142     if not os.path.exists(EcpSourceDir):
    143         EdkLogger.verbose("ECP_SOURCE = %s doesn't exist. Edk modules could not be built." % EcpSourceDir)
    144     elif ' ' in EcpSourceDir:
    145         EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in ECP_SOURCE path",
    146                         ExtraData=EcpSourceDir)
    147     if not os.path.exists(EdkSourceDir):
    148         if EdkSourceDir == EcpSourceDir:
    149             EdkLogger.verbose("EDK_SOURCE = %s doesn't exist. Edk modules could not be built." % EdkSourceDir)
    150         else:
    151             EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE does not exist",
    152                             ExtraData=EdkSourceDir)
    153     elif ' ' in EdkSourceDir:
    154         EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EDK_SOURCE path",
    155                         ExtraData=EdkSourceDir)
    156     if not os.path.exists(EfiSourceDir):
    157         if EfiSourceDir == EcpSourceDir:
    158             EdkLogger.verbose("EFI_SOURCE = %s doesn't exist. Edk modules could not be built." % EfiSourceDir)
    159         else:
    160             EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE does not exist",
    161                             ExtraData=EfiSourceDir)
    162     elif ' ' in EfiSourceDir:
    163         EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EFI_SOURCE path",
    164                         ExtraData=EfiSourceDir)
    165 
    166     # check those variables on single workspace case

    167     if not PackagesPath:
    168         # change absolute path to relative path to WORKSPACE

    169         if EfiSourceDir.upper().find(WorkspaceDir.upper()) != 0:
    170             EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE is not under WORKSPACE",
    171                             ExtraData="WORKSPACE = %s\n    EFI_SOURCE = %s" % (WorkspaceDir, EfiSourceDir))
    172         if EdkSourceDir.upper().find(WorkspaceDir.upper()) != 0:
    173             EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE is not under WORKSPACE",
    174                             ExtraData="WORKSPACE = %s\n    EDK_SOURCE = %s" % (WorkspaceDir, EdkSourceDir))
    175         if EcpSourceDir.upper().find(WorkspaceDir.upper()) != 0:
    176             EdkLogger.error("build", PARAMETER_INVALID, "ECP_SOURCE is not under WORKSPACE",
    177                             ExtraData="WORKSPACE = %s\n    ECP_SOURCE = %s" % (WorkspaceDir, EcpSourceDir))
    178 
    179     # check EDK_TOOLS_PATH

    180     if "EDK_TOOLS_PATH" not in os.environ:
    181         EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
    182                         ExtraData="EDK_TOOLS_PATH")
    183 
    184     # check PATH

    185     if "PATH" not in os.environ:
    186         EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
    187                         ExtraData="PATH")
    188 
    189     GlobalData.gWorkspace = WorkspaceDir
    190     GlobalData.gEfiSource = EfiSourceDir
    191     GlobalData.gEdkSource = EdkSourceDir
    192     GlobalData.gEcpSource = EcpSourceDir
    193 
    194     GlobalData.gGlobalDefines["WORKSPACE"]  = WorkspaceDir
    195     GlobalData.gGlobalDefines["EFI_SOURCE"] = EfiSourceDir
    196     GlobalData.gGlobalDefines["EDK_SOURCE"] = EdkSourceDir
    197     GlobalData.gGlobalDefines["ECP_SOURCE"] = EcpSourceDir
    198     GlobalData.gGlobalDefines["EDK_TOOLS_PATH"] = os.environ["EDK_TOOLS_PATH"]
    199     
    200 ## Get normalized file path

    201 #

    202 # Convert the path to be local format, and remove the WORKSPACE path at the

    203 # beginning if the file path is given in full path.

    204 #

    205 # @param  FilePath      File path to be normalized

    206 # @param  Workspace     Workspace path which the FilePath will be checked against

    207 #

    208 # @retval string        The normalized file path

    209 #

    210 def NormFile(FilePath, Workspace):
    211     # check if the path is absolute or relative

    212     if os.path.isabs(FilePath):
    213         FileFullPath = os.path.normpath(FilePath)
    214     else:
    215         FileFullPath = os.path.normpath(mws.join(Workspace, FilePath))
    216         Workspace = mws.getWs(Workspace, FilePath)
    217 
    218     # check if the file path exists or not

    219     if not os.path.isfile(FileFullPath):
    220         EdkLogger.error("build", FILE_NOT_FOUND, ExtraData="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath)
    221 
    222     # remove workspace directory from the beginning part of the file path

    223     if Workspace[-1] in ["\\", "/"]:
    224         return FileFullPath[len(Workspace):]
    225     else:
    226         return FileFullPath[(len(Workspace) + 1):]
    227 
    228 ## Get the output of an external program

    229 #

    230 # This is the entrance method of thread reading output of an external program and

    231 # putting them in STDOUT/STDERR of current program.

    232 #

    233 # @param  From      The stream message read from

    234 # @param  To        The stream message put on

    235 # @param  ExitFlag  The flag used to indicate stopping reading

    236 #

    237 def ReadMessage(From, To, ExitFlag):
    238     while True:
    239         # read one line a time

    240         Line = From.readline()
    241         # empty string means "end"

    242         if Line != None and Line != "":
    243             To(Line.rstrip())
    244         else:
    245             break
    246         if ExitFlag.isSet():
    247             break
    248 
    249 ## Launch an external program

    250 #

    251 # This method will call subprocess.Popen to execute an external program with

    252 # given options in specified directory. Because of the dead-lock issue during

    253 # redirecting output of the external program, threads are used to to do the

    254 # redirection work.

    255 #

    256 # @param  Command               A list or string containing the call of the program

    257 # @param  WorkingDir            The directory in which the program will be running

    258 #

    259 def LaunchCommand(Command, WorkingDir):
    260     # if working directory doesn't exist, Popen() will raise an exception

    261     if not os.path.isdir(WorkingDir):
    262         EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=WorkingDir)
    263     
    264     # Command is used as the first Argument in following Popen().

    265     # It could be a string or sequence. We find that if command is a string in following Popen(),

    266     # ubuntu may fail with an error message that the command is not found.

    267     # So here we may need convert command from string to list instance.

    268     if platform.system() != 'Windows':
    269         if not isinstance(Command, list):
    270             Command = Command.split()
    271         Command = ' '.join(Command)
    272 
    273     Proc = None
    274     EndOfProcedure = None
    275     try:
    276         # launch the command

    277         Proc = Popen(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir, bufsize=-1, shell=True)
    278 
    279         # launch two threads to read the STDOUT and STDERR

    280         EndOfProcedure = Event()
    281         EndOfProcedure.clear()
    282         if Proc.stdout:
    283             StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure))
    284             StdOutThread.setName("STDOUT-Redirector")
    285             StdOutThread.setDaemon(False)
    286             StdOutThread.start()
    287 
    288         if Proc.stderr:
    289             StdErrThread = Thread(target=ReadMessage, args=(Proc.stderr, EdkLogger.quiet, EndOfProcedure))
    290             StdErrThread.setName("STDERR-Redirector")
    291             StdErrThread.setDaemon(False)
    292             StdErrThread.start()
    293 
    294         # waiting for program exit

    295         Proc.wait()
    296     except: # in case of aborting

    297         # terminate the threads redirecting the program output

    298         EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
    299         if EndOfProcedure != None:
    300             EndOfProcedure.set()
    301         if Proc == None:
    302             if type(Command) != type(""):
    303                 Command = " ".join(Command)
    304             EdkLogger.error("build", COMMAND_FAILURE, "Failed to start command", ExtraData="%s [%s]" % (Command, WorkingDir))
    305 
    306     if Proc.stdout:
    307         StdOutThread.join()
    308     if Proc.stderr:
    309         StdErrThread.join()
    310 
    311     # check the return code of the program

    312     if Proc.returncode != 0:
    313         if type(Command) != type(""):
    314             Command = " ".join(Command)
    315         # print out the Response file and its content when make failure

    316         RespFile = os.path.join(WorkingDir, 'OUTPUT', 'respfilelist.txt')
    317         if os.path.isfile(RespFile):
    318             f = open(RespFile)
    319             RespContent = f.read()
    320             f.close()
    321             EdkLogger.info(RespContent)
    322 
    323         EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir))
    324 
    325 ## The smallest unit that can be built in multi-thread build mode

    326 #

    327 # This is the base class of build unit. The "Obj" parameter must provide

    328 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units

    329 # missing build.

    330 #

    331 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.

    332 #

    333 class BuildUnit:
    334     ## The constructor

    335     #

    336     #   @param  self        The object pointer

    337     #   @param  Obj         The object the build is working on

    338     #   @param  Target      The build target name, one of gSupportedTarget

    339     #   @param  Dependency  The BuildUnit(s) which must be completed in advance

    340     #   @param  WorkingDir  The directory build command starts in

    341     #

    342     def __init__(self, Obj, BuildCommand, Target, Dependency, WorkingDir="."):
    343         self.BuildObject = Obj
    344         self.Dependency = Dependency
    345         self.WorkingDir = WorkingDir
    346         self.Target = Target
    347         self.BuildCommand = BuildCommand
    348         if not BuildCommand:
    349             EdkLogger.error("build", OPTION_MISSING,
    350                             "No build command found for this module. "
    351                             "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
    352                                 (Obj.BuildTarget, Obj.ToolChain, Obj.Arch),
    353                             ExtraData=str(Obj))
    354 
    355 
    356     ## str() method

    357     #

    358     #   It just returns the string representation of self.BuildObject

    359     #

    360     #   @param  self        The object pointer

    361     #

    362     def __str__(self):
    363         return str(self.BuildObject)
    364 
    365     ## "==" operator method

    366     #

    367     #   It just compares self.BuildObject with "Other". So self.BuildObject must

    368     #   provide its own __eq__() method.

    369     #

    370     #   @param  self        The object pointer

    371     #   @param  Other       The other BuildUnit object compared to

    372     #

    373     def __eq__(self, Other):
    374         return Other != None and self.BuildObject == Other.BuildObject \
    375                 and self.BuildObject.Arch == Other.BuildObject.Arch
    376 
    377     ## hash() method

    378     #

    379     #   It just returns the hash value of self.BuildObject which must be hashable.

    380     #

    381     #   @param  self        The object pointer

    382     #

    383     def __hash__(self):
    384         return hash(self.BuildObject) + hash(self.BuildObject.Arch)
    385 
    386     def __repr__(self):
    387         return repr(self.BuildObject)
    388 
    389 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode

    390 #

    391 # This class is for module build by nmake/make build system. The "Obj" parameter

    392 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could

    393 # be make units missing build.

    394 #

    395 # Currently the "Obj" should be only ModuleAutoGen object.

    396 #

    397 class ModuleMakeUnit(BuildUnit):
    398     ## The constructor

    399     #

    400     #   @param  self        The object pointer

    401     #   @param  Obj         The ModuleAutoGen object the build is working on

    402     #   @param  Target      The build target name, one of gSupportedTarget

    403     #

    404     def __init__(self, Obj, Target):
    405         Dependency = [ModuleMakeUnit(La, Target) for La in Obj.LibraryAutoGenList]
    406         BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)
    407         if Target in [None, "", "all"]:
    408             self.Target = "tbuild"
    409 
    410 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode

    411 #

    412 # This class is for platform build by nmake/make build system. The "Obj" parameter

    413 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could

    414 # be make units missing build.

    415 #

    416 # Currently the "Obj" should be only PlatformAutoGen object.

    417 #

    418 class PlatformMakeUnit(BuildUnit):
    419     ## The constructor

    420     #

    421     #   @param  self        The object pointer

    422     #   @param  Obj         The PlatformAutoGen object the build is working on

    423     #   @param  Target      The build target name, one of gSupportedTarget

    424     #

    425     def __init__(self, Obj, Target):
    426         Dependency = [ModuleMakeUnit(Lib, Target) for Lib in self.BuildObject.LibraryAutoGenList]
    427         Dependency.extend([ModuleMakeUnit(Mod, Target) for Mod in self.BuildObject.ModuleAutoGenList])
    428         BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)
    429 
    430 ## The class representing the task of a module build or platform build

    431 #

    432 # This class manages the build tasks in multi-thread build mode. Its jobs include

    433 # scheduling thread running, catching thread error, monitor the thread status, etc.

    434 #

    435 class BuildTask:
    436     # queue for tasks waiting for schedule

    437     _PendingQueue = sdict()
    438     _PendingQueueLock = threading.Lock()
    439 
    440     # queue for tasks ready for running

    441     _ReadyQueue = sdict()
    442     _ReadyQueueLock = threading.Lock()
    443 
    444     # queue for run tasks

    445     _RunningQueue = sdict()
    446     _RunningQueueLock = threading.Lock()
    447 
    448     # queue containing all build tasks, in case duplicate build

    449     _TaskQueue = sdict()
    450 
    451     # flag indicating error occurs in a running thread

    452     _ErrorFlag = threading.Event()
    453     _ErrorFlag.clear()
    454     _ErrorMessage = ""
    455 
    456     # BoundedSemaphore object used to control the number of running threads

    457     _Thread = None
    458 
    459     # flag indicating if the scheduler is started or not

    460     _SchedulerStopped = threading.Event()
    461     _SchedulerStopped.set()
    462 
    463     ## Start the task scheduler thread

    464     #

    465     #   @param  MaxThreadNumber     The maximum thread number

    466     #   @param  ExitFlag            Flag used to end the scheduler

    467     #

    468     @staticmethod
    469     def StartScheduler(MaxThreadNumber, ExitFlag):
    470         SchedulerThread = Thread(target=BuildTask.Scheduler, args=(MaxThreadNumber, ExitFlag))
    471         SchedulerThread.setName("Build-Task-Scheduler")
    472         SchedulerThread.setDaemon(False)
    473         SchedulerThread.start()
    474         # wait for the scheduler to be started, especially useful in Linux

    475         while not BuildTask.IsOnGoing():
    476             time.sleep(0.01)
    477 
    478     ## Scheduler method

    479     #

    480     #   @param  MaxThreadNumber     The maximum thread number

    481     #   @param  ExitFlag            Flag used to end the scheduler

    482     #

    483     @staticmethod
    484     def Scheduler(MaxThreadNumber, ExitFlag):
    485         BuildTask._SchedulerStopped.clear()
    486         try:
    487             # use BoundedSemaphore to control the maximum running threads

    488             BuildTask._Thread = BoundedSemaphore(MaxThreadNumber)
    489             #

    490             # scheduling loop, which will exits when no pending/ready task and

    491             # indicated to do so, or there's error in running thread

    492             #

    493             while (len(BuildTask._PendingQueue) > 0 or len(BuildTask._ReadyQueue) > 0 \
    494                    or not ExitFlag.isSet()) and not BuildTask._ErrorFlag.isSet():
    495                 EdkLogger.debug(EdkLogger.DEBUG_8, "Pending Queue (%d), Ready Queue (%d)"
    496                                 % (len(BuildTask._PendingQueue), len(BuildTask._ReadyQueue)))
    497 
    498                 # get all pending tasks

    499                 BuildTask._PendingQueueLock.acquire()
    500                 BuildObjectList = BuildTask._PendingQueue.keys()
    501                 #

    502                 # check if their dependency is resolved, and if true, move them

    503                 # into ready queue

    504                 #

    505                 for BuildObject in BuildObjectList:
    506                     Bt = BuildTask._PendingQueue[BuildObject]
    507                     if Bt.IsReady():
    508                         BuildTask._ReadyQueue[BuildObject] = BuildTask._PendingQueue.pop(BuildObject)
    509                 BuildTask._PendingQueueLock.release()
    510 
    511                 # launch build thread until the maximum number of threads is reached

    512                 while not BuildTask._ErrorFlag.isSet():
    513                     # empty ready queue, do nothing further

    514                     if len(BuildTask._ReadyQueue) == 0:
    515                         break
    516 
    517                     # wait for active thread(s) exit

    518                     BuildTask._Thread.acquire(True)
    519 
    520                     # start a new build thread

    521                     Bo = BuildTask._ReadyQueue.keys()[0]
    522                     Bt = BuildTask._ReadyQueue.pop(Bo)
    523 
    524                     # move into running queue

    525                     BuildTask._RunningQueueLock.acquire()
    526                     BuildTask._RunningQueue[Bo] = Bt
    527                     BuildTask._RunningQueueLock.release()
    528 
    529                     Bt.Start()
    530                     # avoid tense loop

    531                     time.sleep(0.01)
    532 
    533                 # avoid tense loop

    534                 time.sleep(0.01)
    535 
    536             # wait for all running threads exit

    537             if BuildTask._ErrorFlag.isSet():
    538                 EdkLogger.quiet("\nWaiting for all build threads exit...")
    539             # while not BuildTask._ErrorFlag.isSet() and \

    540             while len(BuildTask._RunningQueue) > 0:
    541                 EdkLogger.verbose("Waiting for thread ending...(%d)" % len(BuildTask._RunningQueue))
    542                 EdkLogger.debug(EdkLogger.DEBUG_8, "Threads [%s]" % ", ".join([Th.getName() for Th in threading.enumerate()]))
    543                 # avoid tense loop

    544                 time.sleep(0.1)
    545         except BaseException, X:
    546             #

    547             # TRICK: hide the output of threads left runing, so that the user can

    548             #        catch the error message easily

    549             #

    550             EdkLogger.SetLevel(EdkLogger.ERROR)
    551             BuildTask._ErrorFlag.set()
    552             BuildTask._ErrorMessage = "build thread scheduler error\n\t%s" % str(X)
    553 
    554         BuildTask._PendingQueue.clear()
    555         BuildTask._ReadyQueue.clear()
    556         BuildTask._RunningQueue.clear()
    557         BuildTask._TaskQueue.clear()
    558         BuildTask._SchedulerStopped.set()
    559 
    560     ## Wait for all running method exit

    561     #

    562     @staticmethod
    563     def WaitForComplete():
    564         BuildTask._SchedulerStopped.wait()
    565 
    566     ## Check if the scheduler is running or not

    567     #

    568     @staticmethod
    569     def IsOnGoing():
    570         return not BuildTask._SchedulerStopped.isSet()
    571 
    572     ## Abort the build

    573     @staticmethod
    574     def Abort():
    575         if BuildTask.IsOnGoing():
    576             BuildTask._ErrorFlag.set()
    577             BuildTask.WaitForComplete()
    578 
    579     ## Check if there's error in running thread

    580     #

    581     #   Since the main thread cannot catch exceptions in other thread, we have to

    582     #   use threading.Event to communicate this formation to main thread.

    583     #

    584     @staticmethod
    585     def HasError():
    586         return BuildTask._ErrorFlag.isSet()
    587 
    588     ## Get error message in running thread

    589     #

    590     #   Since the main thread cannot catch exceptions in other thread, we have to

    591     #   use a static variable to communicate this message to main thread.

    592     #

    593     @staticmethod
    594     def GetErrorMessage():
    595         return BuildTask._ErrorMessage
    596 
    597     ## Factory method to create a BuildTask object

    598     #

    599     #   This method will check if a module is building or has been built. And if

    600     #   true, just return the associated BuildTask object in the _TaskQueue. If

    601     #   not, create and return a new BuildTask object. The new BuildTask object

    602     #   will be appended to the _PendingQueue for scheduling later.

    603     #

    604     #   @param  BuildItem       A BuildUnit object representing a build object

    605     #   @param  Dependency      The dependent build object of BuildItem

    606     #

    607     @staticmethod
    608     def New(BuildItem, Dependency=None):
    609         if BuildItem in BuildTask._TaskQueue:
    610             Bt = BuildTask._TaskQueue[BuildItem]
    611             return Bt
    612 
    613         Bt = BuildTask()
    614         Bt._Init(BuildItem, Dependency)
    615         BuildTask._TaskQueue[BuildItem] = Bt
    616 
    617         BuildTask._PendingQueueLock.acquire()
    618         BuildTask._PendingQueue[BuildItem] = Bt
    619         BuildTask._PendingQueueLock.release()
    620 
    621         return Bt
    622 
    623     ## The real constructor of BuildTask

    624     #

    625     #   @param  BuildItem       A BuildUnit object representing a build object

    626     #   @param  Dependency      The dependent build object of BuildItem

    627     #

    628     def _Init(self, BuildItem, Dependency=None):
    629         self.BuildItem = BuildItem
    630 
    631         self.DependencyList = []
    632         if Dependency == None:
    633             Dependency = BuildItem.Dependency
    634         else:
    635             Dependency.extend(BuildItem.Dependency)
    636         self.AddDependency(Dependency)
    637         # flag indicating build completes, used to avoid unnecessary re-build

    638         self.CompleteFlag = False
    639 
    640     ## Check if all dependent build tasks are completed or not

    641     #

    642     def IsReady(self):
    643         ReadyFlag = True
    644         for Dep in self.DependencyList:
    645             if Dep.CompleteFlag == True:
    646                 continue
    647             ReadyFlag = False
    648             break
    649 
    650         return ReadyFlag
    651 
    652     ## Add dependent build task

    653     #

    654     #   @param  Dependency      The list of dependent build objects

    655     #

    656     def AddDependency(self, Dependency):
    657         for Dep in Dependency:
    658             if not Dep.BuildObject.IsBinaryModule:
    659                 self.DependencyList.append(BuildTask.New(Dep))    # BuildTask list

    660 
    661     ## The thread wrapper of LaunchCommand function

    662     #

    663     # @param  Command               A list or string contains the call of the command

    664     # @param  WorkingDir            The directory in which the program will be running

    665     #

    666     def _CommandThread(self, Command, WorkingDir):
    667         try:
    668             LaunchCommand(Command, WorkingDir)
    669             self.CompleteFlag = True
    670         except:
    671             #

    672             # TRICK: hide the output of threads left runing, so that the user can

    673             #        catch the error message easily

    674             #

    675             if not BuildTask._ErrorFlag.isSet():
    676                 GlobalData.gBuildingModule = "%s [%s, %s, %s]" % (str(self.BuildItem.BuildObject),
    677                                                                   self.BuildItem.BuildObject.Arch,
    678                                                                   self.BuildItem.BuildObject.ToolChain,
    679                                                                   self.BuildItem.BuildObject.BuildTarget
    680                                                                  )
    681             EdkLogger.SetLevel(EdkLogger.ERROR)
    682             BuildTask._ErrorFlag.set()
    683             BuildTask._ErrorMessage = "%s broken\n    %s [%s]" % \
    684                                       (threading.currentThread().getName(), Command, WorkingDir)
    685         # indicate there's a thread is available for another build task

    686         BuildTask._RunningQueueLock.acquire()
    687         BuildTask._RunningQueue.pop(self.BuildItem)
    688         BuildTask._RunningQueueLock.release()
    689         BuildTask._Thread.release()
    690 
    691     ## Start build task thread

    692     #

    693     def Start(self):
    694         EdkLogger.quiet("Building ... %s" % repr(self.BuildItem))
    695         Command = self.BuildItem.BuildCommand + [self.BuildItem.Target]
    696         self.BuildTread = Thread(target=self._CommandThread, args=(Command, self.BuildItem.WorkingDir))
    697         self.BuildTread.setName("build thread")
    698         self.BuildTread.setDaemon(False)
    699         self.BuildTread.start()
    700 
    701 ## The class contains the information related to EFI image

    702 #

    703 class PeImageInfo():
    704     ## Constructor

    705     #

    706     # Constructor will load all required image information.

    707     #

    708     #   @param  BaseName          The full file path of image.

    709     #   @param  Guid              The GUID for image.

    710     #   @param  Arch              Arch of this image.

    711     #   @param  OutputDir         The output directory for image.

    712     #   @param  DebugDir          The debug directory for image.

    713     #   @param  ImageClass        PeImage Information

    714     #

    715     def __init__(self, BaseName, Guid, Arch, OutputDir, DebugDir, ImageClass):
    716         self.BaseName         = BaseName
    717         self.Guid             = Guid
    718         self.Arch             = Arch
    719         self.OutputDir        = OutputDir
    720         self.DebugDir         = DebugDir
    721         self.Image            = ImageClass
    722         self.Image.Size       = (self.Image.Size / 0x1000 + 1) * 0x1000
    723 
    724 ## The class implementing the EDK2 build process

    725 #

    726 #   The build process includes:

    727 #       1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf

    728 #       2. Parse DSC file of active platform

    729 #       3. Parse FDF file if any

    730 #       4. Establish build database, including parse all other files (module, package)

    731 #       5. Create AutoGen files (C code file, depex file, makefile) if necessary

    732 #       6. Call build command

    733 #

    734 class Build():
    735     ## Constructor

    736     #

    737     # Constructor will load all necessary configurations, parse platform, modules

    738     # and packages and the establish a database for AutoGen.

    739     #

    740     #   @param  Target              The build command target, one of gSupportedTarget

    741     #   @param  WorkspaceDir        The directory of workspace

    742     #   @param  BuildOptions        Build options passed from command line

    743     #

    744     def __init__(self, Target, WorkspaceDir, BuildOptions):
    745         self.WorkspaceDir   = WorkspaceDir
    746         self.Target         = Target
    747         self.PlatformFile   = BuildOptions.PlatformFile
    748         self.ModuleFile     = BuildOptions.ModuleFile
    749         self.ArchList       = BuildOptions.TargetArch
    750         self.ToolChainList  = BuildOptions.ToolChain
    751         self.BuildTargetList= BuildOptions.BuildTarget
    752         self.Fdf            = BuildOptions.FdfFile
    753         self.FdList         = BuildOptions.RomImage
    754         self.FvList         = BuildOptions.FvImage
    755         self.CapList        = BuildOptions.CapName
    756         self.SilentMode     = BuildOptions.SilentMode
    757         self.ThreadNumber   = BuildOptions.ThreadNumber
    758         self.SkipAutoGen    = BuildOptions.SkipAutoGen
    759         self.Reparse        = BuildOptions.Reparse
    760         self.SkuId          = BuildOptions.SkuId
    761         self.ConfDirectory = BuildOptions.ConfDirectory
    762         self.SpawnMode      = True
    763         self.BuildReport    = BuildReport(BuildOptions.ReportFile, BuildOptions.ReportType)
    764         self.TargetTxt      = TargetTxtClassObject()
    765         self.ToolDef        = ToolDefClassObject()
    766         GlobalData.BuildOptionPcd     = BuildOptions.OptionPcd
    767         #Set global flag for build mode

    768         GlobalData.gIgnoreSource = BuildOptions.IgnoreSources
    769 
    770         if self.ConfDirectory:
    771             # Get alternate Conf location, if it is absolute, then just use the absolute directory name

    772             ConfDirectoryPath = os.path.normpath(self.ConfDirectory)
    773 
    774             if not os.path.isabs(ConfDirectoryPath):
    775                 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE

    776                 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf

    777                 ConfDirectoryPath = mws.join(self.WorkspaceDir, ConfDirectoryPath)
    778         else:
    779             if "CONF_PATH" in os.environ:
    780                 ConfDirectoryPath = os.path.normcase(os.path.normpath(os.environ["CONF_PATH"]))
    781             else:
    782                 # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf

    783                 ConfDirectoryPath = mws.join(self.WorkspaceDir, 'Conf')
    784         GlobalData.gConfDirectory = ConfDirectoryPath
    785         GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath))
    786 
    787         if BuildOptions.DisableCache:
    788             self.Db         = WorkspaceDatabase(":memory:")
    789         else:
    790             self.Db = WorkspaceDatabase(GlobalData.gDatabasePath, self.Reparse)
    791         self.BuildDatabase = self.Db.BuildObject
    792         self.Platform = None
    793         self.ToolChainFamily = None
    794         self.LoadFixAddress = 0
    795         self.UniFlag        = BuildOptions.Flag
    796         self.BuildModules = []
    797         self.Db_Flag = False
    798         self.LaunchPrebuildFlag = False
    799         self.PrebuildScript = ''
    800         self.PostbuildScript = ''
    801         self.PlatformBuildPath = os.path.join(GlobalData.gConfDirectory,'.cache', '.PlatformBuild')
    802         if BuildOptions.CommandLength:
    803             GlobalData.gCommandMaxLength = BuildOptions.CommandLength
    804 
    805         # print dot character during doing some time-consuming work

    806         self.Progress = Utils.Progressor()
    807         # print current build environment and configuration

    808         EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))
    809         if "PACKAGES_PATH" in os.environ:
    810             # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env. 

    811             EdkLogger.quiet("%-16s = %s" % ("PACKAGES_PATH", os.path.normcase(os.path.normpath(os.environ["PACKAGES_PATH"]))))
    812         EdkLogger.quiet("%-16s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"]))
    813         EdkLogger.quiet("%-16s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"]))
    814         EdkLogger.quiet("%-16s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"]))
    815         EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))
    816         if "EDK_TOOLS_BIN" in os.environ:
    817             # Print the same path style with WORKSPACE env. 

    818             EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os.path.normcase(os.path.normpath(os.environ["EDK_TOOLS_BIN"]))))
    819         EdkLogger.quiet("%-16s = %s" % ("CONF_PATH", GlobalData.gConfDirectory))
    820         self.InitPreBuild()
    821         self.InitPostBuild()
    822         if self.PrebuildScript:
    823             EdkLogger.quiet("%-16s = %s" % ("PREBUILD", self.PrebuildScript))
    824         if self.PostbuildScript:
    825             EdkLogger.quiet("%-16s = %s" % ("POSTBUILD", self.PostbuildScript))
    826         if self.PrebuildScript:
    827             self.LaunchPrebuild()
    828             self.TargetTxt = TargetTxtClassObject()
    829             self.ToolDef   = ToolDefClassObject()
    830         if not (self.LaunchPrebuildFlag and os.path.exists(self.PlatformBuildPath)):
    831             self.InitBuild()
    832 
    833         EdkLogger.info("")
    834         os.chdir(self.WorkspaceDir)
    835 
    836     ## Load configuration

    837     #

    838     #   This method will parse target.txt and get the build configurations.

    839     #

    840     def LoadConfiguration(self):
    841         #

    842         # Check target.txt and tools_def.txt and Init them

    843         #

    844         BuildConfigurationFile = os.path.normpath(os.path.join(GlobalData.gConfDirectory, gBuildConfiguration))
    845         if os.path.isfile(BuildConfigurationFile) == True:
    846             StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)
    847 
    848             ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]
    849             if ToolDefinitionFile == '':
    850                 ToolDefinitionFile = gToolsDefinition
    851                 ToolDefinitionFile = os.path.normpath(mws.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile))
    852             if os.path.isfile(ToolDefinitionFile) == True:
    853                 StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)
    854             else:
    855                 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)
    856         else:
    857             EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)
    858 
    859         # if no ARCH given in command line, get it from target.txt

    860         if not self.ArchList:
    861             self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH]
    862         self.ArchList = tuple(self.ArchList)
    863 
    864         # if no build target given in command line, get it from target.txt

    865         if not self.BuildTargetList:
    866             self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]
    867 
    868         # if no tool chain given in command line, get it from target.txt

    869         if not self.ToolChainList:
    870             self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]
    871             if self.ToolChainList == None or len(self.ToolChainList) == 0:
    872                 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")
    873 
    874         # check if the tool chains are defined or not

    875         NewToolChainList = []
    876         for ToolChain in self.ToolChainList:
    877             if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:
    878                 EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)
    879             else:
    880                 NewToolChainList.append(ToolChain)
    881         # if no tool chain available, break the build

    882         if len(NewToolChainList) == 0:
    883             EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
    884                             ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))
    885         else:
    886             self.ToolChainList = NewToolChainList
    887 
    888         ToolChainFamily = []
    889         ToolDefinition = self.ToolDef.ToolsDefTxtDatabase
    890         for Tool in self.ToolChainList:
    891             if TAB_TOD_DEFINES_FAMILY not in ToolDefinition or Tool not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \
    892                or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool]:
    893                 EdkLogger.warn("No tool chain family found in configuration for %s. Default to MSFT." % Tool)
    894                 ToolChainFamily.append("MSFT")
    895             else:
    896                 ToolChainFamily.append(ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool])
    897         self.ToolChainFamily = ToolChainFamily
    898 
    899         if self.ThreadNumber == None:
    900             self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]
    901             if self.ThreadNumber == '':
    902                 self.ThreadNumber = 0
    903             else:
    904                 self.ThreadNumber = int(self.ThreadNumber, 0)
    905 
    906         if self.ThreadNumber == 0:
    907             self.ThreadNumber = 1
    908 
    909         if not self.PlatformFile:
    910             PlatformFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM]
    911             if not PlatformFile:
    912                 # Try to find one in current directory

    913                 WorkingDirectory = os.getcwd()
    914                 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))
    915                 FileNum = len(FileList)
    916                 if FileNum >= 2:
    917                     EdkLogger.error("build", OPTION_MISSING,
    918                                     ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))
    919                 elif FileNum == 1:
    920                     PlatformFile = FileList[0]
    921                 else:
    922                     EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
    923                                     ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")
    924 
    925             self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)
    926 
    927     ## Initialize build configuration

    928     #

    929     #   This method will parse DSC file and merge the configurations from

    930     #   command line and target.txt, then get the final build configurations.

    931     #

    932     def InitBuild(self):
    933         # parse target.txt, tools_def.txt, and platform file

    934         self.LoadConfiguration()
    935 
    936         # Allow case-insensitive for those from command line or configuration file

    937         ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)
    938         if ErrorCode != 0:
    939             EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
    940 
    941         # create metafile database

    942         if not self.Db_Flag:
    943             self.Db.InitDatabase()
    944 
    945     def InitPreBuild(self):
    946         self.LoadConfiguration()
    947         ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)
    948         if ErrorCode != 0:
    949             EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
    950         if self.BuildTargetList:
    951             GlobalData.gGlobalDefines['TARGET'] = self.BuildTargetList[0]
    952         if self.ArchList:
    953             GlobalData.gGlobalDefines['ARCH'] = self.ArchList[0]
    954         if self.ToolChainList:
    955             GlobalData.gGlobalDefines['TOOLCHAIN'] = self.ToolChainList[0]
    956             GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = self.ToolChainList[0]
    957         if self.ToolChainFamily:
    958             GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[0]
    959         if 'PREBUILD' in GlobalData.gCommandLineDefines.keys():
    960             self.Prebuild   = GlobalData.gCommandLineDefines.get('PREBUILD')
    961         else:
    962             self.Db.InitDatabase()
    963             self.Db_Flag = True
    964             Platform = self.Db._MapPlatform(str(self.PlatformFile))
    965             self.Prebuild = str(Platform.Prebuild)
    966         if self.Prebuild:
    967             PrebuildList = self.Prebuild.split()
    968             if not os.path.isabs(PrebuildList[0]):
    969                 PrebuildList[0] = mws.join(self.WorkspaceDir, PrebuildList[0])
    970             if os.path.isfile(PrebuildList[0]):
    971                 self.PrebuildScript = PrebuildList[0]
    972                 self.Prebuild = ' '.join(PrebuildList)
    973                 self.Prebuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList)
    974                 #self.LaunchPrebuild()

    975             else:
    976                 EdkLogger.error("Prebuild", PREBUILD_ERROR, "the prebuild script %s is not exist.\n If you'd like to disable the Prebuild process, please use the format: -D PREBUILD=\"\" " %(PrebuildList[0]))
    977 
    978     def InitPostBuild(self):
    979         if 'POSTBUILD' in GlobalData.gCommandLineDefines.keys():
    980             self.Postbuild = GlobalData.gCommandLineDefines.get('POSTBUILD')
    981         else:
    982             Platform = self.Db._MapPlatform(str(self.PlatformFile))
    983             self.Postbuild = str(Platform.Postbuild)
    984         if self.Postbuild:
    985             PostbuildList = self.Postbuild.split()
    986             if not os.path.isabs(PostbuildList[0]):
    987                 PostbuildList[0] = mws.join(self.WorkspaceDir, PostbuildList[0])
    988             if os.path.isfile(PostbuildList[0]):
    989                 self.PostbuildScript = PostbuildList[0]
    990                 self.Postbuild = ' '.join(PostbuildList)
    991                 self.Postbuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList)
    992                 #self.LanuchPostbuild()

    993             else:
    994                 EdkLogger.error("Postbuild", POSTBUILD_ERROR, "the postbuild script %s is not exist.\n If you'd like to disable the Postbuild process, please use the format: -D POSTBUILD=\"\" " %(PostbuildList[0]))
    995 
    996     def PassCommandOption(self, BuildTarget, TargetArch, ToolChain):
    997         BuildStr = ''
    998         if GlobalData.gCommand and isinstance(GlobalData.gCommand, list):
    999             BuildStr += ' ' + ' '.join(GlobalData.gCommand)
   1000         TargetFlag = False
   1001         ArchFlag = False
   1002         ToolChainFlag = False
   1003 
   1004         if GlobalData.gOptions and not GlobalData.gOptions.BuildTarget:
   1005             TargetFlag = True
   1006         if GlobalData.gOptions and not GlobalData.gOptions.TargetArch:
   1007             ArchFlag = True
   1008         if GlobalData.gOptions and not GlobalData.gOptions.ToolChain:
   1009             ToolChainFlag = True
   1010 
   1011         if TargetFlag and BuildTarget:
   1012             if isinstance(BuildTarget, list) or isinstance(BuildTarget, tuple):
   1013                 BuildStr += ' -b ' + ' -b '.join(BuildTarget)
   1014             elif isinstance(BuildTarget, str):
   1015                 BuildStr += ' -b ' + BuildTarget
   1016         if ArchFlag and TargetArch:
   1017             if isinstance(TargetArch, list) or isinstance(TargetArch, tuple):
   1018                 BuildStr += ' -a ' + ' -a '.join(TargetArch)
   1019             elif isinstance(TargetArch, str):
   1020                 BuildStr += ' -a ' + TargetArch
   1021         if ToolChainFlag and ToolChain:
   1022             if isinstance(ToolChain, list) or isinstance(ToolChain, tuple):
   1023                 BuildStr += ' -t ' + ' -t '.join(ToolChain)
   1024             elif isinstance(ToolChain, str):
   1025                 BuildStr += ' -t ' + ToolChain
   1026 
   1027         return BuildStr
   1028 
   1029     def LaunchPrebuild(self):
   1030         if self.Prebuild:
   1031             EdkLogger.info("\n- Prebuild Start -\n")
   1032             self.LaunchPrebuildFlag = True
   1033             PrebuildEnvFile = os.path.join(GlobalData.gConfDirectory,'.cache','.PrebuildEnv')
   1034             if os.path.isfile(PrebuildEnvFile):
   1035                 os.remove(PrebuildEnvFile)
   1036             if os.path.isfile(self.PlatformBuildPath):
   1037                 os.remove(self.PlatformBuildPath)
   1038             if sys.platform == "win32":
   1039                 args = ' && '.join((self.Prebuild, 'set > ' + PrebuildEnvFile))
   1040                 Process = Popen(args, stdout=PIPE, stderr=PIPE)
   1041             else:
   1042                 args = ' && '.join((self.Prebuild, 'env > ' + PrebuildEnvFile))
   1043                 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True, executable="/bin/bash")
   1044 
   1045             # launch two threads to read the STDOUT and STDERR

   1046             EndOfProcedure = Event()
   1047             EndOfProcedure.clear()
   1048             if Process.stdout:
   1049                 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))
   1050                 StdOutThread.setName("STDOUT-Redirector")
   1051                 StdOutThread.setDaemon(False)
   1052                 StdOutThread.start()
   1053 
   1054             if Process.stderr:
   1055                 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))
   1056                 StdErrThread.setName("STDERR-Redirector")
   1057                 StdErrThread.setDaemon(False)
   1058                 StdErrThread.start()
   1059             # waiting for program exit

   1060             Process.wait()
   1061 
   1062             if Process.stdout:
   1063                 StdOutThread.join()
   1064             if Process.stderr:
   1065                 StdErrThread.join()
   1066             if Process.returncode != 0 :
   1067                 EdkLogger.error("Prebuild", PREBUILD_ERROR, 'Prebuild process is not success!')
   1068 
   1069             if os.path.exists(PrebuildEnvFile):
   1070                 f = open(PrebuildEnvFile)
   1071                 envs = f.readlines()
   1072                 f.close()
   1073                 envs = itertools.imap(lambda l: l.split('=',1), envs)
   1074                 envs = itertools.ifilter(lambda l: len(l) == 2, envs)
   1075                 envs = itertools.imap(lambda l: [i.strip() for i in l], envs)
   1076                 os.environ.update(dict(envs))
   1077             EdkLogger.info("\n- Prebuild Done -\n")
   1078 
   1079     def LanuchPostbuild(self):
   1080         if self.Postbuild:
   1081             EdkLogger.info("\n- Postbuild Start -\n")
   1082             if sys.platform == "win32":
   1083                 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE)
   1084             else:
   1085                 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True, executable="/bin/bash")
   1086             # launch two threads to read the STDOUT and STDERR

   1087             EndOfProcedure = Event()
   1088             EndOfProcedure.clear()
   1089             if Process.stdout:
   1090                 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))
   1091                 StdOutThread.setName("STDOUT-Redirector")
   1092                 StdOutThread.setDaemon(False)
   1093                 StdOutThread.start()
   1094 
   1095             if Process.stderr:
   1096                 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))
   1097                 StdErrThread.setName("STDERR-Redirector")
   1098                 StdErrThread.setDaemon(False)
   1099                 StdErrThread.start()
   1100             # waiting for program exit

   1101             Process.wait()
   1102 
   1103             if Process.stdout:
   1104                 StdOutThread.join()
   1105             if Process.stderr:
   1106                 StdErrThread.join()
   1107             if Process.returncode != 0 :
   1108                 EdkLogger.error("Postbuild", POSTBUILD_ERROR, 'Postbuild process is not success!')
   1109             EdkLogger.info("\n- Postbuild Done -\n")
   1110     ## Build a module or platform

   1111     #

   1112     # Create autogen code and makefile for a module or platform, and the launch

   1113     # "make" command to build it

   1114     #

   1115     #   @param  Target                      The target of build command

   1116     #   @param  Platform                    The platform file

   1117     #   @param  Module                      The module file

   1118     #   @param  BuildTarget                 The name of build target, one of "DEBUG", "RELEASE"

   1119     #   @param  ToolChain                   The name of toolchain to build

   1120     #   @param  Arch                        The arch of the module/platform

   1121     #   @param  CreateDepModuleCodeFile     Flag used to indicate creating code

   1122     #                                       for dependent modules/Libraries

   1123     #   @param  CreateDepModuleMakeFile     Flag used to indicate creating makefile

   1124     #                                       for dependent modules/Libraries

   1125     #

   1126     def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):
   1127         if AutoGenObject == None:
   1128             return False
   1129 
   1130         # skip file generation for cleanxxx targets, run and fds target

   1131         if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
   1132             # for target which must generate AutoGen code and makefile

   1133             if not self.SkipAutoGen or Target == 'genc':
   1134                 self.Progress.Start("Generating code")
   1135                 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
   1136                 self.Progress.Stop("done!")
   1137             if Target == "genc":
   1138                 return True
   1139 
   1140             if not self.SkipAutoGen or Target == 'genmake':
   1141                 self.Progress.Start("Generating makefile")
   1142                 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)
   1143                 self.Progress.Stop("done!")
   1144             if Target == "genmake":
   1145                 return True
   1146         else:
   1147             # always recreate top/platform makefile when clean, just in case of inconsistency

   1148             AutoGenObject.CreateCodeFile(False)
   1149             AutoGenObject.CreateMakeFile(False)
   1150 
   1151         if EdkLogger.GetLevel() == EdkLogger.QUIET:
   1152             EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
   1153 
   1154         BuildCommand = AutoGenObject.BuildCommand
   1155         if BuildCommand == None or len(BuildCommand) == 0:
   1156             EdkLogger.error("build", OPTION_MISSING,
   1157                             "No build command found for this module. "
   1158                             "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
   1159                                 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
   1160                             ExtraData=str(AutoGenObject))
   1161 
   1162         makefile = GenMake.BuildFile(AutoGenObject)._FILE_NAME_[GenMake.gMakeType]
   1163 
   1164         # run

   1165         if Target == 'run':
   1166             RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))
   1167             Command = '.\SecMain'
   1168             os.chdir(RunDir)
   1169             LaunchCommand(Command, RunDir)
   1170             return True
   1171 
   1172         # build modules

   1173         if BuildModule:
   1174             BuildCommand = BuildCommand + [Target]
   1175             LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
   1176             self.CreateAsBuiltInf()
   1177             return True
   1178 
   1179         # build library

   1180         if Target == 'libraries':
   1181             for Lib in AutoGenObject.LibraryBuildDirectoryList:
   1182                 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']
   1183                 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
   1184             return True
   1185 
   1186         # build module

   1187         if Target == 'modules':
   1188             for Lib in AutoGenObject.LibraryBuildDirectoryList:
   1189                 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']
   1190                 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
   1191             for Mod in AutoGenObject.ModuleBuildDirectoryList:
   1192                 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']
   1193                 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
   1194             self.CreateAsBuiltInf()
   1195             return True
   1196 
   1197         # cleanlib

   1198         if Target == 'cleanlib':
   1199             for Lib in AutoGenObject.LibraryBuildDirectoryList:
   1200                 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))
   1201                 if os.path.exists(LibMakefile):
   1202                     NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
   1203                     LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
   1204             return True
   1205 
   1206         # clean

   1207         if Target == 'clean':
   1208             for Mod in AutoGenObject.ModuleBuildDirectoryList:
   1209                 ModMakefile = os.path.normpath(os.path.join(Mod, makefile))
   1210                 if os.path.exists(ModMakefile):
   1211                     NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']
   1212                     LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
   1213             for Lib in AutoGenObject.LibraryBuildDirectoryList:
   1214                 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))
   1215                 if os.path.exists(LibMakefile):
   1216                     NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
   1217                     LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
   1218             return True
   1219 
   1220         # cleanall

   1221         if Target == 'cleanall':
   1222             try:
   1223                 #os.rmdir(AutoGenObject.BuildDir)

   1224                 RemoveDirectory(AutoGenObject.BuildDir, True)
   1225             except WindowsError, X:
   1226                 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
   1227         return True
   1228 
   1229     ## Build a module or platform

   1230     #

   1231     # Create autogen code and makefile for a module or platform, and the launch

   1232     # "make" command to build it

   1233     #

   1234     #   @param  Target                      The target of build command

   1235     #   @param  Platform                    The platform file

   1236     #   @param  Module                      The module file

   1237     #   @param  BuildTarget                 The name of build target, one of "DEBUG", "RELEASE"

   1238     #   @param  ToolChain                   The name of toolchain to build

   1239     #   @param  Arch                        The arch of the module/platform

   1240     #   @param  CreateDepModuleCodeFile     Flag used to indicate creating code

   1241     #                                       for dependent modules/Libraries

   1242     #   @param  CreateDepModuleMakeFile     Flag used to indicate creating makefile

   1243     #                                       for dependent modules/Libraries

   1244     #

   1245     def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):
   1246         if AutoGenObject == None:
   1247             return False
   1248 
   1249         # skip file generation for cleanxxx targets, run and fds target

   1250         if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
   1251             # for target which must generate AutoGen code and makefile

   1252             if not self.SkipAutoGen or Target == 'genc':
   1253                 self.Progress.Start("Generating code")
   1254                 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
   1255                 self.Progress.Stop("done!")
   1256             if Target == "genc":
   1257                 return True
   1258 
   1259             if not self.SkipAutoGen or Target == 'genmake':
   1260                 self.Progress.Start("Generating makefile")
   1261                 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)
   1262                 #AutoGenObject.CreateAsBuiltInf()

   1263                 self.Progress.Stop("done!")
   1264             if Target == "genmake":
   1265                 return True
   1266         else:
   1267             # always recreate top/platform makefile when clean, just in case of inconsistency

   1268             AutoGenObject.CreateCodeFile(False)
   1269             AutoGenObject.CreateMakeFile(False)
   1270 
   1271         if EdkLogger.GetLevel() == EdkLogger.QUIET:
   1272             EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
   1273 
   1274         BuildCommand = AutoGenObject.BuildCommand
   1275         if BuildCommand == None or len(BuildCommand) == 0:
   1276             EdkLogger.error("build", OPTION_MISSING,
   1277                             "No build command found for this module. "
   1278                             "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
   1279                                 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
   1280                             ExtraData=str(AutoGenObject))
   1281 
   1282         # build modules

   1283         if BuildModule:
   1284             if Target != 'fds':
   1285                 BuildCommand = BuildCommand + [Target]
   1286             LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
   1287             self.CreateAsBuiltInf()
   1288             return True
   1289 
   1290         # genfds

   1291         if Target == 'fds':
   1292             LaunchCommand(AutoGenObject.GenFdsCommand, AutoGenObject.MakeFileDir)
   1293             return True
   1294 
   1295         # run

   1296         if Target == 'run':
   1297             RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))
   1298             Command = '.\SecMain'
   1299             os.chdir(RunDir)
   1300             LaunchCommand(Command, RunDir)
   1301             return True
   1302 
   1303         # build library

   1304         if Target == 'libraries':
   1305             pass
   1306 
   1307         # not build modules

   1308 
   1309 
   1310         # cleanall

   1311         if Target == 'cleanall':
   1312             try:
   1313                 #os.rmdir(AutoGenObject.BuildDir)

   1314                 RemoveDirectory(AutoGenObject.BuildDir, True)
   1315             except WindowsError, X:
   1316                 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
   1317         return True
   1318 
   1319     ## Rebase module image and Get function address for the input module list.

   1320     #

   1321     def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):
   1322         if ModeIsSmm:
   1323             AddrIsOffset = False
   1324         InfFileNameList = ModuleList.keys()
   1325         #InfFileNameList.sort()

   1326         for InfFile in InfFileNameList:
   1327             sys.stdout.write (".")
   1328             sys.stdout.flush()
   1329             ModuleInfo = ModuleList[InfFile]
   1330             ModuleName = ModuleInfo.BaseName
   1331             ModuleOutputImage = ModuleInfo.Image.FileName
   1332             ModuleDebugImage  = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')
   1333             ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.

   1334             if not ModeIsSmm:
   1335                 BaseAddress = BaseAddress - ModuleInfo.Image.Size
   1336                 #

   1337                 # Update Image to new BaseAddress by GenFw tool

   1338                 #

   1339                 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
   1340                 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
   1341             else:
   1342                 #

   1343                 # Set new address to the section header only for SMM driver.

   1344                 #

   1345                 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
   1346                 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
   1347             #

   1348             # Collect funtion address from Map file

   1349             #

   1350             ImageMapTable = ModuleOutputImage.replace('.efi', '.map')
   1351             FunctionList = []
   1352             if os.path.exists(ImageMapTable):
   1353                 OrigImageBaseAddress = 0
   1354                 ImageMap = open(ImageMapTable, 'r')
   1355                 for LinStr in ImageMap:
   1356                     if len (LinStr.strip()) == 0:
   1357                         continue
   1358                     #

   1359                     # Get the preferred address set on link time.

   1360                     #

   1361                     if LinStr.find ('Preferred load address is') != -1:
   1362                         StrList = LinStr.split()
   1363                         OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)
   1364 
   1365                     StrList = LinStr.split()
   1366                     if len (StrList) > 4:
   1367                         if StrList[3] == 'f' or StrList[3] == 'F':
   1368                             Name = StrList[1]
   1369                             RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress
   1370                             FunctionList.append ((Name, RelativeAddress))
   1371                             if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'):
   1372                                 #

   1373                                 # Get the real entry point address for IPF image.

   1374                                 #

   1375                                 ModuleInfo.Image.EntryPoint = RelativeAddress
   1376                 ImageMap.close()
   1377             #

   1378             # Add general information.

   1379             #

   1380             if ModeIsSmm:
   1381                 MapBuffer.write('\n\n%s (Fixed SMRAM Offset,   BaseAddress=0x%010X,  EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
   1382             elif AddrIsOffset:
   1383                 MapBuffer.write('\n\n%s (Fixed Memory Offset,  BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))
   1384             else:
   1385                 MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X,  EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
   1386             #

   1387             # Add guid and general seciton section.

   1388             #

   1389             TextSectionAddress = 0
   1390             DataSectionAddress = 0
   1391             for SectionHeader in ModuleInfo.Image.SectionHeaderList:
   1392                 if SectionHeader[0] == '.text':
   1393                     TextSectionAddress = SectionHeader[1]
   1394                 elif SectionHeader[0] in ['.data', '.sdata']:
   1395                     DataSectionAddress = SectionHeader[1]
   1396             if AddrIsOffset:
   1397                 MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))
   1398             else:
   1399                 MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))
   1400             #

   1401             # Add debug image full path.

   1402             #

   1403             MapBuffer.write('(IMAGE=%s)\n\n' % (ModuleDebugImage))
   1404             #

   1405             # Add funtion address

   1406             #

   1407             for Function in FunctionList:
   1408                 if AddrIsOffset:
   1409                     MapBuffer.write('  -0x%010X    %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))
   1410                 else:
   1411                     MapBuffer.write('  0x%010X    %s\n' % (BaseAddress + Function[1], Function[0]))
   1412             ImageMap.close()
   1413 
   1414             #

   1415             # for SMM module in SMRAM, the SMRAM will be allocated from base to top.

   1416             #

   1417             if ModeIsSmm:
   1418                 BaseAddress = BaseAddress + ModuleInfo.Image.Size
   1419 
   1420     ## Collect MAP information of all FVs

   1421     #

   1422     def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):
   1423         if self.Fdf:
   1424             # First get the XIP base address for FV map file.

   1425             GuidPattern = re.compile("[-a-fA-F0-9]+")
   1426             GuidName = re.compile("\(GUID=[-a-fA-F0-9]+")
   1427             for FvName in Wa.FdfProfile.FvDict.keys():
   1428                 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')
   1429                 if not os.path.exists(FvMapBuffer):
   1430                     continue
   1431                 FvMap = open(FvMapBuffer, 'r')
   1432                 #skip FV size information

   1433                 FvMap.readline()
   1434                 FvMap.readline()
   1435                 FvMap.readline()
   1436                 FvMap.readline()
   1437                 for Line in FvMap:
   1438                     MatchGuid = GuidPattern.match(Line)
   1439                     if MatchGuid != None:
   1440                         #

   1441                         # Replace GUID with module name

   1442                         #

   1443                         GuidString = MatchGuid.group()
   1444                         if GuidString.upper() in ModuleList:
   1445                             Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)
   1446                     MapBuffer.write('%s' % (Line))
   1447                     #

   1448                     # Add the debug image full path.

   1449                     #

   1450                     MatchGuid = GuidName.match(Line)
   1451                     if MatchGuid != None:
   1452                         GuidString = MatchGuid.group().split("=")[1]
   1453                         if GuidString.upper() in ModuleList:
   1454                             MapBuffer.write('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))
   1455 
   1456                 FvMap.close()
   1457 
   1458     ## Collect MAP information of all modules

   1459     #

   1460     def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):
   1461         sys.stdout.write ("Generate Load Module At Fix Address Map")
   1462         sys.stdout.flush()
   1463         PatchEfiImageList = []
   1464         PeiModuleList  = {}
   1465         BtModuleList   = {}
   1466         RtModuleList   = {}
   1467         SmmModuleList  = {}
   1468         PeiSize = 0
   1469         BtSize  = 0
   1470         RtSize  = 0
   1471         # reserve 4K size in SMRAM to make SMM module address not from 0.

   1472         SmmSize = 0x1000
   1473         IsIpfPlatform = False
   1474         if 'IPF' in self.ArchList:
   1475             IsIpfPlatform = True
   1476         for ModuleGuid in ModuleList:
   1477             Module = ModuleList[ModuleGuid]
   1478             GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)
   1479 
   1480             OutputImageFile = ''
   1481             for ResultFile in Module.CodaTargetList:
   1482                 if str(ResultFile.Target).endswith('.efi'):
   1483                     #

   1484                     # module list for PEI, DXE, RUNTIME and SMM

   1485                     #

   1486                     OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')
   1487                     ImageClass = PeImageClass (OutputImageFile)
   1488                     if not ImageClass.IsValid:
   1489                         EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)
   1490                     ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)
   1491                     if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER', 'PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']:
   1492                         PeiModuleList[Module.MetaFile] = ImageInfo
   1493                         PeiSize += ImageInfo.Image.Size
   1494                     elif Module.ModuleType in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']:
   1495                         BtModuleList[Module.MetaFile] = ImageInfo
   1496                         BtSize += ImageInfo.Image.Size
   1497                     elif Module.ModuleType in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']:
   1498                         RtModuleList[Module.MetaFile] = ImageInfo
   1499                         #IPF runtime driver needs to be at 2 page alignment.

   1500                         if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0:
   1501                             ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000
   1502                         RtSize += ImageInfo.Image.Size
   1503                     elif Module.ModuleType in ['SMM_CORE', 'DXE_SMM_DRIVER']:
   1504                         SmmModuleList[Module.MetaFile] = ImageInfo
   1505                         SmmSize += ImageInfo.Image.Size
   1506                         if Module.ModuleType == 'DXE_SMM_DRIVER':
   1507                             PiSpecVersion = '0x00000000'
   1508                             if 'PI_SPECIFICATION_VERSION' in Module.Module.Specification:
   1509                                 PiSpecVersion = Module.Module.Specification['PI_SPECIFICATION_VERSION']
   1510                             # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.

   1511                             if int(PiSpecVersion, 16) < 0x0001000A:
   1512                                 BtModuleList[Module.MetaFile] = ImageInfo
   1513                                 BtSize += ImageInfo.Image.Size
   1514                     break
   1515             #

   1516             # EFI image is final target.

   1517             # Check EFI image contains patchable FixAddress related PCDs.

   1518             #

   1519             if OutputImageFile != '':
   1520                 ModuleIsPatch = False
   1521                 for Pcd in Module.ModulePcdList:
   1522                     if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:
   1523                         ModuleIsPatch = True
   1524                         break
   1525                 if not ModuleIsPatch:
   1526                     for Pcd in Module.LibraryPcdList:
   1527                         if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:
   1528                             ModuleIsPatch = True
   1529                             break
   1530 
   1531                 if not ModuleIsPatch:
   1532                     continue
   1533                 #

   1534                 # Module includes the patchable load fix address PCDs.

   1535                 # It will be fixed up later.

   1536                 #

   1537                 PatchEfiImageList.append (OutputImageFile)
   1538 
   1539         #

   1540         # Get Top Memory address

   1541         #

   1542         ReservedRuntimeMemorySize = 0
   1543         TopMemoryAddress = 0
   1544         if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:
   1545             TopMemoryAddress = 0
   1546         else:
   1547             TopMemoryAddress = self.LoadFixAddress
   1548             if TopMemoryAddress < RtSize + BtSize + PeiSize:
   1549                 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
   1550             # Make IPF runtime driver at 2 page alignment.

   1551             if IsIpfPlatform:
   1552                 ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000
   1553                 RtSize = RtSize + ReservedRuntimeMemorySize
   1554 
   1555         #

   1556         # Patch FixAddress related PCDs into EFI image

   1557         #

   1558         for EfiImage in PatchEfiImageList:
   1559             EfiImageMap = EfiImage.replace('.efi', '.map')
   1560             if not os.path.exists(EfiImageMap):
   1561                 continue
   1562             #

   1563             # Get PCD offset in EFI image by GenPatchPcdTable function

   1564             #

   1565             PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)
   1566             #

   1567             # Patch real PCD value by PatchPcdValue tool

   1568             #

   1569             for PcdInfo in PcdTable:
   1570                 ReturnValue = 0
   1571                 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:
   1572                     ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize / 0x1000))
   1573                 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:
   1574                     ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize / 0x1000))
   1575                 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:
   1576                     ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize / 0x1000))
   1577                 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:
   1578                     ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize / 0x1000))
   1579                 if ReturnValue != 0:
   1580                     EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)
   1581 
   1582         MapBuffer.write('PEI_CODE_PAGE_NUMBER      = 0x%x\n' % (PeiSize / 0x1000))
   1583         MapBuffer.write('BOOT_CODE_PAGE_NUMBER     = 0x%x\n' % (BtSize / 0x1000))
   1584         MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER  = 0x%x\n' % (RtSize / 0x1000))
   1585         if len (SmmModuleList) > 0:
   1586             MapBuffer.write('SMM_CODE_PAGE_NUMBER      = 0x%x\n' % (SmmSize / 0x1000))
   1587 
   1588         PeiBaseAddr = TopMemoryAddress - RtSize - BtSize
   1589         BtBaseAddr  = TopMemoryAddress - RtSize
   1590         RtBaseAddr  = TopMemoryAddress - ReservedRuntimeMemorySize
   1591 
   1592         self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)
   1593         self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)
   1594         self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)
   1595         self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset=False, ModeIsSmm=True)
   1596         MapBuffer.write('\n\n')
   1597         sys.stdout.write ("\n")
   1598         sys.stdout.flush()
   1599 
   1600     ## Save platform Map file

   1601     #

   1602     def _SaveMapFile (self, MapBuffer, Wa):
   1603         #

   1604         # Map file path is got.

   1605         #

   1606         MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')
   1607         #

   1608         # Save address map into MAP file.

   1609         #

   1610         SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)
   1611         MapBuffer.close()
   1612         if self.LoadFixAddress != 0:
   1613             sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath))
   1614         sys.stdout.flush()
   1615 
   1616     ## Build active platform for different build targets and different tool chains

   1617     #

   1618     def _BuildPlatform(self):
   1619         SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)
   1620         for BuildTarget in self.BuildTargetList:
   1621             GlobalData.gGlobalDefines['TARGET'] = BuildTarget
   1622             index = 0
   1623             for ToolChain in self.ToolChainList:
   1624                 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
   1625                 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
   1626                 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
   1627                 index += 1
   1628                 Wa = WorkspaceAutoGen(
   1629                         self.WorkspaceDir,
   1630                         self.PlatformFile,
   1631                         BuildTarget,
   1632                         ToolChain,
   1633                         self.ArchList,
   1634                         self.BuildDatabase,
   1635                         self.TargetTxt,
   1636                         self.ToolDef,
   1637                         self.Fdf,
   1638                         self.FdList,
   1639                         self.FvList,
   1640                         self.CapList,
   1641                         self.SkuId,
   1642                         self.UniFlag,
   1643                         self.Progress
   1644                         )
   1645                 self.Fdf = Wa.FdfFile
   1646                 self.LoadFixAddress = Wa.Platform.LoadFixAddress
   1647                 self.BuildReport.AddPlatformReport(Wa)
   1648                 self.Progress.Stop("done!")
   1649                 for Arch in Wa.ArchList:
   1650                     GlobalData.gGlobalDefines['ARCH'] = Arch
   1651                     Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
   1652                     for Module in Pa.Platform.Modules:
   1653                         # Get ModuleAutoGen object to generate C code file and makefile

   1654                         Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
   1655                         if Ma == None:
   1656                             continue
   1657                         self.BuildModules.append(Ma)
   1658                     self._BuildPa(self.Target, Pa)
   1659 
   1660                 # Create MAP file when Load Fix Address is enabled.

   1661                 if self.Target in ["", "all", "fds"]:
   1662                     for Arch in Wa.ArchList:
   1663                         GlobalData.gGlobalDefines['ARCH'] = Arch
   1664                         #

   1665                         # Check whether the set fix address is above 4G for 32bit image.

   1666                         #

   1667                         if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
   1668                             EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS can't be set to larger than or equal to 4G for the platform with IA32 or ARM arch modules")
   1669                     #

   1670                     # Get Module List

   1671                     #

   1672                     ModuleList = {}
   1673                     for Pa in Wa.AutoGenObjectList:
   1674                         for Ma in Pa.ModuleAutoGenList:
   1675                             if Ma == None:
   1676                                 continue
   1677                             if not Ma.IsLibrary:
   1678                                 ModuleList[Ma.Guid.upper()] = Ma
   1679 
   1680                     MapBuffer = StringIO('')
   1681                     if self.LoadFixAddress != 0:
   1682                         #

   1683                         # Rebase module to the preferred memory address before GenFds

   1684                         #

   1685                         self._CollectModuleMapBuffer(MapBuffer, ModuleList)
   1686                     if self.Fdf:
   1687                         #

   1688                         # create FDS again for the updated EFI image

   1689                         #

   1690                         self._Build("fds", Wa)
   1691                         #

   1692                         # Create MAP file for all platform FVs after GenFds.

   1693                         #

   1694                         self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
   1695                     #

   1696                     # Save MAP buffer into MAP file.

   1697                     #

   1698                     self._SaveMapFile (MapBuffer, Wa)
   1699 
   1700     ## Build active module for different build targets, different tool chains and different archs

   1701     #

   1702     def _BuildModule(self):
   1703         for BuildTarget in self.BuildTargetList:
   1704             GlobalData.gGlobalDefines['TARGET'] = BuildTarget
   1705             index = 0
   1706             for ToolChain in self.ToolChainList:
   1707                 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
   1708                 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
   1709                 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
   1710                 index += 1
   1711                 #

   1712                 # module build needs platform build information, so get platform

   1713                 # AutoGen first

   1714                 #

   1715                 Wa = WorkspaceAutoGen(
   1716                         self.WorkspaceDir,
   1717                         self.PlatformFile,
   1718                         BuildTarget,
   1719                         ToolChain,
   1720                         self.ArchList,
   1721                         self.BuildDatabase,
   1722                         self.TargetTxt,
   1723                         self.ToolDef,
   1724                         self.Fdf,
   1725                         self.FdList,
   1726                         self.FvList,
   1727                         self.CapList,
   1728                         self.SkuId,
   1729                         self.UniFlag,
   1730                         self.Progress,
   1731                         self.ModuleFile
   1732                         )
   1733                 self.Fdf = Wa.FdfFile
   1734                 self.LoadFixAddress = Wa.Platform.LoadFixAddress
   1735                 Wa.CreateMakeFile(False)
   1736                 self.Progress.Stop("done!")
   1737                 MaList = []
   1738                 for Arch in Wa.ArchList:
   1739                     GlobalData.gGlobalDefines['ARCH'] = Arch
   1740                     Ma = ModuleAutoGen(Wa, self.ModuleFile, BuildTarget, ToolChain, Arch, self.PlatformFile)
   1741                     if Ma == None: continue
   1742                     MaList.append(Ma)
   1743                     self.BuildModules.append(Ma)
   1744                     if not Ma.IsBinaryModule:
   1745                         self._Build(self.Target, Ma, BuildModule=True)
   1746 
   1747                 self.BuildReport.AddPlatformReport(Wa, MaList)
   1748                 if MaList == []:
   1749                     EdkLogger.error(
   1750                                 'build',
   1751                                 BUILD_ERROR,
   1752                                 "Module for [%s] is not a component of active platform."\
   1753                                 " Please make sure that the ARCH and inf file path are"\
   1754                                 " given in the same as in [%s]" % \
   1755                                     (', '.join(Wa.ArchList), self.PlatformFile),
   1756                                 ExtraData=self.ModuleFile
   1757                                 )
   1758                 # Create MAP file when Load Fix Address is enabled.

   1759                 if self.Target == "fds" and self.Fdf:
   1760                     for Arch in Wa.ArchList:
   1761                         #

   1762                         # Check whether the set fix address is above 4G for 32bit image.

   1763                         #

   1764                         if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
   1765                             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")
   1766                     #

   1767                     # Get Module List

   1768                     #

   1769                     ModuleList = {}
   1770                     for Pa in Wa.AutoGenObjectList:
   1771                         for Ma in Pa.ModuleAutoGenList:
   1772                             if Ma == None:
   1773                                 continue
   1774                             if not Ma.IsLibrary:
   1775                                 ModuleList[Ma.Guid.upper()] = Ma
   1776 
   1777                     MapBuffer = StringIO('')
   1778                     if self.LoadFixAddress != 0:
   1779                         #

   1780                         # Rebase module to the preferred memory address before GenFds

   1781                         #

   1782                         self._CollectModuleMapBuffer(MapBuffer, ModuleList)
   1783                     #

   1784                     # create FDS again for the updated EFI image

   1785                     #

   1786                     self._Build("fds", Wa)
   1787                     #

   1788                     # Create MAP file for all platform FVs after GenFds.

   1789                     #

   1790                     self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
   1791                     #

   1792                     # Save MAP buffer into MAP file.

   1793                     #

   1794                     self._SaveMapFile (MapBuffer, Wa)
   1795 
   1796     ## Build a platform in multi-thread mode

   1797     #

   1798     def _MultiThreadBuildPlatform(self):
   1799         SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)
   1800         for BuildTarget in self.BuildTargetList:
   1801             GlobalData.gGlobalDefines['TARGET'] = BuildTarget
   1802             index = 0
   1803             for ToolChain in self.ToolChainList:
   1804                 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
   1805                 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
   1806                 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
   1807                 index += 1
   1808                 Wa = WorkspaceAutoGen(
   1809                         self.WorkspaceDir,
   1810                         self.PlatformFile,
   1811                         BuildTarget,
   1812                         ToolChain,
   1813                         self.ArchList,
   1814                         self.BuildDatabase,
   1815                         self.TargetTxt,
   1816                         self.ToolDef,
   1817                         self.Fdf,
   1818                         self.FdList,
   1819                         self.FvList,
   1820                         self.CapList,
   1821                         self.SkuId,
   1822                         self.UniFlag,
   1823                         self.Progress
   1824                         )
   1825                 self.Fdf = Wa.FdfFile
   1826                 self.LoadFixAddress = Wa.Platform.LoadFixAddress
   1827                 self.BuildReport.AddPlatformReport(Wa)
   1828                 Wa.CreateMakeFile(False)
   1829 
   1830                 # multi-thread exit flag

   1831                 ExitFlag = threading.Event()
   1832                 ExitFlag.clear()
   1833                 for Arch in Wa.ArchList:
   1834                     GlobalData.gGlobalDefines['ARCH'] = Arch
   1835                     Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
   1836                     if Pa == None:
   1837                         continue
   1838                     ModuleList = []
   1839                     for Inf in Pa.Platform.Modules:
   1840                         ModuleList.append(Inf)
   1841                     # Add the INF only list in FDF

   1842                     if GlobalData.gFdfParser != None:
   1843                         for InfName in GlobalData.gFdfParser.Profile.InfList:
   1844                             Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)
   1845                             if Inf in Pa.Platform.Modules:
   1846                                 continue
   1847                             ModuleList.append(Inf)
   1848                     for Module in ModuleList:
   1849                         # Get ModuleAutoGen object to generate C code file and makefile

   1850                         Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
   1851                         
   1852                         if Ma == None:
   1853                             continue
   1854                         # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'

   1855                         if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
   1856                             # for target which must generate AutoGen code and makefile

   1857                             if not self.SkipAutoGen or self.Target == 'genc':
   1858                                 Ma.CreateCodeFile(True)
   1859                             if self.Target == "genc":
   1860                                 continue
   1861 
   1862                             if not self.SkipAutoGen or self.Target == 'genmake':
   1863                                 Ma.CreateMakeFile(True)
   1864                             if self.Target == "genmake":
   1865                                 continue
   1866                         self.BuildModules.append(Ma)
   1867                     self.Progress.Stop("done!")
   1868 
   1869                     for Ma in self.BuildModules:
   1870                         # Generate build task for the module

   1871                         if not Ma.IsBinaryModule:
   1872                             Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))
   1873                         # Break build if any build thread has error

   1874                         if BuildTask.HasError():
   1875                             # we need a full version of makefile for platform

   1876                             ExitFlag.set()
   1877                             BuildTask.WaitForComplete()
   1878                             Pa.CreateMakeFile(False)
   1879                             EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
   1880                         # Start task scheduler

   1881                         if not BuildTask.IsOnGoing():
   1882                             BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
   1883 
   1884                     # in case there's an interruption. we need a full version of makefile for platform

   1885                     Pa.CreateMakeFile(False)
   1886                     if BuildTask.HasError():
   1887                         EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
   1888 
   1889                 #

   1890                 # Save temp tables to a TmpTableDict.

   1891                 #

   1892                 for Key in Wa.BuildDatabase._CACHE_:
   1893                     if Wa.BuildDatabase._CACHE_[Key]._RawData and Wa.BuildDatabase._CACHE_[Key]._RawData._Table and Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table:
   1894                         if TemporaryTablePattern.match(Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table):
   1895                             TmpTableDict[Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table] = Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Cur
   1896                 #

   1897                 #

   1898                 # All modules have been put in build tasks queue. Tell task scheduler

   1899                 # to exit if all tasks are completed

   1900                 #

   1901                 ExitFlag.set()
   1902                 BuildTask.WaitForComplete()
   1903                 self.CreateAsBuiltInf()
   1904 
   1905                 #

   1906                 # Check for build error, and raise exception if one

   1907                 # has been signaled.

   1908                 #

   1909                 if BuildTask.HasError():
   1910                     EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
   1911 
   1912                 # Create MAP file when Load Fix Address is enabled.

   1913                 if self.Target in ["", "all", "fds"]:
   1914                     for Arch in Wa.ArchList:
   1915                         #

   1916                         # Check whether the set fix address is above 4G for 32bit image.

   1917                         #

   1918                         if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
   1919                             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")
   1920                     #

   1921                     # Get Module List

   1922                     #

   1923                     ModuleList = {}
   1924                     for Pa in Wa.AutoGenObjectList:
   1925                         for Ma in Pa.ModuleAutoGenList:
   1926                             if Ma == None:
   1927                                 continue
   1928                             if not Ma.IsLibrary:
   1929                                 ModuleList[Ma.Guid.upper()] = Ma
   1930                     #

   1931                     # Rebase module to the preferred memory address before GenFds

   1932                     #

   1933                     MapBuffer = StringIO('')
   1934                     if self.LoadFixAddress != 0:
   1935                         self._CollectModuleMapBuffer(MapBuffer, ModuleList)
   1936 
   1937                     if self.Fdf:
   1938                         #

   1939                         # Generate FD image if there's a FDF file found

   1940                         #

   1941                         LaunchCommand(Wa.GenFdsCommand, os.getcwd())
   1942 
   1943                         #

   1944                         # Create MAP file for all platform FVs after GenFds.

   1945                         #

   1946                         self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
   1947                     #

   1948                     # Save MAP buffer into MAP file.

   1949                     #

   1950                     self._SaveMapFile(MapBuffer, Wa)
   1951 
   1952     ## Generate GuidedSectionTools.txt in the FV directories.

   1953     #

   1954     def CreateGuidedSectionToolsFile(self):
   1955         for BuildTarget in self.BuildTargetList:
   1956             for ToolChain in self.ToolChainList:
   1957                 Wa = WorkspaceAutoGen(
   1958                         self.WorkspaceDir,
   1959                         self.PlatformFile,
   1960                         BuildTarget,
   1961                         ToolChain,
   1962                         self.ArchList,
   1963                         self.BuildDatabase,
   1964                         self.TargetTxt,
   1965                         self.ToolDef,
   1966                         self.Fdf,
   1967                         self.FdList,
   1968                         self.FvList,
   1969                         self.CapList,
   1970                         self.SkuId,
   1971                         self.UniFlag
   1972                         )
   1973                 FvDir = Wa.FvDir
   1974                 if not os.path.exists(FvDir):
   1975                     continue
   1976 
   1977                 for Arch in self.ArchList:
   1978                     # Build up the list of supported architectures for this build

   1979                     prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)
   1980 
   1981                     # Look through the tool definitions for GUIDed tools

   1982                     guidAttribs = []
   1983                     for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():
   1984                         if attrib.upper().endswith('_GUID'):
   1985                             split = attrib.split('_')
   1986                             thisPrefix = '_'.join(split[0:3]) + '_'
   1987                             if thisPrefix == prefix:
   1988                                 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]
   1989                                 guid = guid.lower()
   1990                                 toolName = split[3]
   1991                                 path = '_'.join(split[0:4]) + '_PATH'
   1992                                 path = self.ToolDef.ToolsDefTxtDictionary[path]
   1993                                 path = self.GetFullPathOfTool(path)
   1994                                 guidAttribs.append((guid, toolName, path))
   1995 
   1996                     # Write out GuidedSecTools.txt

   1997                     toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')
   1998                     toolsFile = open(toolsFile, 'wt')
   1999                     for guidedSectionTool in guidAttribs:
   2000                         print >> toolsFile, ' '.join(guidedSectionTool)
   2001                     toolsFile.close()
   2002 
   2003     ## Returns the full path of the tool.

   2004     #

   2005     def GetFullPathOfTool (self, tool):
   2006         if os.path.exists(tool):
   2007             return os.path.realpath(tool)
   2008         else:
   2009             # We need to search for the tool using the

   2010             # PATH environment variable.

   2011             for dirInPath in os.environ['PATH'].split(os.pathsep):
   2012                 foundPath = os.path.join(dirInPath, tool)
   2013                 if os.path.exists(foundPath):
   2014                     return os.path.realpath(foundPath)
   2015 
   2016         # If the tool was not found in the path then we just return

   2017         # the input tool.

   2018         return tool
   2019 
   2020     ## Launch the module or platform build

   2021     #

   2022     def Launch(self):
   2023         if not self.ModuleFile:
   2024             if not self.SpawnMode or self.Target not in ["", "all"]:
   2025                 self.SpawnMode = False
   2026                 self._BuildPlatform()
   2027             else:
   2028                 self._MultiThreadBuildPlatform()
   2029             self.CreateGuidedSectionToolsFile()
   2030         else:
   2031             self.SpawnMode = False
   2032             self._BuildModule()
   2033 
   2034         if self.Target == 'cleanall':
   2035             self.Db.Close()
   2036             RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)
   2037 
   2038     def CreateAsBuiltInf(self):
   2039         for Module in self.BuildModules:
   2040             Module.CreateAsBuiltInf()
   2041         self.BuildModules = []
   2042     ## Do some clean-up works when error occurred

   2043     def Relinquish(self):
   2044         OldLogLevel = EdkLogger.GetLevel()
   2045         EdkLogger.SetLevel(EdkLogger.ERROR)
   2046         #self.DumpBuildData()

   2047         Utils.Progressor.Abort()
   2048         if self.SpawnMode == True:
   2049             BuildTask.Abort()
   2050         EdkLogger.SetLevel(OldLogLevel)
   2051 
   2052     def DumpBuildData(self):
   2053         CacheDirectory = os.path.dirname(GlobalData.gDatabasePath)
   2054         Utils.CreateDirectory(CacheDirectory)
   2055         Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))
   2056         Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))
   2057 
   2058     def RestoreBuildData(self):
   2059         FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gFileTimeStampCache")
   2060         if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):
   2061             Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)
   2062             if Utils.gFileTimeStampCache == None:
   2063                 Utils.gFileTimeStampCache = {}
   2064 
   2065         FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gDependencyDatabase")
   2066         if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):
   2067             Utils.gDependencyDatabase = Utils.DataRestore(FilePath)
   2068             if Utils.gDependencyDatabase == None:
   2069                 Utils.gDependencyDatabase = {}
   2070 
   2071 def ParseDefines(DefineList=[]):
   2072     DefineDict = {}
   2073     if DefineList != None:
   2074         for Define in DefineList:
   2075             DefineTokenList = Define.split("=", 1)
   2076             if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):
   2077                 EdkLogger.error('build', FORMAT_INVALID,
   2078                                 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
   2079                                 ExtraData=DefineTokenList[0])
   2080 
   2081             if len(DefineTokenList) == 1:
   2082                 DefineDict[DefineTokenList[0]] = "TRUE"
   2083             else:
   2084                 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()
   2085     return DefineDict
   2086 
   2087 gParamCheck = []
   2088 def SingleCheckCallback(option, opt_str, value, parser):
   2089     if option not in gParamCheck:
   2090         setattr(parser.values, option.dest, value)
   2091         gParamCheck.append(option)
   2092     else:
   2093         parser.error("Option %s only allows one instance in command line!" % option)
   2094 
   2095 ## Parse command line options

   2096 #

   2097 # Using standard Python module optparse to parse command line option of this tool.

   2098 #

   2099 #   @retval Opt   A optparse.Values object containing the parsed options

   2100 #   @retval Args  Target of build command

   2101 #

   2102 def MyOptionParser():
   2103     Parser = OptionParser(description=__copyright__, version=__version__, prog="build.exe", usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
   2104     Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32', 'X64', 'IPF', 'EBC', 'ARM', 'AARCH64'], dest="TargetArch",
   2105         help="ARCHS is one of list: IA32, X64, IPF, ARM, AARCH64 or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.")
   2106     Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,
   2107         help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
   2108     Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,
   2109         help="Build the module specified by the INF file name argument.")
   2110     Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
   2111                       action="append")
   2112     Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",
   2113         help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
   2114     Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,
   2115         help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
   2116 
   2117     Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,
   2118         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.")
   2119 
   2120     Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,
   2121         help="The name of the FDF file to use, which overrides the setting in the DSC file.")
   2122     Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],
   2123         help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
   2124     Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],
   2125         help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
   2126     Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],
   2127         help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
   2128     Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")
   2129     Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")
   2130 
   2131     Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.")
   2132 
   2133     Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")
   2134     Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")
   2135 
   2136     Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",
   2137         help="Make use of silent mode of (n)make.")
   2138     Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
   2139     Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
   2140                                                                                "including library instances selected, final dependency expression, "\
   2141                                                                                "and warning messages, etc.")
   2142     Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
   2143     Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
   2144 
   2145     Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")
   2146     Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD','LIBRARY','FLASH','DEPEX','BUILD_FLAGS','FIXED_ADDRESS','HASH','EXECUTION_ORDER'], dest="ReportType", default=[],
   2147         help="Flags that control the type of build report to generate.  Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, HASH, EXECUTION_ORDER].  "\
   2148              "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]")
   2149     Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",
   2150         help="Specify the specific option to parse EDK UNI file. Must be one of: [-c, -s]. -c is for EDK framework UNI file, and -s is for EDK UEFI UNI file. "\
   2151              "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
   2152              "will override the setting in [BuildOptions] section of platform DSC.")
   2153     Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism")
   2154     Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")
   2155     Parser.add_option("--check-usage", action="store_true", dest="CheckUsage", default=False, help="Check usage content of entries listed in INF file.")
   2156     Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")
   2157     Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
   2158     Parser.add_option("-l", "--cmd-len", action="store", type="int", dest="CommandLength", help="Specify the maximum line length of build command. Default is 4096.")
   2159 
   2160     (Opt, Args) = Parser.parse_args()
   2161     return (Opt, Args)
   2162 
   2163 ## Tool entrance method

   2164 #

   2165 # This method mainly dispatch specific methods per the command line options.

   2166 # If no error found, return zero value so the caller of this tool can know

   2167 # if it's executed successfully or not.

   2168 #

   2169 #   @retval 0     Tool was successful

   2170 #   @retval 1     Tool failed

   2171 #

   2172 def Main():
   2173     StartTime = time.time()
   2174 
   2175     # Initialize log system

   2176     EdkLogger.Initialize()
   2177     GlobalData.gCommand = sys.argv[1:]
   2178     #

   2179     # Parse the options and args

   2180     #

   2181     (Option, Target) = MyOptionParser()
   2182     GlobalData.gOptions = Option
   2183     GlobalData.gCaseInsensitive = Option.CaseInsensitive
   2184 
   2185     # Set log level

   2186     if Option.verbose != None:
   2187         EdkLogger.SetLevel(EdkLogger.VERBOSE)
   2188     elif Option.quiet != None:
   2189         EdkLogger.SetLevel(EdkLogger.QUIET)
   2190     elif Option.debug != None:
   2191         EdkLogger.SetLevel(Option.debug + 1)
   2192     else:
   2193         EdkLogger.SetLevel(EdkLogger.INFO)
   2194 
   2195     if Option.LogFile != None:
   2196         EdkLogger.SetLogFile(Option.LogFile)
   2197 
   2198     if Option.WarningAsError == True:
   2199         EdkLogger.SetWarningAsError()
   2200 
   2201     if platform.platform().find("Windows") >= 0:
   2202         GlobalData.gIsWindows = True
   2203     else:
   2204         GlobalData.gIsWindows = False
   2205 
   2206     EdkLogger.quiet("Build environment: %s" % platform.platform())
   2207     EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));
   2208     ReturnCode = 0
   2209     MyBuild = None
   2210     BuildError = True
   2211     try:
   2212         if len(Target) == 0:
   2213             Target = "all"
   2214         elif len(Target) >= 2:
   2215             EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",
   2216                             ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))
   2217         else:
   2218             Target = Target[0].lower()
   2219 
   2220         if Target not in gSupportedTarget:
   2221             EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,
   2222                             ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))
   2223 
   2224         #

   2225         # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH

   2226         #

   2227         CheckEnvVariable()
   2228         GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))
   2229 
   2230         Workspace = os.getenv("WORKSPACE")
   2231         #

   2232         # Get files real name in workspace dir

   2233         #

   2234         GlobalData.gAllFiles = Utils.DirCache(Workspace)
   2235 
   2236         WorkingDirectory = os.getcwd()
   2237         if not Option.ModuleFile:
   2238             FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))
   2239             FileNum = len(FileList)
   2240             if FileNum >= 2:
   2241                 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),
   2242                                 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")
   2243             elif FileNum == 1:
   2244                 Option.ModuleFile = NormFile(FileList[0], Workspace)
   2245 
   2246         if Option.ModuleFile:
   2247             if os.path.isabs (Option.ModuleFile):
   2248                 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:
   2249                     Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)
   2250             Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)
   2251             ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)
   2252             if ErrorCode != 0:
   2253                 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
   2254 
   2255         if Option.PlatformFile != None:
   2256             if os.path.isabs (Option.PlatformFile):
   2257                 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:
   2258                     Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)
   2259             Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)
   2260 
   2261         if Option.FdfFile != None:
   2262             if os.path.isabs (Option.FdfFile):
   2263                 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:
   2264                     Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)
   2265             Option.FdfFile = PathClass(Option.FdfFile, Workspace)
   2266             ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)
   2267             if ErrorCode != 0:
   2268                 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
   2269 
   2270         if Option.Flag != None and Option.Flag not in ['-c', '-s']:
   2271             EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")
   2272 
   2273         MyBuild = Build(Target, Workspace, Option)
   2274         GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)
   2275         if not (MyBuild.LaunchPrebuildFlag and os.path.exists(MyBuild.PlatformBuildPath)):
   2276             MyBuild.Launch()
   2277         # Drop temp tables to avoid database locked.

   2278         for TmpTableName in TmpTableDict:
   2279             SqlCommand = """drop table IF EXISTS %s""" % TmpTableName
   2280             TmpTableDict[TmpTableName].execute(SqlCommand)
   2281         #MyBuild.DumpBuildData()

   2282         #

   2283         # All job done, no error found and no exception raised

   2284         #

   2285         BuildError = False
   2286     except FatalError, X:
   2287         if MyBuild != None:
   2288             # for multi-thread build exits safely

   2289             MyBuild.Relinquish()
   2290         if Option != None and Option.debug != None:
   2291             EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
   2292         ReturnCode = X.args[0]
   2293     except Warning, X:
   2294         # error from Fdf parser

   2295         if MyBuild != None:
   2296             # for multi-thread build exits safely

   2297             MyBuild.Relinquish()
   2298         if Option != None and Option.debug != None:
   2299             EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
   2300         else:
   2301             EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)
   2302         ReturnCode = FORMAT_INVALID
   2303     except KeyboardInterrupt:
   2304         ReturnCode = ABORT_ERROR
   2305         if Option != None and Option.debug != None:
   2306             EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
   2307     except:
   2308         if MyBuild != None:
   2309             # for multi-thread build exits safely

   2310             MyBuild.Relinquish()
   2311 
   2312         # try to get the meta-file from the object causing exception

   2313         Tb = sys.exc_info()[-1]
   2314         MetaFile = GlobalData.gProcessingFile
   2315         while Tb != None:
   2316             if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):
   2317                 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile
   2318             Tb = Tb.tb_next
   2319         EdkLogger.error(
   2320                     "\nbuild",
   2321                     CODE_ERROR,
   2322                     "Unknown fatal error when processing [%s]" % MetaFile,
   2323                     ExtraData="\n(Please send email to edk2-devel (at] lists.01.org for help, attaching following call stack trace!)\n",
   2324                     RaiseError=False
   2325                     )
   2326         EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
   2327         ReturnCode = CODE_ERROR
   2328     finally:
   2329         Utils.Progressor.Abort()
   2330         Utils.ClearDuplicatedInf()
   2331 
   2332     if ReturnCode == 0:
   2333         try:
   2334             MyBuild.LanuchPostbuild()
   2335             Conclusion = "Done"
   2336         except:
   2337             Conclusion = "Failed"
   2338     elif ReturnCode == ABORT_ERROR:
   2339         Conclusion = "Aborted"
   2340     else:
   2341         Conclusion = "Failed"
   2342     FinishTime = time.time()
   2343     BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))
   2344     BuildDurationStr = ""
   2345     if BuildDuration.tm_yday > 1:
   2346         BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)" % (BuildDuration.tm_yday - 1)
   2347     else:
   2348         BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)
   2349     if MyBuild != None:
   2350         if not BuildError:
   2351             MyBuild.BuildReport.GenerateReport(BuildDurationStr)
   2352         MyBuild.Db.Close()
   2353     EdkLogger.SetLevel(EdkLogger.QUIET)
   2354     EdkLogger.quiet("\n- %s -" % Conclusion)
   2355     EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))
   2356     EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)
   2357     return ReturnCode
   2358 
   2359 if __name__ == '__main__':
   2360     r = Main()
   2361     ## 0-127 is a safe return range, and 1 is a standard default error

   2362     if r < 0 or r > 127: r = 1
   2363     sys.exit(r)
   2364 
   2365