2019-09-05 06:32:53 +02:00
## @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
2019-09-20 06:56:20 +02:00
from AutoGen . DataPipe import MemoryDataPipe
from AutoGen . ModuleAutoGenHelper import WorkSpaceInfo , PlatformInfo
from GenFds . FdfParser import FdfParser
2019-09-05 06:32:53 +02:00
## 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 " %d ms " % ( 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 ( " \n Waiting 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
2019-09-20 06:56:20 +02:00
GlobalData . gEnableGenfdsMultiThread = not BuildOptions . NoGenfdsMultiThread
2019-09-05 06:32:53 +02:00
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
2019-09-20 06:56:20 +02:00
GlobalData . file_lock = mp . Lock ( )
GlobalData . cache_lock = mp . Lock ( )
2019-09-05 06:32:53 +02:00
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 " )
2019-09-20 06:56:20 +02:00
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 ) ]
2019-09-05 06:32:53 +02:00
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 ) :
2019-09-20 06:56:20 +02:00
continue
2019-09-05 06:32:53 +02:00
PcdMa . CreateCodeFile ( False )
2019-09-20 06:56:20 +02:00
PcdMa . CreateMakeFile ( False , GenFfsList = DataPipe . Get ( " FfsCommand " ) . get ( ( PcdMa . MetaFile . Path , PcdMa . Arch ) , [ ] ) )
2019-09-05 06:32:53 +02:00
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 }
2019-09-20 06:56:20 +02:00
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 }
2019-09-05 06:32:53 +02:00
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 )
2019-09-20 06:56:20 +02:00
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 ) )
2019-09-05 06:32:53 +02:00
self . Progress . Stop ( " done! " )
if not autogen_rt :
self . AutoGenMgr . TerminateWorkers ( )
2019-09-20 06:56:20 +02:00
self . AutoGenMgr . join ( 1 )
2019-09-05 06:32:53 +02:00
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 ( " \n Load 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 )
2019-09-20 06:56:20 +02:00
self . CreateGuidedSectionToolsFile ( Wa )
2019-09-05 06:32:53 +02:00
## 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
2019-09-20 06:56:20 +02:00
if Ma . PcdIsDriver :
Ma . PlatformInfo = Pa
Ma . Workspace = Wa
2019-09-05 06:32:53 +02:00
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 ) :
2019-09-20 06:56:20 +02:00
self . HashSkipModules . append ( Ma )
EdkLogger . quiet ( " cache hit: %s [ %s ] " % ( Ma . MetaFile . Path , Ma . Arch ) )
continue
2019-09-05 06:32:53 +02:00
# 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 " )
2019-09-20 06:56:20 +02:00
if CmdListDict and self . Fdf and ( Module . Path , Arch ) in CmdListDict :
Ma . CreateMakeFile ( True , CmdListDict [ Module . Path , Arch ] )
del CmdListDict [ Module . Path , Arch ]
2019-09-05 06:32:53 +02:00
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
2019-09-20 06:56:20 +02:00
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 :
2020-02-21 22:22:30 +01:00
if str ( FdRegion . RegionType ) == ' FILE ' and self . Platform . VpdToolGuid in str ( FdRegion . RegionDataList ) :
2019-09-20 06:56:20 +02:00
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
2019-09-05 06:32:53 +02:00
## Build a platform in multi-thread mode
#
2019-09-20 06:56:20 +02:00
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
2019-09-05 06:32:53 +02:00
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 ( )
2019-09-20 06:56:20 +02:00
if self . SkipAutoGen :
Wa = self . VerifyAutoGenFiles ( )
if Wa is None :
self . SkipAutoGen = False
Wa , self . BuildModules = self . PerformAutoGen ( BuildTarget , ToolChain )
2019-09-05 06:32:53 +02:00
else :
2019-09-20 06:56:20 +02:00
GlobalData . gAutoGenPhase = True
self . BuildModules = self . SetupMakeSetting ( Wa )
else :
Wa , self . BuildModules = self . PerformAutoGen ( BuildTarget , ToolChain )
Pa = Wa . AutoGenObjectList [ 0 ]
GlobalData . gAutoGenPhase = False
2019-09-05 06:32:53 +02:00
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
2019-09-20 06:56:20 +02:00
2019-09-05 06:32:53 +02:00
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
#
2019-09-20 06:56:20 +02:00
ModuleList = { ma . Guid . upper ( ) : ma for ma in self . BuildModules }
2019-09-05 06:32:53 +02:00
#
# 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 )
2019-09-20 06:56:20 +02:00
self . CreateGuidedSectionToolsFile ( Wa )
2019-09-05 06:32:53 +02:00
self . invalidateHash ( )
## Generate GuidedSectionTools.txt in the FV directories.
#
2019-09-20 06:56:20 +02:00
def CreateGuidedSectionToolsFile ( self , Wa ) :
2019-09-05 06:32:53 +02:00
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 (
" \n build " ,
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 )