2010-03-01 00:39:39 +01:00
## @file
# build a platform or a module
#
2014-12-23 06:48:31 +01:00
# Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
2021-04-21 08:12:51 +02:00
# Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR>
2018-12-18 09:40:34 +01:00
# Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
2021-09-23 10:59:01 +02:00
# Copyright (c) 2020 - 2021, ARM Limited. All rights reserved.<BR>
2010-03-01 00:39:39 +01:00
#
2019-04-04 01:03:11 +02:00
# SPDX-License-Identifier: BSD-2-Clause-Patent
2010-03-01 00:39:39 +01:00
#
##
# Import Modules
#
2018-10-15 02:27:53 +02:00
from __future__ import print_function
2019-07-22 05:09:22 +02:00
from __future__ import absolute_import
import os . path as path
2010-03-01 00:39:39 +01:00
import sys
2019-07-22 05:09:22 +02:00
import os
import re
2010-03-01 00:39:39 +01:00
import glob
import time
import platform
import traceback
2018-01-11 10:11:20 +01:00
import multiprocessing
2019-07-22 05:09:22 +02:00
from threading import Thread , Event , BoundedSemaphore
2019-01-10 19:39:45 +01:00
import threading
2020-04-20 03:20:52 +02:00
from linecache import getlines
2019-12-16 11:18:46 +01:00
from subprocess import Popen , PIPE , STDOUT
2019-07-22 05:09:22 +02:00
from collections import OrderedDict , defaultdict
2020-01-10 09:29:45 +01:00
2019-07-22 05:09:22 +02:00
from AutoGen . PlatformAutoGen import PlatformAutoGen
from AutoGen . ModuleAutoGen import ModuleAutoGen
from AutoGen . WorkspaceAutoGen import WorkspaceAutoGen
2019-07-31 07:31:15 +02:00
from AutoGen . AutoGenWorker import AutoGenWorkerInProcess , AutoGenManager , \
LogAgent
2019-07-22 05:09:22 +02:00
from AutoGen import GenMake
2010-03-01 00:39:39 +01:00
from Common import Misc as Utils
2020-01-10 09:29:45 +01:00
from Common . TargetTxtClassObject import TargetTxtDict
from Common . ToolDefClassObject import ToolDefDict
from buildoptions import MyOptionParser
2019-07-22 05:09:22 +02:00
from Common . Misc import PathClass , SaveFileOnChange , RemoveDirectory
from Common . StringUtils import NormPath
from Common . MultipleWorkspace import MultipleWorkspace as mws
from Common . BuildToolError import *
2010-03-01 00:39:39 +01:00
from Common . DataType import *
2019-07-22 05:09:22 +02:00
import Common . EdkLogger as EdkLogger
2019-07-22 08:23:40 +02:00
2019-07-22 05:09:22 +02:00
from Workspace . WorkspaceDatabase import BuildDB
2010-03-01 00:39:39 +01:00
from BuildReport import BuildReport
2019-07-22 05:09:22 +02:00
from GenPatchPcdTable . GenPatchPcdTable import PeImageClass , parsePcdInfoFromMapFile
from PatchPcdValue . PatchPcdValue import PatchBinaryFile
2010-03-01 00:39:39 +01:00
import Common . GlobalData as GlobalData
2018-11-23 08:04:45 +01:00
from GenFds . GenFds import GenFds , GenFdsApi
2019-07-30 11:15:31 +02:00
import multiprocessing as mp
2019-07-30 12:04:14 +02:00
from multiprocessing import Manager
2019-09-05 11:04:58 +02:00
from AutoGen . DataPipe import MemoryDataPipe
from AutoGen . ModuleAutoGenHelper import WorkSpaceInfo , PlatformInfo
from GenFds . FdfParser import FdfParser
2019-11-20 03:58:30 +01:00
from AutoGen . IncludesAutoGen import IncludesAutoGen
2019-12-11 12:22:21 +01:00
from GenFds . GenFds import resetFdsGlobalVariable
2021-05-07 17:40:29 +02:00
from AutoGen . AutoGen import CalculatePriorityValue
2010-03-01 00:39:39 +01:00
## standard targets of build command
gSupportedTarget = [ ' all ' , ' genc ' , ' genmake ' , ' modules ' , ' libraries ' , ' fds ' , ' clean ' , ' cleanall ' , ' cleanlib ' , ' run ' ]
2012-04-10 09:18:20 +02:00
TemporaryTablePattern = re . compile ( r ' ^_ \ d+_ \ d+_[a-fA-F0-9]+$ ' )
TmpTableDict = { }
2010-03-01 00:39:39 +01:00
## 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 ) :
2018-06-25 12:31:29 +02:00
if ' PATHEXT ' in os . environ :
2010-03-01 00:39:39 +01:00
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 ) :
2018-05-18 02:06:52 +02:00
EdkLogger . error ( " build " , FILE_NOT_FOUND , " WORKSPACE doesn ' t exist " , ExtraData = WorkspaceDir )
2010-03-01 00:39:39 +01:00
elif ' ' in WorkspaceDir :
EdkLogger . error ( " build " , FORMAT_NOT_SUPPORTED , " No space is allowed in WORKSPACE path " ,
ExtraData = WorkspaceDir )
os . environ [ " WORKSPACE " ] = WorkspaceDir
2018-07-05 11:40:04 +02:00
2015-10-08 11:27:14 +02:00
# set multiple workspace
PackagesPath = os . getenv ( " PACKAGES_PATH " )
mws . setWs ( WorkspaceDir , PackagesPath )
2016-05-18 03:59:20 +02:00
if mws . PACKAGES_PATH :
for Path in mws . PACKAGES_PATH :
if not os . path . exists ( Path ) :
2018-05-18 02:06:52 +02:00
EdkLogger . error ( " build " , FILE_NOT_FOUND , " One Path in PACKAGES_PATH doesn ' t exist " , ExtraData = Path )
2016-05-18 03:59:20 +02:00
elif ' ' in Path :
EdkLogger . error ( " build " , FORMAT_NOT_SUPPORTED , " No space is allowed in PACKAGES_PATH " , ExtraData = Path )
2010-03-01 00:39:39 +01:00
2013-08-23 04:18:16 +02:00
2010-03-01 00:39:39 +01:00
os . environ [ " EDK_TOOLS_PATH " ] = os . path . normcase ( os . environ [ " EDK_TOOLS_PATH " ] )
2013-08-23 04:18:16 +02:00
2010-03-01 00:39:39 +01:00
# 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
2011-10-29 08:59:30 +02:00
GlobalData . gGlobalDefines [ " WORKSPACE " ] = WorkspaceDir
GlobalData . gGlobalDefines [ " EDK_TOOLS_PATH " ] = os . environ [ " EDK_TOOLS_PATH " ]
2018-07-05 11:40:04 +02:00
2010-03-01 00:39:39 +01:00
## 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 :
2015-10-08 11:27:14 +02:00
FileFullPath = os . path . normpath ( mws . join ( Workspace , FilePath ) )
Workspace = mws . getWs ( Workspace , FilePath )
2010-03-01 00:39:39 +01:00
# check if the file path exists or not
if not os . path . isfile ( FileFullPath ) :
2015-12-01 05:22:16 +01:00
EdkLogger . error ( " build " , FILE_NOT_FOUND , ExtraData = " \t %s (Please give file in absolute path or relative to WORKSPACE) " % FileFullPath )
2010-03-01 00:39:39 +01:00
# 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
#
2019-11-20 03:58:30 +01:00
def ReadMessage ( From , To , ExitFlag , MemTo = None ) :
2010-03-01 00:39:39 +01:00
while True :
# read one line a time
Line = From . readline ( )
# empty string means "end"
2019-01-23 03:16:00 +01:00
if Line is not None and Line != b " " :
2019-11-20 03:58:30 +01:00
LineStr = Line . rstrip ( ) . decode ( encoding = ' utf-8 ' , errors = ' ignore ' )
if MemTo is not None :
if " Note: including file: " == LineStr . lstrip ( ) [ : 21 ] :
MemTo . append ( LineStr )
else :
To ( LineStr )
MemTo . append ( LineStr )
else :
To ( LineStr )
2010-03-01 00:39:39 +01:00
else :
break
2021-07-23 22:02:26 +02:00
if ExitFlag . is_set ( ) :
2010-03-01 00:39:39 +01:00
break
2019-11-20 03:58:30 +01:00
class MakeSubProc ( Popen ) :
def __init__ ( self , * args , * * argv ) :
super ( MakeSubProc , self ) . __init__ ( * args , * * argv )
self . ProcOut = [ ]
2010-03-01 00:39:39 +01:00
## 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
2022-10-03 09:47:32 +02:00
# redirecting output of the external program, threads are used to do the
2010-03-01 00:39:39 +01:00
# 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
#
2019-11-20 03:58:30 +01:00
def LaunchCommand ( Command , WorkingDir , ModuleAuto = None ) :
2017-09-11 10:50:07 +02:00
BeginTime = time . time ( )
2010-03-01 00:39:39 +01:00
# 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 )
2018-07-05 11:40:04 +02:00
2014-08-19 10:22:04 +02:00
# 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.
2016-09-29 16:47:38 +02:00
if platform . system ( ) != ' Windows ' :
if not isinstance ( Command , list ) :
2014-08-20 09:41:38 +02:00
Command = Command . split ( )
2016-09-29 16:47:38 +02:00
Command = ' ' . join ( Command )
2014-08-20 09:41:38 +02:00
2010-03-01 00:39:39 +01:00
Proc = None
EndOfProcedure = None
try :
# launch the command
2019-12-16 11:18:46 +01:00
Proc = MakeSubProc ( Command , stdout = PIPE , stderr = STDOUT , env = os . environ , cwd = WorkingDir , bufsize = - 1 , shell = True )
2010-03-01 00:39:39 +01:00
# launch two threads to read the STDOUT and STDERR
EndOfProcedure = Event ( )
EndOfProcedure . clear ( )
if Proc . stdout :
2019-11-20 03:58:30 +01:00
StdOutThread = Thread ( target = ReadMessage , args = ( Proc . stdout , EdkLogger . info , EndOfProcedure , Proc . ProcOut ) )
2021-07-23 22:02:26 +02:00
StdOutThread . name = " STDOUT-Redirector "
StdOutThread . daemon = False
2010-03-01 00:39:39 +01:00
StdOutThread . start ( )
# waiting for program exit
Proc . wait ( )
except : # in case of aborting
# terminate the threads redirecting the program output
2016-02-17 07:48:28 +01:00
EdkLogger . quiet ( " (Python %s on %s ) " % ( platform . python_version ( ) , sys . platform ) + traceback . format_exc ( ) )
2018-03-26 22:25:43 +02:00
if EndOfProcedure is not None :
2010-03-01 00:39:39 +01:00
EndOfProcedure . set ( )
2018-03-26 22:25:43 +02:00
if Proc is None :
2018-06-25 12:31:35 +02:00
if not isinstance ( Command , type ( " " ) ) :
2010-03-01 00:39:39 +01:00
Command = " " . join ( Command )
EdkLogger . error ( " build " , COMMAND_FAILURE , " Failed to start command " , ExtraData = " %s [ %s ] " % ( Command , WorkingDir ) )
if Proc . stdout :
StdOutThread . join ( )
# check the return code of the program
if Proc . returncode != 0 :
2018-06-25 12:31:35 +02:00
if not isinstance ( Command , type ( " " ) ) :
2010-03-01 00:39:39 +01:00
Command = " " . join ( Command )
2016-03-16 04:06:44 +01:00
# 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 )
2010-03-01 00:39:39 +01:00
EdkLogger . error ( " build " , COMMAND_FAILURE , ExtraData = " %s [ %s ] " % ( Command , WorkingDir ) )
2019-11-20 03:58:30 +01:00
if ModuleAuto :
iau = IncludesAutoGen ( WorkingDir , ModuleAuto )
if ModuleAuto . ToolChainFamily == TAB_COMPILER_MSFT :
iau . CreateDepsFileForMsvc ( Proc . ProcOut )
else :
iau . UpdateDepsFileforNonMsvc ( )
iau . UpdateDepsFileforTrim ( )
iau . CreateModuleDeps ( )
iau . CreateDepsInclude ( )
2020-01-17 04:11:27 +01:00
iau . CreateDepsTarget ( )
2017-09-11 10:50:07 +02:00
return " %d ms " % ( int ( round ( ( time . time ( ) - BeginTime ) * 1000 ) ) )
2010-03-01 00:39:39 +01:00
## 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
2011-10-29 08:59:30 +02:00
if not BuildCommand :
EdkLogger . error ( " build " , OPTION_MISSING ,
" No build command found for this module. "
2013-08-23 04:18:16 +02:00
" Please check your setting of %s _ %s _ %s _MAKE_PATH in Conf/tools_def.txt file. " %
2011-10-29 08:59:30 +02:00
( Obj . BuildTarget , Obj . ToolChain , Obj . Arch ) ,
2010-03-01 00:39:39 +01:00
ExtraData = str ( Obj ) )
2011-10-29 08:59:30 +02:00
2010-03-01 00:39:39 +01:00
## str() method
#
2010-10-11 08:26:52 +02:00
# It just returns the string representation of self.BuildObject
2010-03-01 00:39:39 +01:00
#
# @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 ) :
2018-04-28 00:32:17 +02:00
return Other and self . BuildObject == Other . BuildObject \
and Other . BuildObject \
2010-03-01 00:39:39 +01:00
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
#
2019-07-30 11:15:31 +02:00
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 )
2010-03-01 00:39:39 +01:00
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
#
2019-07-30 11:15:31 +02:00
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 )
2010-03-01 00:39:39 +01:00
## 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
2018-04-03 23:03:07 +02:00
_PendingQueue = OrderedDict ( )
2010-03-01 00:39:39 +01:00
_PendingQueueLock = threading . Lock ( )
# queue for tasks ready for running
2018-04-03 23:03:07 +02:00
_ReadyQueue = OrderedDict ( )
2010-03-01 00:39:39 +01:00
_ReadyQueueLock = threading . Lock ( )
# queue for run tasks
2018-04-03 23:03:07 +02:00
_RunningQueue = OrderedDict ( )
2010-03-01 00:39:39 +01:00
_RunningQueueLock = threading . Lock ( )
# queue containing all build tasks, in case duplicate build
2018-04-03 23:03:07 +02:00
_TaskQueue = OrderedDict ( )
2010-03-01 00:39:39 +01:00
# 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 ) )
2021-07-23 22:02:26 +02:00
SchedulerThread . name = " Build-Task-Scheduler "
SchedulerThread . daemon = False
2010-03-01 00:39:39 +01:00
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 \
2021-07-23 22:02:26 +02:00
or not ExitFlag . is_set ( ) ) and not BuildTask . _ErrorFlag . is_set ( ) :
2010-03-01 00:39:39 +01:00
EdkLogger . debug ( EdkLogger . DEBUG_8 , " Pending Queue ( %d ), Ready Queue ( %d ) "
% ( len ( BuildTask . _PendingQueue ) , len ( BuildTask . _ReadyQueue ) ) )
# get all pending tasks
BuildTask . _PendingQueueLock . acquire ( )
2019-01-28 08:06:30 +01:00
BuildObjectList = list ( BuildTask . _PendingQueue . keys ( ) )
2010-03-01 00:39:39 +01:00
#
# 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
2021-07-23 22:02:26 +02:00
while not BuildTask . _ErrorFlag . is_set ( ) :
2010-03-01 00:39:39 +01:00
# 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
2018-06-25 12:31:33 +02:00
Bo , Bt = BuildTask . _ReadyQueue . popitem ( )
2010-03-01 00:39:39 +01:00
# 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
2021-07-23 22:02:26 +02:00
if BuildTask . _ErrorFlag . is_set ( ) :
2010-03-01 00:39:39 +01:00
EdkLogger . quiet ( " \n Waiting for all build threads exit... " )
2021-07-23 22:02:26 +02:00
# while not BuildTask._ErrorFlag.is_set() and \
2010-03-01 00:39:39 +01:00
while len ( BuildTask . _RunningQueue ) > 0 :
EdkLogger . verbose ( " Waiting for thread ending...( %d ) " % len ( BuildTask . _RunningQueue ) )
2021-07-23 22:02:26 +02:00
EdkLogger . debug ( EdkLogger . DEBUG_8 , " Threads [ %s ] " % " , " . join ( Th . name for Th in threading . enumerate ( ) ) )
2010-03-01 00:39:39 +01:00
# avoid tense loop
time . sleep ( 0.1 )
2018-06-25 12:31:25 +02:00
except BaseException as X :
2010-03-01 00:39:39 +01:00
#
2019-02-06 08:44:39 +01:00
# TRICK: hide the output of threads left running, so that the user can
2010-03-01 00:39:39 +01:00
# 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 ( ) :
2021-07-23 22:02:26 +02:00
return not BuildTask . _SchedulerStopped . is_set ( )
2010-03-01 00:39:39 +01:00
## 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 ( ) :
2021-07-23 22:02:26 +02:00
return BuildTask . _ErrorFlag . is_set ( )
2010-03-01 00:39:39 +01:00
## 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 = [ ]
2018-03-26 22:25:43 +02:00
if Dependency is None :
2010-03-01 00:39:39 +01:00
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 :
2019-11-19 09:17:00 +01:00
if not Dep . BuildObject . IsBinaryModule and not Dep . BuildObject . CanSkipbyCache ( GlobalData . gModuleCacheHit ) :
2014-08-28 15:53:34 +02:00
self . DependencyList . append ( BuildTask . New ( Dep ) ) # BuildTask list
2010-03-01 00:39:39 +01:00
## 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 :
2019-11-20 03:58:30 +01:00
self . BuildItem . BuildObject . BuildTime = LaunchCommand ( Command , WorkingDir , self . BuildItem . BuildObject )
2010-03-01 00:39:39 +01:00
self . CompleteFlag = True
2019-05-20 16:17:54 +02:00
2019-11-19 09:17:00 +01:00
# Run hash operation post dependency to account for libs
# Run if --hash or --binary-destination
if GlobalData . gUseHashCache and not GlobalData . gBinCacheSource :
self . BuildItem . BuildObject . GenModuleHash ( )
if GlobalData . gBinCacheDest :
self . BuildItem . BuildObject . GenCMakeHash ( )
2010-03-01 00:39:39 +01:00
except :
#
2019-02-06 08:44:39 +01:00
# TRICK: hide the output of threads left running, so that the user can
2010-03-01 00:39:39 +01:00
# catch the error message easily
#
2021-07-23 22:02:26 +02:00
if not BuildTask . _ErrorFlag . is_set ( ) :
2010-03-01 00:39:39 +01:00
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 ] " % \
2021-07-23 22:02:26 +02:00
( threading . current_thread ( ) . name , Command , WorkingDir )
2019-05-29 18:26:49 +02:00
2010-03-01 00:39:39 +01:00
# 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 ) )
2021-07-23 22:02:26 +02:00
self . BuildTread . name = " build thread "
self . BuildTread . daemon = False
2010-03-01 00:39:39 +01:00
self . BuildTread . start ( )
## The class contains the information related to EFI image
#
class PeImageInfo ( ) :
## Constructor
#
# Constructor will load all required image information.
#
2013-08-23 04:18:16 +02:00
# @param BaseName The full file path of image.
2010-03-01 00:39:39 +01:00
# @param Guid The GUID for image.
# @param Arch Arch of this image.
2010-03-19 07:55:07 +01:00
# @param OutputDir The output directory for image.
# @param DebugDir The debug directory for image.
2010-03-01 00:39:39 +01:00
# @param ImageClass PeImage Information
#
2010-03-19 07:55:07 +01:00
def __init__ ( self , BaseName , Guid , Arch , OutputDir , DebugDir , ImageClass ) :
2010-03-01 00:39:39 +01:00
self . BaseName = BaseName
self . Guid = Guid
self . Arch = Arch
2010-03-19 07:55:07 +01:00
self . OutputDir = OutputDir
self . DebugDir = DebugDir
2010-03-01 00:39:39 +01:00
self . Image = ImageClass
2018-12-07 05:34:44 +01:00
self . Image . Size = ( self . Image . Size / / 0x1000 + 1 ) * 0x1000
2010-03-01 00:39:39 +01:00
## 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
2011-10-29 08:59:30 +02:00
# @param BuildOptions Build options passed from command line
#
2019-07-31 07:31:15 +02:00
def __init__ ( self , Target , WorkspaceDir , BuildOptions , log_q ) :
2011-10-29 08:59:30 +02:00
self . WorkspaceDir = WorkspaceDir
2010-03-01 00:39:39 +01:00
self . Target = Target
2011-10-29 08:59:30 +02:00
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
2019-07-31 07:33:31 +02:00
self . ThreadNumber = 1
2011-10-29 08:59:30 +02:00
self . SkipAutoGen = BuildOptions . SkipAutoGen
self . Reparse = BuildOptions . Reparse
self . SkuId = BuildOptions . SkuId
2017-12-22 13:07:54 +01:00
if self . SkuId :
GlobalData . gSKUID_CMD = self . SkuId
2014-08-28 15:53:34 +02:00
self . ConfDirectory = BuildOptions . ConfDirectory
2010-03-01 00:39:39 +01:00
self . SpawnMode = True
2011-10-29 08:59:30 +02:00
self . BuildReport = BuildReport ( BuildOptions . ReportFile , BuildOptions . ReportType )
2017-09-11 10:50:07 +02:00
self . AutoGenTime = 0
self . MakeTime = 0
self . GenFdsTime = 0
2020-02-10 11:49:07 +01:00
self . MakeFileName = " "
2020-01-10 09:29:45 +01:00
TargetObj = TargetTxtDict ( )
ToolDefObj = ToolDefDict ( ( os . path . join ( os . getenv ( " WORKSPACE " ) , " Conf " ) ) )
self . TargetTxt = TargetObj . Target
self . ToolDef = ToolDefObj . ToolDef
2018-03-02 11:11:13 +01:00
GlobalData . BuildOptionPcd = BuildOptions . OptionPcd if BuildOptions . OptionPcd else [ ]
2014-08-26 09:14:38 +02:00
#Set global flag for build mode
GlobalData . gIgnoreSource = BuildOptions . IgnoreSources
BaseTools: add support for BIOS build with binary cache
Add three new options:
--hash enables hash-based caching during build process. when --hash is
enabled, build tool will base on the module hash value to do the
incremental build, without --hash, build tool will base on the
timestamp to do the incremental build. --hash option use md5 method to
get every hash value, DSC/FDF, tools_def.txt, build_rule.txt and build
command are calculated as global hash value, Package DEC and its
include header files are calculated as package hash value, Module
source files and its INF file are calculated as module hash value.
Library hash value will combine the global hash value and its dependent
package hash value. Driver hash value will combine the global hash
value, its dependent package hash value and its linked library hash
value.
When --hash and --binary-destination are specified, build tool will
copy generated binary files for each module into the directory specified
by binary-destination at the build phase. Binary-destination directory
caches all generated binary files.
When --hash and --binary-source are specified, build tool will try to
get the binary files from the binary source directory at the build
phase.If the cached binary has the same hash value, it will be directly
used. Otherwise, build tool will compile the source files and generate
the binary files.
Cc: Liming Gao <liming.gao@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Yonghong Zhu <yonghong.zhu@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
2017-09-19 08:31:09 +02:00
GlobalData . gUseHashCache = BuildOptions . UseHashCache
GlobalData . gBinCacheDest = BuildOptions . BinCacheDest
GlobalData . gBinCacheSource = BuildOptions . BinCacheSource
2019-09-06 15:22:58 +02:00
GlobalData . gEnableGenfdsMultiThread = not BuildOptions . NoGenfdsMultiThread
2019-03-13 23:10:54 +01:00
GlobalData . gDisableIncludePathCheck = BuildOptions . DisableIncludePathCheck
BaseTools: add support for BIOS build with binary cache
Add three new options:
--hash enables hash-based caching during build process. when --hash is
enabled, build tool will base on the module hash value to do the
incremental build, without --hash, build tool will base on the
timestamp to do the incremental build. --hash option use md5 method to
get every hash value, DSC/FDF, tools_def.txt, build_rule.txt and build
command are calculated as global hash value, Package DEC and its
include header files are calculated as package hash value, Module
source files and its INF file are calculated as module hash value.
Library hash value will combine the global hash value and its dependent
package hash value. Driver hash value will combine the global hash
value, its dependent package hash value and its linked library hash
value.
When --hash and --binary-destination are specified, build tool will
copy generated binary files for each module into the directory specified
by binary-destination at the build phase. Binary-destination directory
caches all generated binary files.
When --hash and --binary-source are specified, build tool will try to
get the binary files from the binary source directory at the build
phase.If the cached binary has the same hash value, it will be directly
used. Otherwise, build tool will compile the source files and generate
the binary files.
Cc: Liming Gao <liming.gao@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Yonghong Zhu <yonghong.zhu@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
2017-09-19 08:31:09 +02:00
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
2018-01-18 04:13:06 +01:00
else :
2018-03-26 22:25:43 +02:00
if GlobalData . gBinCacheSource is not None :
2018-01-18 04:13:06 +01:00
EdkLogger . error ( " build " , OPTION_VALUE_INVALID , ExtraData = " Invalid value of option --binary-source. " )
BaseTools: add support for BIOS build with binary cache
Add three new options:
--hash enables hash-based caching during build process. when --hash is
enabled, build tool will base on the module hash value to do the
incremental build, without --hash, build tool will base on the
timestamp to do the incremental build. --hash option use md5 method to
get every hash value, DSC/FDF, tools_def.txt, build_rule.txt and build
command are calculated as global hash value, Package DEC and its
include header files are calculated as package hash value, Module
source files and its INF file are calculated as module hash value.
Library hash value will combine the global hash value and its dependent
package hash value. Driver hash value will combine the global hash
value, its dependent package hash value and its linked library hash
value.
When --hash and --binary-destination are specified, build tool will
copy generated binary files for each module into the directory specified
by binary-destination at the build phase. Binary-destination directory
caches all generated binary files.
When --hash and --binary-source are specified, build tool will try to
get the binary files from the binary source directory at the build
phase.If the cached binary has the same hash value, it will be directly
used. Otherwise, build tool will compile the source files and generate
the binary files.
Cc: Liming Gao <liming.gao@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Yonghong Zhu <yonghong.zhu@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
2017-09-19 08:31:09 +02:00
if GlobalData . gBinCacheDest :
BinCacheDest = os . path . normpath ( GlobalData . gBinCacheDest )
if not os . path . isabs ( BinCacheDest ) :
BinCacheDest = mws . join ( self . WorkspaceDir , BinCacheDest )
GlobalData . gBinCacheDest = BinCacheDest
2018-01-18 04:13:06 +01:00
else :
2018-03-26 22:25:43 +02:00
if GlobalData . gBinCacheDest is not None :
2018-01-18 04:13:06 +01:00
EdkLogger . error ( " build " , OPTION_VALUE_INVALID , ExtraData = " Invalid value of option --binary-destination. " )
2014-08-28 15:53:34 +02:00
2019-07-22 08:23:40 +02:00
GlobalData . gDatabasePath = os . path . normpath ( os . path . join ( GlobalData . gConfDirectory , GlobalData . gDatabasePath ) )
2019-07-19 03:10:28 +02:00
if not os . path . exists ( os . path . join ( GlobalData . gConfDirectory , ' .cache ' ) ) :
os . makedirs ( os . path . join ( GlobalData . gConfDirectory , ' .cache ' ) )
2019-07-22 05:09:22 +02:00
self . Db = BuildDB
2014-08-28 15:53:34 +02:00
self . BuildDatabase = self . Db . BuildObject
self . Platform = None
2016-07-04 10:34:28 +02:00
self . ToolChainFamily = None
2010-03-01 00:39:39 +01:00
self . LoadFixAddress = 0
2011-10-29 08:59:30 +02:00
self . UniFlag = BuildOptions . Flag
2014-08-26 04:52:24 +02:00
self . BuildModules = [ ]
2017-12-12 08:18:22 +01:00
self . HashSkipModules = [ ]
2016-03-31 08:05:59 +02:00
self . Db_Flag = False
self . LaunchPrebuildFlag = False
2018-06-25 12:31:33 +02:00
self . PlatformBuildPath = os . path . join ( GlobalData . gConfDirectory , ' .cache ' , ' .PlatformBuild ' )
2016-03-16 04:06:44 +01:00
if BuildOptions . CommandLength :
GlobalData . gCommandMaxLength = BuildOptions . CommandLength
2010-09-06 03:58:00 +02:00
# print dot character during doing some time-consuming work
2010-03-01 00:39:39 +01:00
self . Progress = Utils . Progressor ( )
# print current build environment and configuration
2011-10-29 08:59:30 +02:00
EdkLogger . quiet ( " %-16s = %s " % ( " WORKSPACE " , os . environ [ " WORKSPACE " ] ) )
2015-11-06 03:57:07 +01:00
if " PACKAGES_PATH " in os . environ :
2018-07-05 11:40:04 +02:00
# WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
2015-11-06 03:57:07 +01:00
EdkLogger . quiet ( " %-16s = %s " % ( " PACKAGES_PATH " , os . path . normcase ( os . path . normpath ( os . environ [ " PACKAGES_PATH " ] ) ) ) )
2011-10-29 08:59:30 +02:00
EdkLogger . quiet ( " %-16s = %s " % ( " EDK_TOOLS_PATH " , os . environ [ " EDK_TOOLS_PATH " ] ) )
2015-11-06 03:57:07 +01:00
if " EDK_TOOLS_BIN " in os . environ :
2018-07-05 11:40:04 +02:00
# Print the same path style with WORKSPACE env.
2015-11-06 03:57:07 +01:00
EdkLogger . quiet ( " %-16s = %s " % ( " EDK_TOOLS_BIN " , os . path . normcase ( os . path . normpath ( os . environ [ " EDK_TOOLS_BIN " ] ) ) ) )
2016-08-18 04:07:36 +02:00
EdkLogger . quiet ( " %-16s = %s " % ( " CONF_PATH " , GlobalData . gConfDirectory ) )
2018-12-25 09:04:28 +01:00
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 ) )
2018-12-28 09:25:04 +01:00
if " PYTHON_COMMAND " in os . environ :
EdkLogger . quiet ( " %-16s = %s " % ( " PYTHON_COMMAND " , os . environ [ " PYTHON_COMMAND " ] ) )
2016-03-31 08:05:59 +02:00
self . InitPreBuild ( )
self . InitPostBuild ( )
2017-08-02 23:07:05 +02:00
if self . Prebuild :
EdkLogger . quiet ( " %-16s = %s " % ( " PREBUILD " , self . Prebuild ) )
if self . Postbuild :
EdkLogger . quiet ( " %-16s = %s " % ( " POSTBUILD " , self . Postbuild ) )
if self . Prebuild :
2016-03-31 08:05:59 +02:00
self . LaunchPrebuild ( )
2020-01-10 09:29:45 +01:00
TargetObj = TargetTxtDict ( )
ToolDefObj = ToolDefDict ( ( os . path . join ( os . getenv ( " WORKSPACE " ) , " Conf " ) ) )
self . TargetTxt = TargetObj . Target
self . ToolDef = ToolDefObj . ToolDef
2016-03-31 08:05:59 +02:00
if not ( self . LaunchPrebuildFlag and os . path . exists ( self . PlatformBuildPath ) ) :
self . InitBuild ( )
2010-03-01 00:39:39 +01:00
2019-07-30 11:15:31 +02:00
self . AutoGenMgr = None
2016-03-31 08:05:59 +02:00
EdkLogger . info ( " " )
2010-03-01 00:39:39 +01:00
os . chdir ( self . WorkspaceDir )
2019-07-31 07:31:15 +02:00
self . log_q = log_q
2019-09-09 03:12:28 +02:00
GlobalData . file_lock = mp . Lock ( )
2019-11-19 09:17:00 +01:00
# Init cache data for local only
GlobalData . gPackageHashFile = dict ( )
GlobalData . gModulePreMakeCacheStatus = dict ( )
GlobalData . gModuleMakeCacheStatus = dict ( )
GlobalData . gHashChainStatus = dict ( )
GlobalData . gCMakeHashFile = dict ( )
GlobalData . gModuleHashFile = dict ( )
GlobalData . gFileHashDict = dict ( )
GlobalData . gModuleAllCacheStatus = set ( )
GlobalData . gModuleCacheHit = set ( )
def StartAutoGen ( self , mqueue , DataPipe , SkipAutoGen , PcdMaList , cqueue ) :
2019-07-30 11:15:31 +02:00
try :
if SkipAutoGen :
return True , 0
feedback_q = mp . Queue ( )
error_event = mp . Event ( )
2019-08-15 16:26:17 +02:00
FfsCmd = DataPipe . Get ( " FfsCommand " )
if FfsCmd is None :
FfsCmd = { }
GlobalData . FfsCmd = FfsCmd
2019-11-19 09:17:00 +01:00
auto_workers = [ AutoGenWorkerInProcess ( mqueue , DataPipe . dump_file , feedback_q , GlobalData . file_lock , cqueue , self . log_q , error_event ) for _ in range ( self . ThreadNumber ) ]
2019-07-30 11:15:31 +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 :
2019-11-19 09:17:00 +01:00
# SourceFileList calling sequence impact the makefile string sequence.
# Create cached SourceFileList here to unify its calling sequence for both
# CanSkipbyPreMakeCache and CreateCodeFile/CreateMakeFile.
RetVal = PcdMa . SourceFileList
# Force cache miss for PCD driver
if GlobalData . gUseHashCache and not GlobalData . gBinCacheDest and self . Target in [ None , " " , " all " ] :
cqueue . put ( ( PcdMa . MetaFile . Path , PcdMa . Arch , " PreMakeCache " , False ) )
2019-08-15 16:26:17 +02:00
2019-07-30 11:15:31 +02:00
PcdMa . CreateCodeFile ( False )
2019-09-06 15:22:59 +02:00
PcdMa . CreateMakeFile ( False , GenFfsList = DataPipe . Get ( " FfsCommand " ) . get ( ( PcdMa . MetaFile . Path , PcdMa . Arch ) , [ ] ) )
2020-08-12 08:09:03 +02:00
PcdMa . CreateAsBuiltInf ( )
2019-11-19 09:17:00 +01:00
# Force cache miss for PCD driver
2019-08-15 16:26:17 +02:00
if GlobalData . gBinCacheSource and self . Target in [ None , " " , " all " ] :
2019-11-19 09:17:00 +01:00
cqueue . put ( ( PcdMa . MetaFile . Path , PcdMa . Arch , " MakeCache " , False ) )
2019-08-15 16:26:17 +02:00
2019-07-30 11:15:31 +02:00
self . AutoGenMgr . join ( )
rt = self . AutoGenMgr . Status
2020-06-02 23:58:50 +02:00
err = 0
if not rt :
err = UNKNOWN_ERROR
return rt , err
2019-08-15 16:26:17 +02:00
except FatalError as e :
return False , e . args [ 0 ]
except :
return False , UNKNOWN_ERROR
2010-03-01 00:39:39 +01:00
2021-04-21 08:12:51 +02:00
## Add TOOLCHAIN and FAMILY declared in DSC [BuildOptions] to ToolsDefTxtDatabase.
#
# Loop through the set of build targets, tool chains, and archs provided on either
# the command line or in target.txt to discover FAMILY and TOOLCHAIN delclarations
# in [BuildOptions] sections that may be within !if expressions that may use
# $(TARGET), $(TOOLCHAIN), $(TOOLCHAIN_TAG), or $(ARCH) operands.
#
def GetToolChainAndFamilyFromDsc ( self , File ) :
2021-04-30 04:01:05 +02:00
SavedGlobalDefines = GlobalData . gGlobalDefines . copy ( )
2021-04-21 08:12:51 +02:00
for BuildTarget in self . BuildTargetList :
GlobalData . gGlobalDefines [ ' TARGET ' ] = BuildTarget
for BuildToolChain in self . ToolChainList :
GlobalData . gGlobalDefines [ ' TOOLCHAIN ' ] = BuildToolChain
GlobalData . gGlobalDefines [ ' TOOL_CHAIN_TAG ' ] = BuildToolChain
for BuildArch in self . ArchList :
GlobalData . gGlobalDefines [ ' ARCH ' ] = BuildArch
dscobj = self . BuildDatabase [ File , BuildArch ]
for KeyFamily , Key , KeyCodeBase in dscobj . BuildOptions :
try :
Target , ToolChain , Arch , Tool , Attr = Key . split ( ' _ ' )
except :
continue
if ToolChain == TAB_STAR or Attr != TAB_TOD_DEFINES_FAMILY :
continue
try :
Family = dscobj . BuildOptions [ ( KeyFamily , Key , KeyCodeBase ) ]
Family = Family . strip ( ) . strip ( ' = ' ) . strip ( )
except :
continue
if TAB_TOD_DEFINES_FAMILY not in self . ToolDef . ToolsDefTxtDatabase :
self . ToolDef . ToolsDefTxtDatabase [ TAB_TOD_DEFINES_FAMILY ] = { }
if ToolChain not in self . ToolDef . ToolsDefTxtDatabase [ TAB_TOD_DEFINES_FAMILY ] :
self . ToolDef . ToolsDefTxtDatabase [ TAB_TOD_DEFINES_FAMILY ] [ ToolChain ] = Family
if TAB_TOD_DEFINES_BUILDRULEFAMILY not in self . ToolDef . ToolsDefTxtDatabase :
self . ToolDef . ToolsDefTxtDatabase [ TAB_TOD_DEFINES_BUILDRULEFAMILY ] = { }
if ToolChain not in self . ToolDef . ToolsDefTxtDatabase [ TAB_TOD_DEFINES_BUILDRULEFAMILY ] :
self . ToolDef . ToolsDefTxtDatabase [ TAB_TOD_DEFINES_BUILDRULEFAMILY ] [ ToolChain ] = Family
if TAB_TOD_DEFINES_TOOL_CHAIN_TAG not in self . ToolDef . ToolsDefTxtDatabase :
self . ToolDef . ToolsDefTxtDatabase [ TAB_TOD_DEFINES_TOOL_CHAIN_TAG ] = [ ]
if ToolChain not in self . ToolDef . ToolsDefTxtDatabase [ TAB_TOD_DEFINES_TOOL_CHAIN_TAG ] :
self . ToolDef . ToolsDefTxtDatabase [ TAB_TOD_DEFINES_TOOL_CHAIN_TAG ] . append ( ToolChain )
2021-04-30 04:01:05 +02:00
GlobalData . gGlobalDefines = SavedGlobalDefines
2021-04-21 08:12:51 +02:00
2010-03-01 00:39:39 +01:00
## 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
2011-10-29 08:59:30 +02:00
if not self . ArchList :
2019-01-09 20:00:41 +01:00
self . ArchList = self . TargetTxt . TargetTxtDictionary [ TAB_TAT_DEFINES_TARGET_ARCH ]
2011-10-29 08:59:30 +02:00
self . ArchList = tuple ( self . ArchList )
2010-03-01 00:39:39 +01:00
# if no build target given in command line, get it from target.txt
2011-10-29 08:59:30 +02:00
if not self . BuildTargetList :
2019-01-09 20:00:41 +01:00
self . BuildTargetList = self . TargetTxt . TargetTxtDictionary [ TAB_TAT_DEFINES_TARGET ]
2010-03-01 00:39:39 +01:00
# if no tool chain given in command line, get it from target.txt
2011-10-29 08:59:30 +02:00
if not self . ToolChainList :
2019-01-09 20:00:41 +01:00
self . ToolChainList = self . TargetTxt . TargetTxtDictionary [ TAB_TAT_DEFINES_TOOL_CHAIN_TAG ]
2018-03-26 22:25:43 +02:00
if self . ToolChainList is None or len ( self . ToolChainList ) == 0 :
2010-03-01 00:39:39 +01:00
EdkLogger . error ( " build " , RESOURCE_NOT_AVAILABLE , ExtraData = " No toolchain given. Don ' t know how to build. \n " )
2021-04-21 08:12:51 +02:00
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 . GetToolChainAndFamilyFromDsc ( self . PlatformFile )
2010-03-01 00:39:39 +01:00
# 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
2016-07-04 10:34:28 +02:00
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 ] :
2017-07-25 07:38:30 +02:00
EdkLogger . warn ( " build " , " No tool chain family found in configuration for %s . Default to MSFT. " % Tool )
2018-08-24 18:33:17 +02:00
ToolChainFamily . append ( TAB_COMPILER_MSFT )
2016-07-04 10:34:28 +02:00
else :
ToolChainFamily . append ( ToolDefinition [ TAB_TOD_DEFINES_FAMILY ] [ Tool ] )
self . ToolChainFamily = ToolChainFamily
2019-07-31 07:33:31 +02:00
self . ThreadNumber = ThreadNum ( )
2010-03-01 00:39:39 +01:00
## 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 ) :
2011-10-29 08:59:30 +02:00
# parse target.txt, tools_def.txt, and platform file
2013-08-23 04:18:16 +02:00
self . LoadConfiguration ( )
2011-10-29 08:59:30 +02:00
# Allow case-insensitive for those from command line or configuration file
ErrorCode , ErrorInfo = self . PlatformFile . Validate ( " .dsc " , False )
2010-03-01 00:39:39 +01:00
if ErrorCode != 0 :
EdkLogger . error ( " build " , ErrorCode , ExtraData = ErrorInfo )
2016-03-31 08:05:59 +02:00
def InitPreBuild ( self ) :
self . LoadConfiguration ( )
2016-04-15 10:46:48 +02:00
ErrorCode , ErrorInfo = self . PlatformFile . Validate ( " .dsc " , False )
if ErrorCode != 0 :
EdkLogger . error ( " build " , ErrorCode , ExtraData = ErrorInfo )
2016-03-31 08:05:59 +02:00
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 ]
2016-07-04 10:34:28 +02:00
if self . ToolChainFamily :
GlobalData . gGlobalDefines [ ' FAMILY ' ] = self . ToolChainFamily [ 0 ]
2018-04-17 16:40:15 +02:00
if ' PREBUILD ' in GlobalData . gCommandLineDefines :
2016-03-31 08:05:59 +02:00
self . Prebuild = GlobalData . gCommandLineDefines . get ( ' PREBUILD ' )
else :
self . Db_Flag = True
2018-09-11 00:18:05 +02:00
Platform = self . Db . MapPlatform ( str ( self . PlatformFile ) )
2016-03-31 08:05:59 +02:00
self . Prebuild = str ( Platform . Prebuild )
if self . Prebuild :
2017-08-02 23:07:05 +02:00
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 )
2010-03-01 00:39:39 +01:00
2016-03-31 08:05:59 +02:00
def InitPostBuild ( self ) :
2018-04-17 16:40:15 +02:00
if ' POSTBUILD ' in GlobalData . gCommandLineDefines :
2016-03-31 08:05:59 +02:00
self . Postbuild = GlobalData . gCommandLineDefines . get ( ' POSTBUILD ' )
else :
2018-09-11 00:18:05 +02:00
Platform = self . Db . MapPlatform ( str ( self . PlatformFile ) )
2016-03-31 08:05:59 +02:00
self . Postbuild = str ( Platform . Postbuild )
if self . Postbuild :
2017-08-02 23:07:05 +02:00
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 ) :
2016-03-31 08:05:59 +02:00
BuildStr = ' '
if GlobalData . gCommand and isinstance ( GlobalData . gCommand , list ) :
BuildStr + = ' ' + ' ' . join ( GlobalData . gCommand )
TargetFlag = False
ArchFlag = False
ToolChainFlag = False
2017-08-02 23:07:05 +02:00
PlatformFileFlag = False
2016-03-31 08:05:59 +02:00
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
2017-08-02 23:07:05 +02:00
if GlobalData . gOptions and not GlobalData . gOptions . PlatformFile :
PlatformFileFlag = True
2016-03-31 08:05:59 +02:00
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
2017-08-02 23:07:05 +02:00
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
2016-03-31 08:05:59 +02:00
return BuildStr
def LaunchPrebuild ( self ) :
if self . Prebuild :
EdkLogger . info ( " \n - Prebuild Start - \n " )
self . LaunchPrebuildFlag = True
2017-07-25 07:56:53 +02:00
#
# 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.
#
2018-06-25 12:31:33 +02:00
PrebuildEnvFile = os . path . join ( GlobalData . gConfDirectory , ' .cache ' , ' .PrebuildEnv ' )
2016-03-31 08:05:59 +02:00
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 ) )
2017-01-31 18:21:20 +01:00
Process = Popen ( args , stdout = PIPE , stderr = PIPE , shell = True )
2016-03-31 08:05:59 +02:00
else :
args = ' && ' . join ( ( self . Prebuild , ' env > ' + PrebuildEnvFile ) )
2017-05-03 09:31:58 +02:00
Process = Popen ( args , stdout = PIPE , stderr = PIPE , shell = True )
2016-03-31 08:05:59 +02:00
# 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 ) )
2021-07-23 22:02:26 +02:00
StdOutThread . name = " STDOUT-Redirector "
StdOutThread . daemon = False
2016-03-31 08:05:59 +02:00
StdOutThread . start ( )
if Process . stderr :
StdErrThread = Thread ( target = ReadMessage , args = ( Process . stderr , EdkLogger . quiet , EndOfProcedure ) )
2021-07-23 22:02:26 +02:00
StdErrThread . name = " STDERR-Redirector "
StdErrThread . daemon = False
2016-03-31 08:05:59 +02:00
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 ( )
2018-12-06 02:09:36 +01:00
envs = [ l . split ( " = " , 1 ) for l in envs ]
envs = [ [ I . strip ( ) for I in item ] for item in envs if len ( item ) == 2 ]
2016-03-31 08:05:59 +02:00
os . environ . update ( dict ( envs ) )
EdkLogger . info ( " \n - Prebuild Done - \n " )
2017-04-26 10:53:58 +02:00
def LaunchPostbuild ( self ) :
2016-03-31 08:05:59 +02:00
if self . Postbuild :
EdkLogger . info ( " \n - Postbuild Start - \n " )
if sys . platform == " win32 " :
2017-01-31 18:21:20 +01:00
Process = Popen ( self . Postbuild , stdout = PIPE , stderr = PIPE , shell = True )
2016-03-31 08:05:59 +02:00
else :
2017-05-03 09:31:58 +02:00
Process = Popen ( self . Postbuild , stdout = PIPE , stderr = PIPE , shell = True )
2016-03-31 08:05:59 +02:00
# 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 ) )
2021-07-23 22:02:26 +02:00
StdOutThread . name = " STDOUT-Redirector "
StdOutThread . daemon = False
2016-03-31 08:05:59 +02:00
StdOutThread . start ( )
if Process . stderr :
StdErrThread = Thread ( target = ReadMessage , args = ( Process . stderr , EdkLogger . quiet , EndOfProcedure ) )
2021-07-23 22:02:26 +02:00
StdErrThread . name = " STDERR-Redirector "
StdErrThread . daemon = False
2016-03-31 08:05:59 +02:00
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 " )
2019-04-10 17:27:05 +02:00
2010-03-01 00:39:39 +01:00
## Build a module or platform
#
2010-10-11 08:26:52 +02:00
# Create autogen code and makefile for a module or platform, and the launch
2010-03-01 00:39:39 +01:00
# "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
#
2019-07-30 11:15:31 +02:00
def _BuildPa ( self , Target , AutoGenObject , CreateDepsCodeFile = True , CreateDepsMakeFile = True , BuildModule = False , FfsCommand = None , PcdMaList = None ) :
2018-03-26 22:25:43 +02:00
if AutoGenObject is None :
2010-03-01 00:39:39 +01:00
return False
2019-07-30 11:15:31 +02:00
if FfsCommand is None :
FfsCommand = { }
2010-03-01 00:39:39 +01:00
# 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
2019-07-30 11:15:31 +02:00
mqueue = mp . Queue ( )
for m in AutoGenObject . GetAllModuleInfo :
mqueue . put ( m )
2020-08-03 04:03:38 +02:00
mqueue . put ( ( None , None , None , None , None , None , None ) )
2019-08-15 16:26:17 +02:00
AutoGenObject . DataPipe . DataContainer = { " CommandTarget " : self . Target }
2019-09-05 11:04:58 +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-07-30 11:15:31 +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 )
2019-11-19 09:17:00 +01:00
cqueue = mp . Queue ( )
autogen_rt , errorcode = self . StartAutoGen ( mqueue , AutoGenObject . DataPipe , self . SkipAutoGen , PcdMaList , cqueue )
2019-09-05 11:04:58 +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-07-30 11:15:31 +02:00
self . Progress . Stop ( " done! " )
if not autogen_rt :
self . AutoGenMgr . TerminateWorkers ( )
2019-09-05 11:04:58 +02:00
self . AutoGenMgr . join ( 1 )
2019-07-30 11:15:31 +02:00
raise FatalError ( errorcode )
2010-03-01 00:39:39 +01:00
AutoGenObject . CreateCodeFile ( False )
AutoGenObject . CreateMakeFile ( False )
2019-07-30 11:15:31 +02:00
else :
# always recreate top/platform makefile when clean, just in case of inconsistency
AutoGenObject . CreateCodeFile ( True )
AutoGenObject . CreateMakeFile ( True )
2010-03-01 00:39:39 +01:00
if EdkLogger . GetLevel ( ) == EdkLogger . QUIET :
EdkLogger . quiet ( " Building ... %s " % repr ( AutoGenObject ) )
BuildCommand = AutoGenObject . BuildCommand
2018-03-26 22:25:43 +02:00
if BuildCommand is None or len ( BuildCommand ) == 0 :
2011-10-29 08:59:30 +02:00
EdkLogger . error ( " build " , OPTION_MISSING ,
" No build command found for this module. "
2013-08-23 04:18:16 +02:00
" Please check your setting of %s _ %s _ %s _MAKE_PATH in Conf/tools_def.txt file. " %
2011-10-29 08:59:30 +02:00
( AutoGenObject . BuildTarget , AutoGenObject . ToolChain , AutoGenObject . Arch ) ,
ExtraData = str ( AutoGenObject ) )
2010-03-01 00:39:39 +01:00
2014-08-18 06:59:01 +02:00
# run
if Target == ' run ' :
return True
2021-09-23 10:59:01 +02:00
# Fetch the MakeFileName.
self . MakeFileName = AutoGenObject . MakeFileName
2014-08-18 06:59:01 +02:00
# build modules
if BuildModule :
BuildCommand = BuildCommand + [ Target ]
LaunchCommand ( BuildCommand , AutoGenObject . MakeFileDir )
2019-06-24 03:51:44 +02:00
if GlobalData . gBinCacheDest :
2019-11-19 09:17:00 +01:00
self . GenDestCache ( )
elif GlobalData . gUseHashCache and not GlobalData . gBinCacheSource :
# Only for --hash
# Update PreMakeCacheChain files
self . GenLocalPreMakeCache ( )
2019-06-24 03:51:44 +02:00
self . BuildModules = [ ]
2014-08-18 06:59:01 +02:00
return True
# build library
if Target == ' libraries ' :
2019-11-20 03:58:30 +01:00
DirList = [ ]
for Lib in AutoGenObject . LibraryAutoGenList :
if not Lib . IsBinaryModule :
DirList . append ( ( os . path . join ( AutoGenObject . BuildDir , Lib . BuildDir ) , Lib ) )
for Lib , LibAutoGen in DirList :
2020-02-10 11:49:07 +01:00
NewBuildCommand = BuildCommand + [ ' -f ' , os . path . normpath ( os . path . join ( Lib , self . MakeFileName ) ) , ' pbuild ' ]
2019-11-20 03:58:30 +01:00
LaunchCommand ( NewBuildCommand , AutoGenObject . MakeFileDir , LibAutoGen )
2014-08-18 06:59:01 +02:00
return True
# build module
if Target == ' modules ' :
2019-11-20 03:58:30 +01:00
DirList = [ ]
for Lib in AutoGenObject . LibraryAutoGenList :
if not Lib . IsBinaryModule :
DirList . append ( ( os . path . join ( AutoGenObject . BuildDir , Lib . BuildDir ) , Lib ) )
for Lib , LibAutoGen in DirList :
2020-02-10 11:49:07 +01:00
NewBuildCommand = BuildCommand + [ ' -f ' , os . path . normpath ( os . path . join ( Lib , self . MakeFileName ) ) , ' pbuild ' ]
2019-11-20 03:58:30 +01:00
LaunchCommand ( NewBuildCommand , AutoGenObject . MakeFileDir , LibAutoGen )
DirList = [ ]
for ModuleAutoGen in AutoGenObject . ModuleAutoGenList :
if not ModuleAutoGen . IsBinaryModule :
DirList . append ( ( os . path . join ( AutoGenObject . BuildDir , ModuleAutoGen . BuildDir ) , ModuleAutoGen ) )
for Mod , ModAutoGen in DirList :
2020-02-10 11:49:07 +01:00
NewBuildCommand = BuildCommand + [ ' -f ' , os . path . normpath ( os . path . join ( Mod , self . MakeFileName ) ) , ' pbuild ' ]
2019-11-20 03:58:30 +01:00
LaunchCommand ( NewBuildCommand , AutoGenObject . MakeFileDir , ModAutoGen )
2014-08-26 04:52:24 +02:00
self . CreateAsBuiltInf ( )
2019-06-24 03:51:44 +02:00
if GlobalData . gBinCacheDest :
2019-11-19 09:17:00 +01:00
self . GenDestCache ( )
elif GlobalData . gUseHashCache and not GlobalData . gBinCacheSource :
# Only for --hash
# Update PreMakeCacheChain files
self . GenLocalPreMakeCache ( )
2019-06-24 03:51:44 +02:00
self . BuildModules = [ ]
2014-08-18 06:59:01 +02:00
return True
# cleanlib
if Target == ' cleanlib ' :
for Lib in AutoGenObject . LibraryBuildDirectoryList :
2020-02-10 11:49:07 +01:00
LibMakefile = os . path . normpath ( os . path . join ( Lib , self . MakeFileName ) )
2014-08-18 06:59:01 +02:00
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 :
2020-02-10 11:49:07 +01:00
ModMakefile = os . path . normpath ( os . path . join ( Mod , self . MakeFileName ) )
2014-08-18 06:59:01 +02:00
if os . path . exists ( ModMakefile ) :
NewBuildCommand = BuildCommand + [ ' -f ' , ModMakefile , ' cleanall ' ]
LaunchCommand ( NewBuildCommand , AutoGenObject . MakeFileDir )
for Lib in AutoGenObject . LibraryBuildDirectoryList :
2020-02-10 11:49:07 +01:00
LibMakefile = os . path . normpath ( os . path . join ( Lib , self . MakeFileName ) )
2014-08-18 06:59:01 +02:00
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 )
2018-06-25 12:31:25 +02:00
except WindowsError as X :
2014-08-18 06:59:01 +02:00
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 ) :
2018-03-26 22:25:43 +02:00
if AutoGenObject is None :
2014-08-18 06:59:01 +02:00
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
2019-07-30 11:15:31 +02:00
AutoGenObject . CreateCodeFile ( True )
AutoGenObject . CreateMakeFile ( True )
2014-08-18 06:59:01 +02:00
if EdkLogger . GetLevel ( ) == EdkLogger . QUIET :
EdkLogger . quiet ( " Building ... %s " % repr ( AutoGenObject ) )
BuildCommand = AutoGenObject . BuildCommand
2018-03-26 22:25:43 +02:00
if BuildCommand is None or len ( BuildCommand ) == 0 :
2014-08-18 06:59:01 +02:00
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 ) )
2015-01-19 06:01:39 +01:00
# build modules
if BuildModule :
if Target != ' fds ' :
BuildCommand = BuildCommand + [ Target ]
2017-09-11 10:50:07 +02:00
AutoGenObject . BuildTime = LaunchCommand ( BuildCommand , AutoGenObject . MakeFileDir )
2015-01-19 06:01:39 +01:00
self . CreateAsBuiltInf ( )
2019-06-24 03:51:44 +02:00
if GlobalData . gBinCacheDest :
2019-11-19 09:17:00 +01:00
self . GenDestCache ( )
elif GlobalData . gUseHashCache and not GlobalData . gBinCacheSource :
# Only for --hash
# Update PreMakeCacheChain files
self . GenLocalPreMakeCache ( )
2019-06-24 03:51:44 +02:00
self . BuildModules = [ ]
2015-01-19 06:01:39 +01:00
return True
2014-08-18 06:59:01 +02:00
# genfds
if Target == ' fds ' :
2018-12-18 09:40:34 +01:00
if GenFdsApi ( AutoGenObject . GenFdsCommandDict , self . Db ) :
EdkLogger . error ( " build " , COMMAND_FAILURE )
2020-04-20 03:20:52 +02:00
Threshold = self . GetFreeSizeThreshold ( )
if Threshold :
self . CheckFreeSizeThreshold ( Threshold , AutoGenObject . FvDir )
2014-08-18 06:59:01 +02:00
return True
# run
if Target == ' run ' :
return True
# build library
if Target == ' libraries ' :
pass
# not build modules
# cleanall
2010-03-01 00:39:39 +01:00
if Target == ' cleanall ' :
try :
#os.rmdir(AutoGenObject.BuildDir)
RemoveDirectory ( AutoGenObject . BuildDir , True )
2018-06-25 12:31:25 +02:00
except WindowsError as X :
2010-03-01 00:39:39 +01:00
EdkLogger . error ( " build " , FILE_DELETE_FAILURE , ExtraData = str ( X ) )
return True
2010-11-15 03:51:34 +01:00
## Rebase module image and Get function address for the input module list.
2010-03-01 00:39:39 +01:00
#
def _RebaseModule ( self , MapBuffer , BaseAddress , ModuleList , AddrIsOffset = True , ModeIsSmm = False ) :
if ModeIsSmm :
AddrIsOffset = False
2018-04-06 01:14:02 +02:00
for InfFile in ModuleList :
2011-05-11 12:26:49 +02:00
sys . stdout . write ( " . " )
sys . stdout . flush ( )
2010-03-01 00:39:39 +01:00
ModuleInfo = ModuleList [ InfFile ]
ModuleName = ModuleInfo . BaseName
2010-03-19 07:55:07 +01:00
ModuleOutputImage = ModuleInfo . Image . FileName
ModuleDebugImage = os . path . join ( ModuleInfo . DebugDir , ModuleInfo . BaseName + ' .efi ' )
2010-03-01 00:39:39 +01:00
## 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
#
2010-03-19 07:55:07 +01:00
LaunchCommand ( [ " GenFw " , " --rebase " , str ( BaseAddress ) , " -r " , ModuleOutputImage ] , ModuleInfo . OutputDir )
2015-12-01 05:22:16 +01:00
LaunchCommand ( [ " GenFw " , " --rebase " , str ( BaseAddress ) , " -r " , ModuleDebugImage ] , ModuleInfo . DebugDir )
2010-03-01 00:39:39 +01:00
else :
#
# Set new address to the section header only for SMM driver.
#
2010-03-19 07:55:07 +01:00
LaunchCommand ( [ " GenFw " , " --address " , str ( BaseAddress ) , " -r " , ModuleOutputImage ] , ModuleInfo . OutputDir )
2015-12-01 05:22:16 +01:00
LaunchCommand ( [ " GenFw " , " --address " , str ( BaseAddress ) , " -r " , ModuleDebugImage ] , ModuleInfo . DebugDir )
2010-03-01 00:39:39 +01:00
#
2019-02-06 08:44:39 +01:00
# Collect function address from Map file
2010-03-01 00:39:39 +01:00
#
2010-03-19 07:55:07 +01:00
ImageMapTable = ModuleOutputImage . replace ( ' .efi ' , ' .map ' )
2010-03-01 00:39:39 +01:00
FunctionList = [ ]
if os . path . exists ( ImageMapTable ) :
OrigImageBaseAddress = 0
2015-12-01 05:22:16 +01:00
ImageMap = open ( ImageMapTable , ' r ' )
2010-03-01 00:39:39 +01:00
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 :
2015-12-01 05:22:16 +01:00
if StrList [ 3 ] == ' f ' or StrList [ 3 ] == ' F ' :
2010-03-01 00:39:39 +01:00
Name = StrList [ 1 ]
RelativeAddress = int ( StrList [ 2 ] , 16 ) - OrigImageBaseAddress
FunctionList . append ( ( Name , RelativeAddress ) )
2019-01-09 07:44:36 +01:00
2010-03-01 00:39:39 +01:00
ImageMap . close ( )
#
# Add general information.
#
if ModeIsSmm :
2019-01-23 03:16:00 +01:00
MapBuffer . append ( ' \n \n %s (Fixed SMRAM Offset, BaseAddress=0x %010X , EntryPoint=0x %010X ) \n ' % ( ModuleName , BaseAddress , BaseAddress + ModuleInfo . Image . EntryPoint ) )
2010-03-01 00:39:39 +01:00
elif AddrIsOffset :
2019-01-23 03:16:00 +01:00
MapBuffer . append ( ' \n \n %s (Fixed Memory Offset, BaseAddress=-0x %010X , EntryPoint=-0x %010X ) \n ' % ( ModuleName , 0 - BaseAddress , 0 - ( BaseAddress + ModuleInfo . Image . EntryPoint ) ) )
2010-03-01 00:39:39 +01:00
else :
2019-01-23 03:16:00 +01:00
MapBuffer . append ( ' \n \n %s (Fixed Memory Address, BaseAddress=0x %010X , EntryPoint=0x %010X ) \n ' % ( ModuleName , BaseAddress , BaseAddress + ModuleInfo . Image . EntryPoint ) )
2010-03-01 00:39:39 +01:00
#
# 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 :
2019-01-23 03:16:00 +01:00
MapBuffer . append ( ' (GUID= %s , .textbaseaddress=-0x %010X , .databaseaddress=-0x %010X ) \n ' % ( ModuleInfo . Guid , 0 - ( BaseAddress + TextSectionAddress ) , 0 - ( BaseAddress + DataSectionAddress ) ) )
2010-03-01 00:39:39 +01:00
else :
2019-01-23 03:16:00 +01:00
MapBuffer . append ( ' (GUID= %s , .textbaseaddress=0x %010X , .databaseaddress=0x %010X ) \n ' % ( ModuleInfo . Guid , BaseAddress + TextSectionAddress , BaseAddress + DataSectionAddress ) )
2010-03-19 07:55:07 +01:00
#
# Add debug image full path.
#
2019-01-23 03:16:00 +01:00
MapBuffer . append ( ' (IMAGE= %s ) \n \n ' % ( ModuleDebugImage ) )
2010-03-01 00:39:39 +01:00
#
2019-02-06 08:44:39 +01:00
# Add function address
2010-03-01 00:39:39 +01:00
#
for Function in FunctionList :
if AddrIsOffset :
2019-01-23 03:16:00 +01:00
MapBuffer . append ( ' -0x %010X %s \n ' % ( 0 - ( BaseAddress + Function [ 1 ] ) , Function [ 0 ] ) )
2010-03-01 00:39:39 +01:00
else :
2019-01-23 03:16:00 +01:00
MapBuffer . append ( ' 0x %010X %s \n ' % ( BaseAddress + Function [ 1 ] , Function [ 0 ] ) )
2010-03-01 00:39:39 +01:00
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
#
2010-03-12 11:54:01 +01:00
def _CollectFvMapBuffer ( self , MapBuffer , Wa , ModuleList ) :
2011-10-29 08:59:30 +02:00
if self . Fdf :
2010-03-01 00:39:39 +01:00
# First get the XIP base address for FV map file.
2010-03-12 11:54:01 +01:00
GuidPattern = re . compile ( " [-a-fA-F0-9]+ " )
2019-07-12 19:29:28 +02:00
GuidName = re . compile ( r " \ (GUID=[-a-fA-F0-9]+ " )
2018-04-17 16:40:15 +02:00
for FvName in Wa . FdfProfile . FvDict :
2010-03-01 00:39:39 +01:00
FvMapBuffer = os . path . join ( Wa . FvDir , FvName + ' .Fv.map ' )
if not os . path . exists ( FvMapBuffer ) :
continue
2014-08-15 05:06:48 +02:00
FvMap = open ( FvMapBuffer , ' r ' )
2010-03-01 00:39:39 +01:00
#skip FV size information
FvMap . readline ( )
FvMap . readline ( )
FvMap . readline ( )
FvMap . readline ( )
2010-03-12 11:54:01 +01:00
for Line in FvMap :
MatchGuid = GuidPattern . match ( Line )
2018-03-26 22:25:43 +02:00
if MatchGuid is not None :
2010-03-12 11:54:01 +01:00
#
# Replace GUID with module name
#
GuidString = MatchGuid . group ( )
if GuidString . upper ( ) in ModuleList :
Line = Line . replace ( GuidString , ModuleList [ GuidString . upper ( ) ] . Name )
2019-01-23 03:16:00 +01:00
MapBuffer . append ( Line )
2010-03-19 07:55:07 +01:00
#
# Add the debug image full path.
#
MatchGuid = GuidName . match ( Line )
2018-03-26 22:25:43 +02:00
if MatchGuid is not None :
2010-03-19 07:55:07 +01:00
GuidString = MatchGuid . group ( ) . split ( " = " ) [ 1 ]
if GuidString . upper ( ) in ModuleList :
2019-01-23 03:16:00 +01:00
MapBuffer . append ( ' (IMAGE= %s ) \n ' % ( os . path . join ( ModuleList [ GuidString . upper ( ) ] . DebugDir , ModuleList [ GuidString . upper ( ) ] . Name + ' .efi ' ) ) )
2010-03-19 07:55:07 +01:00
2010-03-01 00:39:39 +01:00
FvMap . close ( )
## Collect MAP information of all modules
#
def _CollectModuleMapBuffer ( self , MapBuffer , ModuleList ) :
2011-05-11 12:26:49 +02:00
sys . stdout . write ( " Generate Load Module At Fix Address Map " )
sys . stdout . flush ( )
2010-03-01 00:39:39 +01:00
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
2010-03-12 11:54:01 +01:00
for ModuleGuid in ModuleList :
Module = ModuleList [ ModuleGuid ]
2010-03-01 00:39:39 +01:00
GlobalData . gProcessingFile = " %s [ %s , %s , %s ] " % ( Module . MetaFile , Module . Arch , Module . ToolChain , Module . BuildTarget )
2013-08-23 04:18:16 +02:00
2010-03-01 00:39:39 +01:00
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 )
2010-03-19 07:55:07 +01:00
ImageInfo = PeImageInfo ( Module . Name , Module . Guid , Module . Arch , Module . OutputDir , Module . DebugDir , ImageClass )
2018-04-27 16:04:15 +02:00
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 ] :
2010-03-01 00:39:39 +01:00
PeiModuleList [ Module . MetaFile ] = ImageInfo
PeiSize + = ImageInfo . Image . Size
2018-04-27 16:04:15 +02:00
elif Module . ModuleType in [ EDK_COMPONENT_TYPE_BS_DRIVER , SUP_MODULE_DXE_DRIVER , SUP_MODULE_UEFI_DRIVER ] :
2010-03-01 00:39:39 +01:00
BtModuleList [ Module . MetaFile ] = ImageInfo
BtSize + = ImageInfo . Image . Size
2018-04-27 16:04:15 +02:00
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 ] :
2010-03-01 00:39:39 +01:00
RtModuleList [ Module . MetaFile ] = ImageInfo
RtSize + = ImageInfo . Image . Size
2018-04-26 18:57:53 +02:00
elif Module . ModuleType in [ SUP_MODULE_SMM_CORE , SUP_MODULE_DXE_SMM_DRIVER , SUP_MODULE_MM_STANDALONE , SUP_MODULE_MM_CORE_STANDALONE ] :
2010-03-01 00:39:39 +01:00
SmmModuleList [ Module . MetaFile ] = ImageInfo
SmmSize + = ImageInfo . Image . Size
2018-04-26 18:57:53 +02:00
if Module . ModuleType == SUP_MODULE_DXE_SMM_DRIVER :
2018-04-13 22:51:32 +02:00
PiSpecVersion = Module . Module . Specification . get ( ' PI_SPECIFICATION_VERSION ' , ' 0x00000000 ' )
2010-03-01 00:39:39 +01:00
# for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
2011-05-11 12:26:49 +02:00
if int ( PiSpecVersion , 16 ) < 0x0001000A :
2010-03-01 00:39:39 +01:00
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 :
2018-04-20 17:51:37 +02:00
if Pcd . Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd . TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET :
2010-03-01 00:39:39 +01:00
ModuleIsPatch = True
break
if not ModuleIsPatch :
for Pcd in Module . LibraryPcdList :
2018-04-20 17:51:37 +02:00
if Pcd . Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd . TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET :
2010-03-01 00:39:39 +01:00
ModuleIsPatch = True
break
2013-08-23 04:18:16 +02:00
2010-03-01 00:39:39 +01:00
if not ModuleIsPatch :
continue
#
# Module includes the patchable load fix address PCDs.
2013-08-23 04:18:16 +02:00
# It will be fixed up later.
2010-03-01 00:39:39 +01:00
#
PatchEfiImageList . append ( OutputImageFile )
2013-08-23 04:18:16 +02:00
2010-03-01 00:39:39 +01:00
#
# 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
#
2013-08-23 04:18:16 +02:00
for EfiImage in PatchEfiImageList :
2010-03-01 00:39:39 +01:00
EfiImageMap = EfiImage . replace ( ' .efi ' , ' .map ' )
if not os . path . exists ( EfiImageMap ) :
continue
#
# Get PCD offset in EFI image by GenPatchPcdTable function
#
2013-08-23 04:18:16 +02:00
PcdTable = parsePcdInfoFromMapFile ( EfiImageMap , EfiImage )
2010-03-01 00:39:39 +01:00
#
# 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 :
2018-12-07 05:34:44 +01:00
ReturnValue , ErrorInfo = PatchBinaryFile ( EfiImage , PcdInfo [ 1 ] , TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE , str ( PeiSize / / 0x1000 ) )
2010-03-01 00:39:39 +01:00
elif PcdInfo [ 0 ] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE :
2018-12-07 05:34:44 +01:00
ReturnValue , ErrorInfo = PatchBinaryFile ( EfiImage , PcdInfo [ 1 ] , TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE , str ( BtSize / / 0x1000 ) )
2010-03-01 00:39:39 +01:00
elif PcdInfo [ 0 ] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE :
2018-12-07 05:34:44 +01:00
ReturnValue , ErrorInfo = PatchBinaryFile ( EfiImage , PcdInfo [ 1 ] , TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE , str ( RtSize / / 0x1000 ) )
2010-03-01 00:39:39 +01:00
elif PcdInfo [ 0 ] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len ( SmmModuleList ) > 0 :
2018-12-07 05:34:44 +01:00
ReturnValue , ErrorInfo = PatchBinaryFile ( EfiImage , PcdInfo [ 1 ] , TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE , str ( SmmSize / / 0x1000 ) )
2010-03-01 00:39:39 +01:00
if ReturnValue != 0 :
EdkLogger . error ( " build " , PARAMETER_INVALID , " Patch PCD value failed " , ExtraData = ErrorInfo )
2013-08-23 04:18:16 +02:00
2019-01-23 03:16:00 +01:00
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 ) )
2010-03-01 00:39:39 +01:00
if len ( SmmModuleList ) > 0 :
2019-01-23 03:16:00 +01:00
MapBuffer . append ( ' SMM_CODE_PAGE_NUMBER = 0x %x \n ' % ( SmmSize / / 0x1000 ) )
2013-08-23 04:18:16 +02:00
PeiBaseAddr = TopMemoryAddress - RtSize - BtSize
2010-03-01 00:39:39 +01:00
BtBaseAddr = TopMemoryAddress - RtSize
2013-08-23 04:18:16 +02:00
RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize
2010-03-01 00:39:39 +01:00
self . _RebaseModule ( MapBuffer , PeiBaseAddr , PeiModuleList , TopMemoryAddress == 0 )
self . _RebaseModule ( MapBuffer , BtBaseAddr , BtModuleList , TopMemoryAddress == 0 )
self . _RebaseModule ( MapBuffer , RtBaseAddr , RtModuleList , TopMemoryAddress == 0 )
2015-12-01 05:22:16 +01:00
self . _RebaseModule ( MapBuffer , 0x1000 , SmmModuleList , AddrIsOffset = False , ModeIsSmm = True )
2019-01-23 03:16:00 +01:00
MapBuffer . append ( ' \n \n ' )
2011-05-11 12:26:49 +02:00
sys . stdout . write ( " \n " )
sys . stdout . flush ( )
2013-08-23 04:18:16 +02:00
2010-03-01 00:39:39 +01:00
## 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.
#
2019-01-23 03:16:00 +01:00
SaveFileOnChange ( MapFilePath , ' ' . join ( MapBuffer ) , False )
2011-05-11 12:26:49 +02:00
if self . LoadFixAddress != 0 :
2015-12-01 05:22:16 +01:00
sys . stdout . write ( " \n Load Module At Fix Address Map file can be found at %s \n " % ( MapFilePath ) )
2011-05-11 12:26:49 +02:00
sys . stdout . flush ( )
2010-03-01 00:39:39 +01:00
## Build active platform for different build targets and different tool chains
#
def _BuildPlatform ( self ) :
2016-03-31 08:05:59 +02:00
SaveFileOnChange ( self . PlatformBuildPath , ' # DO NOT EDIT \n # FILE auto-generated \n ' , False )
2010-03-01 00:39:39 +01:00
for BuildTarget in self . BuildTargetList :
2011-10-29 08:59:30 +02:00
GlobalData . gGlobalDefines [ ' TARGET ' ] = BuildTarget
2016-07-04 10:34:28 +02:00
index = 0
2010-03-01 00:39:39 +01:00
for ToolChain in self . ToolChainList :
2011-10-29 08:59:30 +02:00
GlobalData . gGlobalDefines [ ' TOOLCHAIN ' ] = ToolChain
GlobalData . gGlobalDefines [ ' TOOL_CHAIN_TAG ' ] = ToolChain
2016-07-04 10:34:28 +02:00
GlobalData . gGlobalDefines [ ' FAMILY ' ] = self . ToolChainFamily [ index ]
index + = 1
2010-03-01 00:39:39 +01:00
Wa = WorkspaceAutoGen (
self . WorkspaceDir ,
2011-10-29 08:59:30 +02:00
self . PlatformFile ,
2010-03-01 00:39:39 +01:00
BuildTarget ,
ToolChain ,
self . ArchList ,
self . BuildDatabase ,
self . TargetTxt ,
self . ToolDef ,
self . Fdf ,
self . FdList ,
self . FvList ,
2011-08-26 09:46:26 +02:00
self . CapList ,
2010-03-19 07:55:07 +01:00
self . SkuId ,
2011-12-16 09:52:13 +01:00
self . UniFlag ,
self . Progress
2010-03-01 00:39:39 +01:00
)
2011-10-29 08:59:30 +02:00
self . Fdf = Wa . FdfFile
self . LoadFixAddress = Wa . Platform . LoadFixAddress
2010-03-01 00:39:39 +01:00
self . BuildReport . AddPlatformReport ( Wa )
self . Progress . Stop ( " done! " )
2017-11-22 08:42:25 +01:00
# Add ffs build to makefile
CmdListDict = { }
if GlobalData . gEnableGenfdsMultiThread and self . Fdf :
2019-04-03 04:17:02 +02:00
CmdListDict = self . _GenFfsCmd ( Wa . ArchList )
2017-11-22 08:42:25 +01:00
2014-08-18 06:59:01 +02:00
for Arch in Wa . ArchList :
2019-07-22 05:09:22 +02:00
PcdMaList = [ ]
2014-08-18 06:59:01 +02:00
GlobalData . gGlobalDefines [ ' ARCH ' ] = Arch
Pa = PlatformAutoGen ( Wa , self . PlatformFile , BuildTarget , ToolChain , Arch )
2014-08-26 04:52:24 +02:00
for Module in Pa . Platform . Modules :
# Get ModuleAutoGen object to generate C code file and makefile
2019-07-22 05:09:22 +02:00
Ma = ModuleAutoGen ( Wa , Module , BuildTarget , ToolChain , Arch , self . PlatformFile , Pa . DataPipe )
2018-03-26 22:25:43 +02:00
if Ma is None :
2014-08-26 04:52:24 +02:00
continue
2019-07-22 05:09:22 +02:00
if Ma . PcdIsDriver :
Ma . PlatformInfo = Pa
2019-07-30 11:15:31 +02:00
Ma . Workspace = Wa
2019-07-22 05:09:22 +02:00
PcdMaList . append ( Ma )
2014-08-26 04:52:24 +02:00
self . BuildModules . append ( Ma )
2019-08-21 11:50:54 +02:00
Pa . DataPipe . DataContainer = { " FfsCommand " : CmdListDict }
Pa . DataPipe . DataContainer = { " Workspace_timestamp " : Wa . _SrcTimeStamp }
2019-07-30 11:15:31 +02:00
self . _BuildPa ( self . Target , Pa , FfsCommand = CmdListDict , PcdMaList = PcdMaList )
2013-08-23 04:18:16 +02:00
2010-03-01 00:39:39 +01:00
# Create MAP file when Load Fix Address is enabled.
2010-03-12 11:54:01 +01:00
if self . Target in [ " " , " all " , " fds " ] :
2011-10-29 08:59:30 +02:00
for Arch in Wa . ArchList :
GlobalData . gGlobalDefines [ ' ARCH ' ] = Arch
2010-03-01 00:39:39 +01:00
#
# 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 :
2011-10-29 08:59:30 +02:00
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 " )
2010-03-01 00:39:39 +01:00
#
# Get Module List
#
2010-03-12 11:54:01 +01:00
ModuleList = { }
2010-03-01 00:39:39 +01:00
for Pa in Wa . AutoGenObjectList :
for Ma in Pa . ModuleAutoGenList :
2018-03-26 22:25:43 +02:00
if Ma is None :
2010-03-01 00:39:39 +01:00
continue
if not Ma . IsLibrary :
2010-03-12 11:54:01 +01:00
ModuleList [ Ma . Guid . upper ( ) ] = Ma
2010-03-01 00:39:39 +01:00
2019-01-23 03:16:00 +01:00
MapBuffer = [ ]
2010-03-12 11:54:01 +01:00
if self . LoadFixAddress != 0 :
#
# Rebase module to the preferred memory address before GenFds
#
self . _CollectModuleMapBuffer ( MapBuffer , ModuleList )
2011-10-29 08:59:30 +02:00
if self . Fdf :
2015-01-19 06:01:39 +01:00
#
# create FDS again for the updated EFI image
#
self . _Build ( " fds " , Wa )
2010-03-01 00:39:39 +01:00
#
# Create MAP file for all platform FVs after GenFds.
#
2010-03-12 11:54:01 +01:00
self . _CollectFvMapBuffer ( MapBuffer , Wa , ModuleList )
2010-03-01 00:39:39 +01:00
#
# Save MAP buffer into MAP file.
#
self . _SaveMapFile ( MapBuffer , Wa )
2019-09-05 11:04:58 +02:00
self . CreateGuidedSectionToolsFile ( Wa )
2010-03-01 00:39:39 +01:00
## Build active module for different build targets, different tool chains and different archs
#
def _BuildModule ( self ) :
for BuildTarget in self . BuildTargetList :
2011-10-29 08:59:30 +02:00
GlobalData . gGlobalDefines [ ' TARGET ' ] = BuildTarget
2016-07-04 10:34:28 +02:00
index = 0
2010-03-01 00:39:39 +01:00
for ToolChain in self . ToolChainList :
2017-09-11 10:50:07 +02:00
WorkspaceAutoGenTime = time . time ( )
2011-10-29 08:59:30 +02:00
GlobalData . gGlobalDefines [ ' TOOLCHAIN ' ] = ToolChain
2013-08-23 04:18:16 +02:00
GlobalData . gGlobalDefines [ ' TOOL_CHAIN_TAG ' ] = ToolChain
2016-07-04 10:34:28 +02:00
GlobalData . gGlobalDefines [ ' FAMILY ' ] = self . ToolChainFamily [ index ]
index + = 1
2010-03-01 00:39:39 +01:00
#
# module build needs platform build information, so get platform
# AutoGen first
#
Wa = WorkspaceAutoGen (
self . WorkspaceDir ,
2011-10-29 08:59:30 +02:00
self . PlatformFile ,
2010-03-01 00:39:39 +01:00
BuildTarget ,
ToolChain ,
self . ArchList ,
self . BuildDatabase ,
self . TargetTxt ,
self . ToolDef ,
self . Fdf ,
self . FdList ,
self . FvList ,
2011-08-26 09:46:26 +02:00
self . CapList ,
2010-03-19 07:55:07 +01:00
self . SkuId ,
2011-12-16 09:52:13 +01:00
self . UniFlag ,
self . Progress ,
self . ModuleFile
2010-03-01 00:39:39 +01:00
)
2011-10-29 08:59:30 +02:00
self . Fdf = Wa . FdfFile
self . LoadFixAddress = Wa . Platform . LoadFixAddress
2010-03-01 00:39:39 +01:00
Wa . CreateMakeFile ( False )
2017-11-22 08:42:25 +01:00
# Add ffs build to makefile
CmdListDict = None
if GlobalData . gEnableGenfdsMultiThread and self . Fdf :
2019-04-03 04:17:02 +02:00
CmdListDict = self . _GenFfsCmd ( Wa . ArchList )
2019-08-15 16:26:17 +02:00
GlobalData . file_lock = mp . Lock ( )
GlobalData . FfsCmd = CmdListDict
2010-03-01 00:39:39 +01:00
self . Progress . Stop ( " done! " )
MaList = [ ]
2017-09-11 10:50:07 +02:00
ExitFlag = threading . Event ( )
ExitFlag . clear ( )
self . AutoGenTime + = int ( round ( ( time . time ( ) - WorkspaceAutoGenTime ) ) )
2011-10-29 08:59:30 +02:00
for Arch in Wa . ArchList :
2017-09-11 10:50:07 +02:00
AutoGenStart = time . time ( )
2011-10-29 08:59:30 +02:00
GlobalData . gGlobalDefines [ ' ARCH ' ] = Arch
2017-06-08 15:54:23 +02:00
Pa = PlatformAutoGen ( Wa , self . PlatformFile , BuildTarget , ToolChain , Arch )
for Module in Pa . Platform . Modules :
2017-10-09 09:59:45 +02:00
if self . ModuleFile . Dir == Module . Dir and self . ModuleFile . Name == Module . Name :
2019-07-22 05:09:22 +02:00
Ma = ModuleAutoGen ( Wa , Module , BuildTarget , ToolChain , Arch , self . PlatformFile , Pa . DataPipe )
2019-04-04 18:04:23 +02:00
if Ma is None :
continue
2019-09-12 10:18:58 +02:00
if Ma . PcdIsDriver :
Ma . PlatformInfo = Pa
Ma . Workspace = Wa
2017-12-12 08:20:18 +01:00
MaList . append ( Ma )
2019-08-15 16:26:17 +02:00
2019-11-19 09:17:00 +01:00
if GlobalData . gUseHashCache and not GlobalData . gBinCacheDest and self . Target in [ None , " " , " all " ] :
if Ma . CanSkipbyPreMakeCache ( ) :
2019-09-05 11:04:58 +02:00
continue
2019-11-19 09:17:00 +01:00
else :
self . PreMakeCacheMiss . add ( Ma )
2019-08-15 16:26:17 +02:00
2017-09-27 15:18:00 +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 ' :
2018-02-28 17:07:48 +01:00
self . Progress . Start ( " Generating code " )
2017-09-27 15:18:00 +02:00
Ma . CreateCodeFile ( True )
2018-02-28 17:07:48 +01:00
self . Progress . Stop ( " done! " )
if self . Target == " genc " :
return True
2017-09-27 15:18:00 +02:00
if not self . SkipAutoGen or self . Target == ' genmake ' :
2018-02-28 17:07:48 +01:00
self . Progress . Start ( " Generating makefile " )
2019-09-06 15:22:59 +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 ]
2017-11-22 08:42:25 +01:00
else :
Ma . CreateMakeFile ( True )
2018-02-28 17:07:48 +01:00
self . Progress . Stop ( " done! " )
if self . Target == " genmake " :
return True
2019-08-15 16:26:17 +02:00
if GlobalData . gBinCacheSource and self . Target in [ None , " " , " all " ] :
2019-11-19 09:17:00 +01:00
if Ma . CanSkipbyMakeCache ( ) :
2019-08-15 16:26:17 +02:00
continue
else :
2019-11-19 09:17:00 +01:00
self . MakeCacheMiss . add ( Ma )
2019-08-15 16:26:17 +02:00
2017-06-08 15:54:23 +02:00
self . BuildModules . append ( Ma )
2017-09-11 10:50:07 +02:00
self . AutoGenTime + = int ( round ( ( time . time ( ) - AutoGenStart ) ) )
MakeStart = time . time ( )
for Ma in self . BuildModules :
if not Ma . IsBinaryModule :
2019-07-30 11:15:31 +02:00
Bt = BuildTask . New ( ModuleMakeUnit ( Ma , Pa . BuildCommand , self . Target ) )
2017-09-11 10:50:07 +02:00
# Break build if any build thread has error
if BuildTask . HasError ( ) :
# we need a full version of makefile for platform
ExitFlag . set ( )
BuildTask . WaitForComplete ( )
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 ( ) :
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 ( )
2019-06-24 03:51:44 +02:00
if GlobalData . gBinCacheDest :
2019-11-19 09:17:00 +01:00
self . GenDestCache ( )
elif GlobalData . gUseHashCache and not GlobalData . gBinCacheSource :
# Only for --hash
# Update PreMakeCacheChain files
self . GenLocalPreMakeCache ( )
2019-06-24 03:51:44 +02:00
self . BuildModules = [ ]
2017-09-11 10:50:07 +02:00
self . MakeTime + = int ( round ( ( time . time ( ) - MakeContiue ) ) )
if BuildTask . HasError ( ) :
EdkLogger . error ( " build " , BUILD_ERROR , " Failed to build module " , ExtraData = GlobalData . gBuildingModule )
2010-03-04 06:29:52 +01:00
self . BuildReport . AddPlatformReport ( Wa , MaList )
2010-03-01 00:39:39 +01:00
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 " \
2015-12-01 05:22:16 +01:00
" given in the same as in [ %s ] " % \
2011-10-29 08:59:30 +02:00
( ' , ' . join ( Wa . ArchList ) , self . PlatformFile ) ,
2010-03-01 00:39:39 +01:00
ExtraData = self . ModuleFile
)
# Create MAP file when Load Fix Address is enabled.
2011-10-29 08:59:30 +02:00
if self . Target == " fds " and self . Fdf :
for Arch in Wa . ArchList :
2010-03-01 00:39:39 +01:00
#
# 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
#
2010-03-12 11:54:01 +01:00
ModuleList = { }
2010-03-01 00:39:39 +01:00
for Pa in Wa . AutoGenObjectList :
for Ma in Pa . ModuleAutoGenList :
2018-03-26 22:25:43 +02:00
if Ma is None :
2010-03-01 00:39:39 +01:00
continue
if not Ma . IsLibrary :
2010-03-12 11:54:01 +01:00
ModuleList [ Ma . Guid . upper ( ) ] = Ma
2010-03-01 00:39:39 +01:00
2019-01-23 03:16:00 +01:00
MapBuffer = [ ]
2010-03-12 11:54:01 +01:00
if self . LoadFixAddress != 0 :
#
# Rebase module to the preferred memory address before GenFds
#
self . _CollectModuleMapBuffer ( MapBuffer , ModuleList )
2015-01-19 06:01:39 +01:00
#
# create FDS again for the updated EFI image
#
2017-09-11 10:50:07 +02:00
GenFdsStart = time . time ( )
2015-01-19 06:01:39 +01:00
self . _Build ( " fds " , Wa )
2017-09-11 10:50:07 +02:00
self . GenFdsTime + = int ( round ( ( time . time ( ) - GenFdsStart ) ) )
2010-03-01 00:39:39 +01:00
#
# Create MAP file for all platform FVs after GenFds.
#
2010-03-12 11:54:01 +01:00
self . _CollectFvMapBuffer ( MapBuffer , Wa , ModuleList )
2010-03-01 00:39:39 +01:00
#
# Save MAP buffer into MAP file.
#
self . _SaveMapFile ( MapBuffer , Wa )
2019-04-03 04:17:02 +02:00
def _GenFfsCmd ( self , ArchList ) :
2018-07-05 11:40:04 +02:00
# convert dictionary of Cmd:(Inf,Arch)
2018-04-17 16:40:15 +02:00
# to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
CmdSetDict = defaultdict ( set )
2019-04-03 04:17:02 +02:00
GenFfsDict = GenFds . GenFfsMakefile ( ' ' , GlobalData . gFdfParser , self , ArchList , GlobalData )
2017-11-22 08:42:25 +01:00
for Cmd in GenFfsDict :
tmpInf , tmpArch = GenFfsDict [ Cmd ]
2018-04-17 16:40:15 +02:00
CmdSetDict [ tmpInf , tmpArch ] . add ( Cmd )
return CmdSetDict
2019-09-05 11:04:58 +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 :
2020-02-10 11:49:07 +01:00
if not os . path . exists ( os . path . join ( m_build_dir , self . MakeFileName ) ) :
2019-09-05 11:04:58 +02:00
return None
for m_build_dir in ModuleBuildDirectoryList :
2020-02-10 11:49:07 +01:00
if not os . path . exists ( os . path . join ( m_build_dir , self . MakeFileName ) ) :
2019-09-05 11:04:58 +02:00
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 :
2019-11-12 07:17:35 +01:00
if str ( FdRegion . RegionType ) == ' FILE ' and self . Platform . VpdToolGuid in str ( FdRegion . RegionDataList ) :
2019-09-05 11:04:58 +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
2017-11-22 08:42:25 +01:00
2010-03-01 00:39:39 +01:00
## Build a platform in multi-thread mode
#
2019-09-05 11:04:58 +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 )
2019-11-19 09:17:00 +01:00
# Add ffs build to makefile
2019-09-05 11:04:58 +02:00
CmdListDict = { }
if GlobalData . gEnableGenfdsMultiThread and self . Fdf :
CmdListDict = self . _GenFfsCmd ( Wa . ArchList )
self . AutoGenTime + = int ( round ( ( time . time ( ) - WorkspaceAutoGenTime ) ) )
BuildModules = [ ]
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 )
2019-11-19 09:17:00 +01:00
# Add the INF only list in FDF
2019-09-05 11:04:58 +02:00
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 ( )
2020-02-10 11:49:07 +01:00
# Fetch the MakeFileName.
self . MakeFileName = Pa . MakeFileName
2019-09-05 11:04:58 +02:00
Pa . DataPipe . DataContainer = { " LibraryBuildDirectoryList " : Pa . LibraryBuildDirectoryList }
Pa . DataPipe . DataContainer = { " ModuleBuildDirectoryList " : Pa . ModuleBuildDirectoryList }
Pa . DataPipe . DataContainer = { " FdsCommandDict " : Wa . GenFdsCommandDict }
2019-11-19 09:17:00 +01:00
# Prepare the cache share data for multiprocessing
Pa . DataPipe . DataContainer = { " gPlatformHashFile " : GlobalData . gPlatformHashFile }
2019-09-05 11:04:58 +02:00
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 }
2019-11-19 09:17:00 +01:00
# ModuleList contains all driver modules only
2019-09-05 11:04:58 +02:00
for Module in ModuleList :
2019-11-19 09:17:00 +01:00
# Get ModuleAutoGen object to generate C code file and makefile
2019-09-05 11:04:58 +02:00
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 )
2019-11-19 09:17:00 +01:00
self . AllDrivers . add ( Ma )
self . AllModules . add ( Ma )
2019-09-05 11:04:58 +02:00
mqueue = mp . Queue ( )
2019-11-19 09:17:00 +01:00
cqueue = mp . Queue ( )
2019-09-05 11:04:58 +02:00
for m in Pa . GetAllModuleInfo :
mqueue . put ( m )
2019-11-19 09:17:00 +01:00
module_file , module_root , module_path , module_basename , \
module_originalpath , module_arch , IsLib = m
Ma = ModuleAutoGen ( Wa , PathClass ( module_path , Wa ) , BuildTarget , \
ToolChain , Arch , self . PlatformFile , Pa . DataPipe )
self . AllModules . add ( Ma )
2019-09-05 11:04:58 +02:00
data_pipe_file = os . path . join ( Pa . BuildDir , " GlobalVar_ %s _ %s .bin " % ( str ( Pa . Guid ) , Pa . Arch ) )
Pa . DataPipe . dump ( data_pipe_file )
2020-08-03 04:03:38 +02:00
mqueue . put ( ( None , None , None , None , None , None , None ) )
2019-11-19 09:17:00 +01:00
autogen_rt , errorcode = self . StartAutoGen ( mqueue , Pa . DataPipe , self . SkipAutoGen , PcdMaList , cqueue )
2019-09-05 11:04:58 +02:00
if not autogen_rt :
self . AutoGenMgr . TerminateWorkers ( )
self . AutoGenMgr . join ( 1 )
raise FatalError ( errorcode )
2019-11-19 09:17:00 +01:00
if GlobalData . gUseHashCache :
for item in GlobalData . gModuleAllCacheStatus :
( MetaFilePath , Arch , CacheStr , Status ) = item
Ma = ModuleAutoGen ( Wa , PathClass ( MetaFilePath , Wa ) , BuildTarget , \
ToolChain , Arch , self . PlatformFile , Pa . DataPipe )
if CacheStr == " PreMakeCache " and Status == False :
self . PreMakeCacheMiss . add ( Ma )
if CacheStr == " PreMakeCache " and Status == True :
self . PreMakeCacheHit . add ( Ma )
GlobalData . gModuleCacheHit . add ( Ma )
if CacheStr == " MakeCache " and Status == False :
self . MakeCacheMiss . add ( Ma )
if CacheStr == " MakeCache " and Status == True :
self . MakeCacheHit . add ( Ma )
GlobalData . gModuleCacheHit . add ( Ma )
2019-09-05 11:04:58 +02:00
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 ) )
2019-11-19 09:17:00 +01:00
if GlobalData . gBinCacheSource :
BuildModules . extend ( self . MakeCacheMiss )
elif GlobalData . gUseHashCache and not GlobalData . gBinCacheDest :
BuildModules . extend ( self . PreMakeCacheMiss )
else :
BuildModules . extend ( self . AllDrivers )
2019-09-05 11:04:58 +02:00
self . Progress . Stop ( " done! " )
return Wa , BuildModules
2010-03-01 00:39:39 +01:00
def _MultiThreadBuildPlatform ( self ) :
2016-03-31 08:05:59 +02:00
SaveFileOnChange ( self . PlatformBuildPath , ' # DO NOT EDIT \n # FILE auto-generated \n ' , False )
2010-03-01 00:39:39 +01:00
for BuildTarget in self . BuildTargetList :
2011-10-29 08:59:30 +02:00
GlobalData . gGlobalDefines [ ' TARGET ' ] = BuildTarget
2016-07-04 10:34:28 +02:00
index = 0
2010-03-01 00:39:39 +01:00
for ToolChain in self . ToolChainList :
2019-12-11 12:22:21 +01:00
resetFdsGlobalVariable ( )
2011-10-29 08:59:30 +02:00
GlobalData . gGlobalDefines [ ' TOOLCHAIN ' ] = ToolChain
2013-08-23 04:18:16 +02:00
GlobalData . gGlobalDefines [ ' TOOL_CHAIN_TAG ' ] = ToolChain
2016-07-04 10:34:28 +02:00
GlobalData . gGlobalDefines [ ' FAMILY ' ] = self . ToolChainFamily [ index ]
index + = 1
2010-03-01 00:39:39 +01:00
ExitFlag = threading . Event ( )
ExitFlag . clear ( )
2019-09-05 11:04:58 +02:00
if self . SkipAutoGen :
Wa = self . VerifyAutoGenFiles ( )
if Wa is None :
2019-09-11 12:01:56 +02:00
self . SkipAutoGen = False
2019-09-05 11:04:58 +02:00
Wa , self . BuildModules = self . PerformAutoGen ( BuildTarget , ToolChain )
2019-08-15 16:26:17 +02:00
else :
2019-09-05 11:04:58 +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-08-15 16:26:17 +02:00
if GlobalData . gBinCacheSource :
2019-11-19 09:17:00 +01:00
EdkLogger . quiet ( " [cache Summary]: Total module num: %s " % len ( self . AllModules ) )
EdkLogger . quiet ( " [cache Summary]: PreMakecache miss num: %s " % len ( self . PreMakeCacheMiss ) )
EdkLogger . quiet ( " [cache Summary]: Makecache miss num: %s " % len ( self . MakeCacheMiss ) )
2019-08-15 16:26:17 +02:00
2019-07-30 11:15:31 +02:00
for Arch in Wa . ArchList :
2017-09-11 10:50:07 +02:00
MakeStart = time . time ( )
2019-08-15 16:26:17 +02:00
for Ma in set ( self . BuildModules ) :
2010-03-01 00:39:39 +01:00
# Generate build task for the module
2014-08-26 04:52:24 +02:00
if not Ma . IsBinaryModule :
2019-07-30 11:15:31 +02:00
Bt = BuildTask . New ( ModuleMakeUnit ( Ma , Pa . BuildCommand , self . Target ) )
2010-03-01 00:39:39 +01:00
# Break build if any build thread has error
if BuildTask . HasError ( ) :
# we need a full version of makefile for platform
ExitFlag . set ( )
BuildTask . WaitForComplete ( )
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-05 11:04:58 +02:00
2010-03-01 00:39:39 +01:00
if BuildTask . HasError ( ) :
EdkLogger . error ( " build " , BUILD_ERROR , " Failed to build module " , ExtraData = GlobalData . gBuildingModule )
2017-09-11 10:50:07 +02:00
self . MakeTime + = int ( round ( ( time . time ( ) - MakeStart ) ) )
2010-03-01 00:39:39 +01:00
2017-09-11 10:50:07 +02:00
MakeContiue = time . time ( )
2012-04-10 09:18:20 +02:00
#
2010-03-01 00:39:39 +01:00
#
# All modules have been put in build tasks queue. Tell task scheduler
# to exit if all tasks are completed
#
ExitFlag . set ( )
BuildTask . WaitForComplete ( )
2019-06-24 03:51:44 +02:00
if GlobalData . gBinCacheDest :
2019-11-19 09:17:00 +01:00
self . GenDestCache ( )
elif GlobalData . gUseHashCache and not GlobalData . gBinCacheSource :
# Only for --hash
# Update PreMakeCacheChain files
self . GenLocalPreMakeCache ( )
2019-11-22 11:54:39 +01:00
#
# Get Module List
#
ModuleList = { ma . Guid . upper ( ) : ma for ma in self . BuildModules }
2019-06-24 03:51:44 +02:00
self . BuildModules = [ ]
2017-09-11 10:50:07 +02:00
self . MakeTime + = int ( round ( ( time . time ( ) - MakeContiue ) ) )
2010-03-01 00:39:39 +01:00
#
# Check for build error, and raise exception if one
# has been signaled.
#
if BuildTask . HasError ( ) :
EdkLogger . error ( " build " , BUILD_ERROR , " Failed to build module " , ExtraData = GlobalData . gBuildingModule )
# Create MAP file when Load Fix Address is enabled.
2010-03-12 11:54:01 +01:00
if self . Target in [ " " , " all " , " fds " ] :
2011-10-29 08:59:30 +02:00
for Arch in Wa . ArchList :
2010-03-01 00:39:39 +01:00
#
# 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 " )
2019-09-05 11:04:58 +02:00
2010-03-01 00:39:39 +01:00
#
# Rebase module to the preferred memory address before GenFds
#
2019-01-23 03:16:00 +01:00
MapBuffer = [ ]
2010-03-12 11:54:01 +01:00
if self . LoadFixAddress != 0 :
self . _CollectModuleMapBuffer ( MapBuffer , ModuleList )
2010-03-01 00:39:39 +01:00
2011-10-29 08:59:30 +02:00
if self . Fdf :
2010-03-19 07:55:07 +01:00
#
# Generate FD image if there's a FDF file found
#
2017-09-11 10:50:07 +02:00
GenFdsStart = time . time ( )
2018-12-18 09:40:34 +01:00
if GenFdsApi ( Wa . GenFdsCommandDict , self . Db ) :
EdkLogger . error ( " build " , COMMAND_FAILURE )
2020-04-20 03:20:52 +02:00
Threshold = self . GetFreeSizeThreshold ( )
if Threshold :
self . CheckFreeSizeThreshold ( Threshold , Wa . FvDir )
2014-08-18 06:59:01 +02:00
2010-03-01 00:39:39 +01:00
#
# Create MAP file for all platform FVs after GenFds.
#
2010-03-12 11:54:01 +01:00
self . _CollectFvMapBuffer ( MapBuffer , Wa , ModuleList )
2017-09-11 10:50:07 +02:00
self . GenFdsTime + = int ( round ( ( time . time ( ) - GenFdsStart ) ) )
2010-03-01 00:39:39 +01:00
#
# Save MAP buffer into MAP file.
#
self . _SaveMapFile ( MapBuffer , Wa )
2019-09-05 11:04:58 +02:00
self . CreateGuidedSectionToolsFile ( Wa )
2020-04-20 03:20:52 +02:00
## GetFreeSizeThreshold()
#
# @retval int Threshold value
#
def GetFreeSizeThreshold ( self ) :
Threshold = None
Threshold_Str = GlobalData . gCommandLineDefines . get ( ' FV_SPARE_SPACE_THRESHOLD ' )
if Threshold_Str :
try :
if Threshold_Str . lower ( ) . startswith ( ' 0x ' ) :
Threshold = int ( Threshold_Str , 16 )
else :
Threshold = int ( Threshold_Str )
except :
EdkLogger . warn ( " build " , ' incorrect value for FV_SPARE_SPACE_THRESHOLD %s .Only decimal or hex format is allowed. ' % Threshold_Str )
return Threshold
def CheckFreeSizeThreshold ( self , Threshold = None , FvDir = None ) :
if not isinstance ( Threshold , int ) :
return
if not isinstance ( FvDir , str ) or not FvDir :
return
FdfParserObject = GlobalData . gFdfParser
FvRegionNameList = [ FvName for FvName in FdfParserObject . Profile . FvDict if FdfParserObject . Profile . FvDict [ FvName ] . FvRegionInFD ]
for FvName in FdfParserObject . Profile . FvDict :
if FvName in FvRegionNameList :
FvSpaceInfoFileName = os . path . join ( FvDir , FvName . upper ( ) + ' .Fv.map ' )
if os . path . exists ( FvSpaceInfoFileName ) :
FileLinesList = getlines ( FvSpaceInfoFileName )
for Line in FileLinesList :
NameValue = Line . split ( ' = ' )
if len ( NameValue ) == 2 and NameValue [ 0 ] . strip ( ) == ' EFI_FV_SPACE_SIZE ' :
FreeSizeValue = int ( NameValue [ 1 ] . strip ( ) , 0 )
if FreeSizeValue < Threshold :
EdkLogger . error ( " build " , FV_FREESIZE_ERROR ,
' %s FV free space %d is not enough to meet with the required spare space %d set by -D FV_SPARE_SPACE_THRESHOLD option. ' % (
FvName , FreeSizeValue , Threshold ) )
break
2010-03-01 00:39:39 +01:00
## Generate GuidedSectionTools.txt in the FV directories.
#
2019-09-05 11:04:58 +02:00
def CreateGuidedSectionToolsFile ( self , Wa ) :
2011-10-29 08:59:30 +02:00
for BuildTarget in self . BuildTargetList :
for ToolChain in self . ToolChainList :
FvDir = Wa . FvDir
if not os . path . exists ( FvDir ) :
continue
2013-08-23 04:18:16 +02:00
for Arch in self . ArchList :
2021-05-07 17:40:29 +02:00
guidList = [ ]
tooldefguidList = [ ]
2010-03-01 00:39:39 +01:00
guidAttribs = [ ]
2021-05-07 17:40:29 +02:00
for Platform in Wa . AutoGenObjectList :
if Platform . BuildTarget != BuildTarget :
continue
if Platform . ToolChain != ToolChain :
continue
if Platform . Arch != Arch :
continue
if hasattr ( Platform , ' BuildOption ' ) :
for Tool in Platform . BuildOption :
if ' GUID ' in Platform . BuildOption [ Tool ] :
if ' PATH ' in Platform . BuildOption [ Tool ] :
value = Platform . BuildOption [ Tool ] [ ' GUID ' ]
if value in guidList :
EdkLogger . error ( " build " , FORMAT_INVALID , " Duplicate GUID value %s used with Tool %s in DSC [BuildOptions]. " % ( value , Tool ) )
path = Platform . BuildOption [ Tool ] [ ' PATH ' ]
guidList . append ( value )
guidAttribs . append ( ( value , Tool , path ) )
for Tool in Platform . ToolDefinition :
if ' GUID ' in Platform . ToolDefinition [ Tool ] :
if ' PATH ' in Platform . ToolDefinition [ Tool ] :
value = Platform . ToolDefinition [ Tool ] [ ' GUID ' ]
if value in tooldefguidList :
EdkLogger . error ( " build " , FORMAT_INVALID , " Duplicate GUID value %s used with Tool %s in tools_def.txt. " % ( value , Tool ) )
tooldefguidList . append ( value )
if value in guidList :
# Already added by platform
continue
path = Platform . ToolDefinition [ Tool ] [ ' PATH ' ]
guidList . append ( value )
guidAttribs . append ( ( value , Tool , path ) )
2021-04-21 08:12:51 +02:00
# Sort by GuidTool name
2021-05-07 17:40:29 +02:00
guidAttribs = sorted ( guidAttribs , key = lambda x : x [ 1 ] )
2010-03-01 00:39:39 +01:00
# Write out GuidedSecTools.txt
toolsFile = os . path . join ( FvDir , ' GuidedSectionTools.txt ' )
toolsFile = open ( toolsFile , ' wt ' )
for guidedSectionTool in guidAttribs :
2018-06-25 12:31:26 +02:00
print ( ' ' . join ( guidedSectionTool ) , file = toolsFile )
2010-03-01 00:39:39 +01:00
toolsFile . close ( )
2020-03-26 10:48:04 +01:00
## Returns the real path of the tool.
2010-03-01 00:39:39 +01:00
#
2020-03-26 10:48:04 +01:00
def GetRealPathOfTool ( self , tool ) :
2010-03-01 00:39:39 +01:00
if os . path . exists ( tool ) :
return os . path . realpath ( tool )
return tool
## Launch the module or platform build
#
def Launch ( self ) :
2019-11-19 09:17:00 +01:00
self . AllDrivers = set ( )
self . AllModules = set ( )
self . PreMakeCacheMiss = set ( )
self . PreMakeCacheHit = set ( )
self . MakeCacheMiss = set ( )
self . MakeCacheHit = set ( )
2011-10-29 08:59:30 +02:00
if not self . ModuleFile :
2010-03-01 00:39:39 +01:00
if not self . SpawnMode or self . Target not in [ " " , " all " ] :
self . SpawnMode = False
self . _BuildPlatform ( )
else :
self . _MultiThreadBuildPlatform ( )
else :
self . SpawnMode = False
self . _BuildModule ( )
2014-11-12 09:26:03 +01:00
if self . Target == ' cleanall ' :
RemoveDirectory ( os . path . dirname ( GlobalData . gDatabasePath ) , True )
2014-08-26 04:52:24 +02:00
def CreateAsBuiltInf ( self ) :
2019-06-24 03:51:44 +02:00
for Module in self . BuildModules :
Module . CreateAsBuiltInf ( )
2019-11-19 09:17:00 +01:00
def GenDestCache ( self ) :
for Module in self . AllModules :
Module . GenPreMakefileHashList ( )
Module . GenMakefileHashList ( )
2019-06-24 03:51:44 +02:00
Module . CopyModuleToCache ( )
2019-11-19 09:17:00 +01:00
def GenLocalPreMakeCache ( self ) :
for Module in self . PreMakeCacheMiss :
Module . GenPreMakefileHashList ( )
2010-03-01 00:39:39 +01:00
## 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 = { }
2018-03-26 22:25:43 +02:00
if DefineList is not None :
2010-03-01 00:39:39 +01:00
for Define in DefineList :
DefineTokenList = Define . split ( " = " , 1 )
2011-10-29 08:59:30 +02:00
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 ] )
2013-08-23 04:18:16 +02:00
2010-03-01 00:39:39 +01:00
if len ( DefineTokenList ) == 1 :
2011-10-29 08:59:30 +02:00
DefineDict [ DefineTokenList [ 0 ] ] = " TRUE "
2010-03-01 00:39:39 +01:00
else :
DefineDict [ DefineTokenList [ 0 ] ] = DefineTokenList [ 1 ] . strip ( )
return DefineDict
2019-07-22 08:23:40 +02:00
2010-03-01 00:39:39 +01:00
2017-09-11 10:50:07 +02:00
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
2019-07-31 07:33:31 +02:00
def ThreadNum ( ) :
2020-01-10 09:29:45 +01:00
OptionParser = MyOptionParser ( )
if not OptionParser . BuildOption and not OptionParser . BuildTarget :
OptionParser . GetOption ( )
BuildOption , BuildTarget = OptionParser . BuildOption , OptionParser . BuildTarget
2019-07-31 07:33:31 +02:00
ThreadNumber = BuildOption . ThreadNumber
2020-01-10 09:29:45 +01:00
GlobalData . gCmdConfDir = BuildOption . ConfDirectory
2019-07-31 07:33:31 +02:00
if ThreadNumber is None :
2020-01-10 09:29:45 +01:00
TargetObj = TargetTxtDict ( )
ThreadNumber = TargetObj . Target . TargetTxtDictionary [ TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER ]
2019-07-31 07:33:31 +02:00
if ThreadNumber == ' ' :
ThreadNumber = 0
else :
ThreadNumber = int ( ThreadNumber , 0 )
2017-09-11 10:50:07 +02:00
2019-07-31 07:33:31 +02:00
if ThreadNumber == 0 :
try :
ThreadNumber = multiprocessing . cpu_count ( )
except ( ImportError , NotImplementedError ) :
ThreadNumber = 1
return ThreadNumber
2010-03-01 00:39:39 +01:00
## 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
#
2019-07-31 07:33:31 +02:00
LogQMaxSize = ThreadNum ( ) * 10
2010-03-01 00:39:39 +01:00
def Main ( ) :
StartTime = time . time ( )
2019-07-31 07:31:15 +02:00
#
# Create a log Queue
#
2019-07-31 07:33:31 +02:00
LogQ = mp . Queue ( LogQMaxSize )
2010-03-01 00:39:39 +01:00
# Initialize log system
2019-07-31 07:31:15 +02:00
EdkLogger . LogClientInitialize ( LogQ )
2016-03-31 08:05:59 +02:00
GlobalData . gCommand = sys . argv [ 1 : ]
2010-03-01 00:39:39 +01:00
#
# Parse the options and args
#
2020-01-10 09:29:45 +01:00
OptionParser = MyOptionParser ( )
if not OptionParser . BuildOption and not OptionParser . BuildTarget :
OptionParser . GetOption ( )
Option , Target = OptionParser . BuildOption , OptionParser . BuildTarget
2010-03-01 00:39:39 +01:00
GlobalData . gOptions = Option
GlobalData . gCaseInsensitive = Option . CaseInsensitive
# Set log level
2019-07-31 07:31:15 +02:00
LogLevel = EdkLogger . INFO
2018-03-26 22:25:43 +02:00
if Option . verbose is not None :
2010-03-01 00:39:39 +01:00
EdkLogger . SetLevel ( EdkLogger . VERBOSE )
2019-07-31 07:31:15 +02:00
LogLevel = EdkLogger . VERBOSE
2018-03-26 22:25:43 +02:00
elif Option . quiet is not None :
2010-03-01 00:39:39 +01:00
EdkLogger . SetLevel ( EdkLogger . QUIET )
2019-07-31 07:31:15 +02:00
LogLevel = EdkLogger . QUIET
2018-03-26 22:25:43 +02:00
elif Option . debug is not None :
2010-03-01 00:39:39 +01:00
EdkLogger . SetLevel ( Option . debug + 1 )
2019-07-31 07:31:15 +02:00
LogLevel = Option . debug + 1
2010-03-01 00:39:39 +01:00
else :
EdkLogger . SetLevel ( EdkLogger . INFO )
if Option . WarningAsError == True :
EdkLogger . SetWarningAsError ( )
2019-07-31 07:31:15 +02:00
Log_Agent = LogAgent ( LogQ , LogLevel , Option . LogFile )
Log_Agent . start ( )
2010-03-01 00:39:39 +01:00
if platform . platform ( ) . find ( " Windows " ) > = 0 :
GlobalData . gIsWindows = True
else :
GlobalData . gIsWindows = False
2010-11-15 03:51:34 +01:00
EdkLogger . quiet ( " Build environment: %s " % platform . platform ( ) )
EdkLogger . quiet ( time . strftime ( " Build start time: % H: % M: % S, % b. %d % Y \n " , time . localtime ( ) ) ) ;
2010-03-01 00:39:39 +01:00
ReturnCode = 0
MyBuild = None
2015-06-23 08:49:25 +02:00
BuildError = True
2010-03-01 00:39:39 +01:00
try :
if len ( Target ) == 0 :
Target = " all "
elif len ( Target ) > = 2 :
EdkLogger . error ( " build " , OPTION_NOT_SUPPORTED , " More than one targets are not supported. " ,
2015-12-01 05:22:16 +01:00
ExtraData = " Please select one of: %s " % ( ' ' . join ( gSupportedTarget ) ) )
2010-03-01 00:39:39 +01:00
else :
Target = Target [ 0 ] . lower ( )
if Target not in gSupportedTarget :
EdkLogger . error ( " build " , OPTION_NOT_SUPPORTED , " Not supported target [ %s ]. " % Target ,
2015-12-01 05:22:16 +01:00
ExtraData = " Please select one of: %s " % ( ' ' . join ( gSupportedTarget ) ) )
2010-03-01 00:39:39 +01:00
#
# Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
#
CheckEnvVariable ( )
2011-10-29 08:59:30 +02:00
GlobalData . gCommandLineDefines . update ( ParseDefines ( Option . Macros ) )
2010-03-01 00:39:39 +01:00
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 )
2018-03-26 22:25:43 +02:00
if Option . PlatformFile is not None :
2010-03-01 00:39:39 +01:00
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 )
2018-03-26 22:25:43 +02:00
if Option . FdfFile is not None :
2010-03-01 00:39:39 +01:00
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 )
2018-03-26 22:25:43 +02:00
if Option . Flag is not None and Option . Flag not in [ ' -c ' , ' -s ' ] :
2010-03-19 07:55:07 +01:00
EdkLogger . error ( " build " , OPTION_VALUE_INVALID , " UNI flag must be one of -c or -s " )
2019-07-31 07:31:15 +02:00
MyBuild = Build ( Target , Workspace , Option , LogQ )
2012-04-10 09:18:20 +02:00
GlobalData . gCommandLineDefines [ ' ARCH ' ] = ' ' . join ( MyBuild . ArchList )
2016-03-31 08:05:59 +02:00
if not ( MyBuild . LaunchPrebuildFlag and os . path . exists ( MyBuild . PlatformBuildPath ) ) :
MyBuild . Launch ( )
2018-11-09 08:41:02 +01:00
2015-06-23 08:49:25 +02:00
#
# All job done, no error found and no exception raised
#
BuildError = False
2018-06-25 12:31:25 +02:00
except FatalError as X :
2018-03-26 22:25:43 +02:00
if MyBuild is not None :
2010-03-01 00:39:39 +01:00
# for multi-thread build exits safely
MyBuild . Relinquish ( )
2018-03-26 22:25:43 +02:00
if Option is not None and Option . debug is not None :
2010-03-01 00:39:39 +01:00
EdkLogger . quiet ( " (Python %s on %s ) " % ( platform . python_version ( ) , sys . platform ) + traceback . format_exc ( ) )
ReturnCode = X . args [ 0 ]
2018-06-25 12:31:25 +02:00
except Warning as X :
2010-03-01 00:39:39 +01:00
# error from Fdf parser
2018-03-26 22:25:43 +02:00
if MyBuild is not None :
2010-03-01 00:39:39 +01:00
# for multi-thread build exits safely
MyBuild . Relinquish ( )
2018-03-26 22:25:43 +02:00
if Option is not None and Option . debug is not None :
2010-03-01 00:39:39 +01:00
EdkLogger . quiet ( " (Python %s on %s ) " % ( platform . python_version ( ) , sys . platform ) + traceback . format_exc ( ) )
else :
2015-12-01 05:22:16 +01:00
EdkLogger . error ( X . ToolName , FORMAT_INVALID , File = X . FileName , Line = X . LineNumber , ExtraData = X . Message , RaiseError = False )
2010-03-01 00:39:39 +01:00
ReturnCode = FORMAT_INVALID
except KeyboardInterrupt :
2019-07-30 11:15:31 +02:00
if MyBuild is not None :
# for multi-thread build exits safely
MyBuild . Relinquish ( )
2010-03-01 00:39:39 +01:00
ReturnCode = ABORT_ERROR
2018-03-26 22:25:43 +02:00
if Option is not None and Option . debug is not None :
2010-03-01 00:39:39 +01:00
EdkLogger . quiet ( " (Python %s on %s ) " % ( platform . python_version ( ) , sys . platform ) + traceback . format_exc ( ) )
except :
2018-03-26 22:25:43 +02:00
if MyBuild is not None :
2010-03-01 00:39:39 +01:00
# 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
2018-03-26 22:25:43 +02:00
while Tb is not None :
2010-03-01 00:39:39 +01:00
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 ,
2019-05-21 04:06:52 +02:00
ExtraData = " \n (Please send email to %s for help, attaching following call stack trace!) \n " % MSG_EDKII_MAIL_ADDR ,
2010-03-01 00:39:39 +01:00
RaiseError = False
)
2011-12-07 07:19:28 +01:00
EdkLogger . quiet ( " (Python %s on %s ) " % ( platform . python_version ( ) , sys . platform ) + traceback . format_exc ( ) )
2010-03-01 00:39:39 +01:00
ReturnCode = CODE_ERROR
finally :
Utils . Progressor . Abort ( )
2014-08-28 15:53:34 +02:00
Utils . ClearDuplicatedInf ( )
2010-03-01 00:39:39 +01:00
if ReturnCode == 0 :
2016-03-31 08:05:59 +02:00
try :
2017-04-26 10:53:58 +02:00
MyBuild . LaunchPostbuild ( )
2016-03-31 08:05:59 +02:00
Conclusion = " Done "
except :
Conclusion = " Failed "
2021-05-14 17:01:43 +02:00
ReturnCode = POSTBUILD_ERROR
2010-03-01 00:39:39 +01:00
elif ReturnCode == ABORT_ERROR :
Conclusion = " Aborted "
else :
Conclusion = " Failed "
FinishTime = time . time ( )
2011-08-26 09:46:26 +02:00
BuildDuration = time . gmtime ( int ( round ( FinishTime - StartTime ) ) )
BuildDurationStr = " "
if BuildDuration . tm_yday > 1 :
2015-12-01 05:22:16 +01:00
BuildDurationStr = time . strftime ( " % H: % M: % S " , BuildDuration ) + " , %d day(s) " % ( BuildDuration . tm_yday - 1 )
2011-08-26 09:46:26 +02:00
else :
BuildDurationStr = time . strftime ( " % H: % M: % S " , BuildDuration )
2018-03-26 22:25:43 +02:00
if MyBuild is not None :
2015-06-23 08:49:25 +02:00
if not BuildError :
2017-09-11 10:50:07 +02:00
MyBuild . BuildReport . GenerateReport ( BuildDurationStr , LogBuildTime ( MyBuild . AutoGenTime ) , LogBuildTime ( MyBuild . MakeTime ) , LogBuildTime ( MyBuild . GenFdsTime ) )
2018-11-09 08:41:02 +01:00
2010-03-01 00:39:39 +01:00
EdkLogger . SetLevel ( EdkLogger . QUIET )
2010-11-15 03:51:34 +01:00
EdkLogger . quiet ( " \n - %s - " % Conclusion )
EdkLogger . quiet ( time . strftime ( " Build end time: % H: % M: % S, % b. %d % Y " , time . localtime ( ) ) )
2011-08-26 09:46:26 +02:00
EdkLogger . quiet ( " Build total time: %s \n " % BuildDurationStr )
2019-07-31 07:31:15 +02:00
Log_Agent . kill ( )
Log_Agent . join ( )
2010-03-01 00:39:39 +01:00
return ReturnCode
if __name__ == ' __main__ ' :
2019-07-30 11:15:31 +02:00
try :
mp . set_start_method ( ' spawn ' )
except :
pass
2010-03-01 00:39:39 +01:00
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 )