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 - 2015, 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 
     29 from struct import *
     30 from threading import *
     31 from optparse import OptionParser
     32 from subprocess import *
     33 from Common import Misc as Utils
     34 
     35 from Common.LongFilePathSupport import OpenLongFilePath as open
     36 from Common.LongFilePathSupport import LongFilePath
     37 from Common.TargetTxtClassObject import *
     38 from Common.ToolDefClassObject import *
     39 from Common.DataType import *
     40 from Common.BuildVersion import gBUILD_VERSION
     41 from AutoGen.AutoGen import *
     42 from Common.BuildToolError import *
     43 from Workspace.WorkspaceDatabase import *
     44 from Common.MultipleWorkspace import MultipleWorkspace as mws
     45 
     46 from BuildReport import BuildReport
     47 from GenPatchPcdTable.GenPatchPcdTable import *
     48 from PatchPcdValue.PatchPcdValue import *
     49 
     50 import Common.EdkLogger
     51 import Common.GlobalData as GlobalData
     52 
     53 # Version and Copyright

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

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

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

     69 #

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

     71 #   Otherwise, False is returned

     72 #

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

     85 #

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

     87 #

     88 #   WORKSPACE           The directory all packages/platforms start from

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

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

     91 #

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

     93 #   will be broken.

     94 #

     95 def CheckEnvVariable():
     96     # check WORKSPACE

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

    110     PackagesPath = os.getenv("PACKAGES_PATH")
    111     mws.setWs(WorkspaceDir, PackagesPath)
    112 
    113     #

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

    115     #

    116     if "ECP_SOURCE" not in os.environ:
    117         os.environ["ECP_SOURCE"] = mws.join(WorkspaceDir, GlobalData.gEdkCompatibilityPkg)
    118     if "EFI_SOURCE" not in os.environ:
    119         os.environ["EFI_SOURCE"] = os.environ["ECP_SOURCE"]
    120     if "EDK_SOURCE" not in os.environ:
    121         os.environ["EDK_SOURCE"] = os.environ["ECP_SOURCE"]
    122 
    123     #

    124     # Unify case of characters on case-insensitive systems

    125     #

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

    160     if not PackagesPath:
    161         # change absolute path to relative path to WORKSPACE

    162         if EfiSourceDir.upper().find(WorkspaceDir.upper()) != 0:
    163             EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE is not under WORKSPACE",
    164                             ExtraData="WORKSPACE = %s\n    EFI_SOURCE = %s" % (WorkspaceDir, EfiSourceDir))
    165         if EdkSourceDir.upper().find(WorkspaceDir.upper()) != 0:
    166             EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE is not under WORKSPACE",
    167                             ExtraData="WORKSPACE = %s\n    EDK_SOURCE = %s" % (WorkspaceDir, EdkSourceDir))
    168         if EcpSourceDir.upper().find(WorkspaceDir.upper()) != 0:
    169             EdkLogger.error("build", PARAMETER_INVALID, "ECP_SOURCE is not under WORKSPACE",
    170                             ExtraData="WORKSPACE = %s\n    ECP_SOURCE = %s" % (WorkspaceDir, EcpSourceDir))
    171 
    172     # check EDK_TOOLS_PATH

    173     if "EDK_TOOLS_PATH" not in os.environ:
    174         EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
    175                         ExtraData="EDK_TOOLS_PATH")
    176 
    177     # check PATH

    178     if "PATH" not in os.environ:
    179         EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
    180                         ExtraData="PATH")
    181 
    182     GlobalData.gWorkspace = WorkspaceDir
    183     GlobalData.gEfiSource = EfiSourceDir
    184     GlobalData.gEdkSource = EdkSourceDir
    185     GlobalData.gEcpSource = EcpSourceDir
    186 
    187     GlobalData.gGlobalDefines["WORKSPACE"]  = WorkspaceDir
    188     GlobalData.gGlobalDefines["EFI_SOURCE"] = EfiSourceDir
    189     GlobalData.gGlobalDefines["EDK_SOURCE"] = EdkSourceDir
    190     GlobalData.gGlobalDefines["ECP_SOURCE"] = EcpSourceDir
    191     GlobalData.gGlobalDefines["EDK_TOOLS_PATH"] = os.environ["EDK_TOOLS_PATH"]
    192     
    193 ## Get normalized file path

    194 #

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

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

    197 #

    198 # @param  FilePath      File path to be normalized

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

    200 #

    201 # @retval string        The normalized file path

    202 #

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

    205     if os.path.isabs(FilePath):
    206         FileFullPath = os.path.normpath(FilePath)
    207     else:
    208         FileFullPath = os.path.normpath(mws.join(Workspace, FilePath))
    209         Workspace = mws.getWs(Workspace, FilePath)
    210 
    211     # check if the file path exists or not

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

    216     if Workspace[-1] in ["\\", "/"]:
    217         return FileFullPath[len(Workspace):]
    218     else:
    219         return FileFullPath[(len(Workspace) + 1):]
    220 
    221 ## Get the output of an external program

    222 #

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

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

    225 #

    226 # @param  From      The stream message read from

    227 # @param  To        The stream message put on

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

    229 #

    230 def ReadMessage(From, To, ExitFlag):
    231     while True:
    232         # read one line a time

    233         Line = From.readline()
    234         # empty string means "end"

    235         if Line != None and Line != "":
    236             To(Line.rstrip())
    237         else:
    238             break
    239         if ExitFlag.isSet():
    240             break
    241 
    242 ## Launch an external program

    243 #

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

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

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

    247 # redirection work.

    248 #

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

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

    251 #

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

    254     if not os.path.isdir(WorkingDir):
    255         EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=WorkingDir)
    256     
    257     # Command is used as the first Argument in following Popen().

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

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

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

    261     if not isinstance(Command, list):
    262         if platform.system() != 'Windows':
    263             Command = Command.split()
    264 
    265     Proc = None
    266     EndOfProcedure = None
    267     try:
    268         # launch the command

    269         Proc = Popen(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir, bufsize=-1)
    270 
    271         # launch two threads to read the STDOUT and STDERR

    272         EndOfProcedure = Event()
    273         EndOfProcedure.clear()
    274         if Proc.stdout:
    275             StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure))
    276             StdOutThread.setName("STDOUT-Redirector")
    277             StdOutThread.setDaemon(False)
    278             StdOutThread.start()
    279 
    280         if Proc.stderr:
    281             StdErrThread = Thread(target=ReadMessage, args=(Proc.stderr, EdkLogger.quiet, EndOfProcedure))
    282             StdErrThread.setName("STDERR-Redirector")
    283             StdErrThread.setDaemon(False)
    284             StdErrThread.start()
    285 
    286         # waiting for program exit

    287         Proc.wait()
    288     except: # in case of aborting

    289         # terminate the threads redirecting the program output

    290         if EndOfProcedure != None:
    291             EndOfProcedure.set()
    292         if Proc == None:
    293             if type(Command) != type(""):
    294                 Command = " ".join(Command)
    295             EdkLogger.error("build", COMMAND_FAILURE, "Failed to start command", ExtraData="%s [%s]" % (Command, WorkingDir))
    296 
    297     if Proc.stdout:
    298         StdOutThread.join()
    299     if Proc.stderr:
    300         StdErrThread.join()
    301 
    302     # check the return code of the program

    303     if Proc.returncode != 0:
    304         if type(Command) != type(""):
    305             Command = " ".join(Command)
    306         EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir))
    307 
    308 ## The smallest unit that can be built in multi-thread build mode

    309 #

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

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

    312 # missing build.

    313 #

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

    315 #

    316 class BuildUnit:
    317     ## The constructor

    318     #

    319     #   @param  self        The object pointer

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

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

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

    323     #   @param  WorkingDir  The directory build command starts in

    324     #

    325     def __init__(self, Obj, BuildCommand, Target, Dependency, WorkingDir="."):
    326         self.BuildObject = Obj
    327         self.Dependency = Dependency
    328         self.WorkingDir = WorkingDir
    329         self.Target = Target
    330         self.BuildCommand = BuildCommand
    331         if not BuildCommand:
    332             EdkLogger.error("build", OPTION_MISSING,
    333                             "No build command found for this module. "
    334                             "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
    335                                 (Obj.BuildTarget, Obj.ToolChain, Obj.Arch),
    336                             ExtraData=str(Obj))
    337 
    338 
    339     ## str() method

    340     #

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

    342     #

    343     #   @param  self        The object pointer

    344     #

    345     def __str__(self):
    346         return str(self.BuildObject)
    347 
    348     ## "==" operator method

    349     #

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

    351     #   provide its own __eq__() method.

    352     #

    353     #   @param  self        The object pointer

    354     #   @param  Other       The other BuildUnit object compared to

    355     #

    356     def __eq__(self, Other):
    357         return Other != None and self.BuildObject == Other.BuildObject \
    358                 and self.BuildObject.Arch == Other.BuildObject.Arch
    359 
    360     ## hash() method

    361     #

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

    363     #

    364     #   @param  self        The object pointer

    365     #

    366     def __hash__(self):
    367         return hash(self.BuildObject) + hash(self.BuildObject.Arch)
    368 
    369     def __repr__(self):
    370         return repr(self.BuildObject)
    371 
    372 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode

    373 #

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

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

    376 # be make units missing build.

    377 #

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

    379 #

    380 class ModuleMakeUnit(BuildUnit):
    381     ## The constructor

    382     #

    383     #   @param  self        The object pointer

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

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

    386     #

    387     def __init__(self, Obj, Target):
    388         Dependency = [ModuleMakeUnit(La, Target) for La in Obj.LibraryAutoGenList]
    389         BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)
    390         if Target in [None, "", "all"]:
    391             self.Target = "tbuild"
    392 
    393 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode

    394 #

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

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

    397 # be make units missing build.

    398 #

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

    400 #

    401 class PlatformMakeUnit(BuildUnit):
    402     ## The constructor

    403     #

    404     #   @param  self        The object pointer

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

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

    407     #

    408     def __init__(self, Obj, Target):
    409         Dependency = [ModuleMakeUnit(Lib, Target) for Lib in self.BuildObject.LibraryAutoGenList]
    410         Dependency.extend([ModuleMakeUnit(Mod, Target) for Mod in self.BuildObject.ModuleAutoGenList])
    411         BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)
    412 
    413 ## The class representing the task of a module build or platform build

    414 #

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

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

    417 #

    418 class BuildTask:
    419     # queue for tasks waiting for schedule

    420     _PendingQueue = sdict()
    421     _PendingQueueLock = threading.Lock()
    422 
    423     # queue for tasks ready for running

    424     _ReadyQueue = sdict()
    425     _ReadyQueueLock = threading.Lock()
    426 
    427     # queue for run tasks

    428     _RunningQueue = sdict()
    429     _RunningQueueLock = threading.Lock()
    430 
    431     # queue containing all build tasks, in case duplicate build

    432     _TaskQueue = sdict()
    433 
    434     # flag indicating error occurs in a running thread

    435     _ErrorFlag = threading.Event()
    436     _ErrorFlag.clear()
    437     _ErrorMessage = ""
    438 
    439     # BoundedSemaphore object used to control the number of running threads

    440     _Thread = None
    441 
    442     # flag indicating if the scheduler is started or not

    443     _SchedulerStopped = threading.Event()
    444     _SchedulerStopped.set()
    445 
    446     ## Start the task scheduler thread

    447     #

    448     #   @param  MaxThreadNumber     The maximum thread number

    449     #   @param  ExitFlag            Flag used to end the scheduler

    450     #

    451     @staticmethod
    452     def StartScheduler(MaxThreadNumber, ExitFlag):
    453         SchedulerThread = Thread(target=BuildTask.Scheduler, args=(MaxThreadNumber, ExitFlag))
    454         SchedulerThread.setName("Build-Task-Scheduler")
    455         SchedulerThread.setDaemon(False)
    456         SchedulerThread.start()
    457         # wait for the scheduler to be started, especially useful in Linux

    458         while not BuildTask.IsOnGoing():
    459             time.sleep(0.01)
    460 
    461     ## Scheduler method

    462     #

    463     #   @param  MaxThreadNumber     The maximum thread number

    464     #   @param  ExitFlag            Flag used to end the scheduler

    465     #

    466     @staticmethod
    467     def Scheduler(MaxThreadNumber, ExitFlag):
    468         BuildTask._SchedulerStopped.clear()
    469         try:
    470             # use BoundedSemaphore to control the maximum running threads

    471             BuildTask._Thread = BoundedSemaphore(MaxThreadNumber)
    472             #

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

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

    475             #

    476             while (len(BuildTask._PendingQueue) > 0 or len(BuildTask._ReadyQueue) > 0 \
    477                    or not ExitFlag.isSet()) and not BuildTask._ErrorFlag.isSet():
    478                 EdkLogger.debug(EdkLogger.DEBUG_8, "Pending Queue (%d), Ready Queue (%d)"
    479                                 % (len(BuildTask._PendingQueue), len(BuildTask._ReadyQueue)))
    480 
    481                 # get all pending tasks

    482                 BuildTask._PendingQueueLock.acquire()
    483                 BuildObjectList = BuildTask._PendingQueue.keys()
    484                 #

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

    486                 # into ready queue

    487                 #

    488                 for BuildObject in BuildObjectList:
    489                     Bt = BuildTask._PendingQueue[BuildObject]
    490                     if Bt.IsReady():
    491                         BuildTask._ReadyQueue[BuildObject] = BuildTask._PendingQueue.pop(BuildObject)
    492                 BuildTask._PendingQueueLock.release()
    493 
    494                 # launch build thread until the maximum number of threads is reached

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

    497                     if len(BuildTask._ReadyQueue) == 0:
    498                         break
    499 
    500                     # wait for active thread(s) exit

    501                     BuildTask._Thread.acquire(True)
    502 
    503                     # start a new build thread

    504                     Bo = BuildTask._ReadyQueue.keys()[0]
    505                     Bt = BuildTask._ReadyQueue.pop(Bo)
    506 
    507                     # move into running queue

    508                     BuildTask._RunningQueueLock.acquire()
    509                     BuildTask._RunningQueue[Bo] = Bt
    510                     BuildTask._RunningQueueLock.release()
    511 
    512                     Bt.Start()
    513                     # avoid tense loop

    514                     time.sleep(0.01)
    515 
    516                 # avoid tense loop

    517                 time.sleep(0.01)
    518 
    519             # wait for all running threads exit

    520             if BuildTask._ErrorFlag.isSet():
    521                 EdkLogger.quiet("\nWaiting for all build threads exit...")
    522             # while not BuildTask._ErrorFlag.isSet() and \

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

    527                 time.sleep(0.1)
    528         except BaseException, X:
    529             #

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

    531             #        catch the error message easily

    532             #

    533             EdkLogger.SetLevel(EdkLogger.ERROR)
    534             BuildTask._ErrorFlag.set()
    535             BuildTask._ErrorMessage = "build thread scheduler error\n\t%s" % str(X)
    536 
    537         BuildTask._PendingQueue.clear()
    538         BuildTask._ReadyQueue.clear()
    539         BuildTask._RunningQueue.clear()
    540         BuildTask._TaskQueue.clear()
    541         BuildTask._SchedulerStopped.set()
    542 
    543     ## Wait for all running method exit

    544     #

    545     @staticmethod
    546     def WaitForComplete():
    547         BuildTask._SchedulerStopped.wait()
    548 
    549     ## Check if the scheduler is running or not

    550     #

    551     @staticmethod
    552     def IsOnGoing():
    553         return not BuildTask._SchedulerStopped.isSet()
    554 
    555     ## Abort the build

    556     @staticmethod
    557     def Abort():
    558         if BuildTask.IsOnGoing():
    559             BuildTask._ErrorFlag.set()
    560             BuildTask.WaitForComplete()
    561 
    562     ## Check if there's error in running thread

    563     #

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

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

    566     #

    567     @staticmethod
    568     def HasError():
    569         return BuildTask._ErrorFlag.isSet()
    570 
    571     ## Get error message in running thread

    572     #

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

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

    575     #

    576     @staticmethod
    577     def GetErrorMessage():
    578         return BuildTask._ErrorMessage
    579 
    580     ## Factory method to create a BuildTask object

    581     #

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

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

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

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

    586     #

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

    588     #   @param  Dependency      The dependent build object of BuildItem

    589     #

    590     @staticmethod
    591     def New(BuildItem, Dependency=None):
    592         if BuildItem in BuildTask._TaskQueue:
    593             Bt = BuildTask._TaskQueue[BuildItem]
    594             return Bt
    595 
    596         Bt = BuildTask()
    597         Bt._Init(BuildItem, Dependency)
    598         BuildTask._TaskQueue[BuildItem] = Bt
    599 
    600         BuildTask._PendingQueueLock.acquire()
    601         BuildTask._PendingQueue[BuildItem] = Bt
    602         BuildTask._PendingQueueLock.release()
    603 
    604         return Bt
    605 
    606     ## The real constructor of BuildTask

    607     #

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

    609     #   @param  Dependency      The dependent build object of BuildItem

    610     #

    611     def _Init(self, BuildItem, Dependency=None):
    612         self.BuildItem = BuildItem
    613 
    614         self.DependencyList = []
    615         if Dependency == None:
    616             Dependency = BuildItem.Dependency
    617         else:
    618             Dependency.extend(BuildItem.Dependency)
    619         self.AddDependency(Dependency)
    620         # flag indicating build completes, used to avoid unnecessary re-build

    621         self.CompleteFlag = False
    622 
    623     ## Check if all dependent build tasks are completed or not

    624     #

    625     def IsReady(self):
    626         ReadyFlag = True
    627         for Dep in self.DependencyList:
    628             if Dep.CompleteFlag == True:
    629                 continue
    630             ReadyFlag = False
    631             break
    632 
    633         return ReadyFlag
    634 
    635     ## Add dependent build task

    636     #

    637     #   @param  Dependency      The list of dependent build objects

    638     #

    639     def AddDependency(self, Dependency):
    640         for Dep in Dependency:
    641             if not Dep.BuildObject.IsBinaryModule:
    642                 self.DependencyList.append(BuildTask.New(Dep))    # BuildTask list

    643 
    644     ## The thread wrapper of LaunchCommand function

    645     #

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

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

    648     #

    649     def _CommandThread(self, Command, WorkingDir):
    650         try:
    651             LaunchCommand(Command, WorkingDir)
    652             self.CompleteFlag = True
    653         except:
    654             #

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

    656             #        catch the error message easily

    657             #

    658             if not BuildTask._ErrorFlag.isSet():
    659                 GlobalData.gBuildingModule = "%s [%s, %s, %s]" % (str(self.BuildItem.BuildObject),
    660                                                                   self.BuildItem.BuildObject.Arch,
    661                                                                   self.BuildItem.BuildObject.ToolChain,
    662                                                                   self.BuildItem.BuildObject.BuildTarget
    663                                                                  )
    664             EdkLogger.SetLevel(EdkLogger.ERROR)
    665             BuildTask._ErrorFlag.set()
    666             BuildTask._ErrorMessage = "%s broken\n    %s [%s]" % \
    667                                       (threading.currentThread().getName(), Command, WorkingDir)
    668         # indicate there's a thread is available for another build task

    669         BuildTask._RunningQueueLock.acquire()
    670         BuildTask._RunningQueue.pop(self.BuildItem)
    671         BuildTask._RunningQueueLock.release()
    672         BuildTask._Thread.release()
    673 
    674     ## Start build task thread

    675     #

    676     def Start(self):
    677         EdkLogger.quiet("Building ... %s" % repr(self.BuildItem))
    678         Command = self.BuildItem.BuildCommand + [self.BuildItem.Target]
    679         self.BuildTread = Thread(target=self._CommandThread, args=(Command, self.BuildItem.WorkingDir))
    680         self.BuildTread.setName("build thread")
    681         self.BuildTread.setDaemon(False)
    682         self.BuildTread.start()
    683 
    684 ## The class contains the information related to EFI image

    685 #

    686 class PeImageInfo():
    687     ## Constructor

    688     #

    689     # Constructor will load all required image information.

    690     #

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

    692     #   @param  Guid              The GUID for image.

    693     #   @param  Arch              Arch of this image.

    694     #   @param  OutputDir         The output directory for image.

    695     #   @param  DebugDir          The debug directory for image.

    696     #   @param  ImageClass        PeImage Information

    697     #

    698     def __init__(self, BaseName, Guid, Arch, OutputDir, DebugDir, ImageClass):
    699         self.BaseName         = BaseName
    700         self.Guid             = Guid
    701         self.Arch             = Arch
    702         self.OutputDir        = OutputDir
    703         self.DebugDir         = DebugDir
    704         self.Image            = ImageClass
    705         self.Image.Size       = (self.Image.Size / 0x1000 + 1) * 0x1000
    706 
    707 ## The class implementing the EDK2 build process

    708 #

    709 #   The build process includes:

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

    711 #       2. Parse DSC file of active platform

    712 #       3. Parse FDF file if any

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

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

    715 #       6. Call build command

    716 #

    717 class Build():
    718     ## Constructor

    719     #

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

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

    722     #

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

    724     #   @param  WorkspaceDir        The directory of workspace

    725     #   @param  BuildOptions        Build options passed from command line

    726     #

    727     def __init__(self, Target, WorkspaceDir, BuildOptions):
    728         self.WorkspaceDir   = WorkspaceDir
    729         self.Target         = Target
    730         self.PlatformFile   = BuildOptions.PlatformFile
    731         self.ModuleFile     = BuildOptions.ModuleFile
    732         self.ArchList       = BuildOptions.TargetArch
    733         self.ToolChainList  = BuildOptions.ToolChain
    734         self.BuildTargetList= BuildOptions.BuildTarget
    735         self.Fdf            = BuildOptions.FdfFile
    736         self.FdList         = BuildOptions.RomImage
    737         self.FvList         = BuildOptions.FvImage
    738         self.CapList        = BuildOptions.CapName
    739         self.SilentMode     = BuildOptions.SilentMode
    740         self.ThreadNumber   = BuildOptions.ThreadNumber
    741         self.SkipAutoGen    = BuildOptions.SkipAutoGen
    742         self.Reparse        = BuildOptions.Reparse
    743         self.SkuId          = BuildOptions.SkuId
    744         self.ConfDirectory = BuildOptions.ConfDirectory
    745         self.SpawnMode      = True
    746         self.BuildReport    = BuildReport(BuildOptions.ReportFile, BuildOptions.ReportType)
    747         self.TargetTxt      = TargetTxtClassObject()
    748         self.ToolDef        = ToolDefClassObject()
    749         #Set global flag for build mode

    750         GlobalData.gIgnoreSource = BuildOptions.IgnoreSources
    751 
    752         if self.ConfDirectory:
    753             # Get alternate Conf location, if it is absolute, then just use the absolute directory name

    754             ConfDirectoryPath = os.path.normpath(self.ConfDirectory)
    755 
    756             if not os.path.isabs(ConfDirectoryPath):
    757                 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE

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

    759                 ConfDirectoryPath = mws.join(self.WorkspaceDir, ConfDirectoryPath)
    760         else:
    761             # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf

    762             ConfDirectoryPath = mws.join(self.WorkspaceDir, 'Conf')
    763         GlobalData.gConfDirectory = ConfDirectoryPath
    764         GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath))
    765 
    766         if BuildOptions.DisableCache:
    767             self.Db         = WorkspaceDatabase(":memory:")
    768         else:
    769             self.Db = WorkspaceDatabase(GlobalData.gDatabasePath, self.Reparse)
    770         self.BuildDatabase = self.Db.BuildObject
    771         self.Platform = None
    772         self.LoadFixAddress = 0
    773         self.UniFlag        = BuildOptions.Flag
    774         self.BuildModules = []
    775 
    776         # print dot character during doing some time-consuming work

    777         self.Progress = Utils.Progressor()
    778 
    779         self.InitBuild()
    780 
    781         # print current build environment and configuration

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

    785             EdkLogger.quiet("%-16s = %s" % ("PACKAGES_PATH", os.path.normcase(os.path.normpath(os.environ["PACKAGES_PATH"]))))
    786         EdkLogger.quiet("%-16s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"]))
    787         EdkLogger.quiet("%-16s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"]))
    788         EdkLogger.quiet("%-16s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"]))
    789         EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))
    790         if "EDK_TOOLS_BIN" in os.environ:
    791             # Print the same path style with WORKSPACE env. 

    792             EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os.path.normcase(os.path.normpath(os.environ["EDK_TOOLS_BIN"]))))
    793 
    794         EdkLogger.info("")
    795 
    796         os.chdir(self.WorkspaceDir)
    797 
    798     ## Load configuration

    799     #

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

    801     #

    802     def LoadConfiguration(self):
    803         #

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

    805         #

    806         BuildConfigurationFile = os.path.normpath(os.path.join(GlobalData.gConfDirectory, gBuildConfiguration))
    807         if os.path.isfile(BuildConfigurationFile) == True:
    808             StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)
    809 
    810             ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]
    811             if ToolDefinitionFile == '':
    812                 ToolDefinitionFile = gToolsDefinition
    813                 ToolDefinitionFile = os.path.normpath(mws.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile))
    814             if os.path.isfile(ToolDefinitionFile) == True:
    815                 StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)
    816             else:
    817                 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)
    818         else:
    819             EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)
    820 
    821         # if no ARCH given in command line, get it from target.txt

    822         if not self.ArchList:
    823             self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH]
    824         self.ArchList = tuple(self.ArchList)
    825 
    826         # if no build target given in command line, get it from target.txt

    827         if not self.BuildTargetList:
    828             self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]
    829 
    830         # if no tool chain given in command line, get it from target.txt

    831         if not self.ToolChainList:
    832             self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]
    833             if self.ToolChainList == None or len(self.ToolChainList) == 0:
    834                 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")
    835 
    836         # check if the tool chains are defined or not

    837         NewToolChainList = []
    838         for ToolChain in self.ToolChainList:
    839             if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:
    840                 EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)
    841             else:
    842                 NewToolChainList.append(ToolChain)
    843         # if no tool chain available, break the build

    844         if len(NewToolChainList) == 0:
    845             EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
    846                             ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))
    847         else:
    848             self.ToolChainList = NewToolChainList
    849 
    850         if self.ThreadNumber == None:
    851             self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]
    852             if self.ThreadNumber == '':
    853                 self.ThreadNumber = 0
    854             else:
    855                 self.ThreadNumber = int(self.ThreadNumber, 0)
    856 
    857         if self.ThreadNumber == 0:
    858             self.ThreadNumber = 1
    859 
    860         if not self.PlatformFile:
    861             PlatformFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM]
    862             if not PlatformFile:
    863                 # Try to find one in current directory

    864                 WorkingDirectory = os.getcwd()
    865                 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))
    866                 FileNum = len(FileList)
    867                 if FileNum >= 2:
    868                     EdkLogger.error("build", OPTION_MISSING,
    869                                     ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))
    870                 elif FileNum == 1:
    871                     PlatformFile = FileList[0]
    872                 else:
    873                     EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
    874                                     ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")
    875 
    876             self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)
    877 
    878     ## Initialize build configuration

    879     #

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

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

    882     #

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

    885         self.LoadConfiguration()
    886 
    887         # Allow case-insensitive for those from command line or configuration file

    888         ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)
    889         if ErrorCode != 0:
    890             EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
    891 
    892         # create metafile database

    893         self.Db.InitDatabase()
    894 
    895     ## Build a module or platform

    896     #

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

    898     # "make" command to build it

    899     #

    900     #   @param  Target                      The target of build command

    901     #   @param  Platform                    The platform file

    902     #   @param  Module                      The module file

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

    904     #   @param  ToolChain                   The name of toolchain to build

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

    906     #   @param  CreateDepModuleCodeFile     Flag used to indicate creating code

    907     #                                       for dependent modules/Libraries

    908     #   @param  CreateDepModuleMakeFile     Flag used to indicate creating makefile

    909     #                                       for dependent modules/Libraries

    910     #

    911     def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):
    912         if AutoGenObject == None:
    913             return False
    914 
    915         # skip file generation for cleanxxx targets, run and fds target

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

    918             if not self.SkipAutoGen or Target == 'genc':
    919                 self.Progress.Start("Generating code")
    920                 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
    921                 self.Progress.Stop("done!")
    922             if Target == "genc":
    923                 return True
    924 
    925             if not self.SkipAutoGen or Target == 'genmake':
    926                 self.Progress.Start("Generating makefile")
    927                 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)
    928                 self.Progress.Stop("done!")
    929             if Target == "genmake":
    930                 return True
    931         else:
    932             # always recreate top/platform makefile when clean, just in case of inconsistency

    933             AutoGenObject.CreateCodeFile(False)
    934             AutoGenObject.CreateMakeFile(False)
    935 
    936         if EdkLogger.GetLevel() == EdkLogger.QUIET:
    937             EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
    938 
    939         BuildCommand = AutoGenObject.BuildCommand
    940         if BuildCommand == None or len(BuildCommand) == 0:
    941             EdkLogger.error("build", OPTION_MISSING,
    942                             "No build command found for this module. "
    943                             "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
    944                                 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
    945                             ExtraData=str(AutoGenObject))
    946 
    947         makefile = GenMake.BuildFile(AutoGenObject)._FILE_NAME_[GenMake.gMakeType]
    948 
    949         # run

    950         if Target == 'run':
    951             RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))
    952             Command = '.\SecMain'
    953             os.chdir(RunDir)
    954             LaunchCommand(Command, RunDir)
    955             return True
    956 
    957         # build modules

    958         if BuildModule:
    959             BuildCommand = BuildCommand + [Target]
    960             LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
    961             self.CreateAsBuiltInf()
    962             return True
    963 
    964         # build library

    965         if Target == 'libraries':
    966             for Lib in AutoGenObject.LibraryBuildDirectoryList:
    967                 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']
    968                 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
    969             return True
    970 
    971         # build module

    972         if Target == 'modules':
    973             for Lib in AutoGenObject.LibraryBuildDirectoryList:
    974                 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']
    975                 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
    976             for Mod in AutoGenObject.ModuleBuildDirectoryList:
    977                 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']
    978                 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
    979             self.CreateAsBuiltInf()
    980             return True
    981 
    982         # cleanlib

    983         if Target == 'cleanlib':
    984             for Lib in AutoGenObject.LibraryBuildDirectoryList:
    985                 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))
    986                 if os.path.exists(LibMakefile):
    987                     NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
    988                     LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
    989             return True
    990 
    991         # clean

    992         if Target == 'clean':
    993             for Mod in AutoGenObject.ModuleBuildDirectoryList:
    994                 ModMakefile = os.path.normpath(os.path.join(Mod, makefile))
    995                 if os.path.exists(ModMakefile):
    996                     NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']
    997                     LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
    998             for Lib in AutoGenObject.LibraryBuildDirectoryList:
    999                 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))
   1000                 if os.path.exists(LibMakefile):
   1001                     NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
   1002                     LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
   1003             return True
   1004 
   1005         # cleanall

   1006         if Target == 'cleanall':
   1007             try:
   1008                 #os.rmdir(AutoGenObject.BuildDir)

   1009                 RemoveDirectory(AutoGenObject.BuildDir, True)
   1010             except WindowsError, X:
   1011                 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
   1012         return True
   1013 
   1014     ## Build a module or platform

   1015     #

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

   1017     # "make" command to build it

   1018     #

   1019     #   @param  Target                      The target of build command

   1020     #   @param  Platform                    The platform file

   1021     #   @param  Module                      The module file

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

   1023     #   @param  ToolChain                   The name of toolchain to build

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

   1025     #   @param  CreateDepModuleCodeFile     Flag used to indicate creating code

   1026     #                                       for dependent modules/Libraries

   1027     #   @param  CreateDepModuleMakeFile     Flag used to indicate creating makefile

   1028     #                                       for dependent modules/Libraries

   1029     #

   1030     def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):
   1031         if AutoGenObject == None:
   1032             return False
   1033 
   1034         # skip file generation for cleanxxx targets, run and fds target

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

   1037             if not self.SkipAutoGen or Target == 'genc':
   1038                 self.Progress.Start("Generating code")
   1039                 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
   1040                 self.Progress.Stop("done!")
   1041             if Target == "genc":
   1042                 return True
   1043 
   1044             if not self.SkipAutoGen or Target == 'genmake':
   1045                 self.Progress.Start("Generating makefile")
   1046                 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)
   1047                 #AutoGenObject.CreateAsBuiltInf()

   1048                 self.Progress.Stop("done!")
   1049             if Target == "genmake":
   1050                 return True
   1051         else:
   1052             # always recreate top/platform makefile when clean, just in case of inconsistency

   1053             AutoGenObject.CreateCodeFile(False)
   1054             AutoGenObject.CreateMakeFile(False)
   1055 
   1056         if EdkLogger.GetLevel() == EdkLogger.QUIET:
   1057             EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
   1058 
   1059         BuildCommand = AutoGenObject.BuildCommand
   1060         if BuildCommand == None or len(BuildCommand) == 0:
   1061             EdkLogger.error("build", OPTION_MISSING,
   1062                             "No build command found for this module. "
   1063                             "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
   1064                                 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
   1065                             ExtraData=str(AutoGenObject))
   1066 
   1067         # build modules

   1068         if BuildModule:
   1069             if Target != 'fds':
   1070                 BuildCommand = BuildCommand + [Target]
   1071             LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
   1072             self.CreateAsBuiltInf()
   1073             return True
   1074 
   1075         # genfds

   1076         if Target == 'fds':
   1077             LaunchCommand(AutoGenObject.GenFdsCommand, AutoGenObject.MakeFileDir)
   1078             return True
   1079 
   1080         # run

   1081         if Target == 'run':
   1082             RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))
   1083             Command = '.\SecMain'
   1084             os.chdir(RunDir)
   1085             LaunchCommand(Command, RunDir)
   1086             return True
   1087 
   1088         # build library

   1089         if Target == 'libraries':
   1090             pass
   1091 
   1092         # not build modules

   1093 
   1094 
   1095         # cleanall

   1096         if Target == 'cleanall':
   1097             try:
   1098                 #os.rmdir(AutoGenObject.BuildDir)

   1099                 RemoveDirectory(AutoGenObject.BuildDir, True)
   1100             except WindowsError, X:
   1101                 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
   1102         return True
   1103 
   1104     ## Rebase module image and Get function address for the input module list.

   1105     #

   1106     def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):
   1107         if ModeIsSmm:
   1108             AddrIsOffset = False
   1109         InfFileNameList = ModuleList.keys()
   1110         #InfFileNameList.sort()

   1111         for InfFile in InfFileNameList:
   1112             sys.stdout.write (".")
   1113             sys.stdout.flush()
   1114             ModuleInfo = ModuleList[InfFile]
   1115             ModuleName = ModuleInfo.BaseName
   1116             ModuleOutputImage = ModuleInfo.Image.FileName
   1117             ModuleDebugImage  = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')
   1118             ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.

   1119             if not ModeIsSmm:
   1120                 BaseAddress = BaseAddress - ModuleInfo.Image.Size
   1121                 #

   1122                 # Update Image to new BaseAddress by GenFw tool

   1123                 #

   1124                 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
   1125                 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
   1126             else:
   1127                 #

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

   1129                 #

   1130                 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
   1131                 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
   1132             #

   1133             # Collect funtion address from Map file

   1134             #

   1135             ImageMapTable = ModuleOutputImage.replace('.efi', '.map')
   1136             FunctionList = []
   1137             if os.path.exists(ImageMapTable):
   1138                 OrigImageBaseAddress = 0
   1139                 ImageMap = open(ImageMapTable, 'r')
   1140                 for LinStr in ImageMap:
   1141                     if len (LinStr.strip()) == 0:
   1142                         continue
   1143                     #

   1144                     # Get the preferred address set on link time.

   1145                     #

   1146                     if LinStr.find ('Preferred load address is') != -1:
   1147                         StrList = LinStr.split()
   1148                         OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)
   1149 
   1150                     StrList = LinStr.split()
   1151                     if len (StrList) > 4:
   1152                         if StrList[3] == 'f' or StrList[3] == 'F':
   1153                             Name = StrList[1]
   1154                             RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress
   1155                             FunctionList.append ((Name, RelativeAddress))
   1156                             if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'):
   1157                                 #

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

   1159                                 #

   1160                                 ModuleInfo.Image.EntryPoint = RelativeAddress
   1161                 ImageMap.close()
   1162             #

   1163             # Add general information.

   1164             #

   1165             if ModeIsSmm:
   1166                 MapBuffer.write('\n\n%s (Fixed SMRAM Offset,   BaseAddress=0x%010X,  EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
   1167             elif AddrIsOffset:
   1168                 MapBuffer.write('\n\n%s (Fixed Memory Offset,  BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))
   1169             else:
   1170                 MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X,  EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
   1171             #

   1172             # Add guid and general seciton section.

   1173             #

   1174             TextSectionAddress = 0
   1175             DataSectionAddress = 0
   1176             for SectionHeader in ModuleInfo.Image.SectionHeaderList:
   1177                 if SectionHeader[0] == '.text':
   1178                     TextSectionAddress = SectionHeader[1]
   1179                 elif SectionHeader[0] in ['.data', '.sdata']:
   1180                     DataSectionAddress = SectionHeader[1]
   1181             if AddrIsOffset:
   1182                 MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))
   1183             else:
   1184                 MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))
   1185             #

   1186             # Add debug image full path.

   1187             #

   1188             MapBuffer.write('(IMAGE=%s)\n\n' % (ModuleDebugImage))
   1189             #

   1190             # Add funtion address

   1191             #

   1192             for Function in FunctionList:
   1193                 if AddrIsOffset:
   1194                     MapBuffer.write('  -0x%010X    %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))
   1195                 else:
   1196                     MapBuffer.write('  0x%010X    %s\n' % (BaseAddress + Function[1], Function[0]))
   1197             ImageMap.close()
   1198 
   1199             #

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

   1201             #

   1202             if ModeIsSmm:
   1203                 BaseAddress = BaseAddress + ModuleInfo.Image.Size
   1204 
   1205     ## Collect MAP information of all FVs

   1206     #

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

   1210             GuidPattern = re.compile("[-a-fA-F0-9]+")
   1211             GuidName = re.compile("\(GUID=[-a-fA-F0-9]+")
   1212             for FvName in Wa.FdfProfile.FvDict.keys():
   1213                 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')
   1214                 if not os.path.exists(FvMapBuffer):
   1215                     continue
   1216                 FvMap = open(FvMapBuffer, 'r')
   1217                 #skip FV size information

   1218                 FvMap.readline()
   1219                 FvMap.readline()
   1220                 FvMap.readline()
   1221                 FvMap.readline()
   1222                 for Line in FvMap:
   1223                     MatchGuid = GuidPattern.match(Line)
   1224                     if MatchGuid != None:
   1225                         #

   1226                         # Replace GUID with module name

   1227                         #

   1228                         GuidString = MatchGuid.group()
   1229                         if GuidString.upper() in ModuleList:
   1230                             Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)
   1231                     MapBuffer.write('%s' % (Line))
   1232                     #

   1233                     # Add the debug image full path.

   1234                     #

   1235                     MatchGuid = GuidName.match(Line)
   1236                     if MatchGuid != None:
   1237                         GuidString = MatchGuid.group().split("=")[1]
   1238                         if GuidString.upper() in ModuleList:
   1239                             MapBuffer.write('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))
   1240 
   1241                 FvMap.close()
   1242 
   1243     ## Collect MAP information of all modules

   1244     #

   1245     def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):
   1246         sys.stdout.write ("Generate Load Module At Fix Address Map")
   1247         sys.stdout.flush()
   1248         PatchEfiImageList = []
   1249         PeiModuleList  = {}
   1250         BtModuleList   = {}
   1251         RtModuleList   = {}
   1252         SmmModuleList  = {}
   1253         PeiSize = 0
   1254         BtSize  = 0
   1255         RtSize  = 0
   1256         # reserve 4K size in SMRAM to make SMM module address not from 0.

   1257         SmmSize = 0x1000
   1258         IsIpfPlatform = False
   1259         if 'IPF' in self.ArchList:
   1260             IsIpfPlatform = True
   1261         for ModuleGuid in ModuleList:
   1262             Module = ModuleList[ModuleGuid]
   1263             GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)
   1264 
   1265             OutputImageFile = ''
   1266             for ResultFile in Module.CodaTargetList:
   1267                 if str(ResultFile.Target).endswith('.efi'):
   1268                     #

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

   1270                     #

   1271                     OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')
   1272                     ImageClass = PeImageClass (OutputImageFile)
   1273                     if not ImageClass.IsValid:
   1274                         EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)
   1275                     ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)
   1276                     if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER', 'PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']:
   1277                         PeiModuleList[Module.MetaFile] = ImageInfo
   1278                         PeiSize += ImageInfo.Image.Size
   1279                     elif Module.ModuleType in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']:
   1280                         BtModuleList[Module.MetaFile] = ImageInfo
   1281                         BtSize += ImageInfo.Image.Size
   1282                     elif Module.ModuleType in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']:
   1283                         RtModuleList[Module.MetaFile] = ImageInfo
   1284                         #IPF runtime driver needs to be at 2 page alignment.

   1285                         if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0:
   1286                             ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000
   1287                         RtSize += ImageInfo.Image.Size
   1288                     elif Module.ModuleType in ['SMM_CORE', 'DXE_SMM_DRIVER']:
   1289                         SmmModuleList[Module.MetaFile] = ImageInfo
   1290                         SmmSize += ImageInfo.Image.Size
   1291                         if Module.ModuleType == 'DXE_SMM_DRIVER':
   1292                             PiSpecVersion = '0x00000000'
   1293                             if 'PI_SPECIFICATION_VERSION' in Module.Module.Specification:
   1294                                 PiSpecVersion = Module.Module.Specification['PI_SPECIFICATION_VERSION']
   1295                             # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.

   1296                             if int(PiSpecVersion, 16) < 0x0001000A:
   1297                                 BtModuleList[Module.MetaFile] = ImageInfo
   1298                                 BtSize += ImageInfo.Image.Size
   1299                     break
   1300             #

   1301             # EFI image is final target.

   1302             # Check EFI image contains patchable FixAddress related PCDs.

   1303             #

   1304             if OutputImageFile != '':
   1305                 ModuleIsPatch = False
   1306                 for Pcd in Module.ModulePcdList:
   1307                     if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:
   1308                         ModuleIsPatch = True
   1309                         break
   1310                 if not ModuleIsPatch:
   1311                     for Pcd in Module.LibraryPcdList:
   1312                         if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:
   1313                             ModuleIsPatch = True
   1314                             break
   1315 
   1316                 if not ModuleIsPatch:
   1317                     continue
   1318                 #

   1319                 # Module includes the patchable load fix address PCDs.

   1320                 # It will be fixed up later.

   1321                 #

   1322                 PatchEfiImageList.append (OutputImageFile)
   1323 
   1324         #

   1325         # Get Top Memory address

   1326         #

   1327         ReservedRuntimeMemorySize = 0
   1328         TopMemoryAddress = 0
   1329         if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:
   1330             TopMemoryAddress = 0
   1331         else:
   1332             TopMemoryAddress = self.LoadFixAddress
   1333             if TopMemoryAddress < RtSize + BtSize + PeiSize:
   1334                 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
   1335             # Make IPF runtime driver at 2 page alignment.

   1336             if IsIpfPlatform:
   1337                 ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000
   1338                 RtSize = RtSize + ReservedRuntimeMemorySize
   1339 
   1340         #

   1341         # Patch FixAddress related PCDs into EFI image

   1342         #

   1343         for EfiImage in PatchEfiImageList:
   1344             EfiImageMap = EfiImage.replace('.efi', '.map')
   1345             if not os.path.exists(EfiImageMap):
   1346                 continue
   1347             #

   1348             # Get PCD offset in EFI image by GenPatchPcdTable function

   1349             #

   1350             PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)
   1351             #

   1352             # Patch real PCD value by PatchPcdValue tool

   1353             #

   1354             for PcdInfo in PcdTable:
   1355                 ReturnValue = 0
   1356                 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:
   1357                     ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize / 0x1000))
   1358                 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:
   1359                     ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize / 0x1000))
   1360                 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:
   1361                     ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize / 0x1000))
   1362                 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:
   1363                     ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize / 0x1000))
   1364                 if ReturnValue != 0:
   1365                     EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)
   1366 
   1367         MapBuffer.write('PEI_CODE_PAGE_NUMBER      = 0x%x\n' % (PeiSize / 0x1000))
   1368         MapBuffer.write('BOOT_CODE_PAGE_NUMBER     = 0x%x\n' % (BtSize / 0x1000))
   1369         MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER  = 0x%x\n' % (RtSize / 0x1000))
   1370         if len (SmmModuleList) > 0:
   1371             MapBuffer.write('SMM_CODE_PAGE_NUMBER      = 0x%x\n' % (SmmSize / 0x1000))
   1372 
   1373         PeiBaseAddr = TopMemoryAddress - RtSize - BtSize
   1374         BtBaseAddr  = TopMemoryAddress - RtSize
   1375         RtBaseAddr  = TopMemoryAddress - ReservedRuntimeMemorySize
   1376 
   1377         self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)
   1378         self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)
   1379         self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)
   1380         self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset=False, ModeIsSmm=True)
   1381         MapBuffer.write('\n\n')
   1382         sys.stdout.write ("\n")
   1383         sys.stdout.flush()
   1384 
   1385     ## Save platform Map file

   1386     #

   1387     def _SaveMapFile (self, MapBuffer, Wa):
   1388         #

   1389         # Map file path is got.

   1390         #

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

   1393         # Save address map into MAP file.

   1394         #

   1395         SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)
   1396         MapBuffer.close()
   1397         if self.LoadFixAddress != 0:
   1398             sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath))
   1399         sys.stdout.flush()
   1400 
   1401     ## Build active platform for different build targets and different tool chains

   1402     #

   1403     def _BuildPlatform(self):
   1404         for BuildTarget in self.BuildTargetList:
   1405             GlobalData.gGlobalDefines['TARGET'] = BuildTarget
   1406             for ToolChain in self.ToolChainList:
   1407                 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
   1408                 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
   1409                 Wa = WorkspaceAutoGen(
   1410                         self.WorkspaceDir,
   1411                         self.PlatformFile,
   1412                         BuildTarget,
   1413                         ToolChain,
   1414                         self.ArchList,
   1415                         self.BuildDatabase,
   1416                         self.TargetTxt,
   1417                         self.ToolDef,
   1418                         self.Fdf,
   1419                         self.FdList,
   1420                         self.FvList,
   1421                         self.CapList,
   1422                         self.SkuId,
   1423                         self.UniFlag,
   1424                         self.Progress
   1425                         )
   1426                 self.Fdf = Wa.FdfFile
   1427                 self.LoadFixAddress = Wa.Platform.LoadFixAddress
   1428                 self.BuildReport.AddPlatformReport(Wa)
   1429                 self.Progress.Stop("done!")
   1430                 for Arch in Wa.ArchList:
   1431                     GlobalData.gGlobalDefines['ARCH'] = Arch
   1432                     Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
   1433                     for Module in Pa.Platform.Modules:
   1434                         # Get ModuleAutoGen object to generate C code file and makefile

   1435                         Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
   1436                         if Ma == None:
   1437                             continue
   1438                         self.BuildModules.append(Ma)
   1439                     self._BuildPa(self.Target, Pa)
   1440 
   1441                 # Create MAP file when Load Fix Address is enabled.

   1442                 if self.Target in ["", "all", "fds"]:
   1443                     for Arch in Wa.ArchList:
   1444                         GlobalData.gGlobalDefines['ARCH'] = Arch
   1445                         #

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

   1447                         #

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

   1451                     # Get Module List

   1452                     #

   1453                     ModuleList = {}
   1454                     for Pa in Wa.AutoGenObjectList:
   1455                         for Ma in Pa.ModuleAutoGenList:
   1456                             if Ma == None:
   1457                                 continue
   1458                             if not Ma.IsLibrary:
   1459                                 ModuleList[Ma.Guid.upper()] = Ma
   1460 
   1461                     MapBuffer = StringIO('')
   1462                     if self.LoadFixAddress != 0:
   1463                         #

   1464                         # Rebase module to the preferred memory address before GenFds

   1465                         #

   1466                         self._CollectModuleMapBuffer(MapBuffer, ModuleList)
   1467                     if self.Fdf:
   1468                         #

   1469                         # create FDS again for the updated EFI image

   1470                         #

   1471                         self._Build("fds", Wa)
   1472                         #

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

   1474                         #

   1475                         self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
   1476                     #

   1477                     # Save MAP buffer into MAP file.

   1478                     #

   1479                     self._SaveMapFile (MapBuffer, Wa)
   1480 
   1481     ## Build active module for different build targets, different tool chains and different archs

   1482     #

   1483     def _BuildModule(self):
   1484         for BuildTarget in self.BuildTargetList:
   1485             GlobalData.gGlobalDefines['TARGET'] = BuildTarget
   1486             for ToolChain in self.ToolChainList:
   1487                 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
   1488                 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
   1489                 #

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

   1491                 # AutoGen first

   1492                 #

   1493                 Wa = WorkspaceAutoGen(
   1494                         self.WorkspaceDir,
   1495                         self.PlatformFile,
   1496                         BuildTarget,
   1497                         ToolChain,
   1498                         self.ArchList,
   1499                         self.BuildDatabase,
   1500                         self.TargetTxt,
   1501                         self.ToolDef,
   1502                         self.Fdf,
   1503                         self.FdList,
   1504                         self.FvList,
   1505                         self.CapList,
   1506                         self.SkuId,
   1507                         self.UniFlag,
   1508                         self.Progress,
   1509                         self.ModuleFile
   1510                         )
   1511                 self.Fdf = Wa.FdfFile
   1512                 self.LoadFixAddress = Wa.Platform.LoadFixAddress
   1513                 Wa.CreateMakeFile(False)
   1514                 self.Progress.Stop("done!")
   1515                 MaList = []
   1516                 for Arch in Wa.ArchList:
   1517                     GlobalData.gGlobalDefines['ARCH'] = Arch
   1518                     Ma = ModuleAutoGen(Wa, self.ModuleFile, BuildTarget, ToolChain, Arch, self.PlatformFile)
   1519                     if Ma == None: continue
   1520                     MaList.append(Ma)
   1521                     self.BuildModules.append(Ma)
   1522                     if not Ma.IsBinaryModule:
   1523                         self._Build(self.Target, Ma, BuildModule=True)
   1524 
   1525                 self.BuildReport.AddPlatformReport(Wa, MaList)
   1526                 if MaList == []:
   1527                     EdkLogger.error(
   1528                                 'build',
   1529                                 BUILD_ERROR,
   1530                                 "Module for [%s] is not a component of active platform."\
   1531                                 " Please make sure that the ARCH and inf file path are"\
   1532                                 " given in the same as in [%s]" % \
   1533                                     (', '.join(Wa.ArchList), self.PlatformFile),
   1534                                 ExtraData=self.ModuleFile
   1535                                 )
   1536                 # Create MAP file when Load Fix Address is enabled.

   1537                 if self.Target == "fds" and self.Fdf:
   1538                     for Arch in Wa.ArchList:
   1539                         #

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

   1541                         #

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

   1545                     # Get Module List

   1546                     #

   1547                     ModuleList = {}
   1548                     for Pa in Wa.AutoGenObjectList:
   1549                         for Ma in Pa.ModuleAutoGenList:
   1550                             if Ma == None:
   1551                                 continue
   1552                             if not Ma.IsLibrary:
   1553                                 ModuleList[Ma.Guid.upper()] = Ma
   1554 
   1555                     MapBuffer = StringIO('')
   1556                     if self.LoadFixAddress != 0:
   1557                         #

   1558                         # Rebase module to the preferred memory address before GenFds

   1559                         #

   1560                         self._CollectModuleMapBuffer(MapBuffer, ModuleList)
   1561                     #

   1562                     # create FDS again for the updated EFI image

   1563                     #

   1564                     self._Build("fds", Wa)
   1565                     #

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

   1567                     #

   1568                     self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
   1569                     #

   1570                     # Save MAP buffer into MAP file.

   1571                     #

   1572                     self._SaveMapFile (MapBuffer, Wa)
   1573 
   1574     ## Build a platform in multi-thread mode

   1575     #

   1576     def _MultiThreadBuildPlatform(self):
   1577         for BuildTarget in self.BuildTargetList:
   1578             GlobalData.gGlobalDefines['TARGET'] = BuildTarget
   1579             for ToolChain in self.ToolChainList:
   1580                 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
   1581                 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
   1582                 Wa = WorkspaceAutoGen(
   1583                         self.WorkspaceDir,
   1584                         self.PlatformFile,
   1585                         BuildTarget,
   1586                         ToolChain,
   1587                         self.ArchList,
   1588                         self.BuildDatabase,
   1589                         self.TargetTxt,
   1590                         self.ToolDef,
   1591                         self.Fdf,
   1592                         self.FdList,
   1593                         self.FvList,
   1594                         self.CapList,
   1595                         self.SkuId,
   1596                         self.UniFlag,
   1597                         self.Progress
   1598                         )
   1599                 self.Fdf = Wa.FdfFile
   1600                 self.LoadFixAddress = Wa.Platform.LoadFixAddress
   1601                 self.BuildReport.AddPlatformReport(Wa)
   1602                 Wa.CreateMakeFile(False)
   1603 
   1604                 # multi-thread exit flag

   1605                 ExitFlag = threading.Event()
   1606                 ExitFlag.clear()
   1607                 for Arch in Wa.ArchList:
   1608                     GlobalData.gGlobalDefines['ARCH'] = Arch
   1609                     Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
   1610                     if Pa == None:
   1611                         continue
   1612                     ModuleList = []
   1613                     for Inf in Pa.Platform.Modules:
   1614                         ModuleList.append(Inf)
   1615                     # Add the INF only list in FDF

   1616                     if GlobalData.gFdfParser != None:
   1617                         for InfName in GlobalData.gFdfParser.Profile.InfList:
   1618                             Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)
   1619                             if Inf in Pa.Platform.Modules:
   1620                                 continue
   1621                             ModuleList.append(Inf)
   1622                     for Module in ModuleList:
   1623                         # Get ModuleAutoGen object to generate C code file and makefile

   1624                         Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
   1625                         
   1626                         if Ma == None:
   1627                             continue
   1628                         # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'

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

   1631                             if not self.SkipAutoGen or self.Target == 'genc':
   1632                                 Ma.CreateCodeFile(True)
   1633                             if self.Target == "genc":
   1634                                 continue
   1635 
   1636                             if not self.SkipAutoGen or self.Target == 'genmake':
   1637                                 Ma.CreateMakeFile(True)
   1638                             if self.Target == "genmake":
   1639                                 continue
   1640                         self.BuildModules.append(Ma)
   1641                     self.Progress.Stop("done!")
   1642 
   1643                     for Ma in self.BuildModules:
   1644                         # Generate build task for the module

   1645                         if not Ma.IsBinaryModule:
   1646                             Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))
   1647                         # Break build if any build thread has error

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

   1650                             ExitFlag.set()
   1651                             BuildTask.WaitForComplete()
   1652                             Pa.CreateMakeFile(False)
   1653                             EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
   1654                         # Start task scheduler

   1655                         if not BuildTask.IsOnGoing():
   1656                             BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
   1657 
   1658                     # in case there's an interruption. we need a full version of makefile for platform

   1659                     Pa.CreateMakeFile(False)
   1660                     if BuildTask.HasError():
   1661                         EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
   1662 
   1663                 #

   1664                 # Save temp tables to a TmpTableDict.

   1665                 #

   1666                 for Key in Wa.BuildDatabase._CACHE_:
   1667                     if Wa.BuildDatabase._CACHE_[Key]._RawData and Wa.BuildDatabase._CACHE_[Key]._RawData._Table and Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table:
   1668                         if TemporaryTablePattern.match(Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table):
   1669                             TmpTableDict[Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table] = Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Cur
   1670                 #

   1671                 #

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

   1673                 # to exit if all tasks are completed

   1674                 #

   1675                 ExitFlag.set()
   1676                 BuildTask.WaitForComplete()
   1677                 self.CreateAsBuiltInf()
   1678 
   1679                 #

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

   1681                 # has been signaled.

   1682                 #

   1683                 if BuildTask.HasError():
   1684                     EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
   1685 
   1686                 # Create MAP file when Load Fix Address is enabled.

   1687                 if self.Target in ["", "all", "fds"]:
   1688                     for Arch in Wa.ArchList:
   1689                         #

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

   1691                         #

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

   1695                     # Get Module List

   1696                     #

   1697                     ModuleList = {}
   1698                     for Pa in Wa.AutoGenObjectList:
   1699                         for Ma in Pa.ModuleAutoGenList:
   1700                             if Ma == None:
   1701                                 continue
   1702                             if not Ma.IsLibrary:
   1703                                 ModuleList[Ma.Guid.upper()] = Ma
   1704                     #

   1705                     # Rebase module to the preferred memory address before GenFds

   1706                     #

   1707                     MapBuffer = StringIO('')
   1708                     if self.LoadFixAddress != 0:
   1709                         self._CollectModuleMapBuffer(MapBuffer, ModuleList)
   1710 
   1711                     if self.Fdf:
   1712                         #

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

   1714                         #

   1715                         LaunchCommand(Wa.GenFdsCommand, os.getcwd())
   1716 
   1717                         #

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

   1719                         #

   1720                         self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
   1721                     #

   1722                     # Save MAP buffer into MAP file.

   1723                     #

   1724                     self._SaveMapFile(MapBuffer, Wa)
   1725 
   1726     ## Generate GuidedSectionTools.txt in the FV directories.

   1727     #

   1728     def CreateGuidedSectionToolsFile(self):
   1729         for BuildTarget in self.BuildTargetList:
   1730             for ToolChain in self.ToolChainList:
   1731                 Wa = WorkspaceAutoGen(
   1732                         self.WorkspaceDir,
   1733                         self.PlatformFile,
   1734                         BuildTarget,
   1735                         ToolChain,
   1736                         self.ArchList,
   1737                         self.BuildDatabase,
   1738                         self.TargetTxt,
   1739                         self.ToolDef,
   1740                         self.Fdf,
   1741                         self.FdList,
   1742                         self.FvList,
   1743                         self.CapList,
   1744                         self.SkuId,
   1745                         self.UniFlag
   1746                         )
   1747                 FvDir = Wa.FvDir
   1748                 if not os.path.exists(FvDir):
   1749                     continue
   1750 
   1751                 for Arch in self.ArchList:
   1752                     # Build up the list of supported architectures for this build

   1753                     prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)
   1754 
   1755                     # Look through the tool definitions for GUIDed tools

   1756                     guidAttribs = []
   1757                     for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():
   1758                         if attrib.upper().endswith('_GUID'):
   1759                             split = attrib.split('_')
   1760                             thisPrefix = '_'.join(split[0:3]) + '_'
   1761                             if thisPrefix == prefix:
   1762                                 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]
   1763                                 guid = guid.lower()
   1764                                 toolName = split[3]
   1765                                 path = '_'.join(split[0:4]) + '_PATH'
   1766                                 path = self.ToolDef.ToolsDefTxtDictionary[path]
   1767                                 path = self.GetFullPathOfTool(path)
   1768                                 guidAttribs.append((guid, toolName, path))
   1769 
   1770                     # Write out GuidedSecTools.txt

   1771                     toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')
   1772                     toolsFile = open(toolsFile, 'wt')
   1773                     for guidedSectionTool in guidAttribs:
   1774                         print >> toolsFile, ' '.join(guidedSectionTool)
   1775                     toolsFile.close()
   1776 
   1777     ## Returns the full path of the tool.

   1778     #

   1779     def GetFullPathOfTool (self, tool):
   1780         if os.path.exists(tool):
   1781             return os.path.realpath(tool)
   1782         else:
   1783             # We need to search for the tool using the

   1784             # PATH environment variable.

   1785             for dirInPath in os.environ['PATH'].split(os.pathsep):
   1786                 foundPath = os.path.join(dirInPath, tool)
   1787                 if os.path.exists(foundPath):
   1788                     return os.path.realpath(foundPath)
   1789 
   1790         # If the tool was not found in the path then we just return

   1791         # the input tool.

   1792         return tool
   1793 
   1794     ## Launch the module or platform build

   1795     #

   1796     def Launch(self):
   1797         if not self.ModuleFile:
   1798             if not self.SpawnMode or self.Target not in ["", "all"]:
   1799                 self.SpawnMode = False
   1800                 self._BuildPlatform()
   1801             else:
   1802                 self._MultiThreadBuildPlatform()
   1803             self.CreateGuidedSectionToolsFile()
   1804         else:
   1805             self.SpawnMode = False
   1806             self._BuildModule()
   1807 
   1808         if self.Target == 'cleanall':
   1809             self.Db.Close()
   1810             RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)
   1811 
   1812     def CreateAsBuiltInf(self):
   1813         for Module in self.BuildModules:
   1814             Module.CreateAsBuiltInf()
   1815         self.BuildModules = []
   1816     ## Do some clean-up works when error occurred

   1817     def Relinquish(self):
   1818         OldLogLevel = EdkLogger.GetLevel()
   1819         EdkLogger.SetLevel(EdkLogger.ERROR)
   1820         #self.DumpBuildData()

   1821         Utils.Progressor.Abort()
   1822         if self.SpawnMode == True:
   1823             BuildTask.Abort()
   1824         EdkLogger.SetLevel(OldLogLevel)
   1825 
   1826     def DumpBuildData(self):
   1827         CacheDirectory = os.path.dirname(GlobalData.gDatabasePath)
   1828         Utils.CreateDirectory(CacheDirectory)
   1829         Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))
   1830         Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))
   1831 
   1832     def RestoreBuildData(self):
   1833         FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gFileTimeStampCache")
   1834         if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):
   1835             Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)
   1836             if Utils.gFileTimeStampCache == None:
   1837                 Utils.gFileTimeStampCache = {}
   1838 
   1839         FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gDependencyDatabase")
   1840         if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):
   1841             Utils.gDependencyDatabase = Utils.DataRestore(FilePath)
   1842             if Utils.gDependencyDatabase == None:
   1843                 Utils.gDependencyDatabase = {}
   1844 
   1845 def ParseDefines(DefineList=[]):
   1846     DefineDict = {}
   1847     if DefineList != None:
   1848         for Define in DefineList:
   1849             DefineTokenList = Define.split("=", 1)
   1850             if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):
   1851                 EdkLogger.error('build', FORMAT_INVALID,
   1852                                 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
   1853                                 ExtraData=DefineTokenList[0])
   1854 
   1855             if len(DefineTokenList) == 1:
   1856                 DefineDict[DefineTokenList[0]] = "TRUE"
   1857             else:
   1858                 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()
   1859     return DefineDict
   1860 
   1861 gParamCheck = []
   1862 def SingleCheckCallback(option, opt_str, value, parser):
   1863     if option not in gParamCheck:
   1864         setattr(parser.values, option.dest, value)
   1865         gParamCheck.append(option)
   1866     else:
   1867         parser.error("Option %s only allows one instance in command line!" % option)
   1868 
   1869 ## Parse command line options

   1870 #

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

   1872 #

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

   1874 #   @retval Args  Target of build command

   1875 #

   1876 def MyOptionParser():
   1877     Parser = OptionParser(description=__copyright__, version=__version__, prog="build.exe", usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
   1878     Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32', 'X64', 'IPF', 'EBC', 'ARM', 'AARCH64'], dest="TargetArch",
   1879         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.")
   1880     Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,
   1881         help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
   1882     Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,
   1883         help="Build the module specified by the INF file name argument.")
   1884     Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
   1885                       action="append")
   1886     Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",
   1887         help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
   1888     Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,
   1889         help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
   1890 
   1891     Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,
   1892         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.")
   1893 
   1894     Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,
   1895         help="The name of the FDF file to use, which overrides the setting in the DSC file.")
   1896     Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],
   1897         help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
   1898     Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],
   1899         help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
   1900     Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],
   1901         help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
   1902     Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")
   1903     Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")
   1904 
   1905     Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.")
   1906 
   1907     Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")
   1908     Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")
   1909 
   1910     Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",
   1911         help="Make use of silent mode of (n)make.")
   1912     Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
   1913     Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
   1914                                                                                "including library instances selected, final dependency expression, "\
   1915                                                                                "and warning messages, etc.")
   1916     Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
   1917     Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
   1918 
   1919     Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")
   1920     Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD', 'LIBRARY', 'FLASH', 'DEPEX', 'BUILD_FLAGS', 'FIXED_ADDRESS', 'EXECUTION_ORDER'], dest="ReportType", default=[],
   1921         help="Flags that control the type of build report to generate.  Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, EXECUTION_ORDER].  "\
   1922              "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]")
   1923     Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",
   1924         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. "\
   1925              "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
   1926              "will override the setting in [BuildOptions] section of platform DSC.")
   1927     Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism")
   1928     Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")
   1929     Parser.add_option("--check-usage", action="store_true", dest="CheckUsage", default=False, help="Check usage content of entries listed in INF file.")
   1930     Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")
   1931 
   1932     (Opt, Args) = Parser.parse_args()
   1933     return (Opt, Args)
   1934 
   1935 ## Tool entrance method

   1936 #

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

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

   1939 # if it's executed successfully or not.

   1940 #

   1941 #   @retval 0     Tool was successful

   1942 #   @retval 1     Tool failed

   1943 #

   1944 def Main():
   1945     StartTime = time.time()
   1946 
   1947     # Initialize log system

   1948     EdkLogger.Initialize()
   1949 
   1950     #

   1951     # Parse the options and args

   1952     #

   1953     (Option, Target) = MyOptionParser()
   1954     GlobalData.gOptions = Option
   1955     GlobalData.gCaseInsensitive = Option.CaseInsensitive
   1956 
   1957     # Set log level

   1958     if Option.verbose != None:
   1959         EdkLogger.SetLevel(EdkLogger.VERBOSE)
   1960     elif Option.quiet != None:
   1961         EdkLogger.SetLevel(EdkLogger.QUIET)
   1962     elif Option.debug != None:
   1963         EdkLogger.SetLevel(Option.debug + 1)
   1964     else:
   1965         EdkLogger.SetLevel(EdkLogger.INFO)
   1966 
   1967     if Option.LogFile != None:
   1968         EdkLogger.SetLogFile(Option.LogFile)
   1969 
   1970     if Option.WarningAsError == True:
   1971         EdkLogger.SetWarningAsError()
   1972 
   1973     if platform.platform().find("Windows") >= 0:
   1974         GlobalData.gIsWindows = True
   1975     else:
   1976         GlobalData.gIsWindows = False
   1977 
   1978     EdkLogger.quiet("Build environment: %s" % platform.platform())
   1979     EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));
   1980     ReturnCode = 0
   1981     MyBuild = None
   1982     BuildError = True
   1983     try:
   1984         if len(Target) == 0:
   1985             Target = "all"
   1986         elif len(Target) >= 2:
   1987             EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",
   1988                             ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))
   1989         else:
   1990             Target = Target[0].lower()
   1991 
   1992         if Target not in gSupportedTarget:
   1993             EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,
   1994                             ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))
   1995 
   1996         #

   1997         # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH

   1998         #

   1999         CheckEnvVariable()
   2000         GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))
   2001 
   2002         Workspace = os.getenv("WORKSPACE")
   2003         #

   2004         # Get files real name in workspace dir

   2005         #

   2006         GlobalData.gAllFiles = Utils.DirCache(Workspace)
   2007 
   2008         WorkingDirectory = os.getcwd()
   2009         if not Option.ModuleFile:
   2010             FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))
   2011             FileNum = len(FileList)
   2012             if FileNum >= 2:
   2013                 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),
   2014                                 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")
   2015             elif FileNum == 1:
   2016                 Option.ModuleFile = NormFile(FileList[0], Workspace)
   2017 
   2018         if Option.ModuleFile:
   2019             if os.path.isabs (Option.ModuleFile):
   2020                 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:
   2021                     Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)
   2022             Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)
   2023             ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)
   2024             if ErrorCode != 0:
   2025                 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
   2026 
   2027         if Option.PlatformFile != None:
   2028             if os.path.isabs (Option.PlatformFile):
   2029                 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:
   2030                     Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)
   2031             Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)
   2032 
   2033         if Option.FdfFile != None:
   2034             if os.path.isabs (Option.FdfFile):
   2035                 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:
   2036                     Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)
   2037             Option.FdfFile = PathClass(Option.FdfFile, Workspace)
   2038             ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)
   2039             if ErrorCode != 0:
   2040                 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
   2041 
   2042         if Option.Flag != None and Option.Flag not in ['-c', '-s']:
   2043             EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")
   2044 
   2045         MyBuild = Build(Target, Workspace, Option)
   2046         GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)
   2047         MyBuild.Launch()
   2048         # Drop temp tables to avoid database locked.

   2049         for TmpTableName in TmpTableDict:
   2050             SqlCommand = """drop table IF EXISTS %s""" % TmpTableName
   2051             TmpTableDict[TmpTableName].execute(SqlCommand)
   2052         #MyBuild.DumpBuildData()

   2053         #

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

   2055         #

   2056         BuildError = False
   2057     except FatalError, X:
   2058         if MyBuild != None:
   2059             # for multi-thread build exits safely

   2060             MyBuild.Relinquish()
   2061         if Option != None and Option.debug != None:
   2062             EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
   2063         ReturnCode = X.args[0]
   2064     except Warning, X:
   2065         # error from Fdf parser

   2066         if MyBuild != None:
   2067             # for multi-thread build exits safely

   2068             MyBuild.Relinquish()
   2069         if Option != None and Option.debug != None:
   2070             EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
   2071         else:
   2072             EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)
   2073         ReturnCode = FORMAT_INVALID
   2074     except KeyboardInterrupt:
   2075         ReturnCode = ABORT_ERROR
   2076         if Option != None and Option.debug != None:
   2077             EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
   2078     except:
   2079         if MyBuild != None:
   2080             # for multi-thread build exits safely

   2081             MyBuild.Relinquish()
   2082 
   2083         # try to get the meta-file from the object causing exception

   2084         Tb = sys.exc_info()[-1]
   2085         MetaFile = GlobalData.gProcessingFile
   2086         while Tb != None:
   2087             if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):
   2088                 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile
   2089             Tb = Tb.tb_next
   2090         EdkLogger.error(
   2091                     "\nbuild",
   2092                     CODE_ERROR,
   2093                     "Unknown fatal error when processing [%s]" % MetaFile,
   2094                     ExtraData="\n(Please send email to edk2-devel (at] lists.sourceforge.net for help, attaching following call stack trace!)\n",
   2095                     RaiseError=False
   2096                     )
   2097         EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
   2098         ReturnCode = CODE_ERROR
   2099     finally:
   2100         Utils.Progressor.Abort()
   2101         Utils.ClearDuplicatedInf()
   2102 
   2103     if ReturnCode == 0:
   2104         Conclusion = "Done"
   2105     elif ReturnCode == ABORT_ERROR:
   2106         Conclusion = "Aborted"
   2107     else:
   2108         Conclusion = "Failed"
   2109     FinishTime = time.time()
   2110     BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))
   2111     BuildDurationStr = ""
   2112     if BuildDuration.tm_yday > 1:
   2113         BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)" % (BuildDuration.tm_yday - 1)
   2114     else:
   2115         BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)
   2116     if MyBuild != None:
   2117         if not BuildError:
   2118             MyBuild.BuildReport.GenerateReport(BuildDurationStr)
   2119         MyBuild.Db.Close()
   2120     EdkLogger.SetLevel(EdkLogger.QUIET)
   2121     EdkLogger.quiet("\n- %s -" % Conclusion)
   2122     EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))
   2123     EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)
   2124     return ReturnCode
   2125 
   2126 if __name__ == '__main__':
   2127     r = Main()
   2128     ## 0-127 is a safe return range, and 1 is a standard default error

   2129     if r < 0 or r > 127: r = 1
   2130     sys.exit(r)
   2131 
   2132