• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1## @file
2# Create makefile for MS nmake and GNU make
3#
4# Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
5# This program and the accompanying materials
6# are licensed and made available under the terms and conditions of the BSD License
7# which accompanies this distribution.  The full text of the license may be found at
8# http://opensource.org/licenses/bsd-license.php
9#
10# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12#
13
14## Import Modules
15#
16import Common.LongFilePathOs as os
17import sys
18import string
19import re
20import os.path as path
21from Common.LongFilePathSupport import OpenLongFilePath as open
22from Common.MultipleWorkspace import MultipleWorkspace as mws
23from Common.BuildToolError import *
24from Common.Misc import *
25from Common.String import *
26from BuildEngine import *
27import Common.GlobalData as GlobalData
28
29## Regular expression for finding header file inclusions
30gIncludePattern = re.compile(r"^[ \t]*#?[ \t]*include(?:[ \t]*(?:\\(?:\r\n|\r|\n))*[ \t]*)*(?:\(?[\"<]?[ \t]*)([-\w.\\/() \t]+)(?:[ \t]*[\">]?\)?)", re.MULTILINE | re.UNICODE | re.IGNORECASE)
31
32## Regular expression for matching macro used in header file inclusion
33gMacroPattern = re.compile("([_A-Z][_A-Z0-9]*)[ \t]*\((.+)\)", re.UNICODE)
34
35gIsFileMap = {}
36
37## pattern for include style in Edk.x code
38gProtocolDefinition = "Protocol/%(HeaderKey)s/%(HeaderKey)s.h"
39gGuidDefinition = "Guid/%(HeaderKey)s/%(HeaderKey)s.h"
40gArchProtocolDefinition = "ArchProtocol/%(HeaderKey)s/%(HeaderKey)s.h"
41gPpiDefinition = "Ppi/%(HeaderKey)s/%(HeaderKey)s.h"
42gIncludeMacroConversion = {
43  "EFI_PROTOCOL_DEFINITION"         :   gProtocolDefinition,
44  "EFI_GUID_DEFINITION"             :   gGuidDefinition,
45  "EFI_ARCH_PROTOCOL_DEFINITION"    :   gArchProtocolDefinition,
46  "EFI_PROTOCOL_PRODUCER"           :   gProtocolDefinition,
47  "EFI_PROTOCOL_CONSUMER"           :   gProtocolDefinition,
48  "EFI_PROTOCOL_DEPENDENCY"         :   gProtocolDefinition,
49  "EFI_ARCH_PROTOCOL_PRODUCER"      :   gArchProtocolDefinition,
50  "EFI_ARCH_PROTOCOL_CONSUMER"      :   gArchProtocolDefinition,
51  "EFI_ARCH_PROTOCOL_DEPENDENCY"    :   gArchProtocolDefinition,
52  "EFI_PPI_DEFINITION"              :   gPpiDefinition,
53  "EFI_PPI_PRODUCER"                :   gPpiDefinition,
54  "EFI_PPI_CONSUMER"                :   gPpiDefinition,
55  "EFI_PPI_DEPENDENCY"              :   gPpiDefinition,
56}
57
58## default makefile type
59gMakeType = ""
60if sys.platform == "win32":
61    gMakeType = "nmake"
62else:
63    gMakeType = "gmake"
64
65
66## BuildFile class
67#
68#  This base class encapsules build file and its generation. It uses template to generate
69#  the content of build file. The content of build file will be got from AutoGen objects.
70#
71class BuildFile(object):
72    ## template used to generate the build file (i.e. makefile if using make)
73    _TEMPLATE_ = TemplateString('')
74
75    _DEFAULT_FILE_NAME_ = "Makefile"
76
77    ## default file name for each type of build file
78    _FILE_NAME_ = {
79        "nmake" :   "Makefile",
80        "gmake" :   "GNUmakefile"
81    }
82
83    ## Fixed header string for makefile
84    _MAKEFILE_HEADER = '''#
85# DO NOT EDIT
86# This file is auto-generated by build utility
87#
88# Module Name:
89#
90#   %s
91#
92# Abstract:
93#
94#   Auto-generated makefile for building modules, libraries or platform
95#
96    '''
97
98    ## Header string for each type of build file
99    _FILE_HEADER_ = {
100        "nmake" :   _MAKEFILE_HEADER % _FILE_NAME_["nmake"],
101        "gmake" :   _MAKEFILE_HEADER % _FILE_NAME_["gmake"]
102    }
103
104    ## shell commands which can be used in build file in the form of macro
105    #   $(CP)     copy file command
106    #   $(MV)     move file command
107    #   $(RM)     remove file command
108    #   $(MD)     create dir command
109    #   $(RD)     remove dir command
110    #
111    _SHELL_CMD_ = {
112        "nmake" : {
113            "CP"    :   "copy /y",
114            "MV"    :   "move /y",
115            "RM"    :   "del /f /q",
116            "MD"    :   "mkdir",
117            "RD"    :   "rmdir /s /q",
118        },
119
120        "gmake" : {
121            "CP"    :   "cp -f",
122            "MV"    :   "mv -f",
123            "RM"    :   "rm -f",
124            "MD"    :   "mkdir -p",
125            "RD"    :   "rm -r -f",
126        }
127    }
128
129    ## directory separator
130    _SEP_ = {
131        "nmake" :   "\\",
132        "gmake" :   "/"
133    }
134
135    ## directory creation template
136    _MD_TEMPLATE_ = {
137        "nmake" :   'if not exist %(dir)s $(MD) %(dir)s',
138        "gmake" :   "$(MD) %(dir)s"
139    }
140
141    ## directory removal template
142    _RD_TEMPLATE_ = {
143        "nmake" :   'if exist %(dir)s $(RD) %(dir)s',
144        "gmake" :   "$(RD) %(dir)s"
145    }
146
147    _CD_TEMPLATE_ = {
148        "nmake" :   'if exist %(dir)s cd %(dir)s',
149        "gmake" :   "test -e %(dir)s && cd %(dir)s"
150    }
151
152    _MAKE_TEMPLATE_ = {
153        "nmake" :   'if exist %(file)s "$(MAKE)" $(MAKE_FLAGS) -f %(file)s',
154        "gmake" :   'test -e %(file)s && "$(MAKE)" $(MAKE_FLAGS) -f %(file)s'
155    }
156
157    _INCLUDE_CMD_ = {
158        "nmake" :   '!INCLUDE',
159        "gmake" :   "include"
160    }
161
162    _INC_FLAG_ = {"MSFT" : "/I", "GCC" : "-I", "INTEL" : "-I", "RVCT" : "-I"}
163
164    ## Constructor of BuildFile
165    #
166    #   @param  AutoGenObject   Object of AutoGen class
167    #
168    def __init__(self, AutoGenObject):
169        self._AutoGenObject = AutoGenObject
170        self._FileType = gMakeType
171
172    ## Create build file
173    #
174    #   @param  FileType    Type of build file. Only nmake and gmake are supported now.
175    #
176    #   @retval TRUE        The build file is created or re-created successfully
177    #   @retval FALSE       The build file exists and is the same as the one to be generated
178    #
179    def Generate(self, FileType=gMakeType):
180        if FileType not in self._FILE_NAME_:
181            EdkLogger.error("build", PARAMETER_INVALID, "Invalid build type [%s]" % FileType,
182                            ExtraData="[%s]" % str(self._AutoGenObject))
183        self._FileType = FileType
184        FileContent = self._TEMPLATE_.Replace(self._TemplateDict)
185        FileName = self._FILE_NAME_[FileType]
186        return SaveFileOnChange(os.path.join(self._AutoGenObject.MakeFileDir, FileName), FileContent, False)
187
188    ## Return a list of directory creation command string
189    #
190    #   @param      DirList     The list of directory to be created
191    #
192    #   @retval     list        The directory creation command list
193    #
194    def GetCreateDirectoryCommand(self, DirList):
195        return [self._MD_TEMPLATE_[self._FileType] % {'dir':Dir} for Dir in DirList]
196
197    ## Return a list of directory removal command string
198    #
199    #   @param      DirList     The list of directory to be removed
200    #
201    #   @retval     list        The directory removal command list
202    #
203    def GetRemoveDirectoryCommand(self, DirList):
204        return [self._RD_TEMPLATE_[self._FileType] % {'dir':Dir} for Dir in DirList]
205
206    def PlaceMacro(self, Path, MacroDefinitions={}):
207        if Path.startswith("$("):
208            return Path
209        else:
210            PathLength = len(Path)
211            for MacroName in MacroDefinitions:
212                MacroValue = MacroDefinitions[MacroName]
213                MacroValueLength = len(MacroValue)
214                if MacroValueLength <= PathLength and Path.startswith(MacroValue):
215                    Path = "$(%s)%s" % (MacroName, Path[MacroValueLength:])
216                    break
217            return Path
218
219## ModuleMakefile class
220#
221#  This class encapsules makefie and its generation for module. It uses template to generate
222#  the content of makefile. The content of makefile will be got from ModuleAutoGen object.
223#
224class ModuleMakefile(BuildFile):
225    ## template used to generate the makefile for module
226    _TEMPLATE_ = TemplateString('''\
227${makefile_header}
228
229#
230# Platform Macro Definition
231#
232PLATFORM_NAME = ${platform_name}
233PLATFORM_GUID = ${platform_guid}
234PLATFORM_VERSION = ${platform_version}
235PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
236PLATFORM_DIR = ${platform_dir}
237PLATFORM_OUTPUT_DIR = ${platform_output_directory}
238
239#
240# Module Macro Definition
241#
242MODULE_NAME = ${module_name}
243MODULE_GUID = ${module_guid}
244MODULE_NAME_GUID = ${module_name_guid}
245MODULE_VERSION = ${module_version}
246MODULE_TYPE = ${module_type}
247MODULE_FILE = ${module_file}
248MODULE_FILE_BASE_NAME = ${module_file_base_name}
249BASE_NAME = $(MODULE_NAME)
250MODULE_RELATIVE_DIR = ${module_relative_directory}
251PACKAGE_RELATIVE_DIR = ${package_relative_directory}
252MODULE_DIR = ${module_dir}
253
254MODULE_ENTRY_POINT = ${module_entry_point}
255ARCH_ENTRY_POINT = ${arch_entry_point}
256IMAGE_ENTRY_POINT = ${image_entry_point}
257
258${BEGIN}${module_extra_defines}
259${END}
260#
261# Build Configuration Macro Definition
262#
263ARCH = ${architecture}
264TOOLCHAIN = ${toolchain_tag}
265TOOLCHAIN_TAG = ${toolchain_tag}
266TARGET = ${build_target}
267
268#
269# Build Directory Macro Definition
270#
271# PLATFORM_BUILD_DIR = ${platform_build_directory}
272BUILD_DIR = ${platform_build_directory}
273BIN_DIR = $(BUILD_DIR)${separator}${architecture}
274LIB_DIR = $(BIN_DIR)
275MODULE_BUILD_DIR = ${module_build_directory}
276OUTPUT_DIR = ${module_output_directory}
277DEBUG_DIR = ${module_debug_directory}
278DEST_DIR_OUTPUT = $(OUTPUT_DIR)
279DEST_DIR_DEBUG = $(DEBUG_DIR)
280
281#
282# Shell Command Macro
283#
284${BEGIN}${shell_command_code} = ${shell_command}
285${END}
286
287#
288# Tools definitions specific to this module
289#
290${BEGIN}${module_tool_definitions}
291${END}
292MAKE_FILE = ${makefile_path}
293
294#
295# Build Macro
296#
297${BEGIN}${file_macro}
298${END}
299
300COMMON_DEPS = ${BEGIN}${common_dependency_file} \\
301              ${END}
302
303#
304# Overridable Target Macro Definitions
305#
306FORCE_REBUILD = force_build
307INIT_TARGET = init
308PCH_TARGET =
309BC_TARGET = ${BEGIN}${backward_compatible_target} ${END}
310CODA_TARGET = ${BEGIN}${remaining_build_target} \\
311              ${END}
312
313#
314# Default target, which will build dependent libraries in addition to source files
315#
316
317all: mbuild
318
319
320#
321# Target used when called from platform makefile, which will bypass the build of dependent libraries
322#
323
324pbuild: $(INIT_TARGET) $(BC_TARGET) $(PCH_TARGET) $(CODA_TARGET)
325
326#
327# ModuleTarget
328#
329
330mbuild: $(INIT_TARGET) $(BC_TARGET) gen_libs $(PCH_TARGET) $(CODA_TARGET)
331
332#
333# Build Target used in multi-thread build mode, which will bypass the init and gen_libs targets
334#
335
336tbuild: $(BC_TARGET) $(PCH_TARGET) $(CODA_TARGET)
337
338#
339# Phony target which is used to force executing commands for a target
340#
341force_build:
342\t-@
343
344#
345# Target to update the FD
346#
347
348fds: mbuild gen_fds
349
350#
351# Initialization target: print build information and create necessary directories
352#
353init: info dirs
354
355info:
356\t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
357
358dirs:
359${BEGIN}\t-@${create_directory_command}\n${END}
360
361strdefs:
362\t-@$(CP) $(DEBUG_DIR)${separator}AutoGen.h $(DEBUG_DIR)${separator}$(MODULE_NAME)StrDefs.h
363
364#
365# GenLibsTarget
366#
367gen_libs:
368\t${BEGIN}@"$(MAKE)" $(MAKE_FLAGS) -f ${dependent_library_build_directory}${separator}${makefile_name}
369\t${END}@cd $(MODULE_BUILD_DIR)
370
371#
372# Build Flash Device Image
373#
374gen_fds:
375\t@"$(MAKE)" $(MAKE_FLAGS) -f $(BUILD_DIR)${separator}${makefile_name} fds
376\t@cd $(MODULE_BUILD_DIR)
377
378#
379# Individual Object Build Targets
380#
381${BEGIN}${file_build_target}
382${END}
383
384#
385# clean all intermediate files
386#
387clean:
388\t${BEGIN}${clean_command}
389\t${END}
390
391#
392# clean all generated files
393#
394cleanall:
395${BEGIN}\t${cleanall_command}
396${END}\t$(RM) *.pdb *.idb > NUL 2>&1
397\t$(RM) $(BIN_DIR)${separator}$(MODULE_NAME).efi
398
399#
400# clean all dependent libraries built
401#
402cleanlib:
403\t${BEGIN}-@${library_build_command} cleanall
404\t${END}@cd $(MODULE_BUILD_DIR)\n\n''')
405
406    _FILE_MACRO_TEMPLATE = TemplateString("${macro_name} = ${BEGIN} \\\n    ${source_file}${END}\n")
407    _BUILD_TARGET_TEMPLATE = TemplateString("${BEGIN}${target} : ${deps}\n${END}\t${cmd}\n")
408
409    ## Constructor of ModuleMakefile
410    #
411    #   @param  ModuleAutoGen   Object of ModuleAutoGen class
412    #
413    def __init__(self, ModuleAutoGen):
414        BuildFile.__init__(self, ModuleAutoGen)
415        self.PlatformInfo = self._AutoGenObject.PlatformInfo
416
417        self.ResultFileList = []
418        self.IntermediateDirectoryList = ["$(DEBUG_DIR)", "$(OUTPUT_DIR)"]
419
420        self.SourceFileDatabase = {}        # {file type : file path}
421        self.DestFileDatabase = {}          # {file type : file path}
422        self.FileBuildTargetList = []       # [(src, target string)]
423        self.BuildTargetList = []           # [target string]
424        self.PendingBuildTargetList = []    # [FileBuildRule objects]
425        self.CommonFileDependency = []
426        self.FileListMacros = {}
427        self.ListFileMacros = {}
428
429        self.FileCache = {}
430        self.FileDependency = []
431        self.LibraryBuildCommandList = []
432        self.LibraryFileList = []
433        self.LibraryMakefileList = []
434        self.LibraryBuildDirectoryList = []
435        self.SystemLibraryList = []
436        self.Macros = sdict()
437        self.Macros["OUTPUT_DIR"      ] = self._AutoGenObject.Macros["OUTPUT_DIR"]
438        self.Macros["DEBUG_DIR"       ] = self._AutoGenObject.Macros["DEBUG_DIR"]
439        self.Macros["MODULE_BUILD_DIR"] = self._AutoGenObject.Macros["MODULE_BUILD_DIR"]
440        self.Macros["BIN_DIR"         ] = self._AutoGenObject.Macros["BIN_DIR"]
441        self.Macros["BUILD_DIR"       ] = self._AutoGenObject.Macros["BUILD_DIR"]
442        self.Macros["WORKSPACE"       ] = self._AutoGenObject.Macros["WORKSPACE"]
443
444    # Compose a dict object containing information used to do replacement in template
445    def _CreateTemplateDict(self):
446        if self._FileType not in self._SEP_:
447            EdkLogger.error("build", PARAMETER_INVALID, "Invalid Makefile type [%s]" % self._FileType,
448                            ExtraData="[%s]" % str(self._AutoGenObject))
449        Separator = self._SEP_[self._FileType]
450
451        # break build if no source files and binary files are found
452        if len(self._AutoGenObject.SourceFileList) == 0 and len(self._AutoGenObject.BinaryFileList) == 0:
453            EdkLogger.error("build", AUTOGEN_ERROR, "No files to be built in module [%s, %s, %s]"
454                            % (self._AutoGenObject.BuildTarget, self._AutoGenObject.ToolChain, self._AutoGenObject.Arch),
455                            ExtraData="[%s]" % str(self._AutoGenObject))
456
457        # convert dependent libraries to build command
458        self.ProcessDependentLibrary()
459        if len(self._AutoGenObject.Module.ModuleEntryPointList) > 0:
460            ModuleEntryPoint = self._AutoGenObject.Module.ModuleEntryPointList[0]
461        else:
462            ModuleEntryPoint = "_ModuleEntryPoint"
463
464        # Intel EBC compiler enforces EfiMain
465        if self._AutoGenObject.AutoGenVersion < 0x00010005 and self._AutoGenObject.Arch == "EBC":
466            ArchEntryPoint = "EfiMain"
467        else:
468            ArchEntryPoint = ModuleEntryPoint
469
470        if self._AutoGenObject.Arch == "EBC":
471            # EBC compiler always use "EfiStart" as entry point. Only applies to EdkII modules
472            ImageEntryPoint = "EfiStart"
473        elif self._AutoGenObject.AutoGenVersion < 0x00010005:
474            # Edk modules use entry point specified in INF file
475            ImageEntryPoint = ModuleEntryPoint
476        else:
477            # EdkII modules always use "_ModuleEntryPoint" as entry point
478            ImageEntryPoint = "_ModuleEntryPoint"
479
480        for k, v in self._AutoGenObject.Module.Defines.iteritems():
481            if k not in self._AutoGenObject.Macros.keys():
482                self._AutoGenObject.Macros[k] = v
483
484        if 'MODULE_ENTRY_POINT' not in self._AutoGenObject.Macros.keys():
485            self._AutoGenObject.Macros['MODULE_ENTRY_POINT'] = ModuleEntryPoint
486        if 'ARCH_ENTRY_POINT' not in self._AutoGenObject.Macros.keys():
487            self._AutoGenObject.Macros['ARCH_ENTRY_POINT'] = ArchEntryPoint
488        if 'IMAGE_ENTRY_POINT' not in self._AutoGenObject.Macros.keys():
489            self._AutoGenObject.Macros['IMAGE_ENTRY_POINT'] = ImageEntryPoint
490
491        PCI_COMPRESS_Flag = False
492        for k, v in self._AutoGenObject.Module.Defines.iteritems():
493            if 'PCI_COMPRESS' == k and 'TRUE' == v:
494                PCI_COMPRESS_Flag = True
495
496        # tools definitions
497        ToolsDef = []
498        IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily]
499        for Tool in self._AutoGenObject.BuildOption:
500            for Attr in self._AutoGenObject.BuildOption[Tool]:
501                Value = self._AutoGenObject.BuildOption[Tool][Attr]
502                if Attr == "FAMILY":
503                    continue
504                elif Attr == "PATH":
505                    ToolsDef.append("%s = %s" % (Tool, Value))
506                else:
507                    # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
508                    if Tool == "MAKE":
509                        continue
510                    # Remove duplicated include path, if any
511                    if Attr == "FLAGS":
512                        Value = RemoveDupOption(Value, IncPrefix, self._AutoGenObject.IncludePathList)
513                        if Tool == "OPTROM" and PCI_COMPRESS_Flag:
514                            ValueList = Value.split()
515                            if ValueList:
516                                for i, v in enumerate(ValueList):
517                                    if '-e' == v:
518                                        ValueList[i] = '-ec'
519                                Value = ' '.join(ValueList)
520
521                    ToolsDef.append("%s_%s = %s" % (Tool, Attr, Value))
522            ToolsDef.append("")
523
524        # generate the Response file and Response flag
525        RespDict = self.CommandExceedLimit()
526        RespFileList = os.path.join(self._AutoGenObject.OutputDir, 'respfilelist.txt')
527        if RespDict:
528            RespFileListContent = ''
529            for Resp in RespDict.keys():
530                RespFile = os.path.join(self._AutoGenObject.OutputDir, str(Resp).lower() + '.txt')
531                StrList = RespDict[Resp].split(' ')
532                UnexpandMacro = []
533                NewStr = []
534                for Str in StrList:
535                    if '$' in Str:
536                        UnexpandMacro.append(Str)
537                    else:
538                        NewStr.append(Str)
539                UnexpandMacroStr = ' '.join(UnexpandMacro)
540                NewRespStr = ' '.join(NewStr)
541                SaveFileOnChange(RespFile, NewRespStr, False)
542                ToolsDef.append("%s = %s" % (Resp, UnexpandMacroStr + ' @' + RespFile))
543                RespFileListContent += '@' + RespFile + os.linesep
544                RespFileListContent += NewRespStr + os.linesep
545            SaveFileOnChange(RespFileList, RespFileListContent, False)
546        else:
547            if os.path.exists(RespFileList):
548                os.remove(RespFileList)
549
550        # convert source files and binary files to build targets
551        self.ResultFileList = [str(T.Target) for T in self._AutoGenObject.CodaTargetList]
552        if len(self.ResultFileList) == 0 and len(self._AutoGenObject.SourceFileList) <> 0:
553            EdkLogger.error("build", AUTOGEN_ERROR, "Nothing to build",
554                            ExtraData="[%s]" % str(self._AutoGenObject))
555
556        self.ProcessBuildTargetList()
557
558        # Generate macros used to represent input files
559        FileMacroList = [] # macro name = file list
560        for FileListMacro in self.FileListMacros:
561            FileMacro = self._FILE_MACRO_TEMPLATE.Replace(
562                                                    {
563                                                        "macro_name"  : FileListMacro,
564                                                        "source_file" : self.FileListMacros[FileListMacro]
565                                                    }
566                                                    )
567            FileMacroList.append(FileMacro)
568
569        # INC_LIST is special
570        FileMacro = ""
571        IncludePathList = []
572        for P in  self._AutoGenObject.IncludePathList:
573            IncludePathList.append(IncPrefix + self.PlaceMacro(P, self.Macros))
574            if FileBuildRule.INC_LIST_MACRO in self.ListFileMacros:
575                self.ListFileMacros[FileBuildRule.INC_LIST_MACRO].append(IncPrefix + P)
576        FileMacro += self._FILE_MACRO_TEMPLATE.Replace(
577                                                {
578                                                    "macro_name"   : "INC",
579                                                    "source_file" : IncludePathList
580                                                }
581                                                )
582        FileMacroList.append(FileMacro)
583
584        # Generate macros used to represent files containing list of input files
585        for ListFileMacro in self.ListFileMacros:
586            ListFileName = os.path.join(self._AutoGenObject.OutputDir, "%s.lst" % ListFileMacro.lower()[:len(ListFileMacro) - 5])
587            FileMacroList.append("%s = %s" % (ListFileMacro, ListFileName))
588            SaveFileOnChange(
589                ListFileName,
590                "\n".join(self.ListFileMacros[ListFileMacro]),
591                False
592                )
593
594        # Edk modules need <BaseName>StrDefs.h for string ID
595        #if self._AutoGenObject.AutoGenVersion < 0x00010005 and len(self._AutoGenObject.UnicodeFileList) > 0:
596        #    BcTargetList = ['strdefs']
597        #else:
598        #    BcTargetList = []
599        BcTargetList = []
600
601        MakefileName = self._FILE_NAME_[self._FileType]
602        LibraryMakeCommandList = []
603        for D in self.LibraryBuildDirectoryList:
604            Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join(D, MakefileName)}
605            LibraryMakeCommandList.append(Command)
606
607        package_rel_dir = self._AutoGenObject.SourceDir
608        current_dir = self.Macros["WORKSPACE"]
609        found = False
610        while not found and os.sep in package_rel_dir:
611            index = package_rel_dir.index(os.sep)
612            current_dir = mws.join(current_dir, package_rel_dir[:index])
613            if os.path.exists(current_dir):
614                for fl in os.listdir(current_dir):
615                    if fl.endswith('.dec'):
616                        found = True
617                        break
618            package_rel_dir = package_rel_dir[index + 1:]
619
620        MakefileTemplateDict = {
621            "makefile_header"           : self._FILE_HEADER_[self._FileType],
622            "makefile_path"             : os.path.join("$(MODULE_BUILD_DIR)", MakefileName),
623            "makefile_name"             : MakefileName,
624            "platform_name"             : self.PlatformInfo.Name,
625            "platform_guid"             : self.PlatformInfo.Guid,
626            "platform_version"          : self.PlatformInfo.Version,
627            "platform_relative_directory": self.PlatformInfo.SourceDir,
628            "platform_output_directory" : self.PlatformInfo.OutputDir,
629            "platform_dir"              : self._AutoGenObject.Macros["PLATFORM_DIR"],
630
631            "module_name"               : self._AutoGenObject.Name,
632            "module_guid"               : self._AutoGenObject.Guid,
633            "module_name_guid"          : self._AutoGenObject._GetUniqueBaseName(),
634            "module_version"            : self._AutoGenObject.Version,
635            "module_type"               : self._AutoGenObject.ModuleType,
636            "module_file"               : self._AutoGenObject.MetaFile.Name,
637            "module_file_base_name"     : self._AutoGenObject.MetaFile.BaseName,
638            "module_relative_directory" : self._AutoGenObject.SourceDir,
639            "module_dir"                : mws.join (self.Macros["WORKSPACE"], self._AutoGenObject.SourceDir),
640            "package_relative_directory": package_rel_dir,
641            "module_extra_defines"      : ["%s = %s" % (k, v) for k, v in self._AutoGenObject.Module.Defines.iteritems()],
642
643            "architecture"              : self._AutoGenObject.Arch,
644            "toolchain_tag"             : self._AutoGenObject.ToolChain,
645            "build_target"              : self._AutoGenObject.BuildTarget,
646
647            "platform_build_directory"  : self.PlatformInfo.BuildDir,
648            "module_build_directory"    : self._AutoGenObject.BuildDir,
649            "module_output_directory"   : self._AutoGenObject.OutputDir,
650            "module_debug_directory"    : self._AutoGenObject.DebugDir,
651
652            "separator"                 : Separator,
653            "module_tool_definitions"   : ToolsDef,
654
655            "shell_command_code"        : self._SHELL_CMD_[self._FileType].keys(),
656            "shell_command"             : self._SHELL_CMD_[self._FileType].values(),
657
658            "module_entry_point"        : ModuleEntryPoint,
659            "image_entry_point"         : ImageEntryPoint,
660            "arch_entry_point"          : ArchEntryPoint,
661            "remaining_build_target"    : self.ResultFileList,
662            "common_dependency_file"    : self.CommonFileDependency,
663            "create_directory_command"  : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
664            "clean_command"             : self.GetRemoveDirectoryCommand(["$(OUTPUT_DIR)"]),
665            "cleanall_command"          : self.GetRemoveDirectoryCommand(["$(DEBUG_DIR)", "$(OUTPUT_DIR)"]),
666            "dependent_library_build_directory" : self.LibraryBuildDirectoryList,
667            "library_build_command"     : LibraryMakeCommandList,
668            "file_macro"                : FileMacroList,
669            "file_build_target"         : self.BuildTargetList,
670            "backward_compatible_target": BcTargetList,
671        }
672
673        return MakefileTemplateDict
674
675    def CommandExceedLimit(self):
676        FlagDict = {
677                    'CC'    :  { 'Macro' : '$(CC_FLAGS)',    'Value' : False},
678                    'PP'    :  { 'Macro' : '$(PP_FLAGS)',    'Value' : False},
679                    'APP'   :  { 'Macro' : '$(APP_FLAGS)',   'Value' : False},
680                    'ASLPP' :  { 'Macro' : '$(ASLPP_FLAGS)', 'Value' : False},
681                    'VFRPP' :  { 'Macro' : '$(VFRPP_FLAGS)', 'Value' : False},
682                    'ASM'   :  { 'Macro' : '$(ASM_FLAGS)',   'Value' : False},
683                    'ASLCC' :  { 'Macro' : '$(ASLCC_FLAGS)', 'Value' : False},
684                   }
685
686        RespDict = {}
687        FileTypeList = []
688        IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily]
689
690        # base on the source files to decide the file type
691        for File in self._AutoGenObject.SourceFileList:
692            for type in self._AutoGenObject.FileTypes:
693                if File in self._AutoGenObject.FileTypes[type]:
694                    if type not in FileTypeList:
695                        FileTypeList.append(type)
696
697        # calculate the command-line length
698        if FileTypeList:
699            for type in FileTypeList:
700                BuildTargets = self._AutoGenObject.BuildRules[type].BuildTargets
701                for Target in BuildTargets:
702                    CommandList = BuildTargets[Target].Commands
703                    for SingleCommand in CommandList:
704                        Tool = ''
705                        SingleCommandLength = len(SingleCommand)
706                        SingleCommandList = SingleCommand.split()
707                        if len(SingleCommandList) > 0:
708                            for Flag in FlagDict.keys():
709                                if '$('+ Flag +')' in SingleCommandList[0]:
710                                    Tool = Flag
711                                    break
712                        if Tool:
713                            SingleCommandLength += len(self._AutoGenObject._BuildOption[Tool]['PATH'])
714                            for item in SingleCommandList[1:]:
715                                if FlagDict[Tool]['Macro'] in item:
716                                    Str = self._AutoGenObject._BuildOption[Tool]['FLAGS']
717                                    for Option in self._AutoGenObject.BuildOption.keys():
718                                        for Attr in self._AutoGenObject.BuildOption[Option]:
719                                            if Str.find(Option + '_' + Attr) != -1:
720                                                Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
721                                    while(Str.find('$(') != -1):
722                                        for macro in self._AutoGenObject.Macros.keys():
723                                            MacroName = '$('+ macro + ')'
724                                            if (Str.find(MacroName) != -1):
725                                                Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
726                                                break
727                                        else:
728                                            break
729                                    SingleCommandLength += len(Str)
730                                elif '$(INC)' in item:
731                                    SingleCommandLength += self._AutoGenObject.IncludePathLength + len(IncPrefix) * len(self._AutoGenObject._IncludePathList)
732                                elif item.find('$(') != -1:
733                                    Str = item
734                                    for Option in self._AutoGenObject.BuildOption.keys():
735                                        for Attr in self._AutoGenObject.BuildOption[Option]:
736                                            if Str.find(Option + '_' + Attr) != -1:
737                                                Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
738                                    while(Str.find('$(') != -1):
739                                        for macro in self._AutoGenObject.Macros.keys():
740                                            MacroName = '$('+ macro + ')'
741                                            if (Str.find(MacroName) != -1):
742                                                Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
743                                                break
744                                        else:
745                                            break
746                                    SingleCommandLength += len(Str)
747
748                            if SingleCommandLength > GlobalData.gCommandMaxLength:
749                                FlagDict[Tool]['Value'] = True
750
751                # generate the response file content by combine the FLAGS and INC
752                for Flag in FlagDict.keys():
753                    if FlagDict[Flag]['Value']:
754                        Key = Flag + '_RESP'
755                        RespMacro = FlagDict[Flag]['Macro'].replace('FLAGS', 'RESP')
756                        Value = self._AutoGenObject.BuildOption[Flag]['FLAGS']
757                        for inc in self._AutoGenObject._IncludePathList:
758                            Value += ' ' + IncPrefix + inc
759                        for Option in self._AutoGenObject.BuildOption.keys():
760                            for Attr in self._AutoGenObject.BuildOption[Option]:
761                                if Value.find(Option + '_' + Attr) != -1:
762                                    Value = Value.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
763                        while (Value.find('$(') != -1):
764                            for macro in self._AutoGenObject.Macros.keys():
765                                MacroName = '$('+ macro + ')'
766                                if (Value.find(MacroName) != -1):
767                                    Value = Value.replace(MacroName, self._AutoGenObject.Macros[macro])
768                                    break
769                            else:
770                                break
771
772                        if self._AutoGenObject.ToolChainFamily == 'GCC':
773                            RespDict[Key] = Value.replace('\\', '/')
774                        else:
775                            RespDict[Key] = Value
776                        for Target in BuildTargets:
777                            for i, SingleCommand in enumerate(BuildTargets[Target].Commands):
778                                if FlagDict[Flag]['Macro'] in SingleCommand:
779                                    BuildTargets[Target].Commands[i] = SingleCommand.replace('$(INC)','').replace(FlagDict[Flag]['Macro'], RespMacro)
780        return RespDict
781
782    def ProcessBuildTargetList(self):
783        #
784        # Search dependency file list for each source file
785        #
786        ForceIncludedFile = []
787        for File in self._AutoGenObject.AutoGenFileList:
788            if File.Ext == '.h':
789                ForceIncludedFile.append(File)
790        SourceFileList = []
791        for Target in self._AutoGenObject.IntroTargetList:
792            SourceFileList.extend(Target.Inputs)
793
794        self.FileDependency = self.GetFileDependency(
795                                    SourceFileList,
796                                    ForceIncludedFile,
797                                    self._AutoGenObject.IncludePathList + self._AutoGenObject.BuildOptionIncPathList
798                                    )
799        DepSet = None
800        for File in self.FileDependency:
801            if not self.FileDependency[File]:
802                self.FileDependency[File] = ['$(FORCE_REBUILD)']
803                continue
804            # skip non-C files
805            if File.Ext not in [".c", ".C"] or File.Name == "AutoGen.c":
806                continue
807            elif DepSet == None:
808                DepSet = set(self.FileDependency[File])
809            else:
810                DepSet &= set(self.FileDependency[File])
811        # in case nothing in SourceFileList
812        if DepSet == None:
813            DepSet = set()
814        #
815        # Extract common files list in the dependency files
816        #
817        for File in DepSet:
818            self.CommonFileDependency.append(self.PlaceMacro(File.Path, self.Macros))
819
820        for File in self.FileDependency:
821            # skip non-C files
822            if File.Ext not in [".c", ".C"] or File.Name == "AutoGen.c":
823                continue
824            NewDepSet = set(self.FileDependency[File])
825            NewDepSet -= DepSet
826            self.FileDependency[File] = ["$(COMMON_DEPS)"] + list(NewDepSet)
827
828        # Convert target description object to target string in makefile
829        for Type in self._AutoGenObject.Targets:
830            for T in self._AutoGenObject.Targets[Type]:
831                # Generate related macros if needed
832                if T.GenFileListMacro and T.FileListMacro not in self.FileListMacros:
833                    self.FileListMacros[T.FileListMacro] = []
834                if T.GenListFile and T.ListFileMacro not in self.ListFileMacros:
835                    self.ListFileMacros[T.ListFileMacro] = []
836                if T.GenIncListFile and T.IncListFileMacro not in self.ListFileMacros:
837                    self.ListFileMacros[T.IncListFileMacro] = []
838
839                Deps = []
840                # Add force-dependencies
841                for Dep in T.Dependencies:
842                    Deps.append(self.PlaceMacro(str(Dep), self.Macros))
843                # Add inclusion-dependencies
844                if len(T.Inputs) == 1 and T.Inputs[0] in self.FileDependency:
845                    for F in self.FileDependency[T.Inputs[0]]:
846                        Deps.append(self.PlaceMacro(str(F), self.Macros))
847                # Add source-dependencies
848                for F in T.Inputs:
849                    NewFile = self.PlaceMacro(str(F), self.Macros)
850                    # In order to use file list macro as dependency
851                    if T.GenListFile:
852                        # gnu tools need forward slash path separater, even on Windows
853                        self.ListFileMacros[T.ListFileMacro].append(str(F).replace ('\\', '/'))
854                        self.FileListMacros[T.FileListMacro].append(NewFile)
855                    elif T.GenFileListMacro:
856                        self.FileListMacros[T.FileListMacro].append(NewFile)
857                    else:
858                        Deps.append(NewFile)
859
860                # Use file list macro as dependency
861                if T.GenFileListMacro:
862                    Deps.append("$(%s)" % T.FileListMacro)
863
864                TargetDict = {
865                    "target"    :   self.PlaceMacro(T.Target.Path, self.Macros),
866                    "cmd"       :   "\n\t".join(T.Commands),
867                    "deps"      :   Deps
868                }
869                self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(TargetDict))
870
871    ## For creating makefile targets for dependent libraries
872    def ProcessDependentLibrary(self):
873        for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
874            if not LibraryAutoGen.IsBinaryModule:
875                self.LibraryBuildDirectoryList.append(self.PlaceMacro(LibraryAutoGen.BuildDir, self.Macros))
876
877    ## Return a list containing source file's dependencies
878    #
879    #   @param      FileList        The list of source files
880    #   @param      ForceInculeList The list of files which will be included forcely
881    #   @param      SearchPathList  The list of search path
882    #
883    #   @retval     dict            The mapping between source file path and its dependencies
884    #
885    def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):
886        Dependency = {}
887        for F in FileList:
888            Dependency[F] = self.GetDependencyList(F, ForceInculeList, SearchPathList)
889        return Dependency
890
891    ## Find dependencies for one source file
892    #
893    #  By searching recursively "#include" directive in file, find out all the
894    #  files needed by given source file. The dependecies will be only searched
895    #  in given search path list.
896    #
897    #   @param      File            The source file
898    #   @param      ForceInculeList The list of files which will be included forcely
899    #   @param      SearchPathList  The list of search path
900    #
901    #   @retval     list            The list of files the given source file depends on
902    #
903    def GetDependencyList(self, File, ForceList, SearchPathList):
904        EdkLogger.debug(EdkLogger.DEBUG_1, "Try to get dependency files for %s" % File)
905        FileStack = [File] + ForceList
906        DependencySet = set()
907
908        if self._AutoGenObject.Arch not in gDependencyDatabase:
909            gDependencyDatabase[self._AutoGenObject.Arch] = {}
910        DepDb = gDependencyDatabase[self._AutoGenObject.Arch]
911
912        while len(FileStack) > 0:
913            F = FileStack.pop()
914
915            FullPathDependList = []
916            if F in self.FileCache:
917                for CacheFile in self.FileCache[F]:
918                    FullPathDependList.append(CacheFile)
919                    if CacheFile not in DependencySet:
920                        FileStack.append(CacheFile)
921                DependencySet.update(FullPathDependList)
922                continue
923
924            CurrentFileDependencyList = []
925            if F in DepDb:
926                CurrentFileDependencyList = DepDb[F]
927            else:
928                try:
929                    Fd = open(F.Path, 'r')
930                except BaseException, X:
931                    EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=F.Path + "\n\t" + str(X))
932
933                FileContent = Fd.read()
934                Fd.close()
935                if len(FileContent) == 0:
936                    continue
937
938                if FileContent[0] == 0xff or FileContent[0] == 0xfe:
939                    FileContent = unicode(FileContent, "utf-16")
940                IncludedFileList = gIncludePattern.findall(FileContent)
941
942                for Inc in IncludedFileList:
943                    Inc = Inc.strip()
944                    # if there's macro used to reference header file, expand it
945                    HeaderList = gMacroPattern.findall(Inc)
946                    if len(HeaderList) == 1 and len(HeaderList[0]) == 2:
947                        HeaderType = HeaderList[0][0]
948                        HeaderKey = HeaderList[0][1]
949                        if HeaderType in gIncludeMacroConversion:
950                            Inc = gIncludeMacroConversion[HeaderType] % {"HeaderKey" : HeaderKey}
951                        else:
952                            # not known macro used in #include, always build the file by
953                            # returning a empty dependency
954                            self.FileCache[File] = []
955                            return []
956                    Inc = os.path.normpath(Inc)
957                    CurrentFileDependencyList.append(Inc)
958                DepDb[F] = CurrentFileDependencyList
959
960            CurrentFilePath = F.Dir
961            PathList = [CurrentFilePath] + SearchPathList
962            for Inc in CurrentFileDependencyList:
963                for SearchPath in PathList:
964                    FilePath = os.path.join(SearchPath, Inc)
965                    if FilePath in gIsFileMap:
966                        if not gIsFileMap[FilePath]:
967                            continue
968                    # If isfile is called too many times, the performance is slow down.
969                    elif not os.path.isfile(FilePath):
970                        gIsFileMap[FilePath] = False
971                        continue
972                    else:
973                        gIsFileMap[FilePath] = True
974                    FilePath = PathClass(FilePath)
975                    FullPathDependList.append(FilePath)
976                    if FilePath not in DependencySet:
977                        FileStack.append(FilePath)
978                    break
979                else:
980                    EdkLogger.debug(EdkLogger.DEBUG_9, "%s included by %s was not found "\
981                                    "in any given path:\n\t%s" % (Inc, F, "\n\t".join(SearchPathList)))
982
983            self.FileCache[F] = FullPathDependList
984            DependencySet.update(FullPathDependList)
985
986        DependencySet.update(ForceList)
987        if File in DependencySet:
988            DependencySet.remove(File)
989        DependencyList = list(DependencySet)  # remove duplicate ones
990
991        return DependencyList
992
993    _TemplateDict = property(_CreateTemplateDict)
994
995## CustomMakefile class
996#
997#  This class encapsules makefie and its generation for module. It uses template to generate
998#  the content of makefile. The content of makefile will be got from ModuleAutoGen object.
999#
1000class CustomMakefile(BuildFile):
1001    ## template used to generate the makefile for module with custom makefile
1002    _TEMPLATE_ = TemplateString('''\
1003${makefile_header}
1004
1005#
1006# Platform Macro Definition
1007#
1008PLATFORM_NAME = ${platform_name}
1009PLATFORM_GUID = ${platform_guid}
1010PLATFORM_VERSION = ${platform_version}
1011PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
1012PLATFORM_DIR = ${platform_dir}
1013PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1014
1015#
1016# Module Macro Definition
1017#
1018MODULE_NAME = ${module_name}
1019MODULE_GUID = ${module_guid}
1020MODULE_NAME_GUID = ${module_name_guid}
1021MODULE_VERSION = ${module_version}
1022MODULE_TYPE = ${module_type}
1023MODULE_FILE = ${module_file}
1024MODULE_FILE_BASE_NAME = ${module_file_base_name}
1025BASE_NAME = $(MODULE_NAME)
1026MODULE_RELATIVE_DIR = ${module_relative_directory}
1027MODULE_DIR = ${module_dir}
1028
1029#
1030# Build Configuration Macro Definition
1031#
1032ARCH = ${architecture}
1033TOOLCHAIN = ${toolchain_tag}
1034TOOLCHAIN_TAG = ${toolchain_tag}
1035TARGET = ${build_target}
1036
1037#
1038# Build Directory Macro Definition
1039#
1040# PLATFORM_BUILD_DIR = ${platform_build_directory}
1041BUILD_DIR = ${platform_build_directory}
1042BIN_DIR = $(BUILD_DIR)${separator}${architecture}
1043LIB_DIR = $(BIN_DIR)
1044MODULE_BUILD_DIR = ${module_build_directory}
1045OUTPUT_DIR = ${module_output_directory}
1046DEBUG_DIR = ${module_debug_directory}
1047DEST_DIR_OUTPUT = $(OUTPUT_DIR)
1048DEST_DIR_DEBUG = $(DEBUG_DIR)
1049
1050#
1051# Tools definitions specific to this module
1052#
1053${BEGIN}${module_tool_definitions}
1054${END}
1055MAKE_FILE = ${makefile_path}
1056
1057#
1058# Shell Command Macro
1059#
1060${BEGIN}${shell_command_code} = ${shell_command}
1061${END}
1062
1063${custom_makefile_content}
1064
1065#
1066# Target used when called from platform makefile, which will bypass the build of dependent libraries
1067#
1068
1069pbuild: init all
1070
1071
1072#
1073# ModuleTarget
1074#
1075
1076mbuild: init all
1077
1078#
1079# Build Target used in multi-thread build mode, which no init target is needed
1080#
1081
1082tbuild: all
1083
1084#
1085# Initialization target: print build information and create necessary directories
1086#
1087init:
1088\t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
1089${BEGIN}\t-@${create_directory_command}\n${END}\
1090
1091''')
1092
1093    ## Constructor of CustomMakefile
1094    #
1095    #   @param  ModuleAutoGen   Object of ModuleAutoGen class
1096    #
1097    def __init__(self, ModuleAutoGen):
1098        BuildFile.__init__(self, ModuleAutoGen)
1099        self.PlatformInfo = self._AutoGenObject.PlatformInfo
1100        self.IntermediateDirectoryList = ["$(DEBUG_DIR)", "$(OUTPUT_DIR)"]
1101
1102    # Compose a dict object containing information used to do replacement in template
1103    def _CreateTemplateDict(self):
1104        Separator = self._SEP_[self._FileType]
1105        if self._FileType not in self._AutoGenObject.CustomMakefile:
1106            EdkLogger.error('build', OPTION_NOT_SUPPORTED, "No custom makefile for %s" % self._FileType,
1107                            ExtraData="[%s]" % str(self._AutoGenObject))
1108        MakefilePath = mws.join(
1109                                self._AutoGenObject.WorkspaceDir,
1110                                self._AutoGenObject.CustomMakefile[self._FileType]
1111                                )
1112        try:
1113            CustomMakefile = open(MakefilePath, 'r').read()
1114        except:
1115            EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(self._AutoGenObject),
1116                            ExtraData=self._AutoGenObject.CustomMakefile[self._FileType])
1117
1118        # tools definitions
1119        ToolsDef = []
1120        for Tool in self._AutoGenObject.BuildOption:
1121            # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
1122            if Tool == "MAKE":
1123                continue
1124            for Attr in self._AutoGenObject.BuildOption[Tool]:
1125                if Attr == "FAMILY":
1126                    continue
1127                elif Attr == "PATH":
1128                    ToolsDef.append("%s = %s" % (Tool, self._AutoGenObject.BuildOption[Tool][Attr]))
1129                else:
1130                    ToolsDef.append("%s_%s = %s" % (Tool, Attr, self._AutoGenObject.BuildOption[Tool][Attr]))
1131            ToolsDef.append("")
1132
1133        MakefileName = self._FILE_NAME_[self._FileType]
1134        MakefileTemplateDict = {
1135            "makefile_header"           : self._FILE_HEADER_[self._FileType],
1136            "makefile_path"             : os.path.join("$(MODULE_BUILD_DIR)", MakefileName),
1137            "platform_name"             : self.PlatformInfo.Name,
1138            "platform_guid"             : self.PlatformInfo.Guid,
1139            "platform_version"          : self.PlatformInfo.Version,
1140            "platform_relative_directory": self.PlatformInfo.SourceDir,
1141            "platform_output_directory" : self.PlatformInfo.OutputDir,
1142            "platform_dir"              : self._AutoGenObject.Macros["PLATFORM_DIR"],
1143
1144            "module_name"               : self._AutoGenObject.Name,
1145            "module_guid"               : self._AutoGenObject.Guid,
1146            "module_name_guid"          : self._AutoGenObject._GetUniqueBaseName(),
1147            "module_version"            : self._AutoGenObject.Version,
1148            "module_type"               : self._AutoGenObject.ModuleType,
1149            "module_file"               : self._AutoGenObject.MetaFile,
1150            "module_file_base_name"     : self._AutoGenObject.MetaFile.BaseName,
1151            "module_relative_directory" : self._AutoGenObject.SourceDir,
1152            "module_dir"                : mws.join (self._AutoGenObject.WorkspaceDir, self._AutoGenObject.SourceDir),
1153
1154            "architecture"              : self._AutoGenObject.Arch,
1155            "toolchain_tag"             : self._AutoGenObject.ToolChain,
1156            "build_target"              : self._AutoGenObject.BuildTarget,
1157
1158            "platform_build_directory"  : self.PlatformInfo.BuildDir,
1159            "module_build_directory"    : self._AutoGenObject.BuildDir,
1160            "module_output_directory"   : self._AutoGenObject.OutputDir,
1161            "module_debug_directory"    : self._AutoGenObject.DebugDir,
1162
1163            "separator"                 : Separator,
1164            "module_tool_definitions"   : ToolsDef,
1165
1166            "shell_command_code"        : self._SHELL_CMD_[self._FileType].keys(),
1167            "shell_command"             : self._SHELL_CMD_[self._FileType].values(),
1168
1169            "create_directory_command"  : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1170            "custom_makefile_content"   : CustomMakefile
1171        }
1172
1173        return MakefileTemplateDict
1174
1175    _TemplateDict = property(_CreateTemplateDict)
1176
1177## PlatformMakefile class
1178#
1179#  This class encapsules makefie and its generation for platform. It uses
1180# template to generate the content of makefile. The content of makefile will be
1181# got from PlatformAutoGen object.
1182#
1183class PlatformMakefile(BuildFile):
1184    ## template used to generate the makefile for platform
1185    _TEMPLATE_ = TemplateString('''\
1186${makefile_header}
1187
1188#
1189# Platform Macro Definition
1190#
1191PLATFORM_NAME = ${platform_name}
1192PLATFORM_GUID = ${platform_guid}
1193PLATFORM_VERSION = ${platform_version}
1194PLATFORM_FILE = ${platform_file}
1195PLATFORM_DIR = ${platform_dir}
1196PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1197
1198#
1199# Build Configuration Macro Definition
1200#
1201TOOLCHAIN = ${toolchain_tag}
1202TOOLCHAIN_TAG = ${toolchain_tag}
1203TARGET = ${build_target}
1204
1205#
1206# Build Directory Macro Definition
1207#
1208BUILD_DIR = ${platform_build_directory}
1209FV_DIR = ${platform_build_directory}${separator}FV
1210
1211#
1212# Shell Command Macro
1213#
1214${BEGIN}${shell_command_code} = ${shell_command}
1215${END}
1216
1217MAKE = ${make_path}
1218MAKE_FILE = ${makefile_path}
1219
1220#
1221# Default target
1222#
1223all: init build_libraries build_modules
1224
1225#
1226# Initialization target: print build information and create necessary directories
1227#
1228init:
1229\t-@echo Building ... $(PLATFORM_FILE) [${build_architecture_list}]
1230\t${BEGIN}-@${create_directory_command}
1231\t${END}
1232#
1233# library build target
1234#
1235libraries: init build_libraries
1236
1237#
1238# module build target
1239#
1240modules: init build_libraries build_modules
1241
1242#
1243# Build all libraries:
1244#
1245build_libraries:
1246${BEGIN}\t@"$(MAKE)" $(MAKE_FLAGS) -f ${library_makefile_list} pbuild
1247${END}\t@cd $(BUILD_DIR)
1248
1249#
1250# Build all modules:
1251#
1252build_modules:
1253${BEGIN}\t@"$(MAKE)" $(MAKE_FLAGS) -f ${module_makefile_list} pbuild
1254${END}\t@cd $(BUILD_DIR)
1255
1256#
1257# Clean intermediate files
1258#
1259clean:
1260\t${BEGIN}-@${library_build_command} clean
1261\t${END}${BEGIN}-@${module_build_command} clean
1262\t${END}@cd $(BUILD_DIR)
1263
1264#
1265# Clean all generated files except to makefile
1266#
1267cleanall:
1268${BEGIN}\t${cleanall_command}
1269${END}
1270
1271#
1272# Clean all library files
1273#
1274cleanlib:
1275\t${BEGIN}-@${library_build_command} cleanall
1276\t${END}@cd $(BUILD_DIR)\n
1277''')
1278
1279    ## Constructor of PlatformMakefile
1280    #
1281    #   @param  ModuleAutoGen   Object of PlatformAutoGen class
1282    #
1283    def __init__(self, PlatformAutoGen):
1284        BuildFile.__init__(self, PlatformAutoGen)
1285        self.ModuleBuildCommandList = []
1286        self.ModuleMakefileList = []
1287        self.IntermediateDirectoryList = []
1288        self.ModuleBuildDirectoryList = []
1289        self.LibraryBuildDirectoryList = []
1290        self.LibraryMakeCommandList = []
1291
1292    # Compose a dict object containing information used to do replacement in template
1293    def _CreateTemplateDict(self):
1294        Separator = self._SEP_[self._FileType]
1295
1296        PlatformInfo = self._AutoGenObject
1297        if "MAKE" not in PlatformInfo.ToolDefinition or "PATH" not in PlatformInfo.ToolDefinition["MAKE"]:
1298            EdkLogger.error("build", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!",
1299                            ExtraData="[%s]" % str(self._AutoGenObject))
1300
1301        self.IntermediateDirectoryList = ["$(BUILD_DIR)"]
1302        self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()
1303        self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()
1304
1305        MakefileName = self._FILE_NAME_[self._FileType]
1306        LibraryMakefileList = []
1307        LibraryMakeCommandList = []
1308        for D in self.LibraryBuildDirectoryList:
1309            D = self.PlaceMacro(D, {"BUILD_DIR":PlatformInfo.BuildDir})
1310            Makefile = os.path.join(D, MakefileName)
1311            Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1312            LibraryMakefileList.append(Makefile)
1313            LibraryMakeCommandList.append(Command)
1314        self.LibraryMakeCommandList = LibraryMakeCommandList
1315
1316        ModuleMakefileList = []
1317        ModuleMakeCommandList = []
1318        for D in self.ModuleBuildDirectoryList:
1319            D = self.PlaceMacro(D, {"BUILD_DIR":PlatformInfo.BuildDir})
1320            Makefile = os.path.join(D, MakefileName)
1321            Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1322            ModuleMakefileList.append(Makefile)
1323            ModuleMakeCommandList.append(Command)
1324
1325        MakefileTemplateDict = {
1326            "makefile_header"           : self._FILE_HEADER_[self._FileType],
1327            "makefile_path"             : os.path.join("$(BUILD_DIR)", MakefileName),
1328            "make_path"                 : PlatformInfo.ToolDefinition["MAKE"]["PATH"],
1329            "makefile_name"             : MakefileName,
1330            "platform_name"             : PlatformInfo.Name,
1331            "platform_guid"             : PlatformInfo.Guid,
1332            "platform_version"          : PlatformInfo.Version,
1333            "platform_file"             : self._AutoGenObject.MetaFile,
1334            "platform_relative_directory": PlatformInfo.SourceDir,
1335            "platform_output_directory" : PlatformInfo.OutputDir,
1336            "platform_build_directory"  : PlatformInfo.BuildDir,
1337            "platform_dir"              : self._AutoGenObject.Macros["PLATFORM_DIR"],
1338
1339            "toolchain_tag"             : PlatformInfo.ToolChain,
1340            "build_target"              : PlatformInfo.BuildTarget,
1341            "shell_command_code"        : self._SHELL_CMD_[self._FileType].keys(),
1342            "shell_command"             : self._SHELL_CMD_[self._FileType].values(),
1343            "build_architecture_list"   : self._AutoGenObject.Arch,
1344            "architecture"              : self._AutoGenObject.Arch,
1345            "separator"                 : Separator,
1346            "create_directory_command"  : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1347            "cleanall_command"          : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1348            "library_makefile_list"     : LibraryMakefileList,
1349            "module_makefile_list"      : ModuleMakefileList,
1350            "library_build_command"     : LibraryMakeCommandList,
1351            "module_build_command"      : ModuleMakeCommandList,
1352        }
1353
1354        return MakefileTemplateDict
1355
1356    ## Get the root directory list for intermediate files of all modules build
1357    #
1358    #   @retval     list    The list of directory
1359    #
1360    def GetModuleBuildDirectoryList(self):
1361        DirList = []
1362        for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1363            if not ModuleAutoGen.IsBinaryModule:
1364                DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1365        return DirList
1366
1367    ## Get the root directory list for intermediate files of all libraries build
1368    #
1369    #   @retval     list    The list of directory
1370    #
1371    def GetLibraryBuildDirectoryList(self):
1372        DirList = []
1373        for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1374            if not LibraryAutoGen.IsBinaryModule:
1375                DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1376        return DirList
1377
1378    _TemplateDict = property(_CreateTemplateDict)
1379
1380## TopLevelMakefile class
1381#
1382#  This class encapsules makefie and its generation for entrance makefile. It
1383# uses template to generate the content of makefile. The content of makefile
1384# will be got from WorkspaceAutoGen object.
1385#
1386class TopLevelMakefile(BuildFile):
1387    ## template used to generate toplevel makefile
1388    _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}''')
1389
1390    ## Constructor of TopLevelMakefile
1391    #
1392    #   @param  Workspace   Object of WorkspaceAutoGen class
1393    #
1394    def __init__(self, Workspace):
1395        BuildFile.__init__(self, Workspace)
1396        self.IntermediateDirectoryList = []
1397
1398    # Compose a dict object containing information used to do replacement in template
1399    def _CreateTemplateDict(self):
1400        Separator = self._SEP_[self._FileType]
1401
1402        # any platform autogen object is ok because we just need common information
1403        PlatformInfo = self._AutoGenObject
1404
1405        if "MAKE" not in PlatformInfo.ToolDefinition or "PATH" not in PlatformInfo.ToolDefinition["MAKE"]:
1406            EdkLogger.error("build", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!",
1407                            ExtraData="[%s]" % str(self._AutoGenObject))
1408
1409        for Arch in PlatformInfo.ArchList:
1410            self.IntermediateDirectoryList.append(Separator.join(["$(BUILD_DIR)", Arch]))
1411        self.IntermediateDirectoryList.append("$(FV_DIR)")
1412
1413        # TRICK: for not generating GenFds call in makefile if no FDF file
1414        MacroList = []
1415        if PlatformInfo.FdfFile != None and PlatformInfo.FdfFile != "":
1416            FdfFileList = [PlatformInfo.FdfFile]
1417            # macros passed to GenFds
1418            MacroList.append('"%s=%s"' % ("EFI_SOURCE", GlobalData.gEfiSource.replace('\\', '\\\\')))
1419            MacroList.append('"%s=%s"' % ("EDK_SOURCE", GlobalData.gEdkSource.replace('\\', '\\\\')))
1420            MacroDict = {}
1421            MacroDict.update(GlobalData.gGlobalDefines)
1422            MacroDict.update(GlobalData.gCommandLineDefines)
1423            MacroDict.pop("EFI_SOURCE", "dummy")
1424            MacroDict.pop("EDK_SOURCE", "dummy")
1425            for MacroName in MacroDict:
1426                if MacroDict[MacroName] != "":
1427                    MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
1428                else:
1429                    MacroList.append('"%s"' % MacroName)
1430        else:
1431            FdfFileList = []
1432
1433        # pass extra common options to external program called in makefile, currently GenFds.exe
1434        ExtraOption = ''
1435        LogLevel = EdkLogger.GetLevel()
1436        if LogLevel == EdkLogger.VERBOSE:
1437            ExtraOption += " -v"
1438        elif LogLevel <= EdkLogger.DEBUG_9:
1439            ExtraOption += " -d %d" % (LogLevel - 1)
1440        elif LogLevel == EdkLogger.QUIET:
1441            ExtraOption += " -q"
1442
1443        if GlobalData.gCaseInsensitive:
1444            ExtraOption += " -c"
1445
1446        if GlobalData.gIgnoreSource:
1447            ExtraOption += " --ignore-sources"
1448
1449        if GlobalData.BuildOptionPcd:
1450            for index, option in enumerate(GlobalData.gCommand):
1451                if "--pcd" == option and GlobalData.gCommand[index+1]:
1452                    ExtraOption += " --pcd " + GlobalData.gCommand[index+1]
1453
1454        MakefileName = self._FILE_NAME_[self._FileType]
1455        SubBuildCommandList = []
1456        for A in PlatformInfo.ArchList:
1457            Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join("$(BUILD_DIR)", A, MakefileName)}
1458            SubBuildCommandList.append(Command)
1459
1460        MakefileTemplateDict = {
1461            "makefile_header"           : self._FILE_HEADER_[self._FileType],
1462            "makefile_path"             : os.path.join("$(BUILD_DIR)", MakefileName),
1463            "make_path"                 : PlatformInfo.ToolDefinition["MAKE"]["PATH"],
1464            "platform_name"             : PlatformInfo.Name,
1465            "platform_guid"             : PlatformInfo.Guid,
1466            "platform_version"          : PlatformInfo.Version,
1467            "platform_build_directory"  : PlatformInfo.BuildDir,
1468            "conf_directory"            : GlobalData.gConfDirectory,
1469
1470            "toolchain_tag"             : PlatformInfo.ToolChain,
1471            "build_target"              : PlatformInfo.BuildTarget,
1472            "shell_command_code"        : self._SHELL_CMD_[self._FileType].keys(),
1473            "shell_command"             : self._SHELL_CMD_[self._FileType].values(),
1474            'arch'                      : list(PlatformInfo.ArchList),
1475            "build_architecture_list"   : ','.join(PlatformInfo.ArchList),
1476            "separator"                 : Separator,
1477            "create_directory_command"  : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1478            "cleanall_command"          : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1479            "sub_build_command"         : SubBuildCommandList,
1480            "fdf_file"                  : FdfFileList,
1481            "active_platform"           : str(PlatformInfo),
1482            "fd"                        : PlatformInfo.FdTargetList,
1483            "fv"                        : PlatformInfo.FvTargetList,
1484            "cap"                       : PlatformInfo.CapTargetList,
1485            "extra_options"             : ExtraOption,
1486            "macro"                     : MacroList,
1487        }
1488
1489        return MakefileTemplateDict
1490
1491    ## Get the root directory list for intermediate files of all modules build
1492    #
1493    #   @retval     list    The list of directory
1494    #
1495    def GetModuleBuildDirectoryList(self):
1496        DirList = []
1497        for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1498            if not ModuleAutoGen.IsBinaryModule:
1499                DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1500        return DirList
1501
1502    ## Get the root directory list for intermediate files of all libraries build
1503    #
1504    #   @retval     list    The list of directory
1505    #
1506    def GetLibraryBuildDirectoryList(self):
1507        DirList = []
1508        for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1509            if not LibraryAutoGen.IsBinaryModule:
1510                DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1511        return DirList
1512
1513    _TemplateDict = property(_CreateTemplateDict)
1514
1515# This acts like the main() function for the script, unless it is 'import'ed into another script.
1516if __name__ == '__main__':
1517    pass
1518
1519