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