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 - 2019, Intel Corporation. All rights reserved.<BR>
6#  Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
7#
8#  SPDX-License-Identifier: BSD-2-Clause-Patent
9#
10
11##
12# Import Modules
13#
14from __future__ import print_function
15import Common.LongFilePathOs as os
16import re
17import sys
18import glob
19import time
20import platform
21import traceback
22import encodings.ascii
23import multiprocessing
24
25from struct import *
26from threading import *
27import threading
28from optparse import OptionParser
29from subprocess import *
30from Common import Misc as Utils
31
32from Common.LongFilePathSupport import OpenLongFilePath as open
33from Common.TargetTxtClassObject import TargetTxtClassObject
34from Common.ToolDefClassObject import ToolDefClassObject
35from Common.DataType import *
36from Common.BuildVersion import gBUILD_VERSION
37from AutoGen.AutoGen import *
38from Common.BuildToolError import *
39from Workspace.WorkspaceDatabase import WorkspaceDatabase
40from Common.MultipleWorkspace import MultipleWorkspace as mws
41
42from BuildReport import BuildReport
43from GenPatchPcdTable.GenPatchPcdTable import *
44from PatchPcdValue.PatchPcdValue import *
45
46import Common.EdkLogger
47import Common.GlobalData as GlobalData
48from GenFds.GenFds import GenFds, GenFdsApi
49
50from collections import OrderedDict, defaultdict
51
52# Version and Copyright
53VersionNumber = "0.60" + ' ' + gBUILD_VERSION
54__version__ = "%prog Version " + VersionNumber
55__copyright__ = "Copyright (c) 2007 - 2018, 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 'PATHEXT' in os.environ:
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=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    # set multiple workspace
109    PackagesPath = os.getenv("PACKAGES_PATH")
110    mws.setWs(WorkspaceDir, PackagesPath)
111    if mws.PACKAGES_PATH:
112        for Path in mws.PACKAGES_PATH:
113            if not os.path.exists(Path):
114                EdkLogger.error("build", FILE_NOT_FOUND, "One Path in PACKAGES_PATH doesn't exist", ExtraData=Path)
115            elif ' ' in Path:
116                EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in PACKAGES_PATH", ExtraData=Path)
117
118
119    os.environ["EDK_TOOLS_PATH"] = os.path.normcase(os.environ["EDK_TOOLS_PATH"])
120
121    # check EDK_TOOLS_PATH
122    if "EDK_TOOLS_PATH" not in os.environ:
123        EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
124                        ExtraData="EDK_TOOLS_PATH")
125
126    # check PATH
127    if "PATH" not in os.environ:
128        EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
129                        ExtraData="PATH")
130
131    GlobalData.gWorkspace = WorkspaceDir
132
133    GlobalData.gGlobalDefines["WORKSPACE"]  = WorkspaceDir
134    GlobalData.gGlobalDefines["EDK_TOOLS_PATH"] = os.environ["EDK_TOOLS_PATH"]
135
136## Get normalized file path
137#
138# Convert the path to be local format, and remove the WORKSPACE path at the
139# beginning if the file path is given in full path.
140#
141# @param  FilePath      File path to be normalized
142# @param  Workspace     Workspace path which the FilePath will be checked against
143#
144# @retval string        The normalized file path
145#
146def NormFile(FilePath, Workspace):
147    # check if the path is absolute or relative
148    if os.path.isabs(FilePath):
149        FileFullPath = os.path.normpath(FilePath)
150    else:
151        FileFullPath = os.path.normpath(mws.join(Workspace, FilePath))
152        Workspace = mws.getWs(Workspace, FilePath)
153
154    # check if the file path exists or not
155    if not os.path.isfile(FileFullPath):
156        EdkLogger.error("build", FILE_NOT_FOUND, ExtraData="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath)
157
158    # remove workspace directory from the beginning part of the file path
159    if Workspace[-1] in ["\\", "/"]:
160        return FileFullPath[len(Workspace):]
161    else:
162        return FileFullPath[(len(Workspace) + 1):]
163
164## Get the output of an external program
165#
166# This is the entrance method of thread reading output of an external program and
167# putting them in STDOUT/STDERR of current program.
168#
169# @param  From      The stream message read from
170# @param  To        The stream message put on
171# @param  ExitFlag  The flag used to indicate stopping reading
172#
173def ReadMessage(From, To, ExitFlag):
174    while True:
175        # read one line a time
176        Line = From.readline()
177        # empty string means "end"
178        if Line is not None and Line != b"":
179            To(Line.rstrip().decode(encoding='utf-8', errors='ignore'))
180        else:
181            break
182        if ExitFlag.isSet():
183            break
184
185## Launch an external program
186#
187# This method will call subprocess.Popen to execute an external program with
188# given options in specified directory. Because of the dead-lock issue during
189# redirecting output of the external program, threads are used to to do the
190# redirection work.
191#
192# @param  Command               A list or string containing the call of the program
193# @param  WorkingDir            The directory in which the program will be running
194#
195def LaunchCommand(Command, WorkingDir):
196    BeginTime = time.time()
197    # if working directory doesn't exist, Popen() will raise an exception
198    if not os.path.isdir(WorkingDir):
199        EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=WorkingDir)
200
201    # Command is used as the first Argument in following Popen().
202    # It could be a string or sequence. We find that if command is a string in following Popen(),
203    # ubuntu may fail with an error message that the command is not found.
204    # So here we may need convert command from string to list instance.
205    if platform.system() != 'Windows':
206        if not isinstance(Command, list):
207            Command = Command.split()
208        Command = ' '.join(Command)
209
210    Proc = None
211    EndOfProcedure = None
212    try:
213        # launch the command
214        Proc = Popen(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir, bufsize=-1, shell=True)
215
216        # launch two threads to read the STDOUT and STDERR
217        EndOfProcedure = Event()
218        EndOfProcedure.clear()
219        if Proc.stdout:
220            StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure))
221            StdOutThread.setName("STDOUT-Redirector")
222            StdOutThread.setDaemon(False)
223            StdOutThread.start()
224
225        if Proc.stderr:
226            StdErrThread = Thread(target=ReadMessage, args=(Proc.stderr, EdkLogger.quiet, EndOfProcedure))
227            StdErrThread.setName("STDERR-Redirector")
228            StdErrThread.setDaemon(False)
229            StdErrThread.start()
230
231        # waiting for program exit
232        Proc.wait()
233    except: # in case of aborting
234        # terminate the threads redirecting the program output
235        EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
236        if EndOfProcedure is not None:
237            EndOfProcedure.set()
238        if Proc is None:
239            if not isinstance(Command, type("")):
240                Command = " ".join(Command)
241            EdkLogger.error("build", COMMAND_FAILURE, "Failed to start command", ExtraData="%s [%s]" % (Command, WorkingDir))
242
243    if Proc.stdout:
244        StdOutThread.join()
245    if Proc.stderr:
246        StdErrThread.join()
247
248    # check the return code of the program
249    if Proc.returncode != 0:
250        if not isinstance(Command, type("")):
251            Command = " ".join(Command)
252        # print out the Response file and its content when make failure
253        RespFile = os.path.join(WorkingDir, 'OUTPUT', 'respfilelist.txt')
254        if os.path.isfile(RespFile):
255            f = open(RespFile)
256            RespContent = f.read()
257            f.close()
258            EdkLogger.info(RespContent)
259
260        EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir))
261    return "%dms" % (int(round((time.time() - BeginTime) * 1000)))
262
263## The smallest unit that can be built in multi-thread build mode
264#
265# This is the base class of build unit. The "Obj" parameter must provide
266# __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
267# missing build.
268#
269# Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
270#
271class BuildUnit:
272    ## The constructor
273    #
274    #   @param  self        The object pointer
275    #   @param  Obj         The object the build is working on
276    #   @param  Target      The build target name, one of gSupportedTarget
277    #   @param  Dependency  The BuildUnit(s) which must be completed in advance
278    #   @param  WorkingDir  The directory build command starts in
279    #
280    def __init__(self, Obj, BuildCommand, Target, Dependency, WorkingDir="."):
281        self.BuildObject = Obj
282        self.Dependency = Dependency
283        self.WorkingDir = WorkingDir
284        self.Target = Target
285        self.BuildCommand = BuildCommand
286        if not BuildCommand:
287            EdkLogger.error("build", OPTION_MISSING,
288                            "No build command found for this module. "
289                            "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
290                                (Obj.BuildTarget, Obj.ToolChain, Obj.Arch),
291                            ExtraData=str(Obj))
292
293
294    ## str() method
295    #
296    #   It just returns the string representation of self.BuildObject
297    #
298    #   @param  self        The object pointer
299    #
300    def __str__(self):
301        return str(self.BuildObject)
302
303    ## "==" operator method
304    #
305    #   It just compares self.BuildObject with "Other". So self.BuildObject must
306    #   provide its own __eq__() method.
307    #
308    #   @param  self        The object pointer
309    #   @param  Other       The other BuildUnit object compared to
310    #
311    def __eq__(self, Other):
312        return Other and self.BuildObject == Other.BuildObject \
313                and Other.BuildObject \
314                and self.BuildObject.Arch == Other.BuildObject.Arch
315
316    ## hash() method
317    #
318    #   It just returns the hash value of self.BuildObject which must be hashable.
319    #
320    #   @param  self        The object pointer
321    #
322    def __hash__(self):
323        return hash(self.BuildObject) + hash(self.BuildObject.Arch)
324
325    def __repr__(self):
326        return repr(self.BuildObject)
327
328## The smallest module unit that can be built by nmake/make command in multi-thread build mode
329#
330# This class is for module build by nmake/make build system. The "Obj" parameter
331# must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
332# be make units missing build.
333#
334# Currently the "Obj" should be only ModuleAutoGen object.
335#
336class ModuleMakeUnit(BuildUnit):
337    ## The constructor
338    #
339    #   @param  self        The object pointer
340    #   @param  Obj         The ModuleAutoGen object the build is working on
341    #   @param  Target      The build target name, one of gSupportedTarget
342    #
343    def __init__(self, Obj, Target):
344        Dependency = [ModuleMakeUnit(La, Target) for La in Obj.LibraryAutoGenList]
345        BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)
346        if Target in [None, "", "all"]:
347            self.Target = "tbuild"
348
349## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
350#
351# This class is for platform build by nmake/make build system. The "Obj" parameter
352# must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
353# be make units missing build.
354#
355# Currently the "Obj" should be only PlatformAutoGen object.
356#
357class PlatformMakeUnit(BuildUnit):
358    ## The constructor
359    #
360    #   @param  self        The object pointer
361    #   @param  Obj         The PlatformAutoGen object the build is working on
362    #   @param  Target      The build target name, one of gSupportedTarget
363    #
364    def __init__(self, Obj, Target):
365        Dependency = [ModuleMakeUnit(Lib, Target) for Lib in self.BuildObject.LibraryAutoGenList]
366        Dependency.extend([ModuleMakeUnit(Mod, Target) for Mod in self.BuildObject.ModuleAutoGenList])
367        BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)
368
369## The class representing the task of a module build or platform build
370#
371# This class manages the build tasks in multi-thread build mode. Its jobs include
372# scheduling thread running, catching thread error, monitor the thread status, etc.
373#
374class BuildTask:
375    # queue for tasks waiting for schedule
376    _PendingQueue = OrderedDict()
377    _PendingQueueLock = threading.Lock()
378
379    # queue for tasks ready for running
380    _ReadyQueue = OrderedDict()
381    _ReadyQueueLock = threading.Lock()
382
383    # queue for run tasks
384    _RunningQueue = OrderedDict()
385    _RunningQueueLock = threading.Lock()
386
387    # queue containing all build tasks, in case duplicate build
388    _TaskQueue = OrderedDict()
389
390    # flag indicating error occurs in a running thread
391    _ErrorFlag = threading.Event()
392    _ErrorFlag.clear()
393    _ErrorMessage = ""
394
395    # BoundedSemaphore object used to control the number of running threads
396    _Thread = None
397
398    # flag indicating if the scheduler is started or not
399    _SchedulerStopped = threading.Event()
400    _SchedulerStopped.set()
401
402    ## Start the task scheduler thread
403    #
404    #   @param  MaxThreadNumber     The maximum thread number
405    #   @param  ExitFlag            Flag used to end the scheduler
406    #
407    @staticmethod
408    def StartScheduler(MaxThreadNumber, ExitFlag):
409        SchedulerThread = Thread(target=BuildTask.Scheduler, args=(MaxThreadNumber, ExitFlag))
410        SchedulerThread.setName("Build-Task-Scheduler")
411        SchedulerThread.setDaemon(False)
412        SchedulerThread.start()
413        # wait for the scheduler to be started, especially useful in Linux
414        while not BuildTask.IsOnGoing():
415            time.sleep(0.01)
416
417    ## Scheduler method
418    #
419    #   @param  MaxThreadNumber     The maximum thread number
420    #   @param  ExitFlag            Flag used to end the scheduler
421    #
422    @staticmethod
423    def Scheduler(MaxThreadNumber, ExitFlag):
424        BuildTask._SchedulerStopped.clear()
425        try:
426            # use BoundedSemaphore to control the maximum running threads
427            BuildTask._Thread = BoundedSemaphore(MaxThreadNumber)
428            #
429            # scheduling loop, which will exits when no pending/ready task and
430            # indicated to do so, or there's error in running thread
431            #
432            while (len(BuildTask._PendingQueue) > 0 or len(BuildTask._ReadyQueue) > 0 \
433                   or not ExitFlag.isSet()) and not BuildTask._ErrorFlag.isSet():
434                EdkLogger.debug(EdkLogger.DEBUG_8, "Pending Queue (%d), Ready Queue (%d)"
435                                % (len(BuildTask._PendingQueue), len(BuildTask._ReadyQueue)))
436
437                # get all pending tasks
438                BuildTask._PendingQueueLock.acquire()
439                BuildObjectList = list(BuildTask._PendingQueue.keys())
440                #
441                # check if their dependency is resolved, and if true, move them
442                # into ready queue
443                #
444                for BuildObject in BuildObjectList:
445                    Bt = BuildTask._PendingQueue[BuildObject]
446                    if Bt.IsReady():
447                        BuildTask._ReadyQueue[BuildObject] = BuildTask._PendingQueue.pop(BuildObject)
448                BuildTask._PendingQueueLock.release()
449
450                # launch build thread until the maximum number of threads is reached
451                while not BuildTask._ErrorFlag.isSet():
452                    # empty ready queue, do nothing further
453                    if len(BuildTask._ReadyQueue) == 0:
454                        break
455
456                    # wait for active thread(s) exit
457                    BuildTask._Thread.acquire(True)
458
459                    # start a new build thread
460                    Bo, Bt = BuildTask._ReadyQueue.popitem()
461
462                    # move into running queue
463                    BuildTask._RunningQueueLock.acquire()
464                    BuildTask._RunningQueue[Bo] = Bt
465                    BuildTask._RunningQueueLock.release()
466
467                    Bt.Start()
468                    # avoid tense loop
469                    time.sleep(0.01)
470
471                # avoid tense loop
472                time.sleep(0.01)
473
474            # wait for all running threads exit
475            if BuildTask._ErrorFlag.isSet():
476                EdkLogger.quiet("\nWaiting for all build threads exit...")
477            # while not BuildTask._ErrorFlag.isSet() and \
478            while len(BuildTask._RunningQueue) > 0:
479                EdkLogger.verbose("Waiting for thread ending...(%d)" % len(BuildTask._RunningQueue))
480                EdkLogger.debug(EdkLogger.DEBUG_8, "Threads [%s]" % ", ".join(Th.getName() for Th in threading.enumerate()))
481                # avoid tense loop
482                time.sleep(0.1)
483        except BaseException as X:
484            #
485            # TRICK: hide the output of threads left running, so that the user can
486            #        catch the error message easily
487            #
488            EdkLogger.SetLevel(EdkLogger.ERROR)
489            BuildTask._ErrorFlag.set()
490            BuildTask._ErrorMessage = "build thread scheduler error\n\t%s" % str(X)
491
492        BuildTask._PendingQueue.clear()
493        BuildTask._ReadyQueue.clear()
494        BuildTask._RunningQueue.clear()
495        BuildTask._TaskQueue.clear()
496        BuildTask._SchedulerStopped.set()
497
498    ## Wait for all running method exit
499    #
500    @staticmethod
501    def WaitForComplete():
502        BuildTask._SchedulerStopped.wait()
503
504    ## Check if the scheduler is running or not
505    #
506    @staticmethod
507    def IsOnGoing():
508        return not BuildTask._SchedulerStopped.isSet()
509
510    ## Abort the build
511    @staticmethod
512    def Abort():
513        if BuildTask.IsOnGoing():
514            BuildTask._ErrorFlag.set()
515            BuildTask.WaitForComplete()
516
517    ## Check if there's error in running thread
518    #
519    #   Since the main thread cannot catch exceptions in other thread, we have to
520    #   use threading.Event to communicate this formation to main thread.
521    #
522    @staticmethod
523    def HasError():
524        return BuildTask._ErrorFlag.isSet()
525
526    ## Get error message in running thread
527    #
528    #   Since the main thread cannot catch exceptions in other thread, we have to
529    #   use a static variable to communicate this message to main thread.
530    #
531    @staticmethod
532    def GetErrorMessage():
533        return BuildTask._ErrorMessage
534
535    ## Factory method to create a BuildTask object
536    #
537    #   This method will check if a module is building or has been built. And if
538    #   true, just return the associated BuildTask object in the _TaskQueue. If
539    #   not, create and return a new BuildTask object. The new BuildTask object
540    #   will be appended to the _PendingQueue for scheduling later.
541    #
542    #   @param  BuildItem       A BuildUnit object representing a build object
543    #   @param  Dependency      The dependent build object of BuildItem
544    #
545    @staticmethod
546    def New(BuildItem, Dependency=None):
547        if BuildItem in BuildTask._TaskQueue:
548            Bt = BuildTask._TaskQueue[BuildItem]
549            return Bt
550
551        Bt = BuildTask()
552        Bt._Init(BuildItem, Dependency)
553        BuildTask._TaskQueue[BuildItem] = Bt
554
555        BuildTask._PendingQueueLock.acquire()
556        BuildTask._PendingQueue[BuildItem] = Bt
557        BuildTask._PendingQueueLock.release()
558
559        return Bt
560
561    ## The real constructor of BuildTask
562    #
563    #   @param  BuildItem       A BuildUnit object representing a build object
564    #   @param  Dependency      The dependent build object of BuildItem
565    #
566    def _Init(self, BuildItem, Dependency=None):
567        self.BuildItem = BuildItem
568
569        self.DependencyList = []
570        if Dependency is None:
571            Dependency = BuildItem.Dependency
572        else:
573            Dependency.extend(BuildItem.Dependency)
574        self.AddDependency(Dependency)
575        # flag indicating build completes, used to avoid unnecessary re-build
576        self.CompleteFlag = False
577
578    ## Check if all dependent build tasks are completed or not
579    #
580    def IsReady(self):
581        ReadyFlag = True
582        for Dep in self.DependencyList:
583            if Dep.CompleteFlag == True:
584                continue
585            ReadyFlag = False
586            break
587
588        return ReadyFlag
589
590    ## Add dependent build task
591    #
592    #   @param  Dependency      The list of dependent build objects
593    #
594    def AddDependency(self, Dependency):
595        for Dep in Dependency:
596            if not Dep.BuildObject.IsBinaryModule and not Dep.BuildObject.CanSkipbyHash():
597                self.DependencyList.append(BuildTask.New(Dep))    # BuildTask list
598
599    ## The thread wrapper of LaunchCommand function
600    #
601    # @param  Command               A list or string contains the call of the command
602    # @param  WorkingDir            The directory in which the program will be running
603    #
604    def _CommandThread(self, Command, WorkingDir):
605        try:
606            self.BuildItem.BuildObject.BuildTime = LaunchCommand(Command, WorkingDir)
607            self.CompleteFlag = True
608
609            # Run hash operation post dependency, to account for libs
610            if GlobalData.gUseHashCache and self.BuildItem.BuildObject.IsLibrary:
611                HashFile = path.join(self.BuildItem.BuildObject.BuildDir, self.BuildItem.BuildObject.Name + ".hash")
612                SaveFileOnChange(HashFile, self.BuildItem.BuildObject.GenModuleHash(), True)
613        except:
614            #
615            # TRICK: hide the output of threads left running, so that the user can
616            #        catch the error message easily
617            #
618            if not BuildTask._ErrorFlag.isSet():
619                GlobalData.gBuildingModule = "%s [%s, %s, %s]" % (str(self.BuildItem.BuildObject),
620                                                                  self.BuildItem.BuildObject.Arch,
621                                                                  self.BuildItem.BuildObject.ToolChain,
622                                                                  self.BuildItem.BuildObject.BuildTarget
623                                                                 )
624            EdkLogger.SetLevel(EdkLogger.ERROR)
625            BuildTask._ErrorFlag.set()
626            BuildTask._ErrorMessage = "%s broken\n    %s [%s]" % \
627                                      (threading.currentThread().getName(), Command, WorkingDir)
628        if self.BuildItem.BuildObject in GlobalData.gModuleBuildTracking and not BuildTask._ErrorFlag.isSet():
629            GlobalData.gModuleBuildTracking[self.BuildItem.BuildObject] = True
630        # indicate there's a thread is available for another build task
631        BuildTask._RunningQueueLock.acquire()
632        BuildTask._RunningQueue.pop(self.BuildItem)
633        BuildTask._RunningQueueLock.release()
634        BuildTask._Thread.release()
635
636    ## Start build task thread
637    #
638    def Start(self):
639        EdkLogger.quiet("Building ... %s" % repr(self.BuildItem))
640        Command = self.BuildItem.BuildCommand + [self.BuildItem.Target]
641        self.BuildTread = Thread(target=self._CommandThread, args=(Command, self.BuildItem.WorkingDir))
642        self.BuildTread.setName("build thread")
643        self.BuildTread.setDaemon(False)
644        self.BuildTread.start()
645
646## The class contains the information related to EFI image
647#
648class PeImageInfo():
649    ## Constructor
650    #
651    # Constructor will load all required image information.
652    #
653    #   @param  BaseName          The full file path of image.
654    #   @param  Guid              The GUID for image.
655    #   @param  Arch              Arch of this image.
656    #   @param  OutputDir         The output directory for image.
657    #   @param  DebugDir          The debug directory for image.
658    #   @param  ImageClass        PeImage Information
659    #
660    def __init__(self, BaseName, Guid, Arch, OutputDir, DebugDir, ImageClass):
661        self.BaseName         = BaseName
662        self.Guid             = Guid
663        self.Arch             = Arch
664        self.OutputDir        = OutputDir
665        self.DebugDir         = DebugDir
666        self.Image            = ImageClass
667        self.Image.Size       = (self.Image.Size // 0x1000 + 1) * 0x1000
668
669## The class implementing the EDK2 build process
670#
671#   The build process includes:
672#       1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
673#       2. Parse DSC file of active platform
674#       3. Parse FDF file if any
675#       4. Establish build database, including parse all other files (module, package)
676#       5. Create AutoGen files (C code file, depex file, makefile) if necessary
677#       6. Call build command
678#
679class Build():
680    ## Constructor
681    #
682    # Constructor will load all necessary configurations, parse platform, modules
683    # and packages and the establish a database for AutoGen.
684    #
685    #   @param  Target              The build command target, one of gSupportedTarget
686    #   @param  WorkspaceDir        The directory of workspace
687    #   @param  BuildOptions        Build options passed from command line
688    #
689    def __init__(self, Target, WorkspaceDir, BuildOptions):
690        self.WorkspaceDir   = WorkspaceDir
691        self.Target         = Target
692        self.PlatformFile   = BuildOptions.PlatformFile
693        self.ModuleFile     = BuildOptions.ModuleFile
694        self.ArchList       = BuildOptions.TargetArch
695        self.ToolChainList  = BuildOptions.ToolChain
696        self.BuildTargetList= BuildOptions.BuildTarget
697        self.Fdf            = BuildOptions.FdfFile
698        self.FdList         = BuildOptions.RomImage
699        self.FvList         = BuildOptions.FvImage
700        self.CapList        = BuildOptions.CapName
701        self.SilentMode     = BuildOptions.SilentMode
702        self.ThreadNumber   = BuildOptions.ThreadNumber
703        self.SkipAutoGen    = BuildOptions.SkipAutoGen
704        self.Reparse        = BuildOptions.Reparse
705        self.SkuId          = BuildOptions.SkuId
706        if self.SkuId:
707            GlobalData.gSKUID_CMD = self.SkuId
708        self.ConfDirectory = BuildOptions.ConfDirectory
709        self.SpawnMode      = True
710        self.BuildReport    = BuildReport(BuildOptions.ReportFile, BuildOptions.ReportType)
711        self.TargetTxt      = TargetTxtClassObject()
712        self.ToolDef        = ToolDefClassObject()
713        self.AutoGenTime    = 0
714        self.MakeTime       = 0
715        self.GenFdsTime     = 0
716        GlobalData.BuildOptionPcd     = BuildOptions.OptionPcd if BuildOptions.OptionPcd else []
717        #Set global flag for build mode
718        GlobalData.gIgnoreSource = BuildOptions.IgnoreSources
719        GlobalData.gUseHashCache = BuildOptions.UseHashCache
720        GlobalData.gBinCacheDest   = BuildOptions.BinCacheDest
721        GlobalData.gBinCacheSource = BuildOptions.BinCacheSource
722        GlobalData.gEnableGenfdsMultiThread = BuildOptions.GenfdsMultiThread
723        GlobalData.gDisableIncludePathCheck = BuildOptions.DisableIncludePathCheck
724
725        if GlobalData.gBinCacheDest and not GlobalData.gUseHashCache:
726            EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-destination must be used together with --hash.")
727
728        if GlobalData.gBinCacheSource and not GlobalData.gUseHashCache:
729            EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-source must be used together with --hash.")
730
731        if GlobalData.gBinCacheDest and GlobalData.gBinCacheSource:
732            EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-destination can not be used together with --binary-source.")
733
734        if GlobalData.gBinCacheSource:
735            BinCacheSource = os.path.normpath(GlobalData.gBinCacheSource)
736            if not os.path.isabs(BinCacheSource):
737                BinCacheSource = mws.join(self.WorkspaceDir, BinCacheSource)
738            GlobalData.gBinCacheSource = BinCacheSource
739        else:
740            if GlobalData.gBinCacheSource is not None:
741                EdkLogger.error("build", OPTION_VALUE_INVALID, ExtraData="Invalid value of option --binary-source.")
742
743        if GlobalData.gBinCacheDest:
744            BinCacheDest = os.path.normpath(GlobalData.gBinCacheDest)
745            if not os.path.isabs(BinCacheDest):
746                BinCacheDest = mws.join(self.WorkspaceDir, BinCacheDest)
747            GlobalData.gBinCacheDest = BinCacheDest
748        else:
749            if GlobalData.gBinCacheDest is not None:
750                EdkLogger.error("build", OPTION_VALUE_INVALID, ExtraData="Invalid value of option --binary-destination.")
751
752        if self.ConfDirectory:
753            # Get alternate Conf location, if it is absolute, then just use the absolute directory name
754            ConfDirectoryPath = os.path.normpath(self.ConfDirectory)
755
756            if not os.path.isabs(ConfDirectoryPath):
757                # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
758                # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
759                ConfDirectoryPath = mws.join(self.WorkspaceDir, ConfDirectoryPath)
760        else:
761            if "CONF_PATH" in os.environ:
762                ConfDirectoryPath = os.path.normcase(os.path.normpath(os.environ["CONF_PATH"]))
763            else:
764                # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf
765                ConfDirectoryPath = mws.join(self.WorkspaceDir, 'Conf')
766        GlobalData.gConfDirectory = ConfDirectoryPath
767        GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath))
768
769        self.Db = WorkspaceDatabase()
770        self.BuildDatabase = self.Db.BuildObject
771        self.Platform = None
772        self.ToolChainFamily = None
773        self.LoadFixAddress = 0
774        self.UniFlag        = BuildOptions.Flag
775        self.BuildModules = []
776        self.HashSkipModules = []
777        self.Db_Flag = False
778        self.LaunchPrebuildFlag = False
779        self.PlatformBuildPath = os.path.join(GlobalData.gConfDirectory, '.cache', '.PlatformBuild')
780        if BuildOptions.CommandLength:
781            GlobalData.gCommandMaxLength = BuildOptions.CommandLength
782
783        # print dot character during doing some time-consuming work
784        self.Progress = Utils.Progressor()
785        # print current build environment and configuration
786        EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))
787        if "PACKAGES_PATH" in os.environ:
788            # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
789            EdkLogger.quiet("%-16s = %s" % ("PACKAGES_PATH", os.path.normcase(os.path.normpath(os.environ["PACKAGES_PATH"]))))
790        EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))
791        if "EDK_TOOLS_BIN" in os.environ:
792            # Print the same path style with WORKSPACE env.
793            EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os.path.normcase(os.path.normpath(os.environ["EDK_TOOLS_BIN"]))))
794        EdkLogger.quiet("%-16s = %s" % ("CONF_PATH", GlobalData.gConfDirectory))
795        if "PYTHON3_ENABLE" in os.environ:
796            PYTHON3_ENABLE = os.environ["PYTHON3_ENABLE"]
797            if PYTHON3_ENABLE != "TRUE":
798                PYTHON3_ENABLE = "FALSE"
799            EdkLogger.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE))
800        if "PYTHON_COMMAND" in os.environ:
801            EdkLogger.quiet("%-16s = %s" % ("PYTHON_COMMAND", os.environ["PYTHON_COMMAND"]))
802        self.InitPreBuild()
803        self.InitPostBuild()
804        if self.Prebuild:
805            EdkLogger.quiet("%-16s = %s" % ("PREBUILD", self.Prebuild))
806        if self.Postbuild:
807            EdkLogger.quiet("%-16s = %s" % ("POSTBUILD", self.Postbuild))
808        if self.Prebuild:
809            self.LaunchPrebuild()
810            self.TargetTxt = TargetTxtClassObject()
811            self.ToolDef   = ToolDefClassObject()
812        if not (self.LaunchPrebuildFlag and os.path.exists(self.PlatformBuildPath)):
813            self.InitBuild()
814
815        EdkLogger.info("")
816        os.chdir(self.WorkspaceDir)
817
818    ## Load configuration
819    #
820    #   This method will parse target.txt and get the build configurations.
821    #
822    def LoadConfiguration(self):
823        #
824        # Check target.txt and tools_def.txt and Init them
825        #
826        BuildConfigurationFile = os.path.normpath(os.path.join(GlobalData.gConfDirectory, gBuildConfiguration))
827        if os.path.isfile(BuildConfigurationFile) == True:
828            StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)
829
830            ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TOOL_CHAIN_CONF]
831            if ToolDefinitionFile == '':
832                ToolDefinitionFile = gToolsDefinition
833                ToolDefinitionFile = os.path.normpath(mws.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile))
834            if os.path.isfile(ToolDefinitionFile) == True:
835                StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)
836            else:
837                EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)
838        else:
839            EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)
840
841        # if no ARCH given in command line, get it from target.txt
842        if not self.ArchList:
843            self.ArchList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET_ARCH]
844        self.ArchList = tuple(self.ArchList)
845
846        # if no build target given in command line, get it from target.txt
847        if not self.BuildTargetList:
848            self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET]
849
850        # if no tool chain given in command line, get it from target.txt
851        if not self.ToolChainList:
852            self.ToolChainList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TOOL_CHAIN_TAG]
853            if self.ToolChainList is None or len(self.ToolChainList) == 0:
854                EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")
855
856        # check if the tool chains are defined or not
857        NewToolChainList = []
858        for ToolChain in self.ToolChainList:
859            if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:
860                EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)
861            else:
862                NewToolChainList.append(ToolChain)
863        # if no tool chain available, break the build
864        if len(NewToolChainList) == 0:
865            EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
866                            ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))
867        else:
868            self.ToolChainList = NewToolChainList
869
870        ToolChainFamily = []
871        ToolDefinition = self.ToolDef.ToolsDefTxtDatabase
872        for Tool in self.ToolChainList:
873            if TAB_TOD_DEFINES_FAMILY not in ToolDefinition or Tool not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \
874               or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool]:
875                EdkLogger.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool)
876                ToolChainFamily.append(TAB_COMPILER_MSFT)
877            else:
878                ToolChainFamily.append(ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool])
879        self.ToolChainFamily = ToolChainFamily
880
881        if self.ThreadNumber is None:
882            self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]
883            if self.ThreadNumber == '':
884                self.ThreadNumber = 0
885            else:
886                self.ThreadNumber = int(self.ThreadNumber, 0)
887
888        if self.ThreadNumber == 0:
889            try:
890                self.ThreadNumber = multiprocessing.cpu_count()
891            except (ImportError, NotImplementedError):
892                self.ThreadNumber = 1
893
894        if not self.PlatformFile:
895            PlatformFile = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_ACTIVE_PLATFORM]
896            if not PlatformFile:
897                # Try to find one in current directory
898                WorkingDirectory = os.getcwd()
899                FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))
900                FileNum = len(FileList)
901                if FileNum >= 2:
902                    EdkLogger.error("build", OPTION_MISSING,
903                                    ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))
904                elif FileNum == 1:
905                    PlatformFile = FileList[0]
906                else:
907                    EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
908                                    ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")
909
910            self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)
911
912    ## Initialize build configuration
913    #
914    #   This method will parse DSC file and merge the configurations from
915    #   command line and target.txt, then get the final build configurations.
916    #
917    def InitBuild(self):
918        # parse target.txt, tools_def.txt, and platform file
919        self.LoadConfiguration()
920
921        # Allow case-insensitive for those from command line or configuration file
922        ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)
923        if ErrorCode != 0:
924            EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
925
926
927    def InitPreBuild(self):
928        self.LoadConfiguration()
929        ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)
930        if ErrorCode != 0:
931            EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
932        if self.BuildTargetList:
933            GlobalData.gGlobalDefines['TARGET'] = self.BuildTargetList[0]
934        if self.ArchList:
935            GlobalData.gGlobalDefines['ARCH'] = self.ArchList[0]
936        if self.ToolChainList:
937            GlobalData.gGlobalDefines['TOOLCHAIN'] = self.ToolChainList[0]
938            GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = self.ToolChainList[0]
939        if self.ToolChainFamily:
940            GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[0]
941        if 'PREBUILD' in GlobalData.gCommandLineDefines:
942            self.Prebuild   = GlobalData.gCommandLineDefines.get('PREBUILD')
943        else:
944            self.Db_Flag = True
945            Platform = self.Db.MapPlatform(str(self.PlatformFile))
946            self.Prebuild = str(Platform.Prebuild)
947        if self.Prebuild:
948            PrebuildList = []
949            #
950            # Evaluate all arguments and convert arguments that are WORKSPACE
951            # relative paths to absolute paths.  Filter arguments that look like
952            # flags or do not follow the file/dir naming rules to avoid false
953            # positives on this conversion.
954            #
955            for Arg in self.Prebuild.split():
956                #
957                # Do not modify Arg if it looks like a flag or an absolute file path
958                #
959                if Arg.startswith('-')  or os.path.isabs(Arg):
960                    PrebuildList.append(Arg)
961                    continue
962                #
963                # Do not modify Arg if it does not look like a Workspace relative
964                # path that starts with a valid package directory name
965                #
966                if not Arg[0].isalpha() or os.path.dirname(Arg) == '':
967                    PrebuildList.append(Arg)
968                    continue
969                #
970                # If Arg looks like a WORKSPACE relative path, then convert to an
971                # absolute path and check to see if the file exists.
972                #
973                Temp = mws.join(self.WorkspaceDir, Arg)
974                if os.path.isfile(Temp):
975                    Arg = Temp
976                PrebuildList.append(Arg)
977            self.Prebuild       = ' '.join(PrebuildList)
978            self.Prebuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)
979
980    def InitPostBuild(self):
981        if 'POSTBUILD' in GlobalData.gCommandLineDefines:
982            self.Postbuild = GlobalData.gCommandLineDefines.get('POSTBUILD')
983        else:
984            Platform = self.Db.MapPlatform(str(self.PlatformFile))
985            self.Postbuild = str(Platform.Postbuild)
986        if self.Postbuild:
987            PostbuildList = []
988            #
989            # Evaluate all arguments and convert arguments that are WORKSPACE
990            # relative paths to absolute paths.  Filter arguments that look like
991            # flags or do not follow the file/dir naming rules to avoid false
992            # positives on this conversion.
993            #
994            for Arg in self.Postbuild.split():
995                #
996                # Do not modify Arg if it looks like a flag or an absolute file path
997                #
998                if Arg.startswith('-')  or os.path.isabs(Arg):
999                    PostbuildList.append(Arg)
1000                    continue
1001                #
1002                # Do not modify Arg if it does not look like a Workspace relative
1003                # path that starts with a valid package directory name
1004                #
1005                if not Arg[0].isalpha() or os.path.dirname(Arg) == '':
1006                    PostbuildList.append(Arg)
1007                    continue
1008                #
1009                # If Arg looks like a WORKSPACE relative path, then convert to an
1010                # absolute path and check to see if the file exists.
1011                #
1012                Temp = mws.join(self.WorkspaceDir, Arg)
1013                if os.path.isfile(Temp):
1014                    Arg = Temp
1015                PostbuildList.append(Arg)
1016            self.Postbuild       = ' '.join(PostbuildList)
1017            self.Postbuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)
1018
1019    def PassCommandOption(self, BuildTarget, TargetArch, ToolChain, PlatformFile, Target):
1020        BuildStr = ''
1021        if GlobalData.gCommand and isinstance(GlobalData.gCommand, list):
1022            BuildStr += ' ' + ' '.join(GlobalData.gCommand)
1023        TargetFlag = False
1024        ArchFlag = False
1025        ToolChainFlag = False
1026        PlatformFileFlag = False
1027
1028        if GlobalData.gOptions and not GlobalData.gOptions.BuildTarget:
1029            TargetFlag = True
1030        if GlobalData.gOptions and not GlobalData.gOptions.TargetArch:
1031            ArchFlag = True
1032        if GlobalData.gOptions and not GlobalData.gOptions.ToolChain:
1033            ToolChainFlag = True
1034        if GlobalData.gOptions and not GlobalData.gOptions.PlatformFile:
1035            PlatformFileFlag = True
1036
1037        if TargetFlag and BuildTarget:
1038            if isinstance(BuildTarget, list) or isinstance(BuildTarget, tuple):
1039                BuildStr += ' -b ' + ' -b '.join(BuildTarget)
1040            elif isinstance(BuildTarget, str):
1041                BuildStr += ' -b ' + BuildTarget
1042        if ArchFlag and TargetArch:
1043            if isinstance(TargetArch, list) or isinstance(TargetArch, tuple):
1044                BuildStr += ' -a ' + ' -a '.join(TargetArch)
1045            elif isinstance(TargetArch, str):
1046                BuildStr += ' -a ' + TargetArch
1047        if ToolChainFlag and ToolChain:
1048            if isinstance(ToolChain, list) or isinstance(ToolChain, tuple):
1049                BuildStr += ' -t ' + ' -t '.join(ToolChain)
1050            elif isinstance(ToolChain, str):
1051                BuildStr += ' -t ' + ToolChain
1052        if PlatformFileFlag and PlatformFile:
1053            if isinstance(PlatformFile, list) or isinstance(PlatformFile, tuple):
1054                BuildStr += ' -p ' + ' -p '.join(PlatformFile)
1055            elif isinstance(PlatformFile, str):
1056                BuildStr += ' -p' + PlatformFile
1057        BuildStr += ' --conf=' + GlobalData.gConfDirectory
1058        if Target:
1059            BuildStr += ' ' + Target
1060
1061        return BuildStr
1062
1063    def LaunchPrebuild(self):
1064        if self.Prebuild:
1065            EdkLogger.info("\n- Prebuild Start -\n")
1066            self.LaunchPrebuildFlag = True
1067            #
1068            # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1069            # and preserve them for the rest of the main build step, because the child process environment will
1070            # evaporate as soon as it exits, we cannot get it in build step.
1071            #
1072            PrebuildEnvFile = os.path.join(GlobalData.gConfDirectory, '.cache', '.PrebuildEnv')
1073            if os.path.isfile(PrebuildEnvFile):
1074                os.remove(PrebuildEnvFile)
1075            if os.path.isfile(self.PlatformBuildPath):
1076                os.remove(self.PlatformBuildPath)
1077            if sys.platform == "win32":
1078                args = ' && '.join((self.Prebuild, 'set > ' + PrebuildEnvFile))
1079                Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)
1080            else:
1081                args = ' && '.join((self.Prebuild, 'env > ' + PrebuildEnvFile))
1082                Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)
1083
1084            # launch two threads to read the STDOUT and STDERR
1085            EndOfProcedure = Event()
1086            EndOfProcedure.clear()
1087            if Process.stdout:
1088                StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))
1089                StdOutThread.setName("STDOUT-Redirector")
1090                StdOutThread.setDaemon(False)
1091                StdOutThread.start()
1092
1093            if Process.stderr:
1094                StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))
1095                StdErrThread.setName("STDERR-Redirector")
1096                StdErrThread.setDaemon(False)
1097                StdErrThread.start()
1098            # waiting for program exit
1099            Process.wait()
1100
1101            if Process.stdout:
1102                StdOutThread.join()
1103            if Process.stderr:
1104                StdErrThread.join()
1105            if Process.returncode != 0 :
1106                EdkLogger.error("Prebuild", PREBUILD_ERROR, 'Prebuild process is not success!')
1107
1108            if os.path.exists(PrebuildEnvFile):
1109                f = open(PrebuildEnvFile)
1110                envs = f.readlines()
1111                f.close()
1112                envs = [l.split("=", 1) for l in envs ]
1113                envs = [[I.strip() for I in item] for item in envs if len(item) == 2]
1114                os.environ.update(dict(envs))
1115            EdkLogger.info("\n- Prebuild Done -\n")
1116
1117    def LaunchPostbuild(self):
1118        if self.Postbuild:
1119            EdkLogger.info("\n- Postbuild Start -\n")
1120            if sys.platform == "win32":
1121                Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)
1122            else:
1123                Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)
1124            # launch two threads to read the STDOUT and STDERR
1125            EndOfProcedure = Event()
1126            EndOfProcedure.clear()
1127            if Process.stdout:
1128                StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))
1129                StdOutThread.setName("STDOUT-Redirector")
1130                StdOutThread.setDaemon(False)
1131                StdOutThread.start()
1132
1133            if Process.stderr:
1134                StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))
1135                StdErrThread.setName("STDERR-Redirector")
1136                StdErrThread.setDaemon(False)
1137                StdErrThread.start()
1138            # waiting for program exit
1139            Process.wait()
1140
1141            if Process.stdout:
1142                StdOutThread.join()
1143            if Process.stderr:
1144                StdErrThread.join()
1145            if Process.returncode != 0 :
1146                EdkLogger.error("Postbuild", POSTBUILD_ERROR, 'Postbuild process is not success!')
1147            EdkLogger.info("\n- Postbuild Done -\n")
1148
1149    ## Error handling for hash feature
1150    #
1151    # On BuildTask error, iterate through the Module Build tracking
1152    # dictionary to determine wheather a module failed to build. Invalidate
1153    # the hash associated with that module by removing it from storage.
1154    #
1155    #
1156    def invalidateHash(self):
1157        # GlobalData.gModuleBuildTracking contains only modules that cannot be skipped by hash
1158        for moduleAutoGenObj in GlobalData.gModuleBuildTracking.keys():
1159            # False == FAIL : True == Success
1160            # Skip invalidating for Successful module builds
1161            if GlobalData.gModuleBuildTracking[moduleAutoGenObj] == True:
1162                continue
1163
1164            # The module failed to build or failed to start building, from this point on
1165
1166            # Remove .hash from build
1167            if GlobalData.gUseHashCache:
1168                ModuleHashFile = path.join(moduleAutoGenObj.BuildDir, moduleAutoGenObj.Name + ".hash")
1169                if os.path.exists(ModuleHashFile):
1170                    os.remove(ModuleHashFile)
1171
1172            # Remove .hash file from cache
1173            if GlobalData.gBinCacheDest:
1174                FileDir = path.join(GlobalData.gBinCacheDest, moduleAutoGenObj.Arch, moduleAutoGenObj.SourceDir, moduleAutoGenObj.MetaFile.BaseName)
1175                HashFile = path.join(FileDir, moduleAutoGenObj.Name + '.hash')
1176                if os.path.exists(HashFile):
1177                    os.remove(HashFile)
1178
1179    ## Build a module or platform
1180    #
1181    # Create autogen code and makefile for a module or platform, and the launch
1182    # "make" command to build it
1183    #
1184    #   @param  Target                      The target of build command
1185    #   @param  Platform                    The platform file
1186    #   @param  Module                      The module file
1187    #   @param  BuildTarget                 The name of build target, one of "DEBUG", "RELEASE"
1188    #   @param  ToolChain                   The name of toolchain to build
1189    #   @param  Arch                        The arch of the module/platform
1190    #   @param  CreateDepModuleCodeFile     Flag used to indicate creating code
1191    #                                       for dependent modules/Libraries
1192    #   @param  CreateDepModuleMakeFile     Flag used to indicate creating makefile
1193    #                                       for dependent modules/Libraries
1194    #
1195    def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False, FfsCommand={}):
1196        if AutoGenObject is None:
1197            return False
1198
1199        # skip file generation for cleanxxx targets, run and fds target
1200        if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1201            # for target which must generate AutoGen code and makefile
1202            if not self.SkipAutoGen or Target == 'genc':
1203                self.Progress.Start("Generating code")
1204                AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
1205                self.Progress.Stop("done!")
1206            if Target == "genc":
1207                return True
1208
1209            if not self.SkipAutoGen or Target == 'genmake':
1210                self.Progress.Start("Generating makefile")
1211                AutoGenObject.CreateMakeFile(CreateDepsMakeFile, FfsCommand)
1212                self.Progress.Stop("done!")
1213            if Target == "genmake":
1214                return True
1215        else:
1216            # always recreate top/platform makefile when clean, just in case of inconsistency
1217            AutoGenObject.CreateCodeFile(False)
1218            AutoGenObject.CreateMakeFile(False)
1219
1220        if EdkLogger.GetLevel() == EdkLogger.QUIET:
1221            EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
1222
1223        BuildCommand = AutoGenObject.BuildCommand
1224        if BuildCommand is None or len(BuildCommand) == 0:
1225            EdkLogger.error("build", OPTION_MISSING,
1226                            "No build command found for this module. "
1227                            "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1228                                (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
1229                            ExtraData=str(AutoGenObject))
1230
1231        makefile = GenMake.BuildFile(AutoGenObject)._FILE_NAME_[GenMake.gMakeType]
1232
1233        # run
1234        if Target == 'run':
1235            return True
1236
1237        # build modules
1238        if BuildModule:
1239            BuildCommand = BuildCommand + [Target]
1240            LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
1241            self.CreateAsBuiltInf()
1242            return True
1243
1244        # build library
1245        if Target == 'libraries':
1246            for Lib in AutoGenObject.LibraryBuildDirectoryList:
1247                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']
1248                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1249            return True
1250
1251        # build module
1252        if Target == 'modules':
1253            for Lib in AutoGenObject.LibraryBuildDirectoryList:
1254                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']
1255                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1256            for Mod in AutoGenObject.ModuleBuildDirectoryList:
1257                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']
1258                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1259            self.CreateAsBuiltInf()
1260            return True
1261
1262        # cleanlib
1263        if Target == 'cleanlib':
1264            for Lib in AutoGenObject.LibraryBuildDirectoryList:
1265                LibMakefile = os.path.normpath(os.path.join(Lib, makefile))
1266                if os.path.exists(LibMakefile):
1267                    NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
1268                    LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1269            return True
1270
1271        # clean
1272        if Target == 'clean':
1273            for Mod in AutoGenObject.ModuleBuildDirectoryList:
1274                ModMakefile = os.path.normpath(os.path.join(Mod, makefile))
1275                if os.path.exists(ModMakefile):
1276                    NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']
1277                    LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1278            for Lib in AutoGenObject.LibraryBuildDirectoryList:
1279                LibMakefile = os.path.normpath(os.path.join(Lib, makefile))
1280                if os.path.exists(LibMakefile):
1281                    NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
1282                    LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1283            return True
1284
1285        # cleanall
1286        if Target == 'cleanall':
1287            try:
1288                #os.rmdir(AutoGenObject.BuildDir)
1289                RemoveDirectory(AutoGenObject.BuildDir, True)
1290            except WindowsError as X:
1291                EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
1292        return True
1293
1294    ## Build a module or platform
1295    #
1296    # Create autogen code and makefile for a module or platform, and the launch
1297    # "make" command to build it
1298    #
1299    #   @param  Target                      The target of build command
1300    #   @param  Platform                    The platform file
1301    #   @param  Module                      The module file
1302    #   @param  BuildTarget                 The name of build target, one of "DEBUG", "RELEASE"
1303    #   @param  ToolChain                   The name of toolchain to build
1304    #   @param  Arch                        The arch of the module/platform
1305    #   @param  CreateDepModuleCodeFile     Flag used to indicate creating code
1306    #                                       for dependent modules/Libraries
1307    #   @param  CreateDepModuleMakeFile     Flag used to indicate creating makefile
1308    #                                       for dependent modules/Libraries
1309    #
1310    def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):
1311        if AutoGenObject is None:
1312            return False
1313
1314        # skip file generation for cleanxxx targets, run and fds target
1315        if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1316            # for target which must generate AutoGen code and makefile
1317            if not self.SkipAutoGen or Target == 'genc':
1318                self.Progress.Start("Generating code")
1319                AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
1320                self.Progress.Stop("done!")
1321            if Target == "genc":
1322                return True
1323
1324            if not self.SkipAutoGen or Target == 'genmake':
1325                self.Progress.Start("Generating makefile")
1326                AutoGenObject.CreateMakeFile(CreateDepsMakeFile)
1327                #AutoGenObject.CreateAsBuiltInf()
1328                self.Progress.Stop("done!")
1329            if Target == "genmake":
1330                return True
1331        else:
1332            # always recreate top/platform makefile when clean, just in case of inconsistency
1333            AutoGenObject.CreateCodeFile(False)
1334            AutoGenObject.CreateMakeFile(False)
1335
1336        if EdkLogger.GetLevel() == EdkLogger.QUIET:
1337            EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
1338
1339        BuildCommand = AutoGenObject.BuildCommand
1340        if BuildCommand is None or len(BuildCommand) == 0:
1341            EdkLogger.error("build", OPTION_MISSING,
1342                            "No build command found for this module. "
1343                            "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1344                                (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
1345                            ExtraData=str(AutoGenObject))
1346
1347        # build modules
1348        if BuildModule:
1349            if Target != 'fds':
1350                BuildCommand = BuildCommand + [Target]
1351            AutoGenObject.BuildTime = LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
1352            self.CreateAsBuiltInf()
1353            return True
1354
1355        # genfds
1356        if Target == 'fds':
1357            if GenFdsApi(AutoGenObject.GenFdsCommandDict, self.Db):
1358                EdkLogger.error("build", COMMAND_FAILURE)
1359            return True
1360
1361        # run
1362        if Target == 'run':
1363            return True
1364
1365        # build library
1366        if Target == 'libraries':
1367            pass
1368
1369        # not build modules
1370
1371
1372        # cleanall
1373        if Target == 'cleanall':
1374            try:
1375                #os.rmdir(AutoGenObject.BuildDir)
1376                RemoveDirectory(AutoGenObject.BuildDir, True)
1377            except WindowsError as X:
1378                EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
1379        return True
1380
1381    ## Rebase module image and Get function address for the input module list.
1382    #
1383    def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):
1384        if ModeIsSmm:
1385            AddrIsOffset = False
1386        for InfFile in ModuleList:
1387            sys.stdout.write (".")
1388            sys.stdout.flush()
1389            ModuleInfo = ModuleList[InfFile]
1390            ModuleName = ModuleInfo.BaseName
1391            ModuleOutputImage = ModuleInfo.Image.FileName
1392            ModuleDebugImage  = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')
1393            ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1394            if not ModeIsSmm:
1395                BaseAddress = BaseAddress - ModuleInfo.Image.Size
1396                #
1397                # Update Image to new BaseAddress by GenFw tool
1398                #
1399                LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
1400                LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
1401            else:
1402                #
1403                # Set new address to the section header only for SMM driver.
1404                #
1405                LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
1406                LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
1407            #
1408            # Collect function address from Map file
1409            #
1410            ImageMapTable = ModuleOutputImage.replace('.efi', '.map')
1411            FunctionList = []
1412            if os.path.exists(ImageMapTable):
1413                OrigImageBaseAddress = 0
1414                ImageMap = open(ImageMapTable, 'r')
1415                for LinStr in ImageMap:
1416                    if len (LinStr.strip()) == 0:
1417                        continue
1418                    #
1419                    # Get the preferred address set on link time.
1420                    #
1421                    if LinStr.find ('Preferred load address is') != -1:
1422                        StrList = LinStr.split()
1423                        OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)
1424
1425                    StrList = LinStr.split()
1426                    if len (StrList) > 4:
1427                        if StrList[3] == 'f' or StrList[3] == 'F':
1428                            Name = StrList[1]
1429                            RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress
1430                            FunctionList.append ((Name, RelativeAddress))
1431
1432                ImageMap.close()
1433            #
1434            # Add general information.
1435            #
1436            if ModeIsSmm:
1437                MapBuffer.append('\n\n%s (Fixed SMRAM Offset,   BaseAddress=0x%010X,  EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
1438            elif AddrIsOffset:
1439                MapBuffer.append('\n\n%s (Fixed Memory Offset,  BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))
1440            else:
1441                MapBuffer.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X,  EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
1442            #
1443            # Add guid and general seciton section.
1444            #
1445            TextSectionAddress = 0
1446            DataSectionAddress = 0
1447            for SectionHeader in ModuleInfo.Image.SectionHeaderList:
1448                if SectionHeader[0] == '.text':
1449                    TextSectionAddress = SectionHeader[1]
1450                elif SectionHeader[0] in ['.data', '.sdata']:
1451                    DataSectionAddress = SectionHeader[1]
1452            if AddrIsOffset:
1453                MapBuffer.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))
1454            else:
1455                MapBuffer.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))
1456            #
1457            # Add debug image full path.
1458            #
1459            MapBuffer.append('(IMAGE=%s)\n\n' % (ModuleDebugImage))
1460            #
1461            # Add function address
1462            #
1463            for Function in FunctionList:
1464                if AddrIsOffset:
1465                    MapBuffer.append('  -0x%010X    %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))
1466                else:
1467                    MapBuffer.append('  0x%010X    %s\n' % (BaseAddress + Function[1], Function[0]))
1468            ImageMap.close()
1469
1470            #
1471            # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1472            #
1473            if ModeIsSmm:
1474                BaseAddress = BaseAddress + ModuleInfo.Image.Size
1475
1476    ## Collect MAP information of all FVs
1477    #
1478    def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):
1479        if self.Fdf:
1480            # First get the XIP base address for FV map file.
1481            GuidPattern = re.compile("[-a-fA-F0-9]+")
1482            GuidName = re.compile("\(GUID=[-a-fA-F0-9]+")
1483            for FvName in Wa.FdfProfile.FvDict:
1484                FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')
1485                if not os.path.exists(FvMapBuffer):
1486                    continue
1487                FvMap = open(FvMapBuffer, 'r')
1488                #skip FV size information
1489                FvMap.readline()
1490                FvMap.readline()
1491                FvMap.readline()
1492                FvMap.readline()
1493                for Line in FvMap:
1494                    MatchGuid = GuidPattern.match(Line)
1495                    if MatchGuid is not None:
1496                        #
1497                        # Replace GUID with module name
1498                        #
1499                        GuidString = MatchGuid.group()
1500                        if GuidString.upper() in ModuleList:
1501                            Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)
1502                    MapBuffer.append(Line)
1503                    #
1504                    # Add the debug image full path.
1505                    #
1506                    MatchGuid = GuidName.match(Line)
1507                    if MatchGuid is not None:
1508                        GuidString = MatchGuid.group().split("=")[1]
1509                        if GuidString.upper() in ModuleList:
1510                            MapBuffer.append('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))
1511
1512                FvMap.close()
1513
1514    ## Collect MAP information of all modules
1515    #
1516    def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):
1517        sys.stdout.write ("Generate Load Module At Fix Address Map")
1518        sys.stdout.flush()
1519        PatchEfiImageList = []
1520        PeiModuleList  = {}
1521        BtModuleList   = {}
1522        RtModuleList   = {}
1523        SmmModuleList  = {}
1524        PeiSize = 0
1525        BtSize  = 0
1526        RtSize  = 0
1527        # reserve 4K size in SMRAM to make SMM module address not from 0.
1528        SmmSize = 0x1000
1529        for ModuleGuid in ModuleList:
1530            Module = ModuleList[ModuleGuid]
1531            GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)
1532
1533            OutputImageFile = ''
1534            for ResultFile in Module.CodaTargetList:
1535                if str(ResultFile.Target).endswith('.efi'):
1536                    #
1537                    # module list for PEI, DXE, RUNTIME and SMM
1538                    #
1539                    OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')
1540                    ImageClass = PeImageClass (OutputImageFile)
1541                    if not ImageClass.IsValid:
1542                        EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)
1543                    ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)
1544                    if Module.ModuleType in [SUP_MODULE_PEI_CORE, SUP_MODULE_PEIM, EDK_COMPONENT_TYPE_COMBINED_PEIM_DRIVER, EDK_COMPONENT_TYPE_PIC_PEIM, EDK_COMPONENT_TYPE_RELOCATABLE_PEIM, SUP_MODULE_DXE_CORE]:
1545                        PeiModuleList[Module.MetaFile] = ImageInfo
1546                        PeiSize += ImageInfo.Image.Size
1547                    elif Module.ModuleType in [EDK_COMPONENT_TYPE_BS_DRIVER, SUP_MODULE_DXE_DRIVER, SUP_MODULE_UEFI_DRIVER]:
1548                        BtModuleList[Module.MetaFile] = ImageInfo
1549                        BtSize += ImageInfo.Image.Size
1550                    elif Module.ModuleType in [SUP_MODULE_DXE_RUNTIME_DRIVER, EDK_COMPONENT_TYPE_RT_DRIVER, SUP_MODULE_DXE_SAL_DRIVER, EDK_COMPONENT_TYPE_SAL_RT_DRIVER]:
1551                        RtModuleList[Module.MetaFile] = ImageInfo
1552                        RtSize += ImageInfo.Image.Size
1553                    elif Module.ModuleType in [SUP_MODULE_SMM_CORE, SUP_MODULE_DXE_SMM_DRIVER, SUP_MODULE_MM_STANDALONE, SUP_MODULE_MM_CORE_STANDALONE]:
1554                        SmmModuleList[Module.MetaFile] = ImageInfo
1555                        SmmSize += ImageInfo.Image.Size
1556                        if Module.ModuleType == SUP_MODULE_DXE_SMM_DRIVER:
1557                            PiSpecVersion = Module.Module.Specification.get('PI_SPECIFICATION_VERSION', '0x00000000')
1558                            # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1559                            if int(PiSpecVersion, 16) < 0x0001000A:
1560                                BtModuleList[Module.MetaFile] = ImageInfo
1561                                BtSize += ImageInfo.Image.Size
1562                    break
1563            #
1564            # EFI image is final target.
1565            # Check EFI image contains patchable FixAddress related PCDs.
1566            #
1567            if OutputImageFile != '':
1568                ModuleIsPatch = False
1569                for Pcd in Module.ModulePcdList:
1570                    if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:
1571                        ModuleIsPatch = True
1572                        break
1573                if not ModuleIsPatch:
1574                    for Pcd in Module.LibraryPcdList:
1575                        if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:
1576                            ModuleIsPatch = True
1577                            break
1578
1579                if not ModuleIsPatch:
1580                    continue
1581                #
1582                # Module includes the patchable load fix address PCDs.
1583                # It will be fixed up later.
1584                #
1585                PatchEfiImageList.append (OutputImageFile)
1586
1587        #
1588        # Get Top Memory address
1589        #
1590        ReservedRuntimeMemorySize = 0
1591        TopMemoryAddress = 0
1592        if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:
1593            TopMemoryAddress = 0
1594        else:
1595            TopMemoryAddress = self.LoadFixAddress
1596            if TopMemoryAddress < RtSize + BtSize + PeiSize:
1597                EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1598
1599        #
1600        # Patch FixAddress related PCDs into EFI image
1601        #
1602        for EfiImage in PatchEfiImageList:
1603            EfiImageMap = EfiImage.replace('.efi', '.map')
1604            if not os.path.exists(EfiImageMap):
1605                continue
1606            #
1607            # Get PCD offset in EFI image by GenPatchPcdTable function
1608            #
1609            PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)
1610            #
1611            # Patch real PCD value by PatchPcdValue tool
1612            #
1613            for PcdInfo in PcdTable:
1614                ReturnValue = 0
1615                if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:
1616                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize // 0x1000))
1617                elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:
1618                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize // 0x1000))
1619                elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:
1620                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize // 0x1000))
1621                elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:
1622                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize // 0x1000))
1623                if ReturnValue != 0:
1624                    EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)
1625
1626        MapBuffer.append('PEI_CODE_PAGE_NUMBER      = 0x%x\n' % (PeiSize // 0x1000))
1627        MapBuffer.append('BOOT_CODE_PAGE_NUMBER     = 0x%x\n' % (BtSize // 0x1000))
1628        MapBuffer.append('RUNTIME_CODE_PAGE_NUMBER  = 0x%x\n' % (RtSize // 0x1000))
1629        if len (SmmModuleList) > 0:
1630            MapBuffer.append('SMM_CODE_PAGE_NUMBER      = 0x%x\n' % (SmmSize // 0x1000))
1631
1632        PeiBaseAddr = TopMemoryAddress - RtSize - BtSize
1633        BtBaseAddr  = TopMemoryAddress - RtSize
1634        RtBaseAddr  = TopMemoryAddress - ReservedRuntimeMemorySize
1635
1636        self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)
1637        self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)
1638        self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)
1639        self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset=False, ModeIsSmm=True)
1640        MapBuffer.append('\n\n')
1641        sys.stdout.write ("\n")
1642        sys.stdout.flush()
1643
1644    ## Save platform Map file
1645    #
1646    def _SaveMapFile (self, MapBuffer, Wa):
1647        #
1648        # Map file path is got.
1649        #
1650        MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')
1651        #
1652        # Save address map into MAP file.
1653        #
1654        SaveFileOnChange(MapFilePath, ''.join(MapBuffer), False)
1655        if self.LoadFixAddress != 0:
1656            sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath))
1657        sys.stdout.flush()
1658
1659    ## Build active platform for different build targets and different tool chains
1660    #
1661    def _BuildPlatform(self):
1662        SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1663        for BuildTarget in self.BuildTargetList:
1664            GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1665            index = 0
1666            for ToolChain in self.ToolChainList:
1667                GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1668                GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1669                GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
1670                index += 1
1671                Wa = WorkspaceAutoGen(
1672                        self.WorkspaceDir,
1673                        self.PlatformFile,
1674                        BuildTarget,
1675                        ToolChain,
1676                        self.ArchList,
1677                        self.BuildDatabase,
1678                        self.TargetTxt,
1679                        self.ToolDef,
1680                        self.Fdf,
1681                        self.FdList,
1682                        self.FvList,
1683                        self.CapList,
1684                        self.SkuId,
1685                        self.UniFlag,
1686                        self.Progress
1687                        )
1688                self.Fdf = Wa.FdfFile
1689                self.LoadFixAddress = Wa.Platform.LoadFixAddress
1690                self.BuildReport.AddPlatformReport(Wa)
1691                self.Progress.Stop("done!")
1692
1693                # Add ffs build to makefile
1694                CmdListDict = {}
1695                if GlobalData.gEnableGenfdsMultiThread and self.Fdf:
1696                    CmdListDict = self._GenFfsCmd(Wa.ArchList)
1697
1698                for Arch in Wa.ArchList:
1699                    GlobalData.gGlobalDefines['ARCH'] = Arch
1700                    Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
1701                    for Module in Pa.Platform.Modules:
1702                        # Get ModuleAutoGen object to generate C code file and makefile
1703                        Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
1704                        if Ma is None:
1705                            continue
1706                        self.BuildModules.append(Ma)
1707                    self._BuildPa(self.Target, Pa, FfsCommand=CmdListDict)
1708
1709                # Create MAP file when Load Fix Address is enabled.
1710                if self.Target in ["", "all", "fds"]:
1711                    for Arch in Wa.ArchList:
1712                        GlobalData.gGlobalDefines['ARCH'] = Arch
1713                        #
1714                        # Check whether the set fix address is above 4G for 32bit image.
1715                        #
1716                        if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1717                            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")
1718                    #
1719                    # Get Module List
1720                    #
1721                    ModuleList = {}
1722                    for Pa in Wa.AutoGenObjectList:
1723                        for Ma in Pa.ModuleAutoGenList:
1724                            if Ma is None:
1725                                continue
1726                            if not Ma.IsLibrary:
1727                                ModuleList[Ma.Guid.upper()] = Ma
1728
1729                    MapBuffer = []
1730                    if self.LoadFixAddress != 0:
1731                        #
1732                        # Rebase module to the preferred memory address before GenFds
1733                        #
1734                        self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1735                    if self.Fdf:
1736                        #
1737                        # create FDS again for the updated EFI image
1738                        #
1739                        self._Build("fds", Wa)
1740                        #
1741                        # Create MAP file for all platform FVs after GenFds.
1742                        #
1743                        self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1744                    #
1745                    # Save MAP buffer into MAP file.
1746                    #
1747                    self._SaveMapFile (MapBuffer, Wa)
1748
1749    ## Build active module for different build targets, different tool chains and different archs
1750    #
1751    def _BuildModule(self):
1752        for BuildTarget in self.BuildTargetList:
1753            GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1754            index = 0
1755            for ToolChain in self.ToolChainList:
1756                WorkspaceAutoGenTime = time.time()
1757                GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1758                GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1759                GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
1760                index += 1
1761                #
1762                # module build needs platform build information, so get platform
1763                # AutoGen first
1764                #
1765                Wa = WorkspaceAutoGen(
1766                        self.WorkspaceDir,
1767                        self.PlatformFile,
1768                        BuildTarget,
1769                        ToolChain,
1770                        self.ArchList,
1771                        self.BuildDatabase,
1772                        self.TargetTxt,
1773                        self.ToolDef,
1774                        self.Fdf,
1775                        self.FdList,
1776                        self.FvList,
1777                        self.CapList,
1778                        self.SkuId,
1779                        self.UniFlag,
1780                        self.Progress,
1781                        self.ModuleFile
1782                        )
1783                self.Fdf = Wa.FdfFile
1784                self.LoadFixAddress = Wa.Platform.LoadFixAddress
1785                Wa.CreateMakeFile(False)
1786                # Add ffs build to makefile
1787                CmdListDict = None
1788                if GlobalData.gEnableGenfdsMultiThread and self.Fdf:
1789                    CmdListDict = self._GenFfsCmd(Wa.ArchList)
1790                self.Progress.Stop("done!")
1791                MaList = []
1792                ExitFlag = threading.Event()
1793                ExitFlag.clear()
1794                self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))
1795                for Arch in Wa.ArchList:
1796                    AutoGenStart = time.time()
1797                    GlobalData.gGlobalDefines['ARCH'] = Arch
1798                    Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
1799                    for Module in Pa.Platform.Modules:
1800                        if self.ModuleFile.Dir == Module.Dir and self.ModuleFile.Name == Module.Name:
1801                            Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
1802                            if Ma is None:
1803                                continue
1804                            MaList.append(Ma)
1805                            if Ma.CanSkipbyHash():
1806                                self.HashSkipModules.append(Ma)
1807                                continue
1808                            # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1809                            if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1810                                # for target which must generate AutoGen code and makefile
1811                                if not self.SkipAutoGen or self.Target == 'genc':
1812                                    self.Progress.Start("Generating code")
1813                                    Ma.CreateCodeFile(True)
1814                                    self.Progress.Stop("done!")
1815                                if self.Target == "genc":
1816                                    return True
1817                                if not self.SkipAutoGen or self.Target == 'genmake':
1818                                    self.Progress.Start("Generating makefile")
1819                                    if CmdListDict and self.Fdf and (Module.File, Arch) in CmdListDict:
1820                                        Ma.CreateMakeFile(True, CmdListDict[Module.File, Arch])
1821                                        del CmdListDict[Module.File, Arch]
1822                                    else:
1823                                        Ma.CreateMakeFile(True)
1824                                    self.Progress.Stop("done!")
1825                                if self.Target == "genmake":
1826                                    return True
1827                            self.BuildModules.append(Ma)
1828                            # Initialize all modules in tracking to False (FAIL)
1829                            if Ma not in GlobalData.gModuleBuildTracking:
1830                                GlobalData.gModuleBuildTracking[Ma] = False
1831                    self.AutoGenTime += int(round((time.time() - AutoGenStart)))
1832                    MakeStart = time.time()
1833                    for Ma in self.BuildModules:
1834                        if not Ma.IsBinaryModule:
1835                            Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))
1836                        # Break build if any build thread has error
1837                        if BuildTask.HasError():
1838                            # we need a full version of makefile for platform
1839                            ExitFlag.set()
1840                            BuildTask.WaitForComplete()
1841                            self.invalidateHash()
1842                            Pa.CreateMakeFile(False)
1843                            EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1844                        # Start task scheduler
1845                        if not BuildTask.IsOnGoing():
1846                            BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
1847
1848                    # in case there's an interruption. we need a full version of makefile for platform
1849                    Pa.CreateMakeFile(False)
1850                    if BuildTask.HasError():
1851                        self.invalidateHash()
1852                        EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1853                    self.MakeTime += int(round((time.time() - MakeStart)))
1854
1855                MakeContiue = time.time()
1856                ExitFlag.set()
1857                BuildTask.WaitForComplete()
1858                self.CreateAsBuiltInf()
1859                self.MakeTime += int(round((time.time() - MakeContiue)))
1860                if BuildTask.HasError():
1861                    self.invalidateHash()
1862                    EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1863
1864                self.BuildReport.AddPlatformReport(Wa, MaList)
1865                if MaList == []:
1866                    EdkLogger.error(
1867                                'build',
1868                                BUILD_ERROR,
1869                                "Module for [%s] is not a component of active platform."\
1870                                " Please make sure that the ARCH and inf file path are"\
1871                                " given in the same as in [%s]" % \
1872                                    (', '.join(Wa.ArchList), self.PlatformFile),
1873                                ExtraData=self.ModuleFile
1874                                )
1875                # Create MAP file when Load Fix Address is enabled.
1876                if self.Target == "fds" and self.Fdf:
1877                    for Arch in Wa.ArchList:
1878                        #
1879                        # Check whether the set fix address is above 4G for 32bit image.
1880                        #
1881                        if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1882                            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")
1883                    #
1884                    # Get Module List
1885                    #
1886                    ModuleList = {}
1887                    for Pa in Wa.AutoGenObjectList:
1888                        for Ma in Pa.ModuleAutoGenList:
1889                            if Ma is None:
1890                                continue
1891                            if not Ma.IsLibrary:
1892                                ModuleList[Ma.Guid.upper()] = Ma
1893
1894                    MapBuffer = []
1895                    if self.LoadFixAddress != 0:
1896                        #
1897                        # Rebase module to the preferred memory address before GenFds
1898                        #
1899                        self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1900                    #
1901                    # create FDS again for the updated EFI image
1902                    #
1903                    GenFdsStart = time.time()
1904                    self._Build("fds", Wa)
1905                    self.GenFdsTime += int(round((time.time() - GenFdsStart)))
1906                    #
1907                    # Create MAP file for all platform FVs after GenFds.
1908                    #
1909                    self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1910                    #
1911                    # Save MAP buffer into MAP file.
1912                    #
1913                    self._SaveMapFile (MapBuffer, Wa)
1914
1915    def _GenFfsCmd(self,ArchList):
1916        # convert dictionary of Cmd:(Inf,Arch)
1917        # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
1918        CmdSetDict = defaultdict(set)
1919        GenFfsDict = GenFds.GenFfsMakefile('', GlobalData.gFdfParser, self, ArchList, GlobalData)
1920        for Cmd in GenFfsDict:
1921            tmpInf, tmpArch = GenFfsDict[Cmd]
1922            CmdSetDict[tmpInf, tmpArch].add(Cmd)
1923        return CmdSetDict
1924
1925    ## Build a platform in multi-thread mode
1926    #
1927    def _MultiThreadBuildPlatform(self):
1928        SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1929        for BuildTarget in self.BuildTargetList:
1930            GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1931            index = 0
1932            for ToolChain in self.ToolChainList:
1933                WorkspaceAutoGenTime = time.time()
1934                GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1935                GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1936                GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
1937                index += 1
1938                Wa = WorkspaceAutoGen(
1939                        self.WorkspaceDir,
1940                        self.PlatformFile,
1941                        BuildTarget,
1942                        ToolChain,
1943                        self.ArchList,
1944                        self.BuildDatabase,
1945                        self.TargetTxt,
1946                        self.ToolDef,
1947                        self.Fdf,
1948                        self.FdList,
1949                        self.FvList,
1950                        self.CapList,
1951                        self.SkuId,
1952                        self.UniFlag,
1953                        self.Progress
1954                        )
1955                self.Fdf = Wa.FdfFile
1956                self.LoadFixAddress = Wa.Platform.LoadFixAddress
1957                self.BuildReport.AddPlatformReport(Wa)
1958                Wa.CreateMakeFile(False)
1959
1960                # Add ffs build to makefile
1961                CmdListDict = None
1962                if GlobalData.gEnableGenfdsMultiThread and self.Fdf:
1963                    CmdListDict = self._GenFfsCmd(Wa.ArchList)
1964
1965                # multi-thread exit flag
1966                ExitFlag = threading.Event()
1967                ExitFlag.clear()
1968                self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))
1969                for Arch in Wa.ArchList:
1970                    AutoGenStart = time.time()
1971                    GlobalData.gGlobalDefines['ARCH'] = Arch
1972                    Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
1973                    if Pa is None:
1974                        continue
1975                    ModuleList = []
1976                    for Inf in Pa.Platform.Modules:
1977                        ModuleList.append(Inf)
1978                    # Add the INF only list in FDF
1979                    if GlobalData.gFdfParser is not None:
1980                        for InfName in GlobalData.gFdfParser.Profile.InfList:
1981                            Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)
1982                            if Inf in Pa.Platform.Modules:
1983                                continue
1984                            ModuleList.append(Inf)
1985                    for Module in ModuleList:
1986                        # Get ModuleAutoGen object to generate C code file and makefile
1987                        Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
1988
1989                        if Ma is None:
1990                            continue
1991                        if Ma.CanSkipbyHash():
1992                            self.HashSkipModules.append(Ma)
1993                            continue
1994
1995                        # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1996                        if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1997                            # for target which must generate AutoGen code and makefile
1998                            if not self.SkipAutoGen or self.Target == 'genc':
1999                                Ma.CreateCodeFile(True)
2000                            if self.Target == "genc":
2001                                continue
2002
2003                            if not self.SkipAutoGen or self.Target == 'genmake':
2004                                if CmdListDict and self.Fdf and (Module.File, Arch) in CmdListDict:
2005                                    Ma.CreateMakeFile(True, CmdListDict[Module.File, Arch])
2006                                    del CmdListDict[Module.File, Arch]
2007                                else:
2008                                    Ma.CreateMakeFile(True)
2009                            if self.Target == "genmake":
2010                                continue
2011                        self.BuildModules.append(Ma)
2012                        # Initialize all modules in tracking to False (FAIL)
2013                        if Ma not in GlobalData.gModuleBuildTracking:
2014                            GlobalData.gModuleBuildTracking[Ma] = False
2015                    self.Progress.Stop("done!")
2016                    self.AutoGenTime += int(round((time.time() - AutoGenStart)))
2017                    MakeStart = time.time()
2018                    for Ma in self.BuildModules:
2019                        # Generate build task for the module
2020                        if not Ma.IsBinaryModule:
2021                            Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))
2022                        # Break build if any build thread has error
2023                        if BuildTask.HasError():
2024                            # we need a full version of makefile for platform
2025                            ExitFlag.set()
2026                            BuildTask.WaitForComplete()
2027                            self.invalidateHash()
2028                            Pa.CreateMakeFile(False)
2029                            EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
2030                        # Start task scheduler
2031                        if not BuildTask.IsOnGoing():
2032                            BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
2033
2034                    # in case there's an interruption. we need a full version of makefile for platform
2035                    Pa.CreateMakeFile(False)
2036                    if BuildTask.HasError():
2037                        self.invalidateHash()
2038                        EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
2039                    self.MakeTime += int(round((time.time() - MakeStart)))
2040
2041                MakeContiue = time.time()
2042
2043                #
2044                #
2045                # All modules have been put in build tasks queue. Tell task scheduler
2046                # to exit if all tasks are completed
2047                #
2048                ExitFlag.set()
2049                BuildTask.WaitForComplete()
2050                self.CreateAsBuiltInf()
2051                self.MakeTime += int(round((time.time() - MakeContiue)))
2052                #
2053                # Check for build error, and raise exception if one
2054                # has been signaled.
2055                #
2056                if BuildTask.HasError():
2057                    self.invalidateHash()
2058                    EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
2059
2060                # Create MAP file when Load Fix Address is enabled.
2061                if self.Target in ["", "all", "fds"]:
2062                    for Arch in Wa.ArchList:
2063                        #
2064                        # Check whether the set fix address is above 4G for 32bit image.
2065                        #
2066                        if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
2067                            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")
2068                    #
2069                    # Get Module List
2070                    #
2071                    ModuleList = {}
2072                    for Pa in Wa.AutoGenObjectList:
2073                        for Ma in Pa.ModuleAutoGenList:
2074                            if Ma is None:
2075                                continue
2076                            if not Ma.IsLibrary:
2077                                ModuleList[Ma.Guid.upper()] = Ma
2078                    #
2079                    # Rebase module to the preferred memory address before GenFds
2080                    #
2081                    MapBuffer = []
2082                    if self.LoadFixAddress != 0:
2083                        self._CollectModuleMapBuffer(MapBuffer, ModuleList)
2084
2085                    if self.Fdf:
2086                        #
2087                        # Generate FD image if there's a FDF file found
2088                        #
2089                        GenFdsStart = time.time()
2090                        if GenFdsApi(Wa.GenFdsCommandDict, self.Db):
2091                            EdkLogger.error("build", COMMAND_FAILURE)
2092
2093                        #
2094                        # Create MAP file for all platform FVs after GenFds.
2095                        #
2096                        self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
2097                        self.GenFdsTime += int(round((time.time() - GenFdsStart)))
2098                    #
2099                    # Save MAP buffer into MAP file.
2100                    #
2101                    self._SaveMapFile(MapBuffer, Wa)
2102
2103    ## Generate GuidedSectionTools.txt in the FV directories.
2104    #
2105    def CreateGuidedSectionToolsFile(self):
2106        for BuildTarget in self.BuildTargetList:
2107            for ToolChain in self.ToolChainList:
2108                Wa = WorkspaceAutoGen(
2109                        self.WorkspaceDir,
2110                        self.PlatformFile,
2111                        BuildTarget,
2112                        ToolChain,
2113                        self.ArchList,
2114                        self.BuildDatabase,
2115                        self.TargetTxt,
2116                        self.ToolDef,
2117                        self.Fdf,
2118                        self.FdList,
2119                        self.FvList,
2120                        self.CapList,
2121                        self.SkuId,
2122                        self.UniFlag
2123                        )
2124                FvDir = Wa.FvDir
2125                if not os.path.exists(FvDir):
2126                    continue
2127
2128                for Arch in self.ArchList:
2129                    # Build up the list of supported architectures for this build
2130                    prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)
2131
2132                    # Look through the tool definitions for GUIDed tools
2133                    guidAttribs = []
2134                    for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.items():
2135                        if attrib.upper().endswith('_GUID'):
2136                            split = attrib.split('_')
2137                            thisPrefix = '_'.join(split[0:3]) + '_'
2138                            if thisPrefix == prefix:
2139                                guid = self.ToolDef.ToolsDefTxtDictionary[attrib]
2140                                guid = guid.lower()
2141                                toolName = split[3]
2142                                path = '_'.join(split[0:4]) + '_PATH'
2143                                path = self.ToolDef.ToolsDefTxtDictionary[path]
2144                                path = self.GetFullPathOfTool(path)
2145                                guidAttribs.append((guid, toolName, path))
2146
2147                    # Write out GuidedSecTools.txt
2148                    toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')
2149                    toolsFile = open(toolsFile, 'wt')
2150                    for guidedSectionTool in guidAttribs:
2151                        print(' '.join(guidedSectionTool), file=toolsFile)
2152                    toolsFile.close()
2153
2154    ## Returns the full path of the tool.
2155    #
2156    def GetFullPathOfTool (self, tool):
2157        if os.path.exists(tool):
2158            return os.path.realpath(tool)
2159        else:
2160            # We need to search for the tool using the
2161            # PATH environment variable.
2162            for dirInPath in os.environ['PATH'].split(os.pathsep):
2163                foundPath = os.path.join(dirInPath, tool)
2164                if os.path.exists(foundPath):
2165                    return os.path.realpath(foundPath)
2166
2167        # If the tool was not found in the path then we just return
2168        # the input tool.
2169        return tool
2170
2171    ## Launch the module or platform build
2172    #
2173    def Launch(self):
2174        if not self.ModuleFile:
2175            if not self.SpawnMode or self.Target not in ["", "all"]:
2176                self.SpawnMode = False
2177                self._BuildPlatform()
2178            else:
2179                self._MultiThreadBuildPlatform()
2180            self.CreateGuidedSectionToolsFile()
2181        else:
2182            self.SpawnMode = False
2183            self._BuildModule()
2184
2185        if self.Target == 'cleanall':
2186            RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)
2187
2188    def CreateAsBuiltInf(self):
2189        all_lib_set = set()
2190        all_mod_set = set()
2191        for Module in self.BuildModules:
2192            Module.CreateAsBuiltInf()
2193            all_mod_set.add(Module)
2194        for Module in self.HashSkipModules:
2195            Module.CreateAsBuiltInf(True)
2196            all_mod_set.add(Module)
2197        for Module in all_mod_set:
2198            for lib in Module.LibraryAutoGenList:
2199                all_lib_set.add(lib)
2200        for lib in all_lib_set:
2201            lib.CreateAsBuiltInf(True)
2202        all_lib_set.clear()
2203        all_mod_set.clear()
2204        self.BuildModules = []
2205        self.HashSkipModules = []
2206    ## Do some clean-up works when error occurred
2207    def Relinquish(self):
2208        OldLogLevel = EdkLogger.GetLevel()
2209        EdkLogger.SetLevel(EdkLogger.ERROR)
2210        Utils.Progressor.Abort()
2211        if self.SpawnMode == True:
2212            BuildTask.Abort()
2213        EdkLogger.SetLevel(OldLogLevel)
2214
2215def ParseDefines(DefineList=[]):
2216    DefineDict = {}
2217    if DefineList is not None:
2218        for Define in DefineList:
2219            DefineTokenList = Define.split("=", 1)
2220            if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):
2221                EdkLogger.error('build', FORMAT_INVALID,
2222                                "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2223                                ExtraData=DefineTokenList[0])
2224
2225            if len(DefineTokenList) == 1:
2226                DefineDict[DefineTokenList[0]] = "TRUE"
2227            else:
2228                DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()
2229    return DefineDict
2230
2231gParamCheck = []
2232def SingleCheckCallback(option, opt_str, value, parser):
2233    if option not in gParamCheck:
2234        setattr(parser.values, option.dest, value)
2235        gParamCheck.append(option)
2236    else:
2237        parser.error("Option %s only allows one instance in command line!" % option)
2238
2239def LogBuildTime(Time):
2240    if Time:
2241        TimeDurStr = ''
2242        TimeDur = time.gmtime(Time)
2243        if TimeDur.tm_yday > 1:
2244            TimeDurStr = time.strftime("%H:%M:%S", TimeDur) + ", %d day(s)" % (TimeDur.tm_yday - 1)
2245        else:
2246            TimeDurStr = time.strftime("%H:%M:%S", TimeDur)
2247        return TimeDurStr
2248    else:
2249        return None
2250
2251## Parse command line options
2252#
2253# Using standard Python module optparse to parse command line option of this tool.
2254#
2255#   @retval Opt   A optparse.Values object containing the parsed options
2256#   @retval Args  Target of build command
2257#
2258def MyOptionParser():
2259    Parser = OptionParser(description=__copyright__, version=__version__, prog="build.exe", usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
2260    Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32', 'X64', 'EBC', 'ARM', 'AARCH64'], dest="TargetArch",
2261        help="ARCHS is one of list: IA32, X64, ARM, AARCH64 or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.")
2262    Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,
2263        help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
2264    Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,
2265        help="Build the module specified by the INF file name argument.")
2266    Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
2267                      action="append")
2268    Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",
2269        help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
2270    Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,
2271        help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
2272
2273    Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,
2274        help="Build the platform using multi-threaded compiler. The value overrides target.txt's MAX_CONCURRENT_THREAD_NUMBER. When value is set to 0, tool automatically detect number of "\
2275             "processor threads, set value to 1 means disable multi-thread build, and set value to more than 1 means user specify the threads number to build.")
2276
2277    Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,
2278        help="The name of the FDF file to use, which overrides the setting in the DSC file.")
2279    Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],
2280        help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
2281    Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],
2282        help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
2283    Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],
2284        help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
2285    Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")
2286    Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")
2287
2288    Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.")
2289
2290    Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")
2291    Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")
2292
2293    Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",
2294        help="Make use of silent mode of (n)make.")
2295    Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
2296    Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
2297                                                                               "including library instances selected, final dependency expression, "\
2298                                                                               "and warning messages, etc.")
2299    Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
2300    Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
2301
2302    Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")
2303    Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD', 'LIBRARY', 'FLASH', 'DEPEX', 'BUILD_FLAGS', 'FIXED_ADDRESS', 'HASH', 'EXECUTION_ORDER'], dest="ReportType", default=[],
2304        help="Flags that control the type of build report to generate.  Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, HASH, EXECUTION_ORDER].  "\
2305             "To specify more than one flag, repeat this option on the command line and the default flag set is [PCD, LIBRARY, FLASH, DEPEX, HASH, BUILD_FLAGS, FIXED_ADDRESS]")
2306    Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",
2307        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. "\
2308             "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
2309             "will override the setting in [BuildOptions] section of platform DSC.")
2310    Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism")
2311    Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")
2312    Parser.add_option("--check-usage", action="store_true", dest="CheckUsage", default=False, help="Check usage content of entries listed in INF file.")
2313    Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")
2314    Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
2315    Parser.add_option("-l", "--cmd-len", action="store", type="int", dest="CommandLength", help="Specify the maximum line length of build command. Default is 4096.")
2316    Parser.add_option("--hash", action="store_true", dest="UseHashCache", default=False, help="Enable hash-based caching during build process.")
2317    Parser.add_option("--binary-destination", action="store", type="string", dest="BinCacheDest", help="Generate a cache of binary files in the specified directory.")
2318    Parser.add_option("--binary-source", action="store", type="string", dest="BinCacheSource", help="Consume a cache of binary files from the specified directory.")
2319    Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=False, help="Enable GenFds multi thread to generate ffs file.")
2320    Parser.add_option("--disable-include-path-check", action="store_true", dest="DisableIncludePathCheck", default=False, help="Disable the include path check for outside of package.")
2321    (Opt, Args) = Parser.parse_args()
2322    return (Opt, Args)
2323
2324## Tool entrance method
2325#
2326# This method mainly dispatch specific methods per the command line options.
2327# If no error found, return zero value so the caller of this tool can know
2328# if it's executed successfully or not.
2329#
2330#   @retval 0     Tool was successful
2331#   @retval 1     Tool failed
2332#
2333def Main():
2334    StartTime = time.time()
2335
2336    # Initialize log system
2337    EdkLogger.Initialize()
2338    GlobalData.gCommand = sys.argv[1:]
2339    #
2340    # Parse the options and args
2341    #
2342    (Option, Target) = MyOptionParser()
2343    GlobalData.gOptions = Option
2344    GlobalData.gCaseInsensitive = Option.CaseInsensitive
2345
2346    # Set log level
2347    if Option.verbose is not None:
2348        EdkLogger.SetLevel(EdkLogger.VERBOSE)
2349    elif Option.quiet is not None:
2350        EdkLogger.SetLevel(EdkLogger.QUIET)
2351    elif Option.debug is not None:
2352        EdkLogger.SetLevel(Option.debug + 1)
2353    else:
2354        EdkLogger.SetLevel(EdkLogger.INFO)
2355
2356    if Option.LogFile is not None:
2357        EdkLogger.SetLogFile(Option.LogFile)
2358
2359    if Option.WarningAsError == True:
2360        EdkLogger.SetWarningAsError()
2361
2362    if platform.platform().find("Windows") >= 0:
2363        GlobalData.gIsWindows = True
2364    else:
2365        GlobalData.gIsWindows = False
2366
2367    EdkLogger.quiet("Build environment: %s" % platform.platform())
2368    EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));
2369    ReturnCode = 0
2370    MyBuild = None
2371    BuildError = True
2372    try:
2373        if len(Target) == 0:
2374            Target = "all"
2375        elif len(Target) >= 2:
2376            EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",
2377                            ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))
2378        else:
2379            Target = Target[0].lower()
2380
2381        if Target not in gSupportedTarget:
2382            EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,
2383                            ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))
2384
2385        #
2386        # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2387        #
2388        CheckEnvVariable()
2389        GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))
2390
2391        Workspace = os.getenv("WORKSPACE")
2392        #
2393        # Get files real name in workspace dir
2394        #
2395        GlobalData.gAllFiles = Utils.DirCache(Workspace)
2396
2397        WorkingDirectory = os.getcwd()
2398        if not Option.ModuleFile:
2399            FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))
2400            FileNum = len(FileList)
2401            if FileNum >= 2:
2402                EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),
2403                                ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2404            elif FileNum == 1:
2405                Option.ModuleFile = NormFile(FileList[0], Workspace)
2406
2407        if Option.ModuleFile:
2408            if os.path.isabs (Option.ModuleFile):
2409                if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:
2410                    Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)
2411            Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)
2412            ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)
2413            if ErrorCode != 0:
2414                EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
2415
2416        if Option.PlatformFile is not None:
2417            if os.path.isabs (Option.PlatformFile):
2418                if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:
2419                    Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)
2420            Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)
2421
2422        if Option.FdfFile is not None:
2423            if os.path.isabs (Option.FdfFile):
2424                if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:
2425                    Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)
2426            Option.FdfFile = PathClass(Option.FdfFile, Workspace)
2427            ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)
2428            if ErrorCode != 0:
2429                EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
2430
2431        if Option.Flag is not None and Option.Flag not in ['-c', '-s']:
2432            EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")
2433
2434        MyBuild = Build(Target, Workspace, Option)
2435        GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)
2436        if not (MyBuild.LaunchPrebuildFlag and os.path.exists(MyBuild.PlatformBuildPath)):
2437            MyBuild.Launch()
2438
2439        #
2440        # All job done, no error found and no exception raised
2441        #
2442        BuildError = False
2443    except FatalError as X:
2444        if MyBuild is not None:
2445            # for multi-thread build exits safely
2446            MyBuild.Relinquish()
2447        if Option is not None and Option.debug is not None:
2448            EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2449        ReturnCode = X.args[0]
2450    except Warning as X:
2451        # error from Fdf parser
2452        if MyBuild is not None:
2453            # for multi-thread build exits safely
2454            MyBuild.Relinquish()
2455        if Option is not None and Option.debug is not None:
2456            EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2457        else:
2458            EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)
2459        ReturnCode = FORMAT_INVALID
2460    except KeyboardInterrupt:
2461        ReturnCode = ABORT_ERROR
2462        if Option is not None and Option.debug is not None:
2463            EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2464    except:
2465        if MyBuild is not None:
2466            # for multi-thread build exits safely
2467            MyBuild.Relinquish()
2468
2469        # try to get the meta-file from the object causing exception
2470        Tb = sys.exc_info()[-1]
2471        MetaFile = GlobalData.gProcessingFile
2472        while Tb is not None:
2473            if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):
2474                MetaFile = Tb.tb_frame.f_locals['self'].MetaFile
2475            Tb = Tb.tb_next
2476        EdkLogger.error(
2477                    "\nbuild",
2478                    CODE_ERROR,
2479                    "Unknown fatal error when processing [%s]" % MetaFile,
2480                    ExtraData="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR,
2481                    RaiseError=False
2482                    )
2483        EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2484        ReturnCode = CODE_ERROR
2485    finally:
2486        Utils.Progressor.Abort()
2487        Utils.ClearDuplicatedInf()
2488
2489    if ReturnCode == 0:
2490        try:
2491            MyBuild.LaunchPostbuild()
2492            Conclusion = "Done"
2493        except:
2494            Conclusion = "Failed"
2495    elif ReturnCode == ABORT_ERROR:
2496        Conclusion = "Aborted"
2497    else:
2498        Conclusion = "Failed"
2499    FinishTime = time.time()
2500    BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))
2501    BuildDurationStr = ""
2502    if BuildDuration.tm_yday > 1:
2503        BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)" % (BuildDuration.tm_yday - 1)
2504    else:
2505        BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)
2506    if MyBuild is not None:
2507        if not BuildError:
2508            MyBuild.BuildReport.GenerateReport(BuildDurationStr, LogBuildTime(MyBuild.AutoGenTime), LogBuildTime(MyBuild.MakeTime), LogBuildTime(MyBuild.GenFdsTime))
2509
2510    EdkLogger.SetLevel(EdkLogger.QUIET)
2511    EdkLogger.quiet("\n- %s -" % Conclusion)
2512    EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))
2513    EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)
2514    return ReturnCode
2515
2516if __name__ == '__main__':
2517    r = Main()
2518    ## 0-127 is a safe return range, and 1 is a standard default error
2519    if r < 0 or r > 127: r = 1
2520    sys.exit(r)
2521
2522