2 # Create makefile for MS nmake and GNU make
4 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 # SPDX-License-Identifier: BSD-2-Clause-Patent
10 from __future__
import absolute_import
11 import Common
.LongFilePathOs
as os
15 import os
.path
as path
16 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
17 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
18 from Common
.BuildToolError
import *
19 from Common
.Misc
import *
20 from Common
.StringUtils
import *
21 from .BuildEngine
import *
22 import Common
.GlobalData
as GlobalData
23 from collections
import OrderedDict
24 from Common
.DataType
import TAB_COMPILER_MSFT
26 ## Regular expression for finding header file inclusions
27 gIncludePattern
= re
.compile(r
"^[ \t]*[#%]?[ \t]*include(?:[ \t]*(?:\\(?:\r\n|\r|\n))*[ \t]*)*(?:\(?[\"<]?
[ \t]*)([-\w
.\\/() \t]+)(?
:[ \t]*[\">]?\
)?
)", re.MULTILINE | re.UNICODE | re.IGNORECASE)
29 ## Regular expression for matching macro used in header file inclusion
30 gMacroPattern = re.compile("([_A
-Z
][_A
-Z0
-9]*)[ \t]*\
((.+)\
)", re.UNICODE)
34 ## pattern for include style in Edk.x code
35 gProtocolDefinition = "Protocol
/%(HeaderKey)s/%(HeaderKey)s.h
"
36 gGuidDefinition = "Guid
/%(HeaderKey)s/%(HeaderKey)s.h
"
37 gArchProtocolDefinition = "ArchProtocol
/%(HeaderKey)s/%(HeaderKey)s.h
"
38 gPpiDefinition = "Ppi
/%(HeaderKey)s/%(HeaderKey)s.h
"
39 gIncludeMacroConversion = {
40 "EFI_PROTOCOL_DEFINITION
" : gProtocolDefinition,
41 "EFI_GUID_DEFINITION
" : gGuidDefinition,
42 "EFI_ARCH_PROTOCOL_DEFINITION
" : gArchProtocolDefinition,
43 "EFI_PROTOCOL_PRODUCER
" : gProtocolDefinition,
44 "EFI_PROTOCOL_CONSUMER
" : gProtocolDefinition,
45 "EFI_PROTOCOL_DEPENDENCY
" : gProtocolDefinition,
46 "EFI_ARCH_PROTOCOL_PRODUCER
" : gArchProtocolDefinition,
47 "EFI_ARCH_PROTOCOL_CONSUMER
" : gArchProtocolDefinition,
48 "EFI_ARCH_PROTOCOL_DEPENDENCY
" : gArchProtocolDefinition,
49 "EFI_PPI_DEFINITION
" : gPpiDefinition,
50 "EFI_PPI_PRODUCER
" : gPpiDefinition,
51 "EFI_PPI_CONSUMER
" : gPpiDefinition,
52 "EFI_PPI_DEPENDENCY
" : gPpiDefinition,
55 ## default makefile type
57 if sys.platform == "win32
":
65 # This base class encapsules build file and its generation. It uses template to generate
66 # the content of build file. The content of build file will be got from AutoGen objects.
68 class BuildFile(object):
69 ## template used to generate the build file (i.e. makefile if using make)
70 _TEMPLATE_ = TemplateString('')
72 _DEFAULT_FILE_NAME_ = "Makefile
"
74 ## default file name for each type of build file
77 "gmake
" : "GNUmakefile
"
80 ## Fixed header string for makefile
81 _MAKEFILE_HEADER = '''#
83 # This file is auto-generated by build utility
91 # Auto-generated makefile for building modules, libraries or platform
95 ## Header string for each type of build file
97 "nmake
" : _MAKEFILE_HEADER % _FILE_NAME_["nmake
"],
98 "gmake
" : _MAKEFILE_HEADER % _FILE_NAME_["gmake
"]
101 ## shell commands which can be used in build file in the form of macro
102 # $(CP) copy file command
103 # $(MV) move file command
104 # $(RM) remove file command
105 # $(MD) create dir command
106 # $(RD) remove dir command
114 "RD
" : "rmdir
/s
/q
",
126 ## directory separator
132 ## directory creation template
134 "nmake
" : 'if not exist %(dir)s $(MD) %(dir)s',
135 "gmake
" : "$
(MD
) %(dir)s"
138 ## directory removal template
140 "nmake
" : 'if exist %(dir)s $(RD) %(dir)s',
141 "gmake
" : "$
(RD
) %(dir)s"
145 "nmake
" : 'if exist %(Src)s $(CP) %(Src)s %(Dst)s',
146 "gmake
" : "test
-f
%(Src)s && $
(CP
) %(Src)s %(Dst)s"
150 "nmake
" : 'if exist %(dir)s cd %(dir)s',
151 "gmake
" : "test
-e
%(dir)s && cd
%(dir)s"
155 "nmake
" : 'if exist %(file)s "$
(MAKE
)" $(MAKE_FLAGS) -f %(file)s',
156 "gmake
" : 'test -e %(file)s && "$
(MAKE
)" $(MAKE_FLAGS) -f %(file)s'
160 "nmake
" : '!INCLUDE',
164 _INC_FLAG_ = {TAB_COMPILER_MSFT : "/I
", "GCC
" : "-I
", "INTEL
" : "-I
", "RVCT
" : "-I
", "NASM
" : "-I
"}
166 ## Constructor of BuildFile
168 # @param AutoGenObject Object of AutoGen class
170 def __init__(self, AutoGenObject):
171 self._AutoGenObject = AutoGenObject
172 self._FileType = gMakeType
176 # @param FileType Type of build file. Only nmake and gmake are supported now.
178 # @retval TRUE The build file is created or re-created successfully
179 # @retval FALSE The build file exists and is the same as the one to be generated
181 def Generate(self, FileType=gMakeType):
182 if FileType not in self._FILE_NAME_:
183 EdkLogger.error("build
", PARAMETER_INVALID, "Invalid build
type [%s]" % FileType,
184 ExtraData="[%s]" % str(self._AutoGenObject))
185 self._FileType = FileType
186 FileContent = self._TEMPLATE_.Replace(self._TemplateDict)
187 FileName = self._FILE_NAME_[FileType]
188 return SaveFileOnChange(os.path.join(self._AutoGenObject.MakeFileDir, FileName), FileContent, False)
190 ## Return a list of directory creation command string
192 # @param DirList The list of directory to be created
194 # @retval list The directory creation command list
196 def GetCreateDirectoryCommand(self, DirList):
197 return [self._MD_TEMPLATE_[self._FileType] % {'dir':Dir} for Dir in DirList]
199 ## Return a list of directory removal command string
201 # @param DirList The list of directory to be removed
203 # @retval list The directory removal command list
205 def GetRemoveDirectoryCommand(self, DirList):
206 return [self._RD_TEMPLATE_[self._FileType] % {'dir':Dir} for Dir in DirList]
208 def PlaceMacro(self, Path, MacroDefinitions=None):
209 if Path.startswith("$
("):
212 if MacroDefinitions is None:
213 MacroDefinitions = {}
214 PathLength = len(Path)
215 for MacroName in MacroDefinitions:
216 MacroValue = MacroDefinitions[MacroName]
217 MacroValueLength = len(MacroValue)
218 if MacroValueLength == 0:
220 if MacroValueLength <= PathLength and Path.startswith(MacroValue):
221 Path = "$
(%s)%s" % (MacroName, Path[MacroValueLength:])
225 ## ModuleMakefile class
227 # This class encapsules makefie and its generation for module. It uses template to generate
228 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
230 class ModuleMakefile(BuildFile):
231 ## template used to generate the makefile for module
232 _TEMPLATE_ = TemplateString('''\
236 # Platform Macro Definition
238 PLATFORM_NAME = ${platform_name}
239 PLATFORM_GUID = ${platform_guid}
240 PLATFORM_VERSION = ${platform_version}
241 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
242 PLATFORM_DIR = ${platform_dir}
243 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
246 # Module Macro Definition
248 MODULE_NAME = ${module_name}
249 MODULE_GUID = ${module_guid}
250 MODULE_NAME_GUID = ${module_name_guid}
251 MODULE_VERSION = ${module_version}
252 MODULE_TYPE = ${module_type}
253 MODULE_FILE = ${module_file}
254 MODULE_FILE_BASE_NAME = ${module_file_base_name}
255 BASE_NAME = $(MODULE_NAME)
256 MODULE_RELATIVE_DIR = ${module_relative_directory}
257 PACKAGE_RELATIVE_DIR = ${package_relative_directory}
258 MODULE_DIR = ${module_dir}
259 FFS_OUTPUT_DIR = ${ffs_output_directory}
261 MODULE_ENTRY_POINT = ${module_entry_point}
262 ARCH_ENTRY_POINT = ${arch_entry_point}
263 IMAGE_ENTRY_POINT = ${image_entry_point}
265 ${BEGIN}${module_extra_defines}
268 # Build Configuration Macro Definition
270 ARCH = ${architecture}
271 TOOLCHAIN = ${toolchain_tag}
272 TOOLCHAIN_TAG = ${toolchain_tag}
273 TARGET = ${build_target}
276 # Build Directory Macro Definition
278 # PLATFORM_BUILD_DIR = ${platform_build_directory}
279 BUILD_DIR = ${platform_build_directory}
280 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
282 MODULE_BUILD_DIR = ${module_build_directory}
283 OUTPUT_DIR = ${module_output_directory}
284 DEBUG_DIR = ${module_debug_directory}
285 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
286 DEST_DIR_DEBUG = $(DEBUG_DIR)
289 # Shell Command Macro
291 ${BEGIN}${shell_command_code} = ${shell_command}
295 # Tools definitions specific to this module
297 ${BEGIN}${module_tool_definitions}
299 MAKE_FILE = ${makefile_path}
304 ${BEGIN}${file_macro}
307 COMMON_DEPS = ${BEGIN}${common_dependency_file} \\
311 # Overridable Target Macro Definitions
313 FORCE_REBUILD = force_build
316 BC_TARGET = ${BEGIN}${backward_compatible_target} ${END}
317 CODA_TARGET = ${BEGIN}${remaining_build_target} \\
321 # Default target, which will build dependent libraries in addition to source files
328 # Target used when called from platform makefile, which will bypass the build of dependent libraries
331 pbuild: $(INIT_TARGET) $(BC_TARGET) $(PCH_TARGET) $(CODA_TARGET)
337 mbuild: $(INIT_TARGET) $(BC_TARGET) gen_libs $(PCH_TARGET) $(CODA_TARGET)
340 # Build Target used in multi-thread build mode, which will bypass the init and gen_libs targets
343 tbuild: $(BC_TARGET) $(PCH_TARGET) $(CODA_TARGET)
346 # Phony target which is used to force executing commands for a target
352 # Target to update the FD
358 # Initialization target: print build information and create necessary directories
363 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
366 ${BEGIN}\t-@${create_directory_command}\n${END}
369 \t-@$(CP) $(DEBUG_DIR)${separator}AutoGen.h $(DEBUG_DIR)${separator}$(MODULE_NAME)StrDefs.h
375 \t${BEGIN}@"$
(MAKE
)" $(MAKE_FLAGS) -f ${dependent_library_build_directory}${separator}${makefile_name}
376 \t${END}@cd $(MODULE_BUILD_DIR)
379 # Build Flash Device Image
382 \t@"$
(MAKE
)" $(MAKE_FLAGS) -f $(BUILD_DIR)${separator}${makefile_name} fds
383 \t@cd $(MODULE_BUILD_DIR)
386 # Individual Object Build Targets
388 ${BEGIN}${file_build_target}
392 # clean all intermediate files
395 \t${BEGIN}${clean_command}
396 \t${END}\t$(RM) AutoGenTimeStamp
399 # clean all generated files
402 ${BEGIN}\t${cleanall_command}
403 ${END}\t$(RM) *.pdb *.idb > NUL 2>&1
404 \t$(RM) $(BIN_DIR)${separator}$(MODULE_NAME).efi
405 \t$(RM) AutoGenTimeStamp
408 # clean all dependent libraries built
411 \t${BEGIN}-@${library_build_command} cleanall
412 \t${END}@cd $(MODULE_BUILD_DIR)\n\n''')
414 _FILE_MACRO_TEMPLATE = TemplateString("${macro_name}
= ${BEGIN}
\\\n ${source_file}${END}
\n")
415 _BUILD_TARGET_TEMPLATE = TemplateString("${BEGIN}${target}
: ${deps}
\n${END}
\t${cmd}
\n")
417 ## Constructor of ModuleMakefile
419 # @param ModuleAutoGen Object of ModuleAutoGen class
421 def __init__(self, ModuleAutoGen):
422 BuildFile.__init__(self, ModuleAutoGen)
423 self.PlatformInfo = self._AutoGenObject.PlatformInfo
425 self.ResultFileList = []
426 self.IntermediateDirectoryList = ["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]
428 self.FileBuildTargetList = [] # [(src, target string)]
429 self.BuildTargetList = [] # [target string]
430 self.PendingBuildTargetList = [] # [FileBuildRule objects]
431 self.CommonFileDependency = []
432 self.FileListMacros = {}
433 self.ListFileMacros = {}
434 self.ObjTargetDict = OrderedDict()
436 self.LibraryBuildCommandList = []
437 self.LibraryFileList = []
438 self.LibraryMakefileList = []
439 self.LibraryBuildDirectoryList = []
440 self.SystemLibraryList = []
441 self.Macros = OrderedDict()
442 self.Macros["OUTPUT_DIR
" ] = self._AutoGenObject.Macros["OUTPUT_DIR
"]
443 self.Macros["DEBUG_DIR
" ] = self._AutoGenObject.Macros["DEBUG_DIR
"]
444 self.Macros["MODULE_BUILD_DIR
"] = self._AutoGenObject.Macros["MODULE_BUILD_DIR
"]
445 self.Macros["BIN_DIR
" ] = self._AutoGenObject.Macros["BIN_DIR
"]
446 self.Macros["BUILD_DIR
" ] = self._AutoGenObject.Macros["BUILD_DIR
"]
447 self.Macros["WORKSPACE
" ] = self._AutoGenObject.Macros["WORKSPACE
"]
448 self.Macros["FFS_OUTPUT_DIR
" ] = self._AutoGenObject.Macros["FFS_OUTPUT_DIR
"]
449 self.GenFfsList = ModuleAutoGen.GenFfsList
450 self.MacroList = ['FFS_OUTPUT_DIR', 'MODULE_GUID', 'OUTPUT_DIR']
451 self.FfsOutputFileList = []
452 self.DependencyHeaderFileSet = set()
454 # Compose a dict object containing information used to do replacement in template
456 def _TemplateDict(self):
457 if self._FileType not in self._SEP_:
458 EdkLogger.error("build
", PARAMETER_INVALID, "Invalid Makefile
type [%s]" % self._FileType,
459 ExtraData="[%s]" % str(self._AutoGenObject))
460 MyAgo = self._AutoGenObject
461 Separator = self._SEP_[self._FileType]
463 # break build if no source files and binary files are found
464 if len(MyAgo.SourceFileList) == 0 and len(MyAgo.BinaryFileList) == 0:
465 EdkLogger.error("build
", AUTOGEN_ERROR, "No files to be built
in module
[%s, %s, %s]"
466 % (MyAgo.BuildTarget, MyAgo.ToolChain, MyAgo.Arch),
467 ExtraData="[%s]" % str(MyAgo))
469 # convert dependent libraries to build command
470 self.ProcessDependentLibrary()
471 if len(MyAgo.Module.ModuleEntryPointList) > 0:
472 ModuleEntryPoint = MyAgo.Module.ModuleEntryPointList[0]
474 ModuleEntryPoint = "_ModuleEntryPoint
"
476 ArchEntryPoint = ModuleEntryPoint
478 if MyAgo.Arch == "EBC
":
479 # EBC compiler always use "EfiStart
" as entry point. Only applies to EdkII modules
480 ImageEntryPoint = "EfiStart
"
482 # EdkII modules always use "_ModuleEntryPoint
" as entry point
483 ImageEntryPoint = "_ModuleEntryPoint
"
485 for k, v in MyAgo.Module.Defines.items():
486 if k not in MyAgo.Macros:
489 if 'MODULE_ENTRY_POINT' not in MyAgo.Macros:
490 MyAgo.Macros['MODULE_ENTRY_POINT'] = ModuleEntryPoint
491 if 'ARCH_ENTRY_POINT' not in MyAgo.Macros:
492 MyAgo.Macros['ARCH_ENTRY_POINT'] = ArchEntryPoint
493 if 'IMAGE_ENTRY_POINT' not in MyAgo.Macros:
494 MyAgo.Macros['IMAGE_ENTRY_POINT'] = ImageEntryPoint
496 PCI_COMPRESS_Flag = False
497 for k, v in MyAgo.Module.Defines.items():
498 if 'PCI_COMPRESS' == k and 'TRUE' == v:
499 PCI_COMPRESS_Flag = True
503 IncPrefix = self._INC_FLAG_[MyAgo.ToolChainFamily]
504 for Tool in MyAgo.BuildOption:
505 for Attr in MyAgo.BuildOption[Tool]:
506 Value = MyAgo.BuildOption[Tool][Attr]
510 ToolsDef.append("%s = %s" % (Tool, Value))
512 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
515 # Remove duplicated include path, if any
517 Value = RemoveDupOption(Value, IncPrefix, MyAgo.IncludePathList)
518 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Tool == 'CC' and '/GM' in Value:
519 Value = Value.replace(' /MP', '')
520 MyAgo.BuildOption[Tool][Attr] = Value
521 if Tool == "OPTROM
" and PCI_COMPRESS_Flag:
522 ValueList = Value.split()
524 for i, v in enumerate(ValueList):
527 Value = ' '.join(ValueList)
529 ToolsDef.append("%s_%s = %s" % (Tool, Attr, Value))
532 # generate the Response file and Response flag
533 RespDict = self.CommandExceedLimit()
534 RespFileList = os.path.join(MyAgo.OutputDir, 'respfilelist.txt')
536 RespFileListContent = ''
537 for Resp in RespDict:
538 RespFile = os.path.join(MyAgo.OutputDir, str(Resp).lower() + '.txt')
539 StrList = RespDict[Resp].split(' ')
544 UnexpandMacro.append(Str)
547 UnexpandMacroStr = ' '.join(UnexpandMacro)
548 NewRespStr = ' '.join(NewStr)
549 SaveFileOnChange(RespFile, NewRespStr, False)
550 ToolsDef.append("%s = %s" % (Resp, UnexpandMacroStr + ' @' + RespFile))
551 RespFileListContent += '@' + RespFile + TAB_LINE_BREAK
552 RespFileListContent += NewRespStr + TAB_LINE_BREAK
553 SaveFileOnChange(RespFileList, RespFileListContent, False)
555 if os.path.exists(RespFileList):
556 os.remove(RespFileList)
558 # convert source files and binary files to build targets
559 self.ResultFileList = [str(T.Target) for T in MyAgo.CodaTargetList]
560 if len(self.ResultFileList) == 0 and len(MyAgo.SourceFileList) != 0:
561 EdkLogger.error("build
", AUTOGEN_ERROR, "Nothing to build
",
562 ExtraData="[%s]" % str(MyAgo))
564 self.ProcessBuildTargetList()
565 self.ParserGenerateFfsCmd()
567 # Generate macros used to represent input files
568 FileMacroList = [] # macro name = file list
569 for FileListMacro in self.FileListMacros:
570 FileMacro = self._FILE_MACRO_TEMPLATE.Replace(
572 "macro_name
" : FileListMacro,
573 "source_file
" : self.FileListMacros[FileListMacro]
576 FileMacroList.append(FileMacro)
578 # INC_LIST is special
581 for P in MyAgo.IncludePathList:
582 IncludePathList.append(IncPrefix + self.PlaceMacro(P, self.Macros))
583 if FileBuildRule.INC_LIST_MACRO in self.ListFileMacros:
584 self.ListFileMacros[FileBuildRule.INC_LIST_MACRO].append(IncPrefix + P)
585 FileMacro += self._FILE_MACRO_TEMPLATE.Replace(
587 "macro_name
" : "INC
",
588 "source_file
" : IncludePathList
591 FileMacroList.append(FileMacro)
592 # Add support when compiling .nasm source files
593 for File in self.FileCache.keys():
594 if not str(File).endswith('.nasm'):
597 for P in MyAgo.IncludePathList:
598 IncludePath = self._INC_FLAG_['NASM'] + self.PlaceMacro(P, self.Macros)
599 if IncludePath.endswith(os.sep):
600 IncludePath = IncludePath.rstrip(os.sep)
601 # When compiling .nasm files, need to add a literal backslash at each path
602 # To specify a literal backslash at the end of the line, precede it with a caret (^)
603 if P == MyAgo.IncludePathList[-1] and os.sep == '\\':
604 IncludePath = ''.join([IncludePath, '^', os.sep])
606 IncludePath = os.path.join(IncludePath, '')
607 IncludePathList.append(IncludePath)
608 FileMacroList.append(self._FILE_MACRO_TEMPLATE.Replace({"macro_name
": "NASM_INC
", "source_file
": IncludePathList}))
611 # Generate macros used to represent files containing list of input files
612 for ListFileMacro in self.ListFileMacros:
613 ListFileName = os.path.join(MyAgo.OutputDir, "%s.lst
" % ListFileMacro.lower()[:len(ListFileMacro) - 5])
614 FileMacroList.append("%s = %s" % (ListFileMacro, ListFileName))
617 "\n".join(self.ListFileMacros[ListFileMacro]),
621 # Generate objlist used to create .obj file
622 for Type in self.ObjTargetDict:
623 NewLine = ' '.join(list(self.ObjTargetDict[Type]))
624 FileMacroList.append("OBJLIST_
%s = %s" % (list(self.ObjTargetDict.keys()).index(Type), NewLine))
628 MakefileName = self._FILE_NAME_[self._FileType]
629 LibraryMakeCommandList = []
630 for D in self.LibraryBuildDirectoryList:
631 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join(D, MakefileName)}
632 LibraryMakeCommandList.append(Command)
634 package_rel_dir = MyAgo.SourceDir
635 current_dir = self.Macros["WORKSPACE
"]
637 while not found and os.sep in package_rel_dir:
638 index = package_rel_dir.index(os.sep)
639 current_dir = mws.join(current_dir, package_rel_dir[:index])
640 if os.path.exists(current_dir):
641 for fl in os.listdir(current_dir):
642 if fl.endswith('.dec'):
645 package_rel_dir = package_rel_dir[index + 1:]
647 MakefileTemplateDict = {
648 "makefile_header
" : self._FILE_HEADER_[self._FileType],
649 "makefile_path
" : os.path.join("$
(MODULE_BUILD_DIR
)", MakefileName),
650 "makefile_name
" : MakefileName,
651 "platform_name
" : self.PlatformInfo.Name,
652 "platform_guid
" : self.PlatformInfo.Guid,
653 "platform_version
" : self.PlatformInfo.Version,
654 "platform_relative_directory
": self.PlatformInfo.SourceDir,
655 "platform_output_directory
" : self.PlatformInfo.OutputDir,
656 "ffs_output_directory
" : MyAgo.Macros["FFS_OUTPUT_DIR
"],
657 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
659 "module_name
" : MyAgo.Name,
660 "module_guid
" : MyAgo.Guid,
661 "module_name_guid
" : MyAgo.UniqueBaseName,
662 "module_version
" : MyAgo.Version,
663 "module_type
" : MyAgo.ModuleType,
664 "module_file
" : MyAgo.MetaFile.Name,
665 "module_file_base_name
" : MyAgo.MetaFile.BaseName,
666 "module_relative_directory
" : MyAgo.SourceDir,
667 "module_dir
" : mws.join (self.Macros["WORKSPACE
"], MyAgo.SourceDir),
668 "package_relative_directory
": package_rel_dir,
669 "module_extra_defines
" : ["%s = %s" % (k, v) for k, v in MyAgo.Module.Defines.items()],
671 "architecture
" : MyAgo.Arch,
672 "toolchain_tag
" : MyAgo.ToolChain,
673 "build_target
" : MyAgo.BuildTarget,
675 "platform_build_directory
" : self.PlatformInfo.BuildDir,
676 "module_build_directory
" : MyAgo.BuildDir,
677 "module_output_directory
" : MyAgo.OutputDir,
678 "module_debug_directory
" : MyAgo.DebugDir,
680 "separator
" : Separator,
681 "module_tool_definitions
" : ToolsDef,
683 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
684 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
686 "module_entry_point
" : ModuleEntryPoint,
687 "image_entry_point
" : ImageEntryPoint,
688 "arch_entry_point
" : ArchEntryPoint,
689 "remaining_build_target
" : self.ResultFileList,
690 "common_dependency_file
" : self.CommonFileDependency,
691 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
692 "clean_command
" : self.GetRemoveDirectoryCommand(["$
(OUTPUT_DIR
)"]),
693 "cleanall_command
" : self.GetRemoveDirectoryCommand(["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]),
694 "dependent_library_build_directory
" : self.LibraryBuildDirectoryList,
695 "library_build_command
" : LibraryMakeCommandList,
696 "file_macro
" : FileMacroList,
697 "file_build_target
" : self.BuildTargetList,
698 "backward_compatible_target
": BcTargetList,
701 return MakefileTemplateDict
703 def ParserGenerateFfsCmd(self):
704 #Add Ffs cmd to self.BuildTargetList
708 for Cmd in self.GenFfsList:
710 for CopyCmd in Cmd[2]:
712 Src = self.ReplaceMacro(Src)
713 Dst = self.ReplaceMacro(Dst)
714 if Dst not in self.ResultFileList:
715 self.ResultFileList.append(Dst)
716 if '%s :' %(Dst) not in self.BuildTargetList:
717 self.BuildTargetList.append("%s :" %(Dst))
718 self.BuildTargetList.append('\t' + self._CP_TEMPLATE_[self._FileType] %{'Src': Src, 'Dst': Dst})
721 for index, Str in enumerate(FfsCmdList):
723 OutputFile = FfsCmdList[index + 1]
724 if '-i' == Str or "-oi
" == Str:
725 if DepsFileList == []:
726 DepsFileList = [FfsCmdList[index + 1]]
728 DepsFileList.append(FfsCmdList[index + 1])
729 DepsFileString = ' '.join(DepsFileList).strip()
730 if DepsFileString == '':
732 OutputFile = self.ReplaceMacro(OutputFile)
733 self.ResultFileList.append(OutputFile)
734 DepsFileString = self.ReplaceMacro(DepsFileString)
735 self.BuildTargetList.append('%s : %s' % (OutputFile, DepsFileString))
736 CmdString = ' '.join(FfsCmdList).strip()
737 CmdString = self.ReplaceMacro(CmdString)
738 self.BuildTargetList.append('\t%s' % CmdString)
740 self.ParseSecCmd(DepsFileList, Cmd[1])
741 for SecOutputFile, SecDepsFile, SecCmd in self.FfsOutputFileList :
742 self.BuildTargetList.append('%s : %s' % (self.ReplaceMacro(SecOutputFile), self.ReplaceMacro(SecDepsFile)))
743 self.BuildTargetList.append('\t%s' % self.ReplaceMacro(SecCmd))
744 self.FfsOutputFileList = []
746 def ParseSecCmd(self, OutputFileList, CmdTuple):
747 for OutputFile in OutputFileList:
748 for SecCmdStr in CmdTuple:
750 SecCmdList = SecCmdStr.split()
751 CmdName = SecCmdList[0]
752 for index, CmdItem in enumerate(SecCmdList):
753 if '-o' == CmdItem and OutputFile == SecCmdList[index + 1]:
755 while index + 1 < len(SecCmdList):
756 if not SecCmdList[index+1].startswith('-'):
757 SecDepsFileList.append(SecCmdList[index + 1])
759 if CmdName == 'Trim':
760 SecDepsFileList.append(os.path.join('$(DEBUG_DIR)', os.path.basename(OutputFile).replace('offset', 'efi')))
761 if OutputFile.endswith('.ui') or OutputFile.endswith('.ver'):
762 SecDepsFileList.append(os.path.join('$(MODULE_DIR)', '$(MODULE_FILE)'))
763 self.FfsOutputFileList.append((OutputFile, ' '.join(SecDepsFileList), SecCmdStr))
764 if len(SecDepsFileList) > 0:
765 self.ParseSecCmd(SecDepsFileList, CmdTuple)
770 def ReplaceMacro(self, str):
771 for Macro in self.MacroList:
772 if self._AutoGenObject.Macros[Macro] and self._AutoGenObject.Macros[Macro] in str:
773 str = str.replace(self._AutoGenObject.Macros[Macro], '$(' + Macro + ')')
776 def CommandExceedLimit(self):
778 'CC' : { 'Macro' : '$(CC_FLAGS)', 'Value' : False},
779 'PP' : { 'Macro' : '$(PP_FLAGS)', 'Value' : False},
780 'APP' : { 'Macro' : '$(APP_FLAGS)', 'Value' : False},
781 'ASLPP' : { 'Macro' : '$(ASLPP_FLAGS)', 'Value' : False},
782 'VFRPP' : { 'Macro' : '$(VFRPP_FLAGS)', 'Value' : False},
783 'ASM' : { 'Macro' : '$(ASM_FLAGS)', 'Value' : False},
784 'ASLCC' : { 'Macro' : '$(ASLCC_FLAGS)', 'Value' : False},
789 IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily]
791 # base on the source files to decide the file type
792 for File in self._AutoGenObject.SourceFileList:
793 for type in self._AutoGenObject.FileTypes:
794 if File in self._AutoGenObject.FileTypes[type]:
795 if type not in FileTypeList:
796 FileTypeList.append(type)
798 # calculate the command-line length
800 for type in FileTypeList:
801 BuildTargets = self._AutoGenObject.BuildRules[type].BuildTargets
802 for Target in BuildTargets:
803 CommandList = BuildTargets[Target].Commands
804 for SingleCommand in CommandList:
806 SingleCommandLength = len(SingleCommand)
807 SingleCommandList = SingleCommand.split()
808 if len(SingleCommandList) > 0:
809 for Flag in FlagDict:
810 if '$('+ Flag +')' in SingleCommandList[0]:
814 if 'PATH' not in self._AutoGenObject.BuildOption[Tool]:
815 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))
816 SingleCommandLength += len(self._AutoGenObject.BuildOption[Tool]['PATH
'])
817 for item in SingleCommandList[1:]:
818 if FlagDict[Tool]['Macro
'] in item:
819 if 'FLAGS
' not in self._AutoGenObject.BuildOption[Tool]:
820 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))
821 Str = self._AutoGenObject.BuildOption[Tool]['FLAGS']
822 for Option in self._AutoGenObject.BuildOption:
823 for Attr in self._AutoGenObject.BuildOption[Option]:
824 if Str.find(Option + '_' + Attr) != -1:
825 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
826 while(Str.find('$(') != -1):
827 for macro in self._AutoGenObject.Macros:
828 MacroName = '$('+ macro + ')'
829 if (Str.find(MacroName) != -1):
830 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
834 SingleCommandLength += len(Str)
835 elif '$(INC)' in item:
836 SingleCommandLength += self._AutoGenObject.IncludePathLength + len(IncPrefix) * len(self._AutoGenObject.IncludePathList)
837 elif item.find('$(') != -1:
839 for Option in self._AutoGenObject.BuildOption:
840 for Attr in self._AutoGenObject.BuildOption[Option]:
841 if Str.find(Option + '_' + Attr) != -1:
842 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
843 while(Str.find('$(') != -1):
844 for macro in self._AutoGenObject.Macros:
845 MacroName = '$('+ macro + ')'
846 if (Str.find(MacroName) != -1):
847 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
851 SingleCommandLength += len(Str)
853 if SingleCommandLength > GlobalData.gCommandMaxLength:
854 FlagDict[Tool]['Value'] = True
856 # generate the response file content by combine the FLAGS and INC
857 for Flag in FlagDict:
858 if FlagDict[Flag]['Value']:
860 RespMacro = FlagDict[Flag]['Macro'].replace('FLAGS', 'RESP')
861 Value = self._AutoGenObject.BuildOption[Flag]['FLAGS']
862 for inc in self._AutoGenObject.IncludePathList:
863 Value += ' ' + IncPrefix + inc
864 for Option in self._AutoGenObject.BuildOption:
865 for Attr in self._AutoGenObject.BuildOption[Option]:
866 if Value.find(Option + '_' + Attr) != -1:
867 Value = Value.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
868 while (Value.find('$(') != -1):
869 for macro in self._AutoGenObject.Macros:
870 MacroName = '$('+ macro + ')'
871 if (Value.find(MacroName) != -1):
872 Value = Value.replace(MacroName, self._AutoGenObject.Macros[macro])
877 if self._AutoGenObject.ToolChainFamily == 'GCC':
878 RespDict[Key] = Value.replace('\\', '/')
880 RespDict[Key] = Value
881 for Target in BuildTargets:
882 for i, SingleCommand in enumerate(BuildTargets[Target].Commands):
883 if FlagDict[Flag]['Macro'] in SingleCommand:
884 BuildTargets[Target].Commands[i] = SingleCommand.replace('$(INC)', '').replace(FlagDict[Flag]['Macro'], RespMacro)
887 def ProcessBuildTargetList(self):
889 # Search dependency file list for each source file
891 ForceIncludedFile = []
892 for File in self._AutoGenObject.AutoGenFileList:
894 ForceIncludedFile.append(File)
897 for Target in self._AutoGenObject.IntroTargetList:
898 SourceFileList.extend(Target.Inputs)
899 OutPutFileList.extend(Target.Outputs)
902 for Item in OutPutFileList:
903 if Item in SourceFileList:
904 SourceFileList.remove(Item)
906 FileDependencyDict = self.GetFileDependency(
909 self._AutoGenObject.IncludePathList + self._AutoGenObject.BuildOptionIncPathList
913 if FileDependencyDict:
914 for Dependency in FileDependencyDict.values():
915 self.DependencyHeaderFileSet.update(set(Dependency))
917 # Get a set of unique package includes from MetaFile
918 parentMetaFileIncludes = set()
919 for aInclude in self._AutoGenObject.PackageIncludePathList:
920 aIncludeName = str(aInclude)
921 parentMetaFileIncludes.add(aIncludeName.lower())
923 # Check if header files are listed in metafile
924 # Get a set of unique module header source files from MetaFile
925 headerFilesInMetaFileSet = set()
926 for aFile in self._AutoGenObject.SourceFileList:
927 aFileName = str(aFile)
928 if not aFileName.endswith('.h'):
930 headerFilesInMetaFileSet.add(aFileName.lower())
932 # Get a set of unique module autogen files
933 localAutoGenFileSet = set()
934 for aFile in self._AutoGenObject.AutoGenFileList:
935 localAutoGenFileSet.add(str(aFile).lower())
937 # Get a set of unique module dependency header files
938 # Exclude autogen files and files not in the source directory
939 # and files that are under the package include list
940 headerFileDependencySet = set()
941 localSourceDir = str(self._AutoGenObject.SourceDir).lower()
942 for Dependency in FileDependencyDict.values():
943 for aFile in Dependency:
944 aFileName = str(aFile).lower()
945 # Exclude non-header files
946 if not aFileName.endswith('.h'):
948 # Exclude autogen files
949 if aFileName in localAutoGenFileSet:
951 # Exclude include out of local scope
952 if localSourceDir not in aFileName:
954 # Exclude files covered by package includes
956 for aIncludePath in parentMetaFileIncludes:
957 if aIncludePath in aFileName:
962 # Keep the file to be checked
963 headerFileDependencySet.add(aFileName)
965 # Check if a module dependency header file is missing from the module's MetaFile
966 for aFile in headerFileDependencySet:
967 if aFile in headerFilesInMetaFileSet:
969 if GlobalData.gUseHashCache:
970 GlobalData.gModuleBuildTracking[self._AutoGenObject] = 'FAIL_METAFILE'
971 EdkLogger.warn("build
","Module MetaFile
[Sources
] is missing local header
!",
972 ExtraData = "Local Header
: " + aFile + " not found
in " + self._AutoGenObject.MetaFile.Path
976 for File,Dependency in FileDependencyDict.items():
978 FileDependencyDict[File] = ['$(FORCE_REBUILD)']
981 self._AutoGenObject.AutoGenDepSet |= set(Dependency)
984 if File.Ext not in [".c
", ".C
"] or File.Name == "AutoGen
.c
":
987 DepSet = set(Dependency)
989 DepSet &= set(Dependency)
990 # in case nothing in SourceFileList
994 # Extract common files list in the dependency files
997 self.CommonFileDependency.append(self.PlaceMacro(File.Path, self.Macros))
1002 DependencyDict = FileDependencyDict.copy()
1003 for File in FileDependencyDict:
1005 if File.Ext not in [".c
", ".C
"] or File.Name == "AutoGen
.c
":
1007 NewDepSet = set(FileDependencyDict[File])
1009 FileDependencyDict[File] = ["$
(COMMON_DEPS
)"] + list(NewDepSet)
1010 DependencyDict[File] = list(NewDepSet)
1012 # Convert target description object to target string in makefile
1013 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and TAB_C_CODE_FILE in self._AutoGenObject.Targets:
1014 for T in self._AutoGenObject.Targets[TAB_C_CODE_FILE]:
1015 NewFile = self.PlaceMacro(str(T), self.Macros)
1016 if not self.ObjTargetDict.get(T.Target.SubDir):
1017 self.ObjTargetDict[T.Target.SubDir] = set()
1018 self.ObjTargetDict[T.Target.SubDir].add(NewFile)
1019 for Type in self._AutoGenObject.Targets:
1020 for T in self._AutoGenObject.Targets[Type]:
1021 # Generate related macros if needed
1022 if T.GenFileListMacro and T.FileListMacro not in self.FileListMacros:
1023 self.FileListMacros[T.FileListMacro] = []
1024 if T.GenListFile and T.ListFileMacro not in self.ListFileMacros:
1025 self.ListFileMacros[T.ListFileMacro] = []
1026 if T.GenIncListFile and T.IncListFileMacro not in self.ListFileMacros:
1027 self.ListFileMacros[T.IncListFileMacro] = []
1031 # Add force-dependencies
1032 for Dep in T.Dependencies:
1033 Deps.append(self.PlaceMacro(str(Dep), self.Macros))
1034 if Dep != '$(MAKE_FILE)':
1035 CCodeDeps.append(self.PlaceMacro(str(Dep), self.Macros))
1036 # Add inclusion-dependencies
1037 if len(T.Inputs) == 1 and T.Inputs[0] in FileDependencyDict:
1038 for F in FileDependencyDict[T.Inputs[0]]:
1039 Deps.append(self.PlaceMacro(str(F), self.Macros))
1040 # Add source-dependencies
1042 NewFile = self.PlaceMacro(str(F), self.Macros)
1043 # In order to use file list macro as dependency
1045 # gnu tools need forward slash path separator, even on Windows
1046 self.ListFileMacros[T.ListFileMacro].append(str(F).replace ('\\', '/'))
1047 self.FileListMacros[T.FileListMacro].append(NewFile)
1048 elif T.GenFileListMacro:
1049 self.FileListMacros[T.FileListMacro].append(NewFile)
1051 Deps.append(NewFile)
1052 for key in self.FileListMacros:
1053 self.FileListMacros[key].sort()
1054 # Use file list macro as dependency
1055 if T.GenFileListMacro:
1056 Deps.append("$
(%s)" % T.FileListMacro)
1057 if Type in [TAB_OBJECT_FILE, TAB_STATIC_LIBRARY]:
1058 Deps.append("$
(%s)" % T.ListFileMacro)
1060 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Type == TAB_C_CODE_FILE:
1061 T, CmdTarget, CmdTargetDict, CmdCppDict = self.ParserCCodeFile(T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict)
1062 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": CCodeDeps}
1063 CmdLine = self._BUILD_TARGET_TEMPLATE.Replace(TargetDict).rstrip().replace('\t$(OBJLIST', '$(OBJLIST')
1065 CmdLine = '%s%s' %(CmdLine, TAB_LINE_BREAK)
1066 if CCodeDeps or CmdLine:
1067 self.BuildTargetList.append(CmdLine)
1069 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": Deps}
1070 self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(TargetDict))
1072 def ParserCCodeFile(self, T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict):
1074 for item in self._AutoGenObject.Targets[Type]:
1075 CmdSumDict[item.Target.SubDir] = item.Target.BaseName
1076 for CppPath in item.Inputs:
1077 Path = self.PlaceMacro(CppPath.Path, self.Macros)
1078 if CmdCppDict.get(item.Target.SubDir):
1079 CmdCppDict[item.Target.SubDir].append(Path)
1081 CmdCppDict[item.Target.SubDir] = ['$(MAKE_FILE)', Path]
1082 if CppPath.Path in DependencyDict:
1083 if '$(FORCE_REBUILD)' in DependencyDict[CppPath.Path]:
1084 if '$(FORCE_REBUILD)' not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):
1085 CmdCppDict[item.Target.SubDir].append('$(FORCE_REBUILD)')
1087 for Temp in DependencyDict[CppPath.Path]:
1089 Path = self.PlaceMacro(Temp.Path, self.Macros)
1092 if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):
1093 CmdCppDict[item.Target.SubDir].append(Path)
1095 CommandList = T.Commands[:]
1096 for Item in CommandList[:]:
1097 SingleCommandList = Item.split()
1098 if len(SingleCommandList) > 0 and self.CheckCCCmd(SingleCommandList):
1099 for Temp in SingleCommandList:
1100 if Temp.startswith('/Fo'):
1101 CmdSign = '%s%s' % (Temp.rsplit(TAB_SLASH, 1)[0], TAB_SLASH)
1104 if CmdSign not in list(CmdTargetDict.keys()):
1105 CmdTargetDict[CmdSign] = Item.replace(Temp, CmdSign)
1107 CmdTargetDict[CmdSign] = "%s %s" % (CmdTargetDict[CmdSign], SingleCommandList[-1])
1108 Index = CommandList.index(Item)
1109 CommandList.pop(Index)
1110 if SingleCommandList[-1].endswith("%s%s.c
" % (TAB_SLASH, CmdSumDict[CmdSign[3:].rsplit(TAB_SLASH, 1)[0]])):
1111 Cpplist = CmdCppDict[T.Target.SubDir]
1112 Cpplist.insert(0, '$(OBJLIST_%d): $(COMMON_DEPS)' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir))
1113 T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign])
1115 T.Commands.pop(Index)
1116 return T, CmdSumDict, CmdTargetDict, CmdCppDict
1118 def CheckCCCmd(self, CommandList):
1119 for cmd in CommandList:
1123 ## For creating makefile targets for dependent libraries
1124 def ProcessDependentLibrary(self):
1125 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1126 if not LibraryAutoGen.IsBinaryModule:
1127 self.LibraryBuildDirectoryList.append(self.PlaceMacro(LibraryAutoGen.BuildDir, self.Macros))
1129 ## Return a list containing source file's dependencies
1131 # @param FileList The list of source files
1132 # @param ForceInculeList The list of files which will be included forcely
1133 # @param SearchPathList The list of search path
1135 # @retval dict The mapping between source file path and its dependencies
1137 def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):
1140 Dependency[F] = GetDependencyList(self._AutoGenObject, self.FileCache, F, ForceInculeList, SearchPathList)
1144 ## CustomMakefile class
1146 # This class encapsules makefie and its generation for module. It uses template to generate
1147 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
1149 class CustomMakefile(BuildFile):
1150 ## template used to generate the makefile for module with custom makefile
1151 _TEMPLATE_ = TemplateString('''\
1155 # Platform Macro Definition
1157 PLATFORM_NAME = ${platform_name}
1158 PLATFORM_GUID = ${platform_guid}
1159 PLATFORM_VERSION = ${platform_version}
1160 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
1161 PLATFORM_DIR = ${platform_dir}
1162 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1165 # Module Macro Definition
1167 MODULE_NAME = ${module_name}
1168 MODULE_GUID = ${module_guid}
1169 MODULE_NAME_GUID = ${module_name_guid}
1170 MODULE_VERSION = ${module_version}
1171 MODULE_TYPE = ${module_type}
1172 MODULE_FILE = ${module_file}
1173 MODULE_FILE_BASE_NAME = ${module_file_base_name}
1174 BASE_NAME = $(MODULE_NAME)
1175 MODULE_RELATIVE_DIR = ${module_relative_directory}
1176 MODULE_DIR = ${module_dir}
1179 # Build Configuration Macro Definition
1181 ARCH = ${architecture}
1182 TOOLCHAIN = ${toolchain_tag}
1183 TOOLCHAIN_TAG = ${toolchain_tag}
1184 TARGET = ${build_target}
1187 # Build Directory Macro Definition
1189 # PLATFORM_BUILD_DIR = ${platform_build_directory}
1190 BUILD_DIR = ${platform_build_directory}
1191 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
1192 LIB_DIR = $(BIN_DIR)
1193 MODULE_BUILD_DIR = ${module_build_directory}
1194 OUTPUT_DIR = ${module_output_directory}
1195 DEBUG_DIR = ${module_debug_directory}
1196 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
1197 DEST_DIR_DEBUG = $(DEBUG_DIR)
1200 # Tools definitions specific to this module
1202 ${BEGIN}${module_tool_definitions}
1204 MAKE_FILE = ${makefile_path}
1207 # Shell Command Macro
1209 ${BEGIN}${shell_command_code} = ${shell_command}
1212 ${custom_makefile_content}
1215 # Target used when called from platform makefile, which will bypass the build of dependent libraries
1228 # Build Target used in multi-thread build mode, which no init target is needed
1234 # Initialization target: print build information and create necessary directories
1237 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
1238 ${BEGIN}\t-@${create_directory_command}\n${END}\
1242 ## Constructor of CustomMakefile
1244 # @param ModuleAutoGen Object of ModuleAutoGen class
1246 def __init__(self, ModuleAutoGen):
1247 BuildFile.__init__(self, ModuleAutoGen)
1248 self.PlatformInfo = self._AutoGenObject.PlatformInfo
1249 self.IntermediateDirectoryList = ["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]
1250 self.DependencyHeaderFileSet = set()
1252 # Compose a dict object containing information used to do replacement in template
1254 def _TemplateDict(self):
1255 Separator = self._SEP_[self._FileType]
1256 MyAgo = self._AutoGenObject
1257 if self._FileType not in MyAgo.CustomMakefile:
1258 EdkLogger.error('build', OPTION_NOT_SUPPORTED, "No custom makefile
for %s" % self._FileType,
1259 ExtraData="[%s]" % str(MyAgo))
1260 MakefilePath = mws.join(
1262 MyAgo.CustomMakefile[self._FileType]
1265 CustomMakefile = open(MakefilePath, 'r').read()
1267 EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(MyAgo),
1268 ExtraData=MyAgo.CustomMakefile[self._FileType])
1272 for Tool in MyAgo.BuildOption:
1273 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
1276 for Attr in MyAgo.BuildOption[Tool]:
1277 if Attr == "FAMILY
":
1279 elif Attr == "PATH
":
1280 ToolsDef.append("%s = %s" % (Tool, MyAgo.BuildOption[Tool][Attr]))
1282 ToolsDef.append("%s_%s = %s" % (Tool, Attr, MyAgo.BuildOption[Tool][Attr]))
1285 MakefileName = self._FILE_NAME_[self._FileType]
1286 MakefileTemplateDict = {
1287 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1288 "makefile_path
" : os.path.join("$
(MODULE_BUILD_DIR
)", MakefileName),
1289 "platform_name
" : self.PlatformInfo.Name,
1290 "platform_guid
" : self.PlatformInfo.Guid,
1291 "platform_version
" : self.PlatformInfo.Version,
1292 "platform_relative_directory
": self.PlatformInfo.SourceDir,
1293 "platform_output_directory
" : self.PlatformInfo.OutputDir,
1294 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1296 "module_name
" : MyAgo.Name,
1297 "module_guid
" : MyAgo.Guid,
1298 "module_name_guid
" : MyAgo.UniqueBaseName,
1299 "module_version
" : MyAgo.Version,
1300 "module_type
" : MyAgo.ModuleType,
1301 "module_file
" : MyAgo.MetaFile,
1302 "module_file_base_name
" : MyAgo.MetaFile.BaseName,
1303 "module_relative_directory
" : MyAgo.SourceDir,
1304 "module_dir
" : mws.join (MyAgo.WorkspaceDir, MyAgo.SourceDir),
1306 "architecture
" : MyAgo.Arch,
1307 "toolchain_tag
" : MyAgo.ToolChain,
1308 "build_target
" : MyAgo.BuildTarget,
1310 "platform_build_directory
" : self.PlatformInfo.BuildDir,
1311 "module_build_directory
" : MyAgo.BuildDir,
1312 "module_output_directory
" : MyAgo.OutputDir,
1313 "module_debug_directory
" : MyAgo.DebugDir,
1315 "separator
" : Separator,
1316 "module_tool_definitions
" : ToolsDef,
1318 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1319 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1321 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1322 "custom_makefile_content
" : CustomMakefile
1325 return MakefileTemplateDict
1327 ## PlatformMakefile class
1329 # This class encapsules makefie and its generation for platform. It uses
1330 # template to generate the content of makefile. The content of makefile will be
1331 # got from PlatformAutoGen object.
1333 class PlatformMakefile(BuildFile):
1334 ## template used to generate the makefile for platform
1335 _TEMPLATE_ = TemplateString('''\
1339 # Platform Macro Definition
1341 PLATFORM_NAME = ${platform_name}
1342 PLATFORM_GUID = ${platform_guid}
1343 PLATFORM_VERSION = ${platform_version}
1344 PLATFORM_FILE = ${platform_file}
1345 PLATFORM_DIR = ${platform_dir}
1346 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1349 # Build Configuration Macro Definition
1351 TOOLCHAIN = ${toolchain_tag}
1352 TOOLCHAIN_TAG = ${toolchain_tag}
1353 TARGET = ${build_target}
1356 # Build Directory Macro Definition
1358 BUILD_DIR = ${platform_build_directory}
1359 FV_DIR = ${platform_build_directory}${separator}FV
1362 # Shell Command Macro
1364 ${BEGIN}${shell_command_code} = ${shell_command}
1368 MAKE_FILE = ${makefile_path}
1373 all: init build_libraries build_modules
1376 # Initialization target: print build information and create necessary directories
1379 \t-@echo Building ... $(PLATFORM_FILE) [${build_architecture_list}]
1380 \t${BEGIN}-@${create_directory_command}
1383 # library build target
1385 libraries: init build_libraries
1388 # module build target
1390 modules: init build_libraries build_modules
1393 # Build all libraries:
1396 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${library_makefile_list} pbuild
1397 ${END}\t@cd $(BUILD_DIR)
1400 # Build all modules:
1403 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${module_makefile_list} pbuild
1404 ${END}\t@cd $(BUILD_DIR)
1407 # Clean intermediate files
1410 \t${BEGIN}-@${library_build_command} clean
1411 \t${END}${BEGIN}-@${module_build_command} clean
1412 \t${END}@cd $(BUILD_DIR)
1415 # Clean all generated files except to makefile
1418 ${BEGIN}\t${cleanall_command}
1422 # Clean all library files
1425 \t${BEGIN}-@${library_build_command} cleanall
1426 \t${END}@cd $(BUILD_DIR)\n
1429 ## Constructor of PlatformMakefile
1431 # @param ModuleAutoGen Object of PlatformAutoGen class
1433 def __init__(self, PlatformAutoGen):
1434 BuildFile.__init__(self, PlatformAutoGen)
1435 self.ModuleBuildCommandList = []
1436 self.ModuleMakefileList = []
1437 self.IntermediateDirectoryList = []
1438 self.ModuleBuildDirectoryList = []
1439 self.LibraryBuildDirectoryList = []
1440 self.LibraryMakeCommandList = []
1441 self.DependencyHeaderFileSet = set()
1443 # Compose a dict object containing information used to do replacement in template
1445 def _TemplateDict(self):
1446 Separator = self._SEP_[self._FileType]
1448 MyAgo = self._AutoGenObject
1449 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1450 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1451 ExtraData="[%s]" % str(MyAgo))
1453 self.IntermediateDirectoryList = ["$
(BUILD_DIR
)"]
1454 self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()
1455 self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()
1457 MakefileName = self._FILE_NAME_[self._FileType]
1458 LibraryMakefileList = []
1459 LibraryMakeCommandList = []
1460 for D in self.LibraryBuildDirectoryList:
1461 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1462 Makefile = os.path.join(D, MakefileName)
1463 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1464 LibraryMakefileList.append(Makefile)
1465 LibraryMakeCommandList.append(Command)
1466 self.LibraryMakeCommandList = LibraryMakeCommandList
1468 ModuleMakefileList = []
1469 ModuleMakeCommandList = []
1470 for D in self.ModuleBuildDirectoryList:
1471 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1472 Makefile = os.path.join(D, MakefileName)
1473 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1474 ModuleMakefileList.append(Makefile)
1475 ModuleMakeCommandList.append(Command)
1477 MakefileTemplateDict = {
1478 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1479 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1480 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1481 "makefile_name
" : MakefileName,
1482 "platform_name
" : MyAgo.Name,
1483 "platform_guid
" : MyAgo.Guid,
1484 "platform_version
" : MyAgo.Version,
1485 "platform_file
" : MyAgo.MetaFile,
1486 "platform_relative_directory
": MyAgo.SourceDir,
1487 "platform_output_directory
" : MyAgo.OutputDir,
1488 "platform_build_directory
" : MyAgo.BuildDir,
1489 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1491 "toolchain_tag
" : MyAgo.ToolChain,
1492 "build_target
" : MyAgo.BuildTarget,
1493 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1494 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1495 "build_architecture_list
" : MyAgo.Arch,
1496 "architecture
" : MyAgo.Arch,
1497 "separator
" : Separator,
1498 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1499 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1500 "library_makefile_list
" : LibraryMakefileList,
1501 "module_makefile_list
" : ModuleMakefileList,
1502 "library_build_command
" : LibraryMakeCommandList,
1503 "module_build_command
" : ModuleMakeCommandList,
1506 return MakefileTemplateDict
1508 ## Get the root directory list for intermediate files of all modules build
1510 # @retval list The list of directory
1512 def GetModuleBuildDirectoryList(self):
1514 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1515 if not ModuleAutoGen.IsBinaryModule:
1516 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1519 ## Get the root directory list for intermediate files of all libraries build
1521 # @retval list The list of directory
1523 def GetLibraryBuildDirectoryList(self):
1525 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1526 if not LibraryAutoGen.IsBinaryModule:
1527 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1530 ## TopLevelMakefile class
1532 # This class encapsules makefie and its generation for entrance makefile. It
1533 # uses template to generate the content of makefile. The content of makefile
1534 # will be got from WorkspaceAutoGen object.
1536 class TopLevelMakefile(BuildFile):
1537 ## template used to generate toplevel makefile
1538 _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}''')
1540 ## Constructor of TopLevelMakefile
1542 # @param Workspace Object of WorkspaceAutoGen class
1544 def __init__(self, Workspace):
1545 BuildFile.__init__(self, Workspace)
1546 self.IntermediateDirectoryList = []
1547 self.DependencyHeaderFileSet = set()
1549 # Compose a dict object containing information used to do replacement in template
1551 def _TemplateDict(self):
1552 Separator = self._SEP_[self._FileType]
1554 # any platform autogen object is ok because we just need common information
1555 MyAgo = self._AutoGenObject
1557 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1558 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1559 ExtraData="[%s]" % str(MyAgo))
1561 for Arch in MyAgo.ArchList:
1562 self.IntermediateDirectoryList.append(Separator.join(["$
(BUILD_DIR
)", Arch]))
1563 self.IntermediateDirectoryList.append("$
(FV_DIR
)")
1565 # TRICK: for not generating GenFds call in makefile if no FDF file
1567 if MyAgo.FdfFile is not None and MyAgo.FdfFile != "":
1568 FdfFileList = [MyAgo.FdfFile]
1569 # macros passed to GenFds
1571 MacroDict.update(GlobalData.gGlobalDefines)
1572 MacroDict.update(GlobalData.gCommandLineDefines)
1573 for MacroName in MacroDict:
1574 if MacroDict[MacroName] != "":
1575 MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
1577 MacroList.append('"%s"' % MacroName)
1581 # pass extra common options to external program called in makefile, currently GenFds.exe
1583 LogLevel = EdkLogger.GetLevel()
1584 if LogLevel == EdkLogger.VERBOSE:
1585 ExtraOption += " -v
"
1586 elif LogLevel <= EdkLogger.DEBUG_9:
1587 ExtraOption += " -d
%d" % (LogLevel - 1)
1588 elif LogLevel == EdkLogger.QUIET:
1589 ExtraOption += " -q
"
1591 if GlobalData.gCaseInsensitive:
1592 ExtraOption += " -c
"
1593 if not GlobalData.gEnableGenfdsMultiThread:
1594 ExtraOption += " --no
-genfds
-multi
-thread
"
1595 if GlobalData.gIgnoreSource:
1596 ExtraOption += " --ignore
-sources
"
1598 for pcd in GlobalData.BuildOptionPcd:
1600 pcdname = '.'.join(pcd[0:3])
1602 pcdname = '.'.join(pcd[0:2])
1603 if pcd[3].startswith('{'):
1604 ExtraOption += " --pcd
" + pcdname + '=' + 'H' + '"' + pcd[3] + '"'
1606 ExtraOption += " --pcd
" + pcdname + '=' + pcd[3]
1608 MakefileName = self._FILE_NAME_[self._FileType]
1609 SubBuildCommandList = []
1610 for A in MyAgo.ArchList:
1611 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join("$
(BUILD_DIR
)", A, MakefileName)}
1612 SubBuildCommandList.append(Command)
1614 MakefileTemplateDict = {
1615 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1616 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1617 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1618 "platform_name
" : MyAgo.Name,
1619 "platform_guid
" : MyAgo.Guid,
1620 "platform_version
" : MyAgo.Version,
1621 "platform_build_directory
" : MyAgo.BuildDir,
1622 "conf_directory
" : GlobalData.gConfDirectory,
1624 "toolchain_tag
" : MyAgo.ToolChain,
1625 "build_target
" : MyAgo.BuildTarget,
1626 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1627 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1628 'arch' : list(MyAgo.ArchList),
1629 "build_architecture_list
" : ','.join(MyAgo.ArchList),
1630 "separator
" : Separator,
1631 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1632 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1633 "sub_build_command
" : SubBuildCommandList,
1634 "fdf_file
" : FdfFileList,
1635 "active_platform
" : str(MyAgo),
1636 "fd
" : MyAgo.FdTargetList,
1637 "fv
" : MyAgo.FvTargetList,
1638 "cap
" : MyAgo.CapTargetList,
1639 "extra_options
" : ExtraOption,
1640 "macro
" : MacroList,
1643 return MakefileTemplateDict
1645 ## Get the root directory list for intermediate files of all modules build
1647 # @retval list The list of directory
1649 def GetModuleBuildDirectoryList(self):
1651 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1652 if not ModuleAutoGen.IsBinaryModule:
1653 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1656 ## Get the root directory list for intermediate files of all libraries build
1658 # @retval list The list of directory
1660 def GetLibraryBuildDirectoryList(self):
1662 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1663 if not LibraryAutoGen.IsBinaryModule:
1664 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1667 ## Find dependencies for one source file
1669 # By searching recursively "#include" directive in file, find out all the
1670 # files needed by given source file. The dependencies will be only searched
1671 # in given search path list.
1673 # @param File The source file
1674 # @param ForceInculeList The list of files which will be included forcely
1675 # @param SearchPathList The list of search path
1677 # @retval list The list of files the given source file depends on
1679 def GetDependencyList(AutoGenObject
, FileCache
, File
, ForceList
, SearchPathList
):
1680 EdkLogger
.debug(EdkLogger
.DEBUG_1
, "Try to get dependency files for %s" % File
)
1681 FileStack
= [File
] + ForceList
1682 DependencySet
= set()
1684 if AutoGenObject
.Arch
not in gDependencyDatabase
:
1685 gDependencyDatabase
[AutoGenObject
.Arch
] = {}
1686 DepDb
= gDependencyDatabase
[AutoGenObject
.Arch
]
1688 while len(FileStack
) > 0:
1691 FullPathDependList
= []
1693 for CacheFile
in FileCache
[F
]:
1694 FullPathDependList
.append(CacheFile
)
1695 if CacheFile
not in DependencySet
:
1696 FileStack
.append(CacheFile
)
1697 DependencySet
.update(FullPathDependList
)
1700 CurrentFileDependencyList
= []
1702 CurrentFileDependencyList
= DepDb
[F
]
1705 Fd
= open(F
.Path
, 'rb')
1706 FileContent
= Fd
.read()
1708 except BaseException
as X
:
1709 EdkLogger
.error("build", FILE_OPEN_FAILURE
, ExtraData
=F
.Path
+ "\n\t" + str(X
))
1710 if len(FileContent
) == 0:
1713 if FileContent
[0] == 0xff or FileContent
[0] == 0xfe:
1714 FileContent
= FileContent
.decode('utf-16')
1716 FileContent
= FileContent
.decode()
1718 # The file is not txt file. for example .mcb file
1720 IncludedFileList
= gIncludePattern
.findall(FileContent
)
1722 for Inc
in IncludedFileList
:
1724 # if there's macro used to reference header file, expand it
1725 HeaderList
= gMacroPattern
.findall(Inc
)
1726 if len(HeaderList
) == 1 and len(HeaderList
[0]) == 2:
1727 HeaderType
= HeaderList
[0][0]
1728 HeaderKey
= HeaderList
[0][1]
1729 if HeaderType
in gIncludeMacroConversion
:
1730 Inc
= gIncludeMacroConversion
[HeaderType
] % {"HeaderKey" : HeaderKey
}
1732 # not known macro used in #include, always build the file by
1733 # returning a empty dependency
1734 FileCache
[File
] = []
1736 Inc
= os
.path
.normpath(Inc
)
1737 CurrentFileDependencyList
.append(Inc
)
1738 DepDb
[F
] = CurrentFileDependencyList
1740 CurrentFilePath
= F
.Dir
1741 PathList
= [CurrentFilePath
] + SearchPathList
1742 for Inc
in CurrentFileDependencyList
:
1743 for SearchPath
in PathList
:
1744 FilePath
= os
.path
.join(SearchPath
, Inc
)
1745 if FilePath
in gIsFileMap
:
1746 if not gIsFileMap
[FilePath
]:
1748 # If isfile is called too many times, the performance is slow down.
1749 elif not os
.path
.isfile(FilePath
):
1750 gIsFileMap
[FilePath
] = False
1753 gIsFileMap
[FilePath
] = True
1754 FilePath
= PathClass(FilePath
)
1755 FullPathDependList
.append(FilePath
)
1756 if FilePath
not in DependencySet
:
1757 FileStack
.append(FilePath
)
1760 EdkLogger
.debug(EdkLogger
.DEBUG_9
, "%s included by %s was not found "\
1761 "in any given path:\n\t%s" % (Inc
, F
, "\n\t".join(SearchPathList
)))
1763 FileCache
[F
] = FullPathDependList
1764 DependencySet
.update(FullPathDependList
)
1766 DependencySet
.update(ForceList
)
1767 if File
in DependencySet
:
1768 DependencySet
.remove(File
)
1769 DependencyList
= list(DependencySet
) # remove duplicate ones
1771 return DependencyList
1773 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1774 if __name__
== '__main__':