BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=2188 build -p MdeModulePkg\MdeModulePkg.dsc -a IA32 -m MdeModulePkg\Universal\PCD\Pei\Pcd.inf Error: AttributeError: 'PlatformInfo' object has no attribute 'DynamicPcdList' The DSC data object used to build a separate module today is PlatformInfo rather than PlatformAutoGen 'PlatformAutoGen' object has attribute 'DynamicPcdList' This patch is going to fixed this issue Cc: Liming Gao <liming.gao@intel.com> Cc: Bob Feng <bob.c.feng@intel.com> Signed-off-by: Zhiju.Fan <zhijux.fan@intel.com> Reviewed-by: Bob Feng <bob.c.feng@intel.com>
		
			
				
	
	
		
			2677 lines
		
	
	
		
			124 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			2677 lines
		
	
	
		
			124 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
## @file
 | 
						|
# build a platform or a module
 | 
						|
#
 | 
						|
#  Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
 | 
						|
#  Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
 | 
						|
#  Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
 | 
						|
#
 | 
						|
#  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
#
 | 
						|
 | 
						|
##
 | 
						|
# Import Modules
 | 
						|
#
 | 
						|
from __future__ import print_function
 | 
						|
from __future__ import absolute_import
 | 
						|
import os.path as path
 | 
						|
import sys
 | 
						|
import os
 | 
						|
import re
 | 
						|
import glob
 | 
						|
import time
 | 
						|
import platform
 | 
						|
import traceback
 | 
						|
import multiprocessing
 | 
						|
from threading import Thread,Event,BoundedSemaphore
 | 
						|
import threading
 | 
						|
from subprocess import Popen,PIPE
 | 
						|
from collections import OrderedDict, defaultdict
 | 
						|
from Common.buildoptions import BuildOption,BuildTarget
 | 
						|
from AutoGen.PlatformAutoGen import PlatformAutoGen
 | 
						|
from AutoGen.ModuleAutoGen import ModuleAutoGen
 | 
						|
from AutoGen.WorkspaceAutoGen import WorkspaceAutoGen
 | 
						|
from AutoGen.AutoGenWorker import AutoGenWorkerInProcess,AutoGenManager,\
 | 
						|
    LogAgent
 | 
						|
from AutoGen import GenMake
 | 
						|
from Common import Misc as Utils
 | 
						|
 | 
						|
from Common.TargetTxtClassObject import TargetTxt
 | 
						|
from Common.ToolDefClassObject import ToolDef
 | 
						|
from Common.Misc import PathClass,SaveFileOnChange,RemoveDirectory
 | 
						|
from Common.StringUtils import NormPath
 | 
						|
from Common.MultipleWorkspace import MultipleWorkspace as mws
 | 
						|
from Common.BuildToolError import *
 | 
						|
from Common.DataType import *
 | 
						|
import Common.EdkLogger as EdkLogger
 | 
						|
 | 
						|
from Workspace.WorkspaceDatabase import BuildDB
 | 
						|
 | 
						|
from BuildReport import BuildReport
 | 
						|
from GenPatchPcdTable.GenPatchPcdTable import PeImageClass,parsePcdInfoFromMapFile
 | 
						|
from PatchPcdValue.PatchPcdValue import PatchBinaryFile
 | 
						|
 | 
						|
import Common.GlobalData as GlobalData
 | 
						|
from GenFds.GenFds import GenFds, GenFdsApi
 | 
						|
import multiprocessing as mp
 | 
						|
from multiprocessing import Manager
 | 
						|
from AutoGen.DataPipe import MemoryDataPipe
 | 
						|
from AutoGen.ModuleAutoGenHelper import WorkSpaceInfo, PlatformInfo
 | 
						|
from GenFds.FdfParser import FdfParser
 | 
						|
 | 
						|
 | 
						|
## standard targets of build command
 | 
						|
gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
 | 
						|
 | 
						|
## build configuration file
 | 
						|
gBuildConfiguration = "target.txt"
 | 
						|
gToolsDefinition = "tools_def.txt"
 | 
						|
 | 
						|
TemporaryTablePattern = re.compile(r'^_\d+_\d+_[a-fA-F0-9]+$')
 | 
						|
TmpTableDict = {}
 | 
						|
 | 
						|
## Check environment PATH variable to make sure the specified tool is found
 | 
						|
#
 | 
						|
#   If the tool is found in the PATH, then True is returned
 | 
						|
#   Otherwise, False is returned
 | 
						|
#
 | 
						|
def IsToolInPath(tool):
 | 
						|
    if 'PATHEXT' in os.environ:
 | 
						|
        extns = os.environ['PATHEXT'].split(os.path.pathsep)
 | 
						|
    else:
 | 
						|
        extns = ('',)
 | 
						|
    for pathDir in os.environ['PATH'].split(os.path.pathsep):
 | 
						|
        for ext in extns:
 | 
						|
            if os.path.exists(os.path.join(pathDir, tool + ext)):
 | 
						|
                return True
 | 
						|
    return False
 | 
						|
 | 
						|
## Check environment variables
 | 
						|
#
 | 
						|
#  Check environment variables that must be set for build. Currently they are
 | 
						|
#
 | 
						|
#   WORKSPACE           The directory all packages/platforms start from
 | 
						|
#   EDK_TOOLS_PATH      The directory contains all tools needed by the build
 | 
						|
#   PATH                $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
 | 
						|
#
 | 
						|
#   If any of above environment variable is not set or has error, the build
 | 
						|
#   will be broken.
 | 
						|
#
 | 
						|
def CheckEnvVariable():
 | 
						|
    # check WORKSPACE
 | 
						|
    if "WORKSPACE" not in os.environ:
 | 
						|
        EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
 | 
						|
                        ExtraData="WORKSPACE")
 | 
						|
 | 
						|
    WorkspaceDir = os.path.normcase(os.path.normpath(os.environ["WORKSPACE"]))
 | 
						|
    if not os.path.exists(WorkspaceDir):
 | 
						|
        EdkLogger.error("build", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData=WorkspaceDir)
 | 
						|
    elif ' ' in WorkspaceDir:
 | 
						|
        EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path",
 | 
						|
                        ExtraData=WorkspaceDir)
 | 
						|
    os.environ["WORKSPACE"] = WorkspaceDir
 | 
						|
 | 
						|
    # set multiple workspace
 | 
						|
    PackagesPath = os.getenv("PACKAGES_PATH")
 | 
						|
    mws.setWs(WorkspaceDir, PackagesPath)
 | 
						|
    if mws.PACKAGES_PATH:
 | 
						|
        for Path in mws.PACKAGES_PATH:
 | 
						|
            if not os.path.exists(Path):
 | 
						|
                EdkLogger.error("build", FILE_NOT_FOUND, "One Path in PACKAGES_PATH doesn't exist", ExtraData=Path)
 | 
						|
            elif ' ' in Path:
 | 
						|
                EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in PACKAGES_PATH", ExtraData=Path)
 | 
						|
 | 
						|
 | 
						|
    os.environ["EDK_TOOLS_PATH"] = os.path.normcase(os.environ["EDK_TOOLS_PATH"])
 | 
						|
 | 
						|
    # check EDK_TOOLS_PATH
 | 
						|
    if "EDK_TOOLS_PATH" not in os.environ:
 | 
						|
        EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
 | 
						|
                        ExtraData="EDK_TOOLS_PATH")
 | 
						|
 | 
						|
    # check PATH
 | 
						|
    if "PATH" not in os.environ:
 | 
						|
        EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
 | 
						|
                        ExtraData="PATH")
 | 
						|
 | 
						|
    GlobalData.gWorkspace = WorkspaceDir
 | 
						|
 | 
						|
    GlobalData.gGlobalDefines["WORKSPACE"]  = WorkspaceDir
 | 
						|
    GlobalData.gGlobalDefines["EDK_TOOLS_PATH"] = os.environ["EDK_TOOLS_PATH"]
 | 
						|
 | 
						|
## Get normalized file path
 | 
						|
#
 | 
						|
# Convert the path to be local format, and remove the WORKSPACE path at the
 | 
						|
# beginning if the file path is given in full path.
 | 
						|
#
 | 
						|
# @param  FilePath      File path to be normalized
 | 
						|
# @param  Workspace     Workspace path which the FilePath will be checked against
 | 
						|
#
 | 
						|
# @retval string        The normalized file path
 | 
						|
#
 | 
						|
def NormFile(FilePath, Workspace):
 | 
						|
    # check if the path is absolute or relative
 | 
						|
    if os.path.isabs(FilePath):
 | 
						|
        FileFullPath = os.path.normpath(FilePath)
 | 
						|
    else:
 | 
						|
        FileFullPath = os.path.normpath(mws.join(Workspace, FilePath))
 | 
						|
        Workspace = mws.getWs(Workspace, FilePath)
 | 
						|
 | 
						|
    # check if the file path exists or not
 | 
						|
    if not os.path.isfile(FileFullPath):
 | 
						|
        EdkLogger.error("build", FILE_NOT_FOUND, ExtraData="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath)
 | 
						|
 | 
						|
    # remove workspace directory from the beginning part of the file path
 | 
						|
    if Workspace[-1] in ["\\", "/"]:
 | 
						|
        return FileFullPath[len(Workspace):]
 | 
						|
    else:
 | 
						|
        return FileFullPath[(len(Workspace) + 1):]
 | 
						|
 | 
						|
## Get the output of an external program
 | 
						|
#
 | 
						|
# This is the entrance method of thread reading output of an external program and
 | 
						|
# putting them in STDOUT/STDERR of current program.
 | 
						|
#
 | 
						|
# @param  From      The stream message read from
 | 
						|
# @param  To        The stream message put on
 | 
						|
# @param  ExitFlag  The flag used to indicate stopping reading
 | 
						|
#
 | 
						|
def ReadMessage(From, To, ExitFlag):
 | 
						|
    while True:
 | 
						|
        # read one line a time
 | 
						|
        Line = From.readline()
 | 
						|
        # empty string means "end"
 | 
						|
        if Line is not None and Line != b"":
 | 
						|
            To(Line.rstrip().decode(encoding='utf-8', errors='ignore'))
 | 
						|
        else:
 | 
						|
            break
 | 
						|
        if ExitFlag.isSet():
 | 
						|
            break
 | 
						|
 | 
						|
## Launch an external program
 | 
						|
#
 | 
						|
# This method will call subprocess.Popen to execute an external program with
 | 
						|
# given options in specified directory. Because of the dead-lock issue during
 | 
						|
# redirecting output of the external program, threads are used to to do the
 | 
						|
# redirection work.
 | 
						|
#
 | 
						|
# @param  Command               A list or string containing the call of the program
 | 
						|
# @param  WorkingDir            The directory in which the program will be running
 | 
						|
#
 | 
						|
def LaunchCommand(Command, WorkingDir):
 | 
						|
    BeginTime = time.time()
 | 
						|
    # if working directory doesn't exist, Popen() will raise an exception
 | 
						|
    if not os.path.isdir(WorkingDir):
 | 
						|
        EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=WorkingDir)
 | 
						|
 | 
						|
    # Command is used as the first Argument in following Popen().
 | 
						|
    # It could be a string or sequence. We find that if command is a string in following Popen(),
 | 
						|
    # ubuntu may fail with an error message that the command is not found.
 | 
						|
    # So here we may need convert command from string to list instance.
 | 
						|
    if platform.system() != 'Windows':
 | 
						|
        if not isinstance(Command, list):
 | 
						|
            Command = Command.split()
 | 
						|
        Command = ' '.join(Command)
 | 
						|
 | 
						|
    Proc = None
 | 
						|
    EndOfProcedure = None
 | 
						|
    try:
 | 
						|
        # launch the command
 | 
						|
        Proc = Popen(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir, bufsize=-1, shell=True)
 | 
						|
 | 
						|
        # launch two threads to read the STDOUT and STDERR
 | 
						|
        EndOfProcedure = Event()
 | 
						|
        EndOfProcedure.clear()
 | 
						|
        if Proc.stdout:
 | 
						|
            StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure))
 | 
						|
            StdOutThread.setName("STDOUT-Redirector")
 | 
						|
            StdOutThread.setDaemon(False)
 | 
						|
            StdOutThread.start()
 | 
						|
 | 
						|
        if Proc.stderr:
 | 
						|
            StdErrThread = Thread(target=ReadMessage, args=(Proc.stderr, EdkLogger.quiet, EndOfProcedure))
 | 
						|
            StdErrThread.setName("STDERR-Redirector")
 | 
						|
            StdErrThread.setDaemon(False)
 | 
						|
            StdErrThread.start()
 | 
						|
 | 
						|
        # waiting for program exit
 | 
						|
        Proc.wait()
 | 
						|
    except: # in case of aborting
 | 
						|
        # terminate the threads redirecting the program output
 | 
						|
        EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
 | 
						|
        if EndOfProcedure is not None:
 | 
						|
            EndOfProcedure.set()
 | 
						|
        if Proc is None:
 | 
						|
            if not isinstance(Command, type("")):
 | 
						|
                Command = " ".join(Command)
 | 
						|
            EdkLogger.error("build", COMMAND_FAILURE, "Failed to start command", ExtraData="%s [%s]" % (Command, WorkingDir))
 | 
						|
 | 
						|
    if Proc.stdout:
 | 
						|
        StdOutThread.join()
 | 
						|
    if Proc.stderr:
 | 
						|
        StdErrThread.join()
 | 
						|
 | 
						|
    # check the return code of the program
 | 
						|
    if Proc.returncode != 0:
 | 
						|
        if not isinstance(Command, type("")):
 | 
						|
            Command = " ".join(Command)
 | 
						|
        # print out the Response file and its content when make failure
 | 
						|
        RespFile = os.path.join(WorkingDir, 'OUTPUT', 'respfilelist.txt')
 | 
						|
        if os.path.isfile(RespFile):
 | 
						|
            f = open(RespFile)
 | 
						|
            RespContent = f.read()
 | 
						|
            f.close()
 | 
						|
            EdkLogger.info(RespContent)
 | 
						|
 | 
						|
        EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir))
 | 
						|
    return "%dms" % (int(round((time.time() - BeginTime) * 1000)))
 | 
						|
 | 
						|
## The smallest unit that can be built in multi-thread build mode
 | 
						|
#
 | 
						|
# This is the base class of build unit. The "Obj" parameter must provide
 | 
						|
# __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
 | 
						|
# missing build.
 | 
						|
#
 | 
						|
# Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
 | 
						|
#
 | 
						|
class BuildUnit:
 | 
						|
    ## The constructor
 | 
						|
    #
 | 
						|
    #   @param  self        The object pointer
 | 
						|
    #   @param  Obj         The object the build is working on
 | 
						|
    #   @param  Target      The build target name, one of gSupportedTarget
 | 
						|
    #   @param  Dependency  The BuildUnit(s) which must be completed in advance
 | 
						|
    #   @param  WorkingDir  The directory build command starts in
 | 
						|
    #
 | 
						|
    def __init__(self, Obj, BuildCommand, Target, Dependency, WorkingDir="."):
 | 
						|
        self.BuildObject = Obj
 | 
						|
        self.Dependency = Dependency
 | 
						|
        self.WorkingDir = WorkingDir
 | 
						|
        self.Target = Target
 | 
						|
        self.BuildCommand = BuildCommand
 | 
						|
        if not BuildCommand:
 | 
						|
            EdkLogger.error("build", OPTION_MISSING,
 | 
						|
                            "No build command found for this module. "
 | 
						|
                            "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
 | 
						|
                                (Obj.BuildTarget, Obj.ToolChain, Obj.Arch),
 | 
						|
                            ExtraData=str(Obj))
 | 
						|
 | 
						|
 | 
						|
    ## str() method
 | 
						|
    #
 | 
						|
    #   It just returns the string representation of self.BuildObject
 | 
						|
    #
 | 
						|
    #   @param  self        The object pointer
 | 
						|
    #
 | 
						|
    def __str__(self):
 | 
						|
        return str(self.BuildObject)
 | 
						|
 | 
						|
    ## "==" operator method
 | 
						|
    #
 | 
						|
    #   It just compares self.BuildObject with "Other". So self.BuildObject must
 | 
						|
    #   provide its own __eq__() method.
 | 
						|
    #
 | 
						|
    #   @param  self        The object pointer
 | 
						|
    #   @param  Other       The other BuildUnit object compared to
 | 
						|
    #
 | 
						|
    def __eq__(self, Other):
 | 
						|
        return Other and self.BuildObject == Other.BuildObject \
 | 
						|
                and Other.BuildObject \
 | 
						|
                and self.BuildObject.Arch == Other.BuildObject.Arch
 | 
						|
 | 
						|
    ## hash() method
 | 
						|
    #
 | 
						|
    #   It just returns the hash value of self.BuildObject which must be hashable.
 | 
						|
    #
 | 
						|
    #   @param  self        The object pointer
 | 
						|
    #
 | 
						|
    def __hash__(self):
 | 
						|
        return hash(self.BuildObject) + hash(self.BuildObject.Arch)
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return repr(self.BuildObject)
 | 
						|
 | 
						|
## The smallest module unit that can be built by nmake/make command in multi-thread build mode
 | 
						|
#
 | 
						|
# This class is for module build by nmake/make build system. The "Obj" parameter
 | 
						|
# must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
 | 
						|
# be make units missing build.
 | 
						|
#
 | 
						|
# Currently the "Obj" should be only ModuleAutoGen object.
 | 
						|
#
 | 
						|
class ModuleMakeUnit(BuildUnit):
 | 
						|
    ## The constructor
 | 
						|
    #
 | 
						|
    #   @param  self        The object pointer
 | 
						|
    #   @param  Obj         The ModuleAutoGen object the build is working on
 | 
						|
    #   @param  Target      The build target name, one of gSupportedTarget
 | 
						|
    #
 | 
						|
    def __init__(self, Obj, BuildCommand,Target):
 | 
						|
        Dependency = [ModuleMakeUnit(La, BuildCommand,Target) for La in Obj.LibraryAutoGenList]
 | 
						|
        BuildUnit.__init__(self, Obj, BuildCommand, Target, Dependency, Obj.MakeFileDir)
 | 
						|
        if Target in [None, "", "all"]:
 | 
						|
            self.Target = "tbuild"
 | 
						|
 | 
						|
## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
 | 
						|
#
 | 
						|
# This class is for platform build by nmake/make build system. The "Obj" parameter
 | 
						|
# must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
 | 
						|
# be make units missing build.
 | 
						|
#
 | 
						|
# Currently the "Obj" should be only PlatformAutoGen object.
 | 
						|
#
 | 
						|
class PlatformMakeUnit(BuildUnit):
 | 
						|
    ## The constructor
 | 
						|
    #
 | 
						|
    #   @param  self        The object pointer
 | 
						|
    #   @param  Obj         The PlatformAutoGen object the build is working on
 | 
						|
    #   @param  Target      The build target name, one of gSupportedTarget
 | 
						|
    #
 | 
						|
    def __init__(self, Obj, BuildCommand, Target):
 | 
						|
        Dependency = [ModuleMakeUnit(Lib, BuildCommand, Target) for Lib in self.BuildObject.LibraryAutoGenList]
 | 
						|
        Dependency.extend([ModuleMakeUnit(Mod, BuildCommand,Target) for Mod in self.BuildObject.ModuleAutoGenList])
 | 
						|
        BuildUnit.__init__(self, Obj, BuildCommand, Target, Dependency, Obj.MakeFileDir)
 | 
						|
 | 
						|
## The class representing the task of a module build or platform build
 | 
						|
#
 | 
						|
# This class manages the build tasks in multi-thread build mode. Its jobs include
 | 
						|
# scheduling thread running, catching thread error, monitor the thread status, etc.
 | 
						|
#
 | 
						|
class BuildTask:
 | 
						|
    # queue for tasks waiting for schedule
 | 
						|
    _PendingQueue = OrderedDict()
 | 
						|
    _PendingQueueLock = threading.Lock()
 | 
						|
 | 
						|
    # queue for tasks ready for running
 | 
						|
    _ReadyQueue = OrderedDict()
 | 
						|
    _ReadyQueueLock = threading.Lock()
 | 
						|
 | 
						|
    # queue for run tasks
 | 
						|
    _RunningQueue = OrderedDict()
 | 
						|
    _RunningQueueLock = threading.Lock()
 | 
						|
 | 
						|
    # queue containing all build tasks, in case duplicate build
 | 
						|
    _TaskQueue = OrderedDict()
 | 
						|
 | 
						|
    # flag indicating error occurs in a running thread
 | 
						|
    _ErrorFlag = threading.Event()
 | 
						|
    _ErrorFlag.clear()
 | 
						|
    _ErrorMessage = ""
 | 
						|
 | 
						|
    # BoundedSemaphore object used to control the number of running threads
 | 
						|
    _Thread = None
 | 
						|
 | 
						|
    # flag indicating if the scheduler is started or not
 | 
						|
    _SchedulerStopped = threading.Event()
 | 
						|
    _SchedulerStopped.set()
 | 
						|
 | 
						|
    ## Start the task scheduler thread
 | 
						|
    #
 | 
						|
    #   @param  MaxThreadNumber     The maximum thread number
 | 
						|
    #   @param  ExitFlag            Flag used to end the scheduler
 | 
						|
    #
 | 
						|
    @staticmethod
 | 
						|
    def StartScheduler(MaxThreadNumber, ExitFlag):
 | 
						|
        SchedulerThread = Thread(target=BuildTask.Scheduler, args=(MaxThreadNumber, ExitFlag))
 | 
						|
        SchedulerThread.setName("Build-Task-Scheduler")
 | 
						|
        SchedulerThread.setDaemon(False)
 | 
						|
        SchedulerThread.start()
 | 
						|
        # wait for the scheduler to be started, especially useful in Linux
 | 
						|
        while not BuildTask.IsOnGoing():
 | 
						|
            time.sleep(0.01)
 | 
						|
 | 
						|
    ## Scheduler method
 | 
						|
    #
 | 
						|
    #   @param  MaxThreadNumber     The maximum thread number
 | 
						|
    #   @param  ExitFlag            Flag used to end the scheduler
 | 
						|
    #
 | 
						|
    @staticmethod
 | 
						|
    def Scheduler(MaxThreadNumber, ExitFlag):
 | 
						|
        BuildTask._SchedulerStopped.clear()
 | 
						|
        try:
 | 
						|
            # use BoundedSemaphore to control the maximum running threads
 | 
						|
            BuildTask._Thread = BoundedSemaphore(MaxThreadNumber)
 | 
						|
            #
 | 
						|
            # scheduling loop, which will exits when no pending/ready task and
 | 
						|
            # indicated to do so, or there's error in running thread
 | 
						|
            #
 | 
						|
            while (len(BuildTask._PendingQueue) > 0 or len(BuildTask._ReadyQueue) > 0 \
 | 
						|
                   or not ExitFlag.isSet()) and not BuildTask._ErrorFlag.isSet():
 | 
						|
                EdkLogger.debug(EdkLogger.DEBUG_8, "Pending Queue (%d), Ready Queue (%d)"
 | 
						|
                                % (len(BuildTask._PendingQueue), len(BuildTask._ReadyQueue)))
 | 
						|
 | 
						|
                # get all pending tasks
 | 
						|
                BuildTask._PendingQueueLock.acquire()
 | 
						|
                BuildObjectList = list(BuildTask._PendingQueue.keys())
 | 
						|
                #
 | 
						|
                # check if their dependency is resolved, and if true, move them
 | 
						|
                # into ready queue
 | 
						|
                #
 | 
						|
                for BuildObject in BuildObjectList:
 | 
						|
                    Bt = BuildTask._PendingQueue[BuildObject]
 | 
						|
                    if Bt.IsReady():
 | 
						|
                        BuildTask._ReadyQueue[BuildObject] = BuildTask._PendingQueue.pop(BuildObject)
 | 
						|
                BuildTask._PendingQueueLock.release()
 | 
						|
 | 
						|
                # launch build thread until the maximum number of threads is reached
 | 
						|
                while not BuildTask._ErrorFlag.isSet():
 | 
						|
                    # empty ready queue, do nothing further
 | 
						|
                    if len(BuildTask._ReadyQueue) == 0:
 | 
						|
                        break
 | 
						|
 | 
						|
                    # wait for active thread(s) exit
 | 
						|
                    BuildTask._Thread.acquire(True)
 | 
						|
 | 
						|
                    # start a new build thread
 | 
						|
                    Bo, Bt = BuildTask._ReadyQueue.popitem()
 | 
						|
 | 
						|
                    # move into running queue
 | 
						|
                    BuildTask._RunningQueueLock.acquire()
 | 
						|
                    BuildTask._RunningQueue[Bo] = Bt
 | 
						|
                    BuildTask._RunningQueueLock.release()
 | 
						|
 | 
						|
                    Bt.Start()
 | 
						|
                    # avoid tense loop
 | 
						|
                    time.sleep(0.01)
 | 
						|
 | 
						|
                # avoid tense loop
 | 
						|
                time.sleep(0.01)
 | 
						|
 | 
						|
            # wait for all running threads exit
 | 
						|
            if BuildTask._ErrorFlag.isSet():
 | 
						|
                EdkLogger.quiet("\nWaiting for all build threads exit...")
 | 
						|
            # while not BuildTask._ErrorFlag.isSet() and \
 | 
						|
            while len(BuildTask._RunningQueue) > 0:
 | 
						|
                EdkLogger.verbose("Waiting for thread ending...(%d)" % len(BuildTask._RunningQueue))
 | 
						|
                EdkLogger.debug(EdkLogger.DEBUG_8, "Threads [%s]" % ", ".join(Th.getName() for Th in threading.enumerate()))
 | 
						|
                # avoid tense loop
 | 
						|
                time.sleep(0.1)
 | 
						|
        except BaseException as X:
 | 
						|
            #
 | 
						|
            # TRICK: hide the output of threads left running, so that the user can
 | 
						|
            #        catch the error message easily
 | 
						|
            #
 | 
						|
            EdkLogger.SetLevel(EdkLogger.ERROR)
 | 
						|
            BuildTask._ErrorFlag.set()
 | 
						|
            BuildTask._ErrorMessage = "build thread scheduler error\n\t%s" % str(X)
 | 
						|
 | 
						|
        BuildTask._PendingQueue.clear()
 | 
						|
        BuildTask._ReadyQueue.clear()
 | 
						|
        BuildTask._RunningQueue.clear()
 | 
						|
        BuildTask._TaskQueue.clear()
 | 
						|
        BuildTask._SchedulerStopped.set()
 | 
						|
 | 
						|
    ## Wait for all running method exit
 | 
						|
    #
 | 
						|
    @staticmethod
 | 
						|
    def WaitForComplete():
 | 
						|
        BuildTask._SchedulerStopped.wait()
 | 
						|
 | 
						|
    ## Check if the scheduler is running or not
 | 
						|
    #
 | 
						|
    @staticmethod
 | 
						|
    def IsOnGoing():
 | 
						|
        return not BuildTask._SchedulerStopped.isSet()
 | 
						|
 | 
						|
    ## Abort the build
 | 
						|
    @staticmethod
 | 
						|
    def Abort():
 | 
						|
        if BuildTask.IsOnGoing():
 | 
						|
            BuildTask._ErrorFlag.set()
 | 
						|
            BuildTask.WaitForComplete()
 | 
						|
 | 
						|
    ## Check if there's error in running thread
 | 
						|
    #
 | 
						|
    #   Since the main thread cannot catch exceptions in other thread, we have to
 | 
						|
    #   use threading.Event to communicate this formation to main thread.
 | 
						|
    #
 | 
						|
    @staticmethod
 | 
						|
    def HasError():
 | 
						|
        return BuildTask._ErrorFlag.isSet()
 | 
						|
 | 
						|
    ## Get error message in running thread
 | 
						|
    #
 | 
						|
    #   Since the main thread cannot catch exceptions in other thread, we have to
 | 
						|
    #   use a static variable to communicate this message to main thread.
 | 
						|
    #
 | 
						|
    @staticmethod
 | 
						|
    def GetErrorMessage():
 | 
						|
        return BuildTask._ErrorMessage
 | 
						|
 | 
						|
    ## Factory method to create a BuildTask object
 | 
						|
    #
 | 
						|
    #   This method will check if a module is building or has been built. And if
 | 
						|
    #   true, just return the associated BuildTask object in the _TaskQueue. If
 | 
						|
    #   not, create and return a new BuildTask object. The new BuildTask object
 | 
						|
    #   will be appended to the _PendingQueue for scheduling later.
 | 
						|
    #
 | 
						|
    #   @param  BuildItem       A BuildUnit object representing a build object
 | 
						|
    #   @param  Dependency      The dependent build object of BuildItem
 | 
						|
    #
 | 
						|
    @staticmethod
 | 
						|
    def New(BuildItem, Dependency=None):
 | 
						|
        if BuildItem in BuildTask._TaskQueue:
 | 
						|
            Bt = BuildTask._TaskQueue[BuildItem]
 | 
						|
            return Bt
 | 
						|
 | 
						|
        Bt = BuildTask()
 | 
						|
        Bt._Init(BuildItem, Dependency)
 | 
						|
        BuildTask._TaskQueue[BuildItem] = Bt
 | 
						|
 | 
						|
        BuildTask._PendingQueueLock.acquire()
 | 
						|
        BuildTask._PendingQueue[BuildItem] = Bt
 | 
						|
        BuildTask._PendingQueueLock.release()
 | 
						|
 | 
						|
        return Bt
 | 
						|
 | 
						|
    ## The real constructor of BuildTask
 | 
						|
    #
 | 
						|
    #   @param  BuildItem       A BuildUnit object representing a build object
 | 
						|
    #   @param  Dependency      The dependent build object of BuildItem
 | 
						|
    #
 | 
						|
    def _Init(self, BuildItem, Dependency=None):
 | 
						|
        self.BuildItem = BuildItem
 | 
						|
 | 
						|
        self.DependencyList = []
 | 
						|
        if Dependency is None:
 | 
						|
            Dependency = BuildItem.Dependency
 | 
						|
        else:
 | 
						|
            Dependency.extend(BuildItem.Dependency)
 | 
						|
        self.AddDependency(Dependency)
 | 
						|
        # flag indicating build completes, used to avoid unnecessary re-build
 | 
						|
        self.CompleteFlag = False
 | 
						|
 | 
						|
    ## Check if all dependent build tasks are completed or not
 | 
						|
    #
 | 
						|
    def IsReady(self):
 | 
						|
        ReadyFlag = True
 | 
						|
        for Dep in self.DependencyList:
 | 
						|
            if Dep.CompleteFlag == True:
 | 
						|
                continue
 | 
						|
            ReadyFlag = False
 | 
						|
            break
 | 
						|
 | 
						|
        return ReadyFlag
 | 
						|
 | 
						|
    ## Add dependent build task
 | 
						|
    #
 | 
						|
    #   @param  Dependency      The list of dependent build objects
 | 
						|
    #
 | 
						|
    def AddDependency(self, Dependency):
 | 
						|
        for Dep in Dependency:
 | 
						|
            if not Dep.BuildObject.IsBinaryModule and not Dep.BuildObject.CanSkipbyCache(GlobalData.gCacheIR):
 | 
						|
                self.DependencyList.append(BuildTask.New(Dep))    # BuildTask list
 | 
						|
 | 
						|
    ## The thread wrapper of LaunchCommand function
 | 
						|
    #
 | 
						|
    # @param  Command               A list or string contains the call of the command
 | 
						|
    # @param  WorkingDir            The directory in which the program will be running
 | 
						|
    #
 | 
						|
    def _CommandThread(self, Command, WorkingDir):
 | 
						|
        try:
 | 
						|
            self.BuildItem.BuildObject.BuildTime = LaunchCommand(Command, WorkingDir)
 | 
						|
            self.CompleteFlag = True
 | 
						|
 | 
						|
            # Run hash operation post dependency, to account for libs
 | 
						|
            if GlobalData.gUseHashCache and self.BuildItem.BuildObject.IsLibrary:
 | 
						|
                HashFile = path.join(self.BuildItem.BuildObject.BuildDir, self.BuildItem.BuildObject.Name + ".hash")
 | 
						|
                SaveFileOnChange(HashFile, self.BuildItem.BuildObject.GenModuleHash(), True)
 | 
						|
        except:
 | 
						|
            #
 | 
						|
            # TRICK: hide the output of threads left running, so that the user can
 | 
						|
            #        catch the error message easily
 | 
						|
            #
 | 
						|
            if not BuildTask._ErrorFlag.isSet():
 | 
						|
                GlobalData.gBuildingModule = "%s [%s, %s, %s]" % (str(self.BuildItem.BuildObject),
 | 
						|
                                                                  self.BuildItem.BuildObject.Arch,
 | 
						|
                                                                  self.BuildItem.BuildObject.ToolChain,
 | 
						|
                                                                  self.BuildItem.BuildObject.BuildTarget
 | 
						|
                                                                 )
 | 
						|
            EdkLogger.SetLevel(EdkLogger.ERROR)
 | 
						|
            BuildTask._ErrorFlag.set()
 | 
						|
            BuildTask._ErrorMessage = "%s broken\n    %s [%s]" % \
 | 
						|
                                      (threading.currentThread().getName(), Command, WorkingDir)
 | 
						|
 | 
						|
        # Set the value used by hash invalidation flow in GlobalData.gModuleBuildTracking to 'SUCCESS'
 | 
						|
        # If Module or Lib is being tracked, it did not fail header check test, and built successfully
 | 
						|
        if (self.BuildItem.BuildObject in GlobalData.gModuleBuildTracking and
 | 
						|
           GlobalData.gModuleBuildTracking[self.BuildItem.BuildObject] != 'FAIL_METAFILE' and
 | 
						|
           not BuildTask._ErrorFlag.isSet()
 | 
						|
           ):
 | 
						|
            GlobalData.gModuleBuildTracking[self.BuildItem.BuildObject] = 'SUCCESS'
 | 
						|
 | 
						|
        # indicate there's a thread is available for another build task
 | 
						|
        BuildTask._RunningQueueLock.acquire()
 | 
						|
        BuildTask._RunningQueue.pop(self.BuildItem)
 | 
						|
        BuildTask._RunningQueueLock.release()
 | 
						|
        BuildTask._Thread.release()
 | 
						|
 | 
						|
    ## Start build task thread
 | 
						|
    #
 | 
						|
    def Start(self):
 | 
						|
        EdkLogger.quiet("Building ... %s" % repr(self.BuildItem))
 | 
						|
        Command = self.BuildItem.BuildCommand + [self.BuildItem.Target]
 | 
						|
        self.BuildTread = Thread(target=self._CommandThread, args=(Command, self.BuildItem.WorkingDir))
 | 
						|
        self.BuildTread.setName("build thread")
 | 
						|
        self.BuildTread.setDaemon(False)
 | 
						|
        self.BuildTread.start()
 | 
						|
 | 
						|
## The class contains the information related to EFI image
 | 
						|
#
 | 
						|
