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 for Temp in DependencyDict[CppPath.Path]:
1085 Path = self.PlaceMacro(Temp.Path, self.Macros)
1088 if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):
1089 CmdCppDict[item.Target.SubDir].append(Path)
1091 CommandList = T.Commands[:]
1092 for Item in CommandList[:]:
1093 SingleCommandList = Item.split()
1094 if len(SingleCommandList) > 0 and self.CheckCCCmd(SingleCommandList):
1095 for Temp in SingleCommandList:
1096 if Temp.startswith('/Fo'):
1097 CmdSign = '%s%s' % (Temp.rsplit(TAB_SLASH, 1)[0], TAB_SLASH)
1100 if CmdSign not in list(CmdTargetDict.keys()):
1101 CmdTargetDict[CmdSign] = Item.replace(Temp, CmdSign)
1103 CmdTargetDict[CmdSign] = "%s %s" % (CmdTargetDict[CmdSign], SingleCommandList[-1])
1104 Index = CommandList.index(Item)
1105 CommandList.pop(Index)
1106 if SingleCommandList[-1].endswith("%s%s.c
" % (TAB_SLASH, CmdSumDict[CmdSign[3:].rsplit(TAB_SLASH, 1)[0]])):
1107 Cpplist = CmdCppDict[T.Target.SubDir]
1108 Cpplist.insert(0, '$(OBJLIST_%d): $(COMMON_DEPS)' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir))
1109 T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign])
1111 T.Commands.pop(Index)
1112 return T, CmdSumDict, CmdTargetDict, CmdCppDict
1114 def CheckCCCmd(self, CommandList):
1115 for cmd in CommandList:
1119 ## For creating makefile targets for dependent libraries
1120 def ProcessDependentLibrary(self):
1121 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1122 if not LibraryAutoGen.IsBinaryModule:
1123 self.LibraryBuildDirectoryList.append(self.PlaceMacro(LibraryAutoGen.BuildDir, self.Macros))
1125 ## Return a list containing source file's dependencies
1127 # @param FileList The list of source files
1128 # @param ForceInculeList The list of files which will be included forcely
1129 # @param SearchPathList The list of search path
1131 # @retval dict The mapping between source file path and its dependencies
1133 def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):
1136 Dependency[F] = GetDependencyList(self._AutoGenObject, self.FileCache, F, ForceInculeList, SearchPathList)
1140 ## CustomMakefile class
1142 # This class encapsules makefie and its generation for module. It uses template to generate
1143 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
1145 class CustomMakefile(BuildFile):
1146 ## template used to generate the makefile for module with custom makefile
1147 _TEMPLATE_ = TemplateString('''\
1151 # Platform Macro Definition
1153 PLATFORM_NAME = ${platform_name}
1154 PLATFORM_GUID = ${platform_guid}
1155 PLATFORM_VERSION = ${platform_version}
1156 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
1157 PLATFORM_DIR = ${platform_dir}
1158 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1161 # Module Macro Definition
1163 MODULE_NAME = ${module_name}
1164 MODULE_GUID = ${module_guid}
1165 MODULE_NAME_GUID = ${module_name_guid}
1166 MODULE_VERSION = ${module_version}
1167 MODULE_TYPE = ${module_type}
1168 MODULE_FILE = ${module_file}
1169 MODULE_FILE_BASE_NAME = ${module_file_base_name}
1170 BASE_NAME = $(MODULE_NAME)
1171 MODULE_RELATIVE_DIR = ${module_relative_directory}
1172 MODULE_DIR = ${module_dir}
1175 # Build Configuration Macro Definition
1177 ARCH = ${architecture}
1178 TOOLCHAIN = ${toolchain_tag}
1179 TOOLCHAIN_TAG = ${toolchain_tag}
1180 TARGET = ${build_target}
1183 # Build Directory Macro Definition
1185 # PLATFORM_BUILD_DIR = ${platform_build_directory}
1186 BUILD_DIR = ${platform_build_directory}
1187 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
1188 LIB_DIR = $(BIN_DIR)
1189 MODULE_BUILD_DIR = ${module_build_directory}
1190 OUTPUT_DIR = ${module_output_directory}
1191 DEBUG_DIR = ${module_debug_directory}
1192 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
1193 DEST_DIR_DEBUG = $(DEBUG_DIR)
1196 # Tools definitions specific to this module
1198 ${BEGIN}${module_tool_definitions}
1200 MAKE_FILE = ${makefile_path}
1203 # Shell Command Macro
1205 ${BEGIN}${shell_command_code} = ${shell_command}
1208 ${custom_makefile_content}
1211 # Target used when called from platform makefile, which will bypass the build of dependent libraries
1224 # Build Target used in multi-thread build mode, which no init target is needed
1230 # Initialization target: print build information and create necessary directories
1233 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
1234 ${BEGIN}\t-@${create_directory_command}\n${END}\
1238 ## Constructor of CustomMakefile
1240 # @param ModuleAutoGen Object of ModuleAutoGen class
1242 def __init__(self, ModuleAutoGen):
1243 BuildFile.__init__(self, ModuleAutoGen)
1244 self.PlatformInfo = self._AutoGenObject.PlatformInfo
1245 self.IntermediateDirectoryList = ["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]
1246 self.DependencyHeaderFileSet = set()
1248 # Compose a dict object containing information used to do replacement in template
1250 def _TemplateDict(self):
1251 Separator = self._SEP_[self._FileType]
1252 MyAgo = self._AutoGenObject
1253 if self._FileType not in MyAgo.CustomMakefile:
1254 EdkLogger.error('build', OPTION_NOT_SUPPORTED, "No custom makefile
for %s" % self._FileType,
1255 ExtraData="[%s]" % str(MyAgo))
1256 MakefilePath = mws.join(
1258 MyAgo.CustomMakefile[self._FileType]
1261 CustomMakefile = open(MakefilePath, 'r').read()
1263 EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(MyAgo),
1264 ExtraData=MyAgo.CustomMakefile[self._FileType])
1268 for Tool in MyAgo.BuildOption:
1269 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
1272 for Attr in MyAgo.BuildOption[Tool]:
1273 if Attr == "FAMILY
":
1275 elif Attr == "PATH
":
1276 ToolsDef.append("%s = %s" % (Tool, MyAgo.BuildOption[Tool][Attr]))
1278 ToolsDef.append("%s_%s = %s" % (Tool, Attr, MyAgo.BuildOption[Tool][Attr]))
1281 MakefileName = self._FILE_NAME_[self._FileType]
1282 MakefileTemplateDict = {
1283 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1284 "makefile_path
" : os.path.join("$
(MODULE_BUILD_DIR
)", MakefileName),
1285 "platform_name
" : self.PlatformInfo.Name,
1286 "platform_guid
" : self.PlatformInfo.Guid,
1287 "platform_version
" : self.PlatformInfo.Version,
1288 "platform_relative_directory
": self.PlatformInfo.SourceDir,
1289 "platform_output_directory
" : self.PlatformInfo.OutputDir,
1290 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1292 "module_name
" : MyAgo.Name,
1293 "module_guid
" : MyAgo.Guid,
1294 "module_name_guid
" : MyAgo.UniqueBaseName,
1295 "module_version
" : MyAgo.Version,
1296 "module_type
" : MyAgo.ModuleType,
1297 "module_file
" : MyAgo.MetaFile,
1298 "module_file_base_name
" : MyAgo.MetaFile.BaseName,
1299 "module_relative_directory
" : MyAgo.SourceDir,
1300 "module_dir
" : mws.join (MyAgo.WorkspaceDir, MyAgo.SourceDir),
1302 "architecture
" : MyAgo.Arch,
1303 "toolchain_tag
" : MyAgo.ToolChain,
1304 "build_target
" : MyAgo.BuildTarget,
1306 "platform_build_directory
" : self.PlatformInfo.BuildDir,
1307 "module_build_directory
" : MyAgo.BuildDir,
1308 "module_output_directory
" : MyAgo.OutputDir,
1309 "module_debug_directory
" : MyAgo.DebugDir,
1311 "separator
" : Separator,
1312 "module_tool_definitions
" : ToolsDef,
1314 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1315 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1317 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1318 "custom_makefile_content
" : CustomMakefile
1321 return MakefileTemplateDict
1323 ## PlatformMakefile class
1325 # This class encapsules makefie and its generation for platform. It uses
1326 # template to generate the content of makefile. The content of makefile will be
1327 # got from PlatformAutoGen object.
1329 class PlatformMakefile(BuildFile):
1330 ## template used to generate the makefile for platform
1331 _TEMPLATE_ = TemplateString('''\
1335 # Platform Macro Definition
1337 PLATFORM_NAME = ${platform_name}
1338 PLATFORM_GUID = ${platform_guid}
1339 PLATFORM_VERSION = ${platform_version}
1340 PLATFORM_FILE = ${platform_file}
1341 PLATFORM_DIR = ${platform_dir}
1342 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1345 # Build Configuration Macro Definition
1347 TOOLCHAIN = ${toolchain_tag}
1348 TOOLCHAIN_TAG = ${toolchain_tag}
1349 TARGET = ${build_target}
1352 # Build Directory Macro Definition
1354 BUILD_DIR = ${platform_build_directory}
1355 FV_DIR = ${platform_build_directory}${separator}FV
1358 # Shell Command Macro
1360 ${BEGIN}${shell_command_code} = ${shell_command}
1364 MAKE_FILE = ${makefile_path}
1369 all: init build_libraries build_modules
1372 # Initialization target: print build information and create necessary directories
1375 \t-@echo Building ... $(PLATFORM_FILE) [${build_architecture_list}]
1376 \t${BEGIN}-@${create_directory_command}
1379 # library build target
1381 libraries: init build_libraries
1384 # module build target
1386 modules: init build_libraries build_modules
1389 # Build all libraries:
1392 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${library_makefile_list} pbuild
1393 ${END}\t@cd $(BUILD_DIR)
1396 # Build all modules:
1399 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${module_makefile_list} pbuild
1400 ${END}\t@cd $(BUILD_DIR)
1403 # Clean intermediate files
1406 \t${BEGIN}-@${library_build_command} clean
1407 \t${END}${BEGIN}-@${module_build_command} clean
1408 \t${END}@cd $(BUILD_DIR)
1411 # Clean all generated files except to makefile
1414 ${BEGIN}\t${cleanall_command}
1418 # Clean all library files
1421 \t${BEGIN}-@${library_build_command} cleanall
1422 \t${END}@cd $(BUILD_DIR)\n
1425 ## Constructor of PlatformMakefile
1427 # @param ModuleAutoGen Object of PlatformAutoGen class
1429 def __init__(self, PlatformAutoGen):
1430 BuildFile.__init__(self, PlatformAutoGen)
1431 self.ModuleBuildCommandList = []
1432 self.ModuleMakefileList = []
1433 self.IntermediateDirectoryList = []
1434 self.ModuleBuildDirectoryList = []
1435 self.LibraryBuildDirectoryList = []
1436 self.LibraryMakeCommandList = []
1437 self.DependencyHeaderFileSet = set()
1439 # Compose a dict object containing information used to do replacement in template
1441 def _TemplateDict(self):
1442 Separator = self._SEP_[self._FileType]
1444 MyAgo = self._AutoGenObject
1445 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1446 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1447 ExtraData="[%s]" % str(MyAgo))
1449 self.IntermediateDirectoryList = ["$
(BUILD_DIR
)"]
1450 self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()
1451 self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()
1453 MakefileName = self._FILE_NAME_[self._FileType]
1454 LibraryMakefileList = []
1455 LibraryMakeCommandList = []
1456 for D in self.LibraryBuildDirectoryList:
1457 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1458 Makefile = os.path.join(D, MakefileName)
1459 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1460 LibraryMakefileList.append(Makefile)
1461 LibraryMakeCommandList.append(Command)
1462 self.LibraryMakeCommandList = LibraryMakeCommandList
1464 ModuleMakefileList = []
1465 ModuleMakeCommandList = []
1466 for D in self.ModuleBuildDirectoryList:
1467 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1468 Makefile = os.path.join(D, MakefileName)
1469 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1470 ModuleMakefileList.append(Makefile)
1471 ModuleMakeCommandList.append(Command)
1473 MakefileTemplateDict = {
1474 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1475 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1476 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1477 "makefile_name
" : MakefileName,
1478 "platform_name
" : MyAgo.Name,
1479 "platform_guid
" : MyAgo.Guid,
1480 "platform_version
" : MyAgo.Version,
1481 "platform_file
" : MyAgo.MetaFile,
1482 "platform_relative_directory
": MyAgo.SourceDir,
1483 "platform_output_directory
" : MyAgo.OutputDir,
1484 "platform_build_directory
" : MyAgo.BuildDir,
1485 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1487 "toolchain_tag
" : MyAgo.ToolChain,
1488 "build_target
" : MyAgo.BuildTarget,
1489 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1490 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1491 "build_architecture_list
" : MyAgo.Arch,
1492 "architecture
" : MyAgo.Arch,
1493 "separator
" : Separator,
1494 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1495 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1496 "library_makefile_list
" : LibraryMakefileList,
1497 "module_makefile_list
" : ModuleMakefileList,
1498 "library_build_command
" : LibraryMakeCommandList,
1499 "module_build_command
" : ModuleMakeCommandList,
1502 return MakefileTemplateDict
1504 ## Get the root directory list for intermediate files of all modules build
1506 # @retval list The list of directory
1508 def GetModuleBuildDirectoryList(self):
1510 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1511 if not ModuleAutoGen.IsBinaryModule:
1512 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1515 ## Get the root directory list for intermediate files of all libraries build
1517 # @retval list The list of directory
1519 def GetLibraryBuildDirectoryList(self):
1521 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1522 if not LibraryAutoGen.IsBinaryModule:
1523 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1526 ## TopLevelMakefile class
1528 # This class encapsules makefie and its generation for entrance makefile. It
1529 # uses template to generate the content of makefile. The content of makefile
1530 # will be got from WorkspaceAutoGen object.
1532 class TopLevelMakefile(BuildFile):
1533 ## template used to generate toplevel makefile
1534 _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}''')
1536 ## Constructor of TopLevelMakefile
1538 # @param Workspace Object of WorkspaceAutoGen class
1540 def __init__(self, Workspace):
1541 BuildFile.__init__(self, Workspace)
1542 self.IntermediateDirectoryList = []
1543 self.DependencyHeaderFileSet = set()
1545 # Compose a dict object containing information used to do replacement in template
1547 def _TemplateDict(self):
1548 Separator = self._SEP_[self._FileType]
1550 # any platform autogen object is ok because we just need common information
1551 MyAgo = self._AutoGenObject
1553 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1554 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1555 ExtraData="[%s]" % str(MyAgo))
1557 for Arch in MyAgo.ArchList:
1558 self.IntermediateDirectoryList.append(Separator.join(["$
(BUILD_DIR
)", Arch]))
1559 self.IntermediateDirectoryList.append("$
(FV_DIR
)")
1561 # TRICK: for not generating GenFds call in makefile if no FDF file
1563 if MyAgo.FdfFile is not None and MyAgo.FdfFile != "":
1564 FdfFileList = [MyAgo.FdfFile]
1565 # macros passed to GenFds
1567 MacroDict.update(GlobalData.gGlobalDefines)
1568 MacroDict.update(GlobalData.gCommandLineDefines)
1569 for MacroName in MacroDict:
1570 if MacroDict[MacroName] != "":
1571 MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
1573 MacroList.append('"%s"' % MacroName)
1577 # pass extra common options to external program called in makefile, currently GenFds.exe
1579 LogLevel = EdkLogger.GetLevel()
1580 if LogLevel == EdkLogger.VERBOSE:
1581 ExtraOption += " -v
"
1582 elif LogLevel <= EdkLogger.DEBUG_9:
1583 ExtraOption += " -d
%d" % (LogLevel - 1)
1584 elif LogLevel == EdkLogger.QUIET:
1585 ExtraOption += " -q
"
1587 if GlobalData.gCaseInsensitive:
1588 ExtraOption += " -c
"
1589 if not GlobalData.gEnableGenfdsMultiThread:
1590 ExtraOption += " --no
-genfds
-multi
-thread
"
1591 if GlobalData.gIgnoreSource:
1592 ExtraOption += " --ignore
-sources
"
1594 for pcd in GlobalData.BuildOptionPcd:
1596 pcdname = '.'.join(pcd[0:3])
1598 pcdname = '.'.join(pcd[0:2])
1599 if pcd[3].startswith('{'):
1600 ExtraOption += " --pcd
" + pcdname + '=' + 'H' + '"' + pcd[3] + '"'
1602 ExtraOption += " --pcd
" + pcdname + '=' + pcd[3]
1604 MakefileName = self._FILE_NAME_[self._FileType]
1605 SubBuildCommandList = []
1606 for A in MyAgo.ArchList:
1607 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join("$
(BUILD_DIR
)", A, MakefileName)}
1608 SubBuildCommandList.append(Command)
1610 MakefileTemplateDict = {
1611 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1612 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1613 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1614 "platform_name
" : MyAgo.Name,
1615 "platform_guid
" : MyAgo.Guid,
1616 "platform_version
" : MyAgo.Version,
1617 "platform_build_directory
" : MyAgo.BuildDir,
1618 "conf_directory
" : GlobalData.gConfDirectory,
1620 "toolchain_tag
" : MyAgo.ToolChain,
1621 "build_target
" : MyAgo.BuildTarget,
1622 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1623 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1624 'arch' : list(MyAgo.ArchList),
1625 "build_architecture_list
" : ','.join(MyAgo.ArchList),
1626 "separator
" : Separator,
1627 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1628 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1629 "sub_build_command
" : SubBuildCommandList,
1630 "fdf_file
" : FdfFileList,
1631 "active_platform
" : str(MyAgo),
1632 "fd
" : MyAgo.FdTargetList,
1633 "fv
" : MyAgo.FvTargetList,
1634 "cap
" : MyAgo.CapTargetList,
1635 "extra_options
" : ExtraOption,
1636 "macro
" : MacroList,
1639 return MakefileTemplateDict
1641 ## Get the root directory list for intermediate files of all modules build
1643 # @retval list The list of directory
1645 def GetModuleBuildDirectoryList(self):
1647 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1648 if not ModuleAutoGen.IsBinaryModule:
1649 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1652 ## Get the root directory list for intermediate files of all libraries build
1654 # @retval list The list of directory
1656 def GetLibraryBuildDirectoryList(self):
1658 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1659 if not LibraryAutoGen.IsBinaryModule:
1660 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1663 ## Find dependencies for one source file
1665 # By searching recursively "#include" directive in file, find out all the
1666 # files needed by given source file. The dependencies will be only searched
1667 # in given search path list.
1669 # @param File The source file
1670 # @param ForceInculeList The list of files which will be included forcely
1671 # @param SearchPathList The list of search path
1673 # @retval list The list of files the given source file depends on
1675 def GetDependencyList(AutoGenObject
, FileCache
, File
, ForceList
, SearchPathList
):
1676 EdkLogger
.debug(EdkLogger
.DEBUG_1
, "Try to get dependency files for %s" % File
)
1677 FileStack
= [File
] + ForceList
1678 DependencySet
= set()
1680 if AutoGenObject
.Arch
not in gDependencyDatabase
:
1681 gDependencyDatabase
[AutoGenObject
.Arch
] = {}
1682 DepDb
= gDependencyDatabase
[AutoGenObject
.Arch
]
1684 while len(FileStack
) > 0:
1687 FullPathDependList
= []
1689 for CacheFile
in FileCache
[F
]:
1690 FullPathDependList
.append(CacheFile
)
1691 if CacheFile
not in DependencySet
:
1692 FileStack
.append(CacheFile
)
1693 DependencySet
.update(FullPathDependList
)
1696 CurrentFileDependencyList
= []
1698 CurrentFileDependencyList
= DepDb
[F
]
1701 Fd
= open(F
.Path
, 'rb')
1702 FileContent
= Fd
.read()
1704 except BaseException
as X
:
1705 EdkLogger
.error("build", FILE_OPEN_FAILURE
, ExtraData
=F
.Path
+ "\n\t" + str(X
))
1706 if len(FileContent
) == 0:
1709 if FileContent
[0] == 0xff or FileContent
[0] == 0xfe:
1710 FileContent
= FileContent
.decode('utf-16')
1712 FileContent
= FileContent
.decode()
1714 # The file is not txt file. for example .mcb file
1716 IncludedFileList
= gIncludePattern
.findall(FileContent
)
1718 for Inc
in IncludedFileList
:
1720 # if there's macro used to reference header file, expand it
1721 HeaderList
= gMacroPattern
.findall(Inc
)
1722 if len(HeaderList
) == 1 and len(HeaderList
[0]) == 2:
1723 HeaderType
= HeaderList
[0][0]
1724 HeaderKey
= HeaderList
[0][1]
1725 if HeaderType
in gIncludeMacroConversion
:
1726 Inc
= gIncludeMacroConversion
[HeaderType
] % {"HeaderKey" : HeaderKey
}
1728 # not known macro used in #include, always build the file by
1729 # returning a empty dependency
1730 FileCache
[File
] = []
1732 Inc
= os
.path
.normpath(Inc
)
1733 CurrentFileDependencyList
.append(Inc
)
1734 DepDb
[F
] = CurrentFileDependencyList
1736 CurrentFilePath
= F
.Dir
1737 PathList
= [CurrentFilePath
] + SearchPathList
1738 for Inc
in CurrentFileDependencyList
:
1739 for SearchPath
in PathList
:
1740 FilePath
= os
.path
.join(SearchPath
, Inc
)
1741 if FilePath
in gIsFileMap
:
1742 if not gIsFileMap
[FilePath
]:
1744 # If isfile is called too many times, the performance is slow down.
1745 elif not os
.path
.isfile(FilePath
):
1746 gIsFileMap
[FilePath
] = False
1749 gIsFileMap
[FilePath
] = True
1750 FilePath
= PathClass(FilePath
)
1751 FullPathDependList
.append(FilePath
)
1752 if FilePath
not in DependencySet
:
1753 FileStack
.append(FilePath
)
1756 EdkLogger
.debug(EdkLogger
.DEBUG_9
, "%s included by %s was not found "\
1757 "in any given path:\n\t%s" % (Inc
, F
, "\n\t".join(SearchPathList
)))
1759 FileCache
[F
] = FullPathDependList
1760 DependencySet
.update(FullPathDependList
)
1762 DependencySet
.update(ForceList
)
1763 if File
in DependencySet
:
1764 DependencySet
.remove(File
)
1765 DependencyList
= list(DependencySet
) # remove duplicate ones
1767 return DependencyList
1769 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1770 if __name__
== '__main__':