mirror of https://github.com/acidanthera/audk.git
1397 lines
51 KiB
Python
1397 lines
51 KiB
Python
## @file
|
|
# Create makefile for MS nmake and GNU make
|
|
#
|
|
# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
|
|
# This program and the accompanying materials
|
|
# are licensed and made available under the terms and conditions of the BSD License
|
|
# which accompanies this distribution. The full text of the license may be found at
|
|
# http://opensource.org/licenses/bsd-license.php
|
|
#
|
|
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
#
|
|
|
|
## Import Modules
|
|
#
|
|
import os
|
|
import sys
|
|
import string
|
|
import re
|
|
import os.path as path
|
|
|
|
from Common.BuildToolError import *
|
|
from Common.Misc import *
|
|
from Common.String import *
|
|
from BuildEngine import *
|
|
import Common.GlobalData as GlobalData
|
|
|
|
## 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)
|
|
|
|
## pattern for include style in R8.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" : 'if not exist %(dir)s $(MD) %(dir)s',
|
|
"gmake" : "$(MD) %(dir)s"
|
|
}
|
|
|
|
## directory removal template
|
|
_RD_TEMPLATE_ = {
|
|
"nmake" : 'if exist %(dir)s $(RD) %(dir)s',
|
|
"gmake" : "$(RD) %(dir)s"
|
|
}
|
|
|
|
_CD_TEMPLATE_ = {
|
|
"nmake" : 'if exist %(dir)s cd %(dir)s',
|
|
"gmake" : "test -e %(dir)s && cd %(dir)s"
|
|
}
|
|
|
|
_MAKE_TEMPLATE_ = {
|
|
"nmake" : 'if exist %(file)s "$(MAKE)" $(MAKE_FLAGS) -f %(file)s',
|
|
"gmake" : 'test -e %(file)s && "$(MAKE)" $(MAKE_FLAGS) -f %(file)s'
|
|
}
|
|
|
|
_INCLUDE_CMD_ = {
|
|
"nmake" : '!INCLUDE',
|
|
"gmake" : "include"
|
|
}
|
|
|
|
_INC_FLAG_ = {"MSFT" : "/I", "GCC" : "-I", "INTEL" : "-I", "RVCT" : "-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={}):
|
|
if Path.startswith("$("):
|
|
return Path
|
|
else:
|
|
PathLength = len(Path)
|
|
for MacroName in MacroDefinitions:
|
|
MacroValue = MacroDefinitions[MacroName]
|
|
MacroValueLength = len(MacroValue)
|
|
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 = $(WORKSPACE)${separator}${platform_relative_directory}
|
|
PLATFORM_OUTPUT_DIR = ${platform_output_directory}
|
|
|
|
#
|
|
# Module Macro Definition
|
|
#
|
|
MODULE_NAME = ${module_name}
|
|
MODULE_GUID = ${module_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 = $(WORKSPACE)${separator}${module_relative_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}
|
|
|
|
#
|
|
# 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
|
|
|
|
#
|
|
# 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.SourceFileDatabase = {} # {file type : file path}
|
|
self.DestFileDatabase = {} # {file type : file path}
|
|
self.FileBuildTargetList = [] # [(src, target string)]
|
|
self.BuildTargetList = [] # [target string]
|
|
self.PendingBuildTargetList = [] # [FileBuildRule objects]
|
|
self.CommonFileDependency = []
|
|
self.FileListMacros = {}
|
|
self.ListFileMacros = {}
|
|
|
|
self.FileDependency = []
|
|
self.LibraryBuildCommandList = []
|
|
self.LibraryFileList = []
|
|
self.LibraryMakefileList = []
|
|
self.LibraryBuildDirectoryList = []
|
|
self.SystemLibraryList = []
|
|
self.Macros = sdict()
|
|
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"]
|
|
|
|
# Compose a dict object containing information used to do replacement in template
|
|
def _CreateTemplateDict(self):
|
|
if self._FileType not in self._SEP_:
|
|
EdkLogger.error("build", PARAMETER_INVALID, "Invalid Makefile type [%s]" % self._FileType,
|
|
ExtraData="[%s]" % str(self._AutoGenObject))
|
|
Separator = self._SEP_[self._FileType]
|
|
|
|
# break build if no source files and binary files are found
|
|
if len(self._AutoGenObject.SourceFileList) == 0 and len(self._AutoGenObject.BinaryFileList) == 0:
|
|
EdkLogger.error("build", AUTOGEN_ERROR, "No files to be built in module [%s, %s, %s]"
|
|
% (self._AutoGenObject.BuildTarget, self._AutoGenObject.ToolChain, self._AutoGenObject.Arch),
|
|
ExtraData="[%s]" % str(self._AutoGenObject))
|
|
|
|
# convert dependent libaries to build command
|
|
self.ProcessDependentLibrary()
|
|
if len(self._AutoGenObject.Module.ModuleEntryPointList) > 0:
|
|
ModuleEntryPoint = self._AutoGenObject.Module.ModuleEntryPointList[0]
|
|
else:
|
|
ModuleEntryPoint = "_ModuleEntryPoint"
|
|
|
|
# Intel EBC compiler enforces EfiMain
|
|
if self._AutoGenObject.AutoGenVersion < 0x00010005 and self._AutoGenObject.Arch == "EBC":
|
|
ArchEntryPoint = "EfiMain"
|
|
else:
|
|
ArchEntryPoint = ModuleEntryPoint
|
|
|
|
if self._AutoGenObject.Arch == "EBC":
|
|
# EBC compiler always use "EfiStart" as entry point. Only applies to R9 modules
|
|
ImageEntryPoint = "EfiStart"
|
|
elif self._AutoGenObject.AutoGenVersion < 0x00010005:
|
|
# R8 modules use entry point specified in INF file
|
|
ImageEntryPoint = ModuleEntryPoint
|
|
else:
|
|
# R9 modules always use "_ModuleEntryPoint" as entry point
|
|
ImageEntryPoint = "_ModuleEntryPoint"
|
|
|
|
# tools definitions
|
|
ToolsDef = []
|
|
IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily]
|
|
for Tool in self._AutoGenObject.BuildOption:
|
|
for Attr in self._AutoGenObject.BuildOption[Tool]:
|
|
Value = self._AutoGenObject.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, self._AutoGenObject.IncludePathList)
|
|
ToolsDef.append("%s_%s = %s" % (Tool, Attr, Value))
|
|
ToolsDef.append("")
|
|
|
|
# convert source files and binary files to build targets
|
|
self.ResultFileList = [str(T.Target) for T in self._AutoGenObject.CodaTargetList]
|
|
if len(self.ResultFileList) == 0:
|
|
EdkLogger.error("build", AUTOGEN_ERROR, "Nothing to build",
|
|
ExtraData="[%s]" % str(self._AutoGenObject))
|
|
|
|
self.ProcessBuildTargetList()
|
|
|
|
# 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 self._AutoGenObject.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)
|
|
|
|
# Generate macros used to represent files containing list of input files
|
|
for ListFileMacro in self.ListFileMacros:
|
|
ListFileName = os.path.join(self._AutoGenObject.OutputDir, "%s.lst" % ListFileMacro.lower()[:len(ListFileMacro)-5])
|
|
FileMacroList.append("%s = %s" % (ListFileMacro, ListFileName))
|
|
SaveFileOnChange(
|
|
ListFileName,
|
|
"\n".join(self.ListFileMacros[ListFileMacro]),
|
|
False
|
|
)
|
|
|
|
# R8 modules need <BaseName>StrDefs.h for string ID
|
|
#if self._AutoGenObject.AutoGenVersion < 0x00010005 and len(self._AutoGenObject.UnicodeFileList) > 0:
|
|
# BcTargetList = ['strdefs']
|
|
#else:
|
|
# BcTargetList = []
|
|
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)
|
|
|
|
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,
|
|
|
|
"module_name" : self._AutoGenObject.Name,
|
|
"module_guid" : self._AutoGenObject.Guid,
|
|
"module_version" : self._AutoGenObject.Version,
|
|
"module_type" : self._AutoGenObject.ModuleType,
|
|
"module_file" : self._AutoGenObject.MetaFile.Name,
|
|
"module_file_base_name" : self._AutoGenObject.MetaFile.BaseName,
|
|
"module_relative_directory" : self._AutoGenObject.SourceDir,
|
|
"module_extra_defines" : ["%s = %s" % (k, v) for k,v in self._AutoGenObject.Module.Defines.iteritems()],
|
|
|
|
"architecture" : self._AutoGenObject.Arch,
|
|
"toolchain_tag" : self._AutoGenObject.ToolChain,
|
|
"build_target" : self._AutoGenObject.BuildTarget,
|
|
|
|
"platform_build_directory" : self.PlatformInfo.BuildDir,
|
|
"module_build_directory" : self._AutoGenObject.BuildDir,
|
|
"module_output_directory" : self._AutoGenObject.OutputDir,
|
|
"module_debug_directory" : self._AutoGenObject.DebugDir,
|
|
|
|
"separator" : Separator,
|
|
"module_tool_definitions" : ToolsDef,
|
|
|
|
"shell_command_code" : self._SHELL_CMD_[self._FileType].keys(),
|
|
"shell_command" : 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 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 = []
|
|
for Target in self._AutoGenObject.IntroTargetList:
|
|
SourceFileList.extend(Target.Inputs)
|
|
|
|
self.FileDependency = self.GetFileDependency(
|
|
SourceFileList,
|
|
ForceIncludedFile,
|
|
self._AutoGenObject.IncludePathList
|
|
)
|
|
DepSet = None
|
|
for File in self.FileDependency:
|
|
if not self.FileDependency[File]:
|
|
self.FileDependency[File] = ['$(FORCE_REBUILD)']
|
|
continue
|
|
# skip non-C files
|
|
if File.Ext not in [".c", ".C"] or File.Name == "AutoGen.c":
|
|
continue
|
|
elif DepSet == None:
|
|
DepSet = set(self.FileDependency[File])
|
|
else:
|
|
DepSet &= set(self.FileDependency[File])
|
|
# in case nothing in SourceFileList
|
|
if DepSet == None:
|
|
DepSet = set()
|
|
#
|
|
# Extract comman files list in the dependency files
|
|
#
|
|
for File in DepSet:
|
|
self.CommonFileDependency.append(self.PlaceMacro(File.Path, self.Macros))
|
|
|
|
for File in self.FileDependency:
|
|
# skip non-C files
|
|
if File.Ext not in [".c", ".C"] or File.Name == "AutoGen.c":
|
|
continue
|
|
NewDepSet = set(self.FileDependency[File])
|
|
NewDepSet -= DepSet
|
|
self.FileDependency[File] = ["$(COMMON_DEPS)"] + list(NewDepSet)
|
|
|
|
# Convert target description object to target string in makefile
|
|
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 = []
|
|
# Add force-dependencies
|
|
for Dep in T.Dependencies:
|
|
Deps.append(self.PlaceMacro(str(Dep), self.Macros))
|
|
# Add inclusion-dependencies
|
|
if len(T.Inputs) == 1 and T.Inputs[0] in self.FileDependency:
|
|
for F in self.FileDependency[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:
|
|
self.ListFileMacros[T.ListFileMacro].append(str(F))
|
|
self.FileListMacros[T.FileListMacro].append(NewFile)
|
|
elif T.GenFileListMacro:
|
|
self.FileListMacros[T.FileListMacro].append(NewFile)
|
|
else:
|
|
Deps.append(NewFile)
|
|
|
|
# Use file list macro as dependency
|
|
if T.GenFileListMacro:
|
|
Deps.append("$(%s)" % T.FileListMacro)
|
|
|
|
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))
|
|
|
|
## For creating makefile targets for dependent libraries
|
|
def ProcessDependentLibrary(self):
|
|
for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
|
|
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] = self.GetDependencyList(F, ForceInculeList, SearchPathList)
|
|
return Dependency
|
|
|
|
## Find dependencies for one source file
|
|
#
|
|
# By searching recursively "#include" directive in file, find out all the
|
|
# files needed by given source file. The dependecies 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(self, File, ForceList, SearchPathList):
|
|
EdkLogger.debug(EdkLogger.DEBUG_1, "Try to get dependency files for %s" % File)
|
|
FileStack = [File] + ForceList
|
|
DependencySet = set()
|
|
MacroUsedByIncludedFile = False
|
|
|
|
if self._AutoGenObject.Arch not in gDependencyDatabase:
|
|
gDependencyDatabase[self._AutoGenObject.Arch] = {}
|
|
DepDb = gDependencyDatabase[self._AutoGenObject.Arch]
|
|
|
|
while len(FileStack) > 0:
|
|
F = FileStack.pop()
|
|
|
|
CurrentFileDependencyList = []
|
|
if F in DepDb:
|
|
CurrentFileDependencyList = DepDb[F]
|
|
for Dep in CurrentFileDependencyList:
|
|
if Dep not in FileStack and Dep not in DependencySet:
|
|
FileStack.append(Dep)
|
|
else:
|
|
try:
|
|
Fd = open(F.Path, 'r')
|
|
except BaseException, X:
|
|
EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=F.Path+"\n\t"+str(X))
|
|
|
|
FileContent = Fd.read()
|
|
Fd.close()
|
|
if len(FileContent) == 0:
|
|
continue
|
|
|
|
if FileContent[0] == 0xff or FileContent[0] == 0xfe:
|
|
FileContent = unicode(FileContent, "utf-16")
|
|
IncludedFileList = gIncludePattern.findall(FileContent)
|
|
|
|
CurrentFilePath = F.Dir
|
|
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
|
|
MacroUsedByIncludedFile = True
|
|
continue
|
|
Inc = os.path.normpath(Inc)
|
|
for SearchPath in [CurrentFilePath] + SearchPathList:
|
|
FilePath = os.path.join(SearchPath, Inc)
|
|
if not os.path.exists(FilePath) or FilePath in CurrentFileDependencyList:
|
|
continue
|
|
FilePath = PathClass(FilePath)
|
|
CurrentFileDependencyList.append(FilePath)
|
|
if FilePath not in FileStack and 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)))
|
|
|
|
if not MacroUsedByIncludedFile:
|
|
if F == File:
|
|
CurrentFileDependencyList += ForceList
|
|
#
|
|
# Don't keep the file in cache if it uses macro in included file.
|
|
# So it will be scanned again if another file includes this file.
|
|
#
|
|
DepDb[F] = CurrentFileDependencyList
|
|
DependencySet.update(CurrentFileDependencyList)
|
|
|
|
#
|
|
# If there's macro used in included file, always build the file by
|
|
# returning a empty dependency
|
|
#
|
|
if MacroUsedByIncludedFile:
|
|
DependencyList = []
|
|
else:
|
|
DependencyList = list(DependencySet) # remove duplicate ones
|
|
|
|
return DependencyList
|
|
|
|
_TemplateDict = property(_CreateTemplateDict)
|
|
|
|
## 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 = $(WORKSPACE)${separator}${platform_relative_directory}
|
|
PLATFORM_OUTPUT_DIR = ${platform_output_directory}
|
|
|
|
#
|
|
# Module Macro Definition
|
|
#
|
|
MODULE_NAME = ${module_name}
|
|
MODULE_GUID = ${module_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 = $(WORKSPACE)${separator}${module_relative_directory}
|
|
|
|
#
|
|
# 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)"]
|
|
|
|
# Compose a dict object containing information used to do replacement in template
|
|
def _CreateTemplateDict(self):
|
|
Separator = self._SEP_[self._FileType]
|
|
if self._FileType not in self._AutoGenObject.CustomMakefile:
|
|
EdkLogger.error('build', OPTION_NOT_SUPPORTED, "No custom makefile for %s" % self._FileType,
|
|
ExtraData="[%s]" % str(self._AutoGenObject))
|
|
MakefilePath = os.path.join(
|
|
self._AutoGenObject.WorkspaceDir,
|
|
self._AutoGenObject.CustomMakefile[self._FileType]
|
|
)
|
|
try:
|
|
CustomMakefile = open(MakefilePath, 'r').read()
|
|
except:
|
|
EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(self._AutoGenObject),
|
|
ExtraData=self._AutoGenObject.CustomMakefile[self._FileType])
|
|
|
|
# tools definitions
|
|
ToolsDef = []
|
|
for Tool in self._AutoGenObject.BuildOption:
|
|
# Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
|
|
if Tool == "MAKE":
|
|
continue
|
|
for Attr in self._AutoGenObject.BuildOption[Tool]:
|
|
if Attr == "FAMILY":
|
|
continue
|
|
elif Attr == "PATH":
|
|
ToolsDef.append("%s = %s" % (Tool, self._AutoGenObject.BuildOption[Tool][Attr]))
|
|
else:
|
|
ToolsDef.append("%s_%s = %s" % (Tool, Attr, self._AutoGenObject.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,
|
|
|
|
"module_name" : self._AutoGenObject.Name,
|
|
"module_guid" : self._AutoGenObject.Guid,
|
|
"module_version" : self._AutoGenObject.Version,
|
|
"module_type" : self._AutoGenObject.ModuleType,
|
|
"module_file" : self._AutoGenObject.MetaFile,
|
|
"module_file_base_name" : self._AutoGenObject.MetaFile.BaseName,
|
|
"module_relative_directory" : self._AutoGenObject.SourceDir,
|
|
|
|
"architecture" : self._AutoGenObject.Arch,
|
|
"toolchain_tag" : self._AutoGenObject.ToolChain,
|
|
"build_target" : self._AutoGenObject.BuildTarget,
|
|
|
|
"platform_build_directory" : self.PlatformInfo.BuildDir,
|
|
"module_build_directory" : self._AutoGenObject.BuildDir,
|
|
"module_output_directory" : self._AutoGenObject.OutputDir,
|
|
"module_debug_directory" : self._AutoGenObject.DebugDir,
|
|
|
|
"separator" : Separator,
|
|
"module_tool_definitions" : ToolsDef,
|
|
|
|
"shell_command_code" : self._SHELL_CMD_[self._FileType].keys(),
|
|
"shell_command" : self._SHELL_CMD_[self._FileType].values(),
|
|
|
|
"create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
|
|
"custom_makefile_content" : CustomMakefile
|
|
}
|
|
|
|
return MakefileTemplateDict
|
|
|
|
_TemplateDict = property(_CreateTemplateDict)
|
|
|
|
## 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 = $(WORKSPACE)${separator}${platform_relative_directory}
|
|
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 = []
|
|
|
|
# Compose a dict object containing information used to do replacement in template
|
|
def _CreateTemplateDict(self):
|
|
Separator = self._SEP_[self._FileType]
|
|
|
|
PlatformInfo = self._AutoGenObject
|
|
if "MAKE" not in PlatformInfo.ToolDefinition or "PATH" not in PlatformInfo.ToolDefinition["MAKE"]:
|
|
EdkLogger.error("build", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!",
|
|
ExtraData="[%s]" % str(self._AutoGenObject))
|
|
|
|
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":PlatformInfo.BuildDir})
|
|
Makefile = os.path.join(D, MakefileName)
|
|
Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
|
|
LibraryMakefileList.append(Makefile)
|
|
LibraryMakeCommandList.append(Command)
|
|
|
|
ModuleMakefileList = []
|
|
ModuleMakeCommandList = []
|
|
for D in self.ModuleBuildDirectoryList:
|
|
D = self.PlaceMacro(D, {"BUILD_DIR":PlatformInfo.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" : PlatformInfo.ToolDefinition["MAKE"]["PATH"],
|
|
"makefile_name" : MakefileName,
|
|
"platform_name" : PlatformInfo.Name,
|
|
"platform_guid" : PlatformInfo.Guid,
|
|
"platform_version" : PlatformInfo.Version,
|
|
"platform_file" : self._AutoGenObject.MetaFile,
|
|
"platform_relative_directory": PlatformInfo.SourceDir,
|
|
"platform_output_directory" : PlatformInfo.OutputDir,
|
|
"platform_build_directory" : PlatformInfo.BuildDir,
|
|
|
|
"toolchain_tag" : PlatformInfo.ToolChain,
|
|
"build_target" : PlatformInfo.BuildTarget,
|
|
"shell_command_code" : self._SHELL_CMD_[self._FileType].keys(),
|
|
"shell_command" : self._SHELL_CMD_[self._FileType].values(),
|
|
"build_architecture_list" : self._AutoGenObject.Arch,
|
|
"architecture" : self._AutoGenObject.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:
|
|
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:
|
|
DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
|
|
return DirList
|
|
|
|
_TemplateDict = property(_CreateTemplateDict)
|
|
|
|
## 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('''\
|
|
${makefile_header}
|
|
|
|
#
|
|
# Platform Macro Definition
|
|
#
|
|
PLATFORM_NAME = ${platform_name}
|
|
PLATFORM_GUID = ${platform_guid}
|
|
PLATFORM_VERSION = ${platform_version}
|
|
|
|
#
|
|
# 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: modules fds
|
|
|
|
#
|
|
# Initialization target: print build information and create necessary directories
|
|
#
|
|
init:
|
|
\t-@
|
|
\t${BEGIN}-@${create_directory_command}
|
|
\t${END}
|
|
#
|
|
# library build target
|
|
#
|
|
libraries: init
|
|
${BEGIN}\t@cd $(BUILD_DIR)${separator}${arch} && "$(MAKE)" $(MAKE_FLAGS) libraries
|
|
${END}\t@cd $(BUILD_DIR)
|
|
|
|
#
|
|
# module build target
|
|
#
|
|
modules: init
|
|
${BEGIN}\t@cd $(BUILD_DIR)${separator}${arch} && "$(MAKE)" $(MAKE_FLAGS) modules
|
|
${END}\t@cd $(BUILD_DIR)
|
|
|
|
#
|
|
# Flash Device Image Target
|
|
#
|
|
fds: init
|
|
\t-@cd $(FV_DIR)
|
|
${BEGIN}\tGenFds -f ${fdf_file} -o $(BUILD_DIR) -t $(TOOLCHAIN) -b $(TARGET) -p ${active_platform} -a ${build_architecture_list} ${extra_options}${END}${BEGIN} -r ${fd} ${END}${BEGIN} -i ${fv} ${END}${BEGIN} -D ${macro} ${END}
|
|
|
|
#
|
|
# run command for emulator platform only
|
|
#
|
|
run:
|
|
\tcd $(BUILD_DIR)${separator}IA32 && ".${separator}SecMain"
|
|
\tcd $(BUILD_DIR)
|
|
|
|
#
|
|
# Clean intermediate files
|
|
#
|
|
clean:
|
|
${BEGIN}\t-@${sub_build_command} clean
|
|
${END}\t@cd $(BUILD_DIR)
|
|
|
|
#
|
|
# Clean all generated files except to makefile
|
|
#
|
|
cleanall:
|
|
${BEGIN}\t${cleanall_command}
|
|
${END}
|
|
|
|
#
|
|
# Clean all library files
|
|
#
|
|
cleanlib:
|
|
${BEGIN}\t-@${sub_build_command} cleanlib
|
|
${END}\t@cd $(BUILD_DIR)\n
|
|
''')
|
|
|
|
## Constructor of TopLevelMakefile
|
|
#
|
|
# @param Workspace Object of WorkspaceAutoGen class
|
|
#
|
|
def __init__(self, Workspace):
|
|
BuildFile.__init__(self, Workspace)
|
|
self.IntermediateDirectoryList = []
|
|
|
|
# Compose a dict object containing information used to do replacement in template
|
|
def _CreateTemplateDict(self):
|
|
Separator = self._SEP_[self._FileType]
|
|
|
|
# any platform autogen object is ok because we just need common information
|
|
PlatformInfo = self._AutoGenObject
|
|
|
|
if "MAKE" not in PlatformInfo.ToolDefinition or "PATH" not in PlatformInfo.ToolDefinition["MAKE"]:
|
|
EdkLogger.error("build", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!",
|
|
ExtraData="[%s]" % str(self._AutoGenObject))
|
|
|
|
for Arch in PlatformInfo.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 PlatformInfo.FdfFile != None and PlatformInfo.FdfFile != "":
|
|
FdfFileList = [PlatformInfo.FdfFile]
|
|
# macros passed to GenFds
|
|
# MacroList.append('"%s=%s"' % ("WORKSPACE", GlobalData.gWorkspace))
|
|
MacroList.append('"%s=%s"' % ("EFI_SOURCE", GlobalData.gEfiSource))
|
|
MacroList.append('"%s=%s"' % ("EDK_SOURCE", GlobalData.gEdkSource))
|
|
for MacroName in GlobalData.gGlobalDefines:
|
|
if GlobalData.gGlobalDefines[MacroName] != "":
|
|
MacroList.append('"%s=%s"' % (MacroName, GlobalData.gGlobalDefines[MacroName]))
|
|
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"
|
|
|
|
MakefileName = self._FILE_NAME_[self._FileType]
|
|
SubBuildCommandList = []
|
|
for A in PlatformInfo.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" : PlatformInfo.ToolDefinition["MAKE"]["PATH"],
|
|
"platform_name" : PlatformInfo.Name,
|
|
"platform_guid" : PlatformInfo.Guid,
|
|
"platform_version" : PlatformInfo.Version,
|
|
"platform_build_directory" : PlatformInfo.BuildDir,
|
|
|
|
"toolchain_tag" : PlatformInfo.ToolChain,
|
|
"build_target" : PlatformInfo.BuildTarget,
|
|
"shell_command_code" : self._SHELL_CMD_[self._FileType].keys(),
|
|
"shell_command" : self._SHELL_CMD_[self._FileType].values(),
|
|
'arch' : list(PlatformInfo.ArchList),
|
|
"build_architecture_list" : ','.join(PlatformInfo.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(PlatformInfo),
|
|
"fd" : PlatformInfo.FdTargetList,
|
|
"fv" : PlatformInfo.FvTargetList,
|
|
"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:
|
|
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:
|
|
DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
|
|
return DirList
|
|
|
|
_TemplateDict = property(_CreateTemplateDict)
|
|
|
|
# This acts like the main() function for the script, unless it is 'import'ed into another script.
|
|
if __name__ == '__main__':
|
|
pass
|
|
|