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#
19import Common.LongFilePathOs as os
20import re
21import StringIO
22import sys
23import glob
24import time
25import platform
26import traceback
27import encodings.ascii
28
29from struct import *
30from threading import *
31from optparse import OptionParser
32from subprocess import *
33from Common import Misc as Utils
34
35from Common.LongFilePathSupport import OpenLongFilePath as open
36from Common.LongFilePathSupport import LongFilePath
37from Common.TargetTxtClassObject import *
38from Common.ToolDefClassObject import *
39from Common.DataType import *
40from Common.BuildVersion import gBUILD_VERSION
41from AutoGen.AutoGen import *
42from Common.BuildToolError import *
43from Workspace.WorkspaceDatabase import *
44
45from BuildReport import BuildReport
46from GenPatchPcdTable.GenPatchPcdTable import *
47from PatchPcdValue.PatchPcdValue import *
48
49import Common.EdkLogger
50import Common.GlobalData as GlobalData
51
52# Version and Copyright
53VersionNumber = "0.60" + ' ' + gBUILD_VERSION
54__version__ = "%prog Version " + VersionNumber
55__copyright__ = "Copyright (c) 2007 - 2014, Intel Corporation  All rights reserved."
56
57## standard targets of build command
58gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
59
60## build configuration file
61gBuildConfiguration = "target.txt"
62gToolsDefinition = "tools_def.txt"
63
64TemporaryTablePattern = re.compile(r'^_\d+_\d+_[a-fA-F0-9]+$')
65TmpTableDict = {}
66
67## Check environment PATH variable to make sure the specified tool is found
68#
69#   If the tool is found in the PATH, then True is returned
70#   Otherwise, False is returned
71#
72def IsToolInPath(tool):
73    if os.environ.has_key('PATHEXT'):
74        extns = os.environ['PATHEXT'].split(os.path.pathsep)
75    else:
76        extns = ('',)
77    for pathDir in os.environ['PATH'].split(os.path.pathsep):
78        for ext in extns:
79            if os.path.exists(os.path.join(pathDir, tool + ext)):
80                return True
81    return False
82
83## Check environment variables
84#
85#  Check environment variables that must be set for build. Currently they are
86#
87#   WORKSPACE           The directory all packages/platforms start from
88#   EDK_TOOLS_PATH      The directory contains all tools needed by the build
89#   PATH                $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
90#
91#   If any of above environment variable is not set or has error, the build
92#   will be broken.
93#
94def CheckEnvVariable():
95    # check WORKSPACE
96    if "WORKSPACE" not in os.environ:
97        EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
98                        ExtraData="WORKSPACE")
99
100    WorkspaceDir = os.path.normcase(os.path.normpath(os.environ["WORKSPACE"]))
101    if not os.path.exists(WorkspaceDir):
102        EdkLogger.error("build", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData="%s" % WorkspaceDir)
103    elif ' ' in WorkspaceDir:
104        EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path",
105                        ExtraData=WorkspaceDir)
106    os.environ["WORKSPACE"] = WorkspaceDir
107
108    #
109    # Check EFI_SOURCE (Edk build convention). EDK_SOURCE will always point to ECP
110    #
111    if "ECP_SOURCE" not in os.environ:
112        os.environ["ECP_SOURCE"] = os.path.join(WorkspaceDir, GlobalData.gEdkCompatibilityPkg)
113    if "EFI_SOURCE" not in os.environ:
114        os.environ["EFI_SOURCE"] = os.environ["ECP_SOURCE"]
115    if "EDK_SOURCE" not in os.environ:
116        os.environ["EDK_SOURCE"] = os.environ["ECP_SOURCE"]
117
118    #
119    # Unify case of characters on case-insensitive systems
120    #
121    EfiSourceDir = os.path.normcase(os.path.normpath(os.environ["EFI_SOURCE"]))
122    EdkSourceDir = os.path.normcase(os.path.normpath(os.environ["EDK_SOURCE"]))
123    EcpSourceDir = os.path.normcase(os.path.normpath(os.environ["ECP_SOURCE"]))
124
125    os.environ["EFI_SOURCE"] = EfiSourceDir
126    os.environ["EDK_SOURCE"] = EdkSourceDir
127    os.environ["ECP_SOURCE"] = EcpSourceDir
128    os.environ["EDK_TOOLS_PATH"] = os.path.normcase(os.environ["EDK_TOOLS_PATH"])
129
130    if not os.path.exists(EcpSourceDir):
131        EdkLogger.verbose("ECP_SOURCE = %s doesn't exist. Edk modules could not be built." % EcpSourceDir)
132    elif ' ' in EcpSourceDir:
133        EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in ECP_SOURCE path",
134                        ExtraData=EcpSourceDir)
135    if not os.path.exists(EdkSourceDir):
136        if EdkSourceDir == EcpSourceDir:
137            EdkLogger.verbose("EDK_SOURCE = %s doesn't exist. Edk modules could not be built." % EdkSourceDir)
138        else:
139            EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE does not exist",
140                            ExtraData=EdkSourceDir)
141    elif ' ' in EdkSourceDir:
142        EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EDK_SOURCE path",
143                        ExtraData=EdkSourceDir)
144    if not os.path.exists(EfiSourceDir):
145        if EfiSourceDir == EcpSourceDir:
146            EdkLogger.verbose("EFI_SOURCE = %s doesn't exist. Edk modules could not be built." % EfiSourceDir)
147        else:
148            EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE does not exist",
149                            ExtraData=EfiSourceDir)
150    elif ' ' in EfiSourceDir:
151        EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EFI_SOURCE path",
152                        ExtraData=EfiSourceDir)
153
154    # change absolute path to relative path to WORKSPACE
155    if EfiSourceDir.upper().find(WorkspaceDir.upper()) != 0:
156        EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE is not under WORKSPACE",
157                        ExtraData="WORKSPACE = %s\n    EFI_SOURCE = %s" % (WorkspaceDir, EfiSourceDir))
158    if EdkSourceDir.upper().find(WorkspaceDir.upper()) != 0:
159        EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE is not under WORKSPACE",
160                        ExtraData="WORKSPACE = %s\n    EDK_SOURCE = %s" % (WorkspaceDir, EdkSourceDir))
161    if EcpSourceDir.upper().find(WorkspaceDir.upper()) != 0:
162        EdkLogger.error("build", PARAMETER_INVALID, "ECP_SOURCE is not under WORKSPACE",
163                        ExtraData="WORKSPACE = %s\n    ECP_SOURCE = %s" % (WorkspaceDir, EcpSourceDir))
164
165    # check EDK_TOOLS_PATH
166    if "EDK_TOOLS_PATH" not in os.environ:
167        EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
168                        ExtraData="EDK_TOOLS_PATH")
169
170    # check PATH
171    if "PATH" not in os.environ:
172        EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
173                        ExtraData="PATH")
174
175    GlobalData.gWorkspace = WorkspaceDir
176    GlobalData.gEfiSource = EfiSourceDir
177    GlobalData.gEdkSource = EdkSourceDir
178    GlobalData.gEcpSource = EcpSourceDir
179
180    GlobalData.gGlobalDefines["WORKSPACE"]  = WorkspaceDir
181    GlobalData.gGlobalDefines["EFI_SOURCE"] = EfiSourceDir
182    GlobalData.gGlobalDefines["EDK_SOURCE"] = EdkSourceDir
183    GlobalData.gGlobalDefines["ECP_SOURCE"] = EcpSourceDir
184    GlobalData.gGlobalDefines["EDK_TOOLS_PATH"] = os.environ["EDK_TOOLS_PATH"]
185
186## Get normalized file path
187#
188# Convert the path to be local format, and remove the WORKSPACE path at the
189# beginning if the file path is given in full path.
190#
191# @param  FilePath      File path to be normalized
192# @param  Workspace     Workspace path which the FilePath will be checked against
193#
194# @retval string        The normalized file path
195#
196def NormFile(FilePath, Workspace):
197    # check if the path is absolute or relative
198    if os.path.isabs(FilePath):
199        FileFullPath = os.path.normpath(FilePath)
200    else:
201        FileFullPath = os.path.normpath(os.path.join(Workspace, FilePath))
202
203    # check if the file path exists or not
204    if not os.path.isfile(FileFullPath):
205        EdkLogger.error("build", FILE_NOT_FOUND, ExtraData="\t%s (Please give file in absolute path or relative to WORKSPACE)"  % FileFullPath)
206
207    # remove workspace directory from the beginning part of the file path
208    if Workspace[-1] in ["\\", "/"]:
209        return FileFullPath[len(Workspace):]
210    else:
211        return FileFullPath[(len(Workspace) + 1):]
212
213## Get the output of an external program
214#
215# This is the entrance method of thread reading output of an external program and
216# putting them in STDOUT/STDERR of current program.
217#
218# @param  From      The stream message read from
219# @param  To        The stream message put on
220# @param  ExitFlag  The flag used to indicate stopping reading
221#
222def ReadMessage(From, To, ExitFlag):
223    while True:
224        # read one line a time
225        Line = From.readline()
226        # empty string means "end"
227        if Line != None and Line != "":
228            To(Line.rstrip())
229        else:
230            break
231        if ExitFlag.isSet():
232            break
233
234## Launch an external program
235#
236# This method will call subprocess.Popen to execute an external program with
237# given options in specified directory. Because of the dead-lock issue during
238# redirecting output of the external program, threads are used to to do the
239# redirection work.
240#
241# @param  Command               A list or string containing the call of the program
242# @param  WorkingDir            The directory in which the program will be running
243#
244def LaunchCommand(Command, WorkingDir):
245    # if working directory doesn't exist, Popen() will raise an exception
246    if not os.path.isdir(WorkingDir):
247        EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=WorkingDir)
248
249    # Command is used as the first Argument in following Popen().
250    # It could be a string or sequence. We find that if command is a string in following Popen(),
251    # ubuntu may fail with an error message that the command is not found.
252    # So here we may need convert command from string to list instance.
253    if not isinstance(Command, list):
254        if platform.system() != 'Windows':
255            Command = Command.split()
256
257    Proc = None
258    EndOfProcedure = None
259    try:
260        # launch the command
261        Proc = Popen(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir, bufsize=-1)
262
263        # launch two threads to read the STDOUT and STDERR
264        EndOfProcedure = Event()
265        EndOfProcedure.clear()
266        if Proc.stdout:
267            StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure))
268            StdOutThread.setName("STDOUT-Redirector")
269            StdOutThread.setDaemon(False)
270            StdOutThread.start()
271
272        if Proc.stderr:
273            StdErrThread = Thread(target=ReadMessage, args=(Proc.stderr, EdkLogger.quiet, EndOfProcedure))
274            StdErrThread.setName("STDERR-Redirector")
275            StdErrThread.setDaemon(False)
276            StdErrThread.start()
277
278        # waiting for program exit
279        Proc.wait()
280    except: # in case of aborting
281        # terminate the threads redirecting the program output
282        if EndOfProcedure != None:
283            EndOfProcedure.set()
284        if Proc == None:
285            if type(Command) != type(""):
286                Command = " ".join(Command)
287            EdkLogger.error("build", COMMAND_FAILURE, "Failed to start command", ExtraData="%s [%s]" % (Command, WorkingDir))
288
289    if Proc.stdout:
290        StdOutThread.join()
291    if Proc.stderr:
292        StdErrThread.join()
293
294    # check the return code of the program
295    if Proc.returncode != 0:
296        if type(Command) != type(""):
297            Command = " ".join(Command)
298        EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir))
299
300## The smallest unit that can be built in multi-thread build mode
301#
302# This is the base class of build unit. The "Obj" parameter must provide
303# __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
304# missing build.
305#
306# Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
307#
308class BuildUnit:
309    ## The constructor
310    #
311    #   @param  self        The object pointer
312    #   @param  Obj         The object the build is working on
313    #   @param  Target      The build target name, one of gSupportedTarget
314    #   @param  Dependency  The BuildUnit(s) which must be completed in advance
315    #   @param  WorkingDir  The directory build command starts in
316    #
317    def __init__(self, Obj, BuildCommand, Target, Dependency, WorkingDir="."):
318        self.BuildObject = Obj
319        self.Dependency = Dependency
320        self.WorkingDir = WorkingDir
321        self.Target = Target
322        self.BuildCommand = BuildCommand
323        if not BuildCommand:
324            EdkLogger.error("build", OPTION_MISSING,
325                            "No build command found for this module. "
326                            "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
327                                (Obj.BuildTarget, Obj.ToolChain, Obj.Arch),
328                            ExtraData=str(Obj))
329
330
331    ## str() method
332    #
333    #   It just returns the string representation of self.BuildObject
334    #
335    #   @param  self        The object pointer
336    #
337    def __str__(self):
338        return str(self.BuildObject)
339
340    ## "==" operator method
341    #
342    #   It just compares self.BuildObject with "Other". So self.BuildObject must
343    #   provide its own __eq__() method.
344    #
345    #   @param  self        The object pointer
346    #   @param  Other       The other BuildUnit object compared to
347    #
348    def __eq__(self, Other):
349        return Other != None and self.BuildObject == Other.BuildObject \
350                and self.BuildObject.Arch == Other.BuildObject.Arch
351
352    ## hash() method
353    #
354    #   It just returns the hash value of self.BuildObject which must be hashable.
355    #
356    #   @param  self        The object pointer
357    #
358    def __hash__(self):
359        return hash(self.BuildObject) + hash(self.BuildObject.Arch)
360
361    def __repr__(self):
362        return repr(self.BuildObject)
363
364## The smallest module unit that can be built by nmake/make command in multi-thread build mode
365#
366# This class is for module build by nmake/make build system. The "Obj" parameter
367# must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
368# be make units missing build.
369#
370# Currently the "Obj" should be only ModuleAutoGen object.
371#
372class ModuleMakeUnit(BuildUnit):
373    ## The constructor
374    #
375    #   @param  self        The object pointer
376    #   @param  Obj         The ModuleAutoGen object the build is working on
377    #   @param  Target      The build target name, one of gSupportedTarget
378    #
379    def __init__(self, Obj, Target):
380        Dependency = [ModuleMakeUnit(La, Target) for La in Obj.LibraryAutoGenList]
381        BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)
382        if Target in [None, "", "all"]:
383            self.Target = "tbuild"
384
385## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
386#
387# This class is for platform build by nmake/make build system. The "Obj" parameter
388# must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
389# be make units missing build.
390#
391# Currently the "Obj" should be only PlatformAutoGen object.
392#
393class PlatformMakeUnit(BuildUnit):
394    ## The constructor
395    #
396    #   @param  self        The object pointer
397    #   @param  Obj         The PlatformAutoGen object the build is working on
398    #   @param  Target      The build target name, one of gSupportedTarget
399    #
400    def __init__(self, Obj, Target):
401        Dependency = [ModuleMakeUnit(Lib, Target) for Lib in self.BuildObject.LibraryAutoGenList]
402        Dependency.extend([ModuleMakeUnit(Mod, Target) for Mod in self.BuildObject.ModuleAutoGenList])
403        BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)
404
405## The class representing the task of a module build or platform build
406#
407# This class manages the build tasks in multi-thread build mode. Its jobs include
408# scheduling thread running, catching thread error, monitor the thread status, etc.
409#
410class BuildTask:
411    # queue for tasks waiting for schedule
412    _PendingQueue = sdict()
413    _PendingQueueLock = threading.Lock()
414
415    # queue for tasks ready for running
416    _ReadyQueue = sdict()
417    _ReadyQueueLock = threading.Lock()
418
419    # queue for run tasks
420    _RunningQueue = sdict()
421    _RunningQueueLock = threading.Lock()
422
423    # queue containing all build tasks, in case duplicate build
424    _TaskQueue = sdict()
425
426    # flag indicating error occurs in a running thread
427    _ErrorFlag = threading.Event()
428    _ErrorFlag.clear()
429    _ErrorMessage = ""
430
431    # BoundedSemaphore object used to control the number of running threads
432    _Thread = None
433
434    # flag indicating if the scheduler is started or not
435    _SchedulerStopped = threading.Event()
436    _SchedulerStopped.set()
437
438    ## Start the task scheduler thread
439    #
440    #   @param  MaxThreadNumber     The maximum thread number
441    #   @param  ExitFlag            Flag used to end the scheduler
442    #
443    @staticmethod
444    def StartScheduler(MaxThreadNumber, ExitFlag):
445        SchedulerThread = Thread(target=BuildTask.Scheduler, args=(MaxThreadNumber, ExitFlag))
446        SchedulerThread.setName("Build-Task-Scheduler")
447        SchedulerThread.setDaemon(False)
448        SchedulerThread.start()
449        # wait for the scheduler to be started, especially useful in Linux
450        while not BuildTask.IsOnGoing():
451            time.sleep(0.01)
452
453    ## Scheduler method
454    #
455    #   @param  MaxThreadNumber     The maximum thread number
456    #   @param  ExitFlag            Flag used to end the scheduler
457    #
458    @staticmethod
459    def Scheduler(MaxThreadNumber, ExitFlag):
460        BuildTask._SchedulerStopped.clear()
461        try:
462            # use BoundedSemaphore to control the maximum running threads
463            BuildTask._Thread = BoundedSemaphore(MaxThreadNumber)
464            #
465            # scheduling loop, which will exits when no pending/ready task and
466            # indicated to do so, or there's error in running thread
467            #
468            while (len(BuildTask._PendingQueue) > 0 or len(BuildTask._ReadyQueue) > 0 \
469                   or not ExitFlag.isSet()) and not BuildTask._ErrorFlag.isSet():
470                EdkLogger.debug(EdkLogger.DEBUG_8, "Pending Queue (%d), Ready Queue (%d)"
471                                % (len(BuildTask._PendingQueue), len(BuildTask._ReadyQueue)))
472
473                # get all pending tasks
474                BuildTask._PendingQueueLock.acquire()
475                BuildObjectList = BuildTask._PendingQueue.keys()
476                #
477                # check if their dependency is resolved, and if true, move them
478                # into ready queue
479                #
480                for BuildObject in BuildObjectList:
481                    Bt = BuildTask._PendingQueue[BuildObject]
482                    if Bt.IsReady():
483                        BuildTask._ReadyQueue[BuildObject] = BuildTask._PendingQueue.pop(BuildObject)
484                BuildTask._PendingQueueLock.release()
485
486                # launch build thread until the maximum number of threads is reached
487                while not BuildTask._ErrorFlag.isSet():
488                    # empty ready queue, do nothing further
489                    if len(BuildTask._ReadyQueue) == 0:
490                        break
491
492                    # wait for active thread(s) exit
493                    BuildTask._Thread.acquire(True)
494
495                    # start a new build thread
496                    Bo = BuildTask._ReadyQueue.keys()[0]
497                    Bt = BuildTask._ReadyQueue.pop(Bo)
498
499                    # move into running queue
500                    BuildTask._RunningQueueLock.acquire()
501                    BuildTask._RunningQueue[Bo] = Bt
502                    BuildTask._RunningQueueLock.release()
503
504                    Bt.Start()
505                    # avoid tense loop
506                    time.sleep(0.01)
507
508                # avoid tense loop
509                time.sleep(0.01)
510
511            # wait for all running threads exit
512            if BuildTask._ErrorFlag.isSet():
513                EdkLogger.quiet("\nWaiting for all build threads exit...")
514            # while not BuildTask._ErrorFlag.isSet() and \
515            while len(BuildTask._RunningQueue) > 0:
516                EdkLogger.verbose("Waiting for thread ending...(%d)" % len(BuildTask._RunningQueue))
517                EdkLogger.debug(EdkLogger.DEBUG_8, "Threads [%s]" % ", ".join([Th.getName() for Th in threading.enumerate()]))
518                # avoid tense loop
519                time.sleep(0.1)
520        except BaseException, X:
521            #
522            # TRICK: hide the output of threads left runing, so that the user can
523            #        catch the error message easily
524            #
525            EdkLogger.SetLevel(EdkLogger.ERROR)
526            BuildTask._ErrorFlag.set()
527            BuildTask._ErrorMessage = "build thread scheduler error\n\t%s" % str(X)
528
529        BuildTask._PendingQueue.clear()
530        BuildTask._ReadyQueue.clear()
531        BuildTask._RunningQueue.clear()
532        BuildTask._TaskQueue.clear()
533        BuildTask._SchedulerStopped.set()
534
535    ## Wait for all running method exit
536    #
537    @staticmethod
538    def WaitForComplete():
539        BuildTask._SchedulerStopped.wait()
540
541    ## Check if the scheduler is running or not
542    #
543    @staticmethod
544    def IsOnGoing():
545        return not BuildTask._SchedulerStopped.isSet()
546
547    ## Abort the build
548    @staticmethod
549    def Abort():
550        if BuildTask.IsOnGoing():
551            BuildTask._ErrorFlag.set()
552            BuildTask.WaitForComplete()
553
554    ## Check if there's error in running thread
555    #
556    #   Since the main thread cannot catch exceptions in other thread, we have to
557    #   use threading.Event to communicate this formation to main thread.
558    #
559    @staticmethod
560    def HasError():
561        return BuildTask._ErrorFlag.isSet()
562
563    ## Get error message in running thread
564    #
565    #   Since the main thread cannot catch exceptions in other thread, we have to
566    #   use a static variable to communicate this message to main thread.
567    #
568    @staticmethod
569    def GetErrorMessage():
570        return BuildTask._ErrorMessage
571
572    ## Factory method to create a BuildTask object
573    #
574    #   This method will check if a module is building or has been built. And if
575    #   true, just return the associated BuildTask object in the _TaskQueue. If
576    #   not, create and return a new BuildTask object. The new BuildTask object
577    #   will be appended to the _PendingQueue for scheduling later.
578    #
579    #   @param  BuildItem       A BuildUnit object representing a build object
580    #   @param  Dependency      The dependent build object of BuildItem
581    #
582    @staticmethod
583    def New(BuildItem, Dependency=None):
584        if BuildItem in BuildTask._TaskQueue:
585            Bt = BuildTask._TaskQueue[BuildItem]
586            return Bt
587
588        Bt = BuildTask()
589        Bt._Init(BuildItem, Dependency)
590        BuildTask._TaskQueue[BuildItem] = Bt
591
592        BuildTask._PendingQueueLock.acquire()
593        BuildTask._PendingQueue[BuildItem] = Bt
594        BuildTask._PendingQueueLock.release()
595
596        return Bt
597
598    ## The real constructor of BuildTask
599    #
600    #   @param  BuildItem       A BuildUnit object representing a build object
601    #   @param  Dependency      The dependent build object of BuildItem
602    #
603    def _Init(self, BuildItem, Dependency=None):
604        self.BuildItem = BuildItem
605
606        self.DependencyList = []
607        if Dependency == None:
608            Dependency = BuildItem.Dependency
609        else:
610            Dependency.extend(BuildItem.Dependency)
611        self.AddDependency(Dependency)
612        # flag indicating build completes, used to avoid unnecessary re-build
613        self.CompleteFlag = False
614
615    ## Check if all dependent build tasks are completed or not
616    #
617    def IsReady(self):
618        ReadyFlag = True
619        for Dep in self.DependencyList:
620            if Dep.CompleteFlag == True:
621                continue
622            ReadyFlag = False
623            break
624
625        return ReadyFlag
626
627    ## Add dependent build task
628    #
629    #   @param  Dependency      The list of dependent build objects
630    #
631    def AddDependency(self, Dependency):
632        for Dep in Dependency:
633            if not Dep.BuildObject.IsBinaryModule:
634                self.DependencyList.append(BuildTask.New(Dep))    # BuildTask list
635
636    ## The thread wrapper of LaunchCommand function
637    #
638    # @param  Command               A list or string contains the call of the command
639    # @param  WorkingDir            The directory in which the program will be running
640    #
641    def _CommandThread(self, Command, WorkingDir):
642        try:
643            LaunchCommand(Command, WorkingDir)
644            self.CompleteFlag = True
645        except:
646            #
647            # TRICK: hide the output of threads left runing, so that the user can
648            #        catch the error message easily
649            #
650            if not BuildTask._ErrorFlag.isSet():
651                GlobalData.gBuildingModule = "%s [%s, %s, %s]" % (str(self.BuildItem.BuildObject),
652                                                                  self.BuildItem.BuildObject.Arch,
653                                                                  self.BuildItem.BuildObject.ToolChain,
654                                                                  self.BuildItem.BuildObject.BuildTarget
655                                                                 )
656            EdkLogger.SetLevel(EdkLogger.ERROR)
657            BuildTask._ErrorFlag.set()
658            BuildTask._ErrorMessage = "%s broken\n    %s [%s]" % \
659                                      (threading.currentThread().getName(), Command, WorkingDir)
660        # indicate there's a thread is available for another build task
661        BuildTask._RunningQueueLock.acquire()
662        BuildTask._RunningQueue.pop(self.BuildItem)
663        BuildTask._RunningQueueLock.release()
664        BuildTask._Thread.release()
665
666    ## Start build task thread
667    #
668    def Start(self):
669        EdkLogger.quiet("Building ... %s" % repr(self.BuildItem))
670        Command = self.BuildItem.BuildCommand + [self.BuildItem.Target]
671        self.BuildTread = Thread(target=self._CommandThread, args=(Command, self.BuildItem.WorkingDir))
672        self.BuildTread.setName("build thread")
673        self.BuildTread.setDaemon(False)
674        self.BuildTread.start()
675
676## The class contains the information related to EFI image
677#
678class PeImageInfo():
679    ## Constructor
680    #
681    # Constructor will load all required image information.
682    #
683    #   @param  BaseName          The full file path of image.
684    #   @param  Guid              The GUID for image.
685    #   @param  Arch              Arch of this image.
686    #   @param  OutputDir         The output directory for image.
687    #   @param  DebugDir          The debug directory for image.
688    #   @param  ImageClass        PeImage Information
689    #
690    def __init__(self, BaseName, Guid, Arch, OutputDir, DebugDir, ImageClass):
691        self.BaseName         = BaseName
692        self.Guid             = Guid
693        self.Arch             = Arch
694        self.OutputDir        = OutputDir
695        self.DebugDir         = DebugDir
696        self.Image            = ImageClass
697        self.Image.Size       = (self.Image.Size / 0x1000 + 1) * 0x1000
698
699## The class implementing the EDK2 build process
700#
701#   The build process includes:
702#       1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
703#       2. Parse DSC file of active platform
704#       3. Parse FDF file if any
705#       4. Establish build database, including parse all other files (module, package)
706#       5. Create AutoGen files (C code file, depex file, makefile) if necessary
707#       6. Call build command
708#
709class Build():
710    ## Constructor
711    #
712    # Constructor will load all necessary configurations, parse platform, modules
713    # and packages and the establish a database for AutoGen.
714    #
715    #   @param  Target              The build command target, one of gSupportedTarget
716    #   @param  WorkspaceDir        The directory of workspace
717    #   @param  BuildOptions        Build options passed from command line
718    #
719    def __init__(self, Target, WorkspaceDir, BuildOptions):
720        self.WorkspaceDir   = WorkspaceDir
721        self.Target         = Target
722        self.PlatformFile   = BuildOptions.PlatformFile
723        self.ModuleFile     = BuildOptions.ModuleFile
724        self.ArchList       = BuildOptions.TargetArch
725        self.ToolChainList  = BuildOptions.ToolChain
726        self.BuildTargetList= BuildOptions.BuildTarget
727        self.Fdf            = BuildOptions.FdfFile
728        self.FdList         = BuildOptions.RomImage
729        self.FvList         = BuildOptions.FvImage
730        self.CapList        = BuildOptions.CapName
731        self.SilentMode     = BuildOptions.SilentMode
732        self.ThreadNumber   = BuildOptions.ThreadNumber
733        self.SkipAutoGen    = BuildOptions.SkipAutoGen
734        self.Reparse        = BuildOptions.Reparse
735        self.SkuId          = BuildOptions.SkuId
736        self.ConfDirectory = BuildOptions.ConfDirectory
737        self.SpawnMode      = True
738        self.BuildReport    = BuildReport(BuildOptions.ReportFile, BuildOptions.ReportType)
739        self.TargetTxt      = TargetTxtClassObject()
740        self.ToolDef        = ToolDefClassObject()
741        #Set global flag for build mode
742        GlobalData.gIgnoreSource = BuildOptions.IgnoreSources
743
744        if self.ConfDirectory:
745            # Get alternate Conf location, if it is absolute, then just use the absolute directory name
746            ConfDirectoryPath = os.path.normpath(self.ConfDirectory)
747
748            if not os.path.isabs(ConfDirectoryPath):
749                # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
750                # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
751                ConfDirectoryPath = os.path.join(self.WorkspaceDir, ConfDirectoryPath)
752        else:
753            # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf
754            ConfDirectoryPath = os.path.join(self.WorkspaceDir, 'Conf')
755        GlobalData.gConfDirectory = ConfDirectoryPath
756        GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath))
757
758        if BuildOptions.DisableCache:
759            self.Db         = WorkspaceDatabase(":memory:")
760        else:
761            self.Db = WorkspaceDatabase(GlobalData.gDatabasePath, self.Reparse)
762        self.BuildDatabase = self.Db.BuildObject
763        self.Platform = None
764        self.LoadFixAddress = 0
765        self.UniFlag        = BuildOptions.Flag
766        self.BuildModules = []
767
768        # print dot character during doing some time-consuming work
769        self.Progress = Utils.Progressor()
770
771        self.InitBuild()
772
773        # print current build environment and configuration
774        EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))
775        EdkLogger.quiet("%-16s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"]))
776        EdkLogger.quiet("%-16s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"]))
777        EdkLogger.quiet("%-16s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"]))
778        EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))
779
780        EdkLogger.info("")
781
782        os.chdir(self.WorkspaceDir)
783
784    ## Load configuration
785    #
786    #   This method will parse target.txt and get the build configurations.
787    #
788    def LoadConfiguration(self):
789        #
790        # Check target.txt and tools_def.txt and Init them
791        #
792        BuildConfigurationFile = os.path.normpath(os.path.join(GlobalData.gConfDirectory, gBuildConfiguration))
793        if os.path.isfile(BuildConfigurationFile) == True:
794            StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)
795
796            ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]
797            if ToolDefinitionFile == '':
798                ToolDefinitionFile = gToolsDefinition
799                ToolDefinitionFile = os.path.normpath(os.path.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile))
800            if os.path.isfile(ToolDefinitionFile) == True:
801                StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)
802            else:
803                EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)
804        else:
805            EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)
806
807        # if no ARCH given in command line, get it from target.txt
808        if not self.ArchList:
809            self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH]
810        self.ArchList = tuple(self.ArchList)
811
812        # if no build target given in command line, get it from target.txt
813        if not self.BuildTargetList:
814            self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]
815
816        # if no tool chain given in command line, get it from target.txt
817        if not self.ToolChainList:
818            self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]
819            if self.ToolChainList == None or len(self.ToolChainList) == 0:
820                EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")
821
822        # check if the tool chains are defined or not
823        NewToolChainList = []
824        for ToolChain in self.ToolChainList:
825            if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:
826                EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)
827            else:
828                NewToolChainList.append(ToolChain)
829        # if no tool chain available, break the build
830        if len(NewToolChainList) == 0:
831            EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
832                            ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))
833        else:
834            self.ToolChainList = NewToolChainList
835
836        if self.ThreadNumber == None:
837            self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]
838            if self.ThreadNumber == '':
839                self.ThreadNumber = 0
840            else:
841                self.ThreadNumber = int(self.ThreadNumber, 0)
842
843        if self.ThreadNumber == 0:
844            self.ThreadNumber = 1
845
846        if not self.PlatformFile:
847            PlatformFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM]
848            if not PlatformFile:
849                # Try to find one in current directory
850                WorkingDirectory = os.getcwd()
851                FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))
852                FileNum = len(FileList)
853                if FileNum >= 2:
854                    EdkLogger.error("build", OPTION_MISSING,
855                                    ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))
856                elif FileNum == 1:
857                    PlatformFile = FileList[0]
858                else:
859                    EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
860                                    ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")
861
862            self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)
863
864    ## Initialize build configuration
865    #
866    #   This method will parse DSC file and merge the configurations from
867    #   command line and target.txt, then get the final build configurations.
868    #
869    def InitBuild(self):
870        # parse target.txt, tools_def.txt, and platform file
871        self.LoadConfiguration()
872
873        # Allow case-insensitive for those from command line or configuration file
874        ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)
875        if ErrorCode != 0:
876            EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
877
878        # create metafile database
879        self.Db.InitDatabase()
880
881    ## Build a module or platform
882    #
883    # Create autogen code and makefile for a module or platform, and the launch
884    # "make" command to build it
885    #
886    #   @param  Target                      The target of build command
887    #   @param  Platform                    The platform file
888    #   @param  Module                      The module file
889    #   @param  BuildTarget                 The name of build target, one of "DEBUG", "RELEASE"
890    #   @param  ToolChain                   The name of toolchain to build
891    #   @param  Arch                        The arch of the module/platform
892    #   @param  CreateDepModuleCodeFile     Flag used to indicate creating code
893    #                                       for dependent modules/Libraries
894    #   @param  CreateDepModuleMakeFile     Flag used to indicate creating makefile
895    #                                       for dependent modules/Libraries
896    #
897    def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):
898        if AutoGenObject == None:
899            return False
900
901        # skip file generation for cleanxxx targets, run and fds target
902        if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
903            # for target which must generate AutoGen code and makefile
904            if not self.SkipAutoGen or Target == 'genc':
905                self.Progress.Start("Generating code")
906                AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
907                self.Progress.Stop("done!")
908            if Target == "genc":
909                return True
910
911            if not self.SkipAutoGen or Target == 'genmake':
912                self.Progress.Start("Generating makefile")
913                AutoGenObject.CreateMakeFile(CreateDepsMakeFile)
914                self.Progress.Stop("done!")
915            if Target == "genmake":
916                return True
917        else:
918            # always recreate top/platform makefile when clean, just in case of inconsistency
919            AutoGenObject.CreateCodeFile(False)
920            AutoGenObject.CreateMakeFile(False)
921
922        if EdkLogger.GetLevel() == EdkLogger.QUIET:
923            EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
924
925        BuildCommand = AutoGenObject.BuildCommand
926        if BuildCommand == None or len(BuildCommand) == 0:
927            EdkLogger.error("build", OPTION_MISSING,
928                            "No build command found for this module. "
929                            "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
930                                (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
931                            ExtraData=str(AutoGenObject))
932
933        makefile = GenMake.BuildFile(AutoGenObject)._FILE_NAME_[GenMake.gMakeType]
934
935        # run
936        if Target == 'run':
937            RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))
938            Command = '.\SecMain'
939            os.chdir(RunDir)
940            LaunchCommand(Command, RunDir)
941            return True
942
943        # build modules
944        if BuildModule:
945            BuildCommand = BuildCommand + [Target]
946            LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
947            self.CreateAsBuiltInf()
948            return True
949
950        # build library
951        if Target == 'libraries':
952            for Lib in AutoGenObject.LibraryBuildDirectoryList:
953                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']
954                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
955            return True
956
957        # build module
958        if Target == 'modules':
959            for Lib in AutoGenObject.LibraryBuildDirectoryList:
960                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']
961                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
962            for Mod in AutoGenObject.ModuleBuildDirectoryList:
963                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']
964                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
965            self.CreateAsBuiltInf()
966            return True
967
968        # cleanlib
969        if Target == 'cleanlib':
970            for Lib in AutoGenObject.LibraryBuildDirectoryList:
971                LibMakefile = os.path.normpath(os.path.join(Lib, makefile))
972                if os.path.exists(LibMakefile):
973                    NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
974                    LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
975            return True
976
977        # clean
978        if Target == 'clean':
979            for Mod in AutoGenObject.ModuleBuildDirectoryList:
980                ModMakefile = os.path.normpath(os.path.join(Mod, makefile))
981                if os.path.exists(ModMakefile):
982                    NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']
983                    LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
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        # cleanall
992        if Target == 'cleanall':
993            try:
994                #os.rmdir(AutoGenObject.BuildDir)
995                RemoveDirectory(AutoGenObject.BuildDir, True)
996            except WindowsError, X:
997                EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
998        return True
999
1000    ## Build a module or platform
1001    #
1002    # Create autogen code and makefile for a module or platform, and the launch
1003    # "make" command to build it
1004    #
1005    #   @param  Target                      The target of build command
1006    #   @param  Platform                    The platform file
1007    #   @param  Module                      The module file
1008    #   @param  BuildTarget                 The name of build target, one of "DEBUG", "RELEASE"
1009    #   @param  ToolChain                   The name of toolchain to build
1010    #   @param  Arch                        The arch of the module/platform
1011    #   @param  CreateDepModuleCodeFile     Flag used to indicate creating code
1012    #                                       for dependent modules/Libraries
1013    #   @param  CreateDepModuleMakeFile     Flag used to indicate creating makefile
1014    #                                       for dependent modules/Libraries
1015    #
1016    def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):
1017        if AutoGenObject == None:
1018            return False
1019
1020        # skip file generation for cleanxxx targets, run and fds target
1021        if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1022            # for target which must generate AutoGen code and makefile
1023            if not self.SkipAutoGen or Target == 'genc':
1024                self.Progress.Start("Generating code")
1025                AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
1026                self.Progress.Stop("done!")
1027            if Target == "genc":
1028                return True
1029
1030            if not self.SkipAutoGen or Target == 'genmake':
1031                self.Progress.Start("Generating makefile")
1032                AutoGenObject.CreateMakeFile(CreateDepsMakeFile)
1033                #AutoGenObject.CreateAsBuiltInf()
1034                self.Progress.Stop("done!")
1035            if Target == "genmake":
1036                return True
1037        else:
1038            # always recreate top/platform makefile when clean, just in case of inconsistency
1039            AutoGenObject.CreateCodeFile(False)
1040            AutoGenObject.CreateMakeFile(False)
1041
1042        if EdkLogger.GetLevel() == EdkLogger.QUIET:
1043            EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
1044
1045        BuildCommand = AutoGenObject.BuildCommand
1046        if BuildCommand == None or len(BuildCommand) == 0:
1047            EdkLogger.error("build", OPTION_MISSING,
1048                            "No build command found for this module. "
1049                            "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1050                                (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
1051                            ExtraData=str(AutoGenObject))
1052
1053        # build modules
1054        if BuildModule:
1055            if Target != 'fds':
1056                BuildCommand = BuildCommand + [Target]
1057            LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
1058            self.CreateAsBuiltInf()
1059            return True
1060
1061        # genfds
1062        if Target == 'fds':
1063            LaunchCommand(AutoGenObject.GenFdsCommand, AutoGenObject.MakeFileDir)
1064            return True
1065
1066        # run
1067        if Target == 'run':
1068            RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))
1069            Command = '.\SecMain'
1070            os.chdir(RunDir)
1071            LaunchCommand(Command, RunDir)
1072            return True
1073
1074        # build library
1075        if Target == 'libraries':
1076            pass
1077
1078        # not build modules
1079
1080
1081        # cleanall
1082        if Target == 'cleanall':
1083            try:
1084                #os.rmdir(AutoGenObject.BuildDir)
1085                RemoveDirectory(AutoGenObject.BuildDir, True)
1086            except WindowsError, X:
1087                EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
1088        return True
1089
1090    ## Rebase module image and Get function address for the input module list.
1091    #
1092    def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):
1093        if ModeIsSmm:
1094            AddrIsOffset = False
1095        InfFileNameList = ModuleList.keys()
1096        #InfFileNameList.sort()
1097        for InfFile in InfFileNameList:
1098            sys.stdout.write (".")
1099            sys.stdout.flush()
1100            ModuleInfo = ModuleList[InfFile]
1101            ModuleName = ModuleInfo.BaseName
1102            ModuleOutputImage = ModuleInfo.Image.FileName
1103            ModuleDebugImage  = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')
1104            ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1105            if not ModeIsSmm:
1106                BaseAddress = BaseAddress - ModuleInfo.Image.Size
1107                #
1108                # Update Image to new BaseAddress by GenFw tool
1109                #
1110                LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
1111                LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage],  ModuleInfo.DebugDir)
1112            else:
1113                #
1114                # Set new address to the section header only for SMM driver.
1115                #
1116                LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
1117                LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage],  ModuleInfo.DebugDir)
1118            #
1119            # Collect funtion address from Map file
1120            #
1121            ImageMapTable = ModuleOutputImage.replace('.efi', '.map')
1122            FunctionList = []
1123            if os.path.exists(ImageMapTable):
1124                OrigImageBaseAddress = 0
1125                ImageMap = open (ImageMapTable, 'r')
1126                for LinStr in ImageMap:
1127                    if len (LinStr.strip()) == 0:
1128                        continue
1129                    #
1130                    # Get the preferred address set on link time.
1131                    #
1132                    if LinStr.find ('Preferred load address is') != -1:
1133                        StrList = LinStr.split()
1134                        OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)
1135
1136                    StrList = LinStr.split()
1137                    if len (StrList) > 4:
1138                        if StrList[3] == 'f' or StrList[3] =='F':
1139                            Name = StrList[1]
1140                            RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress
1141                            FunctionList.append ((Name, RelativeAddress))
1142                            if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'):
1143                                #
1144                                # Get the real entry point address for IPF image.
1145                                #
1146                                ModuleInfo.Image.EntryPoint = RelativeAddress
1147                ImageMap.close()
1148            #
1149            # Add general information.
1150            #
1151            if ModeIsSmm:
1152                MapBuffer.write('\n\n%s (Fixed SMRAM Offset,   BaseAddress=0x%010X,  EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
1153            elif AddrIsOffset:
1154                MapBuffer.write('\n\n%s (Fixed Memory Offset,  BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))
1155            else:
1156                MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X,  EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
1157            #
1158            # Add guid and general seciton section.
1159            #
1160            TextSectionAddress = 0
1161            DataSectionAddress = 0
1162            for SectionHeader in ModuleInfo.Image.SectionHeaderList:
1163                if SectionHeader[0] == '.text':
1164                    TextSectionAddress = SectionHeader[1]
1165                elif SectionHeader[0] in ['.data', '.sdata']:
1166                    DataSectionAddress = SectionHeader[1]
1167            if AddrIsOffset:
1168                MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))
1169            else:
1170                MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))
1171            #
1172            # Add debug image full path.
1173            #
1174            MapBuffer.write('(IMAGE=%s)\n\n' % (ModuleDebugImage))
1175            #
1176            # Add funtion address
1177            #
1178            for Function in FunctionList:
1179                if AddrIsOffset:
1180                    MapBuffer.write('  -0x%010X    %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))
1181                else:
1182                    MapBuffer.write('  0x%010X    %s\n' % (BaseAddress + Function[1], Function[0]))
1183            ImageMap.close()
1184
1185            #
1186            # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1187            #
1188            if ModeIsSmm:
1189                BaseAddress = BaseAddress + ModuleInfo.Image.Size
1190
1191    ## Collect MAP information of all FVs
1192    #
1193    def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):
1194        if self.Fdf:
1195            # First get the XIP base address for FV map file.
1196            GuidPattern = re.compile("[-a-fA-F0-9]+")
1197            GuidName = re.compile("\(GUID=[-a-fA-F0-9]+")
1198            for FvName in Wa.FdfProfile.FvDict.keys():
1199                FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')
1200                if not os.path.exists(FvMapBuffer):
1201                    continue
1202                FvMap = open(FvMapBuffer, 'r')
1203                #skip FV size information
1204                FvMap.readline()
1205                FvMap.readline()
1206                FvMap.readline()
1207                FvMap.readline()
1208                for Line in FvMap:
1209                    MatchGuid = GuidPattern.match(Line)
1210                    if MatchGuid != None:
1211                        #
1212                        # Replace GUID with module name
1213                        #
1214                        GuidString = MatchGuid.group()
1215                        if GuidString.upper() in ModuleList:
1216                            Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)
1217                    MapBuffer.write('%s' % (Line))
1218                    #
1219                    # Add the debug image full path.
1220                    #
1221                    MatchGuid = GuidName.match(Line)
1222                    if MatchGuid != None:
1223                        GuidString = MatchGuid.group().split("=")[1]
1224                        if GuidString.upper() in ModuleList:
1225                            MapBuffer.write('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))
1226
1227                FvMap.close()
1228
1229    ## Collect MAP information of all modules
1230    #
1231    def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):
1232        sys.stdout.write ("Generate Load Module At Fix Address Map")
1233        sys.stdout.flush()
1234        PatchEfiImageList = []
1235        PeiModuleList  = {}
1236        BtModuleList   = {}
1237        RtModuleList   = {}
1238        SmmModuleList  = {}
1239        PeiSize = 0
1240        BtSize  = 0
1241        RtSize  = 0
1242        # reserve 4K size in SMRAM to make SMM module address not from 0.
1243        SmmSize = 0x1000
1244        IsIpfPlatform = False
1245        if 'IPF' in self.ArchList:
1246            IsIpfPlatform = True
1247        for ModuleGuid in ModuleList:
1248            Module = ModuleList[ModuleGuid]
1249            GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)
1250
1251            OutputImageFile = ''
1252            for ResultFile in Module.CodaTargetList:
1253                if str(ResultFile.Target).endswith('.efi'):
1254                    #
1255                    # module list for PEI, DXE, RUNTIME and SMM
1256                    #
1257                    OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')
1258                    ImageClass = PeImageClass (OutputImageFile)
1259                    if not ImageClass.IsValid:
1260                        EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)
1261                    ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)
1262                    if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER','PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']:
1263                        PeiModuleList[Module.MetaFile] = ImageInfo
1264                        PeiSize += ImageInfo.Image.Size
1265                    elif Module.ModuleType in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']:
1266                        BtModuleList[Module.MetaFile] = ImageInfo
1267                        BtSize += ImageInfo.Image.Size
1268                    elif Module.ModuleType in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']:
1269                        RtModuleList[Module.MetaFile] = ImageInfo
1270                        #IPF runtime driver needs to be at 2 page alignment.
1271                        if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0:
1272                            ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000
1273                        RtSize += ImageInfo.Image.Size
1274                    elif Module.ModuleType in ['SMM_CORE', 'DXE_SMM_DRIVER']:
1275                        SmmModuleList[Module.MetaFile] = ImageInfo
1276                        SmmSize += ImageInfo.Image.Size
1277                        if Module.ModuleType == 'DXE_SMM_DRIVER':
1278                            PiSpecVersion = '0x00000000'
1279                            if 'PI_SPECIFICATION_VERSION' in Module.Module.Specification:
1280                                PiSpecVersion = Module.Module.Specification['PI_SPECIFICATION_VERSION']
1281                            # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1282                            if int(PiSpecVersion, 16) < 0x0001000A:
1283                                BtModuleList[Module.MetaFile] = ImageInfo
1284                                BtSize += ImageInfo.Image.Size
1285                    break
1286            #
1287            # EFI image is final target.
1288            # Check EFI image contains patchable FixAddress related PCDs.
1289            #
1290            if OutputImageFile != '':
1291                ModuleIsPatch = False
1292                for Pcd in Module.ModulePcdList:
1293                    if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:
1294                        ModuleIsPatch = True
1295                        break
1296                if not ModuleIsPatch:
1297                    for Pcd in Module.LibraryPcdList:
1298                        if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:
1299                            ModuleIsPatch = True
1300                            break
1301
1302                if not ModuleIsPatch:
1303                    continue
1304                #
1305                # Module includes the patchable load fix address PCDs.
1306                # It will be fixed up later.
1307                #
1308                PatchEfiImageList.append (OutputImageFile)
1309
1310        #
1311        # Get Top Memory address
1312        #
1313        ReservedRuntimeMemorySize = 0
1314        TopMemoryAddress = 0
1315        if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:
1316            TopMemoryAddress = 0
1317        else:
1318            TopMemoryAddress = self.LoadFixAddress
1319            if TopMemoryAddress < RtSize + BtSize + PeiSize:
1320                EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1321            # Make IPF runtime driver at 2 page alignment.
1322            if IsIpfPlatform:
1323                ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000
1324                RtSize = RtSize + ReservedRuntimeMemorySize
1325
1326        #
1327        # Patch FixAddress related PCDs into EFI image
1328        #
1329        for EfiImage in PatchEfiImageList:
1330            EfiImageMap = EfiImage.replace('.efi', '.map')
1331            if not os.path.exists(EfiImageMap):
1332                continue
1333            #
1334            # Get PCD offset in EFI image by GenPatchPcdTable function
1335            #
1336            PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)
1337            #
1338            # Patch real PCD value by PatchPcdValue tool
1339            #
1340            for PcdInfo in PcdTable:
1341                ReturnValue = 0
1342                if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:
1343                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize/0x1000))
1344                elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:
1345                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize/0x1000))
1346                elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:
1347                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize/0x1000))
1348                elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:
1349                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize/0x1000))
1350                if ReturnValue != 0:
1351                    EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)
1352
1353        MapBuffer.write('PEI_CODE_PAGE_NUMBER      = 0x%x\n' % (PeiSize/0x1000))
1354        MapBuffer.write('BOOT_CODE_PAGE_NUMBER     = 0x%x\n' % (BtSize/0x1000))
1355        MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER  = 0x%x\n' % (RtSize/0x1000))
1356        if len (SmmModuleList) > 0:
1357            MapBuffer.write('SMM_CODE_PAGE_NUMBER      = 0x%x\n' % (SmmSize/0x1000))
1358
1359        PeiBaseAddr = TopMemoryAddress - RtSize - BtSize
1360        BtBaseAddr  = TopMemoryAddress - RtSize
1361        RtBaseAddr  = TopMemoryAddress - ReservedRuntimeMemorySize
1362
1363        self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)
1364        self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)
1365        self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)
1366        self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset = False, ModeIsSmm = True)
1367        MapBuffer.write('\n\n')
1368        sys.stdout.write ("\n")
1369        sys.stdout.flush()
1370
1371    ## Save platform Map file
1372    #
1373    def _SaveMapFile (self, MapBuffer, Wa):
1374        #
1375        # Map file path is got.
1376        #
1377        MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')
1378        #
1379        # Save address map into MAP file.
1380        #
1381        SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)
1382        MapBuffer.close()
1383        if self.LoadFixAddress != 0:
1384            sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" %(MapFilePath))
1385        sys.stdout.flush()
1386
1387    ## Build active platform for different build targets and different tool chains
1388    #
1389    def _BuildPlatform(self):
1390        for BuildTarget in self.BuildTargetList:
1391            GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1392            for ToolChain in self.ToolChainList:
1393                GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1394                GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1395                Wa = WorkspaceAutoGen(
1396                        self.WorkspaceDir,
1397                        self.PlatformFile,
1398                        BuildTarget,
1399                        ToolChain,
1400                        self.ArchList,
1401                        self.BuildDatabase,
1402                        self.TargetTxt,
1403                        self.ToolDef,
1404                        self.Fdf,
1405                        self.FdList,
1406                        self.FvList,
1407                        self.CapList,
1408                        self.SkuId,
1409                        self.UniFlag,
1410                        self.Progress
1411                        )
1412                self.Fdf = Wa.FdfFile
1413                self.LoadFixAddress = Wa.Platform.LoadFixAddress
1414                self.BuildReport.AddPlatformReport(Wa)
1415                self.Progress.Stop("done!")
1416                for Arch in Wa.ArchList:
1417                    GlobalData.gGlobalDefines['ARCH'] = Arch
1418                    Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
1419                    for Module in Pa.Platform.Modules:
1420                        # Get ModuleAutoGen object to generate C code file and makefile
1421                        Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
1422                        if Ma == None:
1423                            continue
1424                        self.BuildModules.append(Ma)
1425                    self._BuildPa(self.Target, Pa)
1426
1427                # Create MAP file when Load Fix Address is enabled.
1428                if self.Target in ["", "all", "fds"]:
1429                    for Arch in Wa.ArchList:
1430                        GlobalData.gGlobalDefines['ARCH'] = Arch
1431                        #
1432                        # Check whether the set fix address is above 4G for 32bit image.
1433                        #
1434                        if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1435                            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")
1436                    #
1437                    # Get Module List
1438                    #
1439                    ModuleList = {}
1440                    for Pa in Wa.AutoGenObjectList:
1441                        for Ma in Pa.ModuleAutoGenList:
1442                            if Ma == None:
1443                                continue
1444                            if not Ma.IsLibrary:
1445                                ModuleList[Ma.Guid.upper()] = Ma
1446
1447                    MapBuffer = StringIO('')
1448                    if self.LoadFixAddress != 0:
1449                        #
1450                        # Rebase module to the preferred memory address before GenFds
1451                        #
1452                        self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1453                    if self.Fdf:
1454                        #
1455                        # create FDS again for the updated EFI image
1456                        #
1457                        self._Build("fds", Wa)
1458                        #
1459                        # Create MAP file for all platform FVs after GenFds.
1460                        #
1461                        self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1462                    #
1463                    # Save MAP buffer into MAP file.
1464                    #
1465                    self._SaveMapFile (MapBuffer, Wa)
1466
1467    ## Build active module for different build targets, different tool chains and different archs
1468    #
1469    def _BuildModule(self):
1470        for BuildTarget in self.BuildTargetList:
1471            GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1472            for ToolChain in self.ToolChainList:
1473                GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1474                GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1475                #
1476                # module build needs platform build information, so get platform
1477                # AutoGen first
1478                #
1479                Wa = WorkspaceAutoGen(
1480                        self.WorkspaceDir,
1481                        self.PlatformFile,
1482                        BuildTarget,
1483                        ToolChain,
1484                        self.ArchList,
1485                        self.BuildDatabase,
1486                        self.TargetTxt,
1487                        self.ToolDef,
1488                        self.Fdf,
1489                        self.FdList,
1490                        self.FvList,
1491                        self.CapList,
1492                        self.SkuId,
1493                        self.UniFlag,
1494                        self.Progress,
1495                        self.ModuleFile
1496                        )
1497                self.Fdf = Wa.FdfFile
1498                self.LoadFixAddress = Wa.Platform.LoadFixAddress
1499                Wa.CreateMakeFile(False)
1500                self.Progress.Stop("done!")
1501                MaList = []
1502                for Arch in Wa.ArchList:
1503                    GlobalData.gGlobalDefines['ARCH'] = Arch
1504                    Ma = ModuleAutoGen(Wa, self.ModuleFile, BuildTarget, ToolChain, Arch, self.PlatformFile)
1505                    if Ma == None: continue
1506                    MaList.append(Ma)
1507                    self.BuildModules.append(Ma)
1508                    if not Ma.IsBinaryModule:
1509                        self._Build(self.Target, Ma, BuildModule=True)
1510
1511                self.BuildReport.AddPlatformReport(Wa, MaList)
1512                if MaList == []:
1513                    EdkLogger.error(
1514                                'build',
1515                                BUILD_ERROR,
1516                                "Module for [%s] is not a component of active platform."\
1517                                " Please make sure that the ARCH and inf file path are"\
1518                                " given in the same as in [%s]" %\
1519                                    (', '.join(Wa.ArchList), self.PlatformFile),
1520                                ExtraData=self.ModuleFile
1521                                )
1522                # Create MAP file when Load Fix Address is enabled.
1523                if self.Target == "fds" and self.Fdf:
1524                    for Arch in Wa.ArchList:
1525                        #
1526                        # Check whether the set fix address is above 4G for 32bit image.
1527                        #
1528                        if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1529                            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")
1530                    #
1531                    # Get Module List
1532                    #
1533                    ModuleList = {}
1534                    for Pa in Wa.AutoGenObjectList:
1535                        for Ma in Pa.ModuleAutoGenList:
1536                            if Ma == None:
1537                                continue
1538                            if not Ma.IsLibrary:
1539                                ModuleList[Ma.Guid.upper()] = Ma
1540
1541                    MapBuffer = StringIO('')
1542                    if self.LoadFixAddress != 0:
1543                        #
1544                        # Rebase module to the preferred memory address before GenFds
1545                        #
1546                        self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1547                    #
1548                    # create FDS again for the updated EFI image
1549                    #
1550                    self._Build("fds", Wa)
1551                    #
1552                    # Create MAP file for all platform FVs after GenFds.
1553                    #
1554                    self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1555                    #
1556                    # Save MAP buffer into MAP file.
1557                    #
1558                    self._SaveMapFile (MapBuffer, Wa)
1559
1560    ## Build a platform in multi-thread mode
1561    #
1562    def _MultiThreadBuildPlatform(self):
1563        for BuildTarget in self.BuildTargetList:
1564            GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1565            for ToolChain in self.ToolChainList:
1566                GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1567                GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1568                Wa = WorkspaceAutoGen(
1569                        self.WorkspaceDir,
1570                        self.PlatformFile,
1571                        BuildTarget,
1572                        ToolChain,
1573                        self.ArchList,
1574                        self.BuildDatabase,
1575                        self.TargetTxt,
1576                        self.ToolDef,
1577                        self.Fdf,
1578                        self.FdList,
1579                        self.FvList,
1580                        self.CapList,
1581                        self.SkuId,
1582                        self.UniFlag,
1583                        self.Progress
1584                        )
1585                self.Fdf = Wa.FdfFile
1586                self.LoadFixAddress = Wa.Platform.LoadFixAddress
1587                self.BuildReport.AddPlatformReport(Wa)
1588                Wa.CreateMakeFile(False)
1589
1590                # multi-thread exit flag
1591                ExitFlag = threading.Event()
1592                ExitFlag.clear()
1593                for Arch in Wa.ArchList:
1594                    GlobalData.gGlobalDefines['ARCH'] = Arch
1595                    Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
1596                    if Pa == None:
1597                        continue
1598                    ModuleList = []
1599                    for Inf in Pa.Platform.Modules:
1600                        ModuleList.append(Inf)
1601                    # Add the INF only list in FDF
1602                    if GlobalData.gFdfParser != None:
1603                        for InfName in GlobalData.gFdfParser.Profile.InfList:
1604                            Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)
1605                            if Inf in Pa.Platform.Modules:
1606                                continue
1607                            ModuleList.append(Inf)
1608                    for Module in ModuleList:
1609                        # Get ModuleAutoGen object to generate C code file and makefile
1610                        Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
1611
1612                        if Ma == None:
1613                            continue
1614                        # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1615                        if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1616                            # for target which must generate AutoGen code and makefile
1617                            if not self.SkipAutoGen or self.Target == 'genc':
1618                                Ma.CreateCodeFile(True)
1619                            if self.Target == "genc":
1620                                continue
1621
1622                            if not self.SkipAutoGen or self.Target == 'genmake':
1623                                Ma.CreateMakeFile(True)
1624                            if self.Target == "genmake":
1625                                continue
1626                        self.BuildModules.append(Ma)
1627                    self.Progress.Stop("done!")
1628
1629                    for Ma in self.BuildModules:
1630                        # Generate build task for the module
1631                        if not Ma.IsBinaryModule:
1632                            Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))
1633                        # Break build if any build thread has error
1634                        if BuildTask.HasError():
1635                            # we need a full version of makefile for platform
1636                            ExitFlag.set()
1637                            BuildTask.WaitForComplete()
1638                            Pa.CreateMakeFile(False)
1639                            EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1640                        # Start task scheduler
1641                        if not BuildTask.IsOnGoing():
1642                            BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
1643
1644                    # in case there's an interruption. we need a full version of makefile for platform
1645                    Pa.CreateMakeFile(False)
1646                    if BuildTask.HasError():
1647                        EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1648
1649                #
1650                # Save temp tables to a TmpTableDict.
1651                #
1652                for Key in Wa.BuildDatabase._CACHE_:
1653                    if Wa.BuildDatabase._CACHE_[Key]._RawData and Wa.BuildDatabase._CACHE_[Key]._RawData._Table and Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table:
1654                        if TemporaryTablePattern.match(Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table):
1655                            TmpTableDict[Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table] = Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Cur
1656                #
1657                #
1658                # All modules have been put in build tasks queue. Tell task scheduler
1659                # to exit if all tasks are completed
1660                #
1661                ExitFlag.set()
1662                BuildTask.WaitForComplete()
1663                self.CreateAsBuiltInf()
1664
1665                #
1666                # Check for build error, and raise exception if one
1667                # has been signaled.
1668                #
1669                if BuildTask.HasError():
1670                    EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1671
1672                # Create MAP file when Load Fix Address is enabled.
1673                if self.Target in ["", "all", "fds"]:
1674                    for Arch in Wa.ArchList:
1675                        #
1676                        # Check whether the set fix address is above 4G for 32bit image.
1677                        #
1678                        if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1679                            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")
1680                    #
1681                    # Get Module List
1682                    #
1683                    ModuleList = {}
1684                    for Pa in Wa.AutoGenObjectList:
1685                        for Ma in Pa.ModuleAutoGenList:
1686                            if Ma == None:
1687                                continue
1688                            if not Ma.IsLibrary:
1689                                ModuleList[Ma.Guid.upper()] = Ma
1690                    #
1691                    # Rebase module to the preferred memory address before GenFds
1692                    #
1693                    MapBuffer = StringIO('')
1694                    if self.LoadFixAddress != 0:
1695                        self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1696
1697                    if self.Fdf:
1698                        #
1699                        # Generate FD image if there's a FDF file found
1700                        #
1701                        LaunchCommand(Wa.GenFdsCommand, os.getcwd())
1702
1703                        #
1704                        # Create MAP file for all platform FVs after GenFds.
1705                        #
1706                        self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1707                    #
1708                    # Save MAP buffer into MAP file.
1709                    #
1710                    self._SaveMapFile(MapBuffer, Wa)
1711
1712    ## Generate GuidedSectionTools.txt in the FV directories.
1713    #
1714    def CreateGuidedSectionToolsFile(self):
1715        for BuildTarget in self.BuildTargetList:
1716            for ToolChain in self.ToolChainList:
1717                Wa = WorkspaceAutoGen(
1718                        self.WorkspaceDir,
1719                        self.PlatformFile,
1720                        BuildTarget,
1721                        ToolChain,
1722                        self.ArchList,
1723                        self.BuildDatabase,
1724                        self.TargetTxt,
1725                        self.ToolDef,
1726                        self.Fdf,
1727                        self.FdList,
1728                        self.FvList,
1729                        self.CapList,
1730                        self.SkuId,
1731                        self.UniFlag
1732                        )
1733                FvDir = Wa.FvDir
1734                if not os.path.exists(FvDir):
1735                    continue
1736
1737                for Arch in self.ArchList:
1738                    # Build up the list of supported architectures for this build
1739                    prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)
1740
1741                    # Look through the tool definitions for GUIDed tools
1742                    guidAttribs = []
1743                    for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():
1744                        if attrib.upper().endswith('_GUID'):
1745                            split = attrib.split('_')
1746                            thisPrefix = '_'.join(split[0:3]) + '_'
1747                            if thisPrefix == prefix:
1748                                guid = self.ToolDef.ToolsDefTxtDictionary[attrib]
1749                                guid = guid.lower()
1750                                toolName = split[3]
1751                                path = '_'.join(split[0:4]) + '_PATH'
1752                                path = self.ToolDef.ToolsDefTxtDictionary[path]
1753                                path = self.GetFullPathOfTool(path)
1754                                guidAttribs.append((guid, toolName, path))
1755
1756                    # Write out GuidedSecTools.txt
1757                    toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')
1758                    toolsFile = open(toolsFile, 'wt')
1759                    for guidedSectionTool in guidAttribs:
1760                        print >> toolsFile, ' '.join(guidedSectionTool)
1761                    toolsFile.close()
1762
1763    ## Returns the full path of the tool.
1764    #
1765    def GetFullPathOfTool (self, tool):
1766        if os.path.exists(tool):
1767            return os.path.realpath(tool)
1768        else:
1769            # We need to search for the tool using the
1770            # PATH environment variable.
1771            for dirInPath in os.environ['PATH'].split(os.pathsep):
1772                foundPath = os.path.join(dirInPath, tool)
1773                if os.path.exists(foundPath):
1774                    return os.path.realpath(foundPath)
1775
1776        # If the tool was not found in the path then we just return
1777        # the input tool.
1778        return tool
1779
1780    ## Launch the module or platform build
1781    #
1782    def Launch(self):
1783        if not self.ModuleFile:
1784            if not self.SpawnMode or self.Target not in ["", "all"]:
1785                self.SpawnMode = False
1786                self._BuildPlatform()
1787            else:
1788                self._MultiThreadBuildPlatform()
1789            self.CreateGuidedSectionToolsFile()
1790        else:
1791            self.SpawnMode = False
1792            self._BuildModule()
1793
1794        if self.Target == 'cleanall':
1795            self.Db.Close()
1796            RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)
1797
1798    def CreateAsBuiltInf(self):
1799        for Module in self.BuildModules:
1800            Module.CreateAsBuiltInf()
1801        self.BuildModules = []
1802    ## Do some clean-up works when error occurred
1803    def Relinquish(self):
1804        OldLogLevel = EdkLogger.GetLevel()
1805        EdkLogger.SetLevel(EdkLogger.ERROR)
1806        #self.DumpBuildData()
1807        Utils.Progressor.Abort()
1808        if self.SpawnMode == True:
1809            BuildTask.Abort()
1810        EdkLogger.SetLevel(OldLogLevel)
1811
1812    def DumpBuildData(self):
1813        CacheDirectory = os.path.dirname(GlobalData.gDatabasePath)
1814        Utils.CreateDirectory(CacheDirectory)
1815        Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))
1816        Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))
1817
1818    def RestoreBuildData(self):
1819        FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gFileTimeStampCache")
1820        if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):
1821            Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)
1822            if Utils.gFileTimeStampCache == None:
1823                Utils.gFileTimeStampCache = {}
1824
1825        FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gDependencyDatabase")
1826        if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):
1827            Utils.gDependencyDatabase = Utils.DataRestore(FilePath)
1828            if Utils.gDependencyDatabase == None:
1829                Utils.gDependencyDatabase = {}
1830
1831def ParseDefines(DefineList=[]):
1832    DefineDict = {}
1833    if DefineList != None:
1834        for Define in DefineList:
1835            DefineTokenList = Define.split("=", 1)
1836            if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):
1837                EdkLogger.error('build', FORMAT_INVALID,
1838                                "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
1839                                ExtraData=DefineTokenList[0])
1840
1841            if len(DefineTokenList) == 1:
1842                DefineDict[DefineTokenList[0]] = "TRUE"
1843            else:
1844                DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()
1845    return DefineDict
1846
1847gParamCheck = []
1848def SingleCheckCallback(option, opt_str, value, parser):
1849    if option not in gParamCheck:
1850        setattr(parser.values, option.dest, value)
1851        gParamCheck.append(option)
1852    else:
1853        parser.error("Option %s only allows one instance in command line!" % option)
1854
1855## Parse command line options
1856#
1857# Using standard Python module optparse to parse command line option of this tool.
1858#
1859#   @retval Opt   A optparse.Values object containing the parsed options
1860#   @retval Args  Target of build command
1861#
1862def MyOptionParser():
1863    Parser = OptionParser(description=__copyright__,version=__version__,prog="build.exe",usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
1864    Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32','X64','IPF','EBC','ARM', 'AARCH64'], dest="TargetArch",
1865        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.")
1866    Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,
1867        help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
1868    Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,
1869        help="Build the module specified by the INF file name argument.")
1870    Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
1871                      action="append")
1872    Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",
1873        help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
1874    Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,
1875        help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
1876
1877    Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,
1878        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.")
1879
1880    Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,
1881        help="The name of the FDF file to use, which overrides the setting in the DSC file.")
1882    Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],
1883        help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
1884    Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],
1885        help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
1886    Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],
1887        help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
1888    Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")
1889    Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")
1890
1891    Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.")
1892
1893    Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")
1894    Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")
1895
1896    Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",
1897        help="Make use of silent mode of (n)make.")
1898    Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
1899    Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
1900                                                                               "including library instances selected, final dependency expression, "\
1901                                                                               "and warning messages, etc.")
1902    Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
1903    Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
1904
1905    Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")
1906    Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD','LIBRARY','FLASH','DEPEX','BUILD_FLAGS','FIXED_ADDRESS', 'EXECUTION_ORDER'], dest="ReportType", default=[],
1907        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].  "\
1908             "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]")
1909    Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",
1910        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. "\
1911             "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
1912             "will override the setting in [BuildOptions] section of platform DSC.")
1913    Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism")
1914    Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")
1915    Parser.add_option("--check-usage", action="store_true", dest="CheckUsage", default=False, help="Check usage content of entries listed in INF file.")
1916    Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")
1917
1918    (Opt, Args)=Parser.parse_args()
1919    return (Opt, Args)
1920
1921## Tool entrance method
1922#
1923# This method mainly dispatch specific methods per the command line options.
1924# If no error found, return zero value so the caller of this tool can know
1925# if it's executed successfully or not.
1926#
1927#   @retval 0     Tool was successful
1928#   @retval 1     Tool failed
1929#
1930def Main():
1931    StartTime = time.time()
1932
1933    # Initialize log system
1934    EdkLogger.Initialize()
1935
1936    #
1937    # Parse the options and args
1938    #
1939    (Option, Target) = MyOptionParser()
1940    GlobalData.gOptions = Option
1941    GlobalData.gCaseInsensitive = Option.CaseInsensitive
1942
1943    # Set log level
1944    if Option.verbose != None:
1945        EdkLogger.SetLevel(EdkLogger.VERBOSE)
1946    elif Option.quiet != None:
1947        EdkLogger.SetLevel(EdkLogger.QUIET)
1948    elif Option.debug != None:
1949        EdkLogger.SetLevel(Option.debug + 1)
1950    else:
1951        EdkLogger.SetLevel(EdkLogger.INFO)
1952
1953    if Option.LogFile != None:
1954        EdkLogger.SetLogFile(Option.LogFile)
1955
1956    if Option.WarningAsError == True:
1957        EdkLogger.SetWarningAsError()
1958
1959    if platform.platform().find("Windows") >= 0:
1960        GlobalData.gIsWindows = True
1961    else:
1962        GlobalData.gIsWindows = False
1963
1964    EdkLogger.quiet("Build environment: %s" % platform.platform())
1965    EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));
1966    ReturnCode = 0
1967    MyBuild = None
1968    try:
1969        if len(Target) == 0:
1970            Target = "all"
1971        elif len(Target) >= 2:
1972            EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",
1973                            ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))
1974        else:
1975            Target = Target[0].lower()
1976
1977        if Target not in gSupportedTarget:
1978            EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,
1979                            ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))
1980
1981        #
1982        # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
1983        #
1984        CheckEnvVariable()
1985        GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))
1986
1987        Workspace = os.getenv("WORKSPACE")
1988        #
1989        # Get files real name in workspace dir
1990        #
1991        GlobalData.gAllFiles = Utils.DirCache(Workspace)
1992
1993        WorkingDirectory = os.getcwd()
1994        if not Option.ModuleFile:
1995            FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))
1996            FileNum = len(FileList)
1997            if FileNum >= 2:
1998                EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),
1999                                ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2000            elif FileNum == 1:
2001                Option.ModuleFile = NormFile(FileList[0], Workspace)
2002
2003        if Option.ModuleFile:
2004            if os.path.isabs (Option.ModuleFile):
2005                if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:
2006                    Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)
2007            Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)
2008            ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)
2009            if ErrorCode != 0:
2010                EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
2011
2012        if Option.PlatformFile != None:
2013            if os.path.isabs (Option.PlatformFile):
2014                if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:
2015                    Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)
2016            Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)
2017
2018        if Option.FdfFile != None:
2019            if os.path.isabs (Option.FdfFile):
2020                if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:
2021                    Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)
2022            Option.FdfFile = PathClass(Option.FdfFile, Workspace)
2023            ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)
2024            if ErrorCode != 0:
2025                EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
2026
2027        if Option.Flag != None and Option.Flag not in ['-c', '-s']:
2028            EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")
2029
2030        MyBuild = Build(Target, Workspace, Option)
2031        GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)
2032        MyBuild.Launch()
2033        # Drop temp tables to avoid database locked.
2034        for TmpTableName in TmpTableDict:
2035            SqlCommand = """drop table IF EXISTS %s""" % TmpTableName
2036            TmpTableDict[TmpTableName].execute(SqlCommand)
2037        #MyBuild.DumpBuildData()
2038    except FatalError, X:
2039        if MyBuild != None:
2040            # for multi-thread build exits safely
2041            MyBuild.Relinquish()
2042        if Option != None and Option.debug != None:
2043            EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2044        ReturnCode = X.args[0]
2045    except Warning, X:
2046        # error from Fdf parser
2047        if MyBuild != None:
2048            # for multi-thread build exits safely
2049            MyBuild.Relinquish()
2050        if Option != None and Option.debug != None:
2051            EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2052        else:
2053            EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError = False)
2054        ReturnCode = FORMAT_INVALID
2055    except KeyboardInterrupt:
2056        ReturnCode = ABORT_ERROR
2057        if Option != None and Option.debug != None:
2058            EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2059    except:
2060        if MyBuild != None:
2061            # for multi-thread build exits safely
2062            MyBuild.Relinquish()
2063
2064        # try to get the meta-file from the object causing exception
2065        Tb = sys.exc_info()[-1]
2066        MetaFile = GlobalData.gProcessingFile
2067        while Tb != None:
2068            if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):
2069                MetaFile = Tb.tb_frame.f_locals['self'].MetaFile
2070            Tb = Tb.tb_next
2071        EdkLogger.error(
2072                    "\nbuild",
2073                    CODE_ERROR,
2074                    "Unknown fatal error when processing [%s]" % MetaFile,
2075                    ExtraData="\n(Please send email to edk2-devel@lists.sourceforge.net for help, attaching following call stack trace!)\n",
2076                    RaiseError=False
2077                    )
2078        EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2079        ReturnCode = CODE_ERROR
2080    finally:
2081        Utils.Progressor.Abort()
2082        Utils.ClearDuplicatedInf()
2083
2084    if ReturnCode == 0:
2085        Conclusion = "Done"
2086    elif ReturnCode == ABORT_ERROR:
2087        Conclusion = "Aborted"
2088    else:
2089        Conclusion = "Failed"
2090    FinishTime = time.time()
2091    BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))
2092    BuildDurationStr = ""
2093    if BuildDuration.tm_yday > 1:
2094        BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)"%(BuildDuration.tm_yday - 1)
2095    else:
2096        BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)
2097    if MyBuild != None:
2098        MyBuild.BuildReport.GenerateReport(BuildDurationStr)
2099        MyBuild.Db.Close()
2100    EdkLogger.SetLevel(EdkLogger.QUIET)
2101    EdkLogger.quiet("\n- %s -" % Conclusion)
2102    EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))
2103    EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)
2104    return ReturnCode
2105
2106if __name__ == '__main__':
2107    r = Main()
2108    ## 0-127 is a safe return range, and 1 is a standard default error
2109    if r < 0 or r > 127: r = 1
2110    sys.exit(r)
2111
2112