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])
641 for fl in os.listdir(current_dir):
642 if fl.endswith('.dec'):
646 EdkLogger.error('build', FILE_NOT_FOUND, "WORKSPACE does
not exist
.")
647 package_rel_dir = package_rel_dir[index + 1:]
649 MakefileTemplateDict = {
650 "makefile_header
" : self._FILE_HEADER_[self._FileType],
651 "makefile_path
" : os.path.join("$
(MODULE_BUILD_DIR
)", MakefileName),
652 "makefile_name
" : MakefileName,
653 "platform_name
" : self.PlatformInfo.Name,
654 "platform_guid
" : self.PlatformInfo.Guid,
655 "platform_version
" : self.PlatformInfo.Version,
656 "platform_relative_directory
": self.PlatformInfo.SourceDir,
657 "platform_output_directory
" : self.PlatformInfo.OutputDir,
658 "ffs_output_directory
" : MyAgo.Macros["FFS_OUTPUT_DIR
"],
659 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
661 "module_name
" : MyAgo.Name,
662 "module_guid
" : MyAgo.Guid,
663 "module_name_guid
" : MyAgo.UniqueBaseName,
664 "module_version
" : MyAgo.Version,
665 "module_type
" : MyAgo.ModuleType,
666 "module_file
" : MyAgo.MetaFile.Name,
667 "module_file_base_name
" : MyAgo.MetaFile.BaseName,
668 "module_relative_directory
" : MyAgo.SourceDir,
669 "module_dir
" : mws.join (self.Macros["WORKSPACE
"], MyAgo.SourceDir),
670 "package_relative_directory
": package_rel_dir,
671 "module_extra_defines
" : ["%s = %s" % (k, v) for k, v in MyAgo.Module.Defines.items()],
673 "architecture
" : MyAgo.Arch,
674 "toolchain_tag
" : MyAgo.ToolChain,
675 "build_target
" : MyAgo.BuildTarget,
677 "platform_build_directory
" : self.PlatformInfo.BuildDir,
678 "module_build_directory
" : MyAgo.BuildDir,
679 "module_output_directory
" : MyAgo.OutputDir,
680 "module_debug_directory
" : MyAgo.DebugDir,
682 "separator
" : Separator,
683 "module_tool_definitions
" : ToolsDef,
685 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
686 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
688 "module_entry_point
" : ModuleEntryPoint,
689 "image_entry_point
" : ImageEntryPoint,
690 "arch_entry_point
" : ArchEntryPoint,
691 "remaining_build_target
" : self.ResultFileList,
692 "common_dependency_file
" : self.CommonFileDependency,
693 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
694 "clean_command
" : self.GetRemoveDirectoryCommand(["$
(OUTPUT_DIR
)"]),
695 "cleanall_command
" : self.GetRemoveDirectoryCommand(["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]),
696 "dependent_library_build_directory
" : self.LibraryBuildDirectoryList,
697 "library_build_command
" : LibraryMakeCommandList,
698 "file_macro
" : FileMacroList,
699 "file_build_target
" : self.BuildTargetList,
700 "backward_compatible_target
": BcTargetList,
703 return MakefileTemplateDict
705 def ParserGenerateFfsCmd(self):
706 #Add Ffs cmd to self.BuildTargetList
710 for Cmd in self.GenFfsList:
712 for CopyCmd in Cmd[2]:
714 Src = self.ReplaceMacro(Src)
715 Dst = self.ReplaceMacro(Dst)
716 if Dst not in self.ResultFileList:
717 self.ResultFileList.append(Dst)
718 if '%s :' %(Dst) not in self.BuildTargetList:
719 self.BuildTargetList.append("%s :" %(Dst))
720 self.BuildTargetList.append('\t' + self._CP_TEMPLATE_[self._FileType] %{'Src': Src, 'Dst': Dst})
723 for index, Str in enumerate(FfsCmdList):
725 OutputFile = FfsCmdList[index + 1]
726 if '-i' == Str or "-oi
" == Str:
727 if DepsFileList == []:
728 DepsFileList = [FfsCmdList[index + 1]]
730 DepsFileList.append(FfsCmdList[index + 1])
731 DepsFileString = ' '.join(DepsFileList).strip()
732 if DepsFileString == '':
734 OutputFile = self.ReplaceMacro(OutputFile)
735 self.ResultFileList.append(OutputFile)
736 DepsFileString = self.ReplaceMacro(DepsFileString)
737 self.BuildTargetList.append('%s : %s' % (OutputFile, DepsFileString))
738 CmdString = ' '.join(FfsCmdList).strip()
739 CmdString = self.ReplaceMacro(CmdString)
740 self.BuildTargetList.append('\t%s' % CmdString)
742 self.ParseSecCmd(DepsFileList, Cmd[1])
743 for SecOutputFile, SecDepsFile, SecCmd in self.FfsOutputFileList :
744 self.BuildTargetList.append('%s : %s' % (self.ReplaceMacro(SecOutputFile), self.ReplaceMacro(SecDepsFile)))
745 self.BuildTargetList.append('\t%s' % self.ReplaceMacro(SecCmd))
746 self.FfsOutputFileList = []
748 def ParseSecCmd(self, OutputFileList, CmdTuple):
749 for OutputFile in OutputFileList:
750 for SecCmdStr in CmdTuple:
752 SecCmdList = SecCmdStr.split()
753 CmdName = SecCmdList[0]
754 for index, CmdItem in enumerate(SecCmdList):
755 if '-o' == CmdItem and OutputFile == SecCmdList[index + 1]:
757 while index + 1 < len(SecCmdList):
758 if not SecCmdList[index+1].startswith('-'):
759 SecDepsFileList.append(SecCmdList[index + 1])
761 if CmdName == 'Trim':
762 SecDepsFileList.append(os.path.join('$(DEBUG_DIR)', os.path.basename(OutputFile).replace('offset', 'efi')))
763 if OutputFile.endswith('.ui') or OutputFile.endswith('.ver'):
764 SecDepsFileList.append(os.path.join('$(MODULE_DIR)', '$(MODULE_FILE)'))
765 self.FfsOutputFileList.append((OutputFile, ' '.join(SecDepsFileList), SecCmdStr))
766 if len(SecDepsFileList) > 0:
767 self.ParseSecCmd(SecDepsFileList, CmdTuple)
772 def ReplaceMacro(self, str):
773 for Macro in self.MacroList:
774 if self._AutoGenObject.Macros[Macro] and self._AutoGenObject.Macros[Macro] in str:
775 str = str.replace(self._AutoGenObject.Macros[Macro], '$(' + Macro + ')')
778 def CommandExceedLimit(self):
780 'CC' : { 'Macro' : '$(CC_FLAGS)', 'Value' : False},
781 'PP' : { 'Macro' : '$(PP_FLAGS)', 'Value' : False},
782 'APP' : { 'Macro' : '$(APP_FLAGS)', 'Value' : False},
783 'ASLPP' : { 'Macro' : '$(ASLPP_FLAGS)', 'Value' : False},
784 'VFRPP' : { 'Macro' : '$(VFRPP_FLAGS)', 'Value' : False},
785 'ASM' : { 'Macro' : '$(ASM_FLAGS)', 'Value' : False},
786 'ASLCC' : { 'Macro' : '$(ASLCC_FLAGS)', 'Value' : False},
791 IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily]
793 # base on the source files to decide the file type
794 for File in self._AutoGenObject.SourceFileList:
795 for type in self._AutoGenObject.FileTypes:
796 if File in self._AutoGenObject.FileTypes[type]:
797 if type not in FileTypeList:
798 FileTypeList.append(type)
800 # calculate the command-line length
802 for type in FileTypeList:
803 BuildTargets = self._AutoGenObject.BuildRules[type].BuildTargets
804 for Target in BuildTargets:
805 CommandList = BuildTargets[Target].Commands
806 for SingleCommand in CommandList:
808 SingleCommandLength = len(SingleCommand)
809 SingleCommandList = SingleCommand.split()
810 if len(SingleCommandList) > 0:
811 for Flag in FlagDict:
812 if '$('+ Flag +')' in SingleCommandList[0]:
816 if 'PATH' not in self._AutoGenObject.BuildOption[Tool]:
817 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))
818 SingleCommandLength += len(self._AutoGenObject.BuildOption[Tool]['PATH
'])
819 for item in SingleCommandList[1:]:
820 if FlagDict[Tool]['Macro
'] in item:
821 if 'FLAGS
' not in self._AutoGenObject.BuildOption[Tool]:
822 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))
823 Str = self._AutoGenObject.BuildOption[Tool]['FLAGS']
824 for Option in self._AutoGenObject.BuildOption:
825 for Attr in self._AutoGenObject.BuildOption[Option]:
826 if Str.find(Option + '_' + Attr) != -1:
827 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
828 while(Str.find('$(') != -1):
829 for macro in self._AutoGenObject.Macros:
830 MacroName = '$('+ macro + ')'
831 if (Str.find(MacroName) != -1):
832 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
836 SingleCommandLength += len(Str)
837 elif '$(INC)' in item:
838 SingleCommandLength += self._AutoGenObject.IncludePathLength + len(IncPrefix) * len(self._AutoGenObject.IncludePathList)
839 elif item.find('$(') != -1:
841 for Option in self._AutoGenObject.BuildOption:
842 for Attr in self._AutoGenObject.BuildOption[Option]:
843 if Str.find(Option + '_' + Attr) != -1:
844 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
845 while(Str.find('$(') != -1):
846 for macro in self._AutoGenObject.Macros:
847 MacroName = '$('+ macro + ')'
848 if (Str.find(MacroName) != -1):
849 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
853 SingleCommandLength += len(Str)
855 if SingleCommandLength > GlobalData.gCommandMaxLength:
856 FlagDict[Tool]['Value'] = True
858 # generate the response file content by combine the FLAGS and INC
859 for Flag in FlagDict:
860 if FlagDict[Flag]['Value']:
862 RespMacro = FlagDict[Flag]['Macro'].replace('FLAGS', 'RESP')
863 Value = self._AutoGenObject.BuildOption[Flag]['FLAGS']
864 for inc in self._AutoGenObject.IncludePathList:
865 Value += ' ' + IncPrefix + inc
866 for Option in self._AutoGenObject.BuildOption:
867 for Attr in self._AutoGenObject.BuildOption[Option]:
868 if Value.find(Option + '_' + Attr) != -1:
869 Value = Value.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
870 while (Value.find('$(') != -1):
871 for macro in self._AutoGenObject.Macros:
872 MacroName = '$('+ macro + ')'
873 if (Value.find(MacroName) != -1):
874 Value = Value.replace(MacroName, self._AutoGenObject.Macros[macro])
879 if self._AutoGenObject.ToolChainFamily == 'GCC':
880 RespDict[Key] = Value.replace('\\', '/')
882 RespDict[Key] = Value
883 for Target in BuildTargets:
884 for i, SingleCommand in enumerate(BuildTargets[Target].Commands):
885 if FlagDict[Flag]['Macro'] in SingleCommand:
886 BuildTargets[Target].Commands[i] = SingleCommand.replace('$(INC)', '').replace(FlagDict[Flag]['Macro'], RespMacro)
889 def ProcessBuildTargetList(self):
891 # Search dependency file list for each source file
893 ForceIncludedFile = []
894 for File in self._AutoGenObject.AutoGenFileList:
896 ForceIncludedFile.append(File)
899 for Target in self._AutoGenObject.IntroTargetList:
900 SourceFileList.extend(Target.Inputs)
901 OutPutFileList.extend(Target.Outputs)
904 for Item in OutPutFileList:
905 if Item in SourceFileList:
906 SourceFileList.remove(Item)
908 FileDependencyDict = self.GetFileDependency(
911 self._AutoGenObject.IncludePathList + self._AutoGenObject.BuildOptionIncPathList
915 if FileDependencyDict:
916 for Dependency in FileDependencyDict.values():
917 self.DependencyHeaderFileSet.update(set(Dependency))
919 # Get a set of unique package includes from MetaFile
920 parentMetaFileIncludes = set()
921 for aInclude in self._AutoGenObject.PackageIncludePathList:
922 aIncludeName = str(aInclude)
923 parentMetaFileIncludes.add(aIncludeName.lower())
925 # Check if header files are listed in metafile
926 # Get a set of unique module header source files from MetaFile
927 headerFilesInMetaFileSet = set()
928 for aFile in self._AutoGenObject.SourceFileList:
929 aFileName = str(aFile)
930 if not aFileName.endswith('.h'):
932 headerFilesInMetaFileSet.add(aFileName.lower())
934 # Get a set of unique module autogen files
935 localAutoGenFileSet = set()
936 for aFile in self._AutoGenObject.AutoGenFileList:
937 localAutoGenFileSet.add(str(aFile).lower())
939 # Get a set of unique module dependency header files
940 # Exclude autogen files and files not in the source directory
941 # and files that are under the package include list
942 headerFileDependencySet = set()
943 localSourceDir = str(self._AutoGenObject.SourceDir).lower()
944 for Dependency in FileDependencyDict.values():
945 for aFile in Dependency:
946 aFileName = str(aFile).lower()
947 # Exclude non-header files
948 if not aFileName.endswith('.h'):
950 # Exclude autogen files
951 if aFileName in localAutoGenFileSet:
953 # Exclude include out of local scope
954 if localSourceDir not in aFileName:
956 # Exclude files covered by package includes
958 for aIncludePath in parentMetaFileIncludes:
959 if aIncludePath in aFileName:
964 # Keep the file to be checked
965 headerFileDependencySet.add(aFileName)
967 # Check if a module dependency header file is missing from the module's MetaFile
968 for aFile in headerFileDependencySet:
969 if aFile in headerFilesInMetaFileSet:
971 if GlobalData.gUseHashCache:
972 GlobalData.gModuleBuildTracking[self._AutoGenObject] = 'FAIL_METAFILE'
973 EdkLogger.warn("build
","Module MetaFile
[Sources
] is missing local header
!",
974 ExtraData = "Local Header
: " + aFile + " not found
in " + self._AutoGenObject.MetaFile.Path
978 for File,Dependency in FileDependencyDict.items():
980 FileDependencyDict[File] = ['$(FORCE_REBUILD)']
983 self._AutoGenObject.AutoGenDepSet |= set(Dependency)
986 if File.Ext not in [".c
", ".C
"] or File.Name == "AutoGen
.c
":
989 DepSet = set(Dependency)
991 DepSet &= set(Dependency)
992 # in case nothing in SourceFileList
996 # Extract common files list in the dependency files
999 self.CommonFileDependency.append(self.PlaceMacro(File.Path, self.Macros))
1004 DependencyDict = FileDependencyDict.copy()
1005 for File in FileDependencyDict:
1007 if File.Ext not in [".c
", ".C
"] or File.Name == "AutoGen
.c
":
1009 NewDepSet = set(FileDependencyDict[File])
1011 FileDependencyDict[File] = ["$
(COMMON_DEPS
)"] + list(NewDepSet)
1012 DependencyDict[File] = list(NewDepSet)
1014 # Convert target description object to target string in makefile
1015 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and TAB_C_CODE_FILE in self._AutoGenObject.Targets:
1016 for T in self._AutoGenObject.Targets[TAB_C_CODE_FILE]:
1017 NewFile = self.PlaceMacro(str(T), self.Macros)
1018 if not self.ObjTargetDict.get(T.Target.SubDir):
1019 self.ObjTargetDict[T.Target.SubDir] = set()
1020 self.ObjTargetDict[T.Target.SubDir].add(NewFile)
1021 for Type in self._AutoGenObject.Targets:
1022 for T in self._AutoGenObject.Targets[Type]:
1023 # Generate related macros if needed
1024 if T.GenFileListMacro and T.FileListMacro not in self.FileListMacros:
1025 self.FileListMacros[T.FileListMacro] = []
1026 if T.GenListFile and T.ListFileMacro not in self.ListFileMacros:
1027 self.ListFileMacros[T.ListFileMacro] = []
1028 if T.GenIncListFile and T.IncListFileMacro not in self.ListFileMacros:
1029 self.ListFileMacros[T.IncListFileMacro] = []
1033 # Add force-dependencies
1034 for Dep in T.Dependencies:
1035 Deps.append(self.PlaceMacro(str(Dep), self.Macros))
1036 if Dep != '$(MAKE_FILE)':
1037 CCodeDeps.append(self.PlaceMacro(str(Dep), self.Macros))
1038 # Add inclusion-dependencies
1039 if len(T.Inputs) == 1 and T.Inputs[0] in FileDependencyDict:
1040 for F in FileDependencyDict[T.Inputs[0]]:
1041 Deps.append(self.PlaceMacro(str(F), self.Macros))
1042 # Add source-dependencies
1044 NewFile = self.PlaceMacro(str(F), self.Macros)
1045 # In order to use file list macro as dependency
1047 # gnu tools need forward slash path separator, even on Windows
1048 self.ListFileMacros[T.ListFileMacro].append(str(F).replace ('\\', '/'))
1049 self.FileListMacros[T.FileListMacro].append(NewFile)
1050 elif T.GenFileListMacro:
1051 self.FileListMacros[T.FileListMacro].append(NewFile)
1053 Deps.append(NewFile)
1054 for key in self.FileListMacros:
1055 self.FileListMacros[key].sort()
1056 # Use file list macro as dependency
1057 if T.GenFileListMacro:
1058 Deps.append("$
(%s)" % T.FileListMacro)
1059 if Type in [TAB_OBJECT_FILE, TAB_STATIC_LIBRARY]:
1060 Deps.append("$
(%s)" % T.ListFileMacro)
1062 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Type == TAB_C_CODE_FILE:
1063 T, CmdTarget, CmdTargetDict, CmdCppDict = self.ParserCCodeFile(T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict)
1064 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": CCodeDeps}
1065 CmdLine = self._BUILD_TARGET_TEMPLATE.Replace(TargetDict).rstrip().replace('\t$(OBJLIST', '$(OBJLIST')
1067 CmdLine = '%s%s' %(CmdLine, TAB_LINE_BREAK)
1068 if CCodeDeps or CmdLine:
1069 self.BuildTargetList.append(CmdLine)
1071 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": Deps}
1072 self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(TargetDict))
1074 def ParserCCodeFile(self, T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict):
1076 for item in self._AutoGenObject.Targets[Type]:
1077 CmdSumDict[item.Target.SubDir] = item.Target.BaseName
1078 for CppPath in item.Inputs:
1079 Path = self.PlaceMacro(CppPath.Path, self.Macros)
1080 if CmdCppDict.get(item.Target.SubDir):
1081 CmdCppDict[item.Target.SubDir].append(Path)
1083 CmdCppDict[item.Target.SubDir] = ['$(MAKE_FILE)', Path]
1084 if CppPath.Path in DependencyDict:
1085 for Temp in DependencyDict[CppPath.Path]:
1087 Path = self.PlaceMacro(Temp.Path, self.Macros)
1090 if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):
1091 CmdCppDict[item.Target.SubDir].append(Path)
1093 CommandList = T.Commands[:]
1094 for Item in CommandList[:]:
1095 SingleCommandList = Item.split()
1096 if len(SingleCommandList) > 0 and self.CheckCCCmd(SingleCommandList):
1097 for Temp in SingleCommandList:
1098 if Temp.startswith('/Fo'):
1099 CmdSign = '%s%s' % (Temp.rsplit(TAB_SLASH, 1)[0], TAB_SLASH)
1102 if CmdSign not in list(CmdTargetDict.keys()):
1103 CmdTargetDict[CmdSign] = Item.replace(Temp, CmdSign)
1105 CmdTargetDict[CmdSign] = "%s %s" % (CmdTargetDict[CmdSign], SingleCommandList[-1])
1106 Index = CommandList.index(Item)
1107 CommandList.pop(Index)
1108 if SingleCommandList[-1].endswith("%s%s.c
" % (TAB_SLASH, CmdSumDict[CmdSign[3:].rsplit(TAB_SLASH, 1)[0]])):
1109 Cpplist = CmdCppDict[T.Target.SubDir]
1110 Cpplist.insert(0, '$(OBJLIST_%d): $(COMMON_DEPS)' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir))
1111 T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign])
1113 T.Commands.pop(Index)
1114 return T, CmdSumDict, CmdTargetDict, CmdCppDict
1116 def CheckCCCmd(self, CommandList):
1117 for cmd in CommandList:
1121 ## For creating makefile targets for dependent libraries
1122 def ProcessDependentLibrary(self):
1123 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1124 if not LibraryAutoGen.IsBinaryModule:
1125 self.LibraryBuildDirectoryList.append(self.PlaceMacro(LibraryAutoGen.BuildDir, self.Macros))
1127 ## Return a list containing source file's dependencies
1129 # @param FileList The list of source files
1130 # @param ForceInculeList The list of files which will be included forcely
1131 # @param SearchPathList The list of search path
1133 # @retval dict The mapping between source file path and its dependencies
1135 def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):
1138 Dependency[F] = GetDependencyList(self._AutoGenObject, self.FileCache, F, ForceInculeList, SearchPathList)
1142 ## CustomMakefile class
1144 # This class encapsules makefie and its generation for module. It uses template to generate
1145 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
1147 class CustomMakefile(BuildFile):
1148 ## template used to generate the makefile for module with custom makefile
1149 _TEMPLATE_ = TemplateString('''\
1153 # Platform Macro Definition
1155 PLATFORM_NAME = ${platform_name}
1156 PLATFORM_GUID = ${platform_guid}
1157 PLATFORM_VERSION = ${platform_version}
1158 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
1159 PLATFORM_DIR = ${platform_dir}
1160 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1163 # Module Macro Definition
1165 MODULE_NAME = ${module_name}
1166 MODULE_GUID = ${module_guid}
1167 MODULE_NAME_GUID = ${module_name_guid}
1168 MODULE_VERSION = ${module_version}
1169 MODULE_TYPE = ${module_type}
1170 MODULE_FILE = ${module_file}
1171 MODULE_FILE_BASE_NAME = ${module_file_base_name}
1172 BASE_NAME = $(MODULE_NAME)
1173 MODULE_RELATIVE_DIR = ${module_relative_directory}
1174 MODULE_DIR = ${module_dir}
1177 # Build Configuration Macro Definition
1179 ARCH = ${architecture}
1180 TOOLCHAIN = ${toolchain_tag}
1181 TOOLCHAIN_TAG = ${toolchain_tag}
1182 TARGET = ${build_target}
1185 # Build Directory Macro Definition
1187 # PLATFORM_BUILD_DIR = ${platform_build_directory}
1188 BUILD_DIR = ${platform_build_directory}
1189 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
1190 LIB_DIR = $(BIN_DIR)
1191 MODULE_BUILD_DIR = ${module_build_directory}
1192 OUTPUT_DIR = ${module_output_directory}
1193 DEBUG_DIR = ${module_debug_directory}
1194 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
1195 DEST_DIR_DEBUG = $(DEBUG_DIR)
1198 # Tools definitions specific to this module
1200 ${BEGIN}${module_tool_definitions}
1202 MAKE_FILE = ${makefile_path}
1205 # Shell Command Macro
1207 ${BEGIN}${shell_command_code} = ${shell_command}
1210 ${custom_makefile_content}
1213 # Target used when called from platform makefile, which will bypass the build of dependent libraries
1226 # Build Target used in multi-thread build mode, which no init target is needed
1232 # Initialization target: print build information and create necessary directories
1235 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
1236 ${BEGIN}\t-@${create_directory_command}\n${END}\
1240 ## Constructor of CustomMakefile
1242 # @param ModuleAutoGen Object of ModuleAutoGen class
1244 def __init__(self, ModuleAutoGen):
1245 BuildFile.__init__(self, ModuleAutoGen)
1246 self.PlatformInfo = self._AutoGenObject.PlatformInfo
1247 self.IntermediateDirectoryList = ["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]
1248 self.DependencyHeaderFileSet = set()
1250 # Compose a dict object containing information used to do replacement in template
1252 def _TemplateDict(self):
1253 Separator = self._SEP_[self._FileType]
1254 MyAgo = self._AutoGenObject
1255 if self._FileType not in MyAgo.CustomMakefile:
1256 EdkLogger.error('build', OPTION_NOT_SUPPORTED, "No custom makefile
for %s" % self._FileType,
1257 ExtraData="[%s]" % str(MyAgo))
1258 MakefilePath = mws.join(
1260 MyAgo.CustomMakefile[self._FileType]
1263 CustomMakefile = open(MakefilePath, 'r').read()
1265 EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(MyAgo),
1266 ExtraData=MyAgo.CustomMakefile[self._FileType])
1270 for Tool in MyAgo.BuildOption:
1271 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
1274 for Attr in MyAgo.BuildOption[Tool]:
1275 if Attr == "FAMILY
":
1277 elif Attr == "PATH
":
1278 ToolsDef.append("%s = %s" % (Tool, MyAgo.BuildOption[Tool][Attr]))
1280 ToolsDef.append("%s_%s = %s" % (Tool, Attr, MyAgo.BuildOption[Tool][Attr]))
1283 MakefileName = self._FILE_NAME_[self._FileType]
1284 MakefileTemplateDict = {
1285 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1286 "makefile_path
" : os.path.join("$
(MODULE_BUILD_DIR
)", MakefileName),
1287 "platform_name
" : self.PlatformInfo.Name,
1288 "platform_guid
" : self.PlatformInfo.Guid,
1289 "platform_version
" : self.PlatformInfo.Version,
1290 "platform_relative_directory
": self.PlatformInfo.SourceDir,
1291 "platform_output_directory
" : self.PlatformInfo.OutputDir,
1292 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1294 "module_name
" : MyAgo.Name,
1295 "module_guid
" : MyAgo.Guid,
1296 "module_name_guid
" : MyAgo.UniqueBaseName,
1297 "module_version
" : MyAgo.Version,
1298 "module_type
" : MyAgo.ModuleType,
1299 "module_file
" : MyAgo.MetaFile,
1300 "module_file_base_name
" : MyAgo.MetaFile.BaseName,
1301 "module_relative_directory
" : MyAgo.SourceDir,
1302 "module_dir
" : mws.join (MyAgo.WorkspaceDir, MyAgo.SourceDir),
1304 "architecture
" : MyAgo.Arch,
1305 "toolchain_tag
" : MyAgo.ToolChain,
1306 "build_target
" : MyAgo.BuildTarget,
1308 "platform_build_directory
" : self.PlatformInfo.BuildDir,
1309 "module_build_directory
" : MyAgo.BuildDir,
1310 "module_output_directory
" : MyAgo.OutputDir,
1311 "module_debug_directory
" : MyAgo.DebugDir,
1313 "separator
" : Separator,
1314 "module_tool_definitions
" : ToolsDef,
1316 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1317 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1319 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1320 "custom_makefile_content
" : CustomMakefile
1323 return MakefileTemplateDict
1325 ## PlatformMakefile class
1327 # This class encapsules makefie and its generation for platform. It uses
1328 # template to generate the content of makefile. The content of makefile will be
1329 # got from PlatformAutoGen object.
1331 class PlatformMakefile(BuildFile):
1332 ## template used to generate the makefile for platform
1333 _TEMPLATE_ = TemplateString('''\
1337 # Platform Macro Definition
1339 PLATFORM_NAME = ${platform_name}
1340 PLATFORM_GUID = ${platform_guid}
1341 PLATFORM_VERSION = ${platform_version}
1342 PLATFORM_FILE = ${platform_file}
1343 PLATFORM_DIR = ${platform_dir}
1344 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1347 # Build Configuration Macro Definition
1349 TOOLCHAIN = ${toolchain_tag}
1350 TOOLCHAIN_TAG = ${toolchain_tag}
1351 TARGET = ${build_target}
1354 # Build Directory Macro Definition
1356 BUILD_DIR = ${platform_build_directory}
1357 FV_DIR = ${platform_build_directory}${separator}FV
1360 # Shell Command Macro
1362 ${BEGIN}${shell_command_code} = ${shell_command}
1366 MAKE_FILE = ${makefile_path}
1371 all: init build_libraries build_modules
1374 # Initialization target: print build information and create necessary directories
1377 \t-@echo Building ... $(PLATFORM_FILE) [${build_architecture_list}]
1378 \t${BEGIN}-@${create_directory_command}
1381 # library build target
1383 libraries: init build_libraries
1386 # module build target
1388 modules: init build_libraries build_modules
1391 # Build all libraries:
1394 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${library_makefile_list} pbuild
1395 ${END}\t@cd $(BUILD_DIR)
1398 # Build all modules:
1401 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${module_makefile_list} pbuild
1402 ${END}\t@cd $(BUILD_DIR)
1405 # Clean intermediate files
1408 \t${BEGIN}-@${library_build_command} clean
1409 \t${END}${BEGIN}-@${module_build_command} clean
1410 \t${END}@cd $(BUILD_DIR)
1413 # Clean all generated files except to makefile
1416 ${BEGIN}\t${cleanall_command}
1420 # Clean all library files
1423 \t${BEGIN}-@${library_build_command} cleanall
1424 \t${END}@cd $(BUILD_DIR)\n
1427 ## Constructor of PlatformMakefile
1429 # @param ModuleAutoGen Object of PlatformAutoGen class
1431 def __init__(self, PlatformAutoGen):
1432 BuildFile.__init__(self, PlatformAutoGen)
1433 self.ModuleBuildCommandList = []
1434 self.ModuleMakefileList = []
1435 self.IntermediateDirectoryList = []
1436 self.ModuleBuildDirectoryList = []
1437 self.LibraryBuildDirectoryList = []
1438 self.LibraryMakeCommandList = []
1439 self.DependencyHeaderFileSet = set()
1441 # Compose a dict object containing information used to do replacement in template
1443 def _TemplateDict(self):
1444 Separator = self._SEP_[self._FileType]
1446 MyAgo = self._AutoGenObject
1447 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1448 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1449 ExtraData="[%s]" % str(MyAgo))
1451 self.IntermediateDirectoryList = ["$
(BUILD_DIR
)"]
1452 self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()
1453 self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()
1455 MakefileName = self._FILE_NAME_[self._FileType]
1456 LibraryMakefileList = []
1457 LibraryMakeCommandList = []
1458 for D in self.LibraryBuildDirectoryList:
1459 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1460 Makefile = os.path.join(D, MakefileName)
1461 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1462 LibraryMakefileList.append(Makefile)
1463 LibraryMakeCommandList.append(Command)
1464 self.LibraryMakeCommandList = LibraryMakeCommandList
1466 ModuleMakefileList = []
1467 ModuleMakeCommandList = []
1468 for D in self.ModuleBuildDirectoryList:
1469 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1470 Makefile = os.path.join(D, MakefileName)
1471 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1472 ModuleMakefileList.append(Makefile)
1473 ModuleMakeCommandList.append(Command)
1475 MakefileTemplateDict = {
1476 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1477 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1478 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1479 "makefile_name
" : MakefileName,
1480 "platform_name
" : MyAgo.Name,
1481 "platform_guid
" : MyAgo.Guid,
1482 "platform_version
" : MyAgo.Version,
1483 "platform_file
" : MyAgo.MetaFile,
1484 "platform_relative_directory
": MyAgo.SourceDir,
1485 "platform_output_directory
" : MyAgo.OutputDir,
1486 "platform_build_directory
" : MyAgo.BuildDir,
1487 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1489 "toolchain_tag
" : MyAgo.ToolChain,
1490 "build_target
" : MyAgo.BuildTarget,
1491 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1492 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1493 "build_architecture_list
" : MyAgo.Arch,
1494 "architecture
" : MyAgo.Arch,
1495 "separator
" : Separator,
1496 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1497 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1498 "library_makefile_list
" : LibraryMakefileList,
1499 "module_makefile_list
" : ModuleMakefileList,
1500 "library_build_command
" : LibraryMakeCommandList,
1501 "module_build_command
" : ModuleMakeCommandList,
1504 return MakefileTemplateDict
1506 ## Get the root directory list for intermediate files of all modules build
1508 # @retval list The list of directory
1510 def GetModuleBuildDirectoryList(self):
1512 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1513 if not ModuleAutoGen.IsBinaryModule:
1514 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1517 ## Get the root directory list for intermediate files of all libraries build
1519 # @retval list The list of directory
1521 def GetLibraryBuildDirectoryList(self):
1523 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1524 if not LibraryAutoGen.IsBinaryModule:
1525 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1528 ## TopLevelMakefile class
1530 # This class encapsules makefie and its generation for entrance makefile. It
1531 # uses template to generate the content of makefile. The content of makefile
1532 # will be got from WorkspaceAutoGen object.
1534 class TopLevelMakefile(BuildFile):
1535 ## template used to generate toplevel makefile
1536 _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}''')
1538 ## Constructor of TopLevelMakefile
1540 # @param Workspace Object of WorkspaceAutoGen class
1542 def __init__(self, Workspace):
1543 BuildFile.__init__(self, Workspace)
1544 self.IntermediateDirectoryList = []
1545 self.DependencyHeaderFileSet = set()
1547 # Compose a dict object containing information used to do replacement in template
1549 def _TemplateDict(self):
1550 Separator = self._SEP_[self._FileType]
1552 # any platform autogen object is ok because we just need common information
1553 MyAgo = self._AutoGenObject
1555 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1556 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1557 ExtraData="[%s]" % str(MyAgo))
1559 for Arch in MyAgo.ArchList:
1560 self.IntermediateDirectoryList.append(Separator.join(["$
(BUILD_DIR
)", Arch]))
1561 self.IntermediateDirectoryList.append("$
(FV_DIR
)")
1563 # TRICK: for not generating GenFds call in makefile if no FDF file
1565 if MyAgo.FdfFile is not None and MyAgo.FdfFile != "":
1566 FdfFileList = [MyAgo.FdfFile]
1567 # macros passed to GenFds
1569 MacroDict.update(GlobalData.gGlobalDefines)
1570 MacroDict.update(GlobalData.gCommandLineDefines)
1571 for MacroName in MacroDict:
1572 if MacroDict[MacroName] != "":
1573 MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
1575 MacroList.append('"%s"' % MacroName)
1579 # pass extra common options to external program called in makefile, currently GenFds.exe
1581 LogLevel = EdkLogger.GetLevel()
1582 if LogLevel == EdkLogger.VERBOSE:
1583 ExtraOption += " -v
"
1584 elif LogLevel <= EdkLogger.DEBUG_9:
1585 ExtraOption += " -d
%d" % (LogLevel - 1)
1586 elif LogLevel == EdkLogger.QUIET:
1587 ExtraOption += " -q
"
1589 if GlobalData.gCaseInsensitive:
1590 ExtraOption += " -c
"
1591 if not GlobalData.gEnableGenfdsMultiThread:
1592 ExtraOption += " --no
-genfds
-multi
-thread
"
1593 if GlobalData.gIgnoreSource:
1594 ExtraOption += " --ignore
-sources
"
1596 for pcd in GlobalData.BuildOptionPcd:
1598 pcdname = '.'.join(pcd[0:3])
1600 pcdname = '.'.join(pcd[0:2])
1601 if pcd[3].startswith('{'):
1602 ExtraOption += " --pcd
" + pcdname + '=' + 'H' + '"' + pcd[3] + '"'
1604 ExtraOption += " --pcd
" + pcdname + '=' + pcd[3]
1606 MakefileName = self._FILE_NAME_[self._FileType]
1607 SubBuildCommandList = []
1608 for A in MyAgo.ArchList:
1609 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join("$
(BUILD_DIR
)", A, MakefileName)}
1610 SubBuildCommandList.append(Command)
1612 MakefileTemplateDict = {
1613 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1614 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1615 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1616 "platform_name
" : MyAgo.Name,
1617 "platform_guid
" : MyAgo.Guid,
1618 "platform_version
" : MyAgo.Version,
1619 "platform_build_directory
" : MyAgo.BuildDir,
1620 "conf_directory
" : GlobalData.gConfDirectory,
1622 "toolchain_tag
" : MyAgo.ToolChain,
1623 "build_target
" : MyAgo.BuildTarget,
1624 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1625 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1626 'arch' : list(MyAgo.ArchList),
1627 "build_architecture_list
" : ','.join(MyAgo.ArchList),
1628 "separator
" : Separator,
1629 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1630 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1631 "sub_build_command
" : SubBuildCommandList,
1632 "fdf_file
" : FdfFileList,
1633 "active_platform
" : str(MyAgo),
1634 "fd
" : MyAgo.FdTargetList,
1635 "fv
" : MyAgo.FvTargetList,
1636 "cap
" : MyAgo.CapTargetList,
1637 "extra_options
" : ExtraOption,
1638 "macro
" : MacroList,
1641 return MakefileTemplateDict
1643 ## Get the root directory list for intermediate files of all modules build
1645 # @retval list The list of directory
1647 def GetModuleBuildDirectoryList(self):
1649 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1650 if not ModuleAutoGen.IsBinaryModule:
1651 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1654 ## Get the root directory list for intermediate files of all libraries build
1656 # @retval list The list of directory
1658 def GetLibraryBuildDirectoryList(self):
1660 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1661 if not LibraryAutoGen.IsBinaryModule:
1662 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1665 ## Find dependencies for one source file
1667 # By searching recursively "#include" directive in file, find out all the
1668 # files needed by given source file. The dependencies will be only searched
1669 # in given search path list.
1671 # @param File The source file
1672 # @param ForceInculeList The list of files which will be included forcely
1673 # @param SearchPathList The list of search path
1675 # @retval list The list of files the given source file depends on
1677 def GetDependencyList(AutoGenObject
, FileCache
, File
, ForceList
, SearchPathList
):
1678 EdkLogger
.debug(EdkLogger
.DEBUG_1
, "Try to get dependency files for %s" % File
)
1679 FileStack
= [File
] + ForceList
1680 DependencySet
= set()
1682 if AutoGenObject
.Arch
not in gDependencyDatabase
:
1683 gDependencyDatabase
[AutoGenObject
.Arch
] = {}
1684 DepDb
= gDependencyDatabase
[AutoGenObject
.Arch
]
1686 while len(FileStack
) > 0:
1689 FullPathDependList
= []
1691 for CacheFile
in FileCache
[F
]:
1692 FullPathDependList
.append(CacheFile
)
1693 if CacheFile
not in DependencySet
:
1694 FileStack
.append(CacheFile
)
1695 DependencySet
.update(FullPathDependList
)
1698 CurrentFileDependencyList
= []
1700 CurrentFileDependencyList
= DepDb
[F
]
1703 Fd
= open(F
.Path
, 'rb')
1704 FileContent
= Fd
.read()
1706 except BaseException
as X
:
1707 EdkLogger
.error("build", FILE_OPEN_FAILURE
, ExtraData
=F
.Path
+ "\n\t" + str(X
))
1708 if len(FileContent
) == 0:
1711 if FileContent
[0] == 0xff or FileContent
[0] == 0xfe:
1712 FileContent
= FileContent
.decode('utf-16')
1714 FileContent
= FileContent
.decode()
1716 # The file is not txt file. for example .mcb file
1718 IncludedFileList
= gIncludePattern
.findall(FileContent
)
1720 for Inc
in IncludedFileList
:
1722 # if there's macro used to reference header file, expand it
1723 HeaderList
= gMacroPattern
.findall(Inc
)
1724 if len(HeaderList
) == 1 and len(HeaderList
[0]) == 2:
1725 HeaderType
= HeaderList
[0][0]
1726 HeaderKey
= HeaderList
[0][1]
1727 if HeaderType
in gIncludeMacroConversion
:
1728 Inc
= gIncludeMacroConversion
[HeaderType
] % {"HeaderKey" : HeaderKey
}
1730 # not known macro used in #include, always build the file by
1731 # returning a empty dependency
1732 FileCache
[File
] = []
1734 Inc
= os
.path
.normpath(Inc
)
1735 CurrentFileDependencyList
.append(Inc
)
1736 DepDb
[F
] = CurrentFileDependencyList
1738 CurrentFilePath
= F
.Dir
1739 PathList
= [CurrentFilePath
] + SearchPathList
1740 for Inc
in CurrentFileDependencyList
:
1741 for SearchPath
in PathList
:
1742 FilePath
= os
.path
.join(SearchPath
, Inc
)
1743 if FilePath
in gIsFileMap
:
1744 if not gIsFileMap
[FilePath
]:
1746 # If isfile is called too many times, the performance is slow down.
1747 elif not os
.path
.isfile(FilePath
):
1748 gIsFileMap
[FilePath
] = False
1751 gIsFileMap
[FilePath
] = True
1752 FilePath
= PathClass(FilePath
)
1753 FullPathDependList
.append(FilePath
)
1754 if FilePath
not in DependencySet
:
1755 FileStack
.append(FilePath
)
1758 EdkLogger
.debug(EdkLogger
.DEBUG_9
, "%s included by %s was not found "\
1759 "in any given path:\n\t%s" % (Inc
, F
, "\n\t".join(SearchPathList
)))
1761 FileCache
[F
] = FullPathDependList
1762 DependencySet
.update(FullPathDependList
)
1764 DependencySet
.update(ForceList
)
1765 if File
in DependencySet
:
1766 DependencySet
.remove(File
)
1767 DependencyList
= list(DependencySet
) # remove duplicate ones
1769 return DependencyList
1771 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1772 if __name__
== '__main__':