2021-11-10 11:36:23 +00:00
## @file
# Create makefile for MS nmake and GNU make
#
2021-12-13 09:14:42 -08:00
# Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2020 - 2021, Arm Limited. All rights reserved.<BR>
2021-11-10 11:36:23 +00:00
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
## Import Modules
#
from __future__ import absolute_import
import Common.LongFilePathOs as os
import sys
import string
import re
import os.path as path
from Common.LongFilePathSupport import OpenLongFilePath as open
from Common.MultipleWorkspace import MultipleWorkspace as mws
from Common.BuildToolError import *
from Common.Misc import *
from Common.StringUtils import *
from .BuildEngine import *
import Common.GlobalData as GlobalData
from collections import OrderedDict
from Common.DataType import TAB_COMPILER_MSFT
## Regular expression for finding header file inclusions
gIncludePattern = re . compile ( r "^[ \t]*[#%]?[ \t]*include(?:[ \t]*(?: \\ (?:\r\n|\r|\n))*[ \t]*)*(?:\(?[ \" <]?[ \t]*)([-\w. \\ /() \t]+)(?:[ \t]*[ \" >]?\)?)" , re . MULTILINE | re . UNICODE | re . IGNORECASE )
## Regular expression for matching macro used in header file inclusion
gMacroPattern = re . compile ( "([_A-Z][_A-Z0-9]*)[ \t ]*\((.+)\)" , re . UNICODE )
gIsFileMap = {}
## pattern for include style in Edk.x code
gProtocolDefinition = "Protocol/ %(HeaderKey)s / %(HeaderKey)s .h"
gGuidDefinition = "Guid/ %(HeaderKey)s / %(HeaderKey)s .h"
gArchProtocolDefinition = "ArchProtocol/ %(HeaderKey)s / %(HeaderKey)s .h"
gPpiDefinition = "Ppi/ %(HeaderKey)s / %(HeaderKey)s .h"
gIncludeMacroConversion = {
"EFI_PROTOCOL_DEFINITION" : gProtocolDefinition ,
"EFI_GUID_DEFINITION" : gGuidDefinition ,
"EFI_ARCH_PROTOCOL_DEFINITION" : gArchProtocolDefinition ,
"EFI_PROTOCOL_PRODUCER" : gProtocolDefinition ,
"EFI_PROTOCOL_CONSUMER" : gProtocolDefinition ,
"EFI_PROTOCOL_DEPENDENCY" : gProtocolDefinition ,
"EFI_ARCH_PROTOCOL_PRODUCER" : gArchProtocolDefinition ,
"EFI_ARCH_PROTOCOL_CONSUMER" : gArchProtocolDefinition ,
"EFI_ARCH_PROTOCOL_DEPENDENCY" : gArchProtocolDefinition ,
"EFI_PPI_DEFINITION" : gPpiDefinition ,
"EFI_PPI_PRODUCER" : gPpiDefinition ,
"EFI_PPI_CONSUMER" : gPpiDefinition ,
"EFI_PPI_DEPENDENCY" : gPpiDefinition ,
}
NMAKE_FILETYPE = "nmake"
GMAKE_FILETYPE = "gmake"
WIN32_PLATFORM = "win32"
POSIX_PLATFORM = "posix"
## BuildFile class
#
# This base class encapsules build file and its generation. It uses template to generate
# the content of build file. The content of build file will be got from AutoGen objects.
#
class BuildFile ( object ):
## template used to generate the build file (i.e. makefile if using make)
_TEMPLATE_ = TemplateString ( '' )
_DEFAULT_FILE_NAME_ = "Makefile"
## default file name for each type of build file
_FILE_NAME_ = {
NMAKE_FILETYPE : "Makefile" ,
GMAKE_FILETYPE : "GNUmakefile"
}
# Get Makefile name.
def getMakefileName ( self ):
if not self . _FileType :
return self . _DEFAULT_FILE_NAME_
else :
return self . _FILE_NAME_ [ self . _FileType ]
## Fixed header string for makefile
_MAKEFILE_HEADER = '''#
# DO NOT EDIT
# This file is auto-generated by build utility
#
# Module Name:
#
# %s
#
# Abstract:
#
# Auto-generated makefile for building modules, libraries or platform
#
'''
## Header string for each type of build file
_FILE_HEADER_ = {
NMAKE_FILETYPE : _MAKEFILE_HEADER % _FILE_NAME_ [ NMAKE_FILETYPE ],
GMAKE_FILETYPE : _MAKEFILE_HEADER % _FILE_NAME_ [ GMAKE_FILETYPE ]
}
## shell commands which can be used in build file in the form of macro
# $(CP) copy file command
# $(MV) move file command
# $(RM) remove file command
# $(MD) create dir command
# $(RD) remove dir command
#
_SHELL_CMD_ = {
WIN32_PLATFORM : {
"CP" : "copy /y" ,
"MV" : "move /y" ,
"RM" : "del /f /q" ,
"MD" : "mkdir" ,
"RD" : "rmdir /s /q" ,
},
POSIX_PLATFORM : {
"CP" : "cp -f" ,
"MV" : "mv -f" ,
"RM" : "rm -f" ,
"MD" : "mkdir -p" ,
"RD" : "rm -r -f" ,
}
}
## directory separator
_SEP_ = {
WIN32_PLATFORM : " \\ " ,
POSIX_PLATFORM : "/"
}
## directory creation template
_MD_TEMPLATE_ = {
WIN32_PLATFORM : 'if not exist %(dir)s $(MD) %(dir)s ' ,
POSIX_PLATFORM : "$(MD) %(dir)s "
}
## directory removal template
_RD_TEMPLATE_ = {
WIN32_PLATFORM : 'if exist %(dir)s $(RD) %(dir)s ' ,
POSIX_PLATFORM : "$(RD) %(dir)s "
}
## cp if exist
_CP_TEMPLATE_ = {
WIN32_PLATFORM : 'if exist %(Src)s $(CP) %(Src)s %(Dst)s ' ,
POSIX_PLATFORM : "test -f %(Src)s && $(CP) %(Src)s %(Dst)s "
}
_CD_TEMPLATE_ = {
WIN32_PLATFORM : 'if exist %(dir)s cd %(dir)s ' ,
POSIX_PLATFORM : "test -e %(dir)s && cd %(dir)s "
}
_MAKE_TEMPLATE_ = {
WIN32_PLATFORM : 'if exist %(file)s "$(MAKE)" $(MAKE_FLAGS) -f %(file)s ' ,
POSIX_PLATFORM : 'test -e %(file)s && "$(MAKE)" $(MAKE_FLAGS) -f %(file)s '
}
_INCLUDE_CMD_ = {
NMAKE_FILETYPE : '!INCLUDE' ,
GMAKE_FILETYPE : "include"
}
_INC_FLAG_ = { TAB_COMPILER_MSFT : "/I" , "GCC" : "-I" , "INTEL" : "-I" , "RVCT" : "-I" , "NASM" : "-I" }
## Constructor of BuildFile
#
# @param AutoGenObject Object of AutoGen class
#
def __init__ ( self , AutoGenObject ):
self . _AutoGenObject = AutoGenObject
MakePath = AutoGenObject . BuildOption . get ( 'MAKE' , {}) . get ( 'PATH' )
if not MakePath :
2021-12-13 09:14:42 -08:00
MakePath = AutoGenObject . ToolDefinition . get ( 'MAKE' , {}) . get ( 'PATH' )
if "nmake" in MakePath :
2021-11-10 11:36:23 +00:00
self . _FileType = NMAKE_FILETYPE
else :
2021-12-13 09:14:42 -08:00
self . _FileType = GMAKE_FILETYPE
2021-11-10 11:36:23 +00:00
if sys . platform == "win32" :
self . _Platform = WIN32_PLATFORM
else :
self . _Platform = POSIX_PLATFORM
## Create build file.
#
# Only nmake and gmake are supported.
#
# @retval TRUE The build file is created or re-created successfully.
# @retval FALSE The build file exists and is the same as the one to be generated.
#
def Generate ( self ):
FileContent = self . _TEMPLATE_ . Replace ( self . _TemplateDict )
FileName = self . getMakefileName ()
if not os . path . exists ( os . path . join ( self . _AutoGenObject . MakeFileDir , "deps.txt" )):
with open ( os . path . join ( self . _AutoGenObject . MakeFileDir , "deps.txt" ), "w+" ) as fd :
fd . write ( "" )
if not os . path . exists ( os . path . join ( self . _AutoGenObject . MakeFileDir , "dependency" )):
with open ( os . path . join ( self . _AutoGenObject . MakeFileDir , "dependency" ), "w+" ) as fd :
fd . write ( "" )
if not os . path . exists ( os . path . join ( self . _AutoGenObject . MakeFileDir , "deps_target" )):
with open ( os . path . join ( self . _AutoGenObject . MakeFileDir , "deps_target" ), "w+" ) as fd :
fd . write ( "" )
return SaveFileOnChange ( os . path . join ( self . _AutoGenObject . MakeFileDir , FileName ), FileContent , False )
## Return a list of directory creation command string
#
# @param DirList The list of directory to be created
#
# @retval list The directory creation command list
#
def GetCreateDirectoryCommand ( self , DirList ):
return [ self . _MD_TEMPLATE_ [ self . _Platform ] % { 'dir' : Dir } for Dir in DirList ]
## Return a list of directory removal command string
#
# @param DirList The list of directory to be removed
#
# @retval list The directory removal command list
#
def GetRemoveDirectoryCommand ( self , DirList ):
return [ self . _RD_TEMPLATE_ [ self . _Platform ] % { 'dir' : Dir } for Dir in DirList ]
def PlaceMacro ( self , Path , MacroDefinitions = None ):
if Path . startswith ( "$(" ):
return Path
else :
if MacroDefinitions is None :
MacroDefinitions = {}
PathLength = len ( Path )
for MacroName in MacroDefinitions :
MacroValue = MacroDefinitions [ MacroName ]
MacroValueLength = len ( MacroValue )
if MacroValueLength == 0 :
continue
if MacroValueLength <= PathLength and Path . startswith ( MacroValue ):
Path = "$( %s ) %s " % ( MacroName , Path [ MacroValueLength :])
break
return Path
## ModuleMakefile class
#
# This class encapsules makefie and its generation for module. It uses template to generate
# the content of makefile. The content of makefile will be got from ModuleAutoGen object.
#
class ModuleMakefile ( BuildFile ):
## template used to generate the makefile for module
_TEMPLATE_ = TemplateString ( ''' \
$ {makefile_header}
#
# Platform Macro Definition
#
PLATFORM_NAME = $ {platform_name}
PLATFORM_GUID = $ {platform_guid}
PLATFORM_VERSION = $ {platform_version}
PLATFORM_RELATIVE_DIR = $ {platform_relative_directory}
PLATFORM_DIR = $ {platform_dir}
PLATFORM_OUTPUT_DIR = $ {platform_output_directory}
#
# Module Macro Definition
#
MODULE_NAME = $ {module_name}
MODULE_GUID = $ {module_guid}
MODULE_NAME_GUID = $ {module_name_guid}
MODULE_VERSION = $ {module_version}
MODULE_TYPE = $ {module_type}
MODULE_FILE = $ {module_file}
MODULE_FILE_BASE_NAME = $ {module_file_base_name}
BASE_NAME = $(MODULE_NAME)
MODULE_RELATIVE_DIR = $ {module_relative_directory}
PACKAGE_RELATIVE_DIR = $ {package_relative_directory}
MODULE_DIR = $ {module_dir}
FFS_OUTPUT_DIR = $ {ffs_output_directory}
MODULE_ENTRY_POINT = $ {module_entry_point}
ARCH_ENTRY_POINT = $ {arch_entry_point}
IMAGE_ENTRY_POINT = $ {image_entry_point}
$ {BEGIN} $ {module_extra_defines}
$ {END}
#
# Build Configuration Macro Definition
#
ARCH = $ {architecture}
TOOLCHAIN = $ {toolchain_tag}
TOOLCHAIN_TAG = $ {toolchain_tag}
TARGET = $ {build_target}
#
# Build Directory Macro Definition
#
# PLATFORM_BUILD_DIR = $ {platform_build_directory}
BUILD_DIR = $ {platform_build_directory}
BIN_DIR = $(BUILD_DIR)$ {separator} $ {architecture}
LIB_DIR = $(BIN_DIR)
MODULE_BUILD_DIR = $ {module_build_directory}
OUTPUT_DIR = $ {module_output_directory}
DEBUG_DIR = $ {module_debug_directory}
DEST_DIR_OUTPUT = $(OUTPUT_DIR)
DEST_DIR_DEBUG = $(DEBUG_DIR)
#
# Shell Command Macro
#
$ {BEGIN} $ {shell_command_code} = $ {shell_command}
$ {END}
#
# Tools definitions specific to this module
#
$ {BEGIN} $ {module_tool_definitions}
$ {END}
MAKE_FILE = $ {makefile_path}
#
# Build Macro
#
$ {BEGIN} $ {file_macro}
$ {END}
#
# Overridable Target Macro Definitions
#
FORCE_REBUILD = force_build
INIT_TARGET = init
PCH_TARGET =
BC_TARGET = $ {BEGIN} $ {backward_compatible_target} $ {END}
CODA_TARGET = $ {BEGIN} $ {remaining_build_target} \\
$ {END}
#
# Default target, which will build dependent libraries in addition to source files
#
all: mbuild
#
# Target used when called from platform makefile, which will bypass the build of dependent libraries
#
pbuild: $(INIT_TARGET) $(BC_TARGET) $(PCH_TARGET) $(CODA_TARGET)
#
# ModuleTarget
#
mbuild: $(INIT_TARGET) $(BC_TARGET) gen_libs $(PCH_TARGET) $(CODA_TARGET)
#
# Build Target used in multi-thread build mode, which will bypass the init and gen_libs targets
#
tbuild: $(BC_TARGET) $(PCH_TARGET) $(CODA_TARGET)
#
# Phony target which is used to force executing commands for a target
#
force_build:
\t -@
#
# Target to update the FD
#
fds: mbuild gen_fds
#
# Initialization target: print build information and create necessary directories
#
init: info dirs
info:
\t -@echo Building ... $(MODULE_DIR)$ {separator} $(MODULE_FILE) [$(ARCH)]
dirs:
$ {BEGIN} \t -@$ {create_directory_command} \n $ {END}
strdefs:
\t -@$(CP) $(DEBUG_DIR)$ {separator} AutoGen.h $(DEBUG_DIR)$ {separator} $(MODULE_NAME)StrDefs.h
#
# GenLibsTarget
#
gen_libs:
\t $ {BEGIN} @"$(MAKE)" $(MAKE_FLAGS) -f $ {dependent_library_build_directory} $ {separator} $ {makefile_name}
\t $ {END} @cd $(MODULE_BUILD_DIR)
#
# Build Flash Device Image
#
gen_fds:
\t @"$(MAKE)" $(MAKE_FLAGS) -f $(BUILD_DIR)$ {separator} $ {makefile_name} fds
\t @cd $(MODULE_BUILD_DIR)
$ {INCLUDETAG}
#
# Individual Object Build Targets
#
$ {BEGIN} $ {file_build_target}
$ {END}
#
# clean all intermediate files
#
clean:
\t $ {BEGIN} $ {clean_command}
\t $ {END} \t $(RM) AutoGenTimeStamp
#
# clean all generated files
#
cleanall:
$ {BEGIN} \t $ {cleanall_command}
$ {END} \t $(RM) *.pdb *.idb > NUL 2>&1
\t $(RM) $(BIN_DIR)$ {separator} $(MODULE_NAME).efi
\t $(RM) AutoGenTimeStamp
#
# clean all dependent libraries built
#
cleanlib:
\t $ {BEGIN} -@$ {library_build_command} cleanall
\t $ {END} @cd $(MODULE_BUILD_DIR) \n\n ''' )
_FILE_MACRO_TEMPLATE = TemplateString ( "$ {macro_name} = $ {BEGIN} \\\n $ {source_file} $ {END} \n " )
_BUILD_TARGET_TEMPLATE = TemplateString ( "$ {BEGIN} $ {target} : $ {deps} \n $ {END} \t $ {cmd} \n " )
## Constructor of ModuleMakefile
#
# @param ModuleAutoGen Object of ModuleAutoGen class
#
def __init__ ( self , ModuleAutoGen ):
BuildFile . __init__ ( self , ModuleAutoGen )
self . PlatformInfo = self . _AutoGenObject . PlatformInfo
self . ResultFileList = []
self . IntermediateDirectoryList = [ "$(DEBUG_DIR)" , "$(OUTPUT_DIR)" ]
self . FileBuildTargetList = [] # [(src, target string)]
self . BuildTargetList = [] # [target string]
self . PendingBuildTargetList = [] # [FileBuildRule objects]
self . CommonFileDependency = []
self . FileListMacros = {}
self . ListFileMacros = {}
self . ObjTargetDict = OrderedDict ()
self . FileCache = {}
self . LibraryBuildCommandList = []
self . LibraryFileList = []
self . LibraryMakefileList = []
self . LibraryBuildDirectoryList = []
self . SystemLibraryList = []
self . Macros = OrderedDict ()
self . Macros [ "OUTPUT_DIR" ] = self . _AutoGenObject . Macros [ "OUTPUT_DIR" ]
self . Macros [ "DEBUG_DIR" ] = self . _AutoGenObject . Macros [ "DEBUG_DIR" ]
self . Macros [ "MODULE_BUILD_DIR" ] = self . _AutoGenObject . Macros [ "MODULE_BUILD_DIR" ]
self . Macros [ "BIN_DIR" ] = self . _AutoGenObject . Macros [ "BIN_DIR" ]
self . Macros [ "BUILD_DIR" ] = self . _AutoGenObject . Macros [ "BUILD_DIR" ]
self . Macros [ "WORKSPACE" ] = self . _AutoGenObject . Macros [ "WORKSPACE" ]
self . Macros [ "FFS_OUTPUT_DIR" ] = self . _AutoGenObject . Macros [ "FFS_OUTPUT_DIR" ]
self . GenFfsList = ModuleAutoGen . GenFfsList
self . MacroList = [ 'FFS_OUTPUT_DIR' , 'MODULE_GUID' , 'OUTPUT_DIR' ]
self . FfsOutputFileList = []
self . DependencyHeaderFileSet = set ()
# Compose a dict object containing information used to do replacement in template
@property
def _TemplateDict ( self ):
MyAgo = self . _AutoGenObject
Separator = self . _SEP_ [ self . _Platform ]
# break build if no source files and binary files are found
if len ( MyAgo . SourceFileList ) == 0 and len ( MyAgo . BinaryFileList ) == 0 :
EdkLogger . error ( "build" , AUTOGEN_ERROR , "No files to be built in module [ %s , %s , %s ]"
% ( MyAgo . BuildTarget , MyAgo . ToolChain , MyAgo . Arch ),
ExtraData = "[ %s ]" % str ( MyAgo ))
# convert dependent libraries to build command
self . ProcessDependentLibrary ()
if len ( MyAgo . Module . ModuleEntryPointList ) > 0 :
ModuleEntryPoint = MyAgo . Module . ModuleEntryPointList [ 0 ]
else :
ModuleEntryPoint = "_ModuleEntryPoint"
ArchEntryPoint = ModuleEntryPoint
if MyAgo . Arch == "EBC" :
# EBC compiler always use "EfiStart" as entry point. Only applies to EdkII modules
ImageEntryPoint = "EfiStart"
else :
# EdkII modules always use "_ModuleEntryPoint" as entry point
ImageEntryPoint = "_ModuleEntryPoint"
for k , v in MyAgo . Module . Defines . items ():
if k not in MyAgo . Macros :
MyAgo . Macros [ k ] = v
if 'MODULE_ENTRY_POINT' not in MyAgo . Macros :
MyAgo . Macros [ 'MODULE_ENTRY_POINT' ] = ModuleEntryPoint
if 'ARCH_ENTRY_POINT' not in MyAgo . Macros :
MyAgo . Macros [ 'ARCH_ENTRY_POINT' ] = ArchEntryPoint
if 'IMAGE_ENTRY_POINT' not in MyAgo . Macros :
MyAgo . Macros [ 'IMAGE_ENTRY_POINT' ] = ImageEntryPoint
PCI_COMPRESS_Flag = False
for k , v in MyAgo . Module . Defines . items ():
if 'PCI_COMPRESS' == k and 'TRUE' == v :
PCI_COMPRESS_Flag = True
# tools definitions
ToolsDef = []
IncPrefix = self . _INC_FLAG_ [ MyAgo . ToolChainFamily ]
2021-12-13 09:14:42 -08:00
for Tool in sorted ( list ( MyAgo . BuildOption )):
Appended = False
for Attr in sorted ( list ( MyAgo . BuildOption [ Tool ])):
2021-11-10 11:36:23 +00:00
Value = MyAgo . BuildOption [ Tool ][ Attr ]
if Attr == "FAMILY" :
continue
elif Attr == "PATH" :
ToolsDef . append ( " %s = %s " % ( Tool , Value ))
2021-12-13 09:14:42 -08:00
Appended = True
2021-11-10 11:36:23 +00:00
else :
# Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
if Tool == "MAKE" :
continue
# Remove duplicated include path, if any
if Attr == "FLAGS" :
Value = RemoveDupOption ( Value , IncPrefix , MyAgo . IncludePathList )
if Tool == "OPTROM" and PCI_COMPRESS_Flag :
ValueList = Value . split ()
if ValueList :
for i , v in enumerate ( ValueList ):
if '-e' == v :
ValueList [ i ] = '-ec'
Value = ' ' . join ( ValueList )
ToolsDef . append ( " %s _ %s = %s " % ( Tool , Attr , Value ))
2021-12-13 09:14:42 -08:00
Appended = True
if Appended :
ToolsDef . append ( "" )
2021-11-10 11:36:23 +00:00
# generate the Response file and Response flag
RespDict = self . CommandExceedLimit ()
RespFileList = os . path . join ( MyAgo . OutputDir , 'respfilelist.txt' )
if RespDict :
RespFileListContent = ''
for Resp in RespDict :
RespFile = os . path . join ( MyAgo . OutputDir , str ( Resp ) . lower () + '.txt' )
StrList = RespDict [ Resp ] . split ( ' ' )
UnexpandMacro = []
NewStr = []
for Str in StrList :
if '$' in Str or '-MMD' in Str or '-MF' in Str :
UnexpandMacro . append ( Str )
else :
NewStr . append ( Str )
UnexpandMacroStr = ' ' . join ( UnexpandMacro )
NewRespStr = ' ' . join ( NewStr )
SaveFileOnChange ( RespFile , NewRespStr , False )
ToolsDef . append ( " %s = %s " % ( Resp , UnexpandMacroStr + ' @' + RespFile ))
RespFileListContent += '@' + RespFile + TAB_LINE_BREAK
RespFileListContent += NewRespStr + TAB_LINE_BREAK
SaveFileOnChange ( RespFileList , RespFileListContent , False )
else :
if os . path . exists ( RespFileList ):
os . remove ( RespFileList )
# convert source files and binary files to build targets
self . ResultFileList = [ str ( T . Target ) for T in MyAgo . CodaTargetList ]
if len ( self . ResultFileList ) == 0 and len ( MyAgo . SourceFileList ) != 0 :
EdkLogger . error ( "build" , AUTOGEN_ERROR , "Nothing to build" ,
ExtraData = "[ %s ]" % str ( MyAgo ))
2021-12-13 09:14:42 -08:00
self . ProcessBuildTargetList ( MyAgo . OutputDir , ToolsDef )
2021-11-10 11:36:23 +00:00
self . ParserGenerateFfsCmd ()
# Generate macros used to represent input files
FileMacroList = [] # macro name = file list
for FileListMacro in self . FileListMacros :
FileMacro = self . _FILE_MACRO_TEMPLATE . Replace (
{
"macro_name" : FileListMacro ,
"source_file" : self . FileListMacros [ FileListMacro ]
}
)
FileMacroList . append ( FileMacro )
# INC_LIST is special
FileMacro = ""
IncludePathList = []
for P in MyAgo . IncludePathList :
IncludePathList . append ( IncPrefix + self . PlaceMacro ( P , self . Macros ))
if FileBuildRule . INC_LIST_MACRO in self . ListFileMacros :
self . ListFileMacros [ FileBuildRule . INC_LIST_MACRO ] . append ( IncPrefix + P )
FileMacro += self . _FILE_MACRO_TEMPLATE . Replace (
{
"macro_name" : "INC" ,
"source_file" : IncludePathList
}
)
FileMacroList . append ( FileMacro )
# Add support when compiling .nasm source files
IncludePathList = []
asmsource = [ item for item in MyAgo . SourceFileList if item . File . upper () . endswith (( ".NASM" , ".ASM" , ".NASMB" , "S" ))]
if asmsource :
for P in MyAgo . IncludePathList :
IncludePath = self . _INC_FLAG_ [ 'NASM' ] + self . PlaceMacro ( P , self . Macros )
if IncludePath . endswith ( os . sep ):
IncludePath = IncludePath . rstrip ( os . sep )
# When compiling .nasm files, need to add a literal backslash at each path.
# In nmake makfiles, a trailing literal backslash must be escaped with a caret ('^').
# It is otherwise replaced with a space (' '). This is not necessary for GNU makfefiles.
if P == MyAgo . IncludePathList [ - 1 ] and self . _Platform == WIN32_PLATFORM and self . _FileType == NMAKE_FILETYPE :
IncludePath = '' . join ([ IncludePath , '^' , os . sep ])
else :
IncludePath = os . path . join ( IncludePath , '' )
IncludePathList . append ( IncludePath )
FileMacroList . append ( self . _FILE_MACRO_TEMPLATE . Replace ({ "macro_name" : "NASM_INC" , "source_file" : IncludePathList }))
# Generate macros used to represent files containing list of input files
for ListFileMacro in self . ListFileMacros :
ListFileName = os . path . join ( MyAgo . OutputDir , " %s .lst" % ListFileMacro . lower ()[: len ( ListFileMacro ) - 5 ])
FileMacroList . append ( " %s = %s " % ( ListFileMacro , ListFileName ))
SaveFileOnChange (
ListFileName ,
" \n " . join ( self . ListFileMacros [ ListFileMacro ]),
False
)
# Generate objlist used to create .obj file
for Type in self . ObjTargetDict :
NewLine = ' ' . join ( list ( self . ObjTargetDict [ Type ]))
FileMacroList . append ( "OBJLIST_ %s = %s " % ( list ( self . ObjTargetDict . keys ()) . index ( Type ), NewLine ))
BcTargetList = []
MakefileName = self . getMakefileName ()
LibraryMakeCommandList = []
for D in self . LibraryBuildDirectoryList :
Command = self . _MAKE_TEMPLATE_ [ self . _Platform ] % { "file" : os . path . join ( D , MakefileName )}
LibraryMakeCommandList . append ( Command )
package_rel_dir = MyAgo . SourceDir
current_dir = self . Macros [ "WORKSPACE" ]
found = False
while not found and os . sep in package_rel_dir :
index = package_rel_dir . index ( os . sep )
current_dir = mws . join ( current_dir , package_rel_dir [: index ])
if os . path . exists ( current_dir ):
for fl in os . listdir ( current_dir ):
if fl . endswith ( '.dec' ):
found = True
break
package_rel_dir = package_rel_dir [ index + 1 :]
MakefileTemplateDict = {
"makefile_header" : self . _FILE_HEADER_ [ self . _FileType ],
"makefile_path" : os . path . join ( "$(MODULE_BUILD_DIR)" , MakefileName ),
"makefile_name" : MakefileName ,
"platform_name" : self . PlatformInfo . Name ,
"platform_guid" : self . PlatformInfo . Guid ,
"platform_version" : self . PlatformInfo . Version ,
"platform_relative_directory" : self . PlatformInfo . SourceDir ,
"platform_output_directory" : self . PlatformInfo . OutputDir ,
"ffs_output_directory" : MyAgo . Macros [ "FFS_OUTPUT_DIR" ],
"platform_dir" : MyAgo . Macros [ "PLATFORM_DIR" ],
"module_name" : MyAgo . Name ,
"module_guid" : MyAgo . Guid ,
"module_name_guid" : MyAgo . UniqueBaseName ,
"module_version" : MyAgo . Version ,
"module_type" : MyAgo . ModuleType ,
"module_file" : MyAgo . MetaFile . Name ,
"module_file_base_name" : MyAgo . MetaFile . BaseName ,
"module_relative_directory" : MyAgo . SourceDir ,
"module_dir" : mws . join ( self . Macros [ "WORKSPACE" ], MyAgo . SourceDir ),
"package_relative_directory" : package_rel_dir ,
"module_extra_defines" : [ " %s = %s " % ( k , v ) for k , v in MyAgo . Module . Defines . items ()],
"architecture" : MyAgo . Arch ,
"toolchain_tag" : MyAgo . ToolChain ,
"build_target" : MyAgo . BuildTarget ,
"platform_build_directory" : self . PlatformInfo . BuildDir ,
"module_build_directory" : MyAgo . BuildDir ,
"module_output_directory" : MyAgo . OutputDir ,
"module_debug_directory" : MyAgo . DebugDir ,
"separator" : Separator ,
"module_tool_definitions" : ToolsDef ,
"shell_command_code" : list ( self . _SHELL_CMD_ [ self . _Platform ] . keys ()),
"shell_command" : list ( self . _SHELL_CMD_ [ self . _Platform ] . values ()),
"module_entry_point" : ModuleEntryPoint ,
"image_entry_point" : ImageEntryPoint ,
"arch_entry_point" : ArchEntryPoint ,
"remaining_build_target" : self . ResultFileList ,
"common_dependency_file" : self . CommonFileDependency ,
"create_directory_command" : self . GetCreateDirectoryCommand ( self . IntermediateDirectoryList ),
"clean_command" : self . GetRemoveDirectoryCommand ([ "$(OUTPUT_DIR)" ]),
"cleanall_command" : self . GetRemoveDirectoryCommand ([ "$(DEBUG_DIR)" , "$(OUTPUT_DIR)" ]),
"dependent_library_build_directory" : self . LibraryBuildDirectoryList ,
"library_build_command" : LibraryMakeCommandList ,
"file_macro" : FileMacroList ,
"file_build_target" : self . BuildTargetList ,
"backward_compatible_target" : BcTargetList ,
"INCLUDETAG" : " \n " . join ([ self . _INCLUDE_CMD_ [ self . _FileType ] + " " + os . path . join ( "$(MODULE_BUILD_DIR)" , "dependency" ),
self . _INCLUDE_CMD_ [ self . _FileType ] + " " + os . path . join ( "$(MODULE_BUILD_DIR)" , "deps_target" )
])
}
return MakefileTemplateDict
def ParserGenerateFfsCmd ( self ):
#Add Ffs cmd to self.BuildTargetList
OutputFile = ''
DepsFileList = []
for Cmd in self . GenFfsList :
if Cmd [ 2 ]:
for CopyCmd in Cmd [ 2 ]:
Src , Dst = CopyCmd
Src = self . ReplaceMacro ( Src )
Dst = self . ReplaceMacro ( Dst )
if Dst not in self . ResultFileList :
self . ResultFileList . append ( Dst )
if ' %s :' % ( Dst ) not in self . BuildTargetList :
self . BuildTargetList . append ( " %s : %s " % ( Dst , Src ))
self . BuildTargetList . append ( ' \t ' + self . _CP_TEMPLATE_ [ self . _Platform ] % { 'Src' : Src , 'Dst' : Dst })
FfsCmdList = Cmd [ 0 ]
for index , Str in enumerate ( FfsCmdList ):
if '-o' == Str :
OutputFile = FfsCmdList [ index + 1 ]
if '-i' == Str or "-oi" == Str :
if DepsFileList == []:
DepsFileList = [ FfsCmdList [ index + 1 ]]
else :
DepsFileList . append ( FfsCmdList [ index + 1 ])
DepsFileString = ' ' . join ( DepsFileList ) . strip ()
if DepsFileString == '' :
continue
OutputFile = self . ReplaceMacro ( OutputFile )
self . ResultFileList . append ( OutputFile )
DepsFileString = self . ReplaceMacro ( DepsFileString )
self . BuildTargetList . append ( ' %s : %s ' % ( OutputFile , DepsFileString ))
CmdString = ' ' . join ( FfsCmdList ) . strip ()
CmdString = self . ReplaceMacro ( CmdString )
self . BuildTargetList . append ( ' \t %s ' % CmdString )
self . ParseSecCmd ( DepsFileList , Cmd [ 1 ])
for SecOutputFile , SecDepsFile , SecCmd in self . FfsOutputFileList :
self . BuildTargetList . append ( ' %s : %s ' % ( self . ReplaceMacro ( SecOutputFile ), self . ReplaceMacro ( SecDepsFile )))
self . BuildTargetList . append ( ' \t %s ' % self . ReplaceMacro ( SecCmd ))
self . FfsOutputFileList = []
def ParseSecCmd ( self , OutputFileList , CmdTuple ):
for OutputFile in OutputFileList :
for SecCmdStr in CmdTuple :
SecDepsFileList = []
SecCmdList = SecCmdStr . split ()
CmdName = SecCmdList [ 0 ]
for index , CmdItem in enumerate ( SecCmdList ):
if '-o' == CmdItem and OutputFile == SecCmdList [ index + 1 ]:
index = index + 1
while index + 1 < len ( SecCmdList ):
if not SecCmdList [ index + 1 ] . startswith ( '-' ):
SecDepsFileList . append ( SecCmdList [ index + 1 ])
index = index + 1
if CmdName == 'Trim' :
SecDepsFileList . append ( os . path . join ( '$(DEBUG_DIR)' , os . path . basename ( OutputFile ) . replace ( 'offset' , 'efi' )))
if OutputFile . endswith ( '.ui' ) or OutputFile . endswith ( '.ver' ):
SecDepsFileList . append ( os . path . join ( '$(MODULE_DIR)' , '$(MODULE_FILE)' ))
self . FfsOutputFileList . append (( OutputFile , ' ' . join ( SecDepsFileList ), SecCmdStr ))
if len ( SecDepsFileList ) > 0 :
self . ParseSecCmd ( SecDepsFileList , CmdTuple )
break
else :
continue
def ReplaceMacro ( self , str ):
for Macro in self . MacroList :
2021-12-13 09:14:42 -08:00
if self . _AutoGenObject . Macros [ Macro ] and os . path . normcase ( self . _AutoGenObject . Macros [ Macro ]) in os . path . normcase ( str ):
replace_dir = str [ os . path . normcase ( str ) . index ( os . path . normcase ( self . _AutoGenObject . Macros [ Macro ])): os . path . normcase ( str ) . index (
os . path . normcase ( self . _AutoGenObject . Macros [ Macro ])) + len ( self . _AutoGenObject . Macros [ Macro ])]
str = str . replace ( replace_dir , '$(' + Macro + ')' )
2021-11-10 11:36:23 +00:00
return str
def CommandExceedLimit ( self ):
FlagDict = {
'CC' : { 'Macro' : '$(CC_FLAGS)' , 'Value' : False },
'PP' : { 'Macro' : '$(PP_FLAGS)' , 'Value' : False },
'APP' : { 'Macro' : '$(APP_FLAGS)' , 'Value' : False },
'ASLPP' : { 'Macro' : '$(ASLPP_FLAGS)' , 'Value' : False },
'VFRPP' : { 'Macro' : '$(VFRPP_FLAGS)' , 'Value' : False },
'ASM' : { 'Macro' : '$(ASM_FLAGS)' , 'Value' : False },
'ASLCC' : { 'Macro' : '$(ASLCC_FLAGS)' , 'Value' : False },
}
RespDict = {}
FileTypeList = []
IncPrefix = self . _INC_FLAG_ [ self . _AutoGenObject . ToolChainFamily ]
# base on the source files to decide the file type
for File in self . _AutoGenObject . SourceFileList :
for type in self . _AutoGenObject . FileTypes :
if File in self . _AutoGenObject . FileTypes [ type ]:
if type not in FileTypeList :
FileTypeList . append ( type )
# calculate the command-line length
if FileTypeList :
for type in FileTypeList :
BuildTargets = self . _AutoGenObject . BuildRules [ type ] . BuildTargets
for Target in BuildTargets :
CommandList = BuildTargets [ Target ] . Commands
for SingleCommand in CommandList :
Tool = ''
SingleCommandLength = len ( SingleCommand )
SingleCommandList = SingleCommand . split ()
if len ( SingleCommandList ) > 0 :
for Flag in FlagDict :
if '$(' + Flag + ')' in SingleCommandList [ 0 ]:
Tool = Flag
break
if Tool :
if 'PATH' not in self . _AutoGenObject . BuildOption [ Tool ]:
EdkLogger . error ( "build" , AUTOGEN_ERROR , " %s _PATH doesn't exist in %s ToolChain and %s Arch." % ( Tool , self . _AutoGenObject . ToolChain , self . _AutoGenObject . Arch ), ExtraData = "[ %s ]" % str ( self . _AutoGenObject ))
SingleCommandLength += len ( self . _AutoGenObject . BuildOption [ Tool ][ 'PATH' ])
for item in SingleCommandList [ 1 :]:
if FlagDict [ Tool ][ 'Macro' ] in item :
if 'FLAGS' not in self . _AutoGenObject . BuildOption [ Tool ]:
EdkLogger . error ( "build" , AUTOGEN_ERROR , " %s _FLAGS doesn't exist in %s ToolChain and %s Arch." % ( Tool , self . _AutoGenObject . ToolChain , self . _AutoGenObject . Arch ), ExtraData = "[ %s ]" % str ( self . _AutoGenObject ))
Str = self . _AutoGenObject . BuildOption [ Tool ][ 'FLAGS' ]
for Option in self . _AutoGenObject . BuildOption :
for Attr in self . _AutoGenObject . BuildOption [ Option ]:
if Str . find ( Option + '_' + Attr ) != - 1 :
Str = Str . replace ( '$(' + Option + '_' + Attr + ')' , self . _AutoGenObject . BuildOption [ Option ][ Attr ])
while ( Str . find ( '$(' ) != - 1 ):
for macro in self . _AutoGenObject . Macros :
MacroName = '$(' + macro + ')'
if ( Str . find ( MacroName ) != - 1 ):
Str = Str . replace ( MacroName , self . _AutoGenObject . Macros [ macro ])
break
else :
break
SingleCommandLength += len ( Str )
elif '$(INC)' in item :
SingleCommandLength += self . _AutoGenObject . IncludePathLength + len ( IncPrefix ) * len ( self . _AutoGenObject . IncludePathList )
elif item . find ( '$(' ) != - 1 :
Str = item
for Option in self . _AutoGenObject . BuildOption :
for Attr in self . _AutoGenObject . BuildOption [ Option ]:
if Str . find ( Option + '_' + Attr ) != - 1 :
Str = Str . replace ( '$(' + Option + '_' + Attr + ')' , self . _AutoGenObject . BuildOption [ Option ][ Attr ])
while ( Str . find ( '$(' ) != - 1 ):
for macro in self . _AutoGenObject . Macros :
MacroName = '$(' + macro + ')'
if ( Str . find ( MacroName ) != - 1 ):
Str = Str . replace ( MacroName , self . _AutoGenObject . Macros [ macro ])
break
else :
break
SingleCommandLength += len ( Str )
if SingleCommandLength > GlobalData . gCommandMaxLength :
FlagDict [ Tool ][ 'Value' ] = True
# generate the response file content by combine the FLAGS and INC
for Flag in FlagDict :
if FlagDict [ Flag ][ 'Value' ]:
Key = Flag + '_RESP'
RespMacro = FlagDict [ Flag ][ 'Macro' ] . replace ( 'FLAGS' , 'RESP' )
Value = self . _AutoGenObject . BuildOption [ Flag ][ 'FLAGS' ]
for inc in self . _AutoGenObject . IncludePathList :
Value += ' ' + IncPrefix + inc
for Option in self . _AutoGenObject . BuildOption :
for Attr in self . _AutoGenObject . BuildOption [ Option ]:
if Value . find ( Option + '_' + Attr ) != - 1 :
Value = Value . replace ( '$(' + Option + '_' + Attr + ')' , self . _AutoGenObject . BuildOption [ Option ][ Attr ])
while ( Value . find ( '$(' ) != - 1 ):
for macro in self . _AutoGenObject . Macros :
MacroName = '$(' + macro + ')'
if ( Value . find ( MacroName ) != - 1 ):
Value = Value . replace ( MacroName , self . _AutoGenObject . Macros [ macro ])
break
else :
break
if self . _AutoGenObject . ToolChainFamily == 'GCC' :
RespDict [ Key ] = Value . replace ( ' \\ ' , '/' )
else :
RespDict [ Key ] = Value
for Target in BuildTargets :
for i , SingleCommand in enumerate ( BuildTargets [ Target ] . Commands ):
if FlagDict [ Flag ][ 'Macro' ] in SingleCommand :
BuildTargets [ Target ] . Commands [ i ] = SingleCommand . replace ( '$(INC)' , '' ) . replace ( FlagDict [ Flag ][ 'Macro' ], RespMacro )
return RespDict
2021-12-13 09:14:42 -08:00
def ProcessBuildTargetList ( self , RespFile , ToolsDef ):
2021-11-10 11:36:23 +00:00
#
# Search dependency file list for each source file
#
ForceIncludedFile = []
for File in self . _AutoGenObject . AutoGenFileList :
if File . Ext == '.h' :
ForceIncludedFile . append ( File )
SourceFileList = []
OutPutFileList = []
for Target in self . _AutoGenObject . IntroTargetList :
SourceFileList . extend ( Target . Inputs )
OutPutFileList . extend ( Target . Outputs )
if OutPutFileList :
for Item in OutPutFileList :
if Item in SourceFileList :
SourceFileList . remove ( Item )
FileDependencyDict = { item : ForceIncludedFile for item in SourceFileList }
for Dependency in FileDependencyDict . values ():
self . DependencyHeaderFileSet . update ( set ( Dependency ))
# Get a set of unique package includes from MetaFile
parentMetaFileIncludes = set ()
for aInclude in self . _AutoGenObject . PackageIncludePathList :
aIncludeName = str ( aInclude )
parentMetaFileIncludes . add ( aIncludeName . lower ())
# Check if header files are listed in metafile
# Get a set of unique module header source files from MetaFile
headerFilesInMetaFileSet = set ()
for aFile in self . _AutoGenObject . SourceFileList :
aFileName = str ( aFile )
if not aFileName . endswith ( '.h' ):
continue
headerFilesInMetaFileSet . add ( aFileName . lower ())
# Get a set of unique module autogen files
localAutoGenFileSet = set ()
for aFile in self . _AutoGenObject . AutoGenFileList :
localAutoGenFileSet . add ( str ( aFile ) . lower ())
# Get a set of unique module dependency header files
# Exclude autogen files and files not in the source directory
# and files that are under the package include list
headerFileDependencySet = set ()
localSourceDir = str ( self . _AutoGenObject . SourceDir ) . lower ()
for Dependency in FileDependencyDict . values ():
for aFile in Dependency :
aFileName = str ( aFile ) . lower ()
# Exclude non-header files
if not aFileName . endswith ( '.h' ):
continue
# Exclude autogen files
if aFileName in localAutoGenFileSet :
continue
# Exclude include out of local scope
if localSourceDir not in aFileName :
continue
# Exclude files covered by package includes
pathNeeded = True
for aIncludePath in parentMetaFileIncludes :
if aIncludePath in aFileName :
pathNeeded = False
break
if not pathNeeded :
continue
# Keep the file to be checked
headerFileDependencySet . add ( aFileName )
# Check if a module dependency header file is missing from the module's MetaFile
for aFile in headerFileDependencySet :
if aFile in headerFilesInMetaFileSet :
continue
if GlobalData . gUseHashCache :
GlobalData . gModuleBuildTracking [ self . _AutoGenObject ] = 'FAIL_METAFILE'
EdkLogger . warn ( "build" , "Module MetaFile [Sources] is missing local header!" ,
ExtraData = "Local Header: " + aFile + " not found in " + self . _AutoGenObject . MetaFile . Path
)
for File , Dependency in FileDependencyDict . items ():
if not Dependency :
continue
self . _AutoGenObject . AutoGenDepSet |= set ( Dependency )
CmdSumDict = {}
CmdTargetDict = {}
CmdCppDict = {}
DependencyDict = FileDependencyDict . copy ()
# Convert target description object to target string in makefile
if self . _AutoGenObject . BuildRuleFamily == TAB_COMPILER_MSFT and TAB_C_CODE_FILE in self . _AutoGenObject . Targets :
for T in self . _AutoGenObject . Targets [ TAB_C_CODE_FILE ]:
NewFile = self . PlaceMacro ( str ( T ), self . Macros )
if not self . ObjTargetDict . get ( T . Target . SubDir ):
self . ObjTargetDict [ T . Target . SubDir ] = set ()
self . ObjTargetDict [ T . Target . SubDir ] . add ( NewFile )
for Type in self . _AutoGenObject . Targets :
2021-12-13 09:14:42 -08:00
resp_file_number = 0
2021-11-10 11:36:23 +00:00
for T in self . _AutoGenObject . Targets [ Type ]:
# Generate related macros if needed
if T . GenFileListMacro and T . FileListMacro not in self . FileListMacros :
self . FileListMacros [ T . FileListMacro ] = []
if T . GenListFile and T . ListFileMacro not in self . ListFileMacros :
self . ListFileMacros [ T . ListFileMacro ] = []
if T . GenIncListFile and T . IncListFileMacro not in self . ListFileMacros :
self . ListFileMacros [ T . IncListFileMacro ] = []
Deps = []
CCodeDeps = []
# Add force-dependencies
for Dep in T . Dependencies :
Deps . append ( self . PlaceMacro ( str ( Dep ), self . Macros ))
if Dep != '$(MAKE_FILE)' :
CCodeDeps . append ( self . PlaceMacro ( str ( Dep ), self . Macros ))
# Add inclusion-dependencies
if len ( T . Inputs ) == 1 and T . Inputs [ 0 ] in FileDependencyDict :
for F in FileDependencyDict [ T . Inputs [ 0 ]]:
Deps . append ( self . PlaceMacro ( str ( F ), self . Macros ))
# Add source-dependencies
for F in T . Inputs :
NewFile = self . PlaceMacro ( str ( F ), self . Macros )
# In order to use file list macro as dependency
if T . GenListFile :
# gnu tools need forward slash path separator, even on Windows
self . ListFileMacros [ T . ListFileMacro ] . append ( str ( F ) . replace ( ' \\ ' , '/' ))
self . FileListMacros [ T . FileListMacro ] . append ( NewFile )
elif T . GenFileListMacro :
self . FileListMacros [ T . FileListMacro ] . append ( NewFile )
else :
Deps . append ( NewFile )
for key in self . FileListMacros :
self . FileListMacros [ key ] . sort ()
# Use file list macro as dependency
if T . GenFileListMacro :
Deps . append ( "$( %s )" % T . FileListMacro )
if Type in [ TAB_OBJECT_FILE , TAB_STATIC_LIBRARY ]:
Deps . append ( "$( %s )" % T . ListFileMacro )
if self . _AutoGenObject . BuildRuleFamily == TAB_COMPILER_MSFT and Type == TAB_C_CODE_FILE :
2021-12-13 09:14:42 -08:00
T , CmdTarget , CmdTargetDict , CmdCppDict = self . ParserCCodeFile ( T , Type , CmdSumDict , CmdTargetDict ,
CmdCppDict , DependencyDict , RespFile ,
ToolsDef , resp_file_number )
resp_file_number += 1
2021-11-10 11:36:23 +00:00
TargetDict = { "target" : self . PlaceMacro ( T . Target . Path , self . Macros ), "cmd" : " \n\t " . join ( T . Commands ), "deps" : CCodeDeps }
CmdLine = self . _BUILD_TARGET_TEMPLATE . Replace ( TargetDict ) . rstrip () . replace ( ' \t $(OBJLIST' , '$(OBJLIST' )
if T . Commands :
CmdLine = ' %s%s ' % ( CmdLine , TAB_LINE_BREAK )
if CCodeDeps or CmdLine :
self . BuildTargetList . append ( CmdLine )
else :
TargetDict = { "target" : self . PlaceMacro ( T . Target . Path , self . Macros ), "cmd" : " \n\t " . join ( T . Commands ), "deps" : Deps }
self . BuildTargetList . append ( self . _BUILD_TARGET_TEMPLATE . Replace ( TargetDict ))
# Add a Makefile rule for targets generating multiple files.
# The main output is a prerequisite for the other output files.
for i in T . Outputs [ 1 :]:
AnnexeTargetDict = { "target" : self . PlaceMacro ( i . Path , self . Macros ), "cmd" : "" , "deps" : self . PlaceMacro ( T . Target . Path , self . Macros )}
self . BuildTargetList . append ( self . _BUILD_TARGET_TEMPLATE . Replace ( AnnexeTargetDict ))
2021-12-13 09:14:42 -08:00
def ParserCCodeFile ( self , T , Type , CmdSumDict , CmdTargetDict , CmdCppDict , DependencyDict , RespFile , ToolsDef ,
resp_file_number ):
SaveFilePath = os . path . join ( RespFile , "cc_resp_ %s .txt" % resp_file_number )
2021-11-10 11:36:23 +00:00
if not CmdSumDict :
for item in self . _AutoGenObject . Targets [ Type ]:
CmdSumDict [ item . Target . SubDir ] = item . Target . BaseName
for CppPath in item . Inputs :
Path = self . PlaceMacro ( CppPath . Path , self . Macros )
if CmdCppDict . get ( item . Target . SubDir ):
CmdCppDict [ item . Target . SubDir ] . append ( Path )
else :
CmdCppDict [ item . Target . SubDir ] = [ '$(MAKE_FILE)' , Path ]
if CppPath . Path in DependencyDict :
for Temp in DependencyDict [ CppPath . Path ]:
try :
Path = self . PlaceMacro ( Temp . Path , self . Macros )
except :
continue
if Path not in ( self . CommonFileDependency + CmdCppDict [ item . Target . SubDir ]):
CmdCppDict [ item . Target . SubDir ] . append ( Path )
if T . Commands :
CommandList = T . Commands [:]
for Item in CommandList [:]:
SingleCommandList = Item . split ()
if len ( SingleCommandList ) > 0 and self . CheckCCCmd ( SingleCommandList ):
for Temp in SingleCommandList :
if Temp . startswith ( '/Fo' ):
CmdSign = ' %s%s ' % ( Temp . rsplit ( TAB_SLASH , 1 )[ 0 ], TAB_SLASH )
break
else :
2021-12-13 09:14:42 -08:00
continue
if CmdSign not in list ( CmdTargetDict . keys ()):
cmd = Item . replace ( Temp , CmdSign )
if SingleCommandList [ - 1 ] in cmd :
CmdTargetDict [ CmdSign ] = [ cmd . replace ( SingleCommandList [ - 1 ], "" ) . rstrip (), SingleCommandList [ - 1 ]]
else :
# CmdTargetDict[CmdSign] = "%s %s" % (CmdTargetDict[CmdSign], SingleCommandList[-1])
CmdTargetDict [ CmdSign ] . append ( SingleCommandList [ - 1 ])
2021-11-10 11:36:23 +00:00
Index = CommandList . index ( Item )
CommandList . pop ( Index )
if SingleCommandList [ - 1 ] . endswith ( " %s%s .c" % ( TAB_SLASH , CmdSumDict [ CmdSign [ 3 :] . rsplit ( TAB_SLASH , 1 )[ 0 ]])):
Cpplist = CmdCppDict [ T . Target . SubDir ]
Cpplist . insert ( 0 , '$(OBJLIST_ %d ): ' % list ( self . ObjTargetDict . keys ()) . index ( T . Target . SubDir ))
2021-12-13 09:14:42 -08:00
source_files = CmdTargetDict [ CmdSign ][ 1 :]
source_files . insert ( 0 , " " )
if len ( source_files ) > 2 :
SaveFileOnChange ( SaveFilePath , " " . join ( source_files ), False )
T . Commands [ Index ] = ' %s \n\t %s $(cc_resp_ %s )' % (
' \\\n\t ' . join ( Cpplist ), CmdTargetDict [ CmdSign ][ 0 ], resp_file_number )
ToolsDef . append ( "cc_resp_ %s = @ %s " % ( resp_file_number , SaveFilePath ))
elif len ( source_files ) <= 2 and len ( " " . join ( CmdTargetDict [ CmdSign ][: 2 ])) > GlobalData . gCommandMaxLength :
SaveFileOnChange ( SaveFilePath , " " . join ( source_files ), False )
T . Commands [ Index ] = ' %s \n\t %s $(cc_resp_ %s )' % (
' \\\n\t ' . join ( Cpplist ), CmdTargetDict [ CmdSign ][ 0 ], resp_file_number )
ToolsDef . append ( "cc_resp_ %s = @ %s " % ( resp_file_number , SaveFilePath ))
else :
T . Commands [ Index ] = ' %s \n\t %s ' % ( ' \\\n\t ' . join ( Cpplist ), " " . join ( CmdTargetDict [ CmdSign ]))
2021-11-10 11:36:23 +00:00
else :
T . Commands . pop ( Index )
return T , CmdSumDict , CmdTargetDict , CmdCppDict
def CheckCCCmd ( self , CommandList ):
for cmd in CommandList :
if '$(CC)' in cmd :
return True
return False
## For creating makefile targets for dependent libraries
def ProcessDependentLibrary ( self ):
for LibraryAutoGen in self . _AutoGenObject . LibraryAutoGenList :
if not LibraryAutoGen . IsBinaryModule :
self . LibraryBuildDirectoryList . append ( self . PlaceMacro ( LibraryAutoGen . BuildDir , self . Macros ))
## Return a list containing source file's dependencies
#
# @param FileList The list of source files
# @param ForceInculeList The list of files which will be included forcely
# @param SearchPathList The list of search path
#
# @retval dict The mapping between source file path and its dependencies
#
def GetFileDependency ( self , FileList , ForceInculeList , SearchPathList ):
Dependency = {}
for F in FileList :
Dependency [ F ] = GetDependencyList ( self . _AutoGenObject , self . FileCache , F , ForceInculeList , SearchPathList )
return Dependency
## CustomMakefile class
#
# This class encapsules makefie and its generation for module. It uses template to generate
# the content of makefile. The content of makefile will be got from ModuleAutoGen object.
#
class CustomMakefile ( BuildFile ):
## template used to generate the makefile for module with custom makefile
_TEMPLATE_ = TemplateString ( ''' \
$ {makefile_header}
#
# Platform Macro Definition
#
PLATFORM_NAME = $ {platform_name}
PLATFORM_GUID = $ {platform_guid}
PLATFORM_VERSION = $ {platform_version}
PLATFORM_RELATIVE_DIR = $ {platform_relative_directory}
PLATFORM_DIR = $ {platform_dir}
PLATFORM_OUTPUT_DIR = $ {platform_output_directory}
#
# Module Macro Definition
#
MODULE_NAME = $ {module_name}
MODULE_GUID = $ {module_guid}
MODULE_NAME_GUID = $ {module_name_guid}
MODULE_VERSION = $ {module_version}
MODULE_TYPE = $ {module_type}
MODULE_FILE = $ {module_file}
MODULE_FILE_BASE_NAME = $ {module_file_base_name}
BASE_NAME = $(MODULE_NAME)
MODULE_RELATIVE_DIR = $ {module_relative_directory}
MODULE_DIR = $ {module_dir}
#
# Build Configuration Macro Definition
#
ARCH = $ {architecture}
TOOLCHAIN = $ {toolchain_tag}
TOOLCHAIN_TAG = $ {toolchain_tag}
TARGET = $ {build_target}
#
# Build Directory Macro Definition
#
# PLATFORM_BUILD_DIR = $ {platform_build_directory}
BUILD_DIR = $ {platform_build_directory}
BIN_DIR = $(BUILD_DIR)$ {separator} $ {architecture}
LIB_DIR = $(BIN_DIR)
MODULE_BUILD_DIR = $ {module_build_directory}
OUTPUT_DIR = $ {module_output_directory}
DEBUG_DIR = $ {module_debug_directory}
DEST_DIR_OUTPUT = $(OUTPUT_DIR)
DEST_DIR_DEBUG = $(DEBUG_DIR)
#
# Tools definitions specific to this module
#
$ {BEGIN} $ {module_tool_definitions}
$ {END}
MAKE_FILE = $ {makefile_path}
#
# Shell Command Macro
#
$ {BEGIN} $ {shell_command_code} = $ {shell_command}
$ {END}
$ {custom_makefile_content}
#
# Target used when called from platform makefile, which will bypass the build of dependent libraries
#
pbuild: init all
#
# ModuleTarget
#
mbuild: init all
#
# Build Target used in multi-thread build mode, which no init target is needed
#
tbuild: all
#
# Initialization target: print build information and create necessary directories
#
init:
\t -@echo Building ... $(MODULE_DIR)$ {separator} $(MODULE_FILE) [$(ARCH)]
$ {BEGIN} \t -@$ {create_directory_command} \n $ {END} \
''' )
## Constructor of CustomMakefile
#
# @param ModuleAutoGen Object of ModuleAutoGen class
#
def __init__ ( self , ModuleAutoGen ):
BuildFile . __init__ ( self , ModuleAutoGen )
self . PlatformInfo = self . _AutoGenObject . PlatformInfo
self . IntermediateDirectoryList = [ "$(DEBUG_DIR)" , "$(OUTPUT_DIR)" ]
self . DependencyHeaderFileSet = set ()
# Compose a dict object containing information used to do replacement in template
@property
def _TemplateDict ( self ):
Separator = self . _SEP_ [ self . _Platform ]
MyAgo = self . _AutoGenObject
if self . _FileType not in MyAgo . CustomMakefile :
EdkLogger . error ( 'build' , OPTION_NOT_SUPPORTED , "No custom makefile for %s " % self . _FileType ,
ExtraData = "[ %s ]" % str ( MyAgo ))
MakefilePath = mws . join (
MyAgo . WorkspaceDir ,
MyAgo . CustomMakefile [ self . _FileType ]
)
try :
CustomMakefile = open ( MakefilePath , 'r' ) . read ()
except :
EdkLogger . error ( 'build' , FILE_OPEN_FAILURE , File = str ( MyAgo ),
ExtraData = MyAgo . CustomMakefile [ self . _FileType ])
# tools definitions
ToolsDef = []
for Tool in MyAgo . BuildOption :
# Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
if Tool == "MAKE" :
continue
for Attr in MyAgo . BuildOption [ Tool ]:
if Attr == "FAMILY" :
continue
elif Attr == "PATH" :
ToolsDef . append ( " %s = %s " % ( Tool , MyAgo . BuildOption [ Tool ][ Attr ]))
else :
ToolsDef . append ( " %s _ %s = %s " % ( Tool , Attr , MyAgo . BuildOption [ Tool ][ Attr ]))
ToolsDef . append ( "" )
MakefileName = self . getMakefileName ()
MakefileTemplateDict = {
"makefile_header" : self . _FILE_HEADER_ [ self . _FileType ],
"makefile_path" : os . path . join ( "$(MODULE_BUILD_DIR)" , MakefileName ),
"platform_name" : self . PlatformInfo . Name ,
"platform_guid" : self . PlatformInfo . Guid ,
"platform_version" : self . PlatformInfo . Version ,
"platform_relative_directory" : self . PlatformInfo . SourceDir ,
"platform_output_directory" : self . PlatformInfo . OutputDir ,
"platform_dir" : MyAgo . Macros [ "PLATFORM_DIR" ],
"module_name" : MyAgo . Name ,
"module_guid" : MyAgo . Guid ,
"module_name_guid" : MyAgo . UniqueBaseName ,
"module_version" : MyAgo . Version ,
"module_type" : MyAgo . ModuleType ,
"module_file" : MyAgo . MetaFile ,
"module_file_base_name" : MyAgo . MetaFile . BaseName ,
"module_relative_directory" : MyAgo . SourceDir ,
"module_dir" : mws . join ( MyAgo . WorkspaceDir , MyAgo . SourceDir ),
"architecture" : MyAgo . Arch ,
"toolchain_tag" : MyAgo . ToolChain ,
"build_target" : MyAgo . BuildTarget ,
"platform_build_directory" : self . PlatformInfo . BuildDir ,
"module_build_directory" : MyAgo . BuildDir ,
"module_output_directory" : MyAgo . OutputDir ,
"module_debug_directory" : MyAgo . DebugDir ,
"separator" : Separator ,
"module_tool_definitions" : ToolsDef ,
"shell_command_code" : list ( self . _SHELL_CMD_ [ self . _Platform ] . keys ()),
"shell_command" : list ( self . _SHELL_CMD_ [ self . _Platform ] . values ()),
"create_directory_command" : self . GetCreateDirectoryCommand ( self . IntermediateDirectoryList ),
"custom_makefile_content" : CustomMakefile
}
return MakefileTemplateDict
## PlatformMakefile class
#
# This class encapsules makefie and its generation for platform. It uses
# template to generate the content of makefile. The content of makefile will be
# got from PlatformAutoGen object.
#
class PlatformMakefile ( BuildFile ):
## template used to generate the makefile for platform
_TEMPLATE_ = TemplateString ( ''' \
$ {makefile_header}
#
# Platform Macro Definition
#
PLATFORM_NAME = $ {platform_name}
PLATFORM_GUID = $ {platform_guid}
PLATFORM_VERSION = $ {platform_version}
PLATFORM_FILE = $ {platform_file}
PLATFORM_DIR = $ {platform_dir}
PLATFORM_OUTPUT_DIR = $ {platform_output_directory}
#
# Build Configuration Macro Definition
#
TOOLCHAIN = $ {toolchain_tag}
TOOLCHAIN_TAG = $ {toolchain_tag}
TARGET = $ {build_target}
#
# Build Directory Macro Definition
#
BUILD_DIR = $ {platform_build_directory}
FV_DIR = $ {platform_build_directory} $ {separator} FV
#
# Shell Command Macro
#
$ {BEGIN} $ {shell_command_code} = $ {shell_command}
$ {END}
MAKE = $ {make_path}
MAKE_FILE = $ {makefile_path}
#
# Default target
#
all: init build_libraries build_modules
#
# Initialization target: print build information and create necessary directories
#
init:
\t -@echo Building ... $(PLATFORM_FILE) [$ {build_architecture_list} ]
\t $ {BEGIN} -@$ {create_directory_command}
\t $ {END}
#
# library build target
#
libraries: init build_libraries
#
# module build target
#
modules: init build_libraries build_modules
#
# Build all libraries:
#
build_libraries:
$ {BEGIN} \t @"$(MAKE)" $(MAKE_FLAGS) -f $ {library_makefile_list} pbuild
$ {END} \t @cd $(BUILD_DIR)
#
# Build all modules:
#
build_modules:
$ {BEGIN} \t @"$(MAKE)" $(MAKE_FLAGS) -f $ {module_makefile_list} pbuild
$ {END} \t @cd $(BUILD_DIR)
#
# Clean intermediate files
#
clean:
\t $ {BEGIN} -@$ {library_build_command} clean
\t $ {END} $ {BEGIN} -@$ {module_build_command} clean
\t $ {END} @cd $(BUILD_DIR)
#
# Clean all generated files except to makefile
#
cleanall:
$ {BEGIN} \t $ {cleanall_command}
$ {END}
#
# Clean all library files
#
cleanlib:
\t $ {BEGIN} -@$ {library_build_command} cleanall
\t $ {END} @cd $(BUILD_DIR) \n
''' )
## Constructor of PlatformMakefile
#
# @param ModuleAutoGen Object of PlatformAutoGen class
#
def __init__ ( self , PlatformAutoGen ):
BuildFile . __init__ ( self , PlatformAutoGen )
self . ModuleBuildCommandList = []
self . ModuleMakefileList = []
self . IntermediateDirectoryList = []
self . ModuleBuildDirectoryList = []
self . LibraryBuildDirectoryList = []
self . LibraryMakeCommandList = []
self . DependencyHeaderFileSet = set ()
# Compose a dict object containing information used to do replacement in template
@property
def _TemplateDict ( self ):
Separator = self . _SEP_ [ self . _Platform ]
MyAgo = self . _AutoGenObject
if "MAKE" not in MyAgo . ToolDefinition or "PATH" not in MyAgo . ToolDefinition [ "MAKE" ]:
EdkLogger . error ( "build" , OPTION_MISSING , "No MAKE command defined. Please check your tools_def.txt!" ,
ExtraData = "[ %s ]" % str ( MyAgo ))
self . IntermediateDirectoryList = [ "$(BUILD_DIR)" ]
self . ModuleBuildDirectoryList = self . GetModuleBuildDirectoryList ()
self . LibraryBuildDirectoryList = self . GetLibraryBuildDirectoryList ()
MakefileName = self . getMakefileName ()
LibraryMakefileList = []
LibraryMakeCommandList = []
for D in self . LibraryBuildDirectoryList :
D = self . PlaceMacro ( D , { "BUILD_DIR" : MyAgo . BuildDir })
Makefile = os . path . join ( D , MakefileName )
Command = self . _MAKE_TEMPLATE_ [ self . _Platform ] % { "file" : Makefile }
LibraryMakefileList . append ( Makefile )
LibraryMakeCommandList . append ( Command )
self . LibraryMakeCommandList = LibraryMakeCommandList
ModuleMakefileList = []
ModuleMakeCommandList = []
for D in self . ModuleBuildDirectoryList :
D = self . PlaceMacro ( D , { "BUILD_DIR" : MyAgo . BuildDir })
Makefile = os . path . join ( D , MakefileName )
Command = self . _MAKE_TEMPLATE_ [ self . _Platform ] % { "file" : Makefile }
ModuleMakefileList . append ( Makefile )
ModuleMakeCommandList . append ( Command )
MakefileTemplateDict = {
"makefile_header" : self . _FILE_HEADER_ [ self . _FileType ],
"makefile_path" : os . path . join ( "$(BUILD_DIR)" , MakefileName ),
"make_path" : MyAgo . ToolDefinition [ "MAKE" ][ "PATH" ],
"makefile_name" : MakefileName ,
"platform_name" : MyAgo . Name ,
"platform_guid" : MyAgo . Guid ,
"platform_version" : MyAgo . Version ,
"platform_file" : MyAgo . MetaFile ,
"platform_relative_directory" : MyAgo . SourceDir ,
"platform_output_directory" : MyAgo . OutputDir ,
"platform_build_directory" : MyAgo . BuildDir ,
"platform_dir" : MyAgo . Macros [ "PLATFORM_DIR" ],
"toolchain_tag" : MyAgo . ToolChain ,
"build_target" : MyAgo . BuildTarget ,
"shell_command_code" : list ( self . _SHELL_CMD_ [ self . _Platform ] . keys ()),
"shell_command" : list ( self . _SHELL_CMD_ [ self . _Platform ] . values ()),
"build_architecture_list" : MyAgo . Arch ,
"architecture" : MyAgo . Arch ,
"separator" : Separator ,
"create_directory_command" : self . GetCreateDirectoryCommand ( self . IntermediateDirectoryList ),
"cleanall_command" : self . GetRemoveDirectoryCommand ( self . IntermediateDirectoryList ),
"library_makefile_list" : LibraryMakefileList ,
"module_makefile_list" : ModuleMakefileList ,
"library_build_command" : LibraryMakeCommandList ,
"module_build_command" : ModuleMakeCommandList ,
}
return MakefileTemplateDict
## Get the root directory list for intermediate files of all modules build
#
# @retval list The list of directory
#
def GetModuleBuildDirectoryList ( self ):
DirList = []
for ModuleAutoGen in self . _AutoGenObject . ModuleAutoGenList :
if not ModuleAutoGen . IsBinaryModule :
DirList . append ( os . path . join ( self . _AutoGenObject . BuildDir , ModuleAutoGen . BuildDir ))
return DirList
## Get the root directory list for intermediate files of all libraries build
#
# @retval list The list of directory
#
def GetLibraryBuildDirectoryList ( self ):
DirList = []
for LibraryAutoGen in self . _AutoGenObject . LibraryAutoGenList :
if not LibraryAutoGen . IsBinaryModule :
DirList . append ( os . path . join ( self . _AutoGenObject . BuildDir , LibraryAutoGen . BuildDir ))
return DirList
## TopLevelMakefile class
#
# This class encapsules makefie and its generation for entrance makefile. It
# uses template to generate the content of makefile. The content of makefile
# will be got from WorkspaceAutoGen object.
#
class TopLevelMakefile ( BuildFile ):
## template used to generate toplevel makefile
_TEMPLATE_ = TemplateString ( '''$ {BEGIN} \t GenFds -f $ {fdf_file} --conf=$ {conf_directory} -o $ {platform_build_directory} -t $ {toolchain_tag} -b $ {build_target} -p $ {active_platform} -a $ {build_architecture_list} $ {extra_options} $ {END} $ {BEGIN} -r $ {fd} $ {END} $ {BEGIN} -i $ {fv} $ {END} $ {BEGIN} -C $ {cap} $ {END} $ {BEGIN} -D $ {macro} $ {END} ''' )
## Constructor of TopLevelMakefile
#
# @param Workspace Object of WorkspaceAutoGen class
#
def __init__ ( self , Workspace ):
BuildFile . __init__ ( self , Workspace )
self . IntermediateDirectoryList = []
self . DependencyHeaderFileSet = set ()
# Compose a dict object containing information used to do replacement in template
@property
def _TemplateDict ( self ):
Separator = self . _SEP_ [ self . _Platform ]
# any platform autogen object is ok because we just need common information
MyAgo = self . _AutoGenObject
if "MAKE" not in MyAgo . ToolDefinition or "PATH" not in MyAgo . ToolDefinition [ "MAKE" ]:
EdkLogger . error ( "build" , OPTION_MISSING , "No MAKE command defined. Please check your tools_def.txt!" ,
ExtraData = "[ %s ]" % str ( MyAgo ))
for Arch in MyAgo . ArchList :
self . IntermediateDirectoryList . append ( Separator . join ([ "$(BUILD_DIR)" , Arch ]))
self . IntermediateDirectoryList . append ( "$(FV_DIR)" )
# TRICK: for not generating GenFds call in makefile if no FDF file
MacroList = []
if MyAgo . FdfFile is not None and MyAgo . FdfFile != "" :
FdfFileList = [ MyAgo . FdfFile ]
# macros passed to GenFds
MacroDict = {}
MacroDict . update ( GlobalData . gGlobalDefines )
MacroDict . update ( GlobalData . gCommandLineDefines )
for MacroName in MacroDict :
if MacroDict [ MacroName ] != "" :
MacroList . append ( '" %s = %s "' % ( MacroName , MacroDict [ MacroName ] . replace ( ' \\ ' , ' \\\\ ' )))
else :
MacroList . append ( '" %s "' % MacroName )
else :
FdfFileList = []
# pass extra common options to external program called in makefile, currently GenFds.exe
ExtraOption = ''
LogLevel = EdkLogger . GetLevel ()
if LogLevel == EdkLogger . VERBOSE :
ExtraOption += " -v"
elif LogLevel <= EdkLogger . DEBUG_9 :
ExtraOption += " -d %d " % ( LogLevel - 1 )
elif LogLevel == EdkLogger . QUIET :
ExtraOption += " -q"
if GlobalData . gCaseInsensitive :
ExtraOption += " -c"
if not GlobalData . gEnableGenfdsMultiThread :
ExtraOption += " --no-genfds-multi-thread"
if GlobalData . gIgnoreSource :
ExtraOption += " --ignore-sources"
for pcd in GlobalData . BuildOptionPcd :
if pcd [ 2 ]:
pcdname = '.' . join ( pcd [ 0 : 3 ])
else :
pcdname = '.' . join ( pcd [ 0 : 2 ])
if pcd [ 3 ] . startswith ( '{' ):
ExtraOption += " --pcd " + pcdname + '=' + 'H' + '"' + pcd [ 3 ] + '"'
else :
ExtraOption += " --pcd " + pcdname + '=' + pcd [ 3 ]
MakefileName = self . getMakefileName ()
SubBuildCommandList = []
for A in MyAgo . ArchList :
Command = self . _MAKE_TEMPLATE_ [ self . _Platform ] % { "file" : os . path . join ( "$(BUILD_DIR)" , A , MakefileName )}
SubBuildCommandList . append ( Command )
MakefileTemplateDict = {
"makefile_header" : self . _FILE_HEADER_ [ self . _FileType ],
"makefile_path" : os . path . join ( "$(BUILD_DIR)" , MakefileName ),
"make_path" : MyAgo . ToolDefinition [ "MAKE" ][ "PATH" ],
"platform_name" : MyAgo . Name ,
"platform_guid" : MyAgo . Guid ,
"platform_version" : MyAgo . Version ,
"platform_build_directory" : MyAgo . BuildDir ,
"conf_directory" : GlobalData . gConfDirectory ,
"toolchain_tag" : MyAgo . ToolChain ,
"build_target" : MyAgo . BuildTarget ,
"shell_command_code" : list ( self . _SHELL_CMD_ [ self . _Platform ] . keys ()),
"shell_command" : list ( self . _SHELL_CMD_ [ self . _Platform ] . values ()),
'arch' : list ( MyAgo . ArchList ),
"build_architecture_list" : ',' . join ( MyAgo . ArchList ),
"separator" : Separator ,
"create_directory_command" : self . GetCreateDirectoryCommand ( self . IntermediateDirectoryList ),
"cleanall_command" : self . GetRemoveDirectoryCommand ( self . IntermediateDirectoryList ),
"sub_build_command" : SubBuildCommandList ,
"fdf_file" : FdfFileList ,
"active_platform" : str ( MyAgo ),
"fd" : MyAgo . FdTargetList ,
"fv" : MyAgo . FvTargetList ,
"cap" : MyAgo . CapTargetList ,
"extra_options" : ExtraOption ,
"macro" : MacroList ,
}
return MakefileTemplateDict
## Get the root directory list for intermediate files of all modules build
#
# @retval list The list of directory
#
def GetModuleBuildDirectoryList ( self ):
DirList = []
for ModuleAutoGen in self . _AutoGenObject . ModuleAutoGenList :
if not ModuleAutoGen . IsBinaryModule :
DirList . append ( os . path . join ( self . _AutoGenObject . BuildDir , ModuleAutoGen . BuildDir ))
return DirList
## Get the root directory list for intermediate files of all libraries build
#
# @retval list The list of directory
#
def GetLibraryBuildDirectoryList ( self ):
DirList = []
for LibraryAutoGen in self . _AutoGenObject . LibraryAutoGenList :
if not LibraryAutoGen . IsBinaryModule :
DirList . append ( os . path . join ( self . _AutoGenObject . BuildDir , LibraryAutoGen . BuildDir ))
return DirList
## Find dependencies for one source file
#
# By searching recursively "#include" directive in file, find out all the
# files needed by given source file. The dependencies will be only searched
# in given search path list.
#
# @param File The source file
# @param ForceInculeList The list of files which will be included forcely
# @param SearchPathList The list of search path
#
# @retval list The list of files the given source file depends on
#
def GetDependencyList ( AutoGenObject , FileCache , File , ForceList , SearchPathList ):
EdkLogger . debug ( EdkLogger . DEBUG_1 , "Try to get dependency files for %s " % File )
FileStack = [ File ] + ForceList
DependencySet = set ()
if AutoGenObject . Arch not in gDependencyDatabase :
gDependencyDatabase [ AutoGenObject . Arch ] = {}
DepDb = gDependencyDatabase [ AutoGenObject . Arch ]
while len ( FileStack ) > 0 :
F = FileStack . pop ()
FullPathDependList = []
if F in FileCache :
for CacheFile in FileCache [ F ]:
FullPathDependList . append ( CacheFile )
if CacheFile not in DependencySet :
FileStack . append ( CacheFile )
DependencySet . update ( FullPathDependList )
continue
CurrentFileDependencyList = []
if F in DepDb :
CurrentFileDependencyList = DepDb [ F ]
else :
try :
Fd = open ( F . Path , 'rb' )
FileContent = Fd . read ()
Fd . close ()
except BaseException as X :
EdkLogger . error ( "build" , FILE_OPEN_FAILURE , ExtraData = F . Path + " \n\t " + str ( X ))
if len ( FileContent ) == 0 :
continue
try :
if FileContent [ 0 ] == 0xff or FileContent [ 0 ] == 0xfe :
FileContent = FileContent . decode ( 'utf-16' )
else :
FileContent = FileContent . decode ()
except :
# The file is not txt file. for example .mcb file
continue
IncludedFileList = gIncludePattern . findall ( FileContent )
for Inc in IncludedFileList :
Inc = Inc . strip ()
# if there's macro used to reference header file, expand it
HeaderList = gMacroPattern . findall ( Inc )
if len ( HeaderList ) == 1 and len ( HeaderList [ 0 ]) == 2 :
HeaderType = HeaderList [ 0 ][ 0 ]
HeaderKey = HeaderList [ 0 ][ 1 ]
if HeaderType in gIncludeMacroConversion :
Inc = gIncludeMacroConversion [ HeaderType ] % { "HeaderKey" : HeaderKey }
else :
# not known macro used in #include, always build the file by
# returning a empty dependency
FileCache [ File ] = []
return []
Inc = os . path . normpath ( Inc )
CurrentFileDependencyList . append ( Inc )
DepDb [ F ] = CurrentFileDependencyList
CurrentFilePath = F . Dir
PathList = [ CurrentFilePath ] + SearchPathList
for Inc in CurrentFileDependencyList :
for SearchPath in PathList :
FilePath = os . path . join ( SearchPath , Inc )
if FilePath in gIsFileMap :
if not gIsFileMap [ FilePath ]:
continue
# If isfile is called too many times, the performance is slow down.
elif not os . path . isfile ( FilePath ):
gIsFileMap [ FilePath ] = False
continue
else :
gIsFileMap [ FilePath ] = True
FilePath = PathClass ( FilePath )
FullPathDependList . append ( FilePath )
if FilePath not in DependencySet :
FileStack . append ( FilePath )
break
else :
EdkLogger . debug ( EdkLogger . DEBUG_9 , " %s included by %s was not found " \
"in any given path: \n\t %s " % ( Inc , F , " \n\t " . join ( SearchPathList )))
FileCache [ F ] = FullPathDependList
DependencySet . update ( FullPathDependList )
DependencySet . update ( ForceList )
if File in DependencySet :
DependencySet . remove ( File )
DependencyList = list ( DependencySet ) # remove duplicate ones
return DependencyList
# This acts like the main() function for the script, unless it is 'import'ed into another script.
if __name__ == '__main__' :
pass