| ## @file |
| # Create makefile for MS nmake and GNU make |
| # |
| # Copyright (c) 2007, Intel Corporation |
| # All rights reserved. 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]*[\">])", re.MULTILINE|re.UNICODE) |
| |
| ## 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: |
| # 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 |
| for MacroName in GlobalData.gGlobalDefines: |
| MacroList.append('"%s=%s"' % (MacroName, GlobalData.gGlobalDefines[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 |
| |