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 os.path.normcase(self._AutoGenObject.Macros[Macro]) in os.path.normcase(str):
790 replace_dir = str[os.path.normcase(str).index(os.path.normcase(self._AutoGenObject.Macros[Macro])): os.path.normcase(str).index(
791 os.path.normcase(self._AutoGenObject.Macros[Macro])) + len(self._AutoGenObject.Macros[Macro])]
792 str = str.replace(replace_dir, '$(' + Macro + ')')
795 def CommandExceedLimit(self):
797 'CC' : { 'Macro' : '$(CC_FLAGS)', 'Value' : False},
798 'PP' : { 'Macro' : '$(PP_FLAGS)', 'Value' : False},
799 'APP' : { 'Macro' : '$(APP_FLAGS)', 'Value' : False},
800 'ASLPP' : { 'Macro' : '$(ASLPP_FLAGS)', 'Value' : False},
801 'VFRPP' : { 'Macro' : '$(VFRPP_FLAGS)', 'Value' : False},
802 'ASM' : { 'Macro' : '$(ASM_FLAGS)', 'Value' : False},
803 'ASLCC' : { 'Macro' : '$(ASLCC_FLAGS)', 'Value' : False},
808 IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily]
810 # base on the source files to decide the file type
811 for File in self._AutoGenObject.SourceFileList:
812 for type in self._AutoGenObject.FileTypes:
813 if File in self._AutoGenObject.FileTypes[type]:
814 if type not in FileTypeList:
815 FileTypeList.append(type)
817 # calculate the command-line length
819 for type in FileTypeList:
820 BuildTargets = self._AutoGenObject.BuildRules[type].BuildTargets
821 for Target in BuildTargets:
822 CommandList = BuildTargets[Target].Commands
823 for SingleCommand in CommandList:
825 SingleCommandLength = len(SingleCommand)
826 SingleCommandList = SingleCommand.split()
827 if len(SingleCommandList) > 0:
828 for Flag in FlagDict:
829 if '$('+ Flag +')' in SingleCommandList[0]:
833 if 'PATH' not in self._AutoGenObject.BuildOption[Tool]:
834 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))
835 SingleCommandLength += len(self._AutoGenObject.BuildOption[Tool]['PATH
'])
836 for item in SingleCommandList[1:]:
837 if FlagDict[Tool]['Macro
'] in item:
838 if 'FLAGS
' not in self._AutoGenObject.BuildOption[Tool]:
839 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))
840 Str = self._AutoGenObject.BuildOption[Tool]['FLAGS']
841 for Option in self._AutoGenObject.BuildOption:
842 for Attr in self._AutoGenObject.BuildOption[Option]:
843 if Str.find(Option + '_' + Attr) != -1:
844 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
845 while(Str.find('$(') != -1):
846 for macro in self._AutoGenObject.Macros:
847 MacroName = '$('+ macro + ')'
848 if (Str.find(MacroName) != -1):
849 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
853 SingleCommandLength += len(Str)
854 elif '$(INC)' in item:
855 SingleCommandLength += self._AutoGenObject.IncludePathLength + len(IncPrefix) * len(self._AutoGenObject.IncludePathList)
856 elif item.find('$(') != -1:
858 for Option in self._AutoGenObject.BuildOption:
859 for Attr in self._AutoGenObject.BuildOption[Option]:
860 if Str.find(Option + '_' + Attr) != -1:
861 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
862 while(Str.find('$(') != -1):
863 for macro in self._AutoGenObject.Macros:
864 MacroName = '$('+ macro + ')'
865 if (Str.find(MacroName) != -1):
866 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
870 SingleCommandLength += len(Str)
872 if SingleCommandLength > GlobalData.gCommandMaxLength:
873 FlagDict[Tool]['Value'] = True
875 # generate the response file content by combine the FLAGS and INC
876 for Flag in FlagDict:
877 if FlagDict[Flag]['Value']:
879 RespMacro = FlagDict[Flag]['Macro'].replace('FLAGS', 'RESP')
880 Value = self._AutoGenObject.BuildOption[Flag]['FLAGS']
881 for inc in self._AutoGenObject.IncludePathList:
882 Value += ' ' + IncPrefix + inc
883 for Option in self._AutoGenObject.BuildOption:
884 for Attr in self._AutoGenObject.BuildOption[Option]:
885 if Value.find(Option + '_' + Attr) != -1:
886 Value = Value.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
887 while (Value.find('$(') != -1):
888 for macro in self._AutoGenObject.Macros:
889 MacroName = '$('+ macro + ')'
890 if (Value.find(MacroName) != -1):
891 Value = Value.replace(MacroName, self._AutoGenObject.Macros[macro])
896 if self._AutoGenObject.ToolChainFamily == 'GCC':
897 RespDict[Key] = Value.replace('\\', '/')
899 RespDict[Key] = Value
900 for Target in BuildTargets:
901 for i, SingleCommand in enumerate(BuildTargets[Target].Commands):
902 if FlagDict[Flag]['Macro'] in SingleCommand:
903 BuildTargets[Target].Commands[i] = SingleCommand.replace('$(INC)', '').replace(FlagDict[Flag]['Macro'], RespMacro)
906 def ProcessBuildTargetList(self):
908 # Search dependency file list for each source file
910 ForceIncludedFile = []
911 for File in self._AutoGenObject.AutoGenFileList:
913 ForceIncludedFile.append(File)
916 for Target in self._AutoGenObject.IntroTargetList:
917 SourceFileList.extend(Target.Inputs)
918 OutPutFileList.extend(Target.Outputs)
921 for Item in OutPutFileList:
922 if Item in SourceFileList:
923 SourceFileList.remove(Item)
925 FileDependencyDict = {item:ForceIncludedFile for item in SourceFileList}
927 for Dependency in FileDependencyDict.values():
928 self.DependencyHeaderFileSet.update(set(Dependency))
930 # Get a set of unique package includes from MetaFile
931 parentMetaFileIncludes = set()
932 for aInclude in self._AutoGenObject.PackageIncludePathList:
933 aIncludeName = str(aInclude)
934 parentMetaFileIncludes.add(aIncludeName.lower())
936 # Check if header files are listed in metafile
937 # Get a set of unique module header source files from MetaFile
938 headerFilesInMetaFileSet = set()
939 for aFile in self._AutoGenObject.SourceFileList:
940 aFileName = str(aFile)
941 if not aFileName.endswith('.h'):
943 headerFilesInMetaFileSet.add(aFileName.lower())
945 # Get a set of unique module autogen files
946 localAutoGenFileSet = set()
947 for aFile in self._AutoGenObject.AutoGenFileList:
948 localAutoGenFileSet.add(str(aFile).lower())
950 # Get a set of unique module dependency header files
951 # Exclude autogen files and files not in the source directory
952 # and files that are under the package include list
953 headerFileDependencySet = set()
954 localSourceDir = str(self._AutoGenObject.SourceDir).lower()
955 for Dependency in FileDependencyDict.values():
956 for aFile in Dependency:
957 aFileName = str(aFile).lower()
958 # Exclude non-header files
959 if not aFileName.endswith('.h'):
961 # Exclude autogen files
962 if aFileName in localAutoGenFileSet:
964 # Exclude include out of local scope
965 if localSourceDir not in aFileName:
967 # Exclude files covered by package includes
969 for aIncludePath in parentMetaFileIncludes:
970 if aIncludePath in aFileName:
975 # Keep the file to be checked
976 headerFileDependencySet.add(aFileName)
978 # Check if a module dependency header file is missing from the module's MetaFile
979 for aFile in headerFileDependencySet:
980 if aFile in headerFilesInMetaFileSet:
982 if GlobalData.gUseHashCache:
983 GlobalData.gModuleBuildTracking[self._AutoGenObject] = 'FAIL_METAFILE'
984 EdkLogger.warn("build
","Module MetaFile
[Sources
] is missing local header
!",
985 ExtraData = "Local Header
: " + aFile + " not found
in " + self._AutoGenObject.MetaFile.Path
988 for File,Dependency in FileDependencyDict.items():
992 self._AutoGenObject.AutoGenDepSet |= set(Dependency)
997 DependencyDict = FileDependencyDict.copy()
999 # Convert target description object to target string in makefile
1000 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and TAB_C_CODE_FILE in self._AutoGenObject.Targets:
1001 for T in self._AutoGenObject.Targets[TAB_C_CODE_FILE]:
1002 NewFile = self.PlaceMacro(str(T), self.Macros)
1003 if not self.ObjTargetDict.get(T.Target.SubDir):
1004 self.ObjTargetDict[T.Target.SubDir] = set()
1005 self.ObjTargetDict[T.Target.SubDir].add(NewFile)
1006 for Type in self._AutoGenObject.Targets:
1007 for T in self._AutoGenObject.Targets[Type]:
1008 # Generate related macros if needed
1009 if T.GenFileListMacro and T.FileListMacro not in self.FileListMacros:
1010 self.FileListMacros[T.FileListMacro] = []
1011 if T.GenListFile and T.ListFileMacro not in self.ListFileMacros:
1012 self.ListFileMacros[T.ListFileMacro] = []
1013 if T.GenIncListFile and T.IncListFileMacro not in self.ListFileMacros:
1014 self.ListFileMacros[T.IncListFileMacro] = []
1018 # Add force-dependencies
1019 for Dep in T.Dependencies:
1020 Deps.append(self.PlaceMacro(str(Dep), self.Macros))
1021 if Dep != '$(MAKE_FILE)':
1022 CCodeDeps.append(self.PlaceMacro(str(Dep), self.Macros))
1023 # Add inclusion-dependencies
1024 if len(T.Inputs) == 1 and T.Inputs[0] in FileDependencyDict:
1025 for F in FileDependencyDict[T.Inputs[0]]:
1026 Deps.append(self.PlaceMacro(str(F), self.Macros))
1027 # Add source-dependencies
1029 NewFile = self.PlaceMacro(str(F), self.Macros)
1030 # In order to use file list macro as dependency
1032 # gnu tools need forward slash path separator, even on Windows
1033 self.ListFileMacros[T.ListFileMacro].append(str(F).replace ('\\', '/'))
1034 self.FileListMacros[T.FileListMacro].append(NewFile)
1035 elif T.GenFileListMacro:
1036 self.FileListMacros[T.FileListMacro].append(NewFile)
1038 Deps.append(NewFile)
1039 for key in self.FileListMacros:
1040 self.FileListMacros[key].sort()
1041 # Use file list macro as dependency
1042 if T.GenFileListMacro:
1043 Deps.append("$
(%s)" % T.FileListMacro)
1044 if Type in [TAB_OBJECT_FILE, TAB_STATIC_LIBRARY]:
1045 Deps.append("$
(%s)" % T.ListFileMacro)
1047 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Type == TAB_C_CODE_FILE:
1048 T, CmdTarget, CmdTargetDict, CmdCppDict = self.ParserCCodeFile(T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict)
1049 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": CCodeDeps}
1050 CmdLine = self._BUILD_TARGET_TEMPLATE.Replace(TargetDict).rstrip().replace('\t$(OBJLIST', '$(OBJLIST')
1052 CmdLine = '%s%s' %(CmdLine, TAB_LINE_BREAK)
1053 if CCodeDeps or CmdLine:
1054 self.BuildTargetList.append(CmdLine)
1056 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": Deps}
1057 self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(TargetDict))
1059 # Add a Makefile rule for targets generating multiple files.
1060 # The main output is a prerequisite for the other output files.
1061 for i in T.Outputs[1:]:
1062 AnnexeTargetDict = {"target
": self.PlaceMacro(i.Path, self.Macros), "cmd
": "", "deps
": self.PlaceMacro(T.Target.Path, self.Macros)}
1063 self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(AnnexeTargetDict))
1065 def ParserCCodeFile(self, T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict):
1067 for item in self._AutoGenObject.Targets[Type]:
1068 CmdSumDict[item.Target.SubDir] = item.Target.BaseName
1069 for CppPath in item.Inputs:
1070 Path = self.PlaceMacro(CppPath.Path, self.Macros)
1071 if CmdCppDict.get(item.Target.SubDir):
1072 CmdCppDict[item.Target.SubDir].append(Path)
1074 CmdCppDict[item.Target.SubDir] = ['$(MAKE_FILE)', Path]
1075 if CppPath.Path in DependencyDict:
1076 for Temp in DependencyDict[CppPath.Path]:
1078 Path = self.PlaceMacro(Temp.Path, self.Macros)
1081 if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):
1082 CmdCppDict[item.Target.SubDir].append(Path)
1084 CommandList = T.Commands[:]
1085 for Item in CommandList[:]:
1086 SingleCommandList = Item.split()
1087 if len(SingleCommandList) > 0 and self.CheckCCCmd(SingleCommandList):
1088 for Temp in SingleCommandList:
1089 if Temp.startswith('/Fo'):
1090 CmdSign = '%s%s' % (Temp.rsplit(TAB_SLASH, 1)[0], TAB_SLASH)
1093 if CmdSign not in list(CmdTargetDict.keys()):
1094 CmdTargetDict[CmdSign] = Item.replace(Temp, CmdSign)
1096 CmdTargetDict[CmdSign] = "%s %s" % (CmdTargetDict[CmdSign], SingleCommandList[-1])
1097 Index = CommandList.index(Item)
1098 CommandList.pop(Index)
1099 if SingleCommandList[-1].endswith("%s%s.c
" % (TAB_SLASH, CmdSumDict[CmdSign[3:].rsplit(TAB_SLASH, 1)[0]])):
1100 Cpplist = CmdCppDict[T.Target.SubDir]
1101 Cpplist.insert(0, '$(OBJLIST_%d): ' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir))
1102 T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign])
1104 T.Commands.pop(Index)
1105 return T, CmdSumDict, CmdTargetDict, CmdCppDict
1107 def CheckCCCmd(self, CommandList):
1108 for cmd in CommandList:
1112 ## For creating makefile targets for dependent libraries
1113 def ProcessDependentLibrary(self):
1114 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1115 if not LibraryAutoGen.IsBinaryModule:
1116 self.LibraryBuildDirectoryList.append(self.PlaceMacro(LibraryAutoGen.BuildDir, self.Macros))
1118 ## Return a list containing source file's dependencies
1120 # @param FileList The list of source files
1121 # @param ForceInculeList The list of files which will be included forcely
1122 # @param SearchPathList The list of search path
1124 # @retval dict The mapping between source file path and its dependencies
1126 def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):
1129 Dependency[F] = GetDependencyList(self._AutoGenObject, self.FileCache, F, ForceInculeList, SearchPathList)
1133 ## CustomMakefile class
1135 # This class encapsules makefie and its generation for module. It uses template to generate
1136 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
1138 class CustomMakefile(BuildFile):
1139 ## template used to generate the makefile for module with custom makefile
1140 _TEMPLATE_ = TemplateString('''\
1144 # Platform Macro Definition
1146 PLATFORM_NAME = ${platform_name}
1147 PLATFORM_GUID = ${platform_guid}
1148 PLATFORM_VERSION = ${platform_version}
1149 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
1150 PLATFORM_DIR = ${platform_dir}
1151 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1154 # Module Macro Definition
1156 MODULE_NAME = ${module_name}
1157 MODULE_GUID = ${module_guid}
1158 MODULE_NAME_GUID = ${module_name_guid}
1159 MODULE_VERSION = ${module_version}
1160 MODULE_TYPE = ${module_type}
1161 MODULE_FILE = ${module_file}
1162 MODULE_FILE_BASE_NAME = ${module_file_base_name}
1163 BASE_NAME = $(MODULE_NAME)
1164 MODULE_RELATIVE_DIR = ${module_relative_directory}
1165 MODULE_DIR = ${module_dir}
1168 # Build Configuration Macro Definition
1170 ARCH = ${architecture}
1171 TOOLCHAIN = ${toolchain_tag}
1172 TOOLCHAIN_TAG = ${toolchain_tag}
1173 TARGET = ${build_target}
1176 # Build Directory Macro Definition
1178 # PLATFORM_BUILD_DIR = ${platform_build_directory}
1179 BUILD_DIR = ${platform_build_directory}
1180 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
1181 LIB_DIR = $(BIN_DIR)
1182 MODULE_BUILD_DIR = ${module_build_directory}
1183 OUTPUT_DIR = ${module_output_directory}
1184 DEBUG_DIR = ${module_debug_directory}
1185 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
1186 DEST_DIR_DEBUG = $(DEBUG_DIR)
1189 # Tools definitions specific to this module
1191 ${BEGIN}${module_tool_definitions}
1193 MAKE_FILE = ${makefile_path}
1196 # Shell Command Macro
1198 ${BEGIN}${shell_command_code} = ${shell_command}
1201 ${custom_makefile_content}
1204 # Target used when called from platform makefile, which will bypass the build of dependent libraries
1217 # Build Target used in multi-thread build mode, which no init target is needed
1223 # Initialization target: print build information and create necessary directories
1226 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
1227 ${BEGIN}\t-@${create_directory_command}\n${END}\
1231 ## Constructor of CustomMakefile
1233 # @param ModuleAutoGen Object of ModuleAutoGen class
1235 def __init__(self, ModuleAutoGen):
1236 BuildFile.__init__(self, ModuleAutoGen)
1237 self.PlatformInfo = self._AutoGenObject.PlatformInfo
1238 self.IntermediateDirectoryList = ["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]
1239 self.DependencyHeaderFileSet = set()
1241 # Compose a dict object containing information used to do replacement in template
1243 def _TemplateDict(self):
1244 Separator = self._SEP_[self._Platform]
1245 MyAgo = self._AutoGenObject
1246 if self._FileType not in MyAgo.CustomMakefile:
1247 EdkLogger.error('build', OPTION_NOT_SUPPORTED, "No custom makefile
for %s" % self._FileType,
1248 ExtraData="[%s]" % str(MyAgo))
1249 MakefilePath = mws.join(
1251 MyAgo.CustomMakefile[self._FileType]
1254 CustomMakefile = open(MakefilePath, 'r').read()
1256 EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(MyAgo),
1257 ExtraData=MyAgo.CustomMakefile[self._FileType])
1261 for Tool in MyAgo.BuildOption:
1262 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
1265 for Attr in MyAgo.BuildOption[Tool]:
1266 if Attr == "FAMILY
":
1268 elif Attr == "PATH
":
1269 ToolsDef.append("%s = %s" % (Tool, MyAgo.BuildOption[Tool][Attr]))
1271 ToolsDef.append("%s_%s = %s" % (Tool, Attr, MyAgo.BuildOption[Tool][Attr]))
1274 MakefileName = self.getMakefileName()
1275 MakefileTemplateDict = {
1276 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1277 "makefile_path
" : os.path.join("$
(MODULE_BUILD_DIR
)", MakefileName),
1278 "platform_name
" : self.PlatformInfo.Name,
1279 "platform_guid
" : self.PlatformInfo.Guid,
1280 "platform_version
" : self.PlatformInfo.Version,
1281 "platform_relative_directory
": self.PlatformInfo.SourceDir,
1282 "platform_output_directory
" : self.PlatformInfo.OutputDir,
1283 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1285 "module_name
" : MyAgo.Name,
1286 "module_guid
" : MyAgo.Guid,
1287 "module_name_guid
" : MyAgo.UniqueBaseName,
1288 "module_version
" : MyAgo.Version,
1289 "module_type
" : MyAgo.ModuleType,
1290 "module_file
" : MyAgo.MetaFile,
1291 "module_file_base_name
" : MyAgo.MetaFile.BaseName,
1292 "module_relative_directory
" : MyAgo.SourceDir,
1293 "module_dir
" : mws.join (MyAgo.WorkspaceDir, MyAgo.SourceDir),
1295 "architecture
" : MyAgo.Arch,
1296 "toolchain_tag
" : MyAgo.ToolChain,
1297 "build_target
" : MyAgo.BuildTarget,
1299 "platform_build_directory
" : self.PlatformInfo.BuildDir,
1300 "module_build_directory
" : MyAgo.BuildDir,
1301 "module_output_directory
" : MyAgo.OutputDir,
1302 "module_debug_directory
" : MyAgo.DebugDir,
1304 "separator
" : Separator,
1305 "module_tool_definitions
" : ToolsDef,
1307 "shell_command_code
" : list(self._SHELL_CMD_[self._Platform].keys()),
1308 "shell_command
" : list(self._SHELL_CMD_[self._Platform].values()),
1310 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1311 "custom_makefile_content
" : CustomMakefile
1314 return MakefileTemplateDict
1316 ## PlatformMakefile class
1318 # This class encapsules makefie and its generation for platform. It uses
1319 # template to generate the content of makefile. The content of makefile will be
1320 # got from PlatformAutoGen object.
1322 class PlatformMakefile(BuildFile):
1323 ## template used to generate the makefile for platform
1324 _TEMPLATE_ = TemplateString('''\
1328 # Platform Macro Definition
1330 PLATFORM_NAME = ${platform_name}
1331 PLATFORM_GUID = ${platform_guid}
1332 PLATFORM_VERSION = ${platform_version}
1333 PLATFORM_FILE = ${platform_file}
1334 PLATFORM_DIR = ${platform_dir}
1335 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1338 # Build Configuration Macro Definition
1340 TOOLCHAIN = ${toolchain_tag}
1341 TOOLCHAIN_TAG = ${toolchain_tag}
1342 TARGET = ${build_target}
1345 # Build Directory Macro Definition
1347 BUILD_DIR = ${platform_build_directory}
1348 FV_DIR = ${platform_build_directory}${separator}FV
1351 # Shell Command Macro
1353 ${BEGIN}${shell_command_code} = ${shell_command}
1357 MAKE_FILE = ${makefile_path}
1362 all: init build_libraries build_modules
1365 # Initialization target: print build information and create necessary directories
1368 \t-@echo Building ... $(PLATFORM_FILE) [${build_architecture_list}]
1369 \t${BEGIN}-@${create_directory_command}
1372 # library build target
1374 libraries: init build_libraries
1377 # module build target
1379 modules: init build_libraries build_modules
1382 # Build all libraries:
1385 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${library_makefile_list} pbuild
1386 ${END}\t@cd $(BUILD_DIR)
1389 # Build all modules:
1392 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${module_makefile_list} pbuild
1393 ${END}\t@cd $(BUILD_DIR)
1396 # Clean intermediate files
1399 \t${BEGIN}-@${library_build_command} clean
1400 \t${END}${BEGIN}-@${module_build_command} clean
1401 \t${END}@cd $(BUILD_DIR)
1404 # Clean all generated files except to makefile
1407 ${BEGIN}\t${cleanall_command}
1411 # Clean all library files
1414 \t${BEGIN}-@${library_build_command} cleanall
1415 \t${END}@cd $(BUILD_DIR)\n
1418 ## Constructor of PlatformMakefile
1420 # @param ModuleAutoGen Object of PlatformAutoGen class
1422 def __init__(self, PlatformAutoGen):
1423 BuildFile.__init__(self, PlatformAutoGen)
1424 self.ModuleBuildCommandList = []
1425 self.ModuleMakefileList = []
1426 self.IntermediateDirectoryList = []
1427 self.ModuleBuildDirectoryList = []
1428 self.LibraryBuildDirectoryList = []
1429 self.LibraryMakeCommandList = []
1430 self.DependencyHeaderFileSet = set()
1432 # Compose a dict object containing information used to do replacement in template
1434 def _TemplateDict(self):
1435 Separator = self._SEP_[self._Platform]
1437 MyAgo = self._AutoGenObject
1438 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1439 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1440 ExtraData="[%s]" % str(MyAgo))
1442 self.IntermediateDirectoryList = ["$
(BUILD_DIR
)"]
1443 self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()
1444 self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()
1446 MakefileName = self.getMakefileName()
1447 LibraryMakefileList = []
1448 LibraryMakeCommandList = []
1449 for D in self.LibraryBuildDirectoryList:
1450 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1451 Makefile = os.path.join(D, MakefileName)
1452 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":Makefile}
1453 LibraryMakefileList.append(Makefile)
1454 LibraryMakeCommandList.append(Command)
1455 self.LibraryMakeCommandList = LibraryMakeCommandList
1457 ModuleMakefileList = []
1458 ModuleMakeCommandList = []
1459 for D in self.ModuleBuildDirectoryList:
1460 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1461 Makefile = os.path.join(D, MakefileName)
1462 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":Makefile}
1463 ModuleMakefileList.append(Makefile)
1464 ModuleMakeCommandList.append(Command)
1466 MakefileTemplateDict = {
1467 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1468 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1469 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1470 "makefile_name
" : MakefileName,
1471 "platform_name
" : MyAgo.Name,
1472 "platform_guid
" : MyAgo.Guid,
1473 "platform_version
" : MyAgo.Version,
1474 "platform_file
" : MyAgo.MetaFile,
1475 "platform_relative_directory
": MyAgo.SourceDir,
1476 "platform_output_directory
" : MyAgo.OutputDir,
1477 "platform_build_directory
" : MyAgo.BuildDir,
1478 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1480 "toolchain_tag
" : MyAgo.ToolChain,
1481 "build_target
" : MyAgo.BuildTarget,
1482 "shell_command_code
" : list(self._SHELL_CMD_[self._Platform].keys()),
1483 "shell_command
" : list(self._SHELL_CMD_[self._Platform].values()),
1484 "build_architecture_list
" : MyAgo.Arch,
1485 "architecture
" : MyAgo.Arch,
1486 "separator
" : Separator,
1487 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1488 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1489 "library_makefile_list
" : LibraryMakefileList,
1490 "module_makefile_list
" : ModuleMakefileList,
1491 "library_build_command
" : LibraryMakeCommandList,
1492 "module_build_command
" : ModuleMakeCommandList,
1495 return MakefileTemplateDict
1497 ## Get the root directory list for intermediate files of all modules build
1499 # @retval list The list of directory
1501 def GetModuleBuildDirectoryList(self):
1503 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1504 if not ModuleAutoGen.IsBinaryModule:
1505 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1508 ## Get the root directory list for intermediate files of all libraries build
1510 # @retval list The list of directory
1512 def GetLibraryBuildDirectoryList(self):
1514 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1515 if not LibraryAutoGen.IsBinaryModule:
1516 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1519 ## TopLevelMakefile class
1521 # This class encapsules makefie and its generation for entrance makefile. It
1522 # uses template to generate the content of makefile. The content of makefile
1523 # will be got from WorkspaceAutoGen object.
1525 class TopLevelMakefile(BuildFile):
1526 ## template used to generate toplevel makefile
1527 _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}''')
1529 ## Constructor of TopLevelMakefile
1531 # @param Workspace Object of WorkspaceAutoGen class
1533 def __init__(self, Workspace):
1534 BuildFile.__init__(self, Workspace)
1535 self.IntermediateDirectoryList = []
1536 self.DependencyHeaderFileSet = set()
1538 # Compose a dict object containing information used to do replacement in template
1540 def _TemplateDict(self):
1541 Separator = self._SEP_[self._Platform]
1543 # any platform autogen object is ok because we just need common information
1544 MyAgo = self._AutoGenObject
1546 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1547 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1548 ExtraData="[%s]" % str(MyAgo))
1550 for Arch in MyAgo.ArchList:
1551 self.IntermediateDirectoryList.append(Separator.join(["$
(BUILD_DIR
)", Arch]))
1552 self.IntermediateDirectoryList.append("$
(FV_DIR
)")
1554 # TRICK: for not generating GenFds call in makefile if no FDF file
1556 if MyAgo.FdfFile is not None and MyAgo.FdfFile != "":
1557 FdfFileList = [MyAgo.FdfFile]
1558 # macros passed to GenFds
1560 MacroDict.update(GlobalData.gGlobalDefines)
1561 MacroDict.update(GlobalData.gCommandLineDefines)
1562 for MacroName in MacroDict:
1563 if MacroDict[MacroName] != "":
1564 MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
1566 MacroList.append('"%s"' % MacroName)
1570 # pass extra common options to external program called in makefile, currently GenFds.exe
1572 LogLevel = EdkLogger.GetLevel()
1573 if LogLevel == EdkLogger.VERBOSE:
1574 ExtraOption += " -v
"
1575 elif LogLevel <= EdkLogger.DEBUG_9:
1576 ExtraOption += " -d
%d" % (LogLevel - 1)
1577 elif LogLevel == EdkLogger.QUIET:
1578 ExtraOption += " -q
"
1580 if GlobalData.gCaseInsensitive:
1581 ExtraOption += " -c
"
1582 if not GlobalData.gEnableGenfdsMultiThread:
1583 ExtraOption += " --no
-genfds
-multi
-thread
"
1584 if GlobalData.gIgnoreSource:
1585 ExtraOption += " --ignore
-sources
"
1587 for pcd in GlobalData.BuildOptionPcd:
1589 pcdname = '.'.join(pcd[0:3])
1591 pcdname = '.'.join(pcd[0:2])
1592 if pcd[3].startswith('{'):
1593 ExtraOption += " --pcd
" + pcdname + '=' + 'H' + '"' + pcd[3] + '"'
1595 ExtraOption += " --pcd
" + pcdname + '=' + pcd[3]
1597 MakefileName = self.getMakefileName()
1598 SubBuildCommandList = []
1599 for A in MyAgo.ArchList:
1600 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":os.path.join("$
(BUILD_DIR
)", A, MakefileName)}
1601 SubBuildCommandList.append(Command)
1603 MakefileTemplateDict = {
1604 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1605 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1606 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1607 "platform_name
" : MyAgo.Name,
1608 "platform_guid
" : MyAgo.Guid,
1609 "platform_version
" : MyAgo.Version,
1610 "platform_build_directory
" : MyAgo.BuildDir,
1611 "conf_directory
" : GlobalData.gConfDirectory,
1613 "toolchain_tag
" : MyAgo.ToolChain,
1614 "build_target
" : MyAgo.BuildTarget,
1615 "shell_command_code
" : list(self._SHELL_CMD_[self._Platform].keys()),
1616 "shell_command
" : list(self._SHELL_CMD_[self._Platform].values()),
1617 'arch' : list(MyAgo.ArchList),
1618 "build_architecture_list
" : ','.join(MyAgo.ArchList),
1619 "separator
" : Separator,
1620 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1621 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1622 "sub_build_command
" : SubBuildCommandList,
1623 "fdf_file
" : FdfFileList,
1624 "active_platform
" : str(MyAgo),
1625 "fd
" : MyAgo.FdTargetList,
1626 "fv
" : MyAgo.FvTargetList,
1627 "cap
" : MyAgo.CapTargetList,
1628 "extra_options
" : ExtraOption,
1629 "macro
" : MacroList,
1632 return MakefileTemplateDict
1634 ## Get the root directory list for intermediate files of all modules build
1636 # @retval list The list of directory
1638 def GetModuleBuildDirectoryList(self):
1640 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1641 if not ModuleAutoGen.IsBinaryModule:
1642 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1645 ## Get the root directory list for intermediate files of all libraries build
1647 # @retval list The list of directory
1649 def GetLibraryBuildDirectoryList(self):
1651 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1652 if not LibraryAutoGen.IsBinaryModule:
1653 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1656 ## Find dependencies for one source file
1658 # By searching recursively "#include" directive in file, find out all the
1659 # files needed by given source file. The dependencies will be only searched
1660 # in given search path list.
1662 # @param File The source file
1663 # @param ForceInculeList The list of files which will be included forcely
1664 # @param SearchPathList The list of search path
1666 # @retval list The list of files the given source file depends on
1668 def GetDependencyList(AutoGenObject
, FileCache
, File
, ForceList
, SearchPathList
):
1669 EdkLogger
.debug(EdkLogger
.DEBUG_1
, "Try to get dependency files for %s" % File
)
1670 FileStack
= [File
] + ForceList
1671 DependencySet
= set()
1673 if AutoGenObject
.Arch
not in gDependencyDatabase
:
1674 gDependencyDatabase
[AutoGenObject
.Arch
] = {}
1675 DepDb
= gDependencyDatabase
[AutoGenObject
.Arch
]
1677 while len(FileStack
) > 0:
1680 FullPathDependList
= []
1682 for CacheFile
in FileCache
[F
]:
1683 FullPathDependList
.append(CacheFile
)
1684 if CacheFile
not in DependencySet
:
1685 FileStack
.append(CacheFile
)
1686 DependencySet
.update(FullPathDependList
)
1689 CurrentFileDependencyList
= []
1691 CurrentFileDependencyList
= DepDb
[F
]
1694 Fd
= open(F
.Path
, 'rb')
1695 FileContent
= Fd
.read()
1697 except BaseException
as X
:
1698 EdkLogger
.error("build", FILE_OPEN_FAILURE
, ExtraData
=F
.Path
+ "\n\t" + str(X
))
1699 if len(FileContent
) == 0:
1702 if FileContent
[0] == 0xff or FileContent
[0] == 0xfe:
1703 FileContent
= FileContent
.decode('utf-16')
1705 FileContent
= FileContent
.decode()
1707 # The file is not txt file. for example .mcb file
1709 IncludedFileList
= gIncludePattern
.findall(FileContent
)
1711 for Inc
in IncludedFileList
:
1713 # if there's macro used to reference header file, expand it
1714 HeaderList
= gMacroPattern
.findall(Inc
)
1715 if len(HeaderList
) == 1 and len(HeaderList
[0]) == 2:
1716 HeaderType
= HeaderList
[0][0]
1717 HeaderKey
= HeaderList
[0][1]
1718 if HeaderType
in gIncludeMacroConversion
:
1719 Inc
= gIncludeMacroConversion
[HeaderType
] % {"HeaderKey" : HeaderKey
}
1721 # not known macro used in #include, always build the file by
1722 # returning a empty dependency
1723 FileCache
[File
] = []
1725 Inc
= os
.path
.normpath(Inc
)
1726 CurrentFileDependencyList
.append(Inc
)
1727 DepDb
[F
] = CurrentFileDependencyList
1729 CurrentFilePath
= F
.Dir
1730 PathList
= [CurrentFilePath
] + SearchPathList
1731 for Inc
in CurrentFileDependencyList
:
1732 for SearchPath
in PathList
:
1733 FilePath
= os
.path
.join(SearchPath
, Inc
)
1734 if FilePath
in gIsFileMap
:
1735 if not gIsFileMap
[FilePath
]:
1737 # If isfile is called too many times, the performance is slow down.
1738 elif not os
.path
.isfile(FilePath
):
1739 gIsFileMap
[FilePath
] = False
1742 gIsFileMap
[FilePath
] = True
1743 FilePath
= PathClass(FilePath
)
1744 FullPathDependList
.append(FilePath
)
1745 if FilePath
not in DependencySet
:
1746 FileStack
.append(FilePath
)
1749 EdkLogger
.debug(EdkLogger
.DEBUG_9
, "%s included by %s was not found "\
1750 "in any given path:\n\t%s" % (Inc
, F
, "\n\t".join(SearchPathList
)))
1752 FileCache
[F
] = FullPathDependList
1753 DependencySet
.update(FullPathDependList
)
1755 DependencySet
.update(ForceList
)
1756 if File
in DependencySet
:
1757 DependencySet
.remove(File
)
1758 DependencyList
= list(DependencySet
) # remove duplicate ones
1760 return DependencyList
1762 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1763 if __name__
== '__main__':