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])
639 if os.path.exists(current_dir):
640 for fl in os.listdir(current_dir):
641 if fl.endswith('.dec'):
644 package_rel_dir = package_rel_dir[index + 1:]
646 MakefileTemplateDict = {
647 "makefile_header
" : self._FILE_HEADER_[self._FileType],
648 "makefile_path
" : os.path.join("$
(MODULE_BUILD_DIR
)", MakefileName),
649 "makefile_name
" : MakefileName,
650 "platform_name
" : self.PlatformInfo.Name,
651 "platform_guid
" : self.PlatformInfo.Guid,
652 "platform_version
" : self.PlatformInfo.Version,
653 "platform_relative_directory
": self.PlatformInfo.SourceDir,
654 "platform_output_directory
" : self.PlatformInfo.OutputDir,
655 "ffs_output_directory
" : MyAgo.Macros["FFS_OUTPUT_DIR
"],
656 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
658 "module_name
" : MyAgo.Name,
659 "module_guid
" : MyAgo.Guid,
660 "module_name_guid
" : MyAgo.UniqueBaseName,
661 "module_version
" : MyAgo.Version,
662 "module_type
" : MyAgo.ModuleType,
663 "module_file
" : MyAgo.MetaFile.Name,
664 "module_file_base_name
" : MyAgo.MetaFile.BaseName,
665 "module_relative_directory
" : MyAgo.SourceDir,
666 "module_dir
" : mws.join (self.Macros["WORKSPACE
"], MyAgo.SourceDir),
667 "package_relative_directory
": package_rel_dir,
668 "module_extra_defines
" : ["%s = %s" % (k, v) for k, v in MyAgo.Module.Defines.items()],
670 "architecture
" : MyAgo.Arch,
671 "toolchain_tag
" : MyAgo.ToolChain,
672 "build_target
" : MyAgo.BuildTarget,
674 "platform_build_directory
" : self.PlatformInfo.BuildDir,
675 "module_build_directory
" : MyAgo.BuildDir,
676 "module_output_directory
" : MyAgo.OutputDir,
677 "module_debug_directory
" : MyAgo.DebugDir,
679 "separator
" : Separator,
680 "module_tool_definitions
" : ToolsDef,
682 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
683 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
685 "module_entry_point
" : ModuleEntryPoint,
686 "image_entry_point
" : ImageEntryPoint,
687 "arch_entry_point
" : ArchEntryPoint,
688 "remaining_build_target
" : self.ResultFileList,
689 "common_dependency_file
" : self.CommonFileDependency,
690 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
691 "clean_command
" : self.GetRemoveDirectoryCommand(["$
(OUTPUT_DIR
)"]),
692 "cleanall_command
" : self.GetRemoveDirectoryCommand(["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]),
693 "dependent_library_build_directory
" : self.LibraryBuildDirectoryList,
694 "library_build_command
" : LibraryMakeCommandList,
695 "file_macro
" : FileMacroList,
696 "file_build_target
" : self.BuildTargetList,
697 "backward_compatible_target
": BcTargetList,
700 return MakefileTemplateDict
702 def ParserGenerateFfsCmd(self):
703 #Add Ffs cmd to self.BuildTargetList
707 for Cmd in self.GenFfsList:
709 for CopyCmd in Cmd[2]:
711 Src = self.ReplaceMacro(Src)
712 Dst = self.ReplaceMacro(Dst)
713 if Dst not in self.ResultFileList:
714 self.ResultFileList.append(Dst)
715 if '%s :' %(Dst) not in self.BuildTargetList:
716 self.BuildTargetList.append("%s :" %(Dst))
717 self.BuildTargetList.append('\t' + self._CP_TEMPLATE_[self._FileType] %{'Src': Src, 'Dst': Dst})
720 for index, Str in enumerate(FfsCmdList):
722 OutputFile = FfsCmdList[index + 1]
723 if '-i' == Str or "-oi
" == Str:
724 if DepsFileList == []:
725 DepsFileList = [FfsCmdList[index + 1]]
727 DepsFileList.append(FfsCmdList[index + 1])
728 DepsFileString = ' '.join(DepsFileList).strip()
729 if DepsFileString == '':
731 OutputFile = self.ReplaceMacro(OutputFile)
732 self.ResultFileList.append(OutputFile)
733 DepsFileString = self.ReplaceMacro(DepsFileString)
734 self.BuildTargetList.append('%s : %s' % (OutputFile, DepsFileString))
735 CmdString = ' '.join(FfsCmdList).strip()
736 CmdString = self.ReplaceMacro(CmdString)
737 self.BuildTargetList.append('\t%s' % CmdString)
739 self.ParseSecCmd(DepsFileList, Cmd[1])
740 for SecOutputFile, SecDepsFile, SecCmd in self.FfsOutputFileList :
741 self.BuildTargetList.append('%s : %s' % (self.ReplaceMacro(SecOutputFile), self.ReplaceMacro(SecDepsFile)))
742 self.BuildTargetList.append('\t%s' % self.ReplaceMacro(SecCmd))
743 self.FfsOutputFileList = []
745 def ParseSecCmd(self, OutputFileList, CmdTuple):
746 for OutputFile in OutputFileList:
747 for SecCmdStr in CmdTuple:
749 SecCmdList = SecCmdStr.split()
750 CmdName = SecCmdList[0]
751 for index, CmdItem in enumerate(SecCmdList):
752 if '-o' == CmdItem and OutputFile == SecCmdList[index + 1]:
754 while index + 1 < len(SecCmdList):
755 if not SecCmdList[index+1].startswith('-'):
756 SecDepsFileList.append(SecCmdList[index + 1])
758 if CmdName == 'Trim':
759 SecDepsFileList.append(os.path.join('$(DEBUG_DIR)', os.path.basename(OutputFile).replace('offset', 'efi')))
760 if OutputFile.endswith('.ui') or OutputFile.endswith('.ver'):
761 SecDepsFileList.append(os.path.join('$(MODULE_DIR)', '$(MODULE_FILE)'))
762 self.FfsOutputFileList.append((OutputFile, ' '.join(SecDepsFileList), SecCmdStr))
763 if len(SecDepsFileList) > 0:
764 self.ParseSecCmd(SecDepsFileList, CmdTuple)
769 def ReplaceMacro(self, str):
770 for Macro in self.MacroList:
771 if self._AutoGenObject.Macros[Macro] and self._AutoGenObject.Macros[Macro] in str:
772 str = str.replace(self._AutoGenObject.Macros[Macro], '$(' + Macro + ')')
775 def CommandExceedLimit(self):
777 'CC' : { 'Macro' : '$(CC_FLAGS)', 'Value' : False},
778 'PP' : { 'Macro' : '$(PP_FLAGS)', 'Value' : False},
779 'APP' : { 'Macro' : '$(APP_FLAGS)', 'Value' : False},
780 'ASLPP' : { 'Macro' : '$(ASLPP_FLAGS)', 'Value' : False},
781 'VFRPP' : { 'Macro' : '$(VFRPP_FLAGS)', 'Value' : False},
782 'ASM' : { 'Macro' : '$(ASM_FLAGS)', 'Value' : False},
783 'ASLCC' : { 'Macro' : '$(ASLCC_FLAGS)', 'Value' : False},
788 IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily]
790 # base on the source files to decide the file type
791 for File in self._AutoGenObject.SourceFileList:
792 for type in self._AutoGenObject.FileTypes:
793 if File in self._AutoGenObject.FileTypes[type]:
794 if type not in FileTypeList:
795 FileTypeList.append(type)
797 # calculate the command-line length
799 for type in FileTypeList:
800 BuildTargets = self._AutoGenObject.BuildRules[type].BuildTargets
801 for Target in BuildTargets:
802 CommandList = BuildTargets[Target].Commands
803 for SingleCommand in CommandList:
805 SingleCommandLength = len(SingleCommand)
806 SingleCommandList = SingleCommand.split()
807 if len(SingleCommandList) > 0:
808 for Flag in FlagDict:
809 if '$('+ Flag +')' in SingleCommandList[0]:
813 if 'PATH' not in self._AutoGenObject.BuildOption[Tool]:
814 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))
815 SingleCommandLength += len(self._AutoGenObject.BuildOption[Tool]['PATH
'])
816 for item in SingleCommandList[1:]:
817 if FlagDict[Tool]['Macro
'] in item:
818 if 'FLAGS
' not in self._AutoGenObject.BuildOption[Tool]:
819 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))
820 Str = self._AutoGenObject.BuildOption[Tool]['FLAGS']
821 for Option in self._AutoGenObject.BuildOption:
822 for Attr in self._AutoGenObject.BuildOption[Option]:
823 if Str.find(Option + '_' + Attr) != -1:
824 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
825 while(Str.find('$(') != -1):
826 for macro in self._AutoGenObject.Macros:
827 MacroName = '$('+ macro + ')'
828 if (Str.find(MacroName) != -1):
829 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
833 SingleCommandLength += len(Str)
834 elif '$(INC)' in item:
835 SingleCommandLength += self._AutoGenObject.IncludePathLength + len(IncPrefix) * len(self._AutoGenObject.IncludePathList)
836 elif item.find('$(') != -1:
838 for Option in self._AutoGenObject.BuildOption:
839 for Attr in self._AutoGenObject.BuildOption[Option]:
840 if Str.find(Option + '_' + Attr) != -1:
841 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
842 while(Str.find('$(') != -1):
843 for macro in self._AutoGenObject.Macros:
844 MacroName = '$('+ macro + ')'
845 if (Str.find(MacroName) != -1):
846 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
850 SingleCommandLength += len(Str)
852 if SingleCommandLength > GlobalData.gCommandMaxLength:
853 FlagDict[Tool]['Value'] = True
855 # generate the response file content by combine the FLAGS and INC
856 for Flag in FlagDict:
857 if FlagDict[Flag]['Value']:
859 RespMacro = FlagDict[Flag]['Macro'].replace('FLAGS', 'RESP')
860 Value = self._AutoGenObject.BuildOption[Flag]['FLAGS']
861 for inc in self._AutoGenObject.IncludePathList:
862 Value += ' ' + IncPrefix + inc
863 for Option in self._AutoGenObject.BuildOption:
864 for Attr in self._AutoGenObject.BuildOption[Option]:
865 if Value.find(Option + '_' + Attr) != -1:
866 Value = Value.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
867 while (Value.find('$(') != -1):
868 for macro in self._AutoGenObject.Macros:
869 MacroName = '$('+ macro + ')'
870 if (Value.find(MacroName) != -1):
871 Value = Value.replace(MacroName, self._AutoGenObject.Macros[macro])
876 if self._AutoGenObject.ToolChainFamily == 'GCC':
877 RespDict[Key] = Value.replace('\\', '/')
879 RespDict[Key] = Value
880 for Target in BuildTargets:
881 for i, SingleCommand in enumerate(BuildTargets[Target].Commands):
882 if FlagDict[Flag]['Macro'] in SingleCommand:
883 BuildTargets[Target].Commands[i] = SingleCommand.replace('$(INC)', '').replace(FlagDict[Flag]['Macro'], RespMacro)
886 def ProcessBuildTargetList(self):
888 # Search dependency file list for each source file
890 ForceIncludedFile = []
891 for File in self._AutoGenObject.AutoGenFileList:
893 ForceIncludedFile.append(File)
896 for Target in self._AutoGenObject.IntroTargetList:
897 SourceFileList.extend(Target.Inputs)
898 OutPutFileList.extend(Target.Outputs)
901 for Item in OutPutFileList:
902 if Item in SourceFileList:
903 SourceFileList.remove(Item)
905 FileDependencyDict = self.GetFileDependency(
908 self._AutoGenObject.IncludePathList + self._AutoGenObject.BuildOptionIncPathList
911 self.DependencyHeaderFileSet = set()
912 if FileDependencyDict:
913 for Dependency in FileDependencyDict.values():
914 self.DependencyHeaderFileSet.update(set(Dependency))
916 # Get a set of unique package includes from MetaFile
917 parentMetaFileIncludes = set()
918 for aInclude in self._AutoGenObject.PackageIncludePathList:
919 aIncludeName = str(aInclude)
920 parentMetaFileIncludes.add(aIncludeName.lower())
922 # Check if header files are listed in metafile
923 # Get a set of unique module header source files from MetaFile
924 headerFilesInMetaFileSet = set()
925 for aFile in self._AutoGenObject.SourceFileList:
926 aFileName = str(aFile)
927 if not aFileName.endswith('.h'):
929 headerFilesInMetaFileSet.add(aFileName.lower())
931 # Get a set of unique module autogen files
932 localAutoGenFileSet = set()
933 for aFile in self._AutoGenObject.AutoGenFileList:
934 localAutoGenFileSet.add(str(aFile).lower())
936 # Get a set of unique module dependency header files
937 # Exclude autogen files and files not in the source directory
938 # and files that are under the package include list
939 headerFileDependencySet = set()
940 localSourceDir = str(self._AutoGenObject.SourceDir).lower()
941 for Dependency in FileDependencyDict.values():
942 for aFile in Dependency:
943 aFileName = str(aFile).lower()
944 # Exclude non-header files
945 if not aFileName.endswith('.h'):
947 # Exclude autogen files
948 if aFileName in localAutoGenFileSet:
950 # Exclude include out of local scope
951 if localSourceDir not in aFileName:
953 # Exclude files covered by package includes
955 for aIncludePath in parentMetaFileIncludes:
956 if aIncludePath in aFileName:
961 # Keep the file to be checked
962 headerFileDependencySet.add(aFileName)
964 # Check if a module dependency header file is missing from the module's MetaFile
965 for aFile in headerFileDependencySet:
966 if aFile in headerFilesInMetaFileSet:
968 if GlobalData.gUseHashCache:
969 GlobalData.gModuleBuildTracking[self._AutoGenObject] = 'FAIL_METAFILE'
970 EdkLogger.warn("build
","Module MetaFile
[Sources
] is missing local header
!",
971 ExtraData = "Local Header
: " + aFile + " not found
in " + self._AutoGenObject.MetaFile.Path
975 for File,Dependency in FileDependencyDict.items():
977 FileDependencyDict[File] = ['$(FORCE_REBUILD)']
980 self._AutoGenObject.AutoGenDepSet |= set(Dependency)
983 if File.Ext not in [".c
", ".C
"] or File.Name == "AutoGen
.c
":
986 DepSet = set(Dependency)
988 DepSet &= set(Dependency)
989 # in case nothing in SourceFileList
993 # Extract common files list in the dependency files
996 self.CommonFileDependency.append(self.PlaceMacro(File.Path, self.Macros))
1001 DependencyDict = FileDependencyDict.copy()
1002 for File in FileDependencyDict:
1004 if File.Ext not in [".c
", ".C
"] or File.Name == "AutoGen
.c
":
1006 NewDepSet = set(FileDependencyDict[File])
1008 FileDependencyDict[File] = ["$
(COMMON_DEPS
)"] + list(NewDepSet)
1009 DependencyDict[File] = list(NewDepSet)
1011 # Convert target description object to target string in makefile
1012 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and TAB_C_CODE_FILE in self._AutoGenObject.Targets:
1013 for T in self._AutoGenObject.Targets[TAB_C_CODE_FILE]:
1014 NewFile = self.PlaceMacro(str(T), self.Macros)
1015 if not self.ObjTargetDict.get(T.Target.SubDir):
1016 self.ObjTargetDict[T.Target.SubDir] = set()
1017 self.ObjTargetDict[T.Target.SubDir].add(NewFile)
1018 for Type in self._AutoGenObject.Targets:
1019 for T in self._AutoGenObject.Targets[Type]:
1020 # Generate related macros if needed
1021 if T.GenFileListMacro and T.FileListMacro not in self.FileListMacros:
1022 self.FileListMacros[T.FileListMacro] = []
1023 if T.GenListFile and T.ListFileMacro not in self.ListFileMacros:
1024 self.ListFileMacros[T.ListFileMacro] = []
1025 if T.GenIncListFile and T.IncListFileMacro not in self.ListFileMacros:
1026 self.ListFileMacros[T.IncListFileMacro] = []
1030 # Add force-dependencies
1031 for Dep in T.Dependencies:
1032 Deps.append(self.PlaceMacro(str(Dep), self.Macros))
1033 if Dep != '$(MAKE_FILE)':
1034 CCodeDeps.append(self.PlaceMacro(str(Dep), self.Macros))
1035 # Add inclusion-dependencies
1036 if len(T.Inputs) == 1 and T.Inputs[0] in FileDependencyDict:
1037 for F in FileDependencyDict[T.Inputs[0]]:
1038 Deps.append(self.PlaceMacro(str(F), self.Macros))
1039 # Add source-dependencies
1041 NewFile = self.PlaceMacro(str(F), self.Macros)
1042 # In order to use file list macro as dependency
1044 # gnu tools need forward slash path separator, even on Windows
1045 self.ListFileMacros[T.ListFileMacro].append(str(F).replace ('\\', '/'))
1046 self.FileListMacros[T.FileListMacro].append(NewFile)
1047 elif T.GenFileListMacro:
1048 self.FileListMacros[T.FileListMacro].append(NewFile)
1050 Deps.append(NewFile)
1051 for key in self.FileListMacros:
1052 self.FileListMacros[key].sort()
1053 # Use file list macro as dependency
1054 if T.GenFileListMacro:
1055 Deps.append("$
(%s)" % T.FileListMacro)
1056 if Type in [TAB_OBJECT_FILE, TAB_STATIC_LIBRARY]:
1057 Deps.append("$
(%s)" % T.ListFileMacro)
1059 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Type == TAB_C_CODE_FILE:
1060 T, CmdTarget, CmdTargetDict, CmdCppDict = self.ParserCCodeFile(T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict)
1061 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": CCodeDeps}
1062 CmdLine = self._BUILD_TARGET_TEMPLATE.Replace(TargetDict).rstrip().replace('\t$(OBJLIST', '$(OBJLIST')
1064 CmdLine = '%s%s' %(CmdLine, TAB_LINE_BREAK)
1065 if CCodeDeps or CmdLine:
1066 self.BuildTargetList.append(CmdLine)
1068 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": Deps}
1069 self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(TargetDict))
1071 def ParserCCodeFile(self, T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict):
1073 for item in self._AutoGenObject.Targets[Type]:
1074 CmdSumDict[item.Target.SubDir] = item.Target.BaseName
1075 for CppPath in item.Inputs:
1076 Path = self.PlaceMacro(CppPath.Path, self.Macros)
1077 if CmdCppDict.get(item.Target.SubDir):
1078 CmdCppDict[item.Target.SubDir].append(Path)
1080 CmdCppDict[item.Target.SubDir] = ['$(MAKE_FILE)', Path]
1081 if CppPath.Path in DependencyDict:
1082 for Temp in DependencyDict[CppPath.Path]:
1084 Path = self.PlaceMacro(Temp.Path, self.Macros)
1087 if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):
1088 CmdCppDict[item.Target.SubDir].append(Path)
1090 CommandList = T.Commands[:]
1091 for Item in CommandList[:]:
1092 SingleCommandList = Item.split()
1093 if len(SingleCommandList) > 0 and self.CheckCCCmd(SingleCommandList):
1094 for Temp in SingleCommandList:
1095 if Temp.startswith('/Fo'):
1096 CmdSign = '%s%s' % (Temp.rsplit(TAB_SLASH, 1)[0], TAB_SLASH)
1099 if CmdSign not in list(CmdTargetDict.keys()):
1100 CmdTargetDict[CmdSign] = Item.replace(Temp, CmdSign)
1102 CmdTargetDict[CmdSign] = "%s %s" % (CmdTargetDict[CmdSign], SingleCommandList[-1])
1103 Index = CommandList.index(Item)
1104 CommandList.pop(Index)
1105 if SingleCommandList[-1].endswith("%s%s.c
" % (TAB_SLASH, CmdSumDict[CmdSign[3:].rsplit(TAB_SLASH, 1)[0]])):
1106 Cpplist = CmdCppDict[T.Target.SubDir]
1107 Cpplist.insert(0, '$(OBJLIST_%d): $(COMMON_DEPS)' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir))
1108 T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign])
1110 T.Commands.pop(Index)
1111 return T, CmdSumDict, CmdTargetDict, CmdCppDict
1113 def CheckCCCmd(self, CommandList):
1114 for cmd in CommandList:
1118 ## For creating makefile targets for dependent libraries
1119 def ProcessDependentLibrary(self):
1120 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1121 if not LibraryAutoGen.IsBinaryModule:
1122 self.LibraryBuildDirectoryList.append(self.PlaceMacro(LibraryAutoGen.BuildDir, self.Macros))
1124 ## Return a list containing source file's dependencies
1126 # @param FileList The list of source files
1127 # @param ForceInculeList The list of files which will be included forcely
1128 # @param SearchPathList The list of search path
1130 # @retval dict The mapping between source file path and its dependencies
1132 def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):
1135 Dependency[F] = GetDependencyList(self._AutoGenObject, self.FileCache, F, ForceInculeList, SearchPathList)
1139 ## CustomMakefile class
1141 # This class encapsules makefie and its generation for module. It uses template to generate
1142 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
1144 class CustomMakefile(BuildFile):
1145 ## template used to generate the makefile for module with custom makefile
1146 _TEMPLATE_ = TemplateString('''\
1150 # Platform Macro Definition
1152 PLATFORM_NAME = ${platform_name}
1153 PLATFORM_GUID = ${platform_guid}
1154 PLATFORM_VERSION = ${platform_version}
1155 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
1156 PLATFORM_DIR = ${platform_dir}
1157 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1160 # Module Macro Definition
1162 MODULE_NAME = ${module_name}
1163 MODULE_GUID = ${module_guid}
1164 MODULE_NAME_GUID = ${module_name_guid}
1165 MODULE_VERSION = ${module_version}
1166 MODULE_TYPE = ${module_type}
1167 MODULE_FILE = ${module_file}
1168 MODULE_FILE_BASE_NAME = ${module_file_base_name}
1169 BASE_NAME = $(MODULE_NAME)
1170 MODULE_RELATIVE_DIR = ${module_relative_directory}
1171 MODULE_DIR = ${module_dir}
1174 # Build Configuration Macro Definition
1176 ARCH = ${architecture}
1177 TOOLCHAIN = ${toolchain_tag}
1178 TOOLCHAIN_TAG = ${toolchain_tag}
1179 TARGET = ${build_target}
1182 # Build Directory Macro Definition
1184 # PLATFORM_BUILD_DIR = ${platform_build_directory}
1185 BUILD_DIR = ${platform_build_directory}
1186 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
1187 LIB_DIR = $(BIN_DIR)
1188 MODULE_BUILD_DIR = ${module_build_directory}
1189 OUTPUT_DIR = ${module_output_directory}
1190 DEBUG_DIR = ${module_debug_directory}
1191 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
1192 DEST_DIR_DEBUG = $(DEBUG_DIR)
1195 # Tools definitions specific to this module
1197 ${BEGIN}${module_tool_definitions}
1199 MAKE_FILE = ${makefile_path}
1202 # Shell Command Macro
1204 ${BEGIN}${shell_command_code} = ${shell_command}
1207 ${custom_makefile_content}
1210 # Target used when called from platform makefile, which will bypass the build of dependent libraries
1223 # Build Target used in multi-thread build mode, which no init target is needed
1229 # Initialization target: print build information and create necessary directories
1232 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
1233 ${BEGIN}\t-@${create_directory_command}\n${END}\
1237 ## Constructor of CustomMakefile
1239 # @param ModuleAutoGen Object of ModuleAutoGen class
1241 def __init__(self, ModuleAutoGen):
1242 BuildFile.__init__(self, ModuleAutoGen)
1243 self.PlatformInfo = self._AutoGenObject.PlatformInfo
1244 self.IntermediateDirectoryList = ["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]
1246 # Compose a dict object containing information used to do replacement in template
1248 def _TemplateDict(self):
1249 Separator = self._SEP_[self._FileType]
1250 MyAgo = self._AutoGenObject
1251 if self._FileType not in MyAgo.CustomMakefile:
1252 EdkLogger.error('build', OPTION_NOT_SUPPORTED, "No custom makefile
for %s" % self._FileType,
1253 ExtraData="[%s]" % str(MyAgo))
1254 MakefilePath = mws.join(
1256 MyAgo.CustomMakefile[self._FileType]
1259 CustomMakefile = open(MakefilePath, 'r').read()
1261 EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(MyAgo),
1262 ExtraData=MyAgo.CustomMakefile[self._FileType])
1266 for Tool in MyAgo.BuildOption:
1267 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
1270 for Attr in MyAgo.BuildOption[Tool]:
1271 if Attr == "FAMILY
":
1273 elif Attr == "PATH
":
1274 ToolsDef.append("%s = %s" % (Tool, MyAgo.BuildOption[Tool][Attr]))
1276 ToolsDef.append("%s_%s = %s" % (Tool, Attr, MyAgo.BuildOption[Tool][Attr]))
1279 MakefileName = self._FILE_NAME_[self._FileType]
1280 MakefileTemplateDict = {
1281 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1282 "makefile_path
" : os.path.join("$
(MODULE_BUILD_DIR
)", MakefileName),
1283 "platform_name
" : self.PlatformInfo.Name,
1284 "platform_guid
" : self.PlatformInfo.Guid,
1285 "platform_version
" : self.PlatformInfo.Version,
1286 "platform_relative_directory
": self.PlatformInfo.SourceDir,
1287 "platform_output_directory
" : self.PlatformInfo.OutputDir,
1288 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1290 "module_name
" : MyAgo.Name,
1291 "module_guid
" : MyAgo.Guid,
1292 "module_name_guid
" : MyAgo.UniqueBaseName,
1293 "module_version
" : MyAgo.Version,
1294 "module_type
" : MyAgo.ModuleType,
1295 "module_file
" : MyAgo.MetaFile,
1296 "module_file_base_name
" : MyAgo.MetaFile.BaseName,
1297 "module_relative_directory
" : MyAgo.SourceDir,
1298 "module_dir
" : mws.join (MyAgo.WorkspaceDir, MyAgo.SourceDir),
1300 "architecture
" : MyAgo.Arch,
1301 "toolchain_tag
" : MyAgo.ToolChain,
1302 "build_target
" : MyAgo.BuildTarget,
1304 "platform_build_directory
" : self.PlatformInfo.BuildDir,
1305 "module_build_directory
" : MyAgo.BuildDir,
1306 "module_output_directory
" : MyAgo.OutputDir,
1307 "module_debug_directory
" : MyAgo.DebugDir,
1309 "separator
" : Separator,
1310 "module_tool_definitions
" : ToolsDef,
1312 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1313 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1315 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1316 "custom_makefile_content
" : CustomMakefile
1319 return MakefileTemplateDict
1321 ## PlatformMakefile class
1323 # This class encapsules makefie and its generation for platform. It uses
1324 # template to generate the content of makefile. The content of makefile will be
1325 # got from PlatformAutoGen object.
1327 class PlatformMakefile(BuildFile):
1328 ## template used to generate the makefile for platform
1329 _TEMPLATE_ = TemplateString('''\
1333 # Platform Macro Definition
1335 PLATFORM_NAME = ${platform_name}
1336 PLATFORM_GUID = ${platform_guid}
1337 PLATFORM_VERSION = ${platform_version}
1338 PLATFORM_FILE = ${platform_file}
1339 PLATFORM_DIR = ${platform_dir}
1340 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1343 # Build Configuration Macro Definition
1345 TOOLCHAIN = ${toolchain_tag}
1346 TOOLCHAIN_TAG = ${toolchain_tag}
1347 TARGET = ${build_target}
1350 # Build Directory Macro Definition
1352 BUILD_DIR = ${platform_build_directory}
1353 FV_DIR = ${platform_build_directory}${separator}FV
1356 # Shell Command Macro
1358 ${BEGIN}${shell_command_code} = ${shell_command}
1362 MAKE_FILE = ${makefile_path}
1367 all: init build_libraries build_modules
1370 # Initialization target: print build information and create necessary directories
1373 \t-@echo Building ... $(PLATFORM_FILE) [${build_architecture_list}]
1374 \t${BEGIN}-@${create_directory_command}
1377 # library build target
1379 libraries: init build_libraries
1382 # module build target
1384 modules: init build_libraries build_modules
1387 # Build all libraries:
1390 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${library_makefile_list} pbuild
1391 ${END}\t@cd $(BUILD_DIR)
1394 # Build all modules:
1397 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${module_makefile_list} pbuild
1398 ${END}\t@cd $(BUILD_DIR)
1401 # Clean intermediate files
1404 \t${BEGIN}-@${library_build_command} clean
1405 \t${END}${BEGIN}-@${module_build_command} clean
1406 \t${END}@cd $(BUILD_DIR)
1409 # Clean all generated files except to makefile
1412 ${BEGIN}\t${cleanall_command}
1416 # Clean all library files
1419 \t${BEGIN}-@${library_build_command} cleanall
1420 \t${END}@cd $(BUILD_DIR)\n
1423 ## Constructor of PlatformMakefile
1425 # @param ModuleAutoGen Object of PlatformAutoGen class
1427 def __init__(self, PlatformAutoGen):
1428 BuildFile.__init__(self, PlatformAutoGen)
1429 self.ModuleBuildCommandList = []
1430 self.ModuleMakefileList = []
1431 self.IntermediateDirectoryList = []
1432 self.ModuleBuildDirectoryList = []
1433 self.LibraryBuildDirectoryList = []
1434 self.LibraryMakeCommandList = []
1436 # Compose a dict object containing information used to do replacement in template
1438 def _TemplateDict(self):
1439 Separator = self._SEP_[self._FileType]
1441 MyAgo = self._AutoGenObject
1442 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1443 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1444 ExtraData="[%s]" % str(MyAgo))
1446 self.IntermediateDirectoryList = ["$
(BUILD_DIR
)"]
1447 self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()
1448 self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()
1450 MakefileName = self._FILE_NAME_[self._FileType]
1451 LibraryMakefileList = []
1452 LibraryMakeCommandList = []
1453 for D in self.LibraryBuildDirectoryList:
1454 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1455 Makefile = os.path.join(D, MakefileName)
1456 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1457 LibraryMakefileList.append(Makefile)
1458 LibraryMakeCommandList.append(Command)
1459 self.LibraryMakeCommandList = LibraryMakeCommandList
1461 ModuleMakefileList = []
1462 ModuleMakeCommandList = []
1463 for D in self.ModuleBuildDirectoryList:
1464 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1465 Makefile = os.path.join(D, MakefileName)
1466 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1467 ModuleMakefileList.append(Makefile)
1468 ModuleMakeCommandList.append(Command)
1470 MakefileTemplateDict = {
1471 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1472 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1473 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1474 "makefile_name
" : MakefileName,
1475 "platform_name
" : MyAgo.Name,
1476 "platform_guid
" : MyAgo.Guid,
1477 "platform_version
" : MyAgo.Version,
1478 "platform_file
" : MyAgo.MetaFile,
1479 "platform_relative_directory
": MyAgo.SourceDir,
1480 "platform_output_directory
" : MyAgo.OutputDir,
1481 "platform_build_directory
" : MyAgo.BuildDir,
1482 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1484 "toolchain_tag
" : MyAgo.ToolChain,
1485 "build_target
" : MyAgo.BuildTarget,
1486 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1487 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1488 "build_architecture_list
" : MyAgo.Arch,
1489 "architecture
" : MyAgo.Arch,
1490 "separator
" : Separator,
1491 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1492 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1493 "library_makefile_list
" : LibraryMakefileList,
1494 "module_makefile_list
" : ModuleMakefileList,
1495 "library_build_command
" : LibraryMakeCommandList,
1496 "module_build_command
" : ModuleMakeCommandList,
1499 return MakefileTemplateDict
1501 ## Get the root directory list for intermediate files of all modules build
1503 # @retval list The list of directory
1505 def GetModuleBuildDirectoryList(self):
1507 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1508 if not ModuleAutoGen.IsBinaryModule:
1509 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1512 ## Get the root directory list for intermediate files of all libraries build
1514 # @retval list The list of directory
1516 def GetLibraryBuildDirectoryList(self):
1518 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1519 if not LibraryAutoGen.IsBinaryModule:
1520 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1523 ## TopLevelMakefile class
1525 # This class encapsules makefie and its generation for entrance makefile. It
1526 # uses template to generate the content of makefile. The content of makefile
1527 # will be got from WorkspaceAutoGen object.
1529 class TopLevelMakefile(BuildFile):
1530 ## template used to generate toplevel makefile
1531 _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}''')
1533 ## Constructor of TopLevelMakefile
1535 # @param Workspace Object of WorkspaceAutoGen class
1537 def __init__(self, Workspace):
1538 BuildFile.__init__(self, Workspace)
1539 self.IntermediateDirectoryList = []
1541 # Compose a dict object containing information used to do replacement in template
1543 def _TemplateDict(self):
1544 Separator = self._SEP_[self._FileType]
1546 # any platform autogen object is ok because we just need common information
1547 MyAgo = self._AutoGenObject
1549 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1550 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1551 ExtraData="[%s]" % str(MyAgo))
1553 for Arch in MyAgo.ArchList:
1554 self.IntermediateDirectoryList.append(Separator.join(["$
(BUILD_DIR
)", Arch]))
1555 self.IntermediateDirectoryList.append("$
(FV_DIR
)")
1557 # TRICK: for not generating GenFds call in makefile if no FDF file
1559 if MyAgo.FdfFile is not None and MyAgo.FdfFile != "":
1560 FdfFileList = [MyAgo.FdfFile]
1561 # macros passed to GenFds
1563 MacroDict.update(GlobalData.gGlobalDefines)
1564 MacroDict.update(GlobalData.gCommandLineDefines)
1565 for MacroName in MacroDict:
1566 if MacroDict[MacroName] != "":
1567 MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
1569 MacroList.append('"%s"' % MacroName)
1573 # pass extra common options to external program called in makefile, currently GenFds.exe
1575 LogLevel = EdkLogger.GetLevel()
1576 if LogLevel == EdkLogger.VERBOSE:
1577 ExtraOption += " -v
"
1578 elif LogLevel <= EdkLogger.DEBUG_9:
1579 ExtraOption += " -d
%d" % (LogLevel - 1)
1580 elif LogLevel == EdkLogger.QUIET:
1581 ExtraOption += " -q
"
1583 if GlobalData.gCaseInsensitive:
1584 ExtraOption += " -c
"
1585 if not GlobalData.gEnableGenfdsMultiThread:
1586 ExtraOption += " --no
-genfds
-multi
-thread
"
1587 if GlobalData.gIgnoreSource:
1588 ExtraOption += " --ignore
-sources
"
1590 for pcd in GlobalData.BuildOptionPcd:
1592 pcdname = '.'.join(pcd[0:3])
1594 pcdname = '.'.join(pcd[0:2])
1595 if pcd[3].startswith('{'):
1596 ExtraOption += " --pcd
" + pcdname + '=' + 'H' + '"' + pcd[3] + '"'
1598 ExtraOption += " --pcd
" + pcdname + '=' + pcd[3]
1600 MakefileName = self._FILE_NAME_[self._FileType]
1601 SubBuildCommandList = []
1602 for A in MyAgo.ArchList:
1603 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join("$
(BUILD_DIR
)", A, MakefileName)}
1604 SubBuildCommandList.append(Command)
1606 MakefileTemplateDict = {
1607 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1608 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1609 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1610 "platform_name
" : MyAgo.Name,
1611 "platform_guid
" : MyAgo.Guid,
1612 "platform_version
" : MyAgo.Version,
1613 "platform_build_directory
" : MyAgo.BuildDir,
1614 "conf_directory
" : GlobalData.gConfDirectory,
1616 "toolchain_tag
" : MyAgo.ToolChain,
1617 "build_target
" : MyAgo.BuildTarget,
1618 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1619 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1620 'arch' : list(MyAgo.ArchList),
1621 "build_architecture_list
" : ','.join(MyAgo.ArchList),
1622 "separator
" : Separator,
1623 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1624 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1625 "sub_build_command
" : SubBuildCommandList,
1626 "fdf_file
" : FdfFileList,
1627 "active_platform
" : str(MyAgo),
1628 "fd
" : MyAgo.FdTargetList,
1629 "fv
" : MyAgo.FvTargetList,
1630 "cap
" : MyAgo.CapTargetList,
1631 "extra_options
" : ExtraOption,
1632 "macro
" : MacroList,
1635 return MakefileTemplateDict
1637 ## Get the root directory list for intermediate files of all modules build
1639 # @retval list The list of directory
1641 def GetModuleBuildDirectoryList(self):
1643 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1644 if not ModuleAutoGen.IsBinaryModule:
1645 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1648 ## Get the root directory list for intermediate files of all libraries build
1650 # @retval list The list of directory
1652 def GetLibraryBuildDirectoryList(self):
1654 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1655 if not LibraryAutoGen.IsBinaryModule:
1656 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1659 ## Find dependencies for one source file
1661 # By searching recursively "#include" directive in file, find out all the
1662 # files needed by given source file. The dependencies will be only searched
1663 # in given search path list.
1665 # @param File The source file
1666 # @param ForceInculeList The list of files which will be included forcely
1667 # @param SearchPathList The list of search path
1669 # @retval list The list of files the given source file depends on
1671 def GetDependencyList(AutoGenObject
, FileCache
, File
, ForceList
, SearchPathList
):
1672 EdkLogger
.debug(EdkLogger
.DEBUG_1
, "Try to get dependency files for %s" % File
)
1673 FileStack
= [File
] + ForceList
1674 DependencySet
= set()
1676 if AutoGenObject
.Arch
not in gDependencyDatabase
:
1677 gDependencyDatabase
[AutoGenObject
.Arch
] = {}
1678 DepDb
= gDependencyDatabase
[AutoGenObject
.Arch
]
1680 while len(FileStack
) > 0:
1683 FullPathDependList
= []
1685 for CacheFile
in FileCache
[F
]:
1686 FullPathDependList
.append(CacheFile
)
1687 if CacheFile
not in DependencySet
:
1688 FileStack
.append(CacheFile
)
1689 DependencySet
.update(FullPathDependList
)
1692 CurrentFileDependencyList
= []
1694 CurrentFileDependencyList
= DepDb
[F
]
1697 with
open(F
.Path
, 'rb') as Fd
:
1698 FileContent
= Fd
.read(1)
1702 if FileContent
[0] == 0xff or FileContent
[0] == 0xfe:
1703 FileContent2
= Fd
.read()
1704 FileContent2
= FileContent2
.decode('utf-16')
1705 IncludedFileList
= gIncludePattern
.findall(FileContent2
)
1707 FileLines
= Fd
.readlines()
1708 FileContent2
= [line
for line
in FileLines
if str(line
).lstrip("#\t ")[:8] == "include "]
1709 simpleFileContent
="".join(FileContent2
)
1711 IncludedFileList
= gIncludePattern
.findall(simpleFileContent
)
1712 except BaseException
as X
:
1713 EdkLogger
.error("build", FILE_OPEN_FAILURE
, ExtraData
=F
.Path
+ "\n\t" + str(X
))
1717 for Inc
in IncludedFileList
:
1719 # if there's macro used to reference header file, expand it
1720 HeaderList
= gMacroPattern
.findall(Inc
)
1721 if len(HeaderList
) == 1 and len(HeaderList
[0]) == 2:
1722 HeaderType
= HeaderList
[0][0]
1723 HeaderKey
= HeaderList
[0][1]
1724 if HeaderType
in gIncludeMacroConversion
:
1725 Inc
= gIncludeMacroConversion
[HeaderType
] % {"HeaderKey" : HeaderKey
}
1727 # not known macro used in #include, always build the file by
1728 # returning a empty dependency
1729 FileCache
[File
] = []
1731 Inc
= os
.path
.normpath(Inc
)
1732 CurrentFileDependencyList
.append(Inc
)
1733 DepDb
[F
] = CurrentFileDependencyList
1735 CurrentFilePath
= F
.Dir
1736 PathList
= [CurrentFilePath
] + SearchPathList
1737 for Inc
in CurrentFileDependencyList
:
1738 for SearchPath
in PathList
:
1739 FilePath
= os
.path
.join(SearchPath
, Inc
)
1740 if FilePath
in gIsFileMap
:
1741 if not gIsFileMap
[FilePath
]:
1743 # If isfile is called too many times, the performance is slow down.
1744 elif not os
.path
.isfile(FilePath
):
1745 gIsFileMap
[FilePath
] = False
1748 gIsFileMap
[FilePath
] = True
1749 FilePath
= PathClass(FilePath
)
1750 FullPathDependList
.append(FilePath
)
1751 if FilePath
not in DependencySet
:
1752 FileStack
.append(FilePath
)
1755 EdkLogger
.debug(EdkLogger
.DEBUG_9
, "%s included by %s was not found "\
1756 "in any given path:\n\t%s" % (Inc
, F
, "\n\t".join(SearchPathList
)))
1758 FileCache
[F
] = FullPathDependList
1759 DependencySet
.update(FullPathDependList
)
1761 DependencySet
.update(ForceList
)
1762 if File
in DependencySet
:
1763 DependencySet
.remove(File
)
1764 DependencyList
= list(DependencySet
) # remove duplicate ones
1766 return DependencyList
1768 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1769 if __name__
== '__main__':