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 # To specify a literal backslash at the end of the line, precede it with a caret (^)
617 if P == MyAgo.IncludePathList[-1] and os.sep == '\\':
618 IncludePath = ''.join([IncludePath, '^', os.sep])
620 IncludePath = os.path.join(IncludePath, '')
621 IncludePathList.append(IncludePath)
622 FileMacroList.append(self._FILE_MACRO_TEMPLATE.Replace({"macro_name
": "NASM_INC
", "source_file
": IncludePathList}))
624 # Generate macros used to represent files containing list of input files
625 for ListFileMacro in self.ListFileMacros:
626 ListFileName = os.path.join(MyAgo.OutputDir, "%s.lst
" % ListFileMacro.lower()[:len(ListFileMacro) - 5])
627 FileMacroList.append("%s = %s" % (ListFileMacro, ListFileName))
630 "\n".join(self.ListFileMacros[ListFileMacro]),
634 # Generate objlist used to create .obj file
635 for Type in self.ObjTargetDict:
636 NewLine = ' '.join(list(self.ObjTargetDict[Type]))
637 FileMacroList.append("OBJLIST_
%s = %s" % (list(self.ObjTargetDict.keys()).index(Type), NewLine))
641 MakefileName = self.getMakefileName()
642 LibraryMakeCommandList = []
643 for D in self.LibraryBuildDirectoryList:
644 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":os.path.join(D, MakefileName)}
645 LibraryMakeCommandList.append(Command)
647 package_rel_dir = MyAgo.SourceDir
648 current_dir = self.Macros["WORKSPACE
"]
650 while not found and os.sep in package_rel_dir:
651 index = package_rel_dir.index(os.sep)
652 current_dir = mws.join(current_dir, package_rel_dir[:index])
653 if os.path.exists(current_dir):
654 for fl in os.listdir(current_dir):
655 if fl.endswith('.dec'):
658 package_rel_dir = package_rel_dir[index + 1:]
660 MakefileTemplateDict = {
661 "makefile_header
" : self._FILE_HEADER_[self._FileType],
662 "makefile_path
" : os.path.join("$
(MODULE_BUILD_DIR
)", MakefileName),
663 "makefile_name
" : MakefileName,
664 "platform_name
" : self.PlatformInfo.Name,
665 "platform_guid
" : self.PlatformInfo.Guid,
666 "platform_version
" : self.PlatformInfo.Version,
667 "platform_relative_directory
": self.PlatformInfo.SourceDir,
668 "platform_output_directory
" : self.PlatformInfo.OutputDir,
669 "ffs_output_directory
" : MyAgo.Macros["FFS_OUTPUT_DIR
"],
670 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
672 "module_name
" : MyAgo.Name,
673 "module_guid
" : MyAgo.Guid,
674 "module_name_guid
" : MyAgo.UniqueBaseName,
675 "module_version
" : MyAgo.Version,
676 "module_type
" : MyAgo.ModuleType,
677 "module_file
" : MyAgo.MetaFile.Name,
678 "module_file_base_name
" : MyAgo.MetaFile.BaseName,
679 "module_relative_directory
" : MyAgo.SourceDir,
680 "module_dir
" : mws.join (self.Macros["WORKSPACE
"], MyAgo.SourceDir),
681 "package_relative_directory
": package_rel_dir,
682 "module_extra_defines
" : ["%s = %s" % (k, v) for k, v in MyAgo.Module.Defines.items()],
684 "architecture
" : MyAgo.Arch,
685 "toolchain_tag
" : MyAgo.ToolChain,
686 "build_target
" : MyAgo.BuildTarget,
688 "platform_build_directory
" : self.PlatformInfo.BuildDir,
689 "module_build_directory
" : MyAgo.BuildDir,
690 "module_output_directory
" : MyAgo.OutputDir,
691 "module_debug_directory
" : MyAgo.DebugDir,
693 "separator
" : Separator,
694 "module_tool_definitions
" : ToolsDef,
696 "shell_command_code
" : list(self._SHELL_CMD_[self._Platform].keys()),
697 "shell_command
" : list(self._SHELL_CMD_[self._Platform].values()),
699 "module_entry_point
" : ModuleEntryPoint,
700 "image_entry_point
" : ImageEntryPoint,
701 "arch_entry_point
" : ArchEntryPoint,
702 "remaining_build_target
" : self.ResultFileList,
703 "common_dependency_file
" : self.CommonFileDependency,
704 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
705 "clean_command
" : self.GetRemoveDirectoryCommand(["$
(OUTPUT_DIR
)"]),
706 "cleanall_command
" : self.GetRemoveDirectoryCommand(["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]),
707 "dependent_library_build_directory
" : self.LibraryBuildDirectoryList,
708 "library_build_command
" : LibraryMakeCommandList,
709 "file_macro
" : FileMacroList,
710 "file_build_target
" : self.BuildTargetList,
711 "backward_compatible_target
": BcTargetList,
712 "INCLUDETAG
" : "\n".join([self._INCLUDE_CMD_[self._FileType] + " " + os.path.join("$
(MODULE_BUILD_DIR
)","dependency
"),
713 self._INCLUDE_CMD_[self._FileType] + " " + os.path.join("$
(MODULE_BUILD_DIR
)","deps_target
")
717 return MakefileTemplateDict
719 def ParserGenerateFfsCmd(self):
720 #Add Ffs cmd to self.BuildTargetList
724 for Cmd in self.GenFfsList:
726 for CopyCmd in Cmd[2]:
728 Src = self.ReplaceMacro(Src)
729 Dst = self.ReplaceMacro(Dst)
730 if Dst not in self.ResultFileList:
731 self.ResultFileList.append(Dst)
732 if '%s :' %(Dst) not in self.BuildTargetList:
733 self.BuildTargetList.append("%s : %s" %(Dst,Src))
734 self.BuildTargetList.append('\t' + self._CP_TEMPLATE_[self._Platform] %{'Src': Src, 'Dst': Dst})
737 for index, Str in enumerate(FfsCmdList):
739 OutputFile = FfsCmdList[index + 1]
740 if '-i' == Str or "-oi
" == Str:
741 if DepsFileList == []:
742 DepsFileList = [FfsCmdList[index + 1]]
744 DepsFileList.append(FfsCmdList[index + 1])
745 DepsFileString = ' '.join(DepsFileList).strip()
746 if DepsFileString == '':
748 OutputFile = self.ReplaceMacro(OutputFile)
749 self.ResultFileList.append(OutputFile)
750 DepsFileString = self.ReplaceMacro(DepsFileString)
751 self.BuildTargetList.append('%s : %s' % (OutputFile, DepsFileString))
752 CmdString = ' '.join(FfsCmdList).strip()
753 CmdString = self.ReplaceMacro(CmdString)
754 self.BuildTargetList.append('\t%s' % CmdString)
756 self.ParseSecCmd(DepsFileList, Cmd[1])
757 for SecOutputFile, SecDepsFile, SecCmd in self.FfsOutputFileList :
758 self.BuildTargetList.append('%s : %s' % (self.ReplaceMacro(SecOutputFile), self.ReplaceMacro(SecDepsFile)))
759 self.BuildTargetList.append('\t%s' % self.ReplaceMacro(SecCmd))
760 self.FfsOutputFileList = []
762 def ParseSecCmd(self, OutputFileList, CmdTuple):
763 for OutputFile in OutputFileList:
764 for SecCmdStr in CmdTuple:
766 SecCmdList = SecCmdStr.split()
767 CmdName = SecCmdList[0]
768 for index, CmdItem in enumerate(SecCmdList):
769 if '-o' == CmdItem and OutputFile == SecCmdList[index + 1]:
771 while index + 1 < len(SecCmdList):
772 if not SecCmdList[index+1].startswith('-'):
773 SecDepsFileList.append(SecCmdList[index + 1])
775 if CmdName == 'Trim':
776 SecDepsFileList.append(os.path.join('$(DEBUG_DIR)', os.path.basename(OutputFile).replace('offset', 'efi')))
777 if OutputFile.endswith('.ui') or OutputFile.endswith('.ver'):
778 SecDepsFileList.append(os.path.join('$(MODULE_DIR)', '$(MODULE_FILE)'))
779 self.FfsOutputFileList.append((OutputFile, ' '.join(SecDepsFileList), SecCmdStr))
780 if len(SecDepsFileList) > 0:
781 self.ParseSecCmd(SecDepsFileList, CmdTuple)
786 def ReplaceMacro(self, str):
787 for Macro in self.MacroList:
788 if self._AutoGenObject.Macros[Macro] and self._AutoGenObject.Macros[Macro] in str:
789 str = str.replace(self._AutoGenObject.Macros[Macro], '$(' + Macro + ')')
792 def CommandExceedLimit(self):
794 'CC' : { 'Macro' : '$(CC_FLAGS)', 'Value' : False},
795 'PP' : { 'Macro' : '$(PP_FLAGS)', 'Value' : False},
796 'APP' : { 'Macro' : '$(APP_FLAGS)', 'Value' : False},
797 'ASLPP' : { 'Macro' : '$(ASLPP_FLAGS)', 'Value' : False},
798 'VFRPP' : { 'Macro' : '$(VFRPP_FLAGS)', 'Value' : False},
799 'ASM' : { 'Macro' : '$(ASM_FLAGS)', 'Value' : False},
800 'ASLCC' : { 'Macro' : '$(ASLCC_FLAGS)', 'Value' : False},
805 IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily]
807 # base on the source files to decide the file type
808 for File in self._AutoGenObject.SourceFileList:
809 for type in self._AutoGenObject.FileTypes:
810 if File in self._AutoGenObject.FileTypes[type]:
811 if type not in FileTypeList:
812 FileTypeList.append(type)
814 # calculate the command-line length
816 for type in FileTypeList:
817 BuildTargets = self._AutoGenObject.BuildRules[type].BuildTargets
818 for Target in BuildTargets:
819 CommandList = BuildTargets[Target].Commands
820 for SingleCommand in CommandList:
822 SingleCommandLength = len(SingleCommand)
823 SingleCommandList = SingleCommand.split()
824 if len(SingleCommandList) > 0:
825 for Flag in FlagDict:
826 if '$('+ Flag +')' in SingleCommandList[0]:
830 if 'PATH' not in self._AutoGenObject.BuildOption[Tool]:
831 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))
832 SingleCommandLength += len(self._AutoGenObject.BuildOption[Tool]['PATH
'])
833 for item in SingleCommandList[1:]:
834 if FlagDict[Tool]['Macro
'] in item:
835 if 'FLAGS
' not in self._AutoGenObject.BuildOption[Tool]:
836 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))
837 Str = self._AutoGenObject.BuildOption[Tool]['FLAGS']
838 for Option in self._AutoGenObject.BuildOption:
839 for Attr in self._AutoGenObject.BuildOption[Option]:
840 if Str.find(Option + '_' + Attr) != -1:
841 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
842 while(Str.find('$(') != -1):
843 for macro in self._AutoGenObject.Macros:
844 MacroName = '$('+ macro + ')'
845 if (Str.find(MacroName) != -1):
846 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
850 SingleCommandLength += len(Str)
851 elif '$(INC)' in item:
852 SingleCommandLength += self._AutoGenObject.IncludePathLength + len(IncPrefix) * len(self._AutoGenObject.IncludePathList)
853 elif item.find('$(') != -1:
855 for Option in self._AutoGenObject.BuildOption:
856 for Attr in self._AutoGenObject.BuildOption[Option]:
857 if Str.find(Option + '_' + Attr) != -1:
858 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
859 while(Str.find('$(') != -1):
860 for macro in self._AutoGenObject.Macros:
861 MacroName = '$('+ macro + ')'
862 if (Str.find(MacroName) != -1):
863 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
867 SingleCommandLength += len(Str)
869 if SingleCommandLength > GlobalData.gCommandMaxLength:
870 FlagDict[Tool]['Value'] = True
872 # generate the response file content by combine the FLAGS and INC
873 for Flag in FlagDict:
874 if FlagDict[Flag]['Value']:
876 RespMacro = FlagDict[Flag]['Macro'].replace('FLAGS', 'RESP')
877 Value = self._AutoGenObject.BuildOption[Flag]['FLAGS']
878 for inc in self._AutoGenObject.IncludePathList:
879 Value += ' ' + IncPrefix + inc
880 for Option in self._AutoGenObject.BuildOption:
881 for Attr in self._AutoGenObject.BuildOption[Option]:
882 if Value.find(Option + '_' + Attr) != -1:
883 Value = Value.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
884 while (Value.find('$(') != -1):
885 for macro in self._AutoGenObject.Macros:
886 MacroName = '$('+ macro + ')'
887 if (Value.find(MacroName) != -1):
888 Value = Value.replace(MacroName, self._AutoGenObject.Macros[macro])
893 if self._AutoGenObject.ToolChainFamily == 'GCC':
894 RespDict[Key] = Value.replace('\\', '/')
896 RespDict[Key] = Value
897 for Target in BuildTargets:
898 for i, SingleCommand in enumerate(BuildTargets[Target].Commands):
899 if FlagDict[Flag]['Macro'] in SingleCommand:
900 BuildTargets[Target].Commands[i] = SingleCommand.replace('$(INC)', '').replace(FlagDict[Flag]['Macro'], RespMacro)
903 def ProcessBuildTargetList(self):
905 # Search dependency file list for each source file
907 ForceIncludedFile = []
908 for File in self._AutoGenObject.AutoGenFileList:
910 ForceIncludedFile.append(File)
913 for Target in self._AutoGenObject.IntroTargetList:
914 SourceFileList.extend(Target.Inputs)
915 OutPutFileList.extend(Target.Outputs)
918 for Item in OutPutFileList:
919 if Item in SourceFileList:
920 SourceFileList.remove(Item)
922 FileDependencyDict = {item:ForceIncludedFile for item in SourceFileList}
924 for Dependency in FileDependencyDict.values():
925 self.DependencyHeaderFileSet.update(set(Dependency))
927 # Get a set of unique package includes from MetaFile
928 parentMetaFileIncludes = set()
929 for aInclude in self._AutoGenObject.PackageIncludePathList:
930 aIncludeName = str(aInclude)
931 parentMetaFileIncludes.add(aIncludeName.lower())
933 # Check if header files are listed in metafile
934 # Get a set of unique module header source files from MetaFile
935 headerFilesInMetaFileSet = set()
936 for aFile in self._AutoGenObject.SourceFileList:
937 aFileName = str(aFile)
938 if not aFileName.endswith('.h'):
940 headerFilesInMetaFileSet.add(aFileName.lower())
942 # Get a set of unique module autogen files
943 localAutoGenFileSet = set()
944 for aFile in self._AutoGenObject.AutoGenFileList:
945 localAutoGenFileSet.add(str(aFile).lower())
947 # Get a set of unique module dependency header files
948 # Exclude autogen files and files not in the source directory
949 # and files that are under the package include list
950 headerFileDependencySet = set()
951 localSourceDir = str(self._AutoGenObject.SourceDir).lower()
952 for Dependency in FileDependencyDict.values():
953 for aFile in Dependency:
954 aFileName = str(aFile).lower()
955 # Exclude non-header files
956 if not aFileName.endswith('.h'):
958 # Exclude autogen files
959 if aFileName in localAutoGenFileSet:
961 # Exclude include out of local scope
962 if localSourceDir not in aFileName:
964 # Exclude files covered by package includes
966 for aIncludePath in parentMetaFileIncludes:
967 if aIncludePath in aFileName:
972 # Keep the file to be checked
973 headerFileDependencySet.add(aFileName)
975 # Check if a module dependency header file is missing from the module's MetaFile
976 for aFile in headerFileDependencySet:
977 if aFile in headerFilesInMetaFileSet:
979 if GlobalData.gUseHashCache:
980 GlobalData.gModuleBuildTracking[self._AutoGenObject] = 'FAIL_METAFILE'
981 EdkLogger.warn("build
","Module MetaFile
[Sources
] is missing local header
!",
982 ExtraData = "Local Header
: " + aFile + " not found
in " + self._AutoGenObject.MetaFile.Path
985 for File,Dependency in FileDependencyDict.items():
989 self._AutoGenObject.AutoGenDepSet |= set(Dependency)
994 DependencyDict = FileDependencyDict.copy()
996 # Convert target description object to target string in makefile
997 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and TAB_C_CODE_FILE in self._AutoGenObject.Targets:
998 for T in self._AutoGenObject.Targets[TAB_C_CODE_FILE]:
999 NewFile = self.PlaceMacro(str(T), self.Macros)
1000 if not self.ObjTargetDict.get(T.Target.SubDir):
1001 self.ObjTargetDict[T.Target.SubDir] = set()
1002 self.ObjTargetDict[T.Target.SubDir].add(NewFile)
1003 for Type in self._AutoGenObject.Targets:
1004 for T in self._AutoGenObject.Targets[Type]:
1005 # Generate related macros if needed
1006 if T.GenFileListMacro and T.FileListMacro not in self.FileListMacros:
1007 self.FileListMacros[T.FileListMacro] = []
1008 if T.GenListFile and T.ListFileMacro not in self.ListFileMacros:
1009 self.ListFileMacros[T.ListFileMacro] = []
1010 if T.GenIncListFile and T.IncListFileMacro not in self.ListFileMacros:
1011 self.ListFileMacros[T.IncListFileMacro] = []
1015 # Add force-dependencies
1016 for Dep in T.Dependencies:
1017 Deps.append(self.PlaceMacro(str(Dep), self.Macros))
1018 if Dep != '$(MAKE_FILE)':
1019 CCodeDeps.append(self.PlaceMacro(str(Dep), self.Macros))
1020 # Add inclusion-dependencies
1021 if len(T.Inputs) == 1 and T.Inputs[0] in FileDependencyDict:
1022 for F in FileDependencyDict[T.Inputs[0]]:
1023 Deps.append(self.PlaceMacro(str(F), self.Macros))
1024 # Add source-dependencies
1026 NewFile = self.PlaceMacro(str(F), self.Macros)
1027 # In order to use file list macro as dependency
1029 # gnu tools need forward slash path separator, even on Windows
1030 self.ListFileMacros[T.ListFileMacro].append(str(F).replace ('\\', '/'))
1031 self.FileListMacros[T.FileListMacro].append(NewFile)
1032 elif T.GenFileListMacro:
1033 self.FileListMacros[T.FileListMacro].append(NewFile)
1035 Deps.append(NewFile)
1036 for key in self.FileListMacros:
1037 self.FileListMacros[key].sort()
1038 # Use file list macro as dependency
1039 if T.GenFileListMacro:
1040 Deps.append("$
(%s)" % T.FileListMacro)
1041 if Type in [TAB_OBJECT_FILE, TAB_STATIC_LIBRARY]:
1042 Deps.append("$
(%s)" % T.ListFileMacro)
1044 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Type == TAB_C_CODE_FILE:
1045 T, CmdTarget, CmdTargetDict, CmdCppDict = self.ParserCCodeFile(T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict)
1046 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": CCodeDeps}
1047 CmdLine = self._BUILD_TARGET_TEMPLATE.Replace(TargetDict).rstrip().replace('\t$(OBJLIST', '$(OBJLIST')
1049 CmdLine = '%s%s' %(CmdLine, TAB_LINE_BREAK)
1050 if CCodeDeps or CmdLine:
1051 self.BuildTargetList.append(CmdLine)
1053 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": Deps}
1054 self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(TargetDict))
1056 def ParserCCodeFile(self, T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict):
1058 for item in self._AutoGenObject.Targets[Type]:
1059 CmdSumDict[item.Target.SubDir] = item.Target.BaseName
1060 for CppPath in item.Inputs:
1061 Path = self.PlaceMacro(CppPath.Path, self.Macros)
1062 if CmdCppDict.get(item.Target.SubDir):
1063 CmdCppDict[item.Target.SubDir].append(Path)
1065 CmdCppDict[item.Target.SubDir] = ['$(MAKE_FILE)', Path]
1066 if CppPath.Path in DependencyDict:
1067 for Temp in DependencyDict[CppPath.Path]:
1069 Path = self.PlaceMacro(Temp.Path, self.Macros)
1072 if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):
1073 CmdCppDict[item.Target.SubDir].append(Path)
1075 CommandList = T.Commands[:]
1076 for Item in CommandList[:]:
1077 SingleCommandList = Item.split()
1078 if len(SingleCommandList) > 0 and self.CheckCCCmd(SingleCommandList):
1079 for Temp in SingleCommandList:
1080 if Temp.startswith('/Fo'):
1081 CmdSign = '%s%s' % (Temp.rsplit(TAB_SLASH, 1)[0], TAB_SLASH)
1084 if CmdSign not in list(CmdTargetDict.keys()):
1085 CmdTargetDict[CmdSign] = Item.replace(Temp, CmdSign)
1087 CmdTargetDict[CmdSign] = "%s %s" % (CmdTargetDict[CmdSign], SingleCommandList[-1])
1088 Index = CommandList.index(Item)
1089 CommandList.pop(Index)
1090 if SingleCommandList[-1].endswith("%s%s.c
" % (TAB_SLASH, CmdSumDict[CmdSign[3:].rsplit(TAB_SLASH, 1)[0]])):
1091 Cpplist = CmdCppDict[T.Target.SubDir]
1092 Cpplist.insert(0, '$(OBJLIST_%d): ' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir))
1093 T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign])
1095 T.Commands.pop(Index)
1096 return T, CmdSumDict, CmdTargetDict, CmdCppDict
1098 def CheckCCCmd(self, CommandList):
1099 for cmd in CommandList:
1103 ## For creating makefile targets for dependent libraries
1104 def ProcessDependentLibrary(self):
1105 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1106 if not LibraryAutoGen.IsBinaryModule:
1107 self.LibraryBuildDirectoryList.append(self.PlaceMacro(LibraryAutoGen.BuildDir, self.Macros))
1109 ## Return a list containing source file's dependencies
1111 # @param FileList The list of source files
1112 # @param ForceInculeList The list of files which will be included forcely
1113 # @param SearchPathList The list of search path
1115 # @retval dict The mapping between source file path and its dependencies
1117 def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):
1120 Dependency[F] = GetDependencyList(self._AutoGenObject, self.FileCache, F, ForceInculeList, SearchPathList)
1124 ## CustomMakefile class
1126 # This class encapsules makefie and its generation for module. It uses template to generate
1127 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
1129 class CustomMakefile(BuildFile):
1130 ## template used to generate the makefile for module with custom makefile
1131 _TEMPLATE_ = TemplateString('''\
1135 # Platform Macro Definition
1137 PLATFORM_NAME = ${platform_name}
1138 PLATFORM_GUID = ${platform_guid}
1139 PLATFORM_VERSION = ${platform_version}
1140 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
1141 PLATFORM_DIR = ${platform_dir}
1142 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1145 # Module Macro Definition
1147 MODULE_NAME = ${module_name}
1148 MODULE_GUID = ${module_guid}
1149 MODULE_NAME_GUID = ${module_name_guid}
1150 MODULE_VERSION = ${module_version}
1151 MODULE_TYPE = ${module_type}
1152 MODULE_FILE = ${module_file}
1153 MODULE_FILE_BASE_NAME = ${module_file_base_name}
1154 BASE_NAME = $(MODULE_NAME)
1155 MODULE_RELATIVE_DIR = ${module_relative_directory}
1156 MODULE_DIR = ${module_dir}
1159 # Build Configuration Macro Definition
1161 ARCH = ${architecture}
1162 TOOLCHAIN = ${toolchain_tag}
1163 TOOLCHAIN_TAG = ${toolchain_tag}
1164 TARGET = ${build_target}
1167 # Build Directory Macro Definition
1169 # PLATFORM_BUILD_DIR = ${platform_build_directory}
1170 BUILD_DIR = ${platform_build_directory}
1171 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
1172 LIB_DIR = $(BIN_DIR)
1173 MODULE_BUILD_DIR = ${module_build_directory}
1174 OUTPUT_DIR = ${module_output_directory}
1175 DEBUG_DIR = ${module_debug_directory}
1176 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
1177 DEST_DIR_DEBUG = $(DEBUG_DIR)
1180 # Tools definitions specific to this module
1182 ${BEGIN}${module_tool_definitions}
1184 MAKE_FILE = ${makefile_path}
1187 # Shell Command Macro
1189 ${BEGIN}${shell_command_code} = ${shell_command}
1192 ${custom_makefile_content}
1195 # Target used when called from platform makefile, which will bypass the build of dependent libraries
1208 # Build Target used in multi-thread build mode, which no init target is needed
1214 # Initialization target: print build information and create necessary directories
1217 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
1218 ${BEGIN}\t-@${create_directory_command}\n${END}\
1222 ## Constructor of CustomMakefile
1224 # @param ModuleAutoGen Object of ModuleAutoGen class
1226 def __init__(self, ModuleAutoGen):
1227 BuildFile.__init__(self, ModuleAutoGen)
1228 self.PlatformInfo = self._AutoGenObject.PlatformInfo
1229 self.IntermediateDirectoryList = ["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]
1230 self.DependencyHeaderFileSet = set()
1232 # Compose a dict object containing information used to do replacement in template
1234 def _TemplateDict(self):
1235 Separator = self._SEP_[self._Platform]
1236 MyAgo = self._AutoGenObject
1237 if self._FileType not in MyAgo.CustomMakefile:
1238 EdkLogger.error('build', OPTION_NOT_SUPPORTED, "No custom makefile
for %s" % self._FileType,
1239 ExtraData="[%s]" % str(MyAgo))
1240 MakefilePath = mws.join(
1242 MyAgo.CustomMakefile[self._FileType]
1245 CustomMakefile = open(MakefilePath, 'r').read()
1247 EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(MyAgo),
1248 ExtraData=MyAgo.CustomMakefile[self._FileType])
1252 for Tool in MyAgo.BuildOption:
1253 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
1256 for Attr in MyAgo.BuildOption[Tool]:
1257 if Attr == "FAMILY
":
1259 elif Attr == "PATH
":
1260 ToolsDef.append("%s = %s" % (Tool, MyAgo.BuildOption[Tool][Attr]))
1262 ToolsDef.append("%s_%s = %s" % (Tool, Attr, MyAgo.BuildOption[Tool][Attr]))
1265 MakefileName = self.getMakefileName()
1266 MakefileTemplateDict = {
1267 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1268 "makefile_path
" : os.path.join("$
(MODULE_BUILD_DIR
)", MakefileName),
1269 "platform_name
" : self.PlatformInfo.Name,
1270 "platform_guid
" : self.PlatformInfo.Guid,
1271 "platform_version
" : self.PlatformInfo.Version,
1272 "platform_relative_directory
": self.PlatformInfo.SourceDir,
1273 "platform_output_directory
" : self.PlatformInfo.OutputDir,
1274 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1276 "module_name
" : MyAgo.Name,
1277 "module_guid
" : MyAgo.Guid,
1278 "module_name_guid
" : MyAgo.UniqueBaseName,
1279 "module_version
" : MyAgo.Version,
1280 "module_type
" : MyAgo.ModuleType,
1281 "module_file
" : MyAgo.MetaFile,
1282 "module_file_base_name
" : MyAgo.MetaFile.BaseName,
1283 "module_relative_directory
" : MyAgo.SourceDir,
1284 "module_dir
" : mws.join (MyAgo.WorkspaceDir, MyAgo.SourceDir),
1286 "architecture
" : MyAgo.Arch,
1287 "toolchain_tag
" : MyAgo.ToolChain,
1288 "build_target
" : MyAgo.BuildTarget,
1290 "platform_build_directory
" : self.PlatformInfo.BuildDir,
1291 "module_build_directory
" : MyAgo.BuildDir,
1292 "module_output_directory
" : MyAgo.OutputDir,
1293 "module_debug_directory
" : MyAgo.DebugDir,
1295 "separator
" : Separator,
1296 "module_tool_definitions
" : ToolsDef,
1298 "shell_command_code
" : list(self._SHELL_CMD_[self._Platform].keys()),
1299 "shell_command
" : list(self._SHELL_CMD_[self._Platform].values()),
1301 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1302 "custom_makefile_content
" : CustomMakefile
1305 return MakefileTemplateDict
1307 ## PlatformMakefile class
1309 # This class encapsules makefie and its generation for platform. It uses
1310 # template to generate the content of makefile. The content of makefile will be
1311 # got from PlatformAutoGen object.
1313 class PlatformMakefile(BuildFile):
1314 ## template used to generate the makefile for platform
1315 _TEMPLATE_ = TemplateString('''\
1319 # Platform Macro Definition
1321 PLATFORM_NAME = ${platform_name}
1322 PLATFORM_GUID = ${platform_guid}
1323 PLATFORM_VERSION = ${platform_version}
1324 PLATFORM_FILE = ${platform_file}
1325 PLATFORM_DIR = ${platform_dir}
1326 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1329 # Build Configuration Macro Definition
1331 TOOLCHAIN = ${toolchain_tag}
1332 TOOLCHAIN_TAG = ${toolchain_tag}
1333 TARGET = ${build_target}
1336 # Build Directory Macro Definition
1338 BUILD_DIR = ${platform_build_directory}
1339 FV_DIR = ${platform_build_directory}${separator}FV
1342 # Shell Command Macro
1344 ${BEGIN}${shell_command_code} = ${shell_command}
1348 MAKE_FILE = ${makefile_path}
1353 all: init build_libraries build_modules
1356 # Initialization target: print build information and create necessary directories
1359 \t-@echo Building ... $(PLATFORM_FILE) [${build_architecture_list}]
1360 \t${BEGIN}-@${create_directory_command}
1363 # library build target
1365 libraries: init build_libraries
1368 # module build target
1370 modules: init build_libraries build_modules
1373 # Build all libraries:
1376 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${library_makefile_list} pbuild
1377 ${END}\t@cd $(BUILD_DIR)
1380 # Build all modules:
1383 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${module_makefile_list} pbuild
1384 ${END}\t@cd $(BUILD_DIR)
1387 # Clean intermediate files
1390 \t${BEGIN}-@${library_build_command} clean
1391 \t${END}${BEGIN}-@${module_build_command} clean
1392 \t${END}@cd $(BUILD_DIR)
1395 # Clean all generated files except to makefile
1398 ${BEGIN}\t${cleanall_command}
1402 # Clean all library files
1405 \t${BEGIN}-@${library_build_command} cleanall
1406 \t${END}@cd $(BUILD_DIR)\n
1409 ## Constructor of PlatformMakefile
1411 # @param ModuleAutoGen Object of PlatformAutoGen class
1413 def __init__(self, PlatformAutoGen):
1414 BuildFile.__init__(self, PlatformAutoGen)
1415 self.ModuleBuildCommandList = []
1416 self.ModuleMakefileList = []
1417 self.IntermediateDirectoryList = []
1418 self.ModuleBuildDirectoryList = []
1419 self.LibraryBuildDirectoryList = []
1420 self.LibraryMakeCommandList = []
1421 self.DependencyHeaderFileSet = set()
1423 # Compose a dict object containing information used to do replacement in template
1425 def _TemplateDict(self):
1426 Separator = self._SEP_[self._Platform]
1428 MyAgo = self._AutoGenObject
1429 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1430 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1431 ExtraData="[%s]" % str(MyAgo))
1433 self.IntermediateDirectoryList = ["$
(BUILD_DIR
)"]
1434 self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()
1435 self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()
1437 MakefileName = self.getMakefileName()
1438 LibraryMakefileList = []
1439 LibraryMakeCommandList = []
1440 for D in self.LibraryBuildDirectoryList:
1441 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1442 Makefile = os.path.join(D, MakefileName)
1443 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":Makefile}
1444 LibraryMakefileList.append(Makefile)
1445 LibraryMakeCommandList.append(Command)
1446 self.LibraryMakeCommandList = LibraryMakeCommandList
1448 ModuleMakefileList = []
1449 ModuleMakeCommandList = []
1450 for D in self.ModuleBuildDirectoryList:
1451 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1452 Makefile = os.path.join(D, MakefileName)
1453 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":Makefile}
1454 ModuleMakefileList.append(Makefile)
1455 ModuleMakeCommandList.append(Command)
1457 MakefileTemplateDict = {
1458 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1459 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1460 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1461 "makefile_name
" : MakefileName,
1462 "platform_name
" : MyAgo.Name,
1463 "platform_guid
" : MyAgo.Guid,
1464 "platform_version
" : MyAgo.Version,
1465 "platform_file
" : MyAgo.MetaFile,
1466 "platform_relative_directory
": MyAgo.SourceDir,
1467 "platform_output_directory
" : MyAgo.OutputDir,
1468 "platform_build_directory
" : MyAgo.BuildDir,
1469 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1471 "toolchain_tag
" : MyAgo.ToolChain,
1472 "build_target
" : MyAgo.BuildTarget,
1473 "shell_command_code
" : list(self._SHELL_CMD_[self._Platform].keys()),
1474 "shell_command
" : list(self._SHELL_CMD_[self._Platform].values()),
1475 "build_architecture_list
" : MyAgo.Arch,
1476 "architecture
" : MyAgo.Arch,
1477 "separator
" : Separator,
1478 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1479 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1480 "library_makefile_list
" : LibraryMakefileList,
1481 "module_makefile_list
" : ModuleMakefileList,
1482 "library_build_command
" : LibraryMakeCommandList,
1483 "module_build_command
" : ModuleMakeCommandList,
1486 return MakefileTemplateDict
1488 ## Get the root directory list for intermediate files of all modules build
1490 # @retval list The list of directory
1492 def GetModuleBuildDirectoryList(self):
1494 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1495 if not ModuleAutoGen.IsBinaryModule:
1496 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1499 ## Get the root directory list for intermediate files of all libraries build
1501 # @retval list The list of directory
1503 def GetLibraryBuildDirectoryList(self):
1505 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1506 if not LibraryAutoGen.IsBinaryModule:
1507 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1510 ## TopLevelMakefile class
1512 # This class encapsules makefie and its generation for entrance makefile. It
1513 # uses template to generate the content of makefile. The content of makefile
1514 # will be got from WorkspaceAutoGen object.
1516 class TopLevelMakefile(BuildFile):
1517 ## template used to generate toplevel makefile
1518 _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}''')
1520 ## Constructor of TopLevelMakefile
1522 # @param Workspace Object of WorkspaceAutoGen class
1524 def __init__(self, Workspace):
1525 BuildFile.__init__(self, Workspace)
1526 self.IntermediateDirectoryList = []
1527 self.DependencyHeaderFileSet = set()
1529 # Compose a dict object containing information used to do replacement in template
1531 def _TemplateDict(self):
1532 Separator = self._SEP_[self._Platform]
1534 # any platform autogen object is ok because we just need common information
1535 MyAgo = self._AutoGenObject
1537 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1538 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1539 ExtraData="[%s]" % str(MyAgo))
1541 for Arch in MyAgo.ArchList:
1542 self.IntermediateDirectoryList.append(Separator.join(["$
(BUILD_DIR
)", Arch]))
1543 self.IntermediateDirectoryList.append("$
(FV_DIR
)")
1545 # TRICK: for not generating GenFds call in makefile if no FDF file
1547 if MyAgo.FdfFile is not None and MyAgo.FdfFile != "":
1548 FdfFileList = [MyAgo.FdfFile]
1549 # macros passed to GenFds
1551 MacroDict.update(GlobalData.gGlobalDefines)
1552 MacroDict.update(GlobalData.gCommandLineDefines)
1553 for MacroName in MacroDict:
1554 if MacroDict[MacroName] != "":
1555 MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
1557 MacroList.append('"%s"' % MacroName)
1561 # pass extra common options to external program called in makefile, currently GenFds.exe
1563 LogLevel = EdkLogger.GetLevel()
1564 if LogLevel == EdkLogger.VERBOSE:
1565 ExtraOption += " -v
"
1566 elif LogLevel <= EdkLogger.DEBUG_9:
1567 ExtraOption += " -d
%d" % (LogLevel - 1)
1568 elif LogLevel == EdkLogger.QUIET:
1569 ExtraOption += " -q
"
1571 if GlobalData.gCaseInsensitive:
1572 ExtraOption += " -c
"
1573 if not GlobalData.gEnableGenfdsMultiThread:
1574 ExtraOption += " --no
-genfds
-multi
-thread
"
1575 if GlobalData.gIgnoreSource:
1576 ExtraOption += " --ignore
-sources
"
1578 for pcd in GlobalData.BuildOptionPcd:
1580 pcdname = '.'.join(pcd[0:3])
1582 pcdname = '.'.join(pcd[0:2])
1583 if pcd[3].startswith('{'):
1584 ExtraOption += " --pcd
" + pcdname + '=' + 'H' + '"' + pcd[3] + '"'
1586 ExtraOption += " --pcd
" + pcdname + '=' + pcd[3]
1588 MakefileName = self.getMakefileName()
1589 SubBuildCommandList = []
1590 for A in MyAgo.ArchList:
1591 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":os.path.join("$
(BUILD_DIR
)", A, MakefileName)}
1592 SubBuildCommandList.append(Command)
1594 MakefileTemplateDict = {
1595 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1596 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1597 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1598 "platform_name
" : MyAgo.Name,
1599 "platform_guid
" : MyAgo.Guid,
1600 "platform_version
" : MyAgo.Version,
1601 "platform_build_directory
" : MyAgo.BuildDir,
1602 "conf_directory
" : GlobalData.gConfDirectory,
1604 "toolchain_tag
" : MyAgo.ToolChain,
1605 "build_target
" : MyAgo.BuildTarget,
1606 "shell_command_code
" : list(self._SHELL_CMD_[self._Platform].keys()),
1607 "shell_command
" : list(self._SHELL_CMD_[self._Platform].values()),
1608 'arch' : list(MyAgo.ArchList),
1609 "build_architecture_list
" : ','.join(MyAgo.ArchList),
1610 "separator
" : Separator,
1611 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1612 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1613 "sub_build_command
" : SubBuildCommandList,
1614 "fdf_file
" : FdfFileList,
1615 "active_platform
" : str(MyAgo),
1616 "fd
" : MyAgo.FdTargetList,
1617 "fv
" : MyAgo.FvTargetList,
1618 "cap
" : MyAgo.CapTargetList,
1619 "extra_options
" : ExtraOption,
1620 "macro
" : MacroList,
1623 return MakefileTemplateDict
1625 ## Get the root directory list for intermediate files of all modules build
1627 # @retval list The list of directory
1629 def GetModuleBuildDirectoryList(self):
1631 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1632 if not ModuleAutoGen.IsBinaryModule:
1633 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1636 ## Get the root directory list for intermediate files of all libraries build
1638 # @retval list The list of directory
1640 def GetLibraryBuildDirectoryList(self):
1642 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1643 if not LibraryAutoGen.IsBinaryModule:
1644 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1647 ## Find dependencies for one source file
1649 # By searching recursively "#include" directive in file, find out all the
1650 # files needed by given source file. The dependencies will be only searched
1651 # in given search path list.
1653 # @param File The source file
1654 # @param ForceInculeList The list of files which will be included forcely
1655 # @param SearchPathList The list of search path
1657 # @retval list The list of files the given source file depends on
1659 def GetDependencyList(AutoGenObject
, FileCache
, File
, ForceList
, SearchPathList
):
1660 EdkLogger
.debug(EdkLogger
.DEBUG_1
, "Try to get dependency files for %s" % File
)
1661 FileStack
= [File
] + ForceList
1662 DependencySet
= set()
1664 if AutoGenObject
.Arch
not in gDependencyDatabase
:
1665 gDependencyDatabase
[AutoGenObject
.Arch
] = {}
1666 DepDb
= gDependencyDatabase
[AutoGenObject
.Arch
]
1668 while len(FileStack
) > 0:
1671 FullPathDependList
= []
1673 for CacheFile
in FileCache
[F
]:
1674 FullPathDependList
.append(CacheFile
)
1675 if CacheFile
not in DependencySet
:
1676 FileStack
.append(CacheFile
)
1677 DependencySet
.update(FullPathDependList
)
1680 CurrentFileDependencyList
= []
1682 CurrentFileDependencyList
= DepDb
[F
]
1685 Fd
= open(F
.Path
, 'rb')
1686 FileContent
= Fd
.read()
1688 except BaseException
as X
:
1689 EdkLogger
.error("build", FILE_OPEN_FAILURE
, ExtraData
=F
.Path
+ "\n\t" + str(X
))
1690 if len(FileContent
) == 0:
1693 if FileContent
[0] == 0xff or FileContent
[0] == 0xfe:
1694 FileContent
= FileContent
.decode('utf-16')
1696 FileContent
= FileContent
.decode()
1698 # The file is not txt file. for example .mcb file
1700 IncludedFileList
= gIncludePattern
.findall(FileContent
)
1702 for Inc
in IncludedFileList
:
1704 # if there's macro used to reference header file, expand it
1705 HeaderList
= gMacroPattern
.findall(Inc
)
1706 if len(HeaderList
) == 1 and len(HeaderList
[0]) == 2:
1707 HeaderType
= HeaderList
[0][0]
1708 HeaderKey
= HeaderList
[0][1]
1709 if HeaderType
in gIncludeMacroConversion
:
1710 Inc
= gIncludeMacroConversion
[HeaderType
] % {"HeaderKey" : HeaderKey
}
1712 # not known macro used in #include, always build the file by
1713 # returning a empty dependency
1714 FileCache
[File
] = []
1716 Inc
= os
.path
.normpath(Inc
)
1717 CurrentFileDependencyList
.append(Inc
)
1718 DepDb
[F
] = CurrentFileDependencyList
1720 CurrentFilePath
= F
.Dir
1721 PathList
= [CurrentFilePath
] + SearchPathList
1722 for Inc
in CurrentFileDependencyList
:
1723 for SearchPath
in PathList
:
1724 FilePath
= os
.path
.join(SearchPath
, Inc
)
1725 if FilePath
in gIsFileMap
:
1726 if not gIsFileMap
[FilePath
]:
1728 # If isfile is called too many times, the performance is slow down.
1729 elif not os
.path
.isfile(FilePath
):
1730 gIsFileMap
[FilePath
] = False
1733 gIsFileMap
[FilePath
] = True
1734 FilePath
= PathClass(FilePath
)
1735 FullPathDependList
.append(FilePath
)
1736 if FilePath
not in DependencySet
:
1737 FileStack
.append(FilePath
)
1740 EdkLogger
.debug(EdkLogger
.DEBUG_9
, "%s included by %s was not found "\
1741 "in any given path:\n\t%s" % (Inc
, F
, "\n\t".join(SearchPathList
)))
1743 FileCache
[F
] = FullPathDependList
1744 DependencySet
.update(FullPathDependList
)
1746 DependencySet
.update(ForceList
)
1747 if File
in DependencySet
:
1748 DependencySet
.remove(File
)
1749 DependencyList
= list(DependencySet
) # remove duplicate ones
1751 return DependencyList
1753 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1754 if __name__
== '__main__':