2 # Create makefile for MS nmake and GNU make
4 # Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.<BR>
5 # Copyright (c) 2020, ARM Limited. All rights reserved.<BR>
6 # SPDX-License-Identifier: BSD-2-Clause-Patent
11 from __future__
import absolute_import
12 import Common
.LongFilePathOs
as os
16 import os
.path
as path
17 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
18 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
19 from Common
.BuildToolError
import *
20 from Common
.Misc
import *
21 from Common
.StringUtils
import *
22 from .BuildEngine
import *
23 import Common
.GlobalData
as GlobalData
24 from collections
import OrderedDict
25 from Common
.DataType
import TAB_COMPILER_MSFT
27 ## Regular expression for finding header file inclusions
28 gIncludePattern
= re
.compile(r
"^[ \t]*[#%]?[ \t]*include(?:[ \t]*(?:\\(?:\r\n|\r|\n))*[ \t]*)*(?:\(?[\"<]?
[ \t]*)([-\w
.\\/() \t]+)(?
:[ \t]*[\">]?\
)?
)", re.MULTILINE | re.UNICODE | re.IGNORECASE)
30 ## Regular expression for matching macro used in header file inclusion
31 gMacroPattern = re.compile("([_A
-Z
][_A
-Z0
-9]*)[ \t]*\
((.+)\
)", re.UNICODE)
35 ## pattern for include style in Edk.x code
36 gProtocolDefinition = "Protocol
/%(HeaderKey)s/%(HeaderKey)s.h
"
37 gGuidDefinition = "Guid
/%(HeaderKey)s/%(HeaderKey)s.h
"
38 gArchProtocolDefinition = "ArchProtocol
/%(HeaderKey)s/%(HeaderKey)s.h
"
39 gPpiDefinition = "Ppi
/%(HeaderKey)s/%(HeaderKey)s.h
"
40 gIncludeMacroConversion = {
41 "EFI_PROTOCOL_DEFINITION
" : gProtocolDefinition,
42 "EFI_GUID_DEFINITION
" : gGuidDefinition,
43 "EFI_ARCH_PROTOCOL_DEFINITION
" : gArchProtocolDefinition,
44 "EFI_PROTOCOL_PRODUCER
" : gProtocolDefinition,
45 "EFI_PROTOCOL_CONSUMER
" : gProtocolDefinition,
46 "EFI_PROTOCOL_DEPENDENCY
" : gProtocolDefinition,
47 "EFI_ARCH_PROTOCOL_PRODUCER
" : gArchProtocolDefinition,
48 "EFI_ARCH_PROTOCOL_CONSUMER
" : gArchProtocolDefinition,
49 "EFI_ARCH_PROTOCOL_DEPENDENCY
" : gArchProtocolDefinition,
50 "EFI_PPI_DEFINITION
" : gPpiDefinition,
51 "EFI_PPI_PRODUCER
" : gPpiDefinition,
52 "EFI_PPI_CONSUMER
" : gPpiDefinition,
53 "EFI_PPI_DEPENDENCY
" : gPpiDefinition,
56 NMAKE_FILETYPE = "nmake
"
57 GMAKE_FILETYPE = "gmake
"
58 WIN32_PLATFORM = "win32
"
59 POSIX_PLATFORM = "posix
"
63 # This base class encapsules build file and its generation. It uses template to generate
64 # the content of build file. The content of build file will be got from AutoGen objects.
66 class BuildFile(object):
67 ## template used to generate the build file (i.e. makefile if using make)
68 _TEMPLATE_ = TemplateString('')
70 _DEFAULT_FILE_NAME_ = "Makefile
"
72 ## default file name for each type of build file
74 NMAKE_FILETYPE : "Makefile
",
75 GMAKE_FILETYPE : "GNUmakefile
"
79 def getMakefileName(self):
80 if not self._FileType:
81 return self._DEFAULT_FILE_NAME_
83 return self._FILE_NAME_[self._FileType]
85 ## Fixed header string for makefile
86 _MAKEFILE_HEADER = '''#
88 # This file is auto-generated by build utility
96 # Auto-generated makefile for building modules, libraries or platform
100 ## Header string for each type of build file
102 NMAKE_FILETYPE : _MAKEFILE_HEADER % _FILE_NAME_[NMAKE_FILETYPE],
103 GMAKE_FILETYPE : _MAKEFILE_HEADER % _FILE_NAME_[GMAKE_FILETYPE]
106 ## shell commands which can be used in build file in the form of macro
107 # $(CP) copy file command
108 # $(MV) move file command
109 # $(RM) remove file command
110 # $(MD) create dir command
111 # $(RD) remove dir command
119 "RD
" : "rmdir
/s
/q
",
131 ## directory separator
133 WIN32_PLATFORM : "\\",
137 ## directory creation template
139 WIN32_PLATFORM : 'if not exist %(dir)s $(MD) %(dir)s',
140 POSIX_PLATFORM : "$
(MD
) %(dir)s"
143 ## directory removal template
145 WIN32_PLATFORM : 'if exist %(dir)s $(RD) %(dir)s',
146 POSIX_PLATFORM : "$
(RD
) %(dir)s"
150 WIN32_PLATFORM : 'if exist %(Src)s $(CP) %(Src)s %(Dst)s',
151 POSIX_PLATFORM : "test
-f
%(Src)s && $
(CP
) %(Src)s %(Dst)s"
155 WIN32_PLATFORM : 'if exist %(dir)s cd %(dir)s',
156 POSIX_PLATFORM : "test
-e
%(dir)s && cd
%(dir)s"
160 WIN32_PLATFORM : 'if exist %(file)s "$
(MAKE
)" $(MAKE_FLAGS) -f %(file)s',
161 POSIX_PLATFORM : 'test -e %(file)s && "$
(MAKE
)" $(MAKE_FLAGS) -f %(file)s'
165 NMAKE_FILETYPE : '!INCLUDE',
166 GMAKE_FILETYPE : "include
"
169 _INC_FLAG_ = {TAB_COMPILER_MSFT : "/I
", "GCC
" : "-I
", "INTEL
" : "-I
", "RVCT
" : "-I
", "NASM
" : "-I
"}
171 ## Constructor of BuildFile
173 # @param AutoGenObject Object of AutoGen class
175 def __init__(self, AutoGenObject):
176 self._AutoGenObject = AutoGenObject
178 MakePath = AutoGenObject.BuildOption.get('MAKE', {}).get('PATH')
181 elif "nmake
" in MakePath:
182 self._FileType = NMAKE_FILETYPE
184 self._FileType = "gmake
"
186 if sys.platform == "win32
":
187 self._Platform = WIN32_PLATFORM
189 self._Platform = POSIX_PLATFORM
191 ## Create build file.
193 # Only nmake and gmake are supported.
195 # @retval TRUE The build file is created or re-created successfully.
196 # @retval FALSE The build file exists and is the same as the one to be generated.
199 FileContent = self._TEMPLATE_.Replace(self._TemplateDict)
200 FileName = self.getMakefileName()
201 if not os.path.exists(os.path.join(self._AutoGenObject.MakeFileDir, "deps
.txt
")):
202 with open(os.path.join(self._AutoGenObject.MakeFileDir, "deps
.txt
"),"w
+") as fd:
204 if not os.path.exists(os.path.join(self._AutoGenObject.MakeFileDir, "dependency
")):
205 with open(os.path.join(self._AutoGenObject.MakeFileDir, "dependency
"),"w
+") as fd:
207 if not os.path.exists(os.path.join(self._AutoGenObject.MakeFileDir, "deps_target
")):
208 with open(os.path.join(self._AutoGenObject.MakeFileDir, "deps_target
"),"w
+") as fd:
210 return SaveFileOnChange(os.path.join(self._AutoGenObject.MakeFileDir, FileName), FileContent, False)
212 ## Return a list of directory creation command string
214 # @param DirList The list of directory to be created
216 # @retval list The directory creation command list
218 def GetCreateDirectoryCommand(self, DirList):
219 return [self._MD_TEMPLATE_[self._Platform] % {'dir':Dir} for Dir in DirList]
221 ## Return a list of directory removal command string
223 # @param DirList The list of directory to be removed
225 # @retval list The directory removal command list
227 def GetRemoveDirectoryCommand(self, DirList):
228 return [self._RD_TEMPLATE_[self._Platform] % {'dir':Dir} for Dir in DirList]
230 def PlaceMacro(self, Path, MacroDefinitions=None):
231 if Path.startswith("$
("):
234 if MacroDefinitions is None:
235 MacroDefinitions = {}
236 PathLength = len(Path)
237 for MacroName in MacroDefinitions:
238 MacroValue = MacroDefinitions[MacroName]
239 MacroValueLength = len(MacroValue)
240 if MacroValueLength == 0:
242 if MacroValueLength <= PathLength and Path.startswith(MacroValue):
243 Path = "$
(%s)%s" % (MacroName, Path[MacroValueLength:])
247 ## ModuleMakefile class
249 # This class encapsules makefie and its generation for module. It uses template to generate
250 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
252 class ModuleMakefile(BuildFile):
253 ## template used to generate the makefile for module
254 _TEMPLATE_ = TemplateString('''\
258 # Platform Macro Definition
260 PLATFORM_NAME = ${platform_name}
261 PLATFORM_GUID = ${platform_guid}
262 PLATFORM_VERSION = ${platform_version}
263 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
264 PLATFORM_DIR = ${platform_dir}
265 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
268 # Module Macro Definition
270 MODULE_NAME = ${module_name}
271 MODULE_GUID = ${module_guid}
272 MODULE_NAME_GUID = ${module_name_guid}
273 MODULE_VERSION = ${module_version}
274 MODULE_TYPE = ${module_type}
275 MODULE_FILE = ${module_file}
276 MODULE_FILE_BASE_NAME = ${module_file_base_name}
277 BASE_NAME = $(MODULE_NAME)
278 MODULE_RELATIVE_DIR = ${module_relative_directory}
279 PACKAGE_RELATIVE_DIR = ${package_relative_directory}
280 MODULE_DIR = ${module_dir}
281 FFS_OUTPUT_DIR = ${ffs_output_directory}
283 MODULE_ENTRY_POINT = ${module_entry_point}
284 ARCH_ENTRY_POINT = ${arch_entry_point}
285 IMAGE_ENTRY_POINT = ${image_entry_point}
287 ${BEGIN}${module_extra_defines}
290 # Build Configuration Macro Definition
292 ARCH = ${architecture}
293 TOOLCHAIN = ${toolchain_tag}
294 TOOLCHAIN_TAG = ${toolchain_tag}
295 TARGET = ${build_target}
298 # Build Directory Macro Definition
300 # PLATFORM_BUILD_DIR = ${platform_build_directory}
301 BUILD_DIR = ${platform_build_directory}
302 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
304 MODULE_BUILD_DIR = ${module_build_directory}
305 OUTPUT_DIR = ${module_output_directory}
306 DEBUG_DIR = ${module_debug_directory}
307 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
308 DEST_DIR_DEBUG = $(DEBUG_DIR)
311 # Shell Command Macro
313 ${BEGIN}${shell_command_code} = ${shell_command}
317 # Tools definitions specific to this module
319 ${BEGIN}${module_tool_definitions}
321 MAKE_FILE = ${makefile_path}
326 ${BEGIN}${file_macro}
330 # Overridable Target Macro Definitions
332 FORCE_REBUILD = force_build
335 BC_TARGET = ${BEGIN}${backward_compatible_target} ${END}
336 CODA_TARGET = ${BEGIN}${remaining_build_target} \\
340 # Default target, which will build dependent libraries in addition to source files
347 # Target used when called from platform makefile, which will bypass the build of dependent libraries
350 pbuild: $(INIT_TARGET) $(BC_TARGET) $(PCH_TARGET) $(CODA_TARGET)
356 mbuild: $(INIT_TARGET) $(BC_TARGET) gen_libs $(PCH_TARGET) $(CODA_TARGET)
359 # Build Target used in multi-thread build mode, which will bypass the init and gen_libs targets
362 tbuild: $(BC_TARGET) $(PCH_TARGET) $(CODA_TARGET)
365 # Phony target which is used to force executing commands for a target
371 # Target to update the FD
377 # Initialization target: print build information and create necessary directories
382 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
385 ${BEGIN}\t-@${create_directory_command}\n${END}
388 \t-@$(CP) $(DEBUG_DIR)${separator}AutoGen.h $(DEBUG_DIR)${separator}$(MODULE_NAME)StrDefs.h
394 \t${BEGIN}@"$
(MAKE
)" $(MAKE_FLAGS) -f ${dependent_library_build_directory}${separator}${makefile_name}
395 \t${END}@cd $(MODULE_BUILD_DIR)
398 # Build Flash Device Image
401 \t@"$
(MAKE
)" $(MAKE_FLAGS) -f $(BUILD_DIR)${separator}${makefile_name} fds
402 \t@cd $(MODULE_BUILD_DIR)
407 # Individual Object Build Targets
409 ${BEGIN}${file_build_target}
413 # clean all intermediate files
416 \t${BEGIN}${clean_command}
417 \t${END}\t$(RM) AutoGenTimeStamp
420 # clean all generated files
423 ${BEGIN}\t${cleanall_command}
424 ${END}\t$(RM) *.pdb *.idb > NUL 2>&1
425 \t$(RM) $(BIN_DIR)${separator}$(MODULE_NAME).efi
426 \t$(RM) AutoGenTimeStamp
429 # clean all dependent libraries built
432 \t${BEGIN}-@${library_build_command} cleanall
433 \t${END}@cd $(MODULE_BUILD_DIR)\n\n''')
435 _FILE_MACRO_TEMPLATE = TemplateString("${macro_name}
= ${BEGIN}
\\\n ${source_file}${END}
\n")
436 _BUILD_TARGET_TEMPLATE = TemplateString("${BEGIN}${target}
: ${deps}
\n${END}
\t${cmd}
\n")
438 ## Constructor of ModuleMakefile
440 # @param ModuleAutoGen Object of ModuleAutoGen class
442 def __init__(self, ModuleAutoGen):
443 BuildFile.__init__(self, ModuleAutoGen)
444 self.PlatformInfo = self._AutoGenObject.PlatformInfo
446 self.ResultFileList = []
447 self.IntermediateDirectoryList = ["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]
449 self.FileBuildTargetList = [] # [(src, target string)]
450 self.BuildTargetList = [] # [target string]
451 self.PendingBuildTargetList = [] # [FileBuildRule objects]
452 self.CommonFileDependency = []
453 self.FileListMacros = {}
454 self.ListFileMacros = {}
455 self.ObjTargetDict = OrderedDict()
457 self.LibraryBuildCommandList = []
458 self.LibraryFileList = []
459 self.LibraryMakefileList = []
460 self.LibraryBuildDirectoryList = []
461 self.SystemLibraryList = []
462 self.Macros = OrderedDict()
463 self.Macros["OUTPUT_DIR
" ] = self._AutoGenObject.Macros["OUTPUT_DIR
"]
464 self.Macros["DEBUG_DIR
" ] = self._AutoGenObject.Macros["DEBUG_DIR
"]
465 self.Macros["MODULE_BUILD_DIR
"] = self._AutoGenObject.Macros["MODULE_BUILD_DIR
"]
466 self.Macros["BIN_DIR
" ] = self._AutoGenObject.Macros["BIN_DIR
"]
467 self.Macros["BUILD_DIR
" ] = self._AutoGenObject.Macros["BUILD_DIR
"]
468 self.Macros["WORKSPACE
" ] = self._AutoGenObject.Macros["WORKSPACE
"]
469 self.Macros["FFS_OUTPUT_DIR
" ] = self._AutoGenObject.Macros["FFS_OUTPUT_DIR
"]
470 self.GenFfsList = ModuleAutoGen.GenFfsList
471 self.MacroList = ['FFS_OUTPUT_DIR', 'MODULE_GUID', 'OUTPUT_DIR']
472 self.FfsOutputFileList = []
473 self.DependencyHeaderFileSet = set()
475 # Compose a dict object containing information used to do replacement in template
477 def _TemplateDict(self):
478 MyAgo = self._AutoGenObject
479 Separator = self._SEP_[self._Platform]
481 # break build if no source files and binary files are found
482 if len(MyAgo.SourceFileList) == 0 and len(MyAgo.BinaryFileList) == 0:
483 EdkLogger.error("build
", AUTOGEN_ERROR, "No files to be built
in module
[%s, %s, %s]"
484 % (MyAgo.BuildTarget, MyAgo.ToolChain, MyAgo.Arch),
485 ExtraData="[%s]" % str(MyAgo))
487 # convert dependent libraries to build command
488 self.ProcessDependentLibrary()
489 if len(MyAgo.Module.ModuleEntryPointList) > 0:
490 ModuleEntryPoint = MyAgo.Module.ModuleEntryPointList[0]
492 ModuleEntryPoint = "_ModuleEntryPoint
"
494 ArchEntryPoint = ModuleEntryPoint
496 if MyAgo.Arch == "EBC
":
497 # EBC compiler always use "EfiStart
" as entry point. Only applies to EdkII modules
498 ImageEntryPoint = "EfiStart
"
500 # EdkII modules always use "_ModuleEntryPoint
" as entry point
501 ImageEntryPoint = "_ModuleEntryPoint
"
503 for k, v in MyAgo.Module.Defines.items():
504 if k not in MyAgo.Macros:
507 if 'MODULE_ENTRY_POINT' not in MyAgo.Macros:
508 MyAgo.Macros['MODULE_ENTRY_POINT'] = ModuleEntryPoint
509 if 'ARCH_ENTRY_POINT' not in MyAgo.Macros:
510 MyAgo.Macros['ARCH_ENTRY_POINT'] = ArchEntryPoint
511 if 'IMAGE_ENTRY_POINT' not in MyAgo.Macros:
512 MyAgo.Macros['IMAGE_ENTRY_POINT'] = ImageEntryPoint
514 PCI_COMPRESS_Flag = False
515 for k, v in MyAgo.Module.Defines.items():
516 if 'PCI_COMPRESS' == k and 'TRUE' == v:
517 PCI_COMPRESS_Flag = True
521 IncPrefix = self._INC_FLAG_[MyAgo.ToolChainFamily]
522 for Tool in MyAgo.BuildOption:
523 for Attr in MyAgo.BuildOption[Tool]:
524 Value = MyAgo.BuildOption[Tool][Attr]
528 ToolsDef.append("%s = %s" % (Tool, Value))
530 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
533 # Remove duplicated include path, if any
535 Value = RemoveDupOption(Value, IncPrefix, MyAgo.IncludePathList)
536 if Tool == "OPTROM
" and PCI_COMPRESS_Flag:
537 ValueList = Value.split()
539 for i, v in enumerate(ValueList):
542 Value = ' '.join(ValueList)
544 ToolsDef.append("%s_%s = %s" % (Tool, Attr, Value))
547 # generate the Response file and Response flag
548 RespDict = self.CommandExceedLimit()
549 RespFileList = os.path.join(MyAgo.OutputDir, 'respfilelist.txt')
551 RespFileListContent = ''
552 for Resp in RespDict:
553 RespFile = os.path.join(MyAgo.OutputDir, str(Resp).lower() + '.txt')
554 StrList = RespDict[Resp].split(' ')
558 if '$' in Str or '-MMD' in Str or '-MF' in Str:
559 UnexpandMacro.append(Str)
562 UnexpandMacroStr = ' '.join(UnexpandMacro)
563 NewRespStr = ' '.join(NewStr)
564 SaveFileOnChange(RespFile, NewRespStr, False)
565 ToolsDef.append("%s = %s" % (Resp, UnexpandMacroStr + ' @' + RespFile))
566 RespFileListContent += '@' + RespFile + TAB_LINE_BREAK
567 RespFileListContent += NewRespStr + TAB_LINE_BREAK
568 SaveFileOnChange(RespFileList, RespFileListContent, False)
570 if os.path.exists(RespFileList):
571 os.remove(RespFileList)
573 # convert source files and binary files to build targets
574 self.ResultFileList = [str(T.Target) for T in MyAgo.CodaTargetList]
575 if len(self.ResultFileList) == 0 and len(MyAgo.SourceFileList) != 0:
576 EdkLogger.error("build
", AUTOGEN_ERROR, "Nothing to build
",
577 ExtraData="[%s]" % str(MyAgo))
579 self.ProcessBuildTargetList()
580 self.ParserGenerateFfsCmd()
582 # Generate macros used to represent input files
583 FileMacroList = [] # macro name = file list
584 for FileListMacro in self.FileListMacros:
585 FileMacro = self._FILE_MACRO_TEMPLATE.Replace(
587 "macro_name
" : FileListMacro,
588 "source_file
" : self.FileListMacros[FileListMacro]
591 FileMacroList.append(FileMacro)
593 # INC_LIST is special
596 for P in MyAgo.IncludePathList:
597 IncludePathList.append(IncPrefix + self.PlaceMacro(P, self.Macros))
598 if FileBuildRule.INC_LIST_MACRO in self.ListFileMacros:
599 self.ListFileMacros[FileBuildRule.INC_LIST_MACRO].append(IncPrefix + P)
600 FileMacro += self._FILE_MACRO_TEMPLATE.Replace(
602 "macro_name
" : "INC
",
603 "source_file
" : IncludePathList
606 FileMacroList.append(FileMacro)
607 # Add support when compiling .nasm source files
609 asmsource = [item for item in MyAgo.SourceFileList if item.File.upper().endswith((".NASM
",".ASM
",".NASMB
","S
"))]
611 for P in MyAgo.IncludePathList:
612 IncludePath = self._INC_FLAG_['NASM'] + self.PlaceMacro(P, self.Macros)
613 if IncludePath.endswith(os.sep):
614 IncludePath = IncludePath.rstrip(os.sep)
615 # When compiling .nasm files, need to add a literal backslash at each path.
616 # In nmake makfiles, a trailing literal backslash must be escaped with a caret ('^').
617 # It is otherwise replaced with a space (' '). This is not necessary for GNU makfefiles.
618 if P == MyAgo.IncludePathList[-1] and self._Platform == WIN32_PLATFORM and self._FileType == NMAKE_FILETYPE:
619 IncludePath = ''.join([IncludePath, '^', os.sep])
621 IncludePath = os.path.join(IncludePath, '')
622 IncludePathList.append(IncludePath)
623 FileMacroList.append(self._FILE_MACRO_TEMPLATE.Replace({"macro_name
": "NASM_INC
", "source_file
": IncludePathList}))
625 # Generate macros used to represent files containing list of input files
626 for ListFileMacro in self.ListFileMacros:
627 ListFileName = os.path.join(MyAgo.OutputDir, "%s.lst
" % ListFileMacro.lower()[:len(ListFileMacro) - 5])
628 FileMacroList.append("%s = %s" % (ListFileMacro, ListFileName))
631 "\n".join(self.ListFileMacros[ListFileMacro]),
635 # Generate objlist used to create .obj file
636 for Type in self.ObjTargetDict:
637 NewLine = ' '.join(list(self.ObjTargetDict[Type]))
638 FileMacroList.append("OBJLIST_
%s = %s" % (list(self.ObjTargetDict.keys()).index(Type), NewLine))
642 MakefileName = self.getMakefileName()
643 LibraryMakeCommandList = []
644 for D in self.LibraryBuildDirectoryList:
645 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":os.path.join(D, MakefileName)}
646 LibraryMakeCommandList.append(Command)
648 package_rel_dir = MyAgo.SourceDir
649 current_dir = self.Macros["WORKSPACE
"]
651 while not found and os.sep in package_rel_dir:
652 index = package_rel_dir.index(os.sep)
653 current_dir = mws.join(current_dir, package_rel_dir[:index])
654 if os.path.exists(current_dir):
655 for fl in os.listdir(current_dir):
656 if fl.endswith('.dec'):
659 package_rel_dir = package_rel_dir[index + 1:]
661 MakefileTemplateDict = {
662 "makefile_header
" : self._FILE_HEADER_[self._FileType],
663 "makefile_path
" : os.path.join("$
(MODULE_BUILD_DIR
)", MakefileName),
664 "makefile_name
" : MakefileName,
665 "platform_name
" : self.PlatformInfo.Name,
666 "platform_guid
" : self.PlatformInfo.Guid,
667 "platform_version
" : self.PlatformInfo.Version,
668 "platform_relative_directory
": self.PlatformInfo.SourceDir,
669 "platform_output_directory
" : self.PlatformInfo.OutputDir,
670 "ffs_output_directory
" : MyAgo.Macros["FFS_OUTPUT_DIR
"],
671 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
673 "module_name
" : MyAgo.Name,
674 "module_guid
" : MyAgo.Guid,
675 "module_name_guid
" : MyAgo.UniqueBaseName,
676 "module_version
" : MyAgo.Version,
677 "module_type
" : MyAgo.ModuleType,
678 "module_file
" : MyAgo.MetaFile.Name,
679 "module_file_base_name
" : MyAgo.MetaFile.BaseName,
680 "module_relative_directory
" : MyAgo.SourceDir,
681 "module_dir
" : mws.join (self.Macros["WORKSPACE
"], MyAgo.SourceDir),
682 "package_relative_directory
": package_rel_dir,
683 "module_extra_defines
" : ["%s = %s" % (k, v) for k, v in MyAgo.Module.Defines.items()],
685 "architecture
" : MyAgo.Arch,
686 "toolchain_tag
" : MyAgo.ToolChain,
687 "build_target
" : MyAgo.BuildTarget,
689 "platform_build_directory
" : self.PlatformInfo.BuildDir,
690 "module_build_directory
" : MyAgo.BuildDir,
691 "module_output_directory
" : MyAgo.OutputDir,
692 "module_debug_directory
" : MyAgo.DebugDir,
694 "separator
" : Separator,
695 "module_tool_definitions
" : ToolsDef,
697 "shell_command_code
" : list(self._SHELL_CMD_[self._Platform].keys()),
698 "shell_command
" : list(self._SHELL_CMD_[self._Platform].values()),
700 "module_entry_point
" : ModuleEntryPoint,
701 "image_entry_point
" : ImageEntryPoint,
702 "arch_entry_point
" : ArchEntryPoint,
703 "remaining_build_target
" : self.ResultFileList,
704 "common_dependency_file
" : self.CommonFileDependency,
705 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
706 "clean_command
" : self.GetRemoveDirectoryCommand(["$
(OUTPUT_DIR
)"]),
707 "cleanall_command
" : self.GetRemoveDirectoryCommand(["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]),
708 "dependent_library_build_directory
" : self.LibraryBuildDirectoryList,
709 "library_build_command
" : LibraryMakeCommandList,
710 "file_macro
" : FileMacroList,
711 "file_build_target
" : self.BuildTargetList,
712 "backward_compatible_target
": BcTargetList,
713 "INCLUDETAG
" : "\n".join([self._INCLUDE_CMD_[self._FileType] + " " + os.path.join("$
(MODULE_BUILD_DIR
)","dependency
"),
714 self._INCLUDE_CMD_[self._FileType] + " " + os.path.join("$
(MODULE_BUILD_DIR
)","deps_target
")
718 return MakefileTemplateDict
720 def ParserGenerateFfsCmd(self):
721 #Add Ffs cmd to self.BuildTargetList
725 for Cmd in self.GenFfsList:
727 for CopyCmd in Cmd[2]:
729 Src = self.ReplaceMacro(Src)
730 Dst = self.ReplaceMacro(Dst)
731 if Dst not in self.ResultFileList:
732 self.ResultFileList.append(Dst)
733 if '%s :' %(Dst) not in self.BuildTargetList:
734 self.BuildTargetList.append("%s : %s" %(Dst,Src))
735 self.BuildTargetList.append('\t' + self._CP_TEMPLATE_[self._Platform] %{'Src': Src, 'Dst': Dst})
738 for index, Str in enumerate(FfsCmdList):
740 OutputFile = FfsCmdList[index + 1]
741 if '-i' == Str or "-oi
" == Str:
742 if DepsFileList == []:
743 DepsFileList = [FfsCmdList[index + 1]]
745 DepsFileList.append(FfsCmdList[index + 1])
746 DepsFileString = ' '.join(DepsFileList).strip()
747 if DepsFileString == '':
749 OutputFile = self.ReplaceMacro(OutputFile)
750 self.ResultFileList.append(OutputFile)
751 DepsFileString = self.ReplaceMacro(DepsFileString)
752 self.BuildTargetList.append('%s : %s' % (OutputFile, DepsFileString))
753 CmdString = ' '.join(FfsCmdList).strip()
754 CmdString = self.ReplaceMacro(CmdString)
755 self.BuildTargetList.append('\t%s' % CmdString)
757 self.ParseSecCmd(DepsFileList, Cmd[1])
758 for SecOutputFile, SecDepsFile, SecCmd in self.FfsOutputFileList :
759 self.BuildTargetList.append('%s : %s' % (self.ReplaceMacro(SecOutputFile), self.ReplaceMacro(SecDepsFile)))
760 self.BuildTargetList.append('\t%s' % self.ReplaceMacro(SecCmd))
761 self.FfsOutputFileList = []
763 def ParseSecCmd(self, OutputFileList, CmdTuple):
764 for OutputFile in OutputFileList:
765 for SecCmdStr in CmdTuple:
767 SecCmdList = SecCmdStr.split()
768 CmdName = SecCmdList[0]
769 for index, CmdItem in enumerate(SecCmdList):
770 if '-o' == CmdItem and OutputFile == SecCmdList[index + 1]:
772 while index + 1 < len(SecCmdList):
773 if not SecCmdList[index+1].startswith('-'):
774 SecDepsFileList.append(SecCmdList[index + 1])
776 if CmdName == 'Trim':
777 SecDepsFileList.append(os.path.join('$(DEBUG_DIR)', os.path.basename(OutputFile).replace('offset', 'efi')))
778 if OutputFile.endswith('.ui') or OutputFile.endswith('.ver'):
779 SecDepsFileList.append(os.path.join('$(MODULE_DIR)', '$(MODULE_FILE)'))
780 self.FfsOutputFileList.append((OutputFile, ' '.join(SecDepsFileList), SecCmdStr))
781 if len(SecDepsFileList) > 0:
782 self.ParseSecCmd(SecDepsFileList, CmdTuple)
787 def ReplaceMacro(self, str):
788 for Macro in self.MacroList:
789 if self._AutoGenObject.Macros[Macro] and self._AutoGenObject.Macros[Macro] in str:
790 str = str.replace(self._AutoGenObject.Macros[Macro], '$(' + Macro + ')')
793 def CommandExceedLimit(self):
795 'CC' : { 'Macro' : '$(CC_FLAGS)', 'Value' : False},
796 'PP' : { 'Macro' : '$(PP_FLAGS)', 'Value' : False},
797 'APP' : { 'Macro' : '$(APP_FLAGS)', 'Value' : False},
798 'ASLPP' : { 'Macro' : '$(ASLPP_FLAGS)', 'Value' : False},
799 'VFRPP' : { 'Macro' : '$(VFRPP_FLAGS)', 'Value' : False},
800 'ASM' : { 'Macro' : '$(ASM_FLAGS)', 'Value' : False},
801 'ASLCC' : { 'Macro' : '$(ASLCC_FLAGS)', 'Value' : False},
806 IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily]
808 # base on the source files to decide the file type
809 for File in self._AutoGenObject.SourceFileList:
810 for type in self._AutoGenObject.FileTypes:
811 if File in self._AutoGenObject.FileTypes[type]:
812 if type not in FileTypeList:
813 FileTypeList.append(type)
815 # calculate the command-line length
817 for type in FileTypeList:
818 BuildTargets = self._AutoGenObject.BuildRules[type].BuildTargets
819 for Target in BuildTargets:
820 CommandList = BuildTargets[Target].Commands
821 for SingleCommand in CommandList:
823 SingleCommandLength = len(SingleCommand)
824 SingleCommandList = SingleCommand.split()
825 if len(SingleCommandList) > 0:
826 for Flag in FlagDict:
827 if '$('+ Flag +')' in SingleCommandList[0]:
831 if 'PATH' not in self._AutoGenObject.BuildOption[Tool]:
832 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))
833 SingleCommandLength += len(self._AutoGenObject.BuildOption[Tool]['PATH
'])
834 for item in SingleCommandList[1:]:
835 if FlagDict[Tool]['Macro
'] in item:
836 if 'FLAGS
' not in self._AutoGenObject.BuildOption[Tool]:
837 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))
838 Str = self._AutoGenObject.BuildOption[Tool]['FLAGS']
839 for Option in self._AutoGenObject.BuildOption:
840 for Attr in self._AutoGenObject.BuildOption[Option]:
841 if Str.find(Option + '_' + Attr) != -1:
842 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
843 while(Str.find('$(') != -1):
844 for macro in self._AutoGenObject.Macros:
845 MacroName = '$('+ macro + ')'
846 if (Str.find(MacroName) != -1):
847 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
851 SingleCommandLength += len(Str)
852 elif '$(INC)' in item:
853 SingleCommandLength += self._AutoGenObject.IncludePathLength + len(IncPrefix) * len(self._AutoGenObject.IncludePathList)
854 elif item.find('$(') != -1:
856 for Option in self._AutoGenObject.BuildOption:
857 for Attr in self._AutoGenObject.BuildOption[Option]:
858 if Str.find(Option + '_' + Attr) != -1:
859 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
860 while(Str.find('$(') != -1):
861 for macro in self._AutoGenObject.Macros:
862 MacroName = '$('+ macro + ')'
863 if (Str.find(MacroName) != -1):
864 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
868 SingleCommandLength += len(Str)
870 if SingleCommandLength > GlobalData.gCommandMaxLength:
871 FlagDict[Tool]['Value'] = True
873 # generate the response file content by combine the FLAGS and INC
874 for Flag in FlagDict:
875 if FlagDict[Flag]['Value']:
877 RespMacro = FlagDict[Flag]['Macro'].replace('FLAGS', 'RESP')
878 Value = self._AutoGenObject.BuildOption[Flag]['FLAGS']
879 for inc in self._AutoGenObject.IncludePathList:
880 Value += ' ' + IncPrefix + inc
881 for Option in self._AutoGenObject.BuildOption:
882 for Attr in self._AutoGenObject.BuildOption[Option]:
883 if Value.find(Option + '_' + Attr) != -1:
884 Value = Value.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
885 while (Value.find('$(') != -1):
886 for macro in self._AutoGenObject.Macros:
887 MacroName = '$('+ macro + ')'
888 if (Value.find(MacroName) != -1):
889 Value = Value.replace(MacroName, self._AutoGenObject.Macros[macro])
894 if self._AutoGenObject.ToolChainFamily == 'GCC':
895 RespDict[Key] = Value.replace('\\', '/')
897 RespDict[Key] = Value
898 for Target in BuildTargets:
899 for i, SingleCommand in enumerate(BuildTargets[Target].Commands):
900 if FlagDict[Flag]['Macro'] in SingleCommand:
901 BuildTargets[Target].Commands[i] = SingleCommand.replace('$(INC)', '').replace(FlagDict[Flag]['Macro'], RespMacro)
904 def ProcessBuildTargetList(self):
906 # Search dependency file list for each source file
908 ForceIncludedFile = []
909 for File in self._AutoGenObject.AutoGenFileList:
911 ForceIncludedFile.append(File)
914 for Target in self._AutoGenObject.IntroTargetList:
915 SourceFileList.extend(Target.Inputs)
916 OutPutFileList.extend(Target.Outputs)
919 for Item in OutPutFileList:
920 if Item in SourceFileList:
921 SourceFileList.remove(Item)
923 FileDependencyDict = {item:ForceIncludedFile for item in SourceFileList}
925 for Dependency in FileDependencyDict.values():
926 self.DependencyHeaderFileSet.update(set(Dependency))
928 # Get a set of unique package includes from MetaFile
929 parentMetaFileIncludes = set()
930 for aInclude in self._AutoGenObject.PackageIncludePathList:
931 aIncludeName = str(aInclude)
932 parentMetaFileIncludes.add(aIncludeName.lower())
934 # Check if header files are listed in metafile
935 # Get a set of unique module header source files from MetaFile
936 headerFilesInMetaFileSet = set()
937 for aFile in self._AutoGenObject.SourceFileList:
938 aFileName = str(aFile)
939 if not aFileName.endswith('.h'):
941 headerFilesInMetaFileSet.add(aFileName.lower())
943 # Get a set of unique module autogen files
944 localAutoGenFileSet = set()
945 for aFile in self._AutoGenObject.AutoGenFileList:
946 localAutoGenFileSet.add(str(aFile).lower())
948 # Get a set of unique module dependency header files
949 # Exclude autogen files and files not in the source directory
950 # and files that are under the package include list
951 headerFileDependencySet = set()
952 localSourceDir = str(self._AutoGenObject.SourceDir).lower()
953 for Dependency in FileDependencyDict.values():
954 for aFile in Dependency:
955 aFileName = str(aFile).lower()
956 # Exclude non-header files
957 if not aFileName.endswith('.h'):
959 # Exclude autogen files
960 if aFileName in localAutoGenFileSet:
962 # Exclude include out of local scope
963 if localSourceDir not in aFileName:
965 # Exclude files covered by package includes
967 for aIncludePath in parentMetaFileIncludes:
968 if aIncludePath in aFileName:
973 # Keep the file to be checked
974 headerFileDependencySet.add(aFileName)
976 # Check if a module dependency header file is missing from the module's MetaFile
977 for aFile in headerFileDependencySet:
978 if aFile in headerFilesInMetaFileSet:
980 if GlobalData.gUseHashCache:
981 GlobalData.gModuleBuildTracking[self._AutoGenObject] = 'FAIL_METAFILE'
982 EdkLogger.warn("build
","Module MetaFile
[Sources
] is missing local header
!",
983 ExtraData = "Local Header
: " + aFile + " not found
in " + self._AutoGenObject.MetaFile.Path
986 for File,Dependency in FileDependencyDict.items():
990 self._AutoGenObject.AutoGenDepSet |= set(Dependency)
995 DependencyDict = FileDependencyDict.copy()
997 # Convert target description object to target string in makefile
998 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and TAB_C_CODE_FILE in self._AutoGenObject.Targets:
999 for T in self._AutoGenObject.Targets[TAB_C_CODE_FILE]:
1000 NewFile = self.PlaceMacro(str(T), self.Macros)
1001 if not self.ObjTargetDict.get(T.Target.SubDir):
1002 self.ObjTargetDict[T.Target.SubDir] = set()
1003 self.ObjTargetDict[T.Target.SubDir].add(NewFile)
1004 for Type in self._AutoGenObject.Targets:
1005 for T in self._AutoGenObject.Targets[Type]:
1006 # Generate related macros if needed
1007 if T.GenFileListMacro and T.FileListMacro not in self.FileListMacros:
1008 self.FileListMacros[T.FileListMacro] = []
1009 if T.GenListFile and T.ListFileMacro not in self.ListFileMacros:
1010 self.ListFileMacros[T.ListFileMacro] = []
1011 if T.GenIncListFile and T.IncListFileMacro not in self.ListFileMacros:
1012 self.ListFileMacros[T.IncListFileMacro] = []
1016 # Add force-dependencies
1017 for Dep in T.Dependencies:
1018 Deps.append(self.PlaceMacro(str(Dep), self.Macros))
1019 if Dep != '$(MAKE_FILE)':
1020 CCodeDeps.append(self.PlaceMacro(str(Dep), self.Macros))
1021 # Add inclusion-dependencies
1022 if len(T.Inputs) == 1 and T.Inputs[0] in FileDependencyDict:
1023 for F in FileDependencyDict[T.Inputs[0]]:
1024 Deps.append(self.PlaceMacro(str(F), self.Macros))
1025 # Add source-dependencies
1027 NewFile = self.PlaceMacro(str(F), self.Macros)
1028 # In order to use file list macro as dependency
1030 # gnu tools need forward slash path separator, even on Windows
1031 self.ListFileMacros[T.ListFileMacro].append(str(F).replace ('\\', '/'))
1032 self.FileListMacros[T.FileListMacro].append(NewFile)
1033 elif T.GenFileListMacro:
1034 self.FileListMacros[T.FileListMacro].append(NewFile)
1036 Deps.append(NewFile)
1037 for key in self.FileListMacros:
1038 self.FileListMacros[key].sort()
1039 # Use file list macro as dependency
1040 if T.GenFileListMacro:
1041 Deps.append("$
(%s)" % T.FileListMacro)
1042 if Type in [TAB_OBJECT_FILE, TAB_STATIC_LIBRARY]:
1043 Deps.append("$
(%s)" % T.ListFileMacro)
1045 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Type == TAB_C_CODE_FILE:
1046 T, CmdTarget, CmdTargetDict, CmdCppDict = self.ParserCCodeFile(T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict)
1047 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": CCodeDeps}
1048 CmdLine = self._BUILD_TARGET_TEMPLATE.Replace(TargetDict).rstrip().replace('\t$(OBJLIST', '$(OBJLIST')
1050 CmdLine = '%s%s' %(CmdLine, TAB_LINE_BREAK)
1051 if CCodeDeps or CmdLine:
1052 self.BuildTargetList.append(CmdLine)
1054 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": Deps}
1055 self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(TargetDict))
1057 def ParserCCodeFile(self, T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict):
1059 for item in self._AutoGenObject.Targets[Type]:
1060 CmdSumDict[item.Target.SubDir] = item.Target.BaseName
1061 for CppPath in item.Inputs:
1062 Path = self.PlaceMacro(CppPath.Path, self.Macros)
1063 if CmdCppDict.get(item.Target.SubDir):
1064 CmdCppDict[item.Target.SubDir].append(Path)
1066 CmdCppDict[item.Target.SubDir] = ['$(MAKE_FILE)', Path]
1067 if CppPath.Path in DependencyDict:
1068 for Temp in DependencyDict[CppPath.Path]:
1070 Path = self.PlaceMacro(Temp.Path, self.Macros)
1073 if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):
1074 CmdCppDict[item.Target.SubDir].append(Path)
1076 CommandList = T.Commands[:]
1077 for Item in CommandList[:]:
1078 SingleCommandList = Item.split()
1079 if len(SingleCommandList) > 0 and self.CheckCCCmd(SingleCommandList):
1080 for Temp in SingleCommandList:
1081 if Temp.startswith('/Fo'):
1082 CmdSign = '%s%s' % (Temp.rsplit(TAB_SLASH, 1)[0], TAB_SLASH)
1085 if CmdSign not in list(CmdTargetDict.keys()):
1086 CmdTargetDict[CmdSign] = Item.replace(Temp, CmdSign)
1088 CmdTargetDict[CmdSign] = "%s %s" % (CmdTargetDict[CmdSign], SingleCommandList[-1])
1089 Index = CommandList.index(Item)
1090 CommandList.pop(Index)
1091 if SingleCommandList[-1].endswith("%s%s.c
" % (TAB_SLASH, CmdSumDict[CmdSign[3:].rsplit(TAB_SLASH, 1)[0]])):
1092 Cpplist = CmdCppDict[T.Target.SubDir]
1093 Cpplist.insert(0, '$(OBJLIST_%d): ' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir))
1094 T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign])
1096 T.Commands.pop(Index)
1097 return T, CmdSumDict, CmdTargetDict, CmdCppDict
1099 def CheckCCCmd(self, CommandList):
1100 for cmd in CommandList:
1104 ## For creating makefile targets for dependent libraries
1105 def ProcessDependentLibrary(self):
1106 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1107 if not LibraryAutoGen.IsBinaryModule:
1108 self.LibraryBuildDirectoryList.append(self.PlaceMacro(LibraryAutoGen.BuildDir, self.Macros))
1110 ## Return a list containing source file's dependencies
1112 # @param FileList The list of source files
1113 # @param ForceInculeList The list of files which will be included forcely
1114 # @param SearchPathList The list of search path
1116 # @retval dict The mapping between source file path and its dependencies
1118 def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):
1121 Dependency[F] = GetDependencyList(self._AutoGenObject, self.FileCache, F, ForceInculeList, SearchPathList)
1125 ## CustomMakefile class
1127 # This class encapsules makefie and its generation for module. It uses template to generate
1128 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
1130 class CustomMakefile(BuildFile):
1131 ## template used to generate the makefile for module with custom makefile
1132 _TEMPLATE_ = TemplateString('''\
1136 # Platform Macro Definition
1138 PLATFORM_NAME = ${platform_name}
1139 PLATFORM_GUID = ${platform_guid}
1140 PLATFORM_VERSION = ${platform_version}
1141 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
1142 PLATFORM_DIR = ${platform_dir}
1143 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1146 # Module Macro Definition
1148 MODULE_NAME = ${module_name}
1149 MODULE_GUID = ${module_guid}
1150 MODULE_NAME_GUID = ${module_name_guid}
1151 MODULE_VERSION = ${module_version}
1152 MODULE_TYPE = ${module_type}
1153 MODULE_FILE = ${module_file}
1154 MODULE_FILE_BASE_NAME = ${module_file_base_name}
1155 BASE_NAME = $(MODULE_NAME)
1156 MODULE_RELATIVE_DIR = ${module_relative_directory}
1157 MODULE_DIR = ${module_dir}
1160 # Build Configuration Macro Definition
1162 ARCH = ${architecture}
1163 TOOLCHAIN = ${toolchain_tag}
1164 TOOLCHAIN_TAG = ${toolchain_tag}
1165 TARGET = ${build_target}
1168 # Build Directory Macro Definition
1170 # PLATFORM_BUILD_DIR = ${platform_build_directory}
1171 BUILD_DIR = ${platform_build_directory}
1172 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
1173 LIB_DIR = $(BIN_DIR)
1174 MODULE_BUILD_DIR = ${module_build_directory}
1175 OUTPUT_DIR = ${module_output_directory}
1176 DEBUG_DIR = ${module_debug_directory}
1177 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
1178 DEST_DIR_DEBUG = $(DEBUG_DIR)
1181 # Tools definitions specific to this module
1183 ${BEGIN}${module_tool_definitions}
1185 MAKE_FILE = ${makefile_path}
1188 # Shell Command Macro
1190 ${BEGIN}${shell_command_code} = ${shell_command}
1193 ${custom_makefile_content}
1196 # Target used when called from platform makefile, which will bypass the build of dependent libraries
1209 # Build Target used in multi-thread build mode, which no init target is needed
1215 # Initialization target: print build information and create necessary directories
1218 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
1219 ${BEGIN}\t-@${create_directory_command}\n${END}\
1223 ## Constructor of CustomMakefile
1225 # @param ModuleAutoGen Object of ModuleAutoGen class
1227 def __init__(self, ModuleAutoGen):
1228 BuildFile.__init__(self, ModuleAutoGen)
1229 self.PlatformInfo = self._AutoGenObject.PlatformInfo
1230 self.IntermediateDirectoryList = ["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]
1231 self.DependencyHeaderFileSet = set()
1233 # Compose a dict object containing information used to do replacement in template
1235 def _TemplateDict(self):
1236 Separator = self._SEP_[self._Platform]
1237 MyAgo = self._AutoGenObject
1238 if self._FileType not in MyAgo.CustomMakefile:
1239 EdkLogger.error('build', OPTION_NOT_SUPPORTED, "No custom makefile
for %s" % self._FileType,
1240 ExtraData="[%s]" % str(MyAgo))
1241 MakefilePath = mws.join(
1243 MyAgo.CustomMakefile[self._FileType]
1246 CustomMakefile = open(MakefilePath, 'r').read()
1248 EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(MyAgo),
1249 ExtraData=MyAgo.CustomMakefile[self._FileType])
1253 for Tool in MyAgo.BuildOption:
1254 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
1257 for Attr in MyAgo.BuildOption[Tool]:
1258 if Attr == "FAMILY
":
1260 elif Attr == "PATH
":
1261 ToolsDef.append("%s = %s" % (Tool, MyAgo.BuildOption[Tool][Attr]))
1263 ToolsDef.append("%s_%s = %s" % (Tool, Attr, MyAgo.BuildOption[Tool][Attr]))
1266 MakefileName = self.getMakefileName()
1267 MakefileTemplateDict = {
1268 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1269 "makefile_path
" : os.path.join("$
(MODULE_BUILD_DIR
)", MakefileName),
1270 "platform_name
" : self.PlatformInfo.Name,
1271 "platform_guid
" : self.PlatformInfo.Guid,
1272 "platform_version
" : self.PlatformInfo.Version,
1273 "platform_relative_directory
": self.PlatformInfo.SourceDir,
1274 "platform_output_directory
" : self.PlatformInfo.OutputDir,
1275 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1277 "module_name
" : MyAgo.Name,
1278 "module_guid
" : MyAgo.Guid,
1279 "module_name_guid
" : MyAgo.UniqueBaseName,
1280 "module_version
" : MyAgo.Version,
1281 "module_type
" : MyAgo.ModuleType,
1282 "module_file
" : MyAgo.MetaFile,
1283 "module_file_base_name
" : MyAgo.MetaFile.BaseName,
1284 "module_relative_directory
" : MyAgo.SourceDir,
1285 "module_dir
" : mws.join (MyAgo.WorkspaceDir, MyAgo.SourceDir),
1287 "architecture
" : MyAgo.Arch,
1288 "toolchain_tag
" : MyAgo.ToolChain,
1289 "build_target
" : MyAgo.BuildTarget,
1291 "platform_build_directory
" : self.PlatformInfo.BuildDir,
1292 "module_build_directory
" : MyAgo.BuildDir,
1293 "module_output_directory
" : MyAgo.OutputDir,
1294 "module_debug_directory
" : MyAgo.DebugDir,
1296 "separator
" : Separator,
1297 "module_tool_definitions
" : ToolsDef,
1299 "shell_command_code
" : list(self._SHELL_CMD_[self._Platform].keys()),
1300 "shell_command
" : list(self._SHELL_CMD_[self._Platform].values()),
1302 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1303 "custom_makefile_content
" : CustomMakefile
1306 return MakefileTemplateDict
1308 ## PlatformMakefile class
1310 # This class encapsules makefie and its generation for platform. It uses
1311 # template to generate the content of makefile. The content of makefile will be
1312 # got from PlatformAutoGen object.
1314 class PlatformMakefile(BuildFile):
1315 ## template used to generate the makefile for platform
1316 _TEMPLATE_ = TemplateString('''\
1320 # Platform Macro Definition
1322 PLATFORM_NAME = ${platform_name}
1323 PLATFORM_GUID = ${platform_guid}
1324 PLATFORM_VERSION = ${platform_version}
1325 PLATFORM_FILE = ${platform_file}
1326 PLATFORM_DIR = ${platform_dir}
1327 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1330 # Build Configuration Macro Definition
1332 TOOLCHAIN = ${toolchain_tag}
1333 TOOLCHAIN_TAG = ${toolchain_tag}
1334 TARGET = ${build_target}
1337 # Build Directory Macro Definition
1339 BUILD_DIR = ${platform_build_directory}
1340 FV_DIR = ${platform_build_directory}${separator}FV
1343 # Shell Command Macro
1345 ${BEGIN}${shell_command_code} = ${shell_command}
1349 MAKE_FILE = ${makefile_path}
1354 all: init build_libraries build_modules
1357 # Initialization target: print build information and create necessary directories
1360 \t-@echo Building ... $(PLATFORM_FILE) [${build_architecture_list}]
1361 \t${BEGIN}-@${create_directory_command}
1364 # library build target
1366 libraries: init build_libraries
1369 # module build target
1371 modules: init build_libraries build_modules
1374 # Build all libraries:
1377 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${library_makefile_list} pbuild
1378 ${END}\t@cd $(BUILD_DIR)
1381 # Build all modules:
1384 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${module_makefile_list} pbuild
1385 ${END}\t@cd $(BUILD_DIR)
1388 # Clean intermediate files
1391 \t${BEGIN}-@${library_build_command} clean
1392 \t${END}${BEGIN}-@${module_build_command} clean
1393 \t${END}@cd $(BUILD_DIR)
1396 # Clean all generated files except to makefile
1399 ${BEGIN}\t${cleanall_command}
1403 # Clean all library files
1406 \t${BEGIN}-@${library_build_command} cleanall
1407 \t${END}@cd $(BUILD_DIR)\n
1410 ## Constructor of PlatformMakefile
1412 # @param ModuleAutoGen Object of PlatformAutoGen class
1414 def __init__(self, PlatformAutoGen):
1415 BuildFile.__init__(self, PlatformAutoGen)
1416 self.ModuleBuildCommandList = []
1417 self.ModuleMakefileList = []
1418 self.IntermediateDirectoryList = []
1419 self.ModuleBuildDirectoryList = []
1420 self.LibraryBuildDirectoryList = []
1421 self.LibraryMakeCommandList = []
1422 self.DependencyHeaderFileSet = set()
1424 # Compose a dict object containing information used to do replacement in template
1426 def _TemplateDict(self):
1427 Separator = self._SEP_[self._Platform]
1429 MyAgo = self._AutoGenObject
1430 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1431 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1432 ExtraData="[%s]" % str(MyAgo))
1434 self.IntermediateDirectoryList = ["$
(BUILD_DIR
)"]
1435 self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()
1436 self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()
1438 MakefileName = self.getMakefileName()
1439 LibraryMakefileList = []
1440 LibraryMakeCommandList = []
1441 for D in self.LibraryBuildDirectoryList:
1442 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1443 Makefile = os.path.join(D, MakefileName)
1444 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":Makefile}
1445 LibraryMakefileList.append(Makefile)
1446 LibraryMakeCommandList.append(Command)
1447 self.LibraryMakeCommandList = LibraryMakeCommandList
1449 ModuleMakefileList = []
1450 ModuleMakeCommandList = []
1451 for D in self.ModuleBuildDirectoryList:
1452 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1453 Makefile = os.path.join(D, MakefileName)
1454 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":Makefile}
1455 ModuleMakefileList.append(Makefile)
1456 ModuleMakeCommandList.append(Command)
1458 MakefileTemplateDict = {
1459 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1460 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1461 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1462 "makefile_name
" : MakefileName,
1463 "platform_name
" : MyAgo.Name,
1464 "platform_guid
" : MyAgo.Guid,
1465 "platform_version
" : MyAgo.Version,
1466 "platform_file
" : MyAgo.MetaFile,
1467 "platform_relative_directory
": MyAgo.SourceDir,
1468 "platform_output_directory
" : MyAgo.OutputDir,
1469 "platform_build_directory
" : MyAgo.BuildDir,
1470 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1472 "toolchain_tag
" : MyAgo.ToolChain,
1473 "build_target
" : MyAgo.BuildTarget,
1474 "shell_command_code
" : list(self._SHELL_CMD_[self._Platform].keys()),
1475 "shell_command
" : list(self._SHELL_CMD_[self._Platform].values()),
1476 "build_architecture_list
" : MyAgo.Arch,
1477 "architecture
" : MyAgo.Arch,
1478 "separator
" : Separator,
1479 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1480 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1481 "library_makefile_list
" : LibraryMakefileList,
1482 "module_makefile_list
" : ModuleMakefileList,
1483 "library_build_command
" : LibraryMakeCommandList,
1484 "module_build_command
" : ModuleMakeCommandList,
1487 return MakefileTemplateDict
1489 ## Get the root directory list for intermediate files of all modules build
1491 # @retval list The list of directory
1493 def GetModuleBuildDirectoryList(self):
1495 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1496 if not ModuleAutoGen.IsBinaryModule:
1497 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1500 ## Get the root directory list for intermediate files of all libraries build
1502 # @retval list The list of directory
1504 def GetLibraryBuildDirectoryList(self):
1506 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1507 if not LibraryAutoGen.IsBinaryModule:
1508 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1511 ## TopLevelMakefile class
1513 # This class encapsules makefie and its generation for entrance makefile. It
1514 # uses template to generate the content of makefile. The content of makefile
1515 # will be got from WorkspaceAutoGen object.
1517 class TopLevelMakefile(BuildFile):
1518 ## template used to generate toplevel makefile
1519 _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}''')
1521 ## Constructor of TopLevelMakefile
1523 # @param Workspace Object of WorkspaceAutoGen class
1525 def __init__(self, Workspace):
1526 BuildFile.__init__(self, Workspace)
1527 self.IntermediateDirectoryList = []
1528 self.DependencyHeaderFileSet = set()
1530 # Compose a dict object containing information used to do replacement in template
1532 def _TemplateDict(self):
1533 Separator = self._SEP_[self._Platform]
1535 # any platform autogen object is ok because we just need common information
1536 MyAgo = self._AutoGenObject
1538 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1539 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1540 ExtraData="[%s]" % str(MyAgo))
1542 for Arch in MyAgo.ArchList:
1543 self.IntermediateDirectoryList.append(Separator.join(["$
(BUILD_DIR
)", Arch]))
1544 self.IntermediateDirectoryList.append("$
(FV_DIR
)")
1546 # TRICK: for not generating GenFds call in makefile if no FDF file
1548 if MyAgo.FdfFile is not None and MyAgo.FdfFile != "":
1549 FdfFileList = [MyAgo.FdfFile]
1550 # macros passed to GenFds
1552 MacroDict.update(GlobalData.gGlobalDefines)
1553 MacroDict.update(GlobalData.gCommandLineDefines)
1554 for MacroName in MacroDict:
1555 if MacroDict[MacroName] != "":
1556 MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
1558 MacroList.append('"%s"' % MacroName)
1562 # pass extra common options to external program called in makefile, currently GenFds.exe
1564 LogLevel = EdkLogger.GetLevel()
1565 if LogLevel == EdkLogger.VERBOSE:
1566 ExtraOption += " -v
"
1567 elif LogLevel <= EdkLogger.DEBUG_9:
1568 ExtraOption += " -d
%d" % (LogLevel - 1)
1569 elif LogLevel == EdkLogger.QUIET:
1570 ExtraOption += " -q
"
1572 if GlobalData.gCaseInsensitive:
1573 ExtraOption += " -c
"
1574 if not GlobalData.gEnableGenfdsMultiThread:
1575 ExtraOption += " --no
-genfds
-multi
-thread
"
1576 if GlobalData.gIgnoreSource:
1577 ExtraOption += " --ignore
-sources
"
1579 for pcd in GlobalData.BuildOptionPcd:
1581 pcdname = '.'.join(pcd[0:3])
1583 pcdname = '.'.join(pcd[0:2])
1584 if pcd[3].startswith('{'):
1585 ExtraOption += " --pcd
" + pcdname + '=' + 'H' + '"' + pcd[3] + '"'
1587 ExtraOption += " --pcd
" + pcdname + '=' + pcd[3]
1589 MakefileName = self.getMakefileName()
1590 SubBuildCommandList = []
1591 for A in MyAgo.ArchList:
1592 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":os.path.join("$
(BUILD_DIR
)", A, MakefileName)}
1593 SubBuildCommandList.append(Command)
1595 MakefileTemplateDict = {
1596 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1597 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1598 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1599 "platform_name
" : MyAgo.Name,
1600 "platform_guid
" : MyAgo.Guid,
1601 "platform_version
" : MyAgo.Version,
1602 "platform_build_directory
" : MyAgo.BuildDir,
1603 "conf_directory
" : GlobalData.gConfDirectory,
1605 "toolchain_tag
" : MyAgo.ToolChain,
1606 "build_target
" : MyAgo.BuildTarget,
1607 "shell_command_code
" : list(self._SHELL_CMD_[self._Platform].keys()),
1608 "shell_command
" : list(self._SHELL_CMD_[self._Platform].values()),
1609 'arch' : list(MyAgo.ArchList),
1610 "build_architecture_list
" : ','.join(MyAgo.ArchList),
1611 "separator
" : Separator,
1612 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1613 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1614 "sub_build_command
" : SubBuildCommandList,
1615 "fdf_file
" : FdfFileList,
1616 "active_platform
" : str(MyAgo),
1617 "fd
" : MyAgo.FdTargetList,
1618 "fv
" : MyAgo.FvTargetList,
1619 "cap
" : MyAgo.CapTargetList,
1620 "extra_options
" : ExtraOption,
1621 "macro
" : MacroList,
1624 return MakefileTemplateDict
1626 ## Get the root directory list for intermediate files of all modules build
1628 # @retval list The list of directory
1630 def GetModuleBuildDirectoryList(self):
1632 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1633 if not ModuleAutoGen.IsBinaryModule:
1634 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1637 ## Get the root directory list for intermediate files of all libraries build
1639 # @retval list The list of directory
1641 def GetLibraryBuildDirectoryList(self):
1643 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1644 if not LibraryAutoGen.IsBinaryModule:
1645 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1648 ## Find dependencies for one source file
1650 # By searching recursively "#include" directive in file, find out all the
1651 # files needed by given source file. The dependencies will be only searched
1652 # in given search path list.
1654 # @param File The source file
1655 # @param ForceInculeList The list of files which will be included forcely
1656 # @param SearchPathList The list of search path
1658 # @retval list The list of files the given source file depends on
1660 def GetDependencyList(AutoGenObject
, FileCache
, File
, ForceList
, SearchPathList
):
1661 EdkLogger
.debug(EdkLogger
.DEBUG_1
, "Try to get dependency files for %s" % File
)
1662 FileStack
= [File
] + ForceList
1663 DependencySet
= set()
1665 if AutoGenObject
.Arch
not in gDependencyDatabase
:
1666 gDependencyDatabase
[AutoGenObject
.Arch
] = {}
1667 DepDb
= gDependencyDatabase
[AutoGenObject
.Arch
]
1669 while len(FileStack
) > 0:
1672 FullPathDependList
= []
1674 for CacheFile
in FileCache
[F
]:
1675 FullPathDependList
.append(CacheFile
)
1676 if CacheFile
not in DependencySet
:
1677 FileStack
.append(CacheFile
)
1678 DependencySet
.update(FullPathDependList
)
1681 CurrentFileDependencyList
= []
1683 CurrentFileDependencyList
= DepDb
[F
]
1686 Fd
= open(F
.Path
, 'rb')
1687 FileContent
= Fd
.read()
1689 except BaseException
as X
:
1690 EdkLogger
.error("build", FILE_OPEN_FAILURE
, ExtraData
=F
.Path
+ "\n\t" + str(X
))
1691 if len(FileContent
) == 0:
1694 if FileContent
[0] == 0xff or FileContent
[0] == 0xfe:
1695 FileContent
= FileContent
.decode('utf-16')
1697 FileContent
= FileContent
.decode()
1699 # The file is not txt file. for example .mcb file
1701 IncludedFileList
= gIncludePattern
.findall(FileContent
)
1703 for Inc
in IncludedFileList
:
1705 # if there's macro used to reference header file, expand it
1706 HeaderList
= gMacroPattern
.findall(Inc
)
1707 if len(HeaderList
) == 1 and len(HeaderList
[0]) == 2:
1708 HeaderType
= HeaderList
[0][0]
1709 HeaderKey
= HeaderList
[0][1]
1710 if HeaderType
in gIncludeMacroConversion
:
1711 Inc
= gIncludeMacroConversion
[HeaderType
] % {"HeaderKey" : HeaderKey
}
1713 # not known macro used in #include, always build the file by
1714 # returning a empty dependency
1715 FileCache
[File
] = []
1717 Inc
= os
.path
.normpath(Inc
)
1718 CurrentFileDependencyList
.append(Inc
)
1719 DepDb
[F
] = CurrentFileDependencyList
1721 CurrentFilePath
= F
.Dir
1722 PathList
= [CurrentFilePath
] + SearchPathList
1723 for Inc
in CurrentFileDependencyList
:
1724 for SearchPath
in PathList
:
1725 FilePath
= os
.path
.join(SearchPath
, Inc
)
1726 if FilePath
in gIsFileMap
:
1727 if not gIsFileMap
[FilePath
]:
1729 # If isfile is called too many times, the performance is slow down.
1730 elif not os
.path
.isfile(FilePath
):
1731 gIsFileMap
[FilePath
] = False
1734 gIsFileMap
[FilePath
] = True
1735 FilePath
= PathClass(FilePath
)
1736 FullPathDependList
.append(FilePath
)
1737 if FilePath
not in DependencySet
:
1738 FileStack
.append(FilePath
)
1741 EdkLogger
.debug(EdkLogger
.DEBUG_9
, "%s included by %s was not found "\
1742 "in any given path:\n\t%s" % (Inc
, F
, "\n\t".join(SearchPathList
)))
1744 FileCache
[F
] = FullPathDependList
1745 DependencySet
.update(FullPathDependList
)
1747 DependencySet
.update(ForceList
)
1748 if File
in DependencySet
:
1749 DependencySet
.remove(File
)
1750 DependencyList
= list(DependencySet
) # remove duplicate ones
1752 return DependencyList
1754 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1755 if __name__
== '__main__':