2 # Create makefile for MS nmake and GNU make
4 # Copyright (c) 2007 - 2020, 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 if not os.path.exists(os.path.join(self._AutoGenObject.MakeFileDir, "deps
.txt
")):
189 with open(os.path.join(self._AutoGenObject.MakeFileDir, "deps
.txt
"),"w
+") as fd:
191 if not os.path.exists(os.path.join(self._AutoGenObject.MakeFileDir, "dependency
")):
192 with open(os.path.join(self._AutoGenObject.MakeFileDir, "dependency
"),"w
+") as fd:
194 if not os.path.exists(os.path.join(self._AutoGenObject.MakeFileDir, "deps_target
")):
195 with open(os.path.join(self._AutoGenObject.MakeFileDir, "deps_target
"),"w
+") as fd:
197 return SaveFileOnChange(os.path.join(self._AutoGenObject.MakeFileDir, FileName), FileContent, False)
199 ## Return a list of directory creation command string
201 # @param DirList The list of directory to be created
203 # @retval list The directory creation command list
205 def GetCreateDirectoryCommand(self, DirList):
206 return [self._MD_TEMPLATE_[self._FileType] % {'dir':Dir} for Dir in DirList]
208 ## Return a list of directory removal command string
210 # @param DirList The list of directory to be removed
212 # @retval list The directory removal command list
214 def GetRemoveDirectoryCommand(self, DirList):
215 return [self._RD_TEMPLATE_[self._FileType] % {'dir':Dir} for Dir in DirList]
217 def PlaceMacro(self, Path, MacroDefinitions=None):
218 if Path.startswith("$
("):
221 if MacroDefinitions is None:
222 MacroDefinitions = {}
223 PathLength = len(Path)
224 for MacroName in MacroDefinitions:
225 MacroValue = MacroDefinitions[MacroName]
226 MacroValueLength = len(MacroValue)
227 if MacroValueLength == 0:
229 if MacroValueLength <= PathLength and Path.startswith(MacroValue):
230 Path = "$
(%s)%s" % (MacroName, Path[MacroValueLength:])
234 ## ModuleMakefile class
236 # This class encapsules makefie and its generation for module. It uses template to generate
237 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
239 class ModuleMakefile(BuildFile):
240 ## template used to generate the makefile for module
241 _TEMPLATE_ = TemplateString('''\
245 # Platform Macro Definition
247 PLATFORM_NAME = ${platform_name}
248 PLATFORM_GUID = ${platform_guid}
249 PLATFORM_VERSION = ${platform_version}
250 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
251 PLATFORM_DIR = ${platform_dir}
252 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
255 # Module Macro Definition
257 MODULE_NAME = ${module_name}
258 MODULE_GUID = ${module_guid}
259 MODULE_NAME_GUID = ${module_name_guid}
260 MODULE_VERSION = ${module_version}
261 MODULE_TYPE = ${module_type}
262 MODULE_FILE = ${module_file}
263 MODULE_FILE_BASE_NAME = ${module_file_base_name}
264 BASE_NAME = $(MODULE_NAME)
265 MODULE_RELATIVE_DIR = ${module_relative_directory}
266 PACKAGE_RELATIVE_DIR = ${package_relative_directory}
267 MODULE_DIR = ${module_dir}
268 FFS_OUTPUT_DIR = ${ffs_output_directory}
270 MODULE_ENTRY_POINT = ${module_entry_point}
271 ARCH_ENTRY_POINT = ${arch_entry_point}
272 IMAGE_ENTRY_POINT = ${image_entry_point}
274 ${BEGIN}${module_extra_defines}
277 # Build Configuration Macro Definition
279 ARCH = ${architecture}
280 TOOLCHAIN = ${toolchain_tag}
281 TOOLCHAIN_TAG = ${toolchain_tag}
282 TARGET = ${build_target}
285 # Build Directory Macro Definition
287 # PLATFORM_BUILD_DIR = ${platform_build_directory}
288 BUILD_DIR = ${platform_build_directory}
289 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
291 MODULE_BUILD_DIR = ${module_build_directory}
292 OUTPUT_DIR = ${module_output_directory}
293 DEBUG_DIR = ${module_debug_directory}
294 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
295 DEST_DIR_DEBUG = $(DEBUG_DIR)
298 # Shell Command Macro
300 ${BEGIN}${shell_command_code} = ${shell_command}
304 # Tools definitions specific to this module
306 ${BEGIN}${module_tool_definitions}
308 MAKE_FILE = ${makefile_path}
313 ${BEGIN}${file_macro}
317 # Overridable Target Macro Definitions
319 FORCE_REBUILD = force_build
322 BC_TARGET = ${BEGIN}${backward_compatible_target} ${END}
323 CODA_TARGET = ${BEGIN}${remaining_build_target} \\
327 # Default target, which will build dependent libraries in addition to source files
334 # Target used when called from platform makefile, which will bypass the build of dependent libraries
337 pbuild: $(INIT_TARGET) $(BC_TARGET) $(PCH_TARGET) $(CODA_TARGET)
343 mbuild: $(INIT_TARGET) $(BC_TARGET) gen_libs $(PCH_TARGET) $(CODA_TARGET)
346 # Build Target used in multi-thread build mode, which will bypass the init and gen_libs targets
349 tbuild: $(BC_TARGET) $(PCH_TARGET) $(CODA_TARGET)
352 # Phony target which is used to force executing commands for a target
358 # Target to update the FD
364 # Initialization target: print build information and create necessary directories
369 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
372 ${BEGIN}\t-@${create_directory_command}\n${END}
375 \t-@$(CP) $(DEBUG_DIR)${separator}AutoGen.h $(DEBUG_DIR)${separator}$(MODULE_NAME)StrDefs.h
381 \t${BEGIN}@"$
(MAKE
)" $(MAKE_FLAGS) -f ${dependent_library_build_directory}${separator}${makefile_name}
382 \t${END}@cd $(MODULE_BUILD_DIR)
385 # Build Flash Device Image
388 \t@"$
(MAKE
)" $(MAKE_FLAGS) -f $(BUILD_DIR)${separator}${makefile_name} fds
389 \t@cd $(MODULE_BUILD_DIR)
394 # Individual Object Build Targets
396 ${BEGIN}${file_build_target}
400 # clean all intermediate files
403 \t${BEGIN}${clean_command}
404 \t${END}\t$(RM) AutoGenTimeStamp
407 # clean all generated files
410 ${BEGIN}\t${cleanall_command}
411 ${END}\t$(RM) *.pdb *.idb > NUL 2>&1
412 \t$(RM) $(BIN_DIR)${separator}$(MODULE_NAME).efi
413 \t$(RM) AutoGenTimeStamp
416 # clean all dependent libraries built
419 \t${BEGIN}-@${library_build_command} cleanall
420 \t${END}@cd $(MODULE_BUILD_DIR)\n\n''')
422 _FILE_MACRO_TEMPLATE = TemplateString("${macro_name}
= ${BEGIN}
\\\n ${source_file}${END}
\n")
423 _BUILD_TARGET_TEMPLATE = TemplateString("${BEGIN}${target}
: ${deps}
\n${END}
\t${cmd}
\n")
425 ## Constructor of ModuleMakefile
427 # @param ModuleAutoGen Object of ModuleAutoGen class
429 def __init__(self, ModuleAutoGen):
430 BuildFile.__init__(self, ModuleAutoGen)
431 self.PlatformInfo = self._AutoGenObject.PlatformInfo
433 self.ResultFileList = []
434 self.IntermediateDirectoryList = ["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]
436 self.FileBuildTargetList = [] # [(src, target string)]
437 self.BuildTargetList = [] # [target string]
438 self.PendingBuildTargetList = [] # [FileBuildRule objects]
439 self.CommonFileDependency = []
440 self.FileListMacros = {}
441 self.ListFileMacros = {}
442 self.ObjTargetDict = OrderedDict()
444 self.LibraryBuildCommandList = []
445 self.LibraryFileList = []
446 self.LibraryMakefileList = []
447 self.LibraryBuildDirectoryList = []
448 self.SystemLibraryList = []
449 self.Macros = OrderedDict()
450 self.Macros["OUTPUT_DIR
" ] = self._AutoGenObject.Macros["OUTPUT_DIR
"]
451 self.Macros["DEBUG_DIR
" ] = self._AutoGenObject.Macros["DEBUG_DIR
"]
452 self.Macros["MODULE_BUILD_DIR
"] = self._AutoGenObject.Macros["MODULE_BUILD_DIR
"]
453 self.Macros["BIN_DIR
" ] = self._AutoGenObject.Macros["BIN_DIR
"]
454 self.Macros["BUILD_DIR
" ] = self._AutoGenObject.Macros["BUILD_DIR
"]
455 self.Macros["WORKSPACE
" ] = self._AutoGenObject.Macros["WORKSPACE
"]
456 self.Macros["FFS_OUTPUT_DIR
" ] = self._AutoGenObject.Macros["FFS_OUTPUT_DIR
"]
457 self.GenFfsList = ModuleAutoGen.GenFfsList
458 self.MacroList = ['FFS_OUTPUT_DIR', 'MODULE_GUID', 'OUTPUT_DIR']
459 self.FfsOutputFileList = []
460 self.DependencyHeaderFileSet = set()
462 # Compose a dict object containing information used to do replacement in template
464 def _TemplateDict(self):
465 if self._FileType not in self._SEP_:
466 EdkLogger.error("build
", PARAMETER_INVALID, "Invalid Makefile
type [%s]" % self._FileType,
467 ExtraData="[%s]" % str(self._AutoGenObject))
468 MyAgo = self._AutoGenObject
469 Separator = self._SEP_[self._FileType]
471 # break build if no source files and binary files are found
472 if len(MyAgo.SourceFileList) == 0 and len(MyAgo.BinaryFileList) == 0:
473 EdkLogger.error("build
", AUTOGEN_ERROR, "No files to be built
in module
[%s, %s, %s]"
474 % (MyAgo.BuildTarget, MyAgo.ToolChain, MyAgo.Arch),
475 ExtraData="[%s]" % str(MyAgo))
477 # convert dependent libraries to build command
478 self.ProcessDependentLibrary()
479 if len(MyAgo.Module.ModuleEntryPointList) > 0:
480 ModuleEntryPoint = MyAgo.Module.ModuleEntryPointList[0]
482 ModuleEntryPoint = "_ModuleEntryPoint
"
484 ArchEntryPoint = ModuleEntryPoint
486 if MyAgo.Arch == "EBC
":
487 # EBC compiler always use "EfiStart
" as entry point. Only applies to EdkII modules
488 ImageEntryPoint = "EfiStart
"
490 # EdkII modules always use "_ModuleEntryPoint
" as entry point
491 ImageEntryPoint = "_ModuleEntryPoint
"
493 for k, v in MyAgo.Module.Defines.items():
494 if k not in MyAgo.Macros:
497 if 'MODULE_ENTRY_POINT' not in MyAgo.Macros:
498 MyAgo.Macros['MODULE_ENTRY_POINT'] = ModuleEntryPoint
499 if 'ARCH_ENTRY_POINT' not in MyAgo.Macros:
500 MyAgo.Macros['ARCH_ENTRY_POINT'] = ArchEntryPoint
501 if 'IMAGE_ENTRY_POINT' not in MyAgo.Macros:
502 MyAgo.Macros['IMAGE_ENTRY_POINT'] = ImageEntryPoint
504 PCI_COMPRESS_Flag = False
505 for k, v in MyAgo.Module.Defines.items():
506 if 'PCI_COMPRESS' == k and 'TRUE' == v:
507 PCI_COMPRESS_Flag = True
511 IncPrefix = self._INC_FLAG_[MyAgo.ToolChainFamily]
512 for Tool in MyAgo.BuildOption:
513 for Attr in MyAgo.BuildOption[Tool]:
514 Value = MyAgo.BuildOption[Tool][Attr]
518 ToolsDef.append("%s = %s" % (Tool, Value))
520 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
523 # Remove duplicated include path, if any
525 Value = RemoveDupOption(Value, IncPrefix, MyAgo.IncludePathList)
526 if Tool == "OPTROM
" and PCI_COMPRESS_Flag:
527 ValueList = Value.split()
529 for i, v in enumerate(ValueList):
532 Value = ' '.join(ValueList)
534 ToolsDef.append("%s_%s = %s" % (Tool, Attr, Value))
537 # generate the Response file and Response flag
538 RespDict = self.CommandExceedLimit()
539 RespFileList = os.path.join(MyAgo.OutputDir, 'respfilelist.txt')
541 RespFileListContent = ''
542 for Resp in RespDict:
543 RespFile = os.path.join(MyAgo.OutputDir, str(Resp).lower() + '.txt')
544 StrList = RespDict[Resp].split(' ')
548 if '$' in Str or '-MMD' in Str or '-MF' in Str:
549 UnexpandMacro.append(Str)
552 UnexpandMacroStr = ' '.join(UnexpandMacro)
553 NewRespStr = ' '.join(NewStr)
554 SaveFileOnChange(RespFile, NewRespStr, False)
555 ToolsDef.append("%s = %s" % (Resp, UnexpandMacroStr + ' @' + RespFile))
556 RespFileListContent += '@' + RespFile + TAB_LINE_BREAK
557 RespFileListContent += NewRespStr + TAB_LINE_BREAK
558 SaveFileOnChange(RespFileList, RespFileListContent, False)
560 if os.path.exists(RespFileList):
561 os.remove(RespFileList)
563 # convert source files and binary files to build targets
564 self.ResultFileList = [str(T.Target) for T in MyAgo.CodaTargetList]
565 if len(self.ResultFileList) == 0 and len(MyAgo.SourceFileList) != 0:
566 EdkLogger.error("build
", AUTOGEN_ERROR, "Nothing to build
",
567 ExtraData="[%s]" % str(MyAgo))
569 self.ProcessBuildTargetList()
570 self.ParserGenerateFfsCmd()
572 # Generate macros used to represent input files
573 FileMacroList = [] # macro name = file list
574 for FileListMacro in self.FileListMacros:
575 FileMacro = self._FILE_MACRO_TEMPLATE.Replace(
577 "macro_name
" : FileListMacro,
578 "source_file
" : self.FileListMacros[FileListMacro]
581 FileMacroList.append(FileMacro)
583 # INC_LIST is special
586 for P in MyAgo.IncludePathList:
587 IncludePathList.append(IncPrefix + self.PlaceMacro(P, self.Macros))
588 if FileBuildRule.INC_LIST_MACRO in self.ListFileMacros:
589 self.ListFileMacros[FileBuildRule.INC_LIST_MACRO].append(IncPrefix + P)
590 FileMacro += self._FILE_MACRO_TEMPLATE.Replace(
592 "macro_name
" : "INC
",
593 "source_file
" : IncludePathList
596 FileMacroList.append(FileMacro)
597 # Add support when compiling .nasm source files
599 asmsource = [item for item in MyAgo.SourceFileList if item.File.upper().endswith((".NASM
",".ASM
",".NASMB
","S
"))]
601 for P in MyAgo.IncludePathList:
602 IncludePath = self._INC_FLAG_['NASM'] + self.PlaceMacro(P, self.Macros)
603 if IncludePath.endswith(os.sep):
604 IncludePath = IncludePath.rstrip(os.sep)
605 # When compiling .nasm files, need to add a literal backslash at each path
606 # To specify a literal backslash at the end of the line, precede it with a caret (^)
607 if P == MyAgo.IncludePathList[-1] and os.sep == '\\':
608 IncludePath = ''.join([IncludePath, '^', os.sep])
610 IncludePath = os.path.join(IncludePath, '')
611 IncludePathList.append(IncludePath)
612 FileMacroList.append(self._FILE_MACRO_TEMPLATE.Replace({"macro_name
": "NASM_INC
", "source_file
": IncludePathList}))
614 # Generate macros used to represent files containing list of input files
615 for ListFileMacro in self.ListFileMacros:
616 ListFileName = os.path.join(MyAgo.OutputDir, "%s.lst
" % ListFileMacro.lower()[:len(ListFileMacro) - 5])
617 FileMacroList.append("%s = %s" % (ListFileMacro, ListFileName))
620 "\n".join(self.ListFileMacros[ListFileMacro]),
624 # Generate objlist used to create .obj file
625 for Type in self.ObjTargetDict:
626 NewLine = ' '.join(list(self.ObjTargetDict[Type]))
627 FileMacroList.append("OBJLIST_
%s = %s" % (list(self.ObjTargetDict.keys()).index(Type), NewLine))
631 MakefileName = self._FILE_NAME_[self._FileType]
632 LibraryMakeCommandList = []
633 for D in self.LibraryBuildDirectoryList:
634 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join(D, MakefileName)}
635 LibraryMakeCommandList.append(Command)
637 package_rel_dir = MyAgo.SourceDir
638 current_dir = self.Macros["WORKSPACE
"]
640 while not found and os.sep in package_rel_dir:
641 index = package_rel_dir.index(os.sep)
642 current_dir = mws.join(current_dir, package_rel_dir[:index])
643 if os.path.exists(current_dir):
644 for fl in os.listdir(current_dir):
645 if fl.endswith('.dec'):
648 package_rel_dir = package_rel_dir[index + 1:]
650 MakefileTemplateDict = {
651 "makefile_header
" : self._FILE_HEADER_[self._FileType],
652 "makefile_path
" : os.path.join("$
(MODULE_BUILD_DIR
)", MakefileName),
653 "makefile_name
" : MakefileName,
654 "platform_name
" : self.PlatformInfo.Name,
655 "platform_guid
" : self.PlatformInfo.Guid,
656 "platform_version
" : self.PlatformInfo.Version,
657 "platform_relative_directory
": self.PlatformInfo.SourceDir,
658 "platform_output_directory
" : self.PlatformInfo.OutputDir,
659 "ffs_output_directory
" : MyAgo.Macros["FFS_OUTPUT_DIR
"],
660 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
662 "module_name
" : MyAgo.Name,
663 "module_guid
" : MyAgo.Guid,
664 "module_name_guid
" : MyAgo.UniqueBaseName,
665 "module_version
" : MyAgo.Version,
666 "module_type
" : MyAgo.ModuleType,
667 "module_file
" : MyAgo.MetaFile.Name,
668 "module_file_base_name
" : MyAgo.MetaFile.BaseName,
669 "module_relative_directory
" : MyAgo.SourceDir,
670 "module_dir
" : mws.join (self.Macros["WORKSPACE
"], MyAgo.SourceDir),
671 "package_relative_directory
": package_rel_dir,
672 "module_extra_defines
" : ["%s = %s" % (k, v) for k, v in MyAgo.Module.Defines.items()],
674 "architecture
" : MyAgo.Arch,
675 "toolchain_tag
" : MyAgo.ToolChain,
676 "build_target
" : MyAgo.BuildTarget,
678 "platform_build_directory
" : self.PlatformInfo.BuildDir,
679 "module_build_directory
" : MyAgo.BuildDir,
680 "module_output_directory
" : MyAgo.OutputDir,
681 "module_debug_directory
" : MyAgo.DebugDir,
683 "separator
" : Separator,
684 "module_tool_definitions
" : ToolsDef,
686 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
687 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
689 "module_entry_point
" : ModuleEntryPoint,
690 "image_entry_point
" : ImageEntryPoint,
691 "arch_entry_point
" : ArchEntryPoint,
692 "remaining_build_target
" : self.ResultFileList,
693 "common_dependency_file
" : self.CommonFileDependency,
694 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
695 "clean_command
" : self.GetRemoveDirectoryCommand(["$
(OUTPUT_DIR
)"]),
696 "cleanall_command
" : self.GetRemoveDirectoryCommand(["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]),
697 "dependent_library_build_directory
" : self.LibraryBuildDirectoryList,
698 "library_build_command
" : LibraryMakeCommandList,
699 "file_macro
" : FileMacroList,
700 "file_build_target
" : self.BuildTargetList,
701 "backward_compatible_target
": BcTargetList,
702 "INCLUDETAG
" : "\n".join([self._INCLUDE_CMD_[self._FileType] + " " + os.path.join("$
(MODULE_BUILD_DIR
)","dependency
"),
703 self._INCLUDE_CMD_[self._FileType] + " " + os.path.join("$
(MODULE_BUILD_DIR
)","deps_target
")
707 return MakefileTemplateDict
709 def ParserGenerateFfsCmd(self):
710 #Add Ffs cmd to self.BuildTargetList
714 for Cmd in self.GenFfsList:
716 for CopyCmd in Cmd[2]:
718 Src = self.ReplaceMacro(Src)
719 Dst = self.ReplaceMacro(Dst)
720 if Dst not in self.ResultFileList:
721 self.ResultFileList.append(Dst)
722 if '%s :' %(Dst) not in self.BuildTargetList:
723 self.BuildTargetList.append("%s :" %(Dst))
724 self.BuildTargetList.append('\t' + self._CP_TEMPLATE_[self._FileType] %{'Src': Src, 'Dst': Dst})
727 for index, Str in enumerate(FfsCmdList):
729 OutputFile = FfsCmdList[index + 1]
730 if '-i' == Str or "-oi
" == Str:
731 if DepsFileList == []:
732 DepsFileList = [FfsCmdList[index + 1]]
734 DepsFileList.append(FfsCmdList[index + 1])
735 DepsFileString = ' '.join(DepsFileList).strip()
736 if DepsFileString == '':
738 OutputFile = self.ReplaceMacro(OutputFile)
739 self.ResultFileList.append(OutputFile)
740 DepsFileString = self.ReplaceMacro(DepsFileString)
741 self.BuildTargetList.append('%s : %s' % (OutputFile, DepsFileString))
742 CmdString = ' '.join(FfsCmdList).strip()
743 CmdString = self.ReplaceMacro(CmdString)
744 self.BuildTargetList.append('\t%s' % CmdString)
746 self.ParseSecCmd(DepsFileList, Cmd[1])
747 for SecOutputFile, SecDepsFile, SecCmd in self.FfsOutputFileList :
748 self.BuildTargetList.append('%s : %s' % (self.ReplaceMacro(SecOutputFile), self.ReplaceMacro(SecDepsFile)))
749 self.BuildTargetList.append('\t%s' % self.ReplaceMacro(SecCmd))
750 self.FfsOutputFileList = []
752 def ParseSecCmd(self, OutputFileList, CmdTuple):
753 for OutputFile in OutputFileList:
754 for SecCmdStr in CmdTuple:
756 SecCmdList = SecCmdStr.split()
757 CmdName = SecCmdList[0]
758 for index, CmdItem in enumerate(SecCmdList):
759 if '-o' == CmdItem and OutputFile == SecCmdList[index + 1]:
761 while index + 1 < len(SecCmdList):
762 if not SecCmdList[index+1].startswith('-'):
763 SecDepsFileList.append(SecCmdList[index + 1])
765 if CmdName == 'Trim':
766 SecDepsFileList.append(os.path.join('$(DEBUG_DIR)', os.path.basename(OutputFile).replace('offset', 'efi')))
767 if OutputFile.endswith('.ui') or OutputFile.endswith('.ver'):
768 SecDepsFileList.append(os.path.join('$(MODULE_DIR)', '$(MODULE_FILE)'))
769 self.FfsOutputFileList.append((OutputFile, ' '.join(SecDepsFileList), SecCmdStr))
770 if len(SecDepsFileList) > 0:
771 self.ParseSecCmd(SecDepsFileList, CmdTuple)
776 def ReplaceMacro(self, str):
777 for Macro in self.MacroList:
778 if self._AutoGenObject.Macros[Macro] and self._AutoGenObject.Macros[Macro] in str:
779 str = str.replace(self._AutoGenObject.Macros[Macro], '$(' + Macro + ')')
782 def CommandExceedLimit(self):
784 'CC' : { 'Macro' : '$(CC_FLAGS)', 'Value' : False},
785 'PP' : { 'Macro' : '$(PP_FLAGS)', 'Value' : False},
786 'APP' : { 'Macro' : '$(APP_FLAGS)', 'Value' : False},
787 'ASLPP' : { 'Macro' : '$(ASLPP_FLAGS)', 'Value' : False},
788 'VFRPP' : { 'Macro' : '$(VFRPP_FLAGS)', 'Value' : False},
789 'ASM' : { 'Macro' : '$(ASM_FLAGS)', 'Value' : False},
790 'ASLCC' : { 'Macro' : '$(ASLCC_FLAGS)', 'Value' : False},
795 IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily]
797 # base on the source files to decide the file type
798 for File in self._AutoGenObject.SourceFileList:
799 for type in self._AutoGenObject.FileTypes:
800 if File in self._AutoGenObject.FileTypes[type]:
801 if type not in FileTypeList:
802 FileTypeList.append(type)
804 # calculate the command-line length
806 for type in FileTypeList:
807 BuildTargets = self._AutoGenObject.BuildRules[type].BuildTargets
808 for Target in BuildTargets:
809 CommandList = BuildTargets[Target].Commands
810 for SingleCommand in CommandList:
812 SingleCommandLength = len(SingleCommand)
813 SingleCommandList = SingleCommand.split()
814 if len(SingleCommandList) > 0:
815 for Flag in FlagDict:
816 if '$('+ Flag +')' in SingleCommandList[0]:
820 if 'PATH' not in self._AutoGenObject.BuildOption[Tool]:
821 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))
822 SingleCommandLength += len(self._AutoGenObject.BuildOption[Tool]['PATH
'])
823 for item in SingleCommandList[1:]:
824 if FlagDict[Tool]['Macro
'] in item:
825 if 'FLAGS
' not in self._AutoGenObject.BuildOption[Tool]:
826 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))
827 Str = self._AutoGenObject.BuildOption[Tool]['FLAGS']
828 for Option in self._AutoGenObject.BuildOption:
829 for Attr in self._AutoGenObject.BuildOption[Option]:
830 if Str.find(Option + '_' + Attr) != -1:
831 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
832 while(Str.find('$(') != -1):
833 for macro in self._AutoGenObject.Macros:
834 MacroName = '$('+ macro + ')'
835 if (Str.find(MacroName) != -1):
836 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
840 SingleCommandLength += len(Str)
841 elif '$(INC)' in item:
842 SingleCommandLength += self._AutoGenObject.IncludePathLength + len(IncPrefix) * len(self._AutoGenObject.IncludePathList)
843 elif item.find('$(') != -1:
845 for Option in self._AutoGenObject.BuildOption:
846 for Attr in self._AutoGenObject.BuildOption[Option]:
847 if Str.find(Option + '_' + Attr) != -1:
848 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
849 while(Str.find('$(') != -1):
850 for macro in self._AutoGenObject.Macros:
851 MacroName = '$('+ macro + ')'
852 if (Str.find(MacroName) != -1):
853 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
857 SingleCommandLength += len(Str)
859 if SingleCommandLength > GlobalData.gCommandMaxLength:
860 FlagDict[Tool]['Value'] = True
862 # generate the response file content by combine the FLAGS and INC
863 for Flag in FlagDict:
864 if FlagDict[Flag]['Value']:
866 RespMacro = FlagDict[Flag]['Macro'].replace('FLAGS', 'RESP')
867 Value = self._AutoGenObject.BuildOption[Flag]['FLAGS']
868 for inc in self._AutoGenObject.IncludePathList:
869 Value += ' ' + IncPrefix + inc
870 for Option in self._AutoGenObject.BuildOption:
871 for Attr in self._AutoGenObject.BuildOption[Option]:
872 if Value.find(Option + '_' + Attr) != -1:
873 Value = Value.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
874 while (Value.find('$(') != -1):
875 for macro in self._AutoGenObject.Macros:
876 MacroName = '$('+ macro + ')'
877 if (Value.find(MacroName) != -1):
878 Value = Value.replace(MacroName, self._AutoGenObject.Macros[macro])
883 if self._AutoGenObject.ToolChainFamily == 'GCC':
884 RespDict[Key] = Value.replace('\\', '/')
886 RespDict[Key] = Value
887 for Target in BuildTargets:
888 for i, SingleCommand in enumerate(BuildTargets[Target].Commands):
889 if FlagDict[Flag]['Macro'] in SingleCommand:
890 BuildTargets[Target].Commands[i] = SingleCommand.replace('$(INC)', '').replace(FlagDict[Flag]['Macro'], RespMacro)
893 def ProcessBuildTargetList(self):
895 # Search dependency file list for each source file
897 ForceIncludedFile = []
898 for File in self._AutoGenObject.AutoGenFileList:
900 ForceIncludedFile.append(File)
903 for Target in self._AutoGenObject.IntroTargetList:
904 SourceFileList.extend(Target.Inputs)
905 OutPutFileList.extend(Target.Outputs)
908 for Item in OutPutFileList:
909 if Item in SourceFileList:
910 SourceFileList.remove(Item)
912 FileDependencyDict = {item:ForceIncludedFile for item in SourceFileList}
914 for Dependency in FileDependencyDict.values():
915 self.DependencyHeaderFileSet.update(set(Dependency))
917 # Get a set of unique package includes from MetaFile
918 parentMetaFileIncludes = set()
919 for aInclude in self._AutoGenObject.PackageIncludePathList:
920 aIncludeName = str(aInclude)
921 parentMetaFileIncludes.add(aIncludeName.lower())
923 # Check if header files are listed in metafile
924 # Get a set of unique module header source files from MetaFile
925 headerFilesInMetaFileSet = set()
926 for aFile in self._AutoGenObject.SourceFileList:
927 aFileName = str(aFile)
928 if not aFileName.endswith('.h'):
930 headerFilesInMetaFileSet.add(aFileName.lower())
932 # Get a set of unique module autogen files
933 localAutoGenFileSet = set()
934 for aFile in self._AutoGenObject.AutoGenFileList:
935 localAutoGenFileSet.add(str(aFile).lower())
937 # Get a set of unique module dependency header files
938 # Exclude autogen files and files not in the source directory
939 # and files that are under the package include list
940 headerFileDependencySet = set()
941 localSourceDir = str(self._AutoGenObject.SourceDir).lower()
942 for Dependency in FileDependencyDict.values():
943 for aFile in Dependency:
944 aFileName = str(aFile).lower()
945 # Exclude non-header files
946 if not aFileName.endswith('.h'):
948 # Exclude autogen files
949 if aFileName in localAutoGenFileSet:
951 # Exclude include out of local scope
952 if localSourceDir not in aFileName:
954 # Exclude files covered by package includes
956 for aIncludePath in parentMetaFileIncludes:
957 if aIncludePath in aFileName:
962 # Keep the file to be checked
963 headerFileDependencySet.add(aFileName)
965 # Check if a module dependency header file is missing from the module's MetaFile
966 for aFile in headerFileDependencySet:
967 if aFile in headerFilesInMetaFileSet:
969 if GlobalData.gUseHashCache:
970 GlobalData.gModuleBuildTracking[self._AutoGenObject] = 'FAIL_METAFILE'
971 EdkLogger.warn("build
","Module MetaFile
[Sources
] is missing local header
!",
972 ExtraData = "Local Header
: " + aFile + " not found
in " + self._AutoGenObject.MetaFile.Path
975 for File,Dependency in FileDependencyDict.items():
979 self._AutoGenObject.AutoGenDepSet |= set(Dependency)
984 DependencyDict = FileDependencyDict.copy()
986 # Convert target description object to target string in makefile
987 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and TAB_C_CODE_FILE in self._AutoGenObject.Targets:
988 for T in self._AutoGenObject.Targets[TAB_C_CODE_FILE]:
989 NewFile = self.PlaceMacro(str(T), self.Macros)
990 if not self.ObjTargetDict.get(T.Target.SubDir):
991 self.ObjTargetDict[T.Target.SubDir] = set()
992 self.ObjTargetDict[T.Target.SubDir].add(NewFile)
993 for Type in self._AutoGenObject.Targets:
994 for T in self._AutoGenObject.Targets[Type]:
995 # Generate related macros if needed
996 if T.GenFileListMacro and T.FileListMacro not in self.FileListMacros:
997 self.FileListMacros[T.FileListMacro] = []
998 if T.GenListFile and T.ListFileMacro not in self.ListFileMacros:
999 self.ListFileMacros[T.ListFileMacro] = []
1000 if T.GenIncListFile and T.IncListFileMacro not in self.ListFileMacros:
1001 self.ListFileMacros[T.IncListFileMacro] = []
1005 # Add force-dependencies
1006 for Dep in T.Dependencies:
1007 Deps.append(self.PlaceMacro(str(Dep), self.Macros))
1008 if Dep != '$(MAKE_FILE)':
1009 CCodeDeps.append(self.PlaceMacro(str(Dep), self.Macros))
1010 # Add inclusion-dependencies
1011 if len(T.Inputs) == 1 and T.Inputs[0] in FileDependencyDict:
1012 for F in FileDependencyDict[T.Inputs[0]]:
1013 Deps.append(self.PlaceMacro(str(F), self.Macros))
1014 # Add source-dependencies
1016 NewFile = self.PlaceMacro(str(F), self.Macros)
1017 # In order to use file list macro as dependency
1019 # gnu tools need forward slash path separator, even on Windows
1020 self.ListFileMacros[T.ListFileMacro].append(str(F).replace ('\\', '/'))
1021 self.FileListMacros[T.FileListMacro].append(NewFile)
1022 elif T.GenFileListMacro:
1023 self.FileListMacros[T.FileListMacro].append(NewFile)
1025 Deps.append(NewFile)
1026 for key in self.FileListMacros:
1027 self.FileListMacros[key].sort()
1028 # Use file list macro as dependency
1029 if T.GenFileListMacro:
1030 Deps.append("$
(%s)" % T.FileListMacro)
1031 if Type in [TAB_OBJECT_FILE, TAB_STATIC_LIBRARY]:
1032 Deps.append("$
(%s)" % T.ListFileMacro)
1034 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Type == TAB_C_CODE_FILE:
1035 T, CmdTarget, CmdTargetDict, CmdCppDict = self.ParserCCodeFile(T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict)
1036 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": CCodeDeps}
1037 CmdLine = self._BUILD_TARGET_TEMPLATE.Replace(TargetDict).rstrip().replace('\t$(OBJLIST', '$(OBJLIST')
1039 CmdLine = '%s%s' %(CmdLine, TAB_LINE_BREAK)
1040 if CCodeDeps or CmdLine:
1041 self.BuildTargetList.append(CmdLine)
1043 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": Deps}
1044 self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(TargetDict))
1046 def ParserCCodeFile(self, T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict):
1048 for item in self._AutoGenObject.Targets[Type]:
1049 CmdSumDict[item.Target.SubDir] = item.Target.BaseName
1050 for CppPath in item.Inputs:
1051 Path = self.PlaceMacro(CppPath.Path, self.Macros)
1052 if CmdCppDict.get(item.Target.SubDir):
1053 CmdCppDict[item.Target.SubDir].append(Path)
1055 CmdCppDict[item.Target.SubDir] = ['$(MAKE_FILE)', Path]
1056 if CppPath.Path in DependencyDict:
1057 for Temp in DependencyDict[CppPath.Path]:
1059 Path = self.PlaceMacro(Temp.Path, self.Macros)
1062 if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):
1063 CmdCppDict[item.Target.SubDir].append(Path)
1065 CommandList = T.Commands[:]
1066 for Item in CommandList[:]:
1067 SingleCommandList = Item.split()
1068 if len(SingleCommandList) > 0 and self.CheckCCCmd(SingleCommandList):
1069 for Temp in SingleCommandList:
1070 if Temp.startswith('/Fo'):
1071 CmdSign = '%s%s' % (Temp.rsplit(TAB_SLASH, 1)[0], TAB_SLASH)
1074 if CmdSign not in list(CmdTargetDict.keys()):
1075 CmdTargetDict[CmdSign] = Item.replace(Temp, CmdSign)
1077 CmdTargetDict[CmdSign] = "%s %s" % (CmdTargetDict[CmdSign], SingleCommandList[-1])
1078 Index = CommandList.index(Item)
1079 CommandList.pop(Index)
1080 if SingleCommandList[-1].endswith("%s%s.c
" % (TAB_SLASH, CmdSumDict[CmdSign[3:].rsplit(TAB_SLASH, 1)[0]])):
1081 Cpplist = CmdCppDict[T.Target.SubDir]
1082 Cpplist.insert(0, '$(OBJLIST_%d): ' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir))
1083 T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign])
1085 T.Commands.pop(Index)
1086 return T, CmdSumDict, CmdTargetDict, CmdCppDict
1088 def CheckCCCmd(self, CommandList):
1089 for cmd in CommandList:
1093 ## For creating makefile targets for dependent libraries
1094 def ProcessDependentLibrary(self):
1095 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1096 if not LibraryAutoGen.IsBinaryModule:
1097 self.LibraryBuildDirectoryList.append(self.PlaceMacro(LibraryAutoGen.BuildDir, self.Macros))
1099 ## Return a list containing source file's dependencies
1101 # @param FileList The list of source files
1102 # @param ForceInculeList The list of files which will be included forcely
1103 # @param SearchPathList The list of search path
1105 # @retval dict The mapping between source file path and its dependencies
1107 def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):
1110 Dependency[F] = GetDependencyList(self._AutoGenObject, self.FileCache, F, ForceInculeList, SearchPathList)
1114 ## CustomMakefile class
1116 # This class encapsules makefie and its generation for module. It uses template to generate
1117 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
1119 class CustomMakefile(BuildFile):
1120 ## template used to generate the makefile for module with custom makefile
1121 _TEMPLATE_ = TemplateString('''\
1125 # Platform Macro Definition
1127 PLATFORM_NAME = ${platform_name}
1128 PLATFORM_GUID = ${platform_guid}
1129 PLATFORM_VERSION = ${platform_version}
1130 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
1131 PLATFORM_DIR = ${platform_dir}
1132 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1135 # Module Macro Definition
1137 MODULE_NAME = ${module_name}
1138 MODULE_GUID = ${module_guid}
1139 MODULE_NAME_GUID = ${module_name_guid}
1140 MODULE_VERSION = ${module_version}
1141 MODULE_TYPE = ${module_type}
1142 MODULE_FILE = ${module_file}
1143 MODULE_FILE_BASE_NAME = ${module_file_base_name}
1144 BASE_NAME = $(MODULE_NAME)
1145 MODULE_RELATIVE_DIR = ${module_relative_directory}
1146 MODULE_DIR = ${module_dir}
1149 # Build Configuration Macro Definition
1151 ARCH = ${architecture}
1152 TOOLCHAIN = ${toolchain_tag}
1153 TOOLCHAIN_TAG = ${toolchain_tag}
1154 TARGET = ${build_target}
1157 # Build Directory Macro Definition
1159 # PLATFORM_BUILD_DIR = ${platform_build_directory}
1160 BUILD_DIR = ${platform_build_directory}
1161 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
1162 LIB_DIR = $(BIN_DIR)
1163 MODULE_BUILD_DIR = ${module_build_directory}
1164 OUTPUT_DIR = ${module_output_directory}
1165 DEBUG_DIR = ${module_debug_directory}
1166 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
1167 DEST_DIR_DEBUG = $(DEBUG_DIR)
1170 # Tools definitions specific to this module
1172 ${BEGIN}${module_tool_definitions}
1174 MAKE_FILE = ${makefile_path}
1177 # Shell Command Macro
1179 ${BEGIN}${shell_command_code} = ${shell_command}
1182 ${custom_makefile_content}
1185 # Target used when called from platform makefile, which will bypass the build of dependent libraries
1198 # Build Target used in multi-thread build mode, which no init target is needed
1204 # Initialization target: print build information and create necessary directories
1207 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
1208 ${BEGIN}\t-@${create_directory_command}\n${END}\
1212 ## Constructor of CustomMakefile
1214 # @param ModuleAutoGen Object of ModuleAutoGen class
1216 def __init__(self, ModuleAutoGen):
1217 BuildFile.__init__(self, ModuleAutoGen)
1218 self.PlatformInfo = self._AutoGenObject.PlatformInfo
1219 self.IntermediateDirectoryList = ["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]
1220 self.DependencyHeaderFileSet = set()
1222 # Compose a dict object containing information used to do replacement in template
1224 def _TemplateDict(self):
1225 Separator = self._SEP_[self._FileType]
1226 MyAgo = self._AutoGenObject
1227 if self._FileType not in MyAgo.CustomMakefile:
1228 EdkLogger.error('build', OPTION_NOT_SUPPORTED, "No custom makefile
for %s" % self._FileType,
1229 ExtraData="[%s]" % str(MyAgo))
1230 MakefilePath = mws.join(
1232 MyAgo.CustomMakefile[self._FileType]
1235 CustomMakefile = open(MakefilePath, 'r').read()
1237 EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(MyAgo),
1238 ExtraData=MyAgo.CustomMakefile[self._FileType])
1242 for Tool in MyAgo.BuildOption:
1243 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
1246 for Attr in MyAgo.BuildOption[Tool]:
1247 if Attr == "FAMILY
":
1249 elif Attr == "PATH
":
1250 ToolsDef.append("%s = %s" % (Tool, MyAgo.BuildOption[Tool][Attr]))
1252 ToolsDef.append("%s_%s = %s" % (Tool, Attr, MyAgo.BuildOption[Tool][Attr]))
1255 MakefileName = self._FILE_NAME_[self._FileType]
1256 MakefileTemplateDict = {
1257 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1258 "makefile_path
" : os.path.join("$
(MODULE_BUILD_DIR
)", MakefileName),
1259 "platform_name
" : self.PlatformInfo.Name,
1260 "platform_guid
" : self.PlatformInfo.Guid,
1261 "platform_version
" : self.PlatformInfo.Version,
1262 "platform_relative_directory
": self.PlatformInfo.SourceDir,
1263 "platform_output_directory
" : self.PlatformInfo.OutputDir,
1264 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1266 "module_name
" : MyAgo.Name,
1267 "module_guid
" : MyAgo.Guid,
1268 "module_name_guid
" : MyAgo.UniqueBaseName,
1269 "module_version
" : MyAgo.Version,
1270 "module_type
" : MyAgo.ModuleType,
1271 "module_file
" : MyAgo.MetaFile,
1272 "module_file_base_name
" : MyAgo.MetaFile.BaseName,
1273 "module_relative_directory
" : MyAgo.SourceDir,
1274 "module_dir
" : mws.join (MyAgo.WorkspaceDir, MyAgo.SourceDir),
1276 "architecture
" : MyAgo.Arch,
1277 "toolchain_tag
" : MyAgo.ToolChain,
1278 "build_target
" : MyAgo.BuildTarget,
1280 "platform_build_directory
" : self.PlatformInfo.BuildDir,
1281 "module_build_directory
" : MyAgo.BuildDir,
1282 "module_output_directory
" : MyAgo.OutputDir,
1283 "module_debug_directory
" : MyAgo.DebugDir,
1285 "separator
" : Separator,
1286 "module_tool_definitions
" : ToolsDef,
1288 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1289 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1291 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1292 "custom_makefile_content
" : CustomMakefile
1295 return MakefileTemplateDict
1297 ## PlatformMakefile class
1299 # This class encapsules makefie and its generation for platform. It uses
1300 # template to generate the content of makefile. The content of makefile will be
1301 # got from PlatformAutoGen object.
1303 class PlatformMakefile(BuildFile):
1304 ## template used to generate the makefile for platform
1305 _TEMPLATE_ = TemplateString('''\
1309 # Platform Macro Definition
1311 PLATFORM_NAME = ${platform_name}
1312 PLATFORM_GUID = ${platform_guid}
1313 PLATFORM_VERSION = ${platform_version}
1314 PLATFORM_FILE = ${platform_file}
1315 PLATFORM_DIR = ${platform_dir}
1316 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1319 # Build Configuration Macro Definition
1321 TOOLCHAIN = ${toolchain_tag}
1322 TOOLCHAIN_TAG = ${toolchain_tag}
1323 TARGET = ${build_target}
1326 # Build Directory Macro Definition
1328 BUILD_DIR = ${platform_build_directory}
1329 FV_DIR = ${platform_build_directory}${separator}FV
1332 # Shell Command Macro
1334 ${BEGIN}${shell_command_code} = ${shell_command}
1338 MAKE_FILE = ${makefile_path}
1343 all: init build_libraries build_modules
1346 # Initialization target: print build information and create necessary directories
1349 \t-@echo Building ... $(PLATFORM_FILE) [${build_architecture_list}]
1350 \t${BEGIN}-@${create_directory_command}
1353 # library build target
1355 libraries: init build_libraries
1358 # module build target
1360 modules: init build_libraries build_modules
1363 # Build all libraries:
1366 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${library_makefile_list} pbuild
1367 ${END}\t@cd $(BUILD_DIR)
1370 # Build all modules:
1373 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${module_makefile_list} pbuild
1374 ${END}\t@cd $(BUILD_DIR)
1377 # Clean intermediate files
1380 \t${BEGIN}-@${library_build_command} clean
1381 \t${END}${BEGIN}-@${module_build_command} clean
1382 \t${END}@cd $(BUILD_DIR)
1385 # Clean all generated files except to makefile
1388 ${BEGIN}\t${cleanall_command}
1392 # Clean all library files
1395 \t${BEGIN}-@${library_build_command} cleanall
1396 \t${END}@cd $(BUILD_DIR)\n
1399 ## Constructor of PlatformMakefile
1401 # @param ModuleAutoGen Object of PlatformAutoGen class
1403 def __init__(self, PlatformAutoGen):
1404 BuildFile.__init__(self, PlatformAutoGen)
1405 self.ModuleBuildCommandList = []
1406 self.ModuleMakefileList = []
1407 self.IntermediateDirectoryList = []
1408 self.ModuleBuildDirectoryList = []
1409 self.LibraryBuildDirectoryList = []
1410 self.LibraryMakeCommandList = []
1411 self.DependencyHeaderFileSet = set()
1413 # Compose a dict object containing information used to do replacement in template
1415 def _TemplateDict(self):
1416 Separator = self._SEP_[self._FileType]
1418 MyAgo = self._AutoGenObject
1419 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1420 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1421 ExtraData="[%s]" % str(MyAgo))
1423 self.IntermediateDirectoryList = ["$
(BUILD_DIR
)"]
1424 self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()
1425 self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()
1427 MakefileName = self._FILE_NAME_[self._FileType]
1428 LibraryMakefileList = []
1429 LibraryMakeCommandList = []
1430 for D in self.LibraryBuildDirectoryList:
1431 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1432 Makefile = os.path.join(D, MakefileName)
1433 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1434 LibraryMakefileList.append(Makefile)
1435 LibraryMakeCommandList.append(Command)
1436 self.LibraryMakeCommandList = LibraryMakeCommandList
1438 ModuleMakefileList = []
1439 ModuleMakeCommandList = []
1440 for D in self.ModuleBuildDirectoryList:
1441 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1442 Makefile = os.path.join(D, MakefileName)
1443 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1444 ModuleMakefileList.append(Makefile)
1445 ModuleMakeCommandList.append(Command)
1447 MakefileTemplateDict = {
1448 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1449 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1450 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1451 "makefile_name
" : MakefileName,
1452 "platform_name
" : MyAgo.Name,
1453 "platform_guid
" : MyAgo.Guid,
1454 "platform_version
" : MyAgo.Version,
1455 "platform_file
" : MyAgo.MetaFile,
1456 "platform_relative_directory
": MyAgo.SourceDir,
1457 "platform_output_directory
" : MyAgo.OutputDir,
1458 "platform_build_directory
" : MyAgo.BuildDir,
1459 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1461 "toolchain_tag
" : MyAgo.ToolChain,
1462 "build_target
" : MyAgo.BuildTarget,
1463 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1464 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1465 "build_architecture_list
" : MyAgo.Arch,
1466 "architecture
" : MyAgo.Arch,
1467 "separator
" : Separator,
1468 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1469 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1470 "library_makefile_list
" : LibraryMakefileList,
1471 "module_makefile_list
" : ModuleMakefileList,
1472 "library_build_command
" : LibraryMakeCommandList,
1473 "module_build_command
" : ModuleMakeCommandList,
1476 return MakefileTemplateDict
1478 ## Get the root directory list for intermediate files of all modules build
1480 # @retval list The list of directory
1482 def GetModuleBuildDirectoryList(self):
1484 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1485 if not ModuleAutoGen.IsBinaryModule:
1486 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1489 ## Get the root directory list for intermediate files of all libraries build
1491 # @retval list The list of directory
1493 def GetLibraryBuildDirectoryList(self):
1495 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1496 if not LibraryAutoGen.IsBinaryModule:
1497 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1500 ## TopLevelMakefile class
1502 # This class encapsules makefie and its generation for entrance makefile. It
1503 # uses template to generate the content of makefile. The content of makefile
1504 # will be got from WorkspaceAutoGen object.
1506 class TopLevelMakefile(BuildFile):
1507 ## template used to generate toplevel makefile
1508 _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}''')
1510 ## Constructor of TopLevelMakefile
1512 # @param Workspace Object of WorkspaceAutoGen class
1514 def __init__(self, Workspace):
1515 BuildFile.__init__(self, Workspace)
1516 self.IntermediateDirectoryList = []
1517 self.DependencyHeaderFileSet = set()
1519 # Compose a dict object containing information used to do replacement in template
1521 def _TemplateDict(self):
1522 Separator = self._SEP_[self._FileType]
1524 # any platform autogen object is ok because we just need common information
1525 MyAgo = self._AutoGenObject
1527 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1528 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1529 ExtraData="[%s]" % str(MyAgo))
1531 for Arch in MyAgo.ArchList:
1532 self.IntermediateDirectoryList.append(Separator.join(["$
(BUILD_DIR
)", Arch]))
1533 self.IntermediateDirectoryList.append("$
(FV_DIR
)")
1535 # TRICK: for not generating GenFds call in makefile if no FDF file
1537 if MyAgo.FdfFile is not None and MyAgo.FdfFile != "":
1538 FdfFileList = [MyAgo.FdfFile]
1539 # macros passed to GenFds
1541 MacroDict.update(GlobalData.gGlobalDefines)
1542 MacroDict.update(GlobalData.gCommandLineDefines)
1543 for MacroName in MacroDict:
1544 if MacroDict[MacroName] != "":
1545 MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
1547 MacroList.append('"%s"' % MacroName)
1551 # pass extra common options to external program called in makefile, currently GenFds.exe
1553 LogLevel = EdkLogger.GetLevel()
1554 if LogLevel == EdkLogger.VERBOSE:
1555 ExtraOption += " -v
"
1556 elif LogLevel <= EdkLogger.DEBUG_9:
1557 ExtraOption += " -d
%d" % (LogLevel - 1)
1558 elif LogLevel == EdkLogger.QUIET:
1559 ExtraOption += " -q
"
1561 if GlobalData.gCaseInsensitive:
1562 ExtraOption += " -c
"
1563 if not GlobalData.gEnableGenfdsMultiThread:
1564 ExtraOption += " --no
-genfds
-multi
-thread
"
1565 if GlobalData.gIgnoreSource:
1566 ExtraOption += " --ignore
-sources
"
1568 for pcd in GlobalData.BuildOptionPcd:
1570 pcdname = '.'.join(pcd[0:3])
1572 pcdname = '.'.join(pcd[0:2])
1573 if pcd[3].startswith('{'):
1574 ExtraOption += " --pcd
" + pcdname + '=' + 'H' + '"' + pcd[3] + '"'
1576 ExtraOption += " --pcd
" + pcdname + '=' + pcd[3]
1578 MakefileName = self._FILE_NAME_[self._FileType]
1579 SubBuildCommandList = []
1580 for A in MyAgo.ArchList:
1581 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join("$
(BUILD_DIR
)", A, MakefileName)}
1582 SubBuildCommandList.append(Command)
1584 MakefileTemplateDict = {
1585 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1586 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1587 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1588 "platform_name
" : MyAgo.Name,
1589 "platform_guid
" : MyAgo.Guid,
1590 "platform_version
" : MyAgo.Version,
1591 "platform_build_directory
" : MyAgo.BuildDir,
1592 "conf_directory
" : GlobalData.gConfDirectory,
1594 "toolchain_tag
" : MyAgo.ToolChain,
1595 "build_target
" : MyAgo.BuildTarget,
1596 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1597 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1598 'arch' : list(MyAgo.ArchList),
1599 "build_architecture_list
" : ','.join(MyAgo.ArchList),
1600 "separator
" : Separator,
1601 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1602 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1603 "sub_build_command
" : SubBuildCommandList,
1604 "fdf_file
" : FdfFileList,
1605 "active_platform
" : str(MyAgo),
1606 "fd
" : MyAgo.FdTargetList,
1607 "fv
" : MyAgo.FvTargetList,
1608 "cap
" : MyAgo.CapTargetList,
1609 "extra_options
" : ExtraOption,
1610 "macro
" : MacroList,
1613 return MakefileTemplateDict
1615 ## Get the root directory list for intermediate files of all modules build
1617 # @retval list The list of directory
1619 def GetModuleBuildDirectoryList(self):
1621 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1622 if not ModuleAutoGen.IsBinaryModule:
1623 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1626 ## Get the root directory list for intermediate files of all libraries build
1628 # @retval list The list of directory
1630 def GetLibraryBuildDirectoryList(self):
1632 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1633 if not LibraryAutoGen.IsBinaryModule:
1634 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1637 ## Find dependencies for one source file
1639 # By searching recursively "#include" directive in file, find out all the
1640 # files needed by given source file. The dependencies will be only searched
1641 # in given search path list.
1643 # @param File The source file
1644 # @param ForceInculeList The list of files which will be included forcely
1645 # @param SearchPathList The list of search path
1647 # @retval list The list of files the given source file depends on
1649 def GetDependencyList(AutoGenObject
, FileCache
, File
, ForceList
, SearchPathList
):
1650 EdkLogger
.debug(EdkLogger
.DEBUG_1
, "Try to get dependency files for %s" % File
)
1651 FileStack
= [File
] + ForceList
1652 DependencySet
= set()
1654 if AutoGenObject
.Arch
not in gDependencyDatabase
:
1655 gDependencyDatabase
[AutoGenObject
.Arch
] = {}
1656 DepDb
= gDependencyDatabase
[AutoGenObject
.Arch
]
1658 while len(FileStack
) > 0:
1661 FullPathDependList
= []
1663 for CacheFile
in FileCache
[F
]:
1664 FullPathDependList
.append(CacheFile
)
1665 if CacheFile
not in DependencySet
:
1666 FileStack
.append(CacheFile
)
1667 DependencySet
.update(FullPathDependList
)
1670 CurrentFileDependencyList
= []
1672 CurrentFileDependencyList
= DepDb
[F
]
1675 Fd
= open(F
.Path
, 'rb')
1676 FileContent
= Fd
.read()
1678 except BaseException
as X
:
1679 EdkLogger
.error("build", FILE_OPEN_FAILURE
, ExtraData
=F
.Path
+ "\n\t" + str(X
))
1680 if len(FileContent
) == 0:
1683 if FileContent
[0] == 0xff or FileContent
[0] == 0xfe:
1684 FileContent
= FileContent
.decode('utf-16')
1686 FileContent
= FileContent
.decode()
1688 # The file is not txt file. for example .mcb file
1690 IncludedFileList
= gIncludePattern
.findall(FileContent
)
1692 for Inc
in IncludedFileList
:
1694 # if there's macro used to reference header file, expand it
1695 HeaderList
= gMacroPattern
.findall(Inc
)
1696 if len(HeaderList
) == 1 and len(HeaderList
[0]) == 2:
1697 HeaderType
= HeaderList
[0][0]
1698 HeaderKey
= HeaderList
[0][1]
1699 if HeaderType
in gIncludeMacroConversion
:
1700 Inc
= gIncludeMacroConversion
[HeaderType
] % {"HeaderKey" : HeaderKey
}
1702 # not known macro used in #include, always build the file by
1703 # returning a empty dependency
1704 FileCache
[File
] = []
1706 Inc
= os
.path
.normpath(Inc
)
1707 CurrentFileDependencyList
.append(Inc
)
1708 DepDb
[F
] = CurrentFileDependencyList
1710 CurrentFilePath
= F
.Dir
1711 PathList
= [CurrentFilePath
] + SearchPathList
1712 for Inc
in CurrentFileDependencyList
:
1713 for SearchPath
in PathList
:
1714 FilePath
= os
.path
.join(SearchPath
, Inc
)
1715 if FilePath
in gIsFileMap
:
1716 if not gIsFileMap
[FilePath
]:
1718 # If isfile is called too many times, the performance is slow down.
1719 elif not os
.path
.isfile(FilePath
):
1720 gIsFileMap
[FilePath
] = False
1723 gIsFileMap
[FilePath
] = True
1724 FilePath
= PathClass(FilePath
)
1725 FullPathDependList
.append(FilePath
)
1726 if FilePath
not in DependencySet
:
1727 FileStack
.append(FilePath
)
1730 EdkLogger
.debug(EdkLogger
.DEBUG_9
, "%s included by %s was not found "\
1731 "in any given path:\n\t%s" % (Inc
, F
, "\n\t".join(SearchPathList
)))
1733 FileCache
[F
] = FullPathDependList
1734 DependencySet
.update(FullPathDependList
)
1736 DependencySet
.update(ForceList
)
1737 if File
in DependencySet
:
1738 DependencySet
.remove(File
)
1739 DependencyList
= list(DependencySet
) # remove duplicate ones
1741 return DependencyList
1743 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1744 if __name__
== '__main__':