class PeImageInfo():
 | 
						|
    ## Constructor
 | 
						|
    #
 | 
						|
    # Constructor will load all required image information.
 | 
						|
    #
 | 
						|
    #   @param  BaseName          The full file path of image.
 | 
						|
    #   @param  Guid              The GUID for image.
 | 
						|
    #   @param  Arch              Arch of this image.
 | 
						|
    #   @param  OutputDir         The output directory for image.
 | 
						|
    #   @param  DebugDir          The debug directory for image.
 | 
						|
    #   @param  ImageClass        PeImage Information
 | 
						|
    #
 | 
						|
    def __init__(self, BaseName, Guid, Arch, OutputDir, DebugDir, ImageClass):
 | 
						|
        self.BaseName         = BaseName
 | 
						|
        self.Guid             = Guid
 | 
						|
        self.Arch             = Arch
 | 
						|
        self.OutputDir        = OutputDir
 | 
						|
        self.DebugDir         = DebugDir
 | 
						|
        self.Image            = ImageClass
 | 
						|
        self.Image.Size       = (self.Image.Size // 0x1000 + 1) * 0x1000
 | 
						|
 | 
						|
## The class implementing the EDK2 build process
 | 
						|
#
 | 
						|
#   The build process includes:
 | 
						|
#       1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
 | 
						|
#       2. Parse DSC file of active platform
 | 
						|
#       3. Parse FDF file if any
 | 
						|
#       4. Establish build database, including parse all other files (module, package)
 | 
						|
#       5. Create AutoGen files (C code file, depex file, makefile) if necessary
 | 
						|
#       6. Call build command
 | 
						|
#
 | 
						|
class Build():
 | 
						|
    ## Constructor
 | 
						|
    #
 | 
						|
    # Constructor will load all necessary configurations, parse platform, modules
 | 
						|
    # and packages and the establish a database for AutoGen.
 | 
						|
    #
 | 
						|
    #   @param  Target              The build command target, one of gSupportedTarget
 | 
						|
    #   @param  WorkspaceDir        The directory of workspace
 | 
						|
    #   @param  BuildOptions        Build options passed from command line
 | 
						|
    #
 | 
						|
    def __init__(self, Target, WorkspaceDir, BuildOptions,log_q):
 | 
						|
        self.WorkspaceDir   = WorkspaceDir
 | 
						|
        self.Target         = Target
 | 
						|
        self.PlatformFile   = BuildOptions.PlatformFile
 | 
						|
        self.ModuleFile     = BuildOptions.ModuleFile
 | 
						|
        self.ArchList       = BuildOptions.TargetArch
 | 
						|
        self.ToolChainList  = BuildOptions.ToolChain
 | 
						|
        self.BuildTargetList= BuildOptions.BuildTarget
 | 
						|
        self.Fdf            = BuildOptions.FdfFile
 | 
						|
        self.FdList         = BuildOptions.RomImage
 | 
						|
        self.FvList         = BuildOptions.FvImage
 | 
						|
        self.CapList        = BuildOptions.CapName
 | 
						|
        self.SilentMode     = BuildOptions.SilentMode
 | 
						|
        self.ThreadNumber   = 1
 | 
						|
        self.SkipAutoGen    = BuildOptions.SkipAutoGen
 | 
						|
        self.Reparse        = BuildOptions.Reparse
 | 
						|
        self.SkuId          = BuildOptions.SkuId
 | 
						|
        if self.SkuId:
 | 
						|
            GlobalData.gSKUID_CMD = self.SkuId
 | 
						|
        self.ConfDirectory = BuildOptions.ConfDirectory
 | 
						|
        self.SpawnMode      = True
 | 
						|
        self.BuildReport    = BuildReport(BuildOptions.ReportFile, BuildOptions.ReportType)
 | 
						|
        self.TargetTxt      = TargetTxt
 | 
						|
        self.ToolDef        = ToolDef
 | 
						|
        self.AutoGenTime    = 0
 | 
						|
        self.MakeTime       = 0
 | 
						|
        self.GenFdsTime     = 0
 | 
						|
        GlobalData.BuildOptionPcd     = BuildOptions.OptionPcd if BuildOptions.OptionPcd else []
 | 
						|
        #Set global flag for build mode
 | 
						|
        GlobalData.gIgnoreSource = BuildOptions.IgnoreSources
 | 
						|
        GlobalData.gUseHashCache = BuildOptions.UseHashCache
 | 
						|
        GlobalData.gBinCacheDest   = BuildOptions.BinCacheDest
 | 
						|
        GlobalData.gBinCacheSource = BuildOptions.BinCacheSource
 | 
						|
        GlobalData.gEnableGenfdsMultiThread = not BuildOptions.NoGenfdsMultiThread
 | 
						|
        GlobalData.gDisableIncludePathCheck = BuildOptions.DisableIncludePathCheck
 | 
						|
 | 
						|
        if GlobalData.gBinCacheDest and not GlobalData.gUseHashCache:
 | 
						|
            EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-destination must be used together with --hash.")
 | 
						|
 | 
						|
        if GlobalData.gBinCacheSource and not GlobalData.gUseHashCache:
 | 
						|
            EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-source must be used together with --hash.")
 | 
						|
 | 
						|
        if GlobalData.gBinCacheDest and GlobalData.gBinCacheSource:
 | 
						|
            EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-destination can not be used together with --binary-source.")
 | 
						|
 | 
						|
        if GlobalData.gBinCacheSource:
 | 
						|
            BinCacheSource = os.path.normpath(GlobalData.gBinCacheSource)
 | 
						|
            if not os.path.isabs(BinCacheSource):
 | 
						|
                BinCacheSource = mws.join(self.WorkspaceDir, BinCacheSource)
 | 
						|
            GlobalData.gBinCacheSource = BinCacheSource
 | 
						|
        else:
 | 
						|
            if GlobalData.gBinCacheSource is not None:
 | 
						|
                EdkLogger.error("build", OPTION_VALUE_INVALID, ExtraData="Invalid value of option --binary-source.")
 | 
						|
 | 
						|
        if GlobalData.gBinCacheDest:
 | 
						|
            BinCacheDest = os.path.normpath(GlobalData.gBinCacheDest)
 | 
						|
            if not os.path.isabs(BinCacheDest):
 | 
						|
                BinCacheDest = mws.join(self.WorkspaceDir, BinCacheDest)
 | 
						|
            GlobalData.gBinCacheDest = BinCacheDest
 | 
						|
        else:
 | 
						|
            if GlobalData.gBinCacheDest is not None:
 | 
						|
                EdkLogger.error("build", OPTION_VALUE_INVALID, ExtraData="Invalid value of option --binary-destination.")
 | 
						|
 | 
						|
        GlobalData.gDatabasePath = os.path.normpath(os.path.join(GlobalData.gConfDirectory, GlobalData.gDatabasePath))
 | 
						|
        if not os.path.exists(os.path.join(GlobalData.gConfDirectory, '.cache')):
 | 
						|
            os.makedirs(os.path.join(GlobalData.gConfDirectory, '.cache'))
 | 
						|
        self.Db = BuildDB
 | 
						|
        self.BuildDatabase = self.Db.BuildObject
 | 
						|
        self.Platform = None
 | 
						|
        self.ToolChainFamily = None
 | 
						|
        self.LoadFixAddress = 0
 | 
						|
        self.UniFlag        = BuildOptions.Flag
 | 
						|
        self.BuildModules = []
 | 
						|
        self.HashSkipModules = []
 | 
						|
        self.Db_Flag = False
 | 
						|
        self.LaunchPrebuildFlag = False
 | 
						|
        self.PlatformBuildPath = os.path.join(GlobalData.gConfDirectory, '.cache', '.PlatformBuild')
 | 
						|
        if BuildOptions.CommandLength:
 | 
						|
            GlobalData.gCommandMaxLength = BuildOptions.CommandLength
 | 
						|
 | 
						|
        # print dot character during doing some time-consuming work
 | 
						|
        self.Progress = Utils.Progressor()
 | 
						|
        # print current build environment and configuration
 | 
						|
        EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))
 | 
						|
        if "PACKAGES_PATH" in os.environ:
 | 
						|
            # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
 | 
						|
            EdkLogger.quiet("%-16s = %s" % ("PACKAGES_PATH", os.path.normcase(os.path.normpath(os.environ["PACKAGES_PATH"]))))
 | 
						|
        EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))
 | 
						|
        if "EDK_TOOLS_BIN" in os.environ:
 | 
						|
            # Print the same path style with WORKSPACE env.
 | 
						|
            EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os.path.normcase(os.path.normpath(os.environ["EDK_TOOLS_BIN"]))))
 | 
						|
        EdkLogger.quiet("%-16s = %s" % ("CONF_PATH", GlobalData.gConfDirectory))
 | 
						|
        if "PYTHON3_ENABLE" in os.environ:
 | 
						|
            PYTHON3_ENABLE = os.environ["PYTHON3_ENABLE"]
 | 
						|
            if PYTHON3_ENABLE != "TRUE":
 | 
						|
                PYTHON3_ENABLE = "FALSE"
 | 
						|
            EdkLogger.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE))
 | 
						|
        if "PYTHON_COMMAND" in os.environ:
 | 
						|
            EdkLogger.quiet("%-16s = %s" % ("PYTHON_COMMAND", os.environ["PYTHON_COMMAND"]))
 | 
						|
        self.InitPreBuild()
 | 
						|
        self.InitPostBuild()
 | 
						|
        if self.Prebuild:
 | 
						|
            EdkLogger.quiet("%-16s = %s" % ("PREBUILD", self.Prebuild))
 | 
						|
        if self.Postbuild:
 | 
						|
            EdkLogger.quiet("%-16s = %s" % ("POSTBUILD", self.Postbuild))
 | 
						|
        if self.Prebuild:
 | 
						|
            self.LaunchPrebuild()
 | 
						|
            self.TargetTxt = TargetTxt
 | 
						|
            self.ToolDef   = ToolDef
 | 
						|
        if not (self.LaunchPrebuildFlag and os.path.exists(self.PlatformBuildPath)):
 | 
						|
            self.InitBuild()
 | 
						|
 | 
						|
        self.AutoGenMgr = None
 | 
						|
        EdkLogger.info("")
 | 
						|
        os.chdir(self.WorkspaceDir)
 | 
						|
        GlobalData.gCacheIR = Manager().dict()
 | 
						|
        self.log_q = log_q
 | 
						|
        GlobalData.file_lock =  mp.Lock()
 | 
						|
        GlobalData.cache_lock = mp.Lock()
 | 
						|
    def StartAutoGen(self,mqueue, DataPipe,SkipAutoGen,PcdMaList,share_data):
 | 
						|
        try:
 | 
						|
            if SkipAutoGen:
 | 
						|
                return True,0
 | 
						|
            feedback_q = mp.Queue()
 | 
						|
            error_event = mp.Event()
 | 
						|
            FfsCmd = DataPipe.Get("FfsCommand")
 | 
						|
            if FfsCmd is None:
 | 
						|
                FfsCmd = {}
 | 
						|
            GlobalData.FfsCmd = FfsCmd
 | 
						|
            GlobalData.libConstPcd = DataPipe.Get("LibConstPcd")
 | 
						|
            GlobalData.Refes = DataPipe.Get("REFS")
 | 
						|
            auto_workers = [AutoGenWorkerInProcess(mqueue,DataPipe.dump_file,feedback_q,GlobalData.file_lock,GlobalData.cache_lock,share_data,self.log_q,error_event) for _ in range(self.ThreadNumber)]
 | 
						|
            self.AutoGenMgr = AutoGenManager(auto_workers,feedback_q,error_event)
 | 
						|
            self.AutoGenMgr.start()
 | 
						|
            for w in auto_workers:
 | 
						|
                w.start()
 | 
						|
            if PcdMaList is not None:
 | 
						|
                for PcdMa in PcdMaList:
 | 
						|
                    if GlobalData.gBinCacheSource and self.Target in [None, "", "all"]:
 | 
						|
                        PcdMa.GenModuleFilesHash(share_data)
 | 
						|
                        PcdMa.GenPreMakefileHash(share_data)
 | 
						|
                        if PcdMa.CanSkipbyPreMakefileCache(share_data):
 | 
						|
                            continue
 | 
						|
 | 
						|
                    PcdMa.CreateCodeFile(False)
 | 
						|
                    PcdMa.CreateMakeFile(False,GenFfsList = DataPipe.Get("FfsCommand").get((PcdMa.MetaFile.Path, PcdMa.Arch),[]))
 | 
						|
 | 
						|
                    if GlobalData.gBinCacheSource and self.Target in [None, "", "all"]:
 | 
						|
                        PcdMa.GenMakeHeaderFilesHash(share_data)
 | 
						|
                        PcdMa.GenMakeHash(share_data)
 | 
						|
                        if PcdMa.CanSkipbyMakeCache(share_data):
 | 
						|
                            continue
 | 
						|
 | 
						|
            self.AutoGenMgr.join()
 | 
						|
            rt = self.AutoGenMgr.Status
 | 
						|
            return rt, 0
 | 
						|
        except FatalError as e:
 | 
						|
            return False, e.args[0]
 | 
						|
        except:
 | 
						|
            return False, UNKNOWN_ERROR
 | 
						|
 | 
						|
    ## Load configuration
 | 
						|
    #
 | 
						|
    #   This method will parse target.txt and get the build configurations.
 | 
						|
    #
 | 
						|
    def LoadConfiguration(self):
 | 
						|
 | 
						|
        # if no ARCH given in command line, get it from target.txt
 | 
						|
        if not self.ArchList:
 | 
						|
            self.ArchList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET_ARCH]
 | 
						|
        self.ArchList = tuple(self.ArchList)
 | 
						|
 | 
						|
        # if no build target given in command line, get it from target.txt
 | 
						|
        if not self.BuildTargetList:
 | 
						|
            self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET]
 | 
						|
 | 
						|
        # if no tool chain given in command line, get it from target.txt
 | 
						|
        if not self.ToolChainList:
 | 
						|
            self.ToolChainList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TOOL_CHAIN_TAG]
 | 
						|
            if self.ToolChainList is None or len(self.ToolChainList) == 0:
 | 
						|
                EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")
 | 
						|
 | 
						|
        # check if the tool chains are defined or not
 | 
						|
        NewToolChainList = []
 | 
						|
        for ToolChain in self.ToolChainList:
 | 
						|
            if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:
 | 
						|
                EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)
 | 
						|
            else:
 | 
						|
                NewToolChainList.append(ToolChain)
 | 
						|
        # if no tool chain available, break the build
 | 
						|
        if len(NewToolChainList) == 0:
 | 
						|
            EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
 | 
						|
                            ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))
 | 
						|
        else:
 | 
						|
            self.ToolChainList = NewToolChainList
 | 
						|
 | 
						|
        ToolChainFamily = []
 | 
						|
        ToolDefinition = self.ToolDef.ToolsDefTxtDatabase
 | 
						|
        for Tool in self.ToolChainList:
 | 
						|
            if TAB_TOD_DEFINES_FAMILY not in ToolDefinition or Tool not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \
 | 
						|
               or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool]:
 | 
						|
                EdkLogger.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool)
 | 
						|
                ToolChainFamily.append(TAB_COMPILER_MSFT)
 | 
						|
            else:
 | 
						|
                ToolChainFamily.append(ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool])
 | 
						|
        self.ToolChainFamily = ToolChainFamily
 | 
						|
 | 
						|
        if not self.PlatformFile:
 | 
						|
            PlatformFile = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_ACTIVE_PLATFORM]
 | 
						|
            if not PlatformFile:
 | 
						|
                # Try to find one in current directory
 | 
						|
                WorkingDirectory = os.getcwd()
 | 
						|
                FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))
 | 
						|
                FileNum = len(FileList)
 | 
						|
                if FileNum >= 2:
 | 
						|
                    EdkLogger.error("build", OPTION_MISSING,
 | 
						|
                                    ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))
 | 
						|
                elif FileNum == 1:
 | 
						|
                    PlatformFile = FileList[0]
 | 
						|
                else:
 | 
						|
                    EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
 | 
						|
                                    ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")
 | 
						|
 | 
						|
            self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)
 | 
						|
        self.ThreadNumber   = ThreadNum()
 | 
						|
    ## Initialize build configuration
 | 
						|
    #
 | 
						|
    #   This method will parse DSC file and merge the configurations from
 | 
						|
    #   command line and target.txt, then get the final build configurations.
 | 
						|
    #
 | 
						|
    def InitBuild(self):
 | 
						|
        # parse target.txt, tools_def.txt, and platform file
 | 
						|
        self.LoadConfiguration()
 | 
						|
 | 
						|
        # Allow case-insensitive for those from command line or configuration file
 | 
						|
        ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)
 | 
						|
        if ErrorCode != 0:
 | 
						|
            EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
 | 
						|
 | 
						|
 | 
						|
    def InitPreBuild(self):
 | 
						|
        self.LoadConfiguration()
 | 
						|
        ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)
 | 
						|
        if ErrorCode != 0:
 | 
						|
            EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
 | 
						|
        if self.BuildTargetList:
 | 
						|
            GlobalData.gGlobalDefines['TARGET'] = self.BuildTargetList[0]
 | 
						|
        if self.ArchList:
 | 
						|
            GlobalData.gGlobalDefines['ARCH'] = self.ArchList[0]
 | 
						|
        if self.ToolChainList:
 | 
						|
            GlobalData.gGlobalDefines['TOOLCHAIN'] = self.ToolChainList[0]
 | 
						|
            GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = self.ToolChainList[0]
 | 
						|
        if self.ToolChainFamily:
 | 
						|
            GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[0]
 | 
						|
        if 'PREBUILD' in GlobalData.gCommandLineDefines:
 | 
						|
            self.Prebuild   = GlobalData.gCommandLineDefines.get('PREBUILD')
 | 
						|
        else:
 | 
						|
            self.Db_Flag = True
 | 
						|
            Platform = self.Db.MapPlatform(str(self.PlatformFile))
 | 
						|
            self.Prebuild = str(Platform.Prebuild)
 | 
						|
        if self.Prebuild:
 | 
						|
            PrebuildList = []
 | 
						|
            #
 | 
						|
            # Evaluate all arguments and convert arguments that are WORKSPACE
 | 
						|
            # relative paths to absolute paths.  Filter arguments that look like
 | 
						|
            # flags or do not follow the file/dir naming rules to avoid false
 | 
						|
            # positives on this conversion.
 | 
						|
            #
 | 
						|
            for Arg in self.Prebuild.split():
 | 
						|
                #
 | 
						|
                # Do not modify Arg if it looks like a flag or an absolute file path
 | 
						|
                #
 | 
						|
                if Arg.startswith('-')  or os.path.isabs(Arg):
 | 
						|
                    PrebuildList.append(Arg)
 | 
						|
                    continue
 | 
						|
                #
 | 
						|
                # Do not modify Arg if it does not look like a Workspace relative
 | 
						|
                # path that starts with a valid package directory name
 | 
						|
                #
 | 
						|
                if not Arg[0].isalpha() or os.path.dirname(Arg) == '':
 | 
						|
                    PrebuildList.append(Arg)
 | 
						|
                    continue
 | 
						|
                #
 | 
						|
                # If Arg looks like a WORKSPACE relative path, then convert to an
 | 
						|
                # absolute path and check to see if the file exists.
 | 
						|
                #
 | 
						|
                Temp = mws.join(self.WorkspaceDir, Arg)
 | 
						|
                if os.path.isfile(Temp):
 | 
						|
                    Arg = Temp
 | 
						|
                PrebuildList.append(Arg)
 | 
						|
            self.Prebuild       = ' '.join(PrebuildList)
 | 
						|
            self.Prebuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)
 | 
						|
 | 
						|
    def InitPostBuild(self):
 | 
						|
        if 'POSTBUILD' in GlobalData.gCommandLineDefines:
 | 
						|
            self.Postbuild = GlobalData.gCommandLineDefines.get('POSTBUILD')
 | 
						|
        else:
 | 
						|
            Platform = self.Db.MapPlatform(str(self.PlatformFile))
 | 
						|
            self.Postbuild = str(Platform.Postbuild)
 | 
						|
        if self.Postbuild:
 | 
						|
            PostbuildList = []
 | 
						|
            #
 | 
						|
            # Evaluate all arguments and convert arguments that are WORKSPACE
 | 
						|
            # relative paths to absolute paths.  Filter arguments that look like
 | 
						|
            # flags or do not follow the file/dir naming rules to avoid false
 | 
						|
            # positives on this conversion.
 | 
						|
            #
 | 
						|
            for Arg in self.Postbuild.split():
 | 
						|
                #
 | 
						|
                # Do not modify Arg if it looks like a flag or an absolute file path
 | 
						|
                #
 | 
						|
                if Arg.startswith('-')  or os.path.isabs(Arg):
 | 
						|
                    PostbuildList.append(Arg)
 | 
						|
                    continue
 | 
						|
                #
 | 
						|
                # Do not modify Arg if it does not look like a Workspace relative
 | 
						|
                # path that starts with a valid package directory name
 | 
						|
                #
 | 
						|
                if not Arg[0].isalpha() or os.path.dirname(Arg) == '':
 | 
						|
                    PostbuildList.append(Arg)
 | 
						|
                    continue
 | 
						|
                #
 | 
						|
                # If Arg looks like a WORKSPACE relative path, then convert to an
 | 
						|
                # absolute path and check to see if the file exists.
 | 
						|
                #
 | 
						|
                Temp = mws.join(self.WorkspaceDir, Arg)
 | 
						|
                if os.path.isfile(Temp):
 | 
						|
                    Arg = Temp
 | 
						|
                PostbuildList.append(Arg)
 | 
						|
            self.Postbuild       = ' '.join(PostbuildList)
 | 
						|
            self.Postbuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)
 | 
						|
 | 
						|
    def PassCommandOption(self, BuildTarget, TargetArch, ToolChain, PlatformFile, Target):
 | 
						|
        BuildStr = ''
 | 
						|
        if GlobalData.gCommand and isinstance(GlobalData.gCommand, list):
 | 
						|
            BuildStr += ' ' + ' '.join(GlobalData.gCommand)
 | 
						|
        TargetFlag = False
 | 
						|
        ArchFlag = False
 | 
						|
        ToolChainFlag = False
 | 
						|
        PlatformFileFlag = False
 | 
						|
 | 
						|
        if GlobalData.gOptions and not GlobalData.gOptions.BuildTarget:
 | 
						|
            TargetFlag = True
 | 
						|
        if GlobalData.gOptions and not GlobalData.gOptions.TargetArch:
 | 
						|
            ArchFlag = True
 | 
						|
        if GlobalData.gOptions and not GlobalData.gOptions.ToolChain:
 | 
						|
            ToolChainFlag = True
 | 
						|
        if GlobalData.gOptions and not GlobalData.gOptions.PlatformFile:
 | 
						|
            PlatformFileFlag = True
 | 
						|
 | 
						|
        if TargetFlag and BuildTarget:
 | 
						|
            if isinstance(BuildTarget, list) or isinstance(BuildTarget, tuple):
 | 
						|
                BuildStr += ' -b ' + ' -b '.join(BuildTarget)
 | 
						|
            elif isinstance(BuildTarget, str):
 | 
						|
                BuildStr += ' -b ' + BuildTarget
 | 
						|
        if ArchFlag and TargetArch:
 | 
						|
            if isinstance(TargetArch, list) or isinstance(TargetArch, tuple):
 | 
						|
                BuildStr += ' -a ' + ' -a '.join(TargetArch)
 | 
						|
            elif isinstance(TargetArch, str):
 | 
						|
                BuildStr += ' -a ' + TargetArch
 | 
						|
        if ToolChainFlag and ToolChain:
 | 
						|
            if isinstance(ToolChain, list) or isinstance(ToolChain, tuple):
 | 
						|
                BuildStr += ' -t ' + ' -t '.join(ToolChain)
 | 
						|
            elif isinstance(ToolChain, str):
 | 
						|
                BuildStr += ' -t ' + ToolChain
 | 
						|
        if PlatformFileFlag and PlatformFile:
 | 
						|
            if isinstance(PlatformFile, list) or isinstance(PlatformFile, tuple):
 | 
						|
                BuildStr += ' -p ' + ' -p '.join(PlatformFile)
 | 
						|
            elif isinstance(PlatformFile, str):
 | 
						|
                BuildStr += ' -p' + PlatformFile
 | 
						|
        BuildStr += ' --conf=' + GlobalData.gConfDirectory
 | 
						|
        if Target:
 | 
						|
            BuildStr += ' ' + Target
 | 
						|
 | 
						|
        return BuildStr
 | 
						|
 | 
						|
    def LaunchPrebuild(self):
 | 
						|
        if self.Prebuild:
 | 
						|
            EdkLogger.info("\n- Prebuild Start -\n")
 | 
						|
            self.LaunchPrebuildFlag = True
 | 
						|
            #
 | 
						|
            # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
 | 
						|
            # and preserve them for the rest of the main build step, because the child process environment will
 | 
						|
            # evaporate as soon as it exits, we cannot get it in build step.
 | 
						|
            #
 | 
						|
            PrebuildEnvFile = os.path.join(GlobalData.gConfDirectory, '.cache', '.PrebuildEnv')
 | 
						|
            if os.path.isfile(PrebuildEnvFile):
 | 
						|
                os.remove(PrebuildEnvFile)
 | 
						|
            if os.path.isfile(self.PlatformBuildPath):
 | 
						|
                os.remove(self.PlatformBuildPath)
 | 
						|
            if sys.platform == "win32":
 | 
						|
                args = ' && '.join((self.Prebuild, 'set > ' + PrebuildEnvFile))
 | 
						|
                Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)
 | 
						|
            else:
 | 
						|
                args = ' && '.join((self.Prebuild, 'env > ' + PrebuildEnvFile))
 | 
						|
                Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)
 | 
						|
 | 
						|
            # launch two threads to read the STDOUT and STDERR
 | 
						|
            EndOfProcedure = Event()
 | 
						|
            EndOfProcedure.clear()
 | 
						|
            if Process.stdout:
 | 
						|
                StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))
 | 
						|
                StdOutThread.setName("STDOUT-Redirector")
 | 
						|
                StdOutThread.setDaemon(False)
 | 
						|
                StdOutThread.start()
 | 
						|
 | 
						|
            if Process.stderr:
 | 
						|
                StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))
 | 
						|
                StdErrThread.setName("STDERR-Redirector")
 | 
						|
                StdErrThread.setDaemon(False)
 | 
						|
                StdErrThread.start()
 | 
						|
            # waiting for program exit
 | 
						|
            Process.wait()
 | 
						|
 | 
						|
            if Process.stdout:
 | 
						|
                StdOutThread.join()
 | 
						|
            if Process.stderr:
 | 
						|
                StdErrThread.join()
 | 
						|
            if Process.returncode != 0 :
 | 
						|
                EdkLogger.error("Prebuild", PREBUILD_ERROR, 'Prebuild process is not success!')
 | 
						|
 | 
						|
            if os.path.exists(PrebuildEnvFile):
 | 
						|
                f = open(PrebuildEnvFile)
 | 
						|
                envs = f.readlines()
 | 
						|
                f.close()
 | 
						|
                envs = [l.split("=", 1) for l in envs ]
 | 
						|
                envs = [[I.strip() for I in item] for item in envs if len(item) == 2]
 | 
						|
                os.environ.update(dict(envs))
 | 
						|
            EdkLogger.info("\n- Prebuild Done -\n")
 | 
						|
 | 
						|
    def LaunchPostbuild(self):
 | 
						|
        if self.Postbuild:
 | 
						|
            EdkLogger.info("\n- Postbuild Start -\n")
 | 
						|
            if sys.platform == "win32":
 | 
						|
                Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)
 | 
						|
            else:
 | 
						|
                Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)
 | 
						|
            # launch two threads to read the STDOUT and STDERR
 | 
						|
            EndOfProcedure = Event()
 | 
						|
            EndOfProcedure.clear()
 | 
						|
            if Process.stdout:
 | 
						|
                StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))
 | 
						|
                StdOutThread.setName("STDOUT-Redirector")
 | 
						|
                StdOutThread.setDaemon(False)
 | 
						|
                StdOutThread.start()
 | 
						|
 | 
						|
            if Process.stderr:
 | 
						|
                StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))
 | 
						|
                StdErrThread.setName("STDERR-Redirector")
 | 
						|
                StdErrThread.setDaemon(False)
 | 
						|
                StdErrThread.start()
 | 
						|
            # waiting for program exit
 | 
						|
            Process.wait()
 | 
						|
 | 
						|
            if Process.stdout:
 | 
						|
                StdOutThread.join()
 | 
						|
            if Process.stderr:
 | 
						|
                StdErrThread.join()
 | 
						|
            if Process.returncode != 0 :
 | 
						|
                EdkLogger.error("Postbuild", POSTBUILD_ERROR, 'Postbuild process is not success!')
 | 
						|
            EdkLogger.info("\n- Postbuild Done -\n")
 | 
						|
 | 
						|
    ## Error handling for hash feature
 | 
						|
    #
 | 
						|
    # On BuildTask error, iterate through the Module Build tracking
 | 
						|
    # dictionary to determine wheather a module failed to build. Invalidate
 | 
						|
    # the hash associated with that module by removing it from storage.
 | 
						|
    #
 | 
						|
    #
 | 
						|
    def invalidateHash(self):
 | 
						|
        # Only for hashing feature
 | 
						|
        if not GlobalData.gUseHashCache:
 | 
						|
            return
 | 
						|
 | 
						|
        # GlobalData.gModuleBuildTracking contains only modules or libs that cannot be skipped by hash
 | 
						|
        for Ma in GlobalData.gModuleBuildTracking:
 | 
						|
            # Skip invalidating for Successful Module/Lib builds
 | 
						|
            if GlobalData.gModuleBuildTracking[Ma] == 'SUCCESS':
 | 
						|
                continue
 | 
						|
 | 
						|
            # The module failed to build, failed to start building, or failed the header check test from this point on
 | 
						|
 | 
						|
            # Remove .hash from build
 | 
						|
            ModuleHashFile = os.path.join(Ma.BuildDir, Ma.Name + ".hash")
 | 
						|
            if os.path.exists(ModuleHashFile):
 | 
						|
                os.remove(ModuleHashFile)
 | 
						|
 | 
						|
            # Remove .hash file from cache
 | 
						|
            if GlobalData.gBinCacheDest:
 | 
						|
                FileDir = os.path.join(GlobalData.gBinCacheDest, Ma.PlatformInfo.OutputDir, Ma.BuildTarget + "_" + Ma.ToolChain, Ma.Arch, Ma.SourceDir, Ma.MetaFile.BaseName)
 | 
						|
                HashFile = os.path.join(FileDir, Ma.Name + '.hash')
 | 
						|
                if os.path.exists(HashFile):
 | 
						|
                    os.remove(HashFile)
 | 
						|
 | 
						|
    ## Build a module or platform
 | 
						|
    #
 | 
						|
    # Create autogen code and makefile for a module or platform, and the launch
 | 
						|
    # "make" command to build it
 | 
						|
    #
 | 
						|
    #   @param  Target                      The target of build command
 | 
						|
    #   @param  Platform                    The platform file
 | 
						|
    #   @param  Module                      The module file
 | 
						|
    #   @param  BuildTarget                 The name of build target, one of "DEBUG", "RELEASE"
 | 
						|
    #   @param  ToolChain                   The name of toolchain to build
 | 
						|
    #   @param  Arch                        The arch of the module/platform
 | 
						|
    #   @param  CreateDepModuleCodeFile     Flag used to indicate creating code
 | 
						|
    #                                       for dependent modules/Libraries
 | 
						|
    #   @param  CreateDepModuleMakeFile     Flag used to indicate creating makefile
 | 
						|
    #                                       for dependent modules/Libraries
 | 
						|
    #
 | 
						|
    def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False, FfsCommand=None, PcdMaList=None):
 | 
						|
        if AutoGenObject is None:
 | 
						|
            return False
 | 
						|
        if FfsCommand is None:
 | 
						|
            FfsCommand = {}
 | 
						|
        # skip file generation for cleanxxx targets, run and fds target
 | 
						|
        if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
 | 
						|
            # for target which must generate AutoGen code and makefile
 | 
						|
            mqueue = mp.Queue()
 | 
						|
            for m in AutoGenObject.GetAllModuleInfo:
 | 
						|
                mqueue.put(m)
 | 
						|
 | 
						|
            AutoGenObject.DataPipe.DataContainer = {"CommandTarget": self.Target}
 | 
						|
            AutoGenObject.DataPipe.DataContainer = {"Workspace_timestamp": AutoGenObject.Workspace._SrcTimeStamp}
 | 
						|
            AutoGenObject.CreateLibModuelDirs()
 | 
						|
            AutoGenObject.DataPipe.DataContainer = {"LibraryBuildDirectoryList":AutoGenObject.LibraryBuildDirectoryList}
 | 
						|
            AutoGenObject.DataPipe.DataContainer = {"ModuleBuildDirectoryList":AutoGenObject.ModuleBuildDirectoryList}
 | 
						|
            AutoGenObject.DataPipe.DataContainer = {"FdsCommandDict": AutoGenObject.Workspace.GenFdsCommandDict}
 | 
						|
            self.Progress.Start("Generating makefile and code")
 | 
						|
            data_pipe_file = os.path.join(AutoGenObject.BuildDir, "GlobalVar_%s_%s.bin" % (str(AutoGenObject.Guid),AutoGenObject.Arch))
 | 
						|
            AutoGenObject.DataPipe.dump(data_pipe_file)
 | 
						|
            autogen_rt,errorcode = self.StartAutoGen(mqueue, AutoGenObject.DataPipe, self.SkipAutoGen, PcdMaList, GlobalData.gCacheIR)
 | 
						|
            AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt")
 | 
						|
            with open(AutoGenIdFile,"w") as fw:
 | 
						|
                fw.write("Arch=%s\n" % "|".join((AutoGenObject.Workspace.ArchList)))
 | 
						|
                fw.write("BuildDir=%s\n" % AutoGenObject.Workspace.BuildDir)
 | 
						|
                fw.write("PlatformGuid=%s\n" % str(AutoGenObject.Guid))
 | 
						|
            self.Progress.Stop("done!")
 | 
						|
            if not autogen_rt:
 | 
						|
                self.AutoGenMgr.TerminateWorkers()
 | 
						|
                self.AutoGenMgr.join(1)
 | 
						|
                raise FatalError(errorcode)
 | 
						|
            AutoGenObject.CreateCodeFile(False)
 | 
						|
            AutoGenObject.CreateMakeFile(False)
 | 
						|
        else:
 | 
						|
            # always recreate top/platform makefile when clean, just in case of inconsistency
 | 
						|
            AutoGenObject.CreateCodeFile(True)
 | 
						|
            AutoGenObject.CreateMakeFile(True)
 | 
						|
 | 
						|
        if EdkLogger.GetLevel() == EdkLogger.QUIET:
 | 
						|
            EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
 | 
						|
 | 
						|
        BuildCommand = AutoGenObject.BuildCommand
 | 
						|
        if BuildCommand is None or len(BuildCommand) == 0:
 | 
						|
            EdkLogger.error("build", OPTION_MISSING,
 | 
						|
                            "No build command found for this module. "
 | 
						|
                            "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
 | 
						|
                                (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
 | 
						|
                            ExtraData=str(AutoGenObject))
 | 
						|
 | 
						|
        makefile = GenMake.BuildFile(AutoGenObject)._FILE_NAME_[GenMake.gMakeType]
 | 
						|
 | 
						|
        # run
 | 
						|
        if Target == 'run':
 | 
						|
            return True
 | 
						|
 | 
						|
        # build modules
 | 
						|
        if BuildModule:
 | 
						|
            BuildCommand = BuildCommand + [Target]
 | 
						|
            LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
 | 
						|
            self.CreateAsBuiltInf()
 | 
						|
            if GlobalData.gBinCacheDest:
 | 
						|
                self.UpdateBuildCache()
 | 
						|
            self.BuildModules = []
 | 
						|
            return True
 | 
						|
 | 
						|
        # build library
 | 
						|
        if Target == 'libraries':
 | 
						|
            for Lib in AutoGenObject.LibraryBuildDirectoryList:
 | 
						|
                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']
 | 
						|
                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
 | 
						|
            return True
 | 
						|
 | 
						|
        # build module
 | 
						|
        if Target == 'modules':
 | 
						|
            for Lib in AutoGenObject.LibraryBuildDirectoryList:
 | 
						|
                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']
 | 
						|
                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
 | 
						|
            for Mod in AutoGenObject.ModuleBuildDirectoryList:
 | 
						|
                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']
 | 
						|
                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
 | 
						|
            self.CreateAsBuiltInf()
 | 
						|
            if GlobalData.gBinCacheDest:
 | 
						|
                self.UpdateBuildCache()
 | 
						|
            self.BuildModules = []
 | 
						|
            return True
 | 
						|
 | 
						|
        # cleanlib
 | 
						|
        if Target == 'cleanlib':
 | 
						|
            for Lib in AutoGenObject.LibraryBuildDirectoryList:
 | 
						|
                LibMakefile = os.path.normpath(os.path.join(Lib, makefile))
 | 
						|
                if os.path.exists(LibMakefile):
 | 
						|
                    NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
 | 
						|
                    LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
 | 
						|
            return True
 | 
						|
 | 
						|
        # clean
 | 
						|
        if Target == 'clean':
 | 
						|
            for Mod in AutoGenObject.ModuleBuildDirectoryList:
 | 
						|
                ModMakefile = os.path.normpath(os.path.join(Mod, makefile))
 | 
						|
                if os.path.exists(ModMakefile):
 | 
						|
                    NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']
 | 
						|
                    LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
 | 
						|
            for Lib in AutoGenObject.LibraryBuildDirectoryList:
 | 
						|
                LibMakefile = os.path.normpath(os.path.join(Lib, makefile))
 | 
						|
                if os.path.exists(LibMakefile):
 | 
						|
                    NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
 | 
						|
                    LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
 | 
						|
            return True
 | 
						|
 | 
						|
        # cleanall
 | 
						|
        if Target == 'cleanall':
 | 
						|
            try:
 | 
						|
                #os.rmdir(AutoGenObject.BuildDir)
 | 
						|
                RemoveDirectory(AutoGenObject.BuildDir, True)
 | 
						|
            except WindowsError as X:
 | 
						|
                EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
 | 
						|
        return True
 | 
						|
 | 
						|
    ## Build a module or platform
 | 
						|
    #
 | 
						|
    # Create autogen code and makefile for a module or platform, and the launch
 | 
						|
    # "make" command to build it
 | 
						|
    #
 | 
						|
    #   @param  Target                      The target of build command
 | 
						|
    #   @param  Platform                    The platform file
 | 
						|
    #   @param  Module                      The module file
 | 
						|
    #   @param  BuildTarget                 The name of build target, one of "DEBUG", "RELEASE"
 | 
						|
    #   @param  ToolChain                   The name of toolchain to build
 | 
						|
    #   @param  Arch                        The arch of the module/platform
 | 
						|
    #   @param  CreateDepModuleCodeFile     Flag used to indicate creating code
 | 
						|
    #                                       for dependent modules/Libraries
 | 
						|
    #   @param  CreateDepModuleMakeFile     Flag used to indicate creating makefile
 | 
						|
    #                                       for dependent modules/Libraries
 | 
						|
    #
 | 
						|
    def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):
 | 
						|
        if AutoGenObject is None:
 | 
						|
            return False
 | 
						|
 | 
						|
        # skip file generation for cleanxxx targets, run and fds target
 | 
						|
        if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
 | 
						|
            # for target which must generate AutoGen code and makefile
 | 
						|
            if not self.SkipAutoGen or Target == 'genc':
 | 
						|
                self.Progress.Start("Generating code")
 | 
						|
                AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
 | 
						|
                self.Progress.Stop("done!")
 | 
						|
            if Target == "genc":
 | 
						|
                return True
 | 
						|
 | 
						|
            if not self.SkipAutoGen or Target == 'genmake':
 | 
						|
                self.Progress.Start("Generating makefile")
 | 
						|
                AutoGenObject.CreateMakeFile(CreateDepsMakeFile)
 | 
						|
                #AutoGenObject.CreateAsBuiltInf()
 | 
						|
                self.Progress.Stop("done!")
 | 
						|
            if Target == "genmake":
 | 
						|
                return True
 | 
						|
        else:
 | 
						|
            # always recreate top/platform makefile when clean, just in case of inconsistency
 | 
						|
            AutoGenObject.CreateCodeFile(True)
 | 
						|
            AutoGenObject.CreateMakeFile(True)
 | 
						|
 | 
						|
        if EdkLogger.GetLevel() == EdkLogger.QUIET:
 | 
						|
            EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
 | 
						|
 | 
						|
        BuildCommand = AutoGenObject.BuildCommand
 | 
						|
        if BuildCommand is None or len(BuildCommand) == 0:
 | 
						|
            EdkLogger.error("build", OPTION_MISSING,
 | 
						|
                            "No build command found for this module. "
 | 
						|
                            "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
 | 
						|
                                (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
 | 
						|
                            ExtraData=str(AutoGenObject))
 | 
						|
 | 
						|
        # build modules
 | 
						|
        if BuildModule:
 | 
						|
            if Target != 'fds':
 | 
						|
                BuildCommand = BuildCommand + [Target]
 | 
						|
            AutoGenObject.BuildTime = LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
 | 
						|
            self.CreateAsBuiltInf()
 | 
						|
            if GlobalData.gBinCacheDest:
 | 
						|
                self.UpdateBuildCache()
 | 
						|
            self.BuildModules = []
 | 
						|
            return True
 | 
						|
 | 
						|
        # genfds
 | 
						|
        if Target == 'fds':
 | 
						|
            if GenFdsApi(AutoGenObject.GenFdsCommandDict, self.Db):
 | 
						|
                EdkLogger.error("build", COMMAND_FAILURE)
 | 
						|
            return True
 | 
						|
 | 
						|
        # run
 | 
						|
        if Target == 'run':
 | 
						|
            return True
 | 
						|
 | 
						|
        # build library
 | 
						|
        if Target == 'libraries':
 | 
						|
            pass
 | 
						|
 | 
						|
        # not build modules
 | 
						|
 | 
						|
 | 
						|
        # cleanall
 | 
						|
        if Target == 'cleanall':
 | 
						|
            try:
 | 
						|
                #os.rmdir(AutoGenObject.BuildDir)
 | 
						|
                RemoveDirectory(AutoGenObject.BuildDir, True)
 | 
						|
            except WindowsError as X:
 | 
						|
                EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
 | 
						|
        return True
 | 
						|
 | 
						|
    ## Rebase module image and Get function address for the input module list.
 | 
						|
    #
 | 
						|
    def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):
 | 
						|
        if ModeIsSmm:
 | 
						|
            AddrIsOffset = False
 | 
						|
        for InfFile in ModuleList:
 | 
						|
            sys.stdout.write (".")
 | 
						|
            sys.stdout.flush()
 | 
						|
            ModuleInfo = ModuleList[InfFile]
 | 
						|
            ModuleName = ModuleInfo.BaseName
 | 
						|
            ModuleOutputImage = ModuleInfo.Image.FileName
 | 
						|
            ModuleDebugImage  = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')
 | 
						|
            ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
 | 
						|
            if not ModeIsSmm:
 | 
						|
                BaseAddress = BaseAddress - ModuleInfo.Image.Size
 | 
						|
                #
 | 
						|
                # Update Image to new BaseAddress by GenFw tool
 | 
						|
                #
 | 
						|
                LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
 | 
						|
                LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
 | 
						|
            else:
 | 
						|
                #
 | 
						|
                # Set new address to the section header only for SMM driver.
 | 
						|
                #
 | 
						|
                LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
 | 
						|
                LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
 | 
						|
            #
 | 
						|
            # Collect function address from Map file
 | 
						|
            #
 | 
						|
            ImageMapTable = ModuleOutputImage.replace('.efi', '.map')
 | 
						|
            FunctionList = []
 | 
						|
            if os.path.exists(ImageMapTable):
 | 
						|
                OrigImageBaseAddress = 0
 | 
						|
                ImageMap = open(ImageMapTable, 'r')
 | 
						|
                for LinStr in ImageMap:
 | 
						|
                    if len (LinStr.strip()) == 0:
 | 
						|
                        continue
 | 
						|
                    #
 | 
						|
                    # Get the preferred address set on link time.
 | 
						|
                    #
 | 
						|
                    if LinStr.find ('Preferred load address is') != -1:
 | 
						|
                        StrList = LinStr.split()
 | 
						|
                        OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)
 | 
						|
 | 
						|
                    StrList = LinStr.split()
 | 
						|
                    if len (StrList) > 4:
 | 
						|
                        if StrList[3] == 'f' or StrList[3] == 'F':
 | 
						|
                            Name = StrList[1]
 | 
						|
                            RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress
 | 
						|
                            FunctionList.append ((Name, RelativeAddress))
 | 
						|
 | 
						|
                ImageMap.close()
 | 
						|
            #
 | 
						|
            # Add general information.
 | 
						|
            #
 | 
						|
            if ModeIsSmm:
 | 
						|
                MapBuffer.append('\n\n%s (Fixed SMRAM Offset,   BaseAddress=0x%010X,  EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
 | 
						|
            elif AddrIsOffset:
 | 
						|
                MapBuffer.append('\n\n%s (Fixed Memory Offset,  BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))
 | 
						|
            else:
 | 
						|
                MapBuffer.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X,  EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
 | 
						|
            #
 | 
						|
            # Add guid and general seciton section.
 | 
						|
            #
 | 
						|
            TextSectionAddress = 0
 | 
						|
            DataSectionAddress = 0
 | 
						|
            for SectionHeader in ModuleInfo.Image.SectionHeaderList:
 | 
						|
                if SectionHeader[0] == '.text':
 | 
						|
                    TextSectionAddress = SectionHeader[1]
 | 
						|
                elif SectionHeader[0] in ['.data', '.sdata']:
 | 
						|
                    DataSectionAddress = SectionHeader[1]
 | 
						|
            if AddrIsOffset:
 | 
						|
                MapBuffer.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))
 | 
						|
            else:
 | 
						|
                MapBuffer.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))
 | 
						|
            #
 | 
						|
            # Add debug image full path.
 | 
						|
            #
 | 
						|
            MapBuffer.append('(IMAGE=%s)\n\n' % (ModuleDebugImage))
 | 
						|
            #
 | 
						|
            # Add function address
 | 
						|
            #
 | 
						|
            for Function in FunctionList:
 | 
						|
                if AddrIsOffset:
 | 
						|
                    MapBuffer.append('  -0x%010X    %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))
 | 
						|
                else:
 | 
						|
                    MapBuffer.append('  0x%010X    %s\n' % (BaseAddress + Function[1], Function[0]))
 | 
						|
            ImageMap.close()
 | 
						|
 | 
						|
            #
 | 
						|
            # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
 | 
						|
            #
 | 
						|
            if ModeIsSmm:
 | 
						|
                BaseAddress = BaseAddress + ModuleInfo.Image.Size
 | 
						|
 | 
						|
    ## Collect MAP information of all FVs
 | 
						|
    #
 | 
						|
    def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):
 | 
						|
        if self.Fdf:
 | 
						|
            # First get the XIP base address for FV map file.
 | 
						|
            GuidPattern = re.compile("[-a-fA-F0-9]+")
 | 
						|
            GuidName = re.compile(r"\(GUID=[-a-fA-F0-9]+")
 | 
						|
            for FvName in Wa.FdfProfile.FvDict:
 | 
						|
                FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')
 | 
						|
                if not os.path.exists(FvMapBuffer):
 | 
						|
                    continue
 | 
						|
                FvMap = open(FvMapBuffer, 'r')
 | 
						|
                #skip FV size information
 | 
						|
                FvMap.readline()
 | 
						|
                FvMap.readline()
 | 
						|
                FvMap.readline()
 | 
						|
                FvMap.readline()
 | 
						|
                for Line in FvMap:
 | 
						|
                    MatchGuid = GuidPattern.match(Line)
 | 
						|
                    if MatchGuid is not None:
 | 
						|
                        #
 | 
						|
                        # Replace GUID with module name
 | 
						|
                        #
 | 
						|
                        GuidString = MatchGuid.group()
 | 
						|
                        if GuidString.upper() in ModuleList:
 | 
						|
                            Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)
 | 
						|
                    MapBuffer.append(Line)
 | 
						|
                    #
 | 
						|
                    # Add the debug image full path.
 | 
						|
                    #
 | 
						|
                    MatchGuid = GuidName.match(Line)
 | 
						|
                    if MatchGuid is not None:
 | 
						|
                        GuidString = MatchGuid.group().split("=")[1]
 | 
						|
                        if GuidString.upper() in ModuleList:
 | 
						|
                            MapBuffer.append('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))
 | 
						|
 | 
						|
                FvMap.close()
 | 
						|
 | 
						|
    ## Collect MAP information of all modules
 | 
						|
    #
 | 
						|
    def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):
 | 
						|
        sys.stdout.write ("Generate Load Module At Fix Address Map")
 | 
						|
        sys.stdout.flush()
 | 
						|
        PatchEfiImageList = []
 | 
						|
        PeiModuleList  = {}
 | 
						|
        BtModuleList   = {}
 | 
						|
        RtModuleList   = {}
 | 
						|
        SmmModuleList  = {}
 | 
						|
        PeiSize = 0
 | 
						|
        BtSize  = 0
 | 
						|
        RtSize  = 0
 | 
						|
        # reserve 4K size in SMRAM to make SMM module address not from 0.
 | 
						|
        SmmSize = 0x1000
 | 
						|
        for ModuleGuid in ModuleList:
 | 
						|
            Module = ModuleList[ModuleGuid]
 | 
						|
            GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)
 | 
						|
 | 
						|
            OutputImageFile = ''
 | 
						|
            for ResultFile in Module.CodaTargetList:
 | 
						|
                if str(ResultFile.Target).endswith('.efi'):
 | 
						|
                    #
 | 
						|
                    # module list for PEI, DXE, RUNTIME and SMM
 | 
						|
                    #
 | 
						|
                    OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')
 | 
						|
                    ImageClass = PeImageClass (OutputImageFile)
 | 
						|
                    if not ImageClass.IsValid:
 | 
						|
                        EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)
 | 
						|
                    ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)
 | 
						|
                    if Module.ModuleType in [SUP_MODULE_PEI_CORE, SUP_MODULE_PEIM, EDK_COMPONENT_TYPE_COMBINED_PEIM_DRIVER, EDK_COMPONENT_TYPE_PIC_PEIM, EDK_COMPONENT_TYPE_RELOCATABLE_PEIM, SUP_MODULE_DXE_CORE]:
 | 
						|
                        PeiModuleList[Module.MetaFile] = ImageInfo
 | 
						|
                        PeiSize += ImageInfo.Image.Size
 | 
						|
                    elif Module.ModuleType in [EDK_COMPONENT_TYPE_BS_DRIVER, SUP_MODULE_DXE_DRIVER, SUP_MODULE_UEFI_DRIVER]:
 | 
						|
                        BtModuleList[Module.MetaFile] = ImageInfo
 | 
						|
                        BtSize += ImageInfo.Image.Size
 | 
						|
                    elif Module.ModuleType in [SUP_MODULE_DXE_RUNTIME_DRIVER, EDK_COMPONENT_TYPE_RT_DRIVER, SUP_MODULE_DXE_SAL_DRIVER, EDK_COMPONENT_TYPE_SAL_RT_DRIVER]:
 | 
						|
                        RtModuleList[Module.MetaFile] = ImageInfo
 | 
						|
                        RtSize += ImageInfo.Image.Size
 | 
						|
                    elif Module.ModuleType in [SUP_MODULE_SMM_CORE, SUP_MODULE_DXE_SMM_DRIVER, SUP_MODULE_MM_STANDALONE, SUP_MODULE_MM_CORE_STANDALONE]:
 | 
						|
                        SmmModuleList[Module.MetaFile] = ImageInfo
 | 
						|
                        SmmSize += ImageInfo.Image.Size
 | 
						|
                        if Module.ModuleType == SUP_MODULE_DXE_SMM_DRIVER:
 | 
						|
                            PiSpecVersion = Module.Module.Specification.get('PI_SPECIFICATION_VERSION', '0x00000000')
 | 
						|
                            # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
 | 
						|
                            if int(PiSpecVersion, 16) < 0x0001000A:
 | 
						|
                                BtModuleList[Module.MetaFile] = ImageInfo
 | 
						|
                                BtSize += ImageInfo.Image.Size
 | 
						|
                    break
 | 
						|
            #
 | 
						|
            # EFI image is final target.
 | 
						|
            # Check EFI image contains patchable FixAddress related PCDs.
 | 
						|
            #
 | 
						|
            if OutputImageFile != '':
 | 
						|
                ModuleIsPatch = False
 | 
						|
                for Pcd in Module.ModulePcdList:
 | 
						|
                    if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:
 | 
						|
                        ModuleIsPatch = True
 | 
						|
                        break
 | 
						|
                if not ModuleIsPatch:
 | 
						|
                    for Pcd in Module.LibraryPcdList:
 | 
						|
                        if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:
 | 
						|
                            ModuleIsPatch = True
 | 
						|
                            break
 | 
						|
 | 
						|
                if not ModuleIsPatch:
 | 
						|
                    continue
 | 
						|
                #
 | 
						|
                # Module includes the patchable load fix address PCDs.
 | 
						|
                # It will be fixed up later.
 | 
						|
                #
 | 
						|
                PatchEfiImageList.append (OutputImageFile)
 | 
						|
 | 
						|
        #
 | 
						|
        # Get Top Memory address
 | 
						|
        #
 | 
						|
        ReservedRuntimeMemorySize = 0
 | 
						|
        TopMemoryAddress = 0
 | 
						|
        if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:
 | 
						|
            TopMemoryAddress = 0
 | 
						|
        else:
 | 
						|
            TopMemoryAddress = self.LoadFixAddress
 | 
						|
            if TopMemoryAddress < RtSize + BtSize + PeiSize:
 | 
						|
                EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
 | 
						|
 | 
						|
        #
 | 
						|
        # Patch FixAddress related PCDs into EFI image
 | 
						|
        #
 | 
						|
        for EfiImage in PatchEfiImageList:
 | 
						|
            EfiImageMap = EfiImage.replace('.efi', '.map')
 | 
						|
            if not os.path.exists(EfiImageMap):
 | 
						|
                continue
 | 
						|
            #
 | 
						|
            # Get PCD offset in EFI image by GenPatchPcdTable function
 | 
						|
            #
 | 
						|
            PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)
 | 
						|
            #
 | 
						|
            # Patch real PCD value by PatchPcdValue tool
 | 
						|
            #
 | 
						|
            for PcdInfo in PcdTable:
 | 
						|
                ReturnValue = 0
 | 
						|
                if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:
 | 
						|
                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize // 0x1000))
 | 
						|
                elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:
 | 
						|
                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize // 0x1000))
 | 
						|
                elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:
 | 
						|
                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize // 0x1000))
 | 
						|
                elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:
 | 
						|
                    ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize // 0x1000))
 | 
						|
                if ReturnValue != 0:
 | 
						|
                    EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)
 | 
						|
 | 
						|
        MapBuffer.append('PEI_CODE_PAGE_NUMBER      = 0x%x\n' % (PeiSize // 0x1000))
 | 
						|
        MapBuffer.append('BOOT_CODE_PAGE_NUMBER     = 0x%x\n' % (BtSize // 0x1000))
 | 
						|
        MapBuffer.append('RUNTIME_CODE_PAGE_NUMBER  = 0x%x\n' % (RtSize // 0x1000))
 | 
						|
        if len (SmmModuleList) > 0:
 | 
						|
            MapBuffer.append('SMM_CODE_PAGE_NUMBER      = 0x%x\n' % (SmmSize // 0x1000))
 | 
						|
 | 
						|
        PeiBaseAddr = TopMemoryAddress - RtSize - BtSize
 | 
						|
        BtBaseAddr  = TopMemoryAddress - RtSize
 | 
						|
        RtBaseAddr  = TopMemoryAddress - ReservedRuntimeMemorySize
 | 
						|
 | 
						|
        self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)
 | 
						|
        self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)
 | 
						|
        self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)
 | 
						|
        self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset=False, ModeIsSmm=True)
 | 
						|
        MapBuffer.append('\n\n')
 | 
						|
        sys.stdout.write ("\n")
 | 
						|
        sys.stdout.flush()
 | 
						|
 | 
						|
    ## Save platform Map file
 | 
						|
    #
 | 
						|
    def _SaveMapFile (self, MapBuffer, Wa):
 | 
						|
        #
 | 
						|
        # Map file path is got.
 | 
						|
        #
 | 
						|
        MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')
 | 
						|
        #
 | 
						|
        # Save address map into MAP file.
 | 
						|
        #
 | 
						|
        SaveFileOnChange(MapFilePath, ''.join(MapBuffer), False)
 | 
						|
        if self.LoadFixAddress != 0:
 | 
						|
            sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath))
 | 
						|
        sys.stdout.flush()
 | 
						|
 | 
						|
    ## Build active platform for different build targets and different tool chains
 | 
						|
    #
 | 
						|
    def _BuildPlatform(self):
 | 
						|
        SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)
 | 
						|
        for BuildTarget in self.BuildTargetList:
 | 
						|
            GlobalData.gGlobalDefines['TARGET'] = BuildTarget
 | 
						|
            index = 0
 | 
						|
            for ToolChain in self.ToolChainList:
 | 
						|
                GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
 | 
						|
                GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
 | 
						|
                GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
 | 
						|
                index += 1
 | 
						|
                Wa = WorkspaceAutoGen(
 | 
						|
                        self.WorkspaceDir,
 | 
						|
                        self.PlatformFile,
 | 
						|
                        BuildTarget,
 | 
						|
                        ToolChain,
 | 
						|
                        self.ArchList,
 | 
						|
                        self.BuildDatabase,
 | 
						|
                        self.TargetTxt,
 | 
						|
                        self.ToolDef,
 | 
						|
                        self.Fdf,
 | 
						|
                        self.FdList,
 | 
						|
                        self.FvList,
 | 
						|
                        self.CapList,
 | 
						|
                        self.SkuId,
 | 
						|
                        self.UniFlag,
 | 
						|
                        self.Progress
 | 
						|
                        )
 | 
						|
                self.Fdf = Wa.FdfFile
 | 
						|
                self.LoadFixAddress = Wa.Platform.LoadFixAddress
 | 
						|
                self.BuildReport.AddPlatformReport(Wa)
 | 
						|
                self.Progress.Stop("done!")
 | 
						|
 | 
						|
                # Add ffs build to makefile
 | 
						|
                CmdListDict = {}
 | 
						|
                if GlobalData.gEnableGenfdsMultiThread and self.Fdf:
 | 
						|
                    CmdListDict = self._GenFfsCmd(Wa.ArchList)
 | 
						|
 | 
						|
                for Arch in Wa.ArchList:
 | 
						|
                    PcdMaList    = []
 | 
						|
                    GlobalData.gGlobalDefines['ARCH'] = Arch
 | 
						|
                    Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
 | 
						|
                    for Module in Pa.Platform.Modules:
 | 
						|
                        # Get ModuleAutoGen object to generate C code file and makefile
 | 
						|
                        Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)
 | 
						|
                        if Ma is None:
 | 
						|
                            continue
 | 
						|
                        if Ma.PcdIsDriver:
 | 
						|
                            Ma.PlatformInfo = Pa
 | 
						|
                            Ma.Workspace = Wa
 | 
						|
                            PcdMaList.append(Ma)
 | 
						|
                        self.BuildModules.append(Ma)
 | 
						|
                    Pa.DataPipe.DataContainer = {"FfsCommand":CmdListDict}
 | 
						|
                    Pa.DataPipe.DataContainer = {"Workspace_timestamp": Wa._SrcTimeStamp}
 | 
						|
                    self._BuildPa(self.Target, Pa, FfsCommand=CmdListDict,PcdMaList=PcdMaList)
 | 
						|
 | 
						|
                # Create MAP file when Load Fix Address is enabled.
 | 
						|
                if self.Target in ["", "all", "fds"]:
 | 
						|
                    for Arch in Wa.ArchList:
 | 
						|
                        GlobalData.gGlobalDefines['ARCH'] = Arch
 | 
						|
                        #
 | 
						|
                        # Check whether the set fix address is above 4G for 32bit image.
 | 
						|
                        #
 | 
						|
                        if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
 | 
						|
                            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")
 | 
						|
                    #
 | 
						|
                    # Get Module List
 | 
						|
                    #
 | 
						|
                    ModuleList = {}
 | 
						|
                    for Pa in Wa.AutoGenObjectList:
 | 
						|
                        for Ma in Pa.ModuleAutoGenList:
 | 
						|
                            if Ma is None:
 | 
						|
                                continue
 | 
						|
                            if not Ma.IsLibrary:
 | 
						|
                                ModuleList[Ma.Guid.upper()] = Ma
 | 
						|
 | 
						|
                    MapBuffer = []
 | 
						|
                    if self.LoadFixAddress != 0:
 | 
						|
                        #
 | 
						|
                        # Rebase module to the preferred memory address before GenFds
 | 
						|
                        #
 | 
						|
                        self._CollectModuleMapBuffer(MapBuffer, ModuleList)
 | 
						|
                    if self.Fdf:
 | 
						|
                        #
 | 
						|
                        # create FDS again for the updated EFI image
 | 
						|
                        #
 | 
						|
                        self._Build("fds", Wa)
 | 
						|
                        #
 | 
						|
                        # Create MAP file for all platform FVs after GenFds.
 | 
						|
                        #
 | 
						|
                        self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
 | 
						|
                    #
 | 
						|
                    # Save MAP buffer into MAP file.
 | 
						|
                    #
 | 
						|
                    self._SaveMapFile (MapBuffer, Wa)
 | 
						|
                self.CreateGuidedSectionToolsFile(Wa)
 | 
						|
 | 
						|
    ## Build active module for different build targets, different tool chains and different archs
 | 
						|
    #
 | 
						|
    def _BuildModule(self):
 | 
						|
        for BuildTarget in self.BuildTargetList:
 | 
						|
            GlobalData.gGlobalDefines['TARGET'] = BuildTarget
 | 
						|
            index = 0
 | 
						|
            for ToolChain in self.ToolChainList:
 | 
						|
                WorkspaceAutoGenTime = time.time()
 | 
						|
                GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
 | 
						|
                GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
 | 
						|
                GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
 | 
						|
                index += 1
 | 
						|
                #
 | 
						|
                # module build needs platform build information, so get platform
 | 
						|
                # AutoGen first
 | 
						|
                #
 | 
						|
                Wa = WorkspaceAutoGen(
 | 
						|
                        self.WorkspaceDir,
 | 
						|
                        self.PlatformFile,
 | 
						|
                        BuildTarget,
 | 
						|
                        ToolChain,
 | 
						|
                        self.ArchList,
 | 
						|
                        self.BuildDatabase,
 | 
						|
                        self.TargetTxt,
 | 
						|
                        self.ToolDef,
 | 
						|
                        self.Fdf,
 | 
						|
                        self.FdList,
 | 
						|
                        self.FvList,
 | 
						|
                        self.CapList,
 | 
						|
                        self.SkuId,
 | 
						|
                        self.UniFlag,
 | 
						|
                        self.Progress,
 | 
						|
                        self.ModuleFile
 | 
						|
                        )
 | 
						|
                self.Fdf = Wa.FdfFile
 | 
						|
                self.LoadFixAddress = Wa.Platform.LoadFixAddress
 | 
						|
                Wa.CreateMakeFile(False)
 | 
						|
                # Add ffs build to makefile
 | 
						|
                CmdListDict = None
 | 
						|
                if GlobalData.gEnableGenfdsMultiThread and self.Fdf:
 | 
						|
                    CmdListDict = self._GenFfsCmd(Wa.ArchList)
 | 
						|
 | 
						|
                # Add Platform and Package level hash in share_data for module hash calculation later
 | 
						|
                if GlobalData.gBinCacheSource or GlobalData.gBinCacheDest:
 | 
						|
                    GlobalData.gCacheIR[('PlatformHash')] = GlobalData.gPlatformHash
 | 
						|
                    for PkgName in GlobalData.gPackageHash.keys():
 | 
						|
                        GlobalData.gCacheIR[(PkgName, 'PackageHash')] = GlobalData.gPackageHash[PkgName]
 | 
						|
                GlobalData.file_lock = mp.Lock()
 | 
						|
                GlobalData.cache_lock = mp.Lock()
 | 
						|
                GlobalData.FfsCmd = CmdListDict
 | 
						|
 | 
						|
                self.Progress.Stop("done!")
 | 
						|
                MaList = []
 | 
						|
                ExitFlag = threading.Event()
 | 
						|
                ExitFlag.clear()
 | 
						|
                self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))
 | 
						|
                for Arch in Wa.ArchList:
 | 
						|
                    AutoGenStart = time.time()
 | 
						|
                    GlobalData.gGlobalDefines['ARCH'] = Arch
 | 
						|
                    Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
 | 
						|
                    GlobalData.libConstPcd = Pa.DataPipe.Get("LibConstPcd")
 | 
						|
                    GlobalData.Refes = Pa.DataPipe.Get("REFS")
 | 
						|
                    for Module in Pa.Platform.Modules:
 | 
						|
                        if self.ModuleFile.Dir == Module.Dir and self.ModuleFile.Name == Module.Name:
 | 
						|
                            Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)
 | 
						|
                            if Ma is None:
 | 
						|
                                continue
 | 
						|
                            if Ma.PcdIsDriver:
 | 
						|
                                Ma.PlatformInfo = Pa
 | 
						|
                                Ma.Workspace = Wa
 | 
						|
                            MaList.append(Ma)
 | 
						|
 | 
						|
                            if GlobalData.gBinCacheSource and self.Target in [None, "", "all"]:
 | 
						|
                                Ma.GenModuleFilesHash(GlobalData.gCacheIR)
 | 
						|
                                Ma.GenPreMakefileHash(GlobalData.gCacheIR)
 | 
						|
                                if Ma.CanSkipbyPreMakefileCache(GlobalData.gCacheIR):
 | 
						|
                                    self.HashSkipModules.append(Ma)
 | 
						|
                                    EdkLogger.quiet("cache hit: %s[%s]" % (Ma.MetaFile.Path, Ma.Arch))
 | 
						|
                                    continue
 | 
						|
 | 
						|
                            # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
 | 
						|
                            if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
 | 
						|
                                # for target which must generate AutoGen code and makefile
 | 
						|
                                if not self.SkipAutoGen or self.Target == 'genc':
 | 
						|
                                    self.Progress.Start("Generating code")
 | 
						|
                                    Ma.CreateCodeFile(True)
 | 
						|
                                    self.Progress.Stop("done!")
 | 
						|
                                if self.Target == "genc":
 | 
						|
                                    return True
 | 
						|
                                if not self.SkipAutoGen or self.Target == 'genmake':
 | 
						|
                                    self.Progress.Start("Generating makefile")
 | 
						|
                                    if CmdListDict and self.Fdf and (Module.Path, Arch) in CmdListDict:
 | 
						|
                                        Ma.CreateMakeFile(True, CmdListDict[Module.Path, Arch])
 | 
						|
                                        del CmdListDict[Module.Path, Arch]
 | 
						|
                                    else:
 | 
						|
                                        Ma.CreateMakeFile(True)
 | 
						|
                                    self.Progress.Stop("done!")
 | 
						|
                                if self.Target == "genmake":
 | 
						|
                                    return True
 | 
						|
 | 
						|
                                if GlobalData.gBinCacheSource and self.Target in [None, "", "all"]:
 | 
						|
                                    Ma.GenMakeHeaderFilesHash(GlobalData.gCacheIR)
 | 
						|
                                    Ma.GenMakeHash(GlobalData.gCacheIR)
 | 
						|
                                    if Ma.CanSkipbyMakeCache(GlobalData.gCacheIR):
 | 
						|
                                        self.HashSkipModules.append(Ma)
 | 
						|
                                        EdkLogger.quiet("cache hit: %s[%s]" % (Ma.MetaFile.Path, Ma.Arch))
 | 
						|
                                        continue
 | 
						|
                                    else:
 | 
						|
                                        EdkLogger.quiet("cache miss: %s[%s]" % (Ma.MetaFile.Path, Ma.Arch))
 | 
						|
                                        Ma.PrintFirstMakeCacheMissFile(GlobalData.gCacheIR)
 | 
						|
 | 
						|
                            self.BuildModules.append(Ma)
 | 
						|
                            # Initialize all modules in tracking to 'FAIL'
 | 
						|
                            GlobalData.gModuleBuildTracking[Ma] = 'FAIL'
 | 
						|
                    self.AutoGenTime += int(round((time.time() - AutoGenStart)))
 | 
						|
                    MakeStart = time.time()
 | 
						|
                    for Ma in self.BuildModules:
 | 
						|
                        if not Ma.IsBinaryModule:
 | 
						|
                            Bt = BuildTask.New(ModuleMakeUnit(Ma, Pa.BuildCommand,self.Target))
 | 
						|
                        # Break build if any build thread has error
 | 
						|
                        if BuildTask.HasError():
 | 
						|
                            # we need a full version of makefile for platform
 | 
						|
                            ExitFlag.set()
 | 
						|
                            BuildTask.WaitForComplete()
 | 
						|
                            self.invalidateHash()
 | 
						|
                            Pa.CreateMakeFile(False)
 | 
						|
                            EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
 | 
						|
                        # Start task scheduler
 | 
						|
                        if not BuildTask.IsOnGoing():
 | 
						|
                            BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
 | 
						|
 | 
						|
                    # in case there's an interruption. we need a full version of makefile for platform
 | 
						|
                    Pa.CreateMakeFile(False)
 | 
						|
                    if BuildTask.HasError():
 | 
						|
                        self.invalidateHash()
 | 
						|
                        EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
 | 
						|
                    self.MakeTime += int(round((time.time() - MakeStart)))
 | 
						|
 | 
						|
                MakeContiue = time.time()
 | 
						|
                ExitFlag.set()
 | 
						|
                BuildTask.WaitForComplete()
 | 
						|
                self.CreateAsBuiltInf()
 | 
						|
                if GlobalData.gBinCacheDest:
 | 
						|
                    self.UpdateBuildCache()
 | 
						|
                self.BuildModules = []
 | 
						|
                self.MakeTime += int(round((time.time() - MakeContiue)))
 | 
						|
                if BuildTask.HasError():
 | 
						|
                    self.invalidateHash()
 | 
						|
                    EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
 | 
						|
 | 
						|
                self.BuildReport.AddPlatformReport(Wa, MaList)
 | 
						|
                if MaList == []:
 | 
						|
                    EdkLogger.error(
 | 
						|
                                'build',
 | 
						|
                                BUILD_ERROR,
 | 
						|
                                "Module for [%s] is not a component of active platform."\
 | 
						|
                                " Please make sure that the ARCH and inf file path are"\
 | 
						|
                                " given in the same as in [%s]" % \
 | 
						|
                                    (', '.join(Wa.ArchList), self.PlatformFile),
 | 
						|
                                ExtraData=self.ModuleFile
 | 
						|
                                )
 | 
						|
                # Create MAP file when Load Fix Address is enabled.
 | 
						|
                if self.Target == "fds" and self.Fdf:
 | 
						|
                    for Arch in Wa.ArchList:
 | 
						|
                        #
 | 
						|
                        # Check whether the set fix address is above 4G for 32bit image.
 | 
						|
                        #
 | 
						|
                        if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
 | 
						|
                            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")
 | 
						|
                    #
 | 
						|
                    # Get Module List
 | 
						|
                    #
 | 
						|
                    ModuleList = {}
 | 
						|
                    for Pa in Wa.AutoGenObjectList:
 | 
						|
                        for Ma in Pa.ModuleAutoGenList:
 | 
						|
                            if Ma is None:
 | 
						|
                                continue
 | 
						|
                            if not Ma.IsLibrary:
 | 
						|
                                ModuleList[Ma.Guid.upper()] = Ma
 | 
						|
 | 
						|
                    MapBuffer = []
 | 
						|
                    if self.LoadFixAddress != 0:
 | 
						|
                        #
 | 
						|
                        # Rebase module to the preferred memory address before GenFds
 | 
						|
                        #
 | 
						|
                        self._CollectModuleMapBuffer(MapBuffer, ModuleList)
 | 
						|
                    #
 | 
						|
                    # create FDS again for the updated EFI image
 | 
						|
                    #
 | 
						|
                    GenFdsStart = time.time()
 | 
						|
                    self._Build("fds", Wa)
 | 
						|
                    self.GenFdsTime += int(round((time.time() - GenFdsStart)))
 | 
						|
                    #
 | 
						|
                    # Create MAP file for all platform FVs after GenFds.
 | 
						|
                    #
 | 
						|
                    self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
 | 
						|
                    #
 | 
						|
                    # Save MAP buffer into MAP file.
 | 
						|
                    #
 | 
						|
                    self._SaveMapFile (MapBuffer, Wa)
 | 
						|
        self.invalidateHash()
 | 
						|
 | 
						|
    def _GenFfsCmd(self,ArchList):
 | 
						|
        # convert dictionary of Cmd:(Inf,Arch)
 | 
						|
        # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
 | 
						|
        CmdSetDict = defaultdict(set)
 | 
						|
        GenFfsDict = GenFds.GenFfsMakefile('', GlobalData.gFdfParser, self, ArchList, GlobalData)
 | 
						|
        for Cmd in GenFfsDict:
 | 
						|
            tmpInf, tmpArch = GenFfsDict[Cmd]
 | 
						|
            CmdSetDict[tmpInf, tmpArch].add(Cmd)
 | 
						|
        return CmdSetDict
 | 
						|
    def VerifyAutoGenFiles(self):
 | 
						|
        AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt")
 | 
						|
        try:
 | 
						|
            with open(AutoGenIdFile) as fd:
 | 
						|
                lines = fd.readlines()
 | 
						|
        except:
 | 
						|
            return None
 | 
						|
        for line in lines:
 | 
						|
            if "Arch" in line:
 | 
						|
                ArchList = line.strip().split("=")[1].split("|")
 | 
						|
            if "BuildDir" in line:
 | 
						|
                BuildDir = line.split("=")[1].strip()
 | 
						|
            if "PlatformGuid" in line:
 | 
						|
                PlatformGuid = line.split("=")[1].strip()
 | 
						|
        GlobalVarList = []
 | 
						|
        for arch in ArchList:
 | 
						|
            global_var = os.path.join(BuildDir, "GlobalVar_%s_%s.bin" % (str(PlatformGuid),arch))
 | 
						|
            if not os.path.exists(global_var):
 | 
						|
                return None
 | 
						|
            GlobalVarList.append(global_var)
 | 
						|
        for global_var in GlobalVarList:
 | 
						|
            data_pipe = MemoryDataPipe()
 | 
						|
            data_pipe.load(global_var)
 | 
						|
            target = data_pipe.Get("P_Info").get("Target")
 | 
						|
            toolchain = data_pipe.Get("P_Info").get("ToolChain")
 | 
						|
            archlist = data_pipe.Get("P_Info").get("ArchList")
 | 
						|
            Arch = data_pipe.Get("P_Info").get("Arch")
 | 
						|
            active_p = data_pipe.Get("P_Info").get("ActivePlatform")
 | 
						|
            workspacedir = data_pipe.Get("P_Info").get("WorkspaceDir")
 | 
						|
            PackagesPath = os.getenv("PACKAGES_PATH")
 | 
						|
            mws.setWs(workspacedir, PackagesPath)
 | 
						|
            LibraryBuildDirectoryList = data_pipe.Get("LibraryBuildDirectoryList")
 | 
						|
            ModuleBuildDirectoryList = data_pipe.Get("ModuleBuildDirectoryList")
 | 
						|
 | 
						|
            for m_build_dir in LibraryBuildDirectoryList:
 | 
						|
                if not os.path.exists(os.path.join(m_build_dir,GenMake.BuildFile._FILE_NAME_[GenMake.gMakeType])):
 | 
						|
                    return None
 | 
						|
            for m_build_dir in ModuleBuildDirectoryList:
 | 
						|
                if not os.path.exists(os.path.join(m_build_dir,GenMake.BuildFile._FILE_NAME_[GenMake.gMakeType])):
 | 
						|
                    return None
 | 
						|
            Wa = WorkSpaceInfo(
 | 
						|
                workspacedir,active_p,target,toolchain,archlist
 | 
						|
                )
 | 
						|
            Pa = PlatformInfo(Wa, active_p, target, toolchain, Arch,data_pipe)
 | 
						|
            Wa.AutoGenObjectList.append(Pa)
 | 
						|
        return Wa
 | 
						|
    def SetupMakeSetting(self,Wa):
 | 
						|
        BuildModules = []
 | 
						|
        for Pa in Wa.AutoGenObjectList:
 | 
						|
            for m in Pa._MbList:
 | 
						|
                ma = ModuleAutoGen(Wa,m.MetaFile, Pa.BuildTarget, Wa.ToolChain, Pa.Arch, Pa.MetaFile,Pa.DataPipe)
 | 
						|
                BuildModules.append(ma)
 | 
						|
        fdf_file = Wa.FlashDefinition
 | 
						|
        if fdf_file:
 | 
						|
            Fdf = FdfParser(fdf_file.Path)
 | 
						|
            Fdf.ParseFile()
 | 
						|
            GlobalData.gFdfParser = Fdf
 | 
						|
            if Fdf.CurrentFdName and Fdf.CurrentFdName in Fdf.Profile.FdDict:
 | 
						|
                FdDict = Fdf.Profile.FdDict[Fdf.CurrentFdName]
 | 
						|
                for FdRegion in FdDict.RegionList:
 | 
						|
                    if str(FdRegion.RegionType) is 'FILE' and self.Platform.VpdToolGuid in str(FdRegion.RegionDataList):
 | 
						|
                        if int(FdRegion.Offset) % 8 != 0:
 | 
						|
                            EdkLogger.error("build", FORMAT_INVALID, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion.Offset))
 | 
						|
            Wa.FdfProfile = Fdf.Profile
 | 
						|
            self.Fdf = Fdf
 | 
						|
        else:
 | 
						|
            self.Fdf = None
 | 
						|
        return BuildModules
 | 
						|
 | 
						|
    ## Build a platform in multi-thread mode
 | 
						|
    #
 | 
						|
    def PerformAutoGen(self,BuildTarget,ToolChain):
 | 
						|
        WorkspaceAutoGenTime = time.time()
 | 
						|
        Wa = WorkspaceAutoGen(
 | 
						|
                self.WorkspaceDir,
 | 
						|
                self.PlatformFile,
 | 
						|
                BuildTarget,
 | 
						|
                ToolChain,
 | 
						|
                self.ArchList,
 | 
						|
                self.BuildDatabase,
 | 
						|
                self.TargetTxt,
 | 
						|
                self.ToolDef,
 | 
						|
                self.Fdf,
 | 
						|
                self.FdList,
 | 
						|
                self.FvList,
 | 
						|
                self.CapList,
 | 
						|
                self.SkuId,
 | 
						|
                self.UniFlag,
 | 
						|
                self.Progress
 | 
						|
                )
 | 
						|
        self.Fdf = Wa.FdfFile
 | 
						|
        self.LoadFixAddress = Wa.Platform.LoadFixAddress
 | 
						|
        self.BuildReport.AddPlatformReport(Wa)
 | 
						|
        Wa.CreateMakeFile(False)
 | 
						|
 | 
						|
                # Add ffs build to makefile
 | 
						|
        CmdListDict = {}
 | 
						|
        if GlobalData.gEnableGenfdsMultiThread and self.Fdf:
 | 
						|
            CmdListDict = self._GenFfsCmd(Wa.ArchList)
 | 
						|
 | 
						|
        # Add Platform and Package level hash in share_data for module hash calculation later
 | 
						|
        if GlobalData.gBinCacheSource or GlobalData.gBinCacheDest:
 | 
						|
            GlobalData.gCacheIR[('PlatformHash')] = GlobalData.gPlatformHash
 | 
						|
            for PkgName in GlobalData.gPackageHash.keys():
 | 
						|
                GlobalData.gCacheIR[(PkgName, 'PackageHash')] = GlobalData.gPackageHash[PkgName]
 | 
						|
 | 
						|
        self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))
 | 
						|
        BuildModules = []
 | 
						|
        TotalModules = []
 | 
						|
        for Arch in Wa.ArchList:
 | 
						|
            PcdMaList    = []
 | 
						|
            AutoGenStart = time.time()
 | 
						|
            GlobalData.gGlobalDefines['ARCH'] = Arch
 | 
						|
            Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
 | 
						|
            if Pa is None:
 | 
						|
                continue
 | 
						|
            ModuleList = []
 | 
						|
            for Inf in Pa.Platform.Modules:
 | 
						|
                ModuleList.append(Inf)
 | 
						|
                    # Add the INF only list in FDF
 | 
						|
            if GlobalData.gFdfParser is not None:
 | 
						|
                for InfName in GlobalData.gFdfParser.Profile.InfList:
 | 
						|
                    Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)
 | 
						|
                    if Inf in Pa.Platform.Modules:
 | 
						|
                        continue
 | 
						|
                    ModuleList.append(Inf)
 | 
						|
            Pa.DataPipe.DataContainer = {"FfsCommand":CmdListDict}
 | 
						|
            Pa.DataPipe.DataContainer = {"Workspace_timestamp": Wa._SrcTimeStamp}
 | 
						|
            Pa.DataPipe.DataContainer = {"CommandTarget": self.Target}
 | 
						|
            Pa.CreateLibModuelDirs()
 | 
						|
            Pa.DataPipe.DataContainer = {"LibraryBuildDirectoryList":Pa.LibraryBuildDirectoryList}
 | 
						|
            Pa.DataPipe.DataContainer = {"ModuleBuildDirectoryList":Pa.ModuleBuildDirectoryList}
 | 
						|
            Pa.DataPipe.DataContainer = {"FdsCommandDict": Wa.GenFdsCommandDict}
 | 
						|
            ModuleCodaFile = {}
 | 
						|
            for ma in Pa.ModuleAutoGenList:
 | 
						|
                ModuleCodaFile[(ma.MetaFile.File,ma.MetaFile.Root,ma.Arch,ma.MetaFile.Path)] = [item.Target for item in ma.CodaTargetList]
 | 
						|
            Pa.DataPipe.DataContainer = {"ModuleCodaFile":ModuleCodaFile}
 | 
						|
            for Module in ModuleList:
 | 
						|
                        # Get ModuleAutoGen object to generate C code file and makefile
 | 
						|
                Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)
 | 
						|
 | 
						|
                if Ma is None:
 | 
						|
                    continue
 | 
						|
                if Ma.PcdIsDriver:
 | 
						|
                    Ma.PlatformInfo = Pa
 | 
						|
                    Ma.Workspace = Wa
 | 
						|
                    PcdMaList.append(Ma)
 | 
						|
                TotalModules.append(Ma)
 | 
						|
                # Initialize all modules in tracking to 'FAIL'
 | 
						|
                GlobalData.gModuleBuildTracking[Ma] = 'FAIL'
 | 
						|
 | 
						|
 | 
						|
            mqueue = mp.Queue()
 | 
						|
            for m in Pa.GetAllModuleInfo:
 | 
						|
                mqueue.put(m)
 | 
						|
            data_pipe_file = os.path.join(Pa.BuildDir, "GlobalVar_%s_%s.bin" % (str(Pa.Guid),Pa.Arch))
 | 
						|
            Pa.DataPipe.dump(data_pipe_file)
 | 
						|
 | 
						|
            autogen_rt, errorcode = self.StartAutoGen(mqueue, Pa.DataPipe, self.SkipAutoGen, PcdMaList,GlobalData.gCacheIR)
 | 
						|
 | 
						|
            # Skip cache hit modules
 | 
						|
            if GlobalData.gBinCacheSource:
 | 
						|
                for Ma in TotalModules:
 | 
						|
                    if (Ma.MetaFile.Path, Ma.Arch) in GlobalData.gCacheIR and \
 | 
						|
                        GlobalData.gCacheIR[(Ma.MetaFile.Path, Ma.Arch)].PreMakeCacheHit:
 | 
						|
                            self.HashSkipModules.append(Ma)
 | 
						|
                            continue
 | 
						|
                    if (Ma.MetaFile.Path, Ma.Arch) in GlobalData.gCacheIR and \
 | 
						|
                        GlobalData.gCacheIR[(Ma.MetaFile.Path, Ma.Arch)].MakeCacheHit:
 | 
						|
                            self.HashSkipModules.append(Ma)
 | 
						|
                            continue
 | 
						|
                    BuildModules.append(Ma)
 | 
						|
            else:
 | 
						|
                BuildModules.extend(TotalModules)
 | 
						|
 | 
						|
            if not autogen_rt:
 | 
						|
                self.AutoGenMgr.TerminateWorkers()
 | 
						|
                self.AutoGenMgr.join(1)
 | 
						|
                raise FatalError(errorcode)
 | 
						|
            self.AutoGenTime += int(round((time.time() - AutoGenStart)))
 | 
						|
        AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt")
 | 
						|
        with open(AutoGenIdFile,"w") as fw:
 | 
						|
            fw.write("Arch=%s\n" % "|".join((Wa.ArchList)))
 | 
						|
            fw.write("BuildDir=%s\n" % Wa.BuildDir)
 | 
						|
            fw.write("PlatformGuid=%s\n" % str(Wa.AutoGenObjectList[0].Guid))
 | 
						|
        self.Progress.Stop("done!")
 | 
						|
        return Wa, BuildModules
 | 
						|
 | 
						|
    def _MultiThreadBuildPlatform(self):
 | 
						|
        SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)
 | 
						|
        for BuildTarget in self.BuildTargetList:
 | 
						|
            GlobalData.gGlobalDefines['TARGET'] = BuildTarget
 | 
						|
            index = 0
 | 
						|
            for ToolChain in self.ToolChainList:
 | 
						|
                GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
 | 
						|
                GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
 | 
						|
                GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
 | 
						|
                index += 1
 | 
						|
                ExitFlag = threading.Event()
 | 
						|
                ExitFlag.clear()
 | 
						|
                if self.SkipAutoGen:
 | 
						|
                    Wa = self.VerifyAutoGenFiles()
 | 
						|
                    if Wa is None:
 | 
						|
                        self.SkipAutoGen = False
 | 
						|
                        Wa, self.BuildModules = self.PerformAutoGen(BuildTarget,ToolChain)
 | 
						|
                    else:
 | 
						|
                        GlobalData.gAutoGenPhase = True
 | 
						|
                        self.BuildModules = self.SetupMakeSetting(Wa)
 | 
						|
                else:
 | 
						|
                    Wa, self.BuildModules = self.PerformAutoGen(BuildTarget,ToolChain)
 | 
						|
                Pa = Wa.AutoGenObjectList[0]
 | 
						|
                GlobalData.gAutoGenPhase = False
 | 
						|
 | 
						|
                if GlobalData.gBinCacheSource:
 | 
						|
                    EdkLogger.quiet("Total cache hit driver num: %s, cache miss driver num: %s" % (len(set(self.HashSkipModules)), len(set(self.BuildModules))))
 | 
						|
                    CacheHitMa = set()
 | 
						|
                    CacheNotHitMa = set()
 | 
						|
                    for IR in GlobalData.gCacheIR.keys():
 | 
						|
                        if 'PlatformHash' in IR or 'PackageHash' in IR:
 | 
						|
                            continue
 | 
						|
                        if GlobalData.gCacheIR[IR].PreMakeCacheHit or GlobalData.gCacheIR[IR].MakeCacheHit:
 | 
						|
                            CacheHitMa.add(IR)
 | 
						|
                        else:
 | 
						|
                            # There might be binary module or module which has .inc files, not count for cache miss
 | 
						|
                            CacheNotHitMa.add(IR)
 | 
						|
                    EdkLogger.quiet("Total module num: %s, cache hit module num: %s" % (len(CacheHitMa)+len(CacheNotHitMa), len(CacheHitMa)))
 | 
						|
 | 
						|
                for Arch in Wa.ArchList:
 | 
						|
                    MakeStart = time.time()
 | 
						|
                    for Ma in set(self.BuildModules):
 | 
						|
                        # Generate build task for the module
 | 
						|
                        if not Ma.IsBinaryModule:
 | 
						|
                            Bt = BuildTask.New(ModuleMakeUnit(Ma, Pa.BuildCommand,self.Target))
 | 
						|
                        # Break build if any build thread has error
 | 
						|
                        if BuildTask.HasError():
 | 
						|
                            # we need a full version of makefile for platform
 | 
						|
                            ExitFlag.set()
 | 
						|
                            BuildTask.WaitForComplete()
 | 
						|
                            self.invalidateHash()
 | 
						|
                            Pa.CreateMakeFile(False)
 | 
						|
                            EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
 | 
						|
                        # Start task scheduler
 | 
						|
                        if not BuildTask.IsOnGoing():
 | 
						|
                            BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
 | 
						|
 | 
						|
                    # in case there's an interruption. we need a full version of makefile for platform
 | 
						|
 | 
						|
                    if BuildTask.HasError():
 | 
						|
                        self.invalidateHash()
 | 
						|
                        EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
 | 
						|
                    self.MakeTime += int(round((time.time() - MakeStart)))
 | 
						|
 | 
						|
                MakeContiue = time.time()
 | 
						|
                #
 | 
						|
                #
 | 
						|
                # All modules have been put in build tasks queue. Tell task scheduler
 | 
						|
                # to exit if all tasks are completed
 | 
						|
                #
 | 
						|
                ExitFlag.set()
 | 
						|
                BuildTask.WaitForComplete()
 | 
						|
                self.CreateAsBuiltInf()
 | 
						|
                if GlobalData.gBinCacheDest:
 | 
						|
                    self.UpdateBuildCache()
 | 
						|
                self.BuildModules = []
 | 
						|
                self.MakeTime += int(round((time.time() - MakeContiue)))
 | 
						|
                #
 | 
						|
                # Check for build error, and raise exception if one
 | 
						|
                # has been signaled.
 | 
						|
                #
 | 
						|
                if BuildTask.HasError():
 | 
						|
                    self.invalidateHash()
 | 
						|
                    EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
 | 
						|
 | 
						|
                # Create MAP file when Load Fix Address is enabled.
 | 
						|
                if self.Target in ["", "all", "fds"]:
 | 
						|
                    for Arch in Wa.ArchList:
 | 
						|
                        #
 | 
						|
                        # Check whether the set fix address is above 4G for 32bit image.
 | 
						|
                        #
 | 
						|
                        if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
 | 
						|
                            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")
 | 
						|
                    #
 | 
						|
                    # Get Module List
 | 
						|
                    #
 | 
						|
                    ModuleList = {ma.Guid.upper():ma for ma in self.BuildModules}
 | 
						|
 | 
						|
                    #
 | 
						|
                    # Rebase module to the preferred memory address before GenFds
 | 
						|
                    #
 | 
						|
                    MapBuffer = []
 | 
						|
                    if self.LoadFixAddress != 0:
 | 
						|
                        self._CollectModuleMapBuffer(MapBuffer, ModuleList)
 | 
						|
 | 
						|
                    if self.Fdf:
 | 
						|
                        #
 | 
						|
                        # Generate FD image if there's a FDF file found
 | 
						|
                        #
 | 
						|
                        GenFdsStart = time.time()
 | 
						|
                        if GenFdsApi(Wa.GenFdsCommandDict, self.Db):
 | 
						|
                            EdkLogger.error("build", COMMAND_FAILURE)
 | 
						|
 | 
						|
                        #
 | 
						|
                        # Create MAP file for all platform FVs after GenFds.
 | 
						|
                        #
 | 
						|
                        self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
 | 
						|
                        self.GenFdsTime += int(round((time.time() - GenFdsStart)))
 | 
						|
                    #
 | 
						|
                    # Save MAP buffer into MAP file.
 | 
						|
                    #
 | 
						|
                    self._SaveMapFile(MapBuffer, Wa)
 | 
						|
                self.CreateGuidedSectionToolsFile(Wa)
 | 
						|
        self.invalidateHash()
 | 
						|
    ## Generate GuidedSectionTools.txt in the FV directories.
 | 
						|
    #
 | 
						|
    def CreateGuidedSectionToolsFile(self,Wa):
 | 
						|
        for BuildTarget in self.BuildTargetList:
 | 
						|
            for ToolChain in self.ToolChainList:
 | 
						|
                FvDir = Wa.FvDir
 | 
						|
                if not os.path.exists(FvDir):
 | 
						|
                    continue
 | 
						|
 | 
						|
                for Arch in self.ArchList:
 | 
						|
                    # Build up the list of supported architectures for this build
 | 
						|
                    prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)
 | 
						|
 | 
						|
                    # Look through the tool definitions for GUIDed tools
 | 
						|
                    guidAttribs = []
 | 
						|
                    for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.items():
 | 
						|
                        if attrib.upper().endswith('_GUID'):
 | 
						|
                            split = attrib.split('_')
 | 
						|
                            thisPrefix = '_'.join(split[0:3]) + '_'
 | 
						|
                            if thisPrefix == prefix:
 | 
						|
                                guid = self.ToolDef.ToolsDefTxtDictionary[attrib]
 | 
						|
                                guid = guid.lower()
 | 
						|
                                toolName = split[3]
 | 
						|
                                path = '_'.join(split[0:4]) + '_PATH'
 | 
						|
                                path = self.ToolDef.ToolsDefTxtDictionary[path]
 | 
						|
                                path = self.GetFullPathOfTool(path)
 | 
						|
                                guidAttribs.append((guid, toolName, path))
 | 
						|
 | 
						|
                    # Write out GuidedSecTools.txt
 | 
						|
                    toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')
 | 
						|
                    toolsFile = open(toolsFile, 'wt')
 | 
						|
                    for guidedSectionTool in guidAttribs:
 | 
						|
                        print(' '.join(guidedSectionTool), file=toolsFile)
 | 
						|
                    toolsFile.close()
 | 
						|
 | 
						|
    ## Returns the full path of the tool.
 | 
						|
    #
 | 
						|
    def GetFullPathOfTool (self, tool):
 | 
						|
        if os.path.exists(tool):
 | 
						|
            return os.path.realpath(tool)
 | 
						|
        else:
 | 
						|
            # We need to search for the tool using the
 | 
						|
            # PATH environment variable.
 | 
						|
            for dirInPath in os.environ['PATH'].split(os.pathsep):
 | 
						|
                foundPath = os.path.join(dirInPath, tool)
 | 
						|
                if os.path.exists(foundPath):
 | 
						|
                    return os.path.realpath(foundPath)
 | 
						|
 | 
						|
        # If the tool was not found in the path then we just return
 | 
						|
        # the input tool.
 | 
						|
        return tool
 | 
						|
 | 
						|
    ## Launch the module or platform build
 | 
						|
    #
 | 
						|
    def Launch(self):
 | 
						|
        if not self.ModuleFile:
 | 
						|
            if not self.SpawnMode or self.Target not in ["", "all"]:
 | 
						|
                self.SpawnMode = False
 | 
						|
                self._BuildPlatform()
 | 
						|
            else:
 | 
						|
                self._MultiThreadBuildPlatform()
 | 
						|
        else:
 | 
						|
            self.SpawnMode = False
 | 
						|
            self._BuildModule()
 | 
						|
 | 
						|
        if self.Target == 'cleanall':
 | 
						|
            RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)
 | 
						|
 | 
						|
    def CreateAsBuiltInf(self):
 | 
						|
        for Module in self.BuildModules:
 | 
						|
            Module.CreateAsBuiltInf()
 | 
						|
 | 
						|
    def UpdateBuildCache(self):
 | 
						|
        all_lib_set = set()
 | 
						|
        all_mod_set = set()
 | 
						|
        for Module in self.BuildModules:
 | 
						|
            Module.CopyModuleToCache()
 | 
						|
            all_mod_set.add(Module)
 | 
						|
        for Module in self.HashSkipModules:
 | 
						|
            Module.CopyModuleToCache()
 | 
						|
            all_mod_set.add(Module)
 | 
						|
        for Module in all_mod_set:
 | 
						|
            for lib in Module.LibraryAutoGenList:
 | 
						|
                all_lib_set.add(lib)
 | 
						|
        for lib in all_lib_set:
 | 
						|
            lib.CopyModuleToCache()
 | 
						|
        all_lib_set.clear()
 | 
						|
        all_mod_set.clear()
 | 
						|
        self.HashSkipModules = []
 | 
						|
    ## Do some clean-up works when error occurred
 | 
						|
    def Relinquish(self):
 | 
						|
        OldLogLevel = EdkLogger.GetLevel()
 | 
						|
        EdkLogger.SetLevel(EdkLogger.ERROR)
 | 
						|
        Utils.Progressor.Abort()
 | 
						|
        if self.SpawnMode == True:
 | 
						|
            BuildTask.Abort()
 | 
						|
        EdkLogger.SetLevel(OldLogLevel)
 | 
						|
 | 
						|
def ParseDefines(DefineList=[]):
 | 
						|
    DefineDict = {}
 | 
						|
    if DefineList is not None:
 | 
						|
        for Define in DefineList:
 | 
						|
            DefineTokenList = Define.split("=", 1)
 | 
						|
            if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):
 | 
						|
                EdkLogger.error('build', FORMAT_INVALID,
 | 
						|
                                "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
 | 
						|
                                ExtraData=DefineTokenList[0])
 | 
						|
 | 
						|
            if len(DefineTokenList) == 1:
 | 
						|
                DefineDict[DefineTokenList[0]] = "TRUE"
 | 
						|
            else:
 | 
						|
                DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()
 | 
						|
    return DefineDict
 | 
						|
 | 
						|
 | 
						|
 | 
						|
def LogBuildTime(Time):
 | 
						|
    if Time:
 | 
						|
        TimeDurStr = ''
 | 
						|
        TimeDur = time.gmtime(Time)
 | 
						|
        if TimeDur.tm_yday > 1:
 | 
						|
            TimeDurStr = time.strftime("%H:%M:%S", TimeDur) + ", %d day(s)" % (TimeDur.tm_yday - 1)
 | 
						|
        else:
 | 
						|
            TimeDurStr = time.strftime("%H:%M:%S", TimeDur)
 | 
						|
        return TimeDurStr
 | 
						|
    else:
 | 
						|
        return None
 | 
						|
def ThreadNum():
 | 
						|
    ThreadNumber = BuildOption.ThreadNumber
 | 
						|
    if ThreadNumber is None:
 | 
						|
        ThreadNumber = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]
 | 
						|
        if ThreadNumber == '':
 | 
						|
            ThreadNumber = 0
 | 
						|
        else:
 | 
						|
            ThreadNumber = int(ThreadNumber, 0)
 | 
						|
 | 
						|
    if ThreadNumber == 0:
 | 
						|
        try:
 | 
						|
            ThreadNumber = multiprocessing.cpu_count()
 | 
						|
        except (ImportError, NotImplementedError):
 | 
						|
            ThreadNumber = 1
 | 
						|
    return ThreadNumber
 | 
						|
## Tool entrance method
 | 
						|
#
 | 
						|
# This method mainly dispatch specific methods per the command line options.
 | 
						|
# If no error found, return zero value so the caller of this tool can know
 | 
						|
# if it's executed successfully or not.
 | 
						|
#
 | 
						|
#   @retval 0     Tool was successful
 | 
						|
#   @retval 1     Tool failed
 | 
						|
#
 | 
						|
LogQMaxSize = ThreadNum() * 10
 | 
						|
def Main():
 | 
						|
    StartTime = time.time()
 | 
						|
 | 
						|
    #
 | 
						|
    # Create a log Queue
 | 
						|
    #
 | 
						|
    LogQ = mp.Queue(LogQMaxSize)
 | 
						|
    # Initialize log system
 | 
						|
    EdkLogger.LogClientInitialize(LogQ)
 | 
						|
    GlobalData.gCommand = sys.argv[1:]
 | 
						|
    #
 | 
						|
    # Parse the options and args
 | 
						|
    #
 | 
						|
    Option, Target = BuildOption, BuildTarget
 | 
						|
    GlobalData.gOptions = Option
 | 
						|
    GlobalData.gCaseInsensitive = Option.CaseInsensitive
 | 
						|
 | 
						|
    # Set log level
 | 
						|
    LogLevel = EdkLogger.INFO
 | 
						|
    if Option.verbose is not None:
 | 
						|
        EdkLogger.SetLevel(EdkLogger.VERBOSE)
 | 
						|
        LogLevel = EdkLogger.VERBOSE
 | 
						|
    elif Option.quiet is not None:
 | 
						|
        EdkLogger.SetLevel(EdkLogger.QUIET)
 | 
						|
        LogLevel = EdkLogger.QUIET
 | 
						|
    elif Option.debug is not None:
 | 
						|
        EdkLogger.SetLevel(Option.debug + 1)
 | 
						|
        LogLevel = Option.debug + 1
 | 
						|
    else:
 | 
						|
        EdkLogger.SetLevel(EdkLogger.INFO)
 | 
						|
 | 
						|
    if Option.WarningAsError == True:
 | 
						|
        EdkLogger.SetWarningAsError()
 | 
						|
    Log_Agent = LogAgent(LogQ,LogLevel,Option.LogFile)
 | 
						|
    Log_Agent.start()
 | 
						|
 | 
						|
    if platform.platform().find("Windows") >= 0:
 | 
						|
        GlobalData.gIsWindows = True
 | 
						|
    else:
 | 
						|
        GlobalData.gIsWindows = False
 | 
						|
 | 
						|
    EdkLogger.quiet("Build environment: %s" % platform.platform())
 | 
						|
    EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));
 | 
						|
    ReturnCode = 0
 | 
						|
    MyBuild = None
 | 
						|
    BuildError = True
 | 
						|
    try:
 | 
						|
        if len(Target) == 0:
 | 
						|
            Target = "all"
 | 
						|
        elif len(Target) >= 2:
 | 
						|
            EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",
 | 
						|
                            ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))
 | 
						|
        else:
 | 
						|
            Target = Target[0].lower()
 | 
						|
 | 
						|
        if Target not in gSupportedTarget:
 | 
						|
            EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,
 | 
						|
                            ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))
 | 
						|
 | 
						|
        #
 | 
						|
        # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
 | 
						|
        #
 | 
						|
        CheckEnvVariable()
 | 
						|
        GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))
 | 
						|
 | 
						|
        Workspace = os.getenv("WORKSPACE")
 | 
						|
        #
 | 
						|
        # Get files real name in workspace dir
 | 
						|
        #
 | 
						|
        GlobalData.gAllFiles = Utils.DirCache(Workspace)
 | 
						|
 | 
						|
        WorkingDirectory = os.getcwd()
 | 
						|
        if not Option.ModuleFile:
 | 
						|
            FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))
 | 
						|
            FileNum = len(FileList)
 | 
						|
            if FileNum >= 2:
 | 
						|
                EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),
 | 
						|
                                ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")
 | 
						|
            elif FileNum == 1:
 | 
						|
                Option.ModuleFile = NormFile(FileList[0], Workspace)
 | 
						|
 | 
						|
        if Option.ModuleFile:
 | 
						|
            if os.path.isabs (Option.ModuleFile):
 | 
						|
                if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:
 | 
						|
                    Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)
 | 
						|
            Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)
 | 
						|
            ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)
 | 
						|
            if ErrorCode != 0:
 | 
						|
                EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
 | 
						|
 | 
						|
        if Option.PlatformFile is not None:
 | 
						|
            if os.path.isabs (Option.PlatformFile):
 | 
						|
                if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:
 | 
						|
                    Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)
 | 
						|
            Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)
 | 
						|
 | 
						|
        if Option.FdfFile is not None:
 | 
						|
            if os.path.isabs (Option.FdfFile):
 | 
						|
                if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:
 | 
						|
                    Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)
 | 
						|
            Option.FdfFile = PathClass(Option.FdfFile, Workspace)
 | 
						|
            ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)
 | 
						|
            if ErrorCode != 0:
 | 
						|
                EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
 | 
						|
 | 
						|
        if Option.Flag is not None and Option.Flag not in ['-c', '-s']:
 | 
						|
            EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")
 | 
						|
 | 
						|
        MyBuild = Build(Target, Workspace, Option,LogQ)
 | 
						|
        GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)
 | 
						|
        if not (MyBuild.LaunchPrebuildFlag and os.path.exists(MyBuild.PlatformBuildPath)):
 | 
						|
            MyBuild.Launch()
 | 
						|
 | 
						|
        #
 | 
						|
        # All job done, no error found and no exception raised
 | 
						|
        #
 | 
						|
        BuildError = False
 | 
						|
    except FatalError as X:
 | 
						|
        if MyBuild is not None:
 | 
						|
            # for multi-thread build exits safely
 | 
						|
            MyBuild.Relinquish()
 | 
						|
        if Option is not None and Option.debug is not None:
 | 
						|
            EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
 | 
						|
        ReturnCode = X.args[0]
 | 
						|
    except Warning as X:
 | 
						|
        # error from Fdf parser
 | 
						|
        if MyBuild is not None:
 | 
						|
            # for multi-thread build exits safely
 | 
						|
            MyBuild.Relinquish()
 | 
						|
        if Option is not None and Option.debug is not None:
 | 
						|
            EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
 | 
						|
        else:
 | 
						|
            EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)
 | 
						|
        ReturnCode = FORMAT_INVALID
 | 
						|
    except KeyboardInterrupt:
 | 
						|
        if MyBuild is not None:
 | 
						|
 | 
						|
            # for multi-thread build exits safely
 | 
						|
            MyBuild.Relinquish()
 | 
						|
        ReturnCode = ABORT_ERROR
 | 
						|
        if Option is not None and Option.debug is not None:
 | 
						|
            EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
 | 
						|
    except:
 | 
						|
        if MyBuild is not None:
 | 
						|
            # for multi-thread build exits safely
 | 
						|
            MyBuild.Relinquish()
 | 
						|
 | 
						|
        # try to get the meta-file from the object causing exception
 | 
						|
        Tb = sys.exc_info()[-1]
 | 
						|
        MetaFile = GlobalData.gProcessingFile
 | 
						|
        while Tb is not None:
 | 
						|
            if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):
 | 
						|
                MetaFile = Tb.tb_frame.f_locals['self'].MetaFile
 | 
						|
            Tb = Tb.tb_next
 | 
						|
        EdkLogger.error(
 | 
						|
                    "\nbuild",
 | 
						|
                    CODE_ERROR,
 | 
						|
                    "Unknown fatal error when processing [%s]" % MetaFile,
 | 
						|
                    ExtraData="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR,
 | 
						|
                    RaiseError=False
 | 
						|
                    )
 | 
						|
        EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
 | 
						|
        ReturnCode = CODE_ERROR
 | 
						|
    finally:
 | 
						|
        Utils.Progressor.Abort()
 | 
						|
        Utils.ClearDuplicatedInf()
 | 
						|
 | 
						|
    if ReturnCode == 0:
 | 
						|
        try:
 | 
						|
            MyBuild.LaunchPostbuild()
 | 
						|
            Conclusion = "Done"
 | 
						|
        except:
 | 
						|
            Conclusion = "Failed"
 | 
						|
    elif ReturnCode == ABORT_ERROR:
 | 
						|
        Conclusion = "Aborted"
 | 
						|
    else:
 | 
						|
        Conclusion = "Failed"
 | 
						|
    FinishTime = time.time()
 | 
						|
    BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))
 | 
						|
    BuildDurationStr = ""
 | 
						|
    if BuildDuration.tm_yday > 1:
 | 
						|
        BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)" % (BuildDuration.tm_yday - 1)
 | 
						|
    else:
 | 
						|
        BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)
 | 
						|
    if MyBuild is not None:
 | 
						|
        if not BuildError:
 | 
						|
            MyBuild.BuildReport.GenerateReport(BuildDurationStr, LogBuildTime(MyBuild.AutoGenTime), LogBuildTime(MyBuild.MakeTime), LogBuildTime(MyBuild.GenFdsTime))
 | 
						|
 | 
						|
    EdkLogger.SetLevel(EdkLogger.QUIET)
 | 
						|
    EdkLogger.quiet("\n- %s -" % Conclusion)
 | 
						|
    EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))
 | 
						|
    EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)
 | 
						|
    Log_Agent.kill()
 | 
						|
    Log_Agent.join()
 | 
						|
    return ReturnCode
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    try:
 | 
						|
        mp.set_start_method('spawn')
 | 
						|
    except:
 | 
						|
        pass
 | 
						|
    r = Main()
 | 
						|
    ## 0-127 is a safe return range, and 1 is a standard default error
 | 
						|
    if r < 0 or r > 127: r = 1
 | 
						|
    sys.exit(r)
 | 
						|
 |