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 = []
453 # Compose a dict object containing information used to do replacement in template
455 def _TemplateDict(self):
456 if self._FileType not in self._SEP_:
457 EdkLogger.error("build
", PARAMETER_INVALID, "Invalid Makefile
type [%s]" % self._FileType,
458 ExtraData="[%s]" % str(self._AutoGenObject))
459 MyAgo = self._AutoGenObject
460 Separator = self._SEP_[self._FileType]
462 # break build if no source files and binary files are found
463 if len(MyAgo.SourceFileList) == 0 and len(MyAgo.BinaryFileList) == 0:
464 EdkLogger.error("build
", AUTOGEN_ERROR, "No files to be built
in module
[%s, %s, %s]"
465 % (MyAgo.BuildTarget, MyAgo.ToolChain, MyAgo.Arch),
466 ExtraData="[%s]" % str(MyAgo))
468 # convert dependent libraries to build command
469 self.ProcessDependentLibrary()
470 if len(MyAgo.Module.ModuleEntryPointList) > 0:
471 ModuleEntryPoint = MyAgo.Module.ModuleEntryPointList[0]
473 ModuleEntryPoint = "_ModuleEntryPoint
"
475 ArchEntryPoint = ModuleEntryPoint
477 if MyAgo.Arch == "EBC
":
478 # EBC compiler always use "EfiStart
" as entry point. Only applies to EdkII modules
479 ImageEntryPoint = "EfiStart
"
481 # EdkII modules always use "_ModuleEntryPoint
" as entry point
482 ImageEntryPoint = "_ModuleEntryPoint
"
484 for k, v in MyAgo.Module.Defines.items():
485 if k not in MyAgo.Macros:
488 if 'MODULE_ENTRY_POINT' not in MyAgo.Macros:
489 MyAgo.Macros['MODULE_ENTRY_POINT'] = ModuleEntryPoint
490 if 'ARCH_ENTRY_POINT' not in MyAgo.Macros:
491 MyAgo.Macros['ARCH_ENTRY_POINT'] = ArchEntryPoint
492 if 'IMAGE_ENTRY_POINT' not in MyAgo.Macros:
493 MyAgo.Macros['IMAGE_ENTRY_POINT'] = ImageEntryPoint
495 PCI_COMPRESS_Flag = False
496 for k, v in MyAgo.Module.Defines.items():
497 if 'PCI_COMPRESS' == k and 'TRUE' == v:
498 PCI_COMPRESS_Flag = True
502 IncPrefix = self._INC_FLAG_[MyAgo.ToolChainFamily]
503 for Tool in MyAgo.BuildOption:
504 for Attr in MyAgo.BuildOption[Tool]:
505 Value = MyAgo.BuildOption[Tool][Attr]
509 ToolsDef.append("%s = %s" % (Tool, Value))
511 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
514 # Remove duplicated include path, if any
516 Value = RemoveDupOption(Value, IncPrefix, MyAgo.IncludePathList)
517 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Tool == 'CC' and '/GM' in Value:
518 Value = Value.replace(' /MP', '')
519 MyAgo.BuildOption[Tool][Attr] = Value
520 if Tool == "OPTROM
" and PCI_COMPRESS_Flag:
521 ValueList = Value.split()
523 for i, v in enumerate(ValueList):
526 Value = ' '.join(ValueList)
528 ToolsDef.append("%s_%s = %s" % (Tool, Attr, Value))
531 # generate the Response file and Response flag
532 RespDict = self.CommandExceedLimit()
533 RespFileList = os.path.join(MyAgo.OutputDir, 'respfilelist.txt')
535 RespFileListContent = ''
536 for Resp in RespDict:
537 RespFile = os.path.join(MyAgo.OutputDir, str(Resp).lower() + '.txt')
538 StrList = RespDict[Resp].split(' ')
543 UnexpandMacro.append(Str)
546 UnexpandMacroStr = ' '.join(UnexpandMacro)
547 NewRespStr = ' '.join(NewStr)
548 SaveFileOnChange(RespFile, NewRespStr, False)
549 ToolsDef.append("%s = %s" % (Resp, UnexpandMacroStr + ' @' + RespFile))
550 RespFileListContent += '@' + RespFile + TAB_LINE_BREAK
551 RespFileListContent += NewRespStr + TAB_LINE_BREAK
552 SaveFileOnChange(RespFileList, RespFileListContent, False)
554 if os.path.exists(RespFileList):
555 os.remove(RespFileList)
557 # convert source files and binary files to build targets
558 self.ResultFileList = [str(T.Target) for T in MyAgo.CodaTargetList]
559 if len(self.ResultFileList) == 0 and len(MyAgo.SourceFileList) != 0:
560 EdkLogger.error("build
", AUTOGEN_ERROR, "Nothing to build
",
561 ExtraData="[%s]" % str(MyAgo))
563 self.ProcessBuildTargetList()
564 self.ParserGenerateFfsCmd()
566 # Generate macros used to represent input files
567 FileMacroList = [] # macro name = file list
568 for FileListMacro in self.FileListMacros:
569 FileMacro = self._FILE_MACRO_TEMPLATE.Replace(
571 "macro_name
" : FileListMacro,
572 "source_file
" : self.FileListMacros[FileListMacro]
575 FileMacroList.append(FileMacro)
577 # INC_LIST is special
580 for P in MyAgo.IncludePathList:
581 IncludePathList.append(IncPrefix + self.PlaceMacro(P, self.Macros))
582 if FileBuildRule.INC_LIST_MACRO in self.ListFileMacros:
583 self.ListFileMacros[FileBuildRule.INC_LIST_MACRO].append(IncPrefix + P)
584 FileMacro += self._FILE_MACRO_TEMPLATE.Replace(
586 "macro_name
" : "INC
",
587 "source_file
" : IncludePathList
590 FileMacroList.append(FileMacro)
591 # Add support when compiling .nasm source files
592 for File in self.FileCache.keys():
593 if not str(File).endswith('.nasm'):
596 for P in MyAgo.IncludePathList:
597 IncludePath = self._INC_FLAG_['NASM'] + self.PlaceMacro(P, self.Macros)
598 if IncludePath.endswith(os.sep):
599 IncludePath = IncludePath.rstrip(os.sep)
600 # When compiling .nasm files, need to add a literal backslash at each path
601 # To specify a literal backslash at the end of the line, precede it with a caret (^)
602 if P == MyAgo.IncludePathList[-1] and os.sep == '\\':
603 IncludePath = ''.join([IncludePath, '^', os.sep])
605 IncludePath = os.path.join(IncludePath, '')
606 IncludePathList.append(IncludePath)
607 FileMacroList.append(self._FILE_MACRO_TEMPLATE.Replace({"macro_name
": "NASM_INC
", "source_file
": IncludePathList}))
610 # Generate macros used to represent files containing list of input files
611 for ListFileMacro in self.ListFileMacros:
612 ListFileName = os.path.join(MyAgo.OutputDir, "%s.lst
" % ListFileMacro.lower()[:len(ListFileMacro) - 5])
613 FileMacroList.append("%s = %s" % (ListFileMacro, ListFileName))
616 "\n".join(self.ListFileMacros[ListFileMacro]),
620 # Generate objlist used to create .obj file
621 for Type in self.ObjTargetDict:
622 NewLine = ' '.join(list(self.ObjTargetDict[Type]))
623 FileMacroList.append("OBJLIST_
%s = %s" % (list(self.ObjTargetDict.keys()).index(Type), NewLine))
627 MakefileName = self._FILE_NAME_[self._FileType]
628 LibraryMakeCommandList = []
629 for D in self.LibraryBuildDirectoryList:
630 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join(D, MakefileName)}
631 LibraryMakeCommandList.append(Command)
633 package_rel_dir = MyAgo.SourceDir
634 current_dir = self.Macros["WORKSPACE
"]
636 while not found and os.sep in package_rel_dir:
637 index = package_rel_dir.index(os.sep)
638 current_dir = mws.join(current_dir, package_rel_dir[:index])
640 for fl in os.listdir(current_dir):
641 if fl.endswith('.dec'):
645 EdkLogger.error('build', FILE_NOT_FOUND, "WORKSPACE does
not exist
.")
646 package_rel_dir = package_rel_dir[index + 1:]
648 MakefileTemplateDict = {
649 "makefile_header
" : self._FILE_HEADER_[self._FileType],
650 "makefile_path
" : os.path.join("$
(MODULE_BUILD_DIR
)", MakefileName),
651 "makefile_name
" : MakefileName,
652 "platform_name
" : self.PlatformInfo.Name,
653 "platform_guid
" : self.PlatformInfo.Guid,
654 "platform_version
" : self.PlatformInfo.Version,
655 "platform_relative_directory
": self.PlatformInfo.SourceDir,
656 "platform_output_directory
" : self.PlatformInfo.OutputDir,
657 "ffs_output_directory
" : MyAgo.Macros["FFS_OUTPUT_DIR
"],
658 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
660 "module_name
" : MyAgo.Name,
661 "module_guid
" : MyAgo.Guid,
662 "module_name_guid
" : MyAgo.UniqueBaseName,
663 "module_version
" : MyAgo.Version,
664 "module_type
" : MyAgo.ModuleType,
665 "module_file
" : MyAgo.MetaFile.Name,
666 "module_file_base_name
" : MyAgo.MetaFile.BaseName,
667 "module_relative_directory
" : MyAgo.SourceDir,
668 "module_dir
" : mws.join (self.Macros["WORKSPACE
"], MyAgo.SourceDir),
669 "package_relative_directory
": package_rel_dir,
670 "module_extra_defines
" : ["%s = %s" % (k, v) for k, v in MyAgo.Module.Defines.items()],
672 "architecture
" : MyAgo.Arch,
673 "toolchain_tag
" : MyAgo.ToolChain,
674 "build_target
" : MyAgo.BuildTarget,
676 "platform_build_directory
" : self.PlatformInfo.BuildDir,
677 "module_build_directory
" : MyAgo.BuildDir,
678 "module_output_directory
" : MyAgo.OutputDir,
679 "module_debug_directory
" : MyAgo.DebugDir,
681 "separator
" : Separator,
682 "module_tool_definitions
" : ToolsDef,
684 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
685 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
687 "module_entry_point
" : ModuleEntryPoint,
688 "image_entry_point
" : ImageEntryPoint,
689 "arch_entry_point
" : ArchEntryPoint,
690 "remaining_build_target
" : self.ResultFileList,
691 "common_dependency_file
" : self.CommonFileDependency,
692 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
693 "clean_command
" : self.GetRemoveDirectoryCommand(["$
(OUTPUT_DIR
)"]),
694 "cleanall_command
" : self.GetRemoveDirectoryCommand(["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]),
695 "dependent_library_build_directory
" : self.LibraryBuildDirectoryList,
696 "library_build_command
" : LibraryMakeCommandList,
697 "file_macro
" : FileMacroList,
698 "file_build_target
" : self.BuildTargetList,
699 "backward_compatible_target
": BcTargetList,
702 return MakefileTemplateDict
704 def ParserGenerateFfsCmd(self):
705 #Add Ffs cmd to self.BuildTargetList
709 for Cmd in self.GenFfsList:
711 for CopyCmd in Cmd[2]:
713 Src = self.ReplaceMacro(Src)
714 Dst = self.ReplaceMacro(Dst)
715 if Dst not in self.ResultFileList:
716 self.ResultFileList.append(Dst)
717 if '%s :' %(Dst) not in self.BuildTargetList:
718 self.BuildTargetList.append("%s :" %(Dst))
719 self.BuildTargetList.append('\t' + self._CP_TEMPLATE_[self._FileType] %{'Src': Src, 'Dst': Dst})
722 for index, Str in enumerate(FfsCmdList):
724 OutputFile = FfsCmdList[index + 1]
725 if '-i' == Str or "-oi
" == Str:
726 if DepsFileList == []:
727 DepsFileList = [FfsCmdList[index + 1]]
729 DepsFileList.append(FfsCmdList[index + 1])
730 DepsFileString = ' '.join(DepsFileList).strip()
731 if DepsFileString == '':
733 OutputFile = self.ReplaceMacro(OutputFile)
734 self.ResultFileList.append(OutputFile)
735 DepsFileString = self.ReplaceMacro(DepsFileString)
736 self.BuildTargetList.append('%s : %s' % (OutputFile, DepsFileString))
737 CmdString = ' '.join(FfsCmdList).strip()
738 CmdString = self.ReplaceMacro(CmdString)
739 self.BuildTargetList.append('\t%s' % CmdString)
741 self.ParseSecCmd(DepsFileList, Cmd[1])
742 for SecOutputFile, SecDepsFile, SecCmd in self.FfsOutputFileList :
743 self.BuildTargetList.append('%s : %s' % (self.ReplaceMacro(SecOutputFile), self.ReplaceMacro(SecDepsFile)))
744 self.BuildTargetList.append('\t%s' % self.ReplaceMacro(SecCmd))
745 self.FfsOutputFileList = []
747 def ParseSecCmd(self, OutputFileList, CmdTuple):
748 for OutputFile in OutputFileList:
749 for SecCmdStr in CmdTuple:
751 SecCmdList = SecCmdStr.split()
752 CmdName = SecCmdList[0]
753 for index, CmdItem in enumerate(SecCmdList):
754 if '-o' == CmdItem and OutputFile == SecCmdList[index + 1]:
756 while index + 1 < len(SecCmdList):
757 if not SecCmdList[index+1].startswith('-'):
758 SecDepsFileList.append(SecCmdList[index + 1])
760 if CmdName == 'Trim':
761 SecDepsFileList.append(os.path.join('$(DEBUG_DIR)', os.path.basename(OutputFile).replace('offset', 'efi')))
762 if OutputFile.endswith('.ui') or OutputFile.endswith('.ver'):
763 SecDepsFileList.append(os.path.join('$(MODULE_DIR)', '$(MODULE_FILE)'))
764 self.FfsOutputFileList.append((OutputFile, ' '.join(SecDepsFileList), SecCmdStr))
765 if len(SecDepsFileList) > 0:
766 self.ParseSecCmd(SecDepsFileList, CmdTuple)
771 def ReplaceMacro(self, str):
772 for Macro in self.MacroList:
773 if self._AutoGenObject.Macros[Macro] and self._AutoGenObject.Macros[Macro] in str:
774 str = str.replace(self._AutoGenObject.Macros[Macro], '$(' + Macro + ')')
777 def CommandExceedLimit(self):
779 'CC' : { 'Macro' : '$(CC_FLAGS)', 'Value' : False},
780 'PP' : { 'Macro' : '$(PP_FLAGS)', 'Value' : False},
781 'APP' : { 'Macro' : '$(APP_FLAGS)', 'Value' : False},
782 'ASLPP' : { 'Macro' : '$(ASLPP_FLAGS)', 'Value' : False},
783 'VFRPP' : { 'Macro' : '$(VFRPP_FLAGS)', 'Value' : False},
784 'ASM' : { 'Macro' : '$(ASM_FLAGS)', 'Value' : False},
785 'ASLCC' : { 'Macro' : '$(ASLCC_FLAGS)', 'Value' : False},
790 IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily]
792 # base on the source files to decide the file type
793 for File in self._AutoGenObject.SourceFileList:
794 for type in self._AutoGenObject.FileTypes:
795 if File in self._AutoGenObject.FileTypes[type]:
796 if type not in FileTypeList:
797 FileTypeList.append(type)
799 # calculate the command-line length
801 for type in FileTypeList:
802 BuildTargets = self._AutoGenObject.BuildRules[type].BuildTargets
803 for Target in BuildTargets:
804 CommandList = BuildTargets[Target].Commands
805 for SingleCommand in CommandList:
807 SingleCommandLength = len(SingleCommand)
808 SingleCommandList = SingleCommand.split()
809 if len(SingleCommandList) > 0:
810 for Flag in FlagDict:
811 if '$('+ Flag +')' in SingleCommandList[0]:
815 if 'PATH' not in self._AutoGenObject.BuildOption[Tool]:
816 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))
817 SingleCommandLength += len(self._AutoGenObject.BuildOption[Tool]['PATH
'])
818 for item in SingleCommandList[1:]:
819 if FlagDict[Tool]['Macro
'] in item:
820 if 'FLAGS
' not in self._AutoGenObject.BuildOption[Tool]:
821 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))
822 Str = self._AutoGenObject.BuildOption[Tool]['FLAGS']
823 for Option in self._AutoGenObject.BuildOption:
824 for Attr in self._AutoGenObject.BuildOption[Option]:
825 if Str.find(Option + '_' + Attr) != -1:
826 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
827 while(Str.find('$(') != -1):
828 for macro in self._AutoGenObject.Macros:
829 MacroName = '$('+ macro + ')'
830 if (Str.find(MacroName) != -1):
831 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
835 SingleCommandLength += len(Str)
836 elif '$(INC)' in item:
837 SingleCommandLength += self._AutoGenObject.IncludePathLength + len(IncPrefix) * len(self._AutoGenObject.IncludePathList)
838 elif item.find('$(') != -1:
840 for Option in self._AutoGenObject.BuildOption:
841 for Attr in self._AutoGenObject.BuildOption[Option]:
842 if Str.find(Option + '_' + Attr) != -1:
843 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
844 while(Str.find('$(') != -1):
845 for macro in self._AutoGenObject.Macros:
846 MacroName = '$('+ macro + ')'
847 if (Str.find(MacroName) != -1):
848 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
852 SingleCommandLength += len(Str)
854 if SingleCommandLength > GlobalData.gCommandMaxLength:
855 FlagDict[Tool]['Value'] = True
857 # generate the response file content by combine the FLAGS and INC
858 for Flag in FlagDict:
859 if FlagDict[Flag]['Value']:
861 RespMacro = FlagDict[Flag]['Macro'].replace('FLAGS', 'RESP')
862 Value = self._AutoGenObject.BuildOption[Flag]['FLAGS']
863 for inc in self._AutoGenObject.IncludePathList:
864 Value += ' ' + IncPrefix + inc
865 for Option in self._AutoGenObject.BuildOption:
866 for Attr in self._AutoGenObject.BuildOption[Option]:
867 if Value.find(Option + '_' + Attr) != -1:
868 Value = Value.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
869 while (Value.find('$(') != -1):
870 for macro in self._AutoGenObject.Macros:
871 MacroName = '$('+ macro + ')'
872 if (Value.find(MacroName) != -1):
873 Value = Value.replace(MacroName, self._AutoGenObject.Macros[macro])
878 if self._AutoGenObject.ToolChainFamily == 'GCC':
879 RespDict[Key] = Value.replace('\\', '/')
881 RespDict[Key] = Value
882 for Target in BuildTargets:
883 for i, SingleCommand in enumerate(BuildTargets[Target].Commands):
884 if FlagDict[Flag]['Macro'] in SingleCommand:
885 BuildTargets[Target].Commands[i] = SingleCommand.replace('$(INC)', '').replace(FlagDict[Flag]['Macro'], RespMacro)
888 def ProcessBuildTargetList(self):
890 # Search dependency file list for each source file
892 ForceIncludedFile = []
893 for File in self._AutoGenObject.AutoGenFileList:
895 ForceIncludedFile.append(File)
898 for Target in self._AutoGenObject.IntroTargetList:
899 SourceFileList.extend(Target.Inputs)
900 OutPutFileList.extend(Target.Outputs)
903 for Item in OutPutFileList:
904 if Item in SourceFileList:
905 SourceFileList.remove(Item)
907 FileDependencyDict = self.GetFileDependency(
910 self._AutoGenObject.IncludePathList + self._AutoGenObject.BuildOptionIncPathList
913 self.DependencyHeaderFileSet = set()
914 if FileDependencyDict:
915 for Dependency in FileDependencyDict.values():
916 self.DependencyHeaderFileSet.update(set(Dependency))
918 # Get a set of unique package includes from MetaFile
919 parentMetaFileIncludes = set()
920 for aInclude in self._AutoGenObject.PackageIncludePathList:
921 aIncludeName = str(aInclude)
922 parentMetaFileIncludes.add(aIncludeName.lower())
924 # Check if header files are listed in metafile
925 # Get a set of unique module header source files from MetaFile
926 headerFilesInMetaFileSet = set()
927 for aFile in self._AutoGenObject.SourceFileList:
928 aFileName = str(aFile)
929 if not aFileName.endswith('.h'):
931 headerFilesInMetaFileSet.add(aFileName.lower())
933 # Get a set of unique module autogen files
934 localAutoGenFileSet = set()
935 for aFile in self._AutoGenObject.AutoGenFileList:
936 localAutoGenFileSet.add(str(aFile).lower())
938 # Get a set of unique module dependency header files
939 # Exclude autogen files and files not in the source directory
940 # and files that are under the package include list
941 headerFileDependencySet = set()
942 localSourceDir = str(self._AutoGenObject.SourceDir).lower()
943 for Dependency in FileDependencyDict.values():
944 for aFile in Dependency:
945 aFileName = str(aFile).lower()
946 # Exclude non-header files
947 if not aFileName.endswith('.h'):
949 # Exclude autogen files
950 if aFileName in localAutoGenFileSet:
952 # Exclude include out of local scope
953 if localSourceDir not in aFileName:
955 # Exclude files covered by package includes
957 for aIncludePath in parentMetaFileIncludes:
958 if aIncludePath in aFileName:
963 # Keep the file to be checked
964 headerFileDependencySet.add(aFileName)
966 # Check if a module dependency header file is missing from the module's MetaFile
967 for aFile in headerFileDependencySet:
968 if aFile in headerFilesInMetaFileSet:
970 if GlobalData.gUseHashCache:
971 GlobalData.gModuleBuildTracking[self._AutoGenObject] = 'FAIL_METAFILE'
972 EdkLogger.warn("build
","Module MetaFile
[Sources
] is missing local header
!",
973 ExtraData = "Local Header
: " + aFile + " not found
in " + self._AutoGenObject.MetaFile.Path
977 for File,Dependency in FileDependencyDict.items():
979 FileDependencyDict[File] = ['$(FORCE_REBUILD)']
982 self._AutoGenObject.AutoGenDepSet |= set(Dependency)
985 if File.Ext not in [".c
", ".C
"] or File.Name == "AutoGen
.c
":
988 DepSet = set(Dependency)
990 DepSet &= set(Dependency)
991 # in case nothing in SourceFileList
995 # Extract common files list in the dependency files
998 self.CommonFileDependency.append(self.PlaceMacro(File.Path, self.Macros))
1003 DependencyDict = FileDependencyDict.copy()
1004 for File in FileDependencyDict:
1006 if File.Ext not in [".c
", ".C
"] or File.Name == "AutoGen
.c
":
1008 NewDepSet = set(FileDependencyDict[File])
1010 FileDependencyDict[File] = ["$
(COMMON_DEPS
)"] + list(NewDepSet)
1011 DependencyDict[File] = list(NewDepSet)
1013 # Convert target description object to target string in makefile
1014 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and TAB_C_CODE_FILE in self._AutoGenObject.Targets:
1015 for T in self._AutoGenObject.Targets[TAB_C_CODE_FILE]:
1016 NewFile = self.PlaceMacro(str(T), self.Macros)
1017 if not self.ObjTargetDict.get(T.Target.SubDir):
1018 self.ObjTargetDict[T.Target.SubDir] = set()
1019 self.ObjTargetDict[T.Target.SubDir].add(NewFile)
1020 for Type in self._AutoGenObject.Targets:
1021 for T in self._AutoGenObject.Targets[Type]:
1022 # Generate related macros if needed
1023 if T.GenFileListMacro and T.FileListMacro not in self.FileListMacros:
1024 self.FileListMacros[T.FileListMacro] = []
1025 if T.GenListFile and T.ListFileMacro not in self.ListFileMacros:
1026 self.ListFileMacros[T.ListFileMacro] = []
1027 if T.GenIncListFile and T.IncListFileMacro not in self.ListFileMacros:
1028 self.ListFileMacros[T.IncListFileMacro] = []
1032 # Add force-dependencies
1033 for Dep in T.Dependencies:
1034 Deps.append(self.PlaceMacro(str(Dep), self.Macros))
1035 if Dep != '$(MAKE_FILE)':
1036 CCodeDeps.append(self.PlaceMacro(str(Dep), self.Macros))
1037 # Add inclusion-dependencies
1038 if len(T.Inputs) == 1 and T.Inputs[0] in FileDependencyDict:
1039 for F in FileDependencyDict[T.Inputs[0]]:
1040 Deps.append(self.PlaceMacro(str(F), self.Macros))
1041 # Add source-dependencies
1043 NewFile = self.PlaceMacro(str(F), self.Macros)
1044 # In order to use file list macro as dependency
1046 # gnu tools need forward slash path separator, even on Windows
1047 self.ListFileMacros[T.ListFileMacro].append(str(F).replace ('\\', '/'))
1048 self.FileListMacros[T.FileListMacro].append(NewFile)
1049 elif T.GenFileListMacro:
1050 self.FileListMacros[T.FileListMacro].append(NewFile)
1052 Deps.append(NewFile)
1053 for key in self.FileListMacros:
1054 self.FileListMacros[key].sort()
1055 # Use file list macro as dependency
1056 if T.GenFileListMacro:
1057 Deps.append("$
(%s)" % T.FileListMacro)
1058 if Type in [TAB_OBJECT_FILE, TAB_STATIC_LIBRARY]:
1059 Deps.append("$
(%s)" % T.ListFileMacro)
1061 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Type == TAB_C_CODE_FILE:
1062 T, CmdTarget, CmdTargetDict, CmdCppDict = self.ParserCCodeFile(T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict)
1063 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": CCodeDeps}
1064 CmdLine = self._BUILD_TARGET_TEMPLATE.Replace(TargetDict).rstrip().replace('\t$(OBJLIST', '$(OBJLIST')
1066 CmdLine = '%s%s' %(CmdLine, TAB_LINE_BREAK)
1067 if CCodeDeps or CmdLine:
1068 self.BuildTargetList.append(CmdLine)
1070 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": Deps}
1071 self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(TargetDict))
1073 def ParserCCodeFile(self, T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict):
1075 for item in self._AutoGenObject.Targets[Type]:
1076 CmdSumDict[item.Target.SubDir] = item.Target.BaseName
1077 for CppPath in item.Inputs:
1078 Path = self.PlaceMacro(CppPath.Path, self.Macros)
1079 if CmdCppDict.get(item.Target.SubDir):
1080 CmdCppDict[item.Target.SubDir].append(Path)
1082 CmdCppDict[item.Target.SubDir] = ['$(MAKE_FILE)', Path]
1083 if CppPath.Path in DependencyDict:
1084 for Temp in DependencyDict[CppPath.Path]:
1086 Path = self.PlaceMacro(Temp.Path, self.Macros)
1089 if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):
1090 CmdCppDict[item.Target.SubDir].append(Path)
1092 CommandList = T.Commands[:]
1093 for Item in CommandList[:]:
1094 SingleCommandList = Item.split()
1095 if len(SingleCommandList) > 0 and self.CheckCCCmd(SingleCommandList):
1096 for Temp in SingleCommandList:
1097 if Temp.startswith('/Fo'):
1098 CmdSign = '%s%s' % (Temp.rsplit(TAB_SLASH, 1)[0], TAB_SLASH)
1101 if CmdSign not in list(CmdTargetDict.keys()):
1102 CmdTargetDict[CmdSign] = Item.replace(Temp, CmdSign)
1104 CmdTargetDict[CmdSign] = "%s %s" % (CmdTargetDict[CmdSign], SingleCommandList[-1])
1105 Index = CommandList.index(Item)
1106 CommandList.pop(Index)
1107 if SingleCommandList[-1].endswith("%s%s.c
" % (TAB_SLASH, CmdSumDict[CmdSign[3:].rsplit(TAB_SLASH, 1)[0]])):
1108 Cpplist = CmdCppDict[T.Target.SubDir]
1109 Cpplist.insert(0, '$(OBJLIST_%d): $(COMMON_DEPS)' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir))
1110 T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign])
1112 T.Commands.pop(Index)
1113 return T, CmdSumDict, CmdTargetDict, CmdCppDict
1115 def CheckCCCmd(self, CommandList):
1116 for cmd in CommandList:
1120 ## For creating makefile targets for dependent libraries
1121 def ProcessDependentLibrary(self):
1122 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1123 if not LibraryAutoGen.IsBinaryModule:
1124 self.LibraryBuildDirectoryList.append(self.PlaceMacro(LibraryAutoGen.BuildDir, self.Macros))
1126 ## Return a list containing source file's dependencies
1128 # @param FileList The list of source files
1129 # @param ForceInculeList The list of files which will be included forcely
1130 # @param SearchPathList The list of search path
1132 # @retval dict The mapping between source file path and its dependencies
1134 def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):
1137 Dependency[F] = GetDependencyList(self._AutoGenObject, self.FileCache, F, ForceInculeList, SearchPathList)
1141 ## CustomMakefile class
1143 # This class encapsules makefie and its generation for module. It uses template to generate
1144 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
1146 class CustomMakefile(BuildFile):
1147 ## template used to generate the makefile for module with custom makefile
1148 _TEMPLATE_ = TemplateString('''\
1152 # Platform Macro Definition
1154 PLATFORM_NAME = ${platform_name}
1155 PLATFORM_GUID = ${platform_guid}
1156 PLATFORM_VERSION = ${platform_version}
1157 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
1158 PLATFORM_DIR = ${platform_dir}
1159 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1162 # Module Macro Definition
1164 MODULE_NAME = ${module_name}
1165 MODULE_GUID = ${module_guid}
1166 MODULE_NAME_GUID = ${module_name_guid}
1167 MODULE_VERSION = ${module_version}
1168 MODULE_TYPE = ${module_type}
1169 MODULE_FILE = ${module_file}
1170 MODULE_FILE_BASE_NAME = ${module_file_base_name}
1171 BASE_NAME = $(MODULE_NAME)
1172 MODULE_RELATIVE_DIR = ${module_relative_directory}
1173 MODULE_DIR = ${module_dir}
1176 # Build Configuration Macro Definition
1178 ARCH = ${architecture}
1179 TOOLCHAIN = ${toolchain_tag}
1180 TOOLCHAIN_TAG = ${toolchain_tag}
1181 TARGET = ${build_target}
1184 # Build Directory Macro Definition
1186 # PLATFORM_BUILD_DIR = ${platform_build_directory}
1187 BUILD_DIR = ${platform_build_directory}
1188 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
1189 LIB_DIR = $(BIN_DIR)
1190 MODULE_BUILD_DIR = ${module_build_directory}
1191 OUTPUT_DIR = ${module_output_directory}
1192 DEBUG_DIR = ${module_debug_directory}
1193 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
1194 DEST_DIR_DEBUG = $(DEBUG_DIR)
1197 # Tools definitions specific to this module
1199 ${BEGIN}${module_tool_definitions}
1201 MAKE_FILE = ${makefile_path}
1204 # Shell Command Macro
1206 ${BEGIN}${shell_command_code} = ${shell_command}
1209 ${custom_makefile_content}
1212 # Target used when called from platform makefile, which will bypass the build of dependent libraries
1225 # Build Target used in multi-thread build mode, which no init target is needed
1231 # Initialization target: print build information and create necessary directories
1234 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
1235 ${BEGIN}\t-@${create_directory_command}\n${END}\
1239 ## Constructor of CustomMakefile
1241 # @param ModuleAutoGen Object of ModuleAutoGen class
1243 def __init__(self, ModuleAutoGen):
1244 BuildFile.__init__(self, ModuleAutoGen)
1245 self.PlatformInfo = self._AutoGenObject.PlatformInfo
1246 self.IntermediateDirectoryList = ["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]
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 = []
1438 # Compose a dict object containing information used to do replacement in template
1440 def _TemplateDict(self):
1441 Separator = self._SEP_[self._FileType]
1443 MyAgo = self._AutoGenObject
1444 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1445 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1446 ExtraData="[%s]" % str(MyAgo))
1448 self.IntermediateDirectoryList = ["$
(BUILD_DIR
)"]
1449 self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()
1450 self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()
1452 MakefileName = self._FILE_NAME_[self._FileType]
1453 LibraryMakefileList = []
1454 LibraryMakeCommandList = []
1455 for D in self.LibraryBuildDirectoryList:
1456 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1457 Makefile = os.path.join(D, MakefileName)
1458 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1459 LibraryMakefileList.append(Makefile)
1460 LibraryMakeCommandList.append(Command)
1461 self.LibraryMakeCommandList = LibraryMakeCommandList
1463 ModuleMakefileList = []
1464 ModuleMakeCommandList = []
1465 for D in self.ModuleBuildDirectoryList:
1466 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1467 Makefile = os.path.join(D, MakefileName)
1468 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1469 ModuleMakefileList.append(Makefile)
1470 ModuleMakeCommandList.append(Command)
1472 MakefileTemplateDict = {
1473 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1474 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1475 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1476 "makefile_name
" : MakefileName,
1477 "platform_name
" : MyAgo.Name,
1478 "platform_guid
" : MyAgo.Guid,
1479 "platform_version
" : MyAgo.Version,
1480 "platform_file
" : MyAgo.MetaFile,
1481 "platform_relative_directory
": MyAgo.SourceDir,
1482 "platform_output_directory
" : MyAgo.OutputDir,
1483 "platform_build_directory
" : MyAgo.BuildDir,
1484 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1486 "toolchain_tag
" : MyAgo.ToolChain,
1487 "build_target
" : MyAgo.BuildTarget,
1488 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1489 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1490 "build_architecture_list
" : MyAgo.Arch,
1491 "architecture
" : MyAgo.Arch,
1492 "separator
" : Separator,
1493 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1494 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1495 "library_makefile_list
" : LibraryMakefileList,
1496 "module_makefile_list
" : ModuleMakefileList,
1497 "library_build_command
" : LibraryMakeCommandList,
1498 "module_build_command
" : ModuleMakeCommandList,
1501 return MakefileTemplateDict
1503 ## Get the root directory list for intermediate files of all modules build
1505 # @retval list The list of directory
1507 def GetModuleBuildDirectoryList(self):
1509 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1510 if not ModuleAutoGen.IsBinaryModule:
1511 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1514 ## Get the root directory list for intermediate files of all libraries build
1516 # @retval list The list of directory
1518 def GetLibraryBuildDirectoryList(self):
1520 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1521 if not LibraryAutoGen.IsBinaryModule:
1522 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1525 ## TopLevelMakefile class
1527 # This class encapsules makefie and its generation for entrance makefile. It
1528 # uses template to generate the content of makefile. The content of makefile
1529 # will be got from WorkspaceAutoGen object.
1531 class TopLevelMakefile(BuildFile):
1532 ## template used to generate toplevel makefile
1533 _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}''')
1535 ## Constructor of TopLevelMakefile
1537 # @param Workspace Object of WorkspaceAutoGen class
1539 def __init__(self, Workspace):
1540 BuildFile.__init__(self, Workspace)
1541 self.IntermediateDirectoryList = []
1543 # Compose a dict object containing information used to do replacement in template
1545 def _TemplateDict(self):
1546 Separator = self._SEP_[self._FileType]
1548 # any platform autogen object is ok because we just need common information
1549 MyAgo = self._AutoGenObject
1551 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1552 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1553 ExtraData="[%s]" % str(MyAgo))
1555 for Arch in MyAgo.ArchList:
1556 self.IntermediateDirectoryList.append(Separator.join(["$
(BUILD_DIR
)", Arch]))
1557 self.IntermediateDirectoryList.append("$
(FV_DIR
)")
1559 # TRICK: for not generating GenFds call in makefile if no FDF file
1561 if MyAgo.FdfFile is not None and MyAgo.FdfFile != "":
1562 FdfFileList = [MyAgo.FdfFile]
1563 # macros passed to GenFds
1565 MacroDict.update(GlobalData.gGlobalDefines)
1566 MacroDict.update(GlobalData.gCommandLineDefines)
1567 for MacroName in MacroDict:
1568 if MacroDict[MacroName] != "":
1569 MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
1571 MacroList.append('"%s"' % MacroName)
1575 # pass extra common options to external program called in makefile, currently GenFds.exe
1577 LogLevel = EdkLogger.GetLevel()
1578 if LogLevel == EdkLogger.VERBOSE:
1579 ExtraOption += " -v
"
1580 elif LogLevel <= EdkLogger.DEBUG_9:
1581 ExtraOption += " -d
%d" % (LogLevel - 1)
1582 elif LogLevel == EdkLogger.QUIET:
1583 ExtraOption += " -q
"
1585 if GlobalData.gCaseInsensitive:
1586 ExtraOption += " -c
"
1587 if not GlobalData.gEnableGenfdsMultiThread:
1588 ExtraOption += " --no
-genfds
-multi
-thread
"
1589 if GlobalData.gIgnoreSource:
1590 ExtraOption += " --ignore
-sources
"
1592 for pcd in GlobalData.BuildOptionPcd:
1594 pcdname = '.'.join(pcd[0:3])
1596 pcdname = '.'.join(pcd[0:2])
1597 if pcd[3].startswith('{'):
1598 ExtraOption += " --pcd
" + pcdname + '=' + 'H' + '"' + pcd[3] + '"'
1600 ExtraOption += " --pcd
" + pcdname + '=' + pcd[3]
1602 MakefileName = self._FILE_NAME_[self._FileType]
1603 SubBuildCommandList = []
1604 for A in MyAgo.ArchList:
1605 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join("$
(BUILD_DIR
)", A, MakefileName)}
1606 SubBuildCommandList.append(Command)
1608 MakefileTemplateDict = {
1609 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1610 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1611 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1612 "platform_name
" : MyAgo.Name,
1613 "platform_guid
" : MyAgo.Guid,
1614 "platform_version
" : MyAgo.Version,
1615 "platform_build_directory
" : MyAgo.BuildDir,
1616 "conf_directory
" : GlobalData.gConfDirectory,
1618 "toolchain_tag
" : MyAgo.ToolChain,
1619 "build_target
" : MyAgo.BuildTarget,
1620 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1621 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1622 'arch' : list(MyAgo.ArchList),
1623 "build_architecture_list
" : ','.join(MyAgo.ArchList),
1624 "separator
" : Separator,
1625 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1626 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1627 "sub_build_command
" : SubBuildCommandList,
1628 "fdf_file
" : FdfFileList,
1629 "active_platform
" : str(MyAgo),
1630 "fd
" : MyAgo.FdTargetList,
1631 "fv
" : MyAgo.FvTargetList,
1632 "cap
" : MyAgo.CapTargetList,
1633 "extra_options
" : ExtraOption,
1634 "macro
" : MacroList,
1637 return MakefileTemplateDict
1639 ## Get the root directory list for intermediate files of all modules build
1641 # @retval list The list of directory
1643 def GetModuleBuildDirectoryList(self):
1645 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1646 if not ModuleAutoGen.IsBinaryModule:
1647 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1650 ## Get the root directory list for intermediate files of all libraries build
1652 # @retval list The list of directory
1654 def GetLibraryBuildDirectoryList(self):
1656 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1657 if not LibraryAutoGen.IsBinaryModule:
1658 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1661 ## Find dependencies for one source file
1663 # By searching recursively "#include" directive in file, find out all the
1664 # files needed by given source file. The dependencies will be only searched
1665 # in given search path list.
1667 # @param File The source file
1668 # @param ForceInculeList The list of files which will be included forcely
1669 # @param SearchPathList The list of search path
1671 # @retval list The list of files the given source file depends on
1673 def GetDependencyList(AutoGenObject
, FileCache
, File
, ForceList
, SearchPathList
):
1674 EdkLogger
.debug(EdkLogger
.DEBUG_1
, "Try to get dependency files for %s" % File
)
1675 FileStack
= [File
] + ForceList
1676 DependencySet
= set()
1678 if AutoGenObject
.Arch
not in gDependencyDatabase
:
1679 gDependencyDatabase
[AutoGenObject
.Arch
] = {}
1680 DepDb
= gDependencyDatabase
[AutoGenObject
.Arch
]
1682 while len(FileStack
) > 0:
1685 FullPathDependList
= []
1687 for CacheFile
in FileCache
[F
]:
1688 FullPathDependList
.append(CacheFile
)
1689 if CacheFile
not in DependencySet
:
1690 FileStack
.append(CacheFile
)
1691 DependencySet
.update(FullPathDependList
)
1694 CurrentFileDependencyList
= []
1696 CurrentFileDependencyList
= DepDb
[F
]
1699 with
open(F
.Path
, 'rb') as Fd
:
1700 FileContent
= Fd
.read(1)
1704 if FileContent
[0] == 0xff or FileContent
[0] == 0xfe:
1705 FileContent2
= Fd
.read()
1706 FileContent2
= FileContent2
.decode('utf-16')
1707 IncludedFileList
= gIncludePattern
.findall(FileContent2
)
1709 FileLines
= Fd
.readlines()
1710 FileContent2
= [line
for line
in FileLines
if str(line
).lstrip("#\t ")[:8] == "include "]
1711 simpleFileContent
="".join(FileContent2
)
1713 IncludedFileList
= gIncludePattern
.findall(simpleFileContent
)
1714 except BaseException
as X
:
1715 EdkLogger
.error("build", FILE_OPEN_FAILURE
, ExtraData
=F
.Path
+ "\n\t" + str(X
))
1719 for Inc
in IncludedFileList
:
1721 # if there's macro used to reference header file, expand it
1722 HeaderList
= gMacroPattern
.findall(Inc
)
1723 if len(HeaderList
) == 1 and len(HeaderList
[0]) == 2:
1724 HeaderType
= HeaderList
[0][0]
1725 HeaderKey
= HeaderList
[0][1]
1726 if HeaderType
in gIncludeMacroConversion
:
1727 Inc
= gIncludeMacroConversion
[HeaderType
] % {"HeaderKey" : HeaderKey
}
1729 # not known macro used in #include, always build the file by
1730 # returning a empty dependency
1731 FileCache
[File
] = []
1733 Inc
= os
.path
.normpath(Inc
)
1734 CurrentFileDependencyList
.append(Inc
)
1735 DepDb
[F
] = CurrentFileDependencyList
1737 CurrentFilePath
= F
.Dir
1738 PathList
= [CurrentFilePath
] + SearchPathList
1739 for Inc
in CurrentFileDependencyList
:
1740 for SearchPath
in PathList
:
1741 FilePath
= os
.path
.join(SearchPath
, Inc
)
1742 if FilePath
in gIsFileMap
:
1743 if not gIsFileMap
[FilePath
]:
1745 # If isfile is called too many times, the performance is slow down.
1746 elif not os
.path
.isfile(FilePath
):
1747 gIsFileMap
[FilePath
] = False
1750 gIsFileMap
[FilePath
] = True
1751 FilePath
= PathClass(FilePath
)
1752 FullPathDependList
.append(FilePath
)
1753 if FilePath
not in DependencySet
:
1754 FileStack
.append(FilePath
)
1757 EdkLogger
.debug(EdkLogger
.DEBUG_9
, "%s included by %s was not found "\
1758 "in any given path:\n\t%s" % (Inc
, F
, "\n\t".join(SearchPathList
)))
1760 FileCache
[F
] = FullPathDependList
1761 DependencySet
.update(FullPathDependList
)
1763 DependencySet
.update(ForceList
)
1764 if File
in DependencySet
:
1765 DependencySet
.remove(File
)
1766 DependencyList
= list(DependencySet
) # remove duplicate ones
1768 return DependencyList
1770 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1771 if __name__
== '__main__':