mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-24 11:45:27 +01:00
1796 lines
75 KiB
Python
Executable File
1796 lines
75 KiB
Python
Executable File
## @file
|
|
# Create makefile for MS nmake and GNU make
|
|
#
|
|
# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
# 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,
|
|
}
|
|
|
|
## default makefile type
|
|
gMakeType = ""
|
|
if sys.platform == "win32":
|
|
gMakeType = "nmake"
|
|
else:
|
|
gMakeType = "gmake"
|
|
|
|
|
|
## 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" : "Makefile",
|
|
"gmake" : "GNUmakefile"
|
|
}
|
|
|
|
## 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" : _MAKEFILE_HEADER % _FILE_NAME_["nmake"],
|
|
"gmake" : _MAKEFILE_HEADER % _FILE_NAME_["gmake"]
|
|
}
|
|
|
|
## 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_ = {
|
|
"nmake" : {
|
|
"CP" : "copy /y",
|
|
"MV" : "move /y",
|
|
"RM" : "del /f /q",
|
|
"MD" : "mkdir",
|
|
"RD" : "rmdir /s /q",
|
|
},
|
|
|
|
"gmake" : {
|
|
"CP" : "cp -f",
|
|
"MV" : "mv -f",
|
|
"RM" : "rm -f",
|
|
"MD" : "mkdir -p",
|
|
"RD" : "rm -r -f",
|
|
}
|
|
}
|
|
|
|
## directory separator
|
|
_SEP_ = {
|
|
"nmake" : "\\",
|
|
"gmake" : "/"
|
|
}
|
|
|
|
## directory creation template
|
|
_MD_TEMPLATE_ = {
|
|
"nmake" : '$(AT)if not exist %(dir)s $(MD) %(dir)s',
|
|
"gmake" : "$(AT)$(MD) %(dir)s"
|
|
}
|
|
|
|
## directory removal template
|
|
_RD_TEMPLATE_ = {
|
|
"nmake" : '$(AT)if exist %(dir)s $(RD) %(dir)s',
|
|
"gmake" : "$(AT)$(RD) %(dir)s"
|
|
}
|
|
## cp if exist
|
|
_CP_TEMPLATE_ = {
|
|
"nmake" : '$(AT)if exist %(Src)s $(CP) %(Src)s %(Dst)s',
|
|
"gmake" : "$(AT)test -f %(Src)s && $(CP) %(Src)s %(Dst)s"
|
|
}
|
|
|
|
_CD_TEMPLATE_ = {
|
|
"nmake" : '$(AT)if exist %(dir)s cd %(dir)s',
|
|
"gmake" : "$(AT)test -e %(dir)s && cd %(dir)s"
|
|
}
|
|
|
|
_MAKE_TEMPLATE_ = {
|
|
"nmake" : '$(AT)if exist %(file)s "$(MAKE)" $(MAKE_FLAGS) -f %(file)s',
|
|
"gmake" : '$(AT)test -e %(file)s && "$(MAKE)" $(MAKE_FLAGS) -f %(file)s'
|
|
}
|
|
|
|
_INCLUDE_CMD_ = {
|
|
"nmake" : '!INCLUDE',
|
|
"gmake" : "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
|
|
self._FileType = gMakeType
|
|
|
|
## Create build file
|
|
#
|
|
# @param FileType Type of build file. Only nmake and gmake are supported now.
|
|
#
|
|
# @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, FileType=gMakeType):
|
|
if FileType not in self._FILE_NAME_:
|
|
EdkLogger.error("build", PARAMETER_INVALID, "Invalid build type [%s]" % FileType,
|
|
ExtraData="[%s]" % str(self._AutoGenObject))
|
|
self._FileType = FileType
|
|
FileContent = self._TEMPLATE_.Replace(self._TemplateDict)
|
|
FileName = self._FILE_NAME_[FileType]
|
|
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._FileType] % {'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._FileType] % {'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
|
|
TemplStr = '''\
|
|
${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}
|
|
|
|
COMMON_DEPS = ${BEGIN}${common_dependency_file} \\
|
|
${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)
|
|
|
|
#
|
|
# 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'''
|
|
|
|
if sys.platform == "win32":
|
|
_TEMPLATE_ = TemplateString('''
|
|
AT = @
|
|
!IF defined(V) && "$(V)" != "0"
|
|
AT =
|
|
!ENDIF
|
|
|
|
''' + TemplStr)
|
|
|
|
else:
|
|
_TEMPLATE_ = TemplateString('''
|
|
#Verbose
|
|
AT_ = @
|
|
AT_0 = @
|
|
AT_1 =
|
|
AT = $(AT_$(V))
|
|
|
|
''' + TemplStr)
|
|
|
|
|
|
_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):
|
|
if self._FileType not in self._SEP_:
|
|
EdkLogger.error("build", PARAMETER_INVALID, "Invalid Makefile type [%s]" % self._FileType,
|
|
ExtraData="[%s]" % str(self._AutoGenObject))
|
|
MyAgo = self._AutoGenObject
|
|
Separator = self._SEP_[self._FileType]
|
|
|
|
# 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]
|
|
for Tool in MyAgo.BuildOption:
|
|
for Attr in MyAgo.BuildOption[Tool]:
|
|
Value = MyAgo.BuildOption[Tool][Attr]
|
|
if Attr == "FAMILY":
|
|
continue
|
|
elif Attr == "PATH":
|
|
ToolsDef.append("%s = %s" % (Tool, Value))
|
|
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 self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Tool == 'CC' and '/GM' in Value:
|
|
Value = Value.replace(' /MP', '')
|
|
MyAgo.BuildOption[Tool][Attr] = Value
|
|
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))
|
|
ToolsDef.append("")
|
|
|
|
# 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:
|
|
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))
|
|
|
|
self.ProcessBuildTargetList()
|
|
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
|
|
for File in self.FileCache.keys():
|
|
if not str(File).endswith('.nasm'):
|
|
continue
|
|
IncludePathList = []
|
|
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
|
|
# To specify a literal backslash at the end of the line, precede it with a caret (^)
|
|
if P == MyAgo.IncludePathList[-1] and os.sep == '\\':
|
|
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}))
|
|
break
|
|
|
|
# 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._FILE_NAME_[self._FileType]
|
|
LibraryMakeCommandList = []
|
|
for D in self.LibraryBuildDirectoryList:
|
|
Command = self._MAKE_TEMPLATE_[self._FileType] % {"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])
|
|
try:
|
|
for fl in os.listdir(current_dir):
|
|
if fl.endswith('.dec'):
|
|
found = True
|
|
break
|
|
except:
|
|
EdkLogger.error('build', FILE_NOT_FOUND, "WORKSPACE does not exist.")
|
|
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._FileType].keys()),
|
|
"shell_command" : list(self._SHELL_CMD_[self._FileType].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,
|
|
}
|
|
|
|
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 :" %(Dst))
|
|
self.BuildTargetList.append('\t' + self._CP_TEMPLATE_[self._FileType] %{'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$(AT)%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$(AT)%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:
|
|
if self._AutoGenObject.Macros[Macro] and self._AutoGenObject.Macros[Macro] in str:
|
|
str = str.replace(self._AutoGenObject.Macros[Macro], '$(' + Macro + ')')
|
|
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
|
|
|
|
def ProcessBuildTargetList(self):
|
|
#
|
|
# 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 = self.GetFileDependency(
|
|
SourceFileList,
|
|
ForceIncludedFile,
|
|
self._AutoGenObject.IncludePathList + self._AutoGenObject.BuildOptionIncPathList
|
|
)
|
|
|
|
if FileDependencyDict:
|
|
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
|
|
)
|
|
|
|
DepSet = None
|
|
for File,Dependency in FileDependencyDict.items():
|
|
if not Dependency:
|
|
FileDependencyDict[File] = ['$(FORCE_REBUILD)']
|
|
continue
|
|
|
|
self._AutoGenObject.AutoGenDepSet |= set(Dependency)
|
|
|
|
# skip non-C files
|
|
if File.Ext not in [".c", ".C"] or File.Name == "AutoGen.c":
|
|
continue
|
|
elif DepSet is None:
|
|
DepSet = set(Dependency)
|
|
else:
|
|
DepSet &= set(Dependency)
|
|
# in case nothing in SourceFileList
|
|
if DepSet is None:
|
|
DepSet = set()
|
|
#
|
|
# Extract common files list in the dependency files
|
|
#
|
|
for File in DepSet:
|
|
self.CommonFileDependency.append(self.PlaceMacro(File.Path, self.Macros))
|
|
|
|
CmdSumDict = {}
|
|
CmdTargetDict = {}
|
|
CmdCppDict = {}
|
|
DependencyDict = FileDependencyDict.copy()
|
|
for File in FileDependencyDict:
|
|
# skip non-C files
|
|
if File.Ext not in [".c", ".C"] or File.Name == "AutoGen.c":
|
|
continue
|
|
NewDepSet = set(FileDependencyDict[File])
|
|
NewDepSet -= DepSet
|
|
FileDependencyDict[File] = ["$(COMMON_DEPS)"] + list(NewDepSet)
|
|
DependencyDict[File] = list(NewDepSet)
|
|
|
|
# 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:
|
|
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:
|
|
T, CmdTarget, CmdTargetDict, CmdCppDict = self.ParserCCodeFile(T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict)
|
|
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))
|
|
|
|
def ParserCCodeFile(self, T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict):
|
|
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: continue
|
|
if CmdSign not in list(CmdTargetDict.keys()):
|
|
CmdTargetDict[CmdSign] = Item.replace(Temp, CmdSign)
|
|
else:
|
|
CmdTargetDict[CmdSign] = "%s %s" % (CmdTargetDict[CmdSign], SingleCommandList[-1])
|
|
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): $(COMMON_DEPS)' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir))
|
|
T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign])
|
|
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._FileType]
|
|
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._FILE_NAME_[self._FileType]
|
|
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._FileType].keys()),
|
|
"shell_command" : list(self._SHELL_CMD_[self._FileType].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._FileType]
|
|
|
|
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._FILE_NAME_[self._FileType]
|
|
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._FileType] % {"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._FileType] % {"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._FileType].keys()),
|
|
"shell_command" : list(self._SHELL_CMD_[self._FileType].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}\tGenFds -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._FileType]
|
|
|
|
# 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._FILE_NAME_[self._FileType]
|
|
SubBuildCommandList = []
|
|
for A in MyAgo.ArchList:
|
|
Command = self._MAKE_TEMPLATE_[self._FileType] % {"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._FileType].keys()),
|
|
"shell_command" : list(self._SHELL_CMD_[self._FileType].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:
|
|
with open(F.Path, 'rb') as Fd:
|
|
FileContent = Fd.read(1)
|
|
Fd.seek(0)
|
|
if not FileContent:
|
|
continue
|
|
if FileContent[0] == 0xff or FileContent[0] == 0xfe:
|
|
FileContent2 = Fd.read()
|
|
FileContent2 = FileContent2.decode('utf-16')
|
|
IncludedFileList = gIncludePattern.findall(FileContent2)
|
|
else:
|
|
FileLines = Fd.readlines()
|
|
FileContent2 = [line for line in FileLines if str(line).lstrip("#\t ")[:8] == "include "]
|
|
simpleFileContent="".join(FileContent2)
|
|
|
|
IncludedFileList = gIncludePattern.findall(simpleFileContent)
|
|
except BaseException as X:
|
|
EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=F.Path + "\n\t" + str(X))
|
|
if not FileContent:
|
|
continue
|
|
|
|
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
|