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