| ## @file | |
| # Create makefile for MS nmake and GNU make | |
| # | |
| # Copyright (c) 2007 - 2016, 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 Common.LongFilePathOs as os | |
| import sys | |
| import string | |
| import re | |
| import os.path as path | |
| from Common.LongFilePathSupport import OpenLongFilePath as open | |
| from Common.MultipleWorkspace import MultipleWorkspace as mws | |
| from Common.BuildToolError import * | |
| from Common.Misc import * | |
| from Common.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) | |
| gIsFileMap = {} | |
| ## pattern for include style in Edk.x code | |
| gProtocolDefinition = "Protocol/%(HeaderKey)s/%(HeaderKey)s.h" | |
| gGuidDefinition = "Guid/%(HeaderKey)s/%(HeaderKey)s.h" | |
| gArchProtocolDefinition = "ArchProtocol/%(HeaderKey)s/%(HeaderKey)s.h" | |
| gPpiDefinition = "Ppi/%(HeaderKey)s/%(HeaderKey)s.h" | |
| gIncludeMacroConversion = { | |
| "EFI_PROTOCOL_DEFINITION" : gProtocolDefinition, | |
| "EFI_GUID_DEFINITION" : gGuidDefinition, | |
| "EFI_ARCH_PROTOCOL_DEFINITION" : gArchProtocolDefinition, | |
| "EFI_PROTOCOL_PRODUCER" : gProtocolDefinition, | |
| "EFI_PROTOCOL_CONSUMER" : gProtocolDefinition, | |
| "EFI_PROTOCOL_DEPENDENCY" : gProtocolDefinition, | |
| "EFI_ARCH_PROTOCOL_PRODUCER" : gArchProtocolDefinition, | |
| "EFI_ARCH_PROTOCOL_CONSUMER" : gArchProtocolDefinition, | |
| "EFI_ARCH_PROTOCOL_DEPENDENCY" : gArchProtocolDefinition, | |
| "EFI_PPI_DEFINITION" : gPpiDefinition, | |
| "EFI_PPI_PRODUCER" : gPpiDefinition, | |
| "EFI_PPI_CONSUMER" : gPpiDefinition, | |
| "EFI_PPI_DEPENDENCY" : gPpiDefinition, | |
| } | |
| ## default makefile type | |
| gMakeType = "" | |
| if sys.platform == "win32": | |
| gMakeType = "nmake" | |
| else: | |
| gMakeType = "gmake" | |
| ## BuildFile class | |
| # | |
| # This base class encapsules build file and its generation. It uses template to generate | |
| # the content of build file. The content of build file will be got from AutoGen objects. | |
| # | |
| class BuildFile(object): | |
| ## template used to generate the build file (i.e. makefile if using make) | |
| _TEMPLATE_ = TemplateString('') | |
| _DEFAULT_FILE_NAME_ = "Makefile" | |
| ## default file name for each type of build file | |
| _FILE_NAME_ = { | |
| "nmake" : "Makefile", | |
| "gmake" : "GNUmakefile" | |
| } | |
| ## Fixed header string for makefile | |
| _MAKEFILE_HEADER = '''# | |
| # DO NOT EDIT | |
| # This file is auto-generated by build utility | |
| # | |
| # Module Name: | |
| # | |
| # %s | |
| # | |
| # Abstract: | |
| # | |
| # Auto-generated makefile for building modules, libraries or platform | |
| # | |
| ''' | |
| ## Header string for each type of build file | |
| _FILE_HEADER_ = { | |
| "nmake" : _MAKEFILE_HEADER % _FILE_NAME_["nmake"], | |
| "gmake" : _MAKEFILE_HEADER % _FILE_NAME_["gmake"] | |
| } | |
| ## shell commands which can be used in build file in the form of macro | |
| # $(CP) copy file command | |
| # $(MV) move file command | |
| # $(RM) remove file command | |
| # $(MD) create dir command | |
| # $(RD) remove dir command | |
| # | |
| _SHELL_CMD_ = { | |
| "nmake" : { | |
| "CP" : "copy /y", | |
| "MV" : "move /y", | |
| "RM" : "del /f /q", | |
| "MD" : "mkdir", | |
| "RD" : "rmdir /s /q", | |
| }, | |
| "gmake" : { | |
| "CP" : "cp -f", | |
| "MV" : "mv -f", | |
| "RM" : "rm -f", | |
| "MD" : "mkdir -p", | |
| "RD" : "rm -r -f", | |
| } | |
| } | |
| ## directory separator | |
| _SEP_ = { | |
| "nmake" : "\\", | |
| "gmake" : "/" | |
| } | |
| ## directory creation template | |
| _MD_TEMPLATE_ = { | |
| "nmake" : '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_NAME_GUID = ${module_name_guid} | |
| MODULE_VERSION = ${module_version} | |
| MODULE_TYPE = ${module_type} | |
| MODULE_FILE = ${module_file} | |
| MODULE_FILE_BASE_NAME = ${module_file_base_name} | |
| BASE_NAME = $(MODULE_NAME) | |
| MODULE_RELATIVE_DIR = ${module_relative_directory} | |
| PACKAGE_RELATIVE_DIR = ${package_relative_directory} | |
| MODULE_DIR = ${module_dir} | |
| 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.FileCache = {} | |
| 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 libraries 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 EdkII modules | |
| ImageEntryPoint = "EfiStart" | |
| elif self._AutoGenObject.AutoGenVersion < 0x00010005: | |
| # Edk modules use entry point specified in INF file | |
| ImageEntryPoint = ModuleEntryPoint | |
| else: | |
| # EdkII modules always use "_ModuleEntryPoint" as entry point | |
| ImageEntryPoint = "_ModuleEntryPoint" | |
| for k, v in self._AutoGenObject.Module.Defines.iteritems(): | |
| if k not in self._AutoGenObject.Macros.keys(): | |
| self._AutoGenObject.Macros[k] = v | |
| if 'MODULE_ENTRY_POINT' not in self._AutoGenObject.Macros.keys(): | |
| self._AutoGenObject.Macros['MODULE_ENTRY_POINT'] = ModuleEntryPoint | |
| if 'ARCH_ENTRY_POINT' not in self._AutoGenObject.Macros.keys(): | |
| self._AutoGenObject.Macros['ARCH_ENTRY_POINT'] = ArchEntryPoint | |
| if 'IMAGE_ENTRY_POINT' not in self._AutoGenObject.Macros.keys(): | |
| self._AutoGenObject.Macros['IMAGE_ENTRY_POINT'] = ImageEntryPoint | |
| # 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("") | |
| # generate the Response file and Response flag | |
| RespDict = self.CommandExceedLimit() | |
| RespFileList = os.path.join(self._AutoGenObject.OutputDir, 'respfilelist.txt') | |
| if RespDict: | |
| RespFileListContent = '' | |
| for Resp in RespDict.keys(): | |
| RespFile = os.path.join(self._AutoGenObject.OutputDir, str(Resp).lower() + '.txt') | |
| StrList = RespDict[Resp].split(' ') | |
| UnexpandMacro = [] | |
| NewStr = [] | |
| for Str in StrList: | |
| if '$' in Str: | |
| UnexpandMacro.append(Str) | |
| else: | |
| NewStr.append(Str) | |
| UnexpandMacroStr = ' '.join(UnexpandMacro) | |
| NewRespStr = ' '.join(NewStr) | |
| SaveFileOnChange(RespFile, NewRespStr, False) | |
| ToolsDef.append("%s = %s" % (Resp, UnexpandMacroStr + ' @' + RespFile)) | |
| RespFileListContent += '@' + RespFile + os.linesep | |
| RespFileListContent += NewRespStr + os.linesep | |
| SaveFileOnChange(RespFileList, RespFileListContent, False) | |
| else: | |
| if os.path.exists(RespFileList): | |
| os.remove(RespFileList) | |
| # convert source files and binary files to build targets | |
| self.ResultFileList = [str(T.Target) for T in self._AutoGenObject.CodaTargetList] | |
| if len(self.ResultFileList) == 0 and len(self._AutoGenObject.SourceFileList) <> 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 | |
| ) | |
| # Edk 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) | |
| package_rel_dir = self._AutoGenObject.SourceDir | |
| current_dir = self.Macros["WORKSPACE"] | |
| found = False | |
| while not found and os.sep in package_rel_dir: | |
| index = package_rel_dir.index(os.sep) | |
| current_dir = mws.join(current_dir, package_rel_dir[:index]) | |
| for fl in os.listdir(current_dir): | |
| if fl.endswith('.dec'): | |
| found = True | |
| break | |
| package_rel_dir = package_rel_dir[index + 1:] | |
| MakefileTemplateDict = { | |
| "makefile_header" : self._FILE_HEADER_[self._FileType], | |
| "makefile_path" : os.path.join("$(MODULE_BUILD_DIR)", MakefileName), | |
| "makefile_name" : MakefileName, | |
| "platform_name" : self.PlatformInfo.Name, | |
| "platform_guid" : self.PlatformInfo.Guid, | |
| "platform_version" : self.PlatformInfo.Version, | |
| "platform_relative_directory": self.PlatformInfo.SourceDir, | |
| "platform_output_directory" : self.PlatformInfo.OutputDir, | |
| "module_name" : self._AutoGenObject.Name, | |
| "module_guid" : self._AutoGenObject.Guid, | |
| "module_name_guid" : self._AutoGenObject._GetUniqueBaseName(), | |
| "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_dir" : mws.join (self.Macros["WORKSPACE"], self._AutoGenObject.SourceDir), | |
| "package_relative_directory": package_rel_dir, | |
| "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 CommandExceedLimit(self): | |
| FlagDict = { | |
| 'CC' : { 'Macro' : '$(CC_FLAGS)', 'Value' : False}, | |
| 'PP' : { 'Macro' : '$(PP_FLAGS)', 'Value' : False}, | |
| 'APP' : { 'Macro' : '$(APP_FLAGS)', 'Value' : False}, | |
| 'ASLPP' : { 'Macro' : '$(ASLPP_FLAGS)', 'Value' : False}, | |
| 'VFRPP' : { 'Macro' : '$(VFRPP_FLAGS)', 'Value' : False}, | |
| 'ASM' : { 'Macro' : '$(ASM_FLAGS)', 'Value' : False}, | |
| 'ASLCC' : { 'Macro' : '$(ASLCC_FLAGS)', 'Value' : False}, | |
| } | |
| RespDict = {} | |
| FileTypeList = [] | |
| IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily] | |
| # base on the source files to decide the file type | |
| for File in self._AutoGenObject.SourceFileList: | |
| for type in self._AutoGenObject.FileTypes: | |
| if File in self._AutoGenObject.FileTypes[type]: | |
| if type not in FileTypeList: | |
| FileTypeList.append(type) | |
| # calculate the command-line length | |
| if FileTypeList: | |
| for type in FileTypeList: | |
| BuildTargets = self._AutoGenObject.BuildRules[type].BuildTargets | |
| for Target in BuildTargets: | |
| CommandList = BuildTargets[Target].Commands | |
| for SingleCommand in CommandList: | |
| Tool = '' | |
| SingleCommandLength = len(SingleCommand) | |
| SingleCommandList = SingleCommand.split() | |
| if len(SingleCommandList) > 0: | |
| for Flag in FlagDict.keys(): | |
| if '$('+ Flag +')' in SingleCommandList[0]: | |
| Tool = Flag | |
| break | |
| if Tool: | |
| SingleCommandLength += len(self._AutoGenObject._BuildOption[Tool]['PATH']) | |
| for item in SingleCommandList[1:]: | |
| if FlagDict[Tool]['Macro'] in item: | |
| Str = self._AutoGenObject._BuildOption[Tool]['FLAGS'] | |
| for Option in self._AutoGenObject.BuildOption.keys(): | |
| for Attr in self._AutoGenObject.BuildOption[Option]: | |
| if Str.find(Option + '_' + Attr) != -1: | |
| Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr]) | |
| while(Str.find('$(') != -1): | |
| for macro in self._AutoGenObject.Macros.keys(): | |
| MacroName = '$('+ macro + ')' | |
| if (Str.find(MacroName) != -1): | |
| Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro]) | |
| break | |
| else: | |
| break | |
| SingleCommandLength += len(Str) | |
| elif '$(INC)' in item: | |
| SingleCommandLength += self._AutoGenObject.IncludePathLength + len(IncPrefix) * len(self._AutoGenObject._IncludePathList) | |
| elif item.find('$(') != -1: | |
| Str = item | |
| for Option in self._AutoGenObject.BuildOption.keys(): | |
| for Attr in self._AutoGenObject.BuildOption[Option]: | |
| if Str.find(Option + '_' + Attr) != -1: | |
| Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr]) | |
| while(Str.find('$(') != -1): | |
| for macro in self._AutoGenObject.Macros.keys(): | |
| MacroName = '$('+ macro + ')' | |
| if (Str.find(MacroName) != -1): | |
| Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro]) | |
| break | |
| else: | |
| break | |
| SingleCommandLength += len(Str) | |
| if SingleCommandLength > GlobalData.gCommandMaxLength: | |
| FlagDict[Tool]['Value'] = True | |
| # generate the response file content by combine the FLAGS and INC | |
| for Flag in FlagDict.keys(): | |
| if FlagDict[Flag]['Value']: | |
| Key = Flag + '_RESP' | |
| RespMacro = FlagDict[Flag]['Macro'].replace('FLAGS', 'RESP') | |
| Value = self._AutoGenObject.BuildOption[Flag]['FLAGS'] | |
| for inc in self._AutoGenObject._IncludePathList: | |
| Value += ' ' + IncPrefix + inc | |
| for Option in self._AutoGenObject.BuildOption.keys(): | |
| for Attr in self._AutoGenObject.BuildOption[Option]: | |
| if Value.find(Option + '_' + Attr) != -1: | |
| Value = Value.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr]) | |
| while (Value.find('$(') != -1): | |
| for macro in self._AutoGenObject.Macros.keys(): | |
| MacroName = '$('+ macro + ')' | |
| if (Value.find(MacroName) != -1): | |
| Value = Value.replace(MacroName, self._AutoGenObject.Macros[macro]) | |
| break | |
| else: | |
| break | |
| RespDict[Key] = Value | |
| for Target in BuildTargets: | |
| for i, SingleCommand in enumerate(BuildTargets[Target].Commands): | |
| if FlagDict[Flag]['Macro'] in SingleCommand: | |
| BuildTargets[Target].Commands[i] = SingleCommand.replace('$(INC)','').replace(FlagDict[Flag]['Macro'], RespMacro) | |
| return RespDict | |
| def ProcessBuildTargetList(self): | |
| # | |
| # Search dependency file list for each source file | |
| # | |
| ForceIncludedFile = [] | |
| for File in self._AutoGenObject.AutoGenFileList: | |
| if File.Ext == '.h': | |
| ForceIncludedFile.append(File) | |
| SourceFileList = [] | |
| for Target in self._AutoGenObject.IntroTargetList: | |
| SourceFileList.extend(Target.Inputs) | |
| self.FileDependency = self.GetFileDependency( | |
| SourceFileList, | |
| ForceIncludedFile, | |
| self._AutoGenObject.IncludePathList + self._AutoGenObject.BuildOptionIncPathList | |
| ) | |
| 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 common 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: | |
| # gnu tools need forward slash path separater, even on Windows | |
| self.ListFileMacros[T.ListFileMacro].append(str(F).replace ('\\', '/')) | |
| self.FileListMacros[T.FileListMacro].append(NewFile) | |
| elif T.GenFileListMacro: | |
| self.FileListMacros[T.FileListMacro].append(NewFile) | |
| else: | |
| Deps.append(NewFile) | |
| # 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() | |
| if self._AutoGenObject.Arch not in gDependencyDatabase: | |
| gDependencyDatabase[self._AutoGenObject.Arch] = {} | |
| DepDb = gDependencyDatabase[self._AutoGenObject.Arch] | |
| while len(FileStack) > 0: | |
| F = FileStack.pop() | |
| FullPathDependList = [] | |
| if F in self.FileCache: | |
| for CacheFile in self.FileCache[F]: | |
| FullPathDependList.append(CacheFile) | |
| if CacheFile not in DependencySet: | |
| FileStack.append(CacheFile) | |
| DependencySet.update(FullPathDependList) | |
| continue | |
| CurrentFileDependencyList = [] | |
| if F in DepDb: | |
| CurrentFileDependencyList = DepDb[F] | |
| else: | |
| try: | |
| Fd = open(F.Path, '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) | |
| for Inc in IncludedFileList: | |
| Inc = Inc.strip() | |
| # if there's macro used to reference header file, expand it | |
| HeaderList = gMacroPattern.findall(Inc) | |
| if len(HeaderList) == 1 and len(HeaderList[0]) == 2: | |
| HeaderType = HeaderList[0][0] | |
| HeaderKey = HeaderList[0][1] | |
| if HeaderType in gIncludeMacroConversion: | |
| Inc = gIncludeMacroConversion[HeaderType] % {"HeaderKey" : HeaderKey} | |
| else: | |
| # not known macro used in #include, always build the file by | |
| # returning a empty dependency | |
| self.FileCache[File] = [] | |
| return [] | |
| Inc = os.path.normpath(Inc) | |
| CurrentFileDependencyList.append(Inc) | |
| DepDb[F] = CurrentFileDependencyList | |
| CurrentFilePath = F.Dir | |
| PathList = [CurrentFilePath] + SearchPathList | |
| for Inc in CurrentFileDependencyList: | |
| for SearchPath in PathList: | |
| FilePath = os.path.join(SearchPath, Inc) | |
| if FilePath in gIsFileMap: | |
| if not gIsFileMap[FilePath]: | |
| continue | |
| # If isfile is called too many times, the performance is slow down. | |
| elif not os.path.isfile(FilePath): | |
| gIsFileMap[FilePath] = False | |
| continue | |
| else: | |
| gIsFileMap[FilePath] = True | |
| FilePath = PathClass(FilePath) | |
| FullPathDependList.append(FilePath) | |
| if FilePath not in DependencySet: | |
| FileStack.append(FilePath) | |
| break | |
| else: | |
| EdkLogger.debug(EdkLogger.DEBUG_9, "%s included by %s was not found "\ | |
| "in any given path:\n\t%s" % (Inc, F, "\n\t".join(SearchPathList))) | |
| self.FileCache[F] = FullPathDependList | |
| DependencySet.update(FullPathDependList) | |
| DependencySet.update(ForceList) | |
| if File in DependencySet: | |
| DependencySet.remove(File) | |
| 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_NAME_GUID = ${module_name_guid} | |
| MODULE_VERSION = ${module_version} | |
| MODULE_TYPE = ${module_type} | |
| MODULE_FILE = ${module_file} | |
| MODULE_FILE_BASE_NAME = ${module_file_base_name} | |
| BASE_NAME = $(MODULE_NAME) | |
| MODULE_RELATIVE_DIR = ${module_relative_directory} | |
| MODULE_DIR = ${module_dir} | |
| # | |
| # Build Configuration Macro Definition | |
| # | |
| ARCH = ${architecture} | |
| TOOLCHAIN = ${toolchain_tag} | |
| TOOLCHAIN_TAG = ${toolchain_tag} | |
| TARGET = ${build_target} | |
| # | |
| # Build Directory Macro Definition | |
| # | |
| # PLATFORM_BUILD_DIR = ${platform_build_directory} | |
| BUILD_DIR = ${platform_build_directory} | |
| BIN_DIR = $(BUILD_DIR)${separator}${architecture} | |
| LIB_DIR = $(BIN_DIR) | |
| MODULE_BUILD_DIR = ${module_build_directory} | |
| OUTPUT_DIR = ${module_output_directory} | |
| DEBUG_DIR = ${module_debug_directory} | |
| DEST_DIR_OUTPUT = $(OUTPUT_DIR) | |
| DEST_DIR_DEBUG = $(DEBUG_DIR) | |
| # | |
| # Tools definitions specific to this module | |
| # | |
| ${BEGIN}${module_tool_definitions} | |
| ${END} | |
| MAKE_FILE = ${makefile_path} | |
| # | |
| # Shell Command Macro | |
| # | |
| ${BEGIN}${shell_command_code} = ${shell_command} | |
| ${END} | |
| ${custom_makefile_content} | |
| # | |
| # Target used when called from platform makefile, which will bypass the build of dependent libraries | |
| # | |
| pbuild: init all | |
| # | |
| # ModuleTarget | |
| # | |
| mbuild: init all | |
| # | |
| # Build Target used in multi-thread build mode, which no init target is needed | |
| # | |
| tbuild: all | |
| # | |
| # Initialization target: print build information and create necessary directories | |
| # | |
| init: | |
| \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)] | |
| ${BEGIN}\t-@${create_directory_command}\n${END}\ | |
| ''') | |
| ## Constructor of CustomMakefile | |
| # | |
| # @param ModuleAutoGen Object of ModuleAutoGen class | |
| # | |
| def __init__(self, ModuleAutoGen): | |
| BuildFile.__init__(self, ModuleAutoGen) | |
| self.PlatformInfo = self._AutoGenObject.PlatformInfo | |
| self.IntermediateDirectoryList = ["$(DEBUG_DIR)", "$(OUTPUT_DIR)"] | |
| # 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 = mws.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_name_guid" : self._AutoGenObject._GetUniqueBaseName(), | |
| "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, | |
| "module_dir" : mws.join (self._AutoGenObject.WorkspaceDir, 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 = [] | |
| self.LibraryMakeCommandList = [] | |
| # 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) | |
| self.LibraryMakeCommandList = LibraryMakeCommandList | |
| 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: | |
| if not ModuleAutoGen.IsBinaryModule: | |
| DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir)) | |
| return DirList | |
| ## Get the root directory list for intermediate files of all libraries build | |
| # | |
| # @retval list The list of directory | |
| # | |
| def GetLibraryBuildDirectoryList(self): | |
| DirList = [] | |
| for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList: | |
| if not LibraryAutoGen.IsBinaryModule: | |
| DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir)) | |
| return DirList | |
| _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('''${BEGIN}\tGenFds -f ${fdf_file} --conf=${conf_directory} -o ${platform_build_directory} -t ${toolchain_tag} -b ${build_target} -p ${active_platform} -a ${build_architecture_list} ${extra_options}${END}${BEGIN} -r ${fd} ${END}${BEGIN} -i ${fv} ${END}${BEGIN} -C ${cap} ${END}${BEGIN} -D ${macro} ${END}''') | |
| ## Constructor of TopLevelMakefile | |
| # | |
| # @param Workspace Object of WorkspaceAutoGen class | |
| # | |
| def __init__(self, Workspace): | |
| BuildFile.__init__(self, Workspace) | |
| self.IntermediateDirectoryList = [] | |
| # 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"' % ("EFI_SOURCE", GlobalData.gEfiSource.replace('\\', '\\\\'))) | |
| MacroList.append('"%s=%s"' % ("EDK_SOURCE", GlobalData.gEdkSource.replace('\\', '\\\\'))) | |
| MacroDict = {} | |
| MacroDict.update(GlobalData.gGlobalDefines) | |
| MacroDict.update(GlobalData.gCommandLineDefines) | |
| MacroDict.pop("EFI_SOURCE", "dummy") | |
| MacroDict.pop("EDK_SOURCE", "dummy") | |
| for MacroName in MacroDict: | |
| if MacroDict[MacroName] != "": | |
| MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\'))) | |
| else: | |
| MacroList.append('"%s"' % MacroName) | |
| else: | |
| FdfFileList = [] | |
| # pass extra common options to external program called in makefile, currently GenFds.exe | |
| ExtraOption = '' | |
| LogLevel = EdkLogger.GetLevel() | |
| if LogLevel == EdkLogger.VERBOSE: | |
| ExtraOption += " -v" | |
| elif LogLevel <= EdkLogger.DEBUG_9: | |
| ExtraOption += " -d %d" % (LogLevel - 1) | |
| elif LogLevel == EdkLogger.QUIET: | |
| ExtraOption += " -q" | |
| if GlobalData.gCaseInsensitive: | |
| ExtraOption += " -c" | |
| if GlobalData.gIgnoreSource: | |
| ExtraOption += " --ignore-sources" | |
| 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, | |
| "conf_directory" : GlobalData.gConfDirectory, | |
| "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, | |
| "cap" : PlatformInfo.CapTargetList, | |
| "extra_options" : ExtraOption, | |
| "macro" : MacroList, | |
| } | |
| return MakefileTemplateDict | |
| ## Get the root directory list for intermediate files of all modules build | |
| # | |
| # @retval list The list of directory | |
| # | |
| def GetModuleBuildDirectoryList(self): | |
| DirList = [] | |
| for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList: | |
| if not ModuleAutoGen.IsBinaryModule: | |
| DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir)) | |
| return DirList | |
| ## Get the root directory list for intermediate files of all libraries build | |
| # | |
| # @retval list The list of directory | |
| # | |
| def GetLibraryBuildDirectoryList(self): | |
| DirList = [] | |
| for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList: | |
| if not LibraryAutoGen.IsBinaryModule: | |
| DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir)) | |
| return DirList | |
| _TemplateDict = property(_CreateTemplateDict) | |
| # This acts like the main() function for the script, unless it is 'import'ed into another script. | |
| if __name__ == '__main__': | |
| pass | |