text: ## @file
  # Create makefile for MS nmake and GNU make
  #
  # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
  # This program and the accompanying materials
  # are licensed and made available under the terms and conditions of the BSD License
  # which accompanies this distribution.  The full text of the license may be found at
  # http://opensource.org/licenses/bsd-license.php
  #
  # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
  # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
  #
  
  ## Import Modules
  #
  import Common.LongFilePathOs as os
  import sys
  import string
  import re
  import os.path as path
  from Common.LongFilePathSupport import OpenLongFilePath as open
  from Common.MultipleWorkspace import MultipleWorkspace as mws
  from Common.BuildToolError import *
  from Common.Misc import *
  from Common.StringUtils import *
  from BuildEngine import *
  import Common.GlobalData as GlobalData
  from collections import OrderedDict
  
  ## 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_ = {"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 == 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.FileCache = {}
          self.FileDependency = []
          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
      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))
          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"
  
          # Intel EBC compiler enforces EfiMain
          if MyAgo.AutoGenVersion < 0x00010005 and MyAgo.Arch == "EBC":
              ArchEntryPoint = "EfiMain"
          else:
              ArchEntryPoint = ModuleEntryPoint
  
          if MyAgo.Arch == "EBC":
              # EBC compiler always use "EfiStart" as entry point. Only applies to EdkII modules
              ImageEntryPoint = "EfiStart"
          elif MyAgo.AutoGenVersion < 0x00010005:
              # Edk modules use entry point specified in INF file
              ImageEntryPoint = ModuleEntryPoint
          else:
              # EdkII modules always use "_ModuleEntryPoint" as entry point
              ImageEntryPoint = "_ModuleEntryPoint"
  
          for k, v in MyAgo.Module.Defines.iteritems():
              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.iteritems():
              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 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 + os.linesep
                  RespFileListContent += NewRespStr + os.linesep
              SaveFileOnChange(RespFileList, RespFileListContent, False)
          else:
              if os.path.exists(RespFileList):
                  os.remove(RespFileList)
  
          # convert source files and binary files to build targets
          self.ResultFileList = [str(T.Target) for T in 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)
  
          # 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
                  )
  
          # Edk modules need <BaseName>StrDefs.h for string ID
          #if MyAgo.AutoGenVersion < 0x00010005 and len(MyAgo.UnicodeFileList) > 0:
          #    BcTargetList = ['strdefs']
          #else:
          #    BcTargetList = []
          BcTargetList = []
  
          MakefileName = self._FILE_NAME_[self._FileType]
          LibraryMakeCommandList = []
          for D in self.LibraryBuildDirectoryList:
              Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join(D, MakefileName)}
              LibraryMakeCommandList.append(Command)
  
          package_rel_dir = 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.iteritems()],
  
              "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"        : 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 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:
                      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)
  
          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
  
              self._AutoGenObject.AutoGenDepSet |= set(self.FileDependency[File])
  
              # skip non-C files
              if File.Ext not in [".c", ".C"] or File.Name == "AutoGen.c":
                  continue
              elif DepSet is None:
                  DepSet = set(self.FileDependency[File])
              else:
                  DepSet &= set(self.FileDependency[File])
          # 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))
  
          for File in self.FileDependency:
              # skip non-C files
              if File.Ext not in [".c", ".C"] or File.Name == "AutoGen.c":
                  continue
              NewDepSet = set(self.FileDependency[File])
              NewDepSet -= DepSet
              self.FileDependency[File] = ["$(COMMON_DEPS)"] + list(NewDepSet)
  
          # Convert target description object to target string in makefile
          for Type in self._AutoGenObject.Targets:
              for T in self._AutoGenObject.Targets[Type]:
                  # Generate related macros if needed
                  if T.GenFileListMacro and T.FileListMacro not in self.FileListMacros:
                      self.FileListMacros[T.FileListMacro] = []
                  if T.GenListFile and T.ListFileMacro not in self.ListFileMacros:
                      self.ListFileMacros[T.ListFileMacro] = []
                  if T.GenIncListFile and T.IncListFileMacro not in self.ListFileMacros:
                      self.ListFileMacros[T.IncListFileMacro] = []
  
                  Deps = []
                  # Add force-dependencies
                  for Dep in T.Dependencies:
                      Deps.append(self.PlaceMacro(str(Dep), self.Macros))
                  # Add inclusion-dependencies
                  if len(T.Inputs) == 1 and T.Inputs[0] in self.FileDependency:
                      for F in self.FileDependency[T.Inputs[0]]:
                          Deps.append(self.PlaceMacro(str(F), self.Macros))
                  # Add source-dependencies
                  for F in T.Inputs:
                      NewFile = self.PlaceMacro(str(F), self.Macros)
                      # In order to use file list macro as dependency
                      if T.GenListFile:
                          # gnu tools need forward slash path separater, even on Windows
                          self.ListFileMacros[T.ListFileMacro].append(str(F).replace ('\\', '/'))
                          self.FileListMacros[T.FileListMacro].append(NewFile)
                      elif T.GenFileListMacro:
                          self.FileListMacros[T.FileListMacro].append(NewFile)
                      else:
                          Deps.append(NewFile)
  
                  # Use file list macro as dependency
                  if T.GenFileListMacro:
                      Deps.append("$(%s)" % T.FileListMacro)
                      if Type in [TAB_OBJECT_FILE, TAB_STATIC_LIBRARY]:
                          Deps.append("$(%s)" % T.ListFileMacro)
  
                  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:
              if not LibraryAutoGen.IsBinaryModule:
                  self.LibraryBuildDirectoryList.append(self.PlaceMacro(LibraryAutoGen.BuildDir, self.Macros))
  
      ## Return a list containing source file's dependencies
      #
      #   @param      FileList        The list of source files
      #   @param      ForceInculeList The list of files which will be included forcely
      #   @param      SearchPathList  The list of search path
      #
      #   @retval     dict            The mapping between source file path and its dependencies
      #
      def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):
          Dependency = {}
          for F in FileList:
              Dependency[F] = self.GetDependencyList(F, ForceInculeList, SearchPathList)
          return Dependency
  
      ## Find dependencies for one source file
      #
      #  By searching recursively "#include" directive in file, find out all the
      #  files needed by given source file. The dependecies will be only searched
      #  in given search path list.
      #
      #   @param      File            The source file
      #   @param      ForceInculeList The list of files which will be included forcely
      #   @param      SearchPathList  The list of search path
      #
      #   @retval     list            The list of files the given source file depends on
      #
      def GetDependencyList(self, File, ForceList, SearchPathList):
          EdkLogger.debug(EdkLogger.DEBUG_1, "Try to get dependency files for %s" % File)
          FileStack = [File] + ForceList
          DependencySet = set()
  
          if self._AutoGenObject.Arch not in gDependencyDatabase:
              gDependencyDatabase[self._AutoGenObject.Arch] = {}
          DepDb = gDependencyDatabase[self._AutoGenObject.Arch]
  
          while len(FileStack) > 0:
              F = FileStack.pop()
  
              FullPathDependList = []
              if F in self.FileCache:
                  for CacheFile in self.FileCache[F]:
                      FullPathDependList.append(CacheFile)
                      if CacheFile not in DependencySet:
                          FileStack.append(CacheFile)
                  DependencySet.update(FullPathDependList)
                  continue
  
              CurrentFileDependencyList = []
              if F in DepDb:
                  CurrentFileDependencyList = DepDb[F]
              else:
                  try:
                      Fd = open(F.Path, 'r')
                  except BaseException as X:
                      EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=F.Path + "\n\t" + str(X))
  
                  FileContent = Fd.read()
                  Fd.close()
                  if len(FileContent) == 0:
                      continue
  
                  if FileContent[0] == 0xff or FileContent[0] == 0xfe:
                      FileContent = unicode(FileContent, "utf-16")
                  IncludedFileList = gIncludePattern.findall(FileContent)
  
                  for Inc in IncludedFileList:
                      Inc = Inc.strip()
                      # if there's macro used to reference header file, expand it
                      HeaderList = gMacroPattern.findall(Inc)
                      if len(HeaderList) == 1 and len(HeaderList[0]) == 2:
                          HeaderType = HeaderList[0][0]
                          HeaderKey = HeaderList[0][1]
                          if HeaderType in gIncludeMacroConversion:
                              Inc = gIncludeMacroConversion[HeaderType] % {"HeaderKey" : HeaderKey}
                          else:
                              # not known macro used in #include, always build the file by
                              # returning a empty dependency
                              self.FileCache[File] = []
                              return []
                      Inc = os.path.normpath(Inc)
                      CurrentFileDependencyList.append(Inc)
                  DepDb[F] = CurrentFileDependencyList
  
              CurrentFilePath = F.Dir
              PathList = [CurrentFilePath] + SearchPathList
              for Inc in CurrentFileDependencyList:
                  for SearchPath in PathList:
                      FilePath = os.path.join(SearchPath, Inc)
                      if FilePath in gIsFileMap:
                          if not gIsFileMap[FilePath]:
                              continue
                      # If isfile is called too many times, the performance is slow down.
                      elif not os.path.isfile(FilePath):
                          gIsFileMap[FilePath] = False
                          continue
                      else:
                          gIsFileMap[FilePath] = True
                      FilePath = PathClass(FilePath)
                      FullPathDependList.append(FilePath)
                      if FilePath not in DependencySet:
                          FileStack.append(FilePath)
                      break
                  else:
                      EdkLogger.debug(EdkLogger.DEBUG_9, "%s included by %s was not found "\
                                      "in any given path:\n\t%s" % (Inc, F, "\n\t".join(SearchPathList)))
  
              self.FileCache[F] = FullPathDependList
              DependencySet.update(FullPathDependList)
  
          DependencySet.update(ForceList)
          if File in DependencySet:
              DependencySet.remove(File)
          DependencyList = list(DependencySet)  # remove duplicate ones
  
          return DependencyList
  
      _TemplateDict = property(_CreateTemplateDict)
  
  ## CustomMakefile class
  #
  #  This class encapsules makefie and its generation for module. It uses template to generate
  #  the content of makefile. The content of makefile will be got from ModuleAutoGen object.
  #
  class CustomMakefile(BuildFile):
      ## template used to generate the makefile for module with custom makefile
      _TEMPLATE_ = TemplateString('''\
  ${makefile_header}
  
  #
  # Platform Macro Definition
  #
  PLATFORM_NAME = ${platform_name}
  PLATFORM_GUID = ${platform_guid}
  PLATFORM_VERSION = ${platform_version}
  PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
  PLATFORM_DIR = ${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
      def _CreateTemplateDict(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"        : 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 = ${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
      def _CreateTemplateDict(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"        : self._SHELL_CMD_[self._FileType].keys(),
              "shell_command"             : self._SHELL_CMD_[self._FileType].values(),
              "build_architecture_list"   : MyAgo.Arch,
              "architecture"              : MyAgo.Arch,
              "separator"                 : Separator,
              "create_directory_command"  : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
              "cleanall_command"          : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
              "library_makefile_list"     : LibraryMakefileList,
              "module_makefile_list"      : ModuleMakefileList,
              "library_build_command"     : LibraryMakeCommandList,
              "module_build_command"      : ModuleMakeCommandList,
          }
  
          return MakefileTemplateDict
  
      ## Get the root directory list for intermediate files of all modules build
      #
      #   @retval     list    The list of directory
      #
      def GetModuleBuildDirectoryList(self):
          DirList = []
          for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
              if not ModuleAutoGen.IsBinaryModule:
                  DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
          return DirList
  
      ## Get the root directory list for intermediate files of all libraries build
      #
      #   @retval     list    The list of directory
      #
      def GetLibraryBuildDirectoryList(self):
          DirList = []
          for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
              if not LibraryAutoGen.IsBinaryModule:
                  DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
          return DirList
  
      _TemplateDict = property(_CreateTemplateDict)
  
  ## TopLevelMakefile class
  #
  #  This class encapsules makefie and its generation for entrance makefile. It
  # uses template to generate the content of makefile. The content of makefile
  # will be got from WorkspaceAutoGen object.
  #
  class TopLevelMakefile(BuildFile):
      ## template used to generate toplevel makefile
      _TEMPLATE_ = TemplateString('''${BEGIN}\tGenFds -f ${fdf_file} --conf=${conf_directory} -o ${platform_build_directory} -t ${toolchain_tag} -b ${build_target} -p ${active_platform} -a ${build_architecture_list} ${extra_options}${END}${BEGIN} -r ${fd} ${END}${BEGIN} -i ${fv} ${END}${BEGIN} -C ${cap} ${END}${BEGIN} -D ${macro} ${END}''')
  
      ## Constructor of TopLevelMakefile
      #
      #   @param  Workspace   Object of WorkspaceAutoGen class
      #
      def __init__(self, Workspace):
          BuildFile.__init__(self, Workspace)
          self.IntermediateDirectoryList = []
  
      # Compose a dict object containing information used to do replacement in template
      def _CreateTemplateDict(self):
          Separator = self._SEP_[self._FileType]
  
          # any platform autogen object is ok because we just need common information
          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
              MacroList.append('"%s=%s"' % ("EFI_SOURCE", GlobalData.gEfiSource.replace('\\', '\\\\')))
              MacroList.append('"%s=%s"' % ("EDK_SOURCE", GlobalData.gEdkSource.replace('\\', '\\\\')))
              MacroDict = {}
              MacroDict.update(GlobalData.gGlobalDefines)
              MacroDict.update(GlobalData.gCommandLineDefines)
              MacroDict.pop("EFI_SOURCE", "dummy")
              MacroDict.pop("EDK_SOURCE", "dummy")
              for MacroName in MacroDict:
                  if MacroDict[MacroName] != "":
                      MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
                  else:
                      MacroList.append('"%s"' % MacroName)
          else:
              FdfFileList = []
  
          # pass extra common options to external program called in makefile, currently GenFds.exe
          ExtraOption = ''
          LogLevel = EdkLogger.GetLevel()
          if LogLevel == EdkLogger.VERBOSE:
              ExtraOption += " -v"
          elif LogLevel <= EdkLogger.DEBUG_9:
              ExtraOption += " -d %d" % (LogLevel - 1)
          elif LogLevel == EdkLogger.QUIET:
              ExtraOption += " -q"
  
          if GlobalData.gCaseInsensitive:
              ExtraOption += " -c"
          if GlobalData.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"        : self._SHELL_CMD_[self._FileType].keys(),
              "shell_command"             : self._SHELL_CMD_[self._FileType].values(),
              'arch'                      : list(MyAgo.ArchList),
              "build_architecture_list"   : ','.join(MyAgo.ArchList),
              "separator"                 : Separator,
              "create_directory_command"  : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
              "cleanall_command"          : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
              "sub_build_command"         : SubBuildCommandList,
              "fdf_file"                  : FdfFileList,
              "active_platform"           : str(MyAgo),
              "fd"                        : MyAgo.FdTargetList,
              "fv"                        : MyAgo.FvTargetList,
              "cap"                       : MyAgo.CapTargetList,
              "extra_options"             : ExtraOption,
              "macro"                     : MacroList,
          }
  
          return MakefileTemplateDict
  
      ## Get the root directory list for intermediate files of all modules build
      #
      #   @retval     list    The list of directory
      #
      def GetModuleBuildDirectoryList(self):
          DirList = []
          for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
              if not ModuleAutoGen.IsBinaryModule:
                  DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
          return DirList
  
      ## Get the root directory list for intermediate files of all libraries build
      #
      #   @retval     list    The list of directory
      #
      def GetLibraryBuildDirectoryList(self):
          DirList = []
          for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
              if not LibraryAutoGen.IsBinaryModule:
                  DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
          return DirList
  
      _TemplateDict = property(_CreateTemplateDict)
  
  # This acts like the main() function for the script, unless it is 'import'ed into another script.
  if __name__ == '__main__':
      pass
  
  