2 # Create makefile for MS nmake and GNU make
4 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 # SPDX-License-Identifier: BSD-2-Clause-Patent
10 from __future__
import absolute_import
11 import Common
.LongFilePathOs
as os
15 import os
.path
as path
16 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
17 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
18 from Common
.BuildToolError
import *
19 from Common
.Misc
import *
20 from Common
.StringUtils
import *
21 from .BuildEngine
import *
22 import Common
.GlobalData
as GlobalData
23 from collections
import OrderedDict
24 from Common
.DataType
import TAB_COMPILER_MSFT
26 ## Regular expression for finding header file inclusions
27 gIncludePattern
= re
.compile(r
"^[ \t]*[#%]?[ \t]*include(?:[ \t]*(?:\\(?:\r\n|\r|\n))*[ \t]*)*(?:\(?[\"<]?
[ \t]*)([-\w
.\\/() \t]+)(?
:[ \t]*[\">]?\
)?
)", re.MULTILINE | re.UNICODE | re.IGNORECASE)
29 ## Regular expression for matching macro used in header file inclusion
30 gMacroPattern = re.compile("([_A
-Z
][_A
-Z0
-9]*)[ \t]*\
((.+)\
)", re.UNICODE)
34 ## pattern for include style in Edk.x code
35 gProtocolDefinition = "Protocol
/%(HeaderKey)s/%(HeaderKey)s.h
"
36 gGuidDefinition = "Guid
/%(HeaderKey)s/%(HeaderKey)s.h
"
37 gArchProtocolDefinition = "ArchProtocol
/%(HeaderKey)s/%(HeaderKey)s.h
"
38 gPpiDefinition = "Ppi
/%(HeaderKey)s/%(HeaderKey)s.h
"
39 gIncludeMacroConversion = {
40 "EFI_PROTOCOL_DEFINITION
" : gProtocolDefinition,
41 "EFI_GUID_DEFINITION
" : gGuidDefinition,
42 "EFI_ARCH_PROTOCOL_DEFINITION
" : gArchProtocolDefinition,
43 "EFI_PROTOCOL_PRODUCER
" : gProtocolDefinition,
44 "EFI_PROTOCOL_CONSUMER
" : gProtocolDefinition,
45 "EFI_PROTOCOL_DEPENDENCY
" : gProtocolDefinition,
46 "EFI_ARCH_PROTOCOL_PRODUCER
" : gArchProtocolDefinition,
47 "EFI_ARCH_PROTOCOL_CONSUMER
" : gArchProtocolDefinition,
48 "EFI_ARCH_PROTOCOL_DEPENDENCY
" : gArchProtocolDefinition,
49 "EFI_PPI_DEFINITION
" : gPpiDefinition,
50 "EFI_PPI_PRODUCER
" : gPpiDefinition,
51 "EFI_PPI_CONSUMER
" : gPpiDefinition,
52 "EFI_PPI_DEPENDENCY
" : gPpiDefinition,
55 ## default makefile type
57 if sys.platform == "win32
":
65 # This base class encapsules build file and its generation. It uses template to generate
66 # the content of build file. The content of build file will be got from AutoGen objects.
68 class BuildFile(object):
69 ## template used to generate the build file (i.e. makefile if using make)
70 _TEMPLATE_ = TemplateString('')
72 _DEFAULT_FILE_NAME_ = "Makefile
"
74 ## default file name for each type of build file
77 "gmake
" : "GNUmakefile
"
80 ## Fixed header string for makefile
81 _MAKEFILE_HEADER = '''#
83 # This file is auto-generated by build utility
91 # Auto-generated makefile for building modules, libraries or platform
95 ## Header string for each type of build file
97 "nmake
" : _MAKEFILE_HEADER % _FILE_NAME_["nmake
"],
98 "gmake
" : _MAKEFILE_HEADER % _FILE_NAME_["gmake
"]
101 ## shell commands which can be used in build file in the form of macro
102 # $(CP) copy file command
103 # $(MV) move file command
104 # $(RM) remove file command
105 # $(MD) create dir command
106 # $(RD) remove dir command
114 "RD
" : "rmdir
/s
/q
",
126 ## directory separator
132 ## directory creation template
134 "nmake
" : 'if not exist %(dir)s $(MD) %(dir)s',
135 "gmake
" : "$
(MD
) %(dir)s"
138 ## directory removal template
140 "nmake
" : 'if exist %(dir)s $(RD) %(dir)s',
141 "gmake
" : "$
(RD
) %(dir)s"
145 "nmake
" : 'if exist %(Src)s $(CP) %(Src)s %(Dst)s',
146 "gmake
" : "test
-f
%(Src)s && $
(CP
) %(Src)s %(Dst)s"
150 "nmake
" : 'if exist %(dir)s cd %(dir)s',
151 "gmake
" : "test
-e
%(dir)s && cd
%(dir)s"
155 "nmake
" : 'if exist %(file)s "$
(MAKE
)" $(MAKE_FLAGS) -f %(file)s',
156 "gmake
" : 'test -e %(file)s && "$
(MAKE
)" $(MAKE_FLAGS) -f %(file)s'
160 "nmake
" : '!INCLUDE',
164 _INC_FLAG_ = {TAB_COMPILER_MSFT : "/I
", "GCC
" : "-I
", "INTEL
" : "-I
", "RVCT
" : "-I
", "NASM
" : "-I
"}
166 ## Constructor of BuildFile
168 # @param AutoGenObject Object of AutoGen class
170 def __init__(self, AutoGenObject):
171 self._AutoGenObject = AutoGenObject
172 self._FileType = gMakeType
176 # @param FileType Type of build file. Only nmake and gmake are supported now.
178 # @retval TRUE The build file is created or re-created successfully
179 # @retval FALSE The build file exists and is the same as the one to be generated
181 def Generate(self, FileType=gMakeType):
182 if FileType not in self._FILE_NAME_:
183 EdkLogger.error("build
", PARAMETER_INVALID, "Invalid build
type [%s]" % FileType,
184 ExtraData="[%s]" % str(self._AutoGenObject))
185 self._FileType = FileType
186 FileContent = self._TEMPLATE_.Replace(self._TemplateDict)
187 FileName = self._FILE_NAME_[FileType]
188 if not os.path.exists(os.path.join(self._AutoGenObject.MakeFileDir, "deps
.txt
")):
189 with open(os.path.join(self._AutoGenObject.MakeFileDir, "deps
.txt
"),"w
+") as fd:
191 if not os.path.exists(os.path.join(self._AutoGenObject.MakeFileDir, "dependency
")):
192 with open(os.path.join(self._AutoGenObject.MakeFileDir, "dependency
"),"w
+") as fd:
194 return SaveFileOnChange(os.path.join(self._AutoGenObject.MakeFileDir, FileName), FileContent, False)
196 ## Return a list of directory creation command string
198 # @param DirList The list of directory to be created
200 # @retval list The directory creation command list
202 def GetCreateDirectoryCommand(self, DirList):
203 return [self._MD_TEMPLATE_[self._FileType] % {'dir':Dir} for Dir in DirList]
205 ## Return a list of directory removal command string
207 # @param DirList The list of directory to be removed
209 # @retval list The directory removal command list
211 def GetRemoveDirectoryCommand(self, DirList):
212 return [self._RD_TEMPLATE_[self._FileType] % {'dir':Dir} for Dir in DirList]
214 def PlaceMacro(self, Path, MacroDefinitions=None):
215 if Path.startswith("$
("):
218 if MacroDefinitions is None:
219 MacroDefinitions = {}
220 PathLength = len(Path)
221 for MacroName in MacroDefinitions:
222 MacroValue = MacroDefinitions[MacroName]
223 MacroValueLength = len(MacroValue)
224 if MacroValueLength == 0:
226 if MacroValueLength <= PathLength and Path.startswith(MacroValue):
227 Path = "$
(%s)%s" % (MacroName, Path[MacroValueLength:])
231 ## ModuleMakefile class
233 # This class encapsules makefie and its generation for module. It uses template to generate
234 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
236 class ModuleMakefile(BuildFile):
237 ## template used to generate the makefile for module
238 _TEMPLATE_ = TemplateString('''\
242 # Platform Macro Definition
244 PLATFORM_NAME = ${platform_name}
245 PLATFORM_GUID = ${platform_guid}
246 PLATFORM_VERSION = ${platform_version}
247 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
248 PLATFORM_DIR = ${platform_dir}
249 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
252 # Module Macro Definition
254 MODULE_NAME = ${module_name}
255 MODULE_GUID = ${module_guid}
256 MODULE_NAME_GUID = ${module_name_guid}
257 MODULE_VERSION = ${module_version}
258 MODULE_TYPE = ${module_type}
259 MODULE_FILE = ${module_file}
260 MODULE_FILE_BASE_NAME = ${module_file_base_name}
261 BASE_NAME = $(MODULE_NAME)
262 MODULE_RELATIVE_DIR = ${module_relative_directory}
263 PACKAGE_RELATIVE_DIR = ${package_relative_directory}
264 MODULE_DIR = ${module_dir}
265 FFS_OUTPUT_DIR = ${ffs_output_directory}
267 MODULE_ENTRY_POINT = ${module_entry_point}
268 ARCH_ENTRY_POINT = ${arch_entry_point}
269 IMAGE_ENTRY_POINT = ${image_entry_point}
271 ${BEGIN}${module_extra_defines}
274 # Build Configuration Macro Definition
276 ARCH = ${architecture}
277 TOOLCHAIN = ${toolchain_tag}
278 TOOLCHAIN_TAG = ${toolchain_tag}
279 TARGET = ${build_target}
282 # Build Directory Macro Definition
284 # PLATFORM_BUILD_DIR = ${platform_build_directory}
285 BUILD_DIR = ${platform_build_directory}
286 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
288 MODULE_BUILD_DIR = ${module_build_directory}
289 OUTPUT_DIR = ${module_output_directory}
290 DEBUG_DIR = ${module_debug_directory}
291 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
292 DEST_DIR_DEBUG = $(DEBUG_DIR)
295 # Shell Command Macro
297 ${BEGIN}${shell_command_code} = ${shell_command}
301 # Tools definitions specific to this module
303 ${BEGIN}${module_tool_definitions}
305 MAKE_FILE = ${makefile_path}
310 ${BEGIN}${file_macro}
314 # Overridable Target Macro Definitions
316 FORCE_REBUILD = force_build
319 BC_TARGET = ${BEGIN}${backward_compatible_target} ${END}
320 CODA_TARGET = ${BEGIN}${remaining_build_target} \\
324 # Default target, which will build dependent libraries in addition to source files
331 # Target used when called from platform makefile, which will bypass the build of dependent libraries
334 pbuild: $(INIT_TARGET) $(BC_TARGET) $(PCH_TARGET) $(CODA_TARGET)
340 mbuild: $(INIT_TARGET) $(BC_TARGET) gen_libs $(PCH_TARGET) $(CODA_TARGET)
343 # Build Target used in multi-thread build mode, which will bypass the init and gen_libs targets
346 tbuild: $(BC_TARGET) $(PCH_TARGET) $(CODA_TARGET)
349 # Phony target which is used to force executing commands for a target
355 # Target to update the FD
361 # Initialization target: print build information and create necessary directories
366 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
369 ${BEGIN}\t-@${create_directory_command}\n${END}
372 \t-@$(CP) $(DEBUG_DIR)${separator}AutoGen.h $(DEBUG_DIR)${separator}$(MODULE_NAME)StrDefs.h
378 \t${BEGIN}@"$
(MAKE
)" $(MAKE_FLAGS) -f ${dependent_library_build_directory}${separator}${makefile_name}
379 \t${END}@cd $(MODULE_BUILD_DIR)
382 # Build Flash Device Image
385 \t@"$
(MAKE
)" $(MAKE_FLAGS) -f $(BUILD_DIR)${separator}${makefile_name} fds
386 \t@cd $(MODULE_BUILD_DIR)
391 # Individual Object Build Targets
393 ${BEGIN}${file_build_target}
397 # clean all intermediate files
400 \t${BEGIN}${clean_command}
401 \t${END}\t$(RM) AutoGenTimeStamp
404 # clean all generated files
407 ${BEGIN}\t${cleanall_command}
408 ${END}\t$(RM) *.pdb *.idb > NUL 2>&1
409 \t$(RM) $(BIN_DIR)${separator}$(MODULE_NAME).efi
410 \t$(RM) AutoGenTimeStamp
413 # clean all dependent libraries built
416 \t${BEGIN}-@${library_build_command} cleanall
417 \t${END}@cd $(MODULE_BUILD_DIR)\n\n''')
419 _FILE_MACRO_TEMPLATE = TemplateString("${macro_name}
= ${BEGIN}
\\\n ${source_file}${END}
\n")
420 _BUILD_TARGET_TEMPLATE = TemplateString("${BEGIN}${target}
: ${deps}
\n${END}
\t${cmd}
\n")
422 ## Constructor of ModuleMakefile
424 # @param ModuleAutoGen Object of ModuleAutoGen class
426 def __init__(self, ModuleAutoGen):
427 BuildFile.__init__(self, ModuleAutoGen)
428 self.PlatformInfo = self._AutoGenObject.PlatformInfo
430 self.ResultFileList = []
431 self.IntermediateDirectoryList = ["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]
433 self.FileBuildTargetList = [] # [(src, target string)]
434 self.BuildTargetList = [] # [target string]
435 self.PendingBuildTargetList = [] # [FileBuildRule objects]
436 self.CommonFileDependency = []
437 self.FileListMacros = {}
438 self.ListFileMacros = {}
439 self.ObjTargetDict = OrderedDict()
441 self.LibraryBuildCommandList = []
442 self.LibraryFileList = []
443 self.LibraryMakefileList = []
444 self.LibraryBuildDirectoryList = []
445 self.SystemLibraryList = []
446 self.Macros = OrderedDict()
447 self.Macros["OUTPUT_DIR
" ] = self._AutoGenObject.Macros["OUTPUT_DIR
"]
448 self.Macros["DEBUG_DIR
" ] = self._AutoGenObject.Macros["DEBUG_DIR
"]
449 self.Macros["MODULE_BUILD_DIR
"] = self._AutoGenObject.Macros["MODULE_BUILD_DIR
"]
450 self.Macros["BIN_DIR
" ] = self._AutoGenObject.Macros["BIN_DIR
"]
451 self.Macros["BUILD_DIR
" ] = self._AutoGenObject.Macros["BUILD_DIR
"]
452 self.Macros["WORKSPACE
" ] = self._AutoGenObject.Macros["WORKSPACE
"]
453 self.Macros["FFS_OUTPUT_DIR
" ] = self._AutoGenObject.Macros["FFS_OUTPUT_DIR
"]
454 self.GenFfsList = ModuleAutoGen.GenFfsList
455 self.MacroList = ['FFS_OUTPUT_DIR', 'MODULE_GUID', 'OUTPUT_DIR']
456 self.FfsOutputFileList = []
457 self.DependencyHeaderFileSet = set()
459 # Compose a dict object containing information used to do replacement in template
461 def _TemplateDict(self):
462 if self._FileType not in self._SEP_:
463 EdkLogger.error("build
", PARAMETER_INVALID, "Invalid Makefile
type [%s]" % self._FileType,
464 ExtraData="[%s]" % str(self._AutoGenObject))
465 MyAgo = self._AutoGenObject
466 Separator = self._SEP_[self._FileType]
468 # break build if no source files and binary files are found
469 if len(MyAgo.SourceFileList) == 0 and len(MyAgo.BinaryFileList) == 0:
470 EdkLogger.error("build
", AUTOGEN_ERROR, "No files to be built
in module
[%s, %s, %s]"
471 % (MyAgo.BuildTarget, MyAgo.ToolChain, MyAgo.Arch),
472 ExtraData="[%s]" % str(MyAgo))
474 # convert dependent libraries to build command
475 self.ProcessDependentLibrary()
476 if len(MyAgo.Module.ModuleEntryPointList) > 0:
477 ModuleEntryPoint = MyAgo.Module.ModuleEntryPointList[0]
479 ModuleEntryPoint = "_ModuleEntryPoint
"
481 ArchEntryPoint = ModuleEntryPoint
483 if MyAgo.Arch == "EBC
":
484 # EBC compiler always use "EfiStart
" as entry point. Only applies to EdkII modules
485 ImageEntryPoint = "EfiStart
"
487 # EdkII modules always use "_ModuleEntryPoint
" as entry point
488 ImageEntryPoint = "_ModuleEntryPoint
"
490 for k, v in MyAgo.Module.Defines.items():
491 if k not in MyAgo.Macros:
494 if 'MODULE_ENTRY_POINT' not in MyAgo.Macros:
495 MyAgo.Macros['MODULE_ENTRY_POINT'] = ModuleEntryPoint
496 if 'ARCH_ENTRY_POINT' not in MyAgo.Macros:
497 MyAgo.Macros['ARCH_ENTRY_POINT'] = ArchEntryPoint
498 if 'IMAGE_ENTRY_POINT' not in MyAgo.Macros:
499 MyAgo.Macros['IMAGE_ENTRY_POINT'] = ImageEntryPoint
501 PCI_COMPRESS_Flag = False
502 for k, v in MyAgo.Module.Defines.items():
503 if 'PCI_COMPRESS' == k and 'TRUE' == v:
504 PCI_COMPRESS_Flag = True
508 IncPrefix = self._INC_FLAG_[MyAgo.ToolChainFamily]
509 for Tool in MyAgo.BuildOption:
510 for Attr in MyAgo.BuildOption[Tool]:
511 Value = MyAgo.BuildOption[Tool][Attr]
515 ToolsDef.append("%s = %s" % (Tool, Value))
517 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
520 # Remove duplicated include path, if any
522 Value = RemoveDupOption(Value, IncPrefix, MyAgo.IncludePathList)
523 if Tool == "OPTROM
" and PCI_COMPRESS_Flag:
524 ValueList = Value.split()
526 for i, v in enumerate(ValueList):
529 Value = ' '.join(ValueList)
531 ToolsDef.append("%s_%s = %s" % (Tool, Attr, Value))
534 # generate the Response file and Response flag
535 RespDict = self.CommandExceedLimit()
536 RespFileList = os.path.join(MyAgo.OutputDir, 'respfilelist.txt')
538 RespFileListContent = ''
539 for Resp in RespDict:
540 RespFile = os.path.join(MyAgo.OutputDir, str(Resp).lower() + '.txt')
541 StrList = RespDict[Resp].split(' ')
545 if '$' in Str or '-MMD' in Str or '-MF' in Str:
546 UnexpandMacro.append(Str)
549 UnexpandMacroStr = ' '.join(UnexpandMacro)
550 NewRespStr = ' '.join(NewStr)
551 SaveFileOnChange(RespFile, NewRespStr, False)
552 ToolsDef.append("%s = %s" % (Resp, UnexpandMacroStr + ' @' + RespFile))
553 RespFileListContent += '@' + RespFile + TAB_LINE_BREAK
554 RespFileListContent += NewRespStr + TAB_LINE_BREAK
555 SaveFileOnChange(RespFileList, RespFileListContent, False)
557 if os.path.exists(RespFileList):
558 os.remove(RespFileList)
560 # convert source files and binary files to build targets
561 self.ResultFileList = [str(T.Target) for T in MyAgo.CodaTargetList]
562 if len(self.ResultFileList) == 0 and len(MyAgo.SourceFileList) != 0:
563 EdkLogger.error("build
", AUTOGEN_ERROR, "Nothing to build
",
564 ExtraData="[%s]" % str(MyAgo))
566 self.ProcessBuildTargetList()
567 self.ParserGenerateFfsCmd()
569 # Generate macros used to represent input files
570 FileMacroList = [] # macro name = file list
571 for FileListMacro in self.FileListMacros:
572 FileMacro = self._FILE_MACRO_TEMPLATE.Replace(
574 "macro_name
" : FileListMacro,
575 "source_file
" : self.FileListMacros[FileListMacro]
578 FileMacroList.append(FileMacro)
580 # INC_LIST is special
583 for P in MyAgo.IncludePathList:
584 IncludePathList.append(IncPrefix + self.PlaceMacro(P, self.Macros))
585 if FileBuildRule.INC_LIST_MACRO in self.ListFileMacros:
586 self.ListFileMacros[FileBuildRule.INC_LIST_MACRO].append(IncPrefix + P)
587 FileMacro += self._FILE_MACRO_TEMPLATE.Replace(
589 "macro_name
" : "INC
",
590 "source_file
" : IncludePathList
593 FileMacroList.append(FileMacro)
594 # Add support when compiling .nasm source files
596 asmsource = [item for item in MyAgo.SourceFileList if item.File.upper().endswith((".NASM
",".ASM
",".NASMB
","S
"))]
598 for P in MyAgo.IncludePathList:
599 IncludePath = self._INC_FLAG_['NASM'] + self.PlaceMacro(P, self.Macros)
600 if IncludePath.endswith(os.sep):
601 IncludePath = IncludePath.rstrip(os.sep)
602 # When compiling .nasm files, need to add a literal backslash at each path
603 # To specify a literal backslash at the end of the line, precede it with a caret (^)
604 if P == MyAgo.IncludePathList[-1] and os.sep == '\\':
605 IncludePath = ''.join([IncludePath, '^', os.sep])
607 IncludePath = os.path.join(IncludePath, '')
608 IncludePathList.append(IncludePath)
609 FileMacroList.append(self._FILE_MACRO_TEMPLATE.Replace({"macro_name
": "NASM_INC
", "source_file
": IncludePathList}))
611 # Generate macros used to represent files containing list of input files
612 for ListFileMacro in self.ListFileMacros:
613 ListFileName = os.path.join(MyAgo.OutputDir, "%s.lst
" % ListFileMacro.lower()[:len(ListFileMacro) - 5])
614 FileMacroList.append("%s = %s" % (ListFileMacro, ListFileName))
617 "\n".join(self.ListFileMacros[ListFileMacro]),
621 # Generate objlist used to create .obj file
622 for Type in self.ObjTargetDict:
623 NewLine = ' '.join(list(self.ObjTargetDict[Type]))
624 FileMacroList.append("OBJLIST_
%s = %s" % (list(self.ObjTargetDict.keys()).index(Type), NewLine))
628 MakefileName = self._FILE_NAME_[self._FileType]
629 LibraryMakeCommandList = []
630 for D in self.LibraryBuildDirectoryList:
631 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join(D, MakefileName)}
632 LibraryMakeCommandList.append(Command)
634 package_rel_dir = MyAgo.SourceDir
635 current_dir = self.Macros["WORKSPACE
"]
637 while not found and os.sep in package_rel_dir:
638 index = package_rel_dir.index(os.sep)
639 current_dir = mws.join(current_dir, package_rel_dir[:index])
640 if os.path.exists(current_dir):
641 for fl in os.listdir(current_dir):
642 if fl.endswith('.dec'):
645 package_rel_dir = package_rel_dir[index + 1:]
647 MakefileTemplateDict = {
648 "makefile_header
" : self._FILE_HEADER_[self._FileType],
649 "makefile_path
" : os.path.join("$
(MODULE_BUILD_DIR
)", MakefileName),
650 "makefile_name
" : MakefileName,
651 "platform_name
" : self.PlatformInfo.Name,
652 "platform_guid
" : self.PlatformInfo.Guid,
653 "platform_version
" : self.PlatformInfo.Version,
654 "platform_relative_directory
": self.PlatformInfo.SourceDir,
655 "platform_output_directory
" : self.PlatformInfo.OutputDir,
656 "ffs_output_directory
" : MyAgo.Macros["FFS_OUTPUT_DIR
"],
657 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
659 "module_name
" : MyAgo.Name,
660 "module_guid
" : MyAgo.Guid,
661 "module_name_guid
" : MyAgo.UniqueBaseName,
662 "module_version
" : MyAgo.Version,
663 "module_type
" : MyAgo.ModuleType,
664 "module_file
" : MyAgo.MetaFile.Name,
665 "module_file_base_name
" : MyAgo.MetaFile.BaseName,
666 "module_relative_directory
" : MyAgo.SourceDir,
667 "module_dir
" : mws.join (self.Macros["WORKSPACE
"], MyAgo.SourceDir),
668 "package_relative_directory
": package_rel_dir,
669 "module_extra_defines
" : ["%s = %s" % (k, v) for k, v in MyAgo.Module.Defines.items()],
671 "architecture
" : MyAgo.Arch,
672 "toolchain_tag
" : MyAgo.ToolChain,
673 "build_target
" : MyAgo.BuildTarget,
675 "platform_build_directory
" : self.PlatformInfo.BuildDir,
676 "module_build_directory
" : MyAgo.BuildDir,
677 "module_output_directory
" : MyAgo.OutputDir,
678 "module_debug_directory
" : MyAgo.DebugDir,
680 "separator
" : Separator,
681 "module_tool_definitions
" : ToolsDef,
683 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
684 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
686 "module_entry_point
" : ModuleEntryPoint,
687 "image_entry_point
" : ImageEntryPoint,
688 "arch_entry_point
" : ArchEntryPoint,
689 "remaining_build_target
" : self.ResultFileList,
690 "common_dependency_file
" : self.CommonFileDependency,
691 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
692 "clean_command
" : self.GetRemoveDirectoryCommand(["$
(OUTPUT_DIR
)"]),
693 "cleanall_command
" : self.GetRemoveDirectoryCommand(["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]),
694 "dependent_library_build_directory
" : self.LibraryBuildDirectoryList,
695 "library_build_command
" : LibraryMakeCommandList,
696 "file_macro
" : FileMacroList,
697 "file_build_target
" : self.BuildTargetList,
698 "backward_compatible_target
": BcTargetList,
699 "INCLUDETAG
" : self._INCLUDE_CMD_[self._FileType] + " " + os.path.join("$
(MODULE_BUILD_DIR
)","dependency
")
702 return MakefileTemplateDict
704 def ParserGenerateFfsCmd(self):
705 #Add Ffs cmd to self.BuildTargetList
709 for Cmd in self.GenFfsList:
711 for CopyCmd in Cmd[2]:
713 Src = self.ReplaceMacro(Src)
714 Dst = self.ReplaceMacro(Dst)
715 if Dst not in self.ResultFileList:
716 self.ResultFileList.append(Dst)
717 if '%s :' %(Dst) not in self.BuildTargetList:
718 self.BuildTargetList.append("%s :" %(Dst))
719 self.BuildTargetList.append('\t' + self._CP_TEMPLATE_[self._FileType] %{'Src': Src, 'Dst': Dst})
722 for index, Str in enumerate(FfsCmdList):
724 OutputFile = FfsCmdList[index + 1]
725 if '-i' == Str or "-oi
" == Str:
726 if DepsFileList == []:
727 DepsFileList = [FfsCmdList[index + 1]]
729 DepsFileList.append(FfsCmdList[index + 1])
730 DepsFileString = ' '.join(DepsFileList).strip()
731 if DepsFileString == '':
733 OutputFile = self.ReplaceMacro(OutputFile)
734 self.ResultFileList.append(OutputFile)
735 DepsFileString = self.ReplaceMacro(DepsFileString)
736 self.BuildTargetList.append('%s : %s' % (OutputFile, DepsFileString))
737 CmdString = ' '.join(FfsCmdList).strip()
738 CmdString = self.ReplaceMacro(CmdString)
739 self.BuildTargetList.append('\t%s' % CmdString)
741 self.ParseSecCmd(DepsFileList, Cmd[1])
742 for SecOutputFile, SecDepsFile, SecCmd in self.FfsOutputFileList :
743 self.BuildTargetList.append('%s : %s' % (self.ReplaceMacro(SecOutputFile), self.ReplaceMacro(SecDepsFile)))
744 self.BuildTargetList.append('\t%s' % self.ReplaceMacro(SecCmd))
745 self.FfsOutputFileList = []
747 def ParseSecCmd(self, OutputFileList, CmdTuple):
748 for OutputFile in OutputFileList:
749 for SecCmdStr in CmdTuple:
751 SecCmdList = SecCmdStr.split()
752 CmdName = SecCmdList[0]
753 for index, CmdItem in enumerate(SecCmdList):
754 if '-o' == CmdItem and OutputFile == SecCmdList[index + 1]:
756 while index + 1 < len(SecCmdList):
757 if not SecCmdList[index+1].startswith('-'):
758 SecDepsFileList.append(SecCmdList[index + 1])
760 if CmdName == 'Trim':
761 SecDepsFileList.append(os.path.join('$(DEBUG_DIR)', os.path.basename(OutputFile).replace('offset', 'efi')))
762 if OutputFile.endswith('.ui') or OutputFile.endswith('.ver'):
763 SecDepsFileList.append(os.path.join('$(MODULE_DIR)', '$(MODULE_FILE)'))
764 self.FfsOutputFileList.append((OutputFile, ' '.join(SecDepsFileList), SecCmdStr))
765 if len(SecDepsFileList) > 0:
766 self.ParseSecCmd(SecDepsFileList, CmdTuple)
771 def ReplaceMacro(self, str):
772 for Macro in self.MacroList:
773 if self._AutoGenObject.Macros[Macro] and self._AutoGenObject.Macros[Macro] in str:
774 str = str.replace(self._AutoGenObject.Macros[Macro], '$(' + Macro + ')')
777 def CommandExceedLimit(self):
779 'CC' : { 'Macro' : '$(CC_FLAGS)', 'Value' : False},
780 'PP' : { 'Macro' : '$(PP_FLAGS)', 'Value' : False},
781 'APP' : { 'Macro' : '$(APP_FLAGS)', 'Value' : False},
782 'ASLPP' : { 'Macro' : '$(ASLPP_FLAGS)', 'Value' : False},
783 'VFRPP' : { 'Macro' : '$(VFRPP_FLAGS)', 'Value' : False},
784 'ASM' : { 'Macro' : '$(ASM_FLAGS)', 'Value' : False},
785 'ASLCC' : { 'Macro' : '$(ASLCC_FLAGS)', 'Value' : False},
790 IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily]
792 # base on the source files to decide the file type
793 for File in self._AutoGenObject.SourceFileList:
794 for type in self._AutoGenObject.FileTypes:
795 if File in self._AutoGenObject.FileTypes[type]:
796 if type not in FileTypeList:
797 FileTypeList.append(type)
799 # calculate the command-line length
801 for type in FileTypeList:
802 BuildTargets = self._AutoGenObject.BuildRules[type].BuildTargets
803 for Target in BuildTargets:
804 CommandList = BuildTargets[Target].Commands
805 for SingleCommand in CommandList:
807 SingleCommandLength = len(SingleCommand)
808 SingleCommandList = SingleCommand.split()
809 if len(SingleCommandList) > 0:
810 for Flag in FlagDict:
811 if '$('+ Flag +')' in SingleCommandList[0]:
815 if 'PATH' not in self._AutoGenObject.BuildOption[Tool]:
816 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))
817 SingleCommandLength += len(self._AutoGenObject.BuildOption[Tool]['PATH
'])
818 for item in SingleCommandList[1:]:
819 if FlagDict[Tool]['Macro
'] in item:
820 if 'FLAGS
' not in self._AutoGenObject.BuildOption[Tool]:
821 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))
822 Str = self._AutoGenObject.BuildOption[Tool]['FLAGS']
823 for Option in self._AutoGenObject.BuildOption:
824 for Attr in self._AutoGenObject.BuildOption[Option]:
825 if Str.find(Option + '_' + Attr) != -1:
826 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
827 while(Str.find('$(') != -1):
828 for macro in self._AutoGenObject.Macros:
829 MacroName = '$('+ macro + ')'
830 if (Str.find(MacroName) != -1):
831 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
835 SingleCommandLength += len(Str)
836 elif '$(INC)' in item:
837 SingleCommandLength += self._AutoGenObject.IncludePathLength + len(IncPrefix) * len(self._AutoGenObject.IncludePathList)
838 elif item.find('$(') != -1:
840 for Option in self._AutoGenObject.BuildOption:
841 for Attr in self._AutoGenObject.BuildOption[Option]:
842 if Str.find(Option + '_' + Attr) != -1:
843 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
844 while(Str.find('$(') != -1):
845 for macro in self._AutoGenObject.Macros:
846 MacroName = '$('+ macro + ')'
847 if (Str.find(MacroName) != -1):
848 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
852 SingleCommandLength += len(Str)
854 if SingleCommandLength > GlobalData.gCommandMaxLength:
855 FlagDict[Tool]['Value'] = True
857 # generate the response file content by combine the FLAGS and INC
858 for Flag in FlagDict:
859 if FlagDict[Flag]['Value']:
861 RespMacro = FlagDict[Flag]['Macro'].replace('FLAGS', 'RESP')
862 Value = self._AutoGenObject.BuildOption[Flag]['FLAGS']
863 for inc in self._AutoGenObject.IncludePathList:
864 Value += ' ' + IncPrefix + inc
865 for Option in self._AutoGenObject.BuildOption:
866 for Attr in self._AutoGenObject.BuildOption[Option]:
867 if Value.find(Option + '_' + Attr) != -1:
868 Value = Value.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
869 while (Value.find('$(') != -1):
870 for macro in self._AutoGenObject.Macros:
871 MacroName = '$('+ macro + ')'
872 if (Value.find(MacroName) != -1):
873 Value = Value.replace(MacroName, self._AutoGenObject.Macros[macro])
878 if self._AutoGenObject.ToolChainFamily == 'GCC':
879 RespDict[Key] = Value.replace('\\', '/')
881 RespDict[Key] = Value
882 for Target in BuildTargets:
883 for i, SingleCommand in enumerate(BuildTargets[Target].Commands):
884 if FlagDict[Flag]['Macro'] in SingleCommand:
885 BuildTargets[Target].Commands[i] = SingleCommand.replace('$(INC)', '').replace(FlagDict[Flag]['Macro'], RespMacro)
888 def ProcessBuildTargetList(self):
890 # Search dependency file list for each source file
892 ForceIncludedFile = []
893 for File in self._AutoGenObject.AutoGenFileList:
895 ForceIncludedFile.append(File)
898 for Target in self._AutoGenObject.IntroTargetList:
899 SourceFileList.extend(Target.Inputs)
900 OutPutFileList.extend(Target.Outputs)
903 for Item in OutPutFileList:
904 if Item in SourceFileList:
905 SourceFileList.remove(Item)
907 FileDependencyDict = {item:ForceIncludedFile for item in SourceFileList}
909 for Dependency in FileDependencyDict.values():
910 self.DependencyHeaderFileSet.update(set(Dependency))
912 # Get a set of unique package includes from MetaFile
913 parentMetaFileIncludes = set()
914 for aInclude in self._AutoGenObject.PackageIncludePathList:
915 aIncludeName = str(aInclude)
916 parentMetaFileIncludes.add(aIncludeName.lower())
918 # Check if header files are listed in metafile
919 # Get a set of unique module header source files from MetaFile
920 headerFilesInMetaFileSet = set()
921 for aFile in self._AutoGenObject.SourceFileList:
922 aFileName = str(aFile)
923 if not aFileName.endswith('.h'):
925 headerFilesInMetaFileSet.add(aFileName.lower())
927 # Get a set of unique module autogen files
928 localAutoGenFileSet = set()
929 for aFile in self._AutoGenObject.AutoGenFileList:
930 localAutoGenFileSet.add(str(aFile).lower())
932 # Get a set of unique module dependency header files
933 # Exclude autogen files and files not in the source directory
934 # and files that are under the package include list
935 headerFileDependencySet = set()
936 localSourceDir = str(self._AutoGenObject.SourceDir).lower()
937 for Dependency in FileDependencyDict.values():
938 for aFile in Dependency:
939 aFileName = str(aFile).lower()
940 # Exclude non-header files
941 if not aFileName.endswith('.h'):
943 # Exclude autogen files
944 if aFileName in localAutoGenFileSet:
946 # Exclude include out of local scope
947 if localSourceDir not in aFileName:
949 # Exclude files covered by package includes
951 for aIncludePath in parentMetaFileIncludes:
952 if aIncludePath in aFileName:
957 # Keep the file to be checked
958 headerFileDependencySet.add(aFileName)
960 # Check if a module dependency header file is missing from the module's MetaFile
961 for aFile in headerFileDependencySet:
962 if aFile in headerFilesInMetaFileSet:
964 if GlobalData.gUseHashCache:
965 GlobalData.gModuleBuildTracking[self._AutoGenObject] = 'FAIL_METAFILE'
966 EdkLogger.warn("build
","Module MetaFile
[Sources
] is missing local header
!",
967 ExtraData = "Local Header
: " + aFile + " not found
in " + self._AutoGenObject.MetaFile.Path
970 for File,Dependency in FileDependencyDict.items():
974 self._AutoGenObject.AutoGenDepSet |= set(Dependency)
979 DependencyDict = FileDependencyDict.copy()
981 # Convert target description object to target string in makefile
982 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and TAB_C_CODE_FILE in self._AutoGenObject.Targets:
983 for T in self._AutoGenObject.Targets[TAB_C_CODE_FILE]:
984 NewFile = self.PlaceMacro(str(T), self.Macros)
985 if not self.ObjTargetDict.get(T.Target.SubDir):
986 self.ObjTargetDict[T.Target.SubDir] = set()
987 self.ObjTargetDict[T.Target.SubDir].add(NewFile)
988 for Type in self._AutoGenObject.Targets:
989 for T in self._AutoGenObject.Targets[Type]:
990 # Generate related macros if needed
991 if T.GenFileListMacro and T.FileListMacro not in self.FileListMacros:
992 self.FileListMacros[T.FileListMacro] = []
993 if T.GenListFile and T.ListFileMacro not in self.ListFileMacros:
994 self.ListFileMacros[T.ListFileMacro] = []
995 if T.GenIncListFile and T.IncListFileMacro not in self.ListFileMacros:
996 self.ListFileMacros[T.IncListFileMacro] = []
1000 # Add force-dependencies
1001 for Dep in T.Dependencies:
1002 Deps.append(self.PlaceMacro(str(Dep), self.Macros))
1003 if Dep != '$(MAKE_FILE)':
1004 CCodeDeps.append(self.PlaceMacro(str(Dep), self.Macros))
1005 # Add inclusion-dependencies
1006 if len(T.Inputs) == 1 and T.Inputs[0] in FileDependencyDict:
1007 for F in FileDependencyDict[T.Inputs[0]]:
1008 Deps.append(self.PlaceMacro(str(F), self.Macros))
1009 # Add source-dependencies
1011 NewFile = self.PlaceMacro(str(F), self.Macros)
1012 # In order to use file list macro as dependency
1014 # gnu tools need forward slash path separator, even on Windows
1015 self.ListFileMacros[T.ListFileMacro].append(str(F).replace ('\\', '/'))
1016 self.FileListMacros[T.FileListMacro].append(NewFile)
1017 elif T.GenFileListMacro:
1018 self.FileListMacros[T.FileListMacro].append(NewFile)
1020 Deps.append(NewFile)
1021 for key in self.FileListMacros:
1022 self.FileListMacros[key].sort()
1023 # Use file list macro as dependency
1024 if T.GenFileListMacro:
1025 Deps.append("$
(%s)" % T.FileListMacro)
1026 if Type in [TAB_OBJECT_FILE, TAB_STATIC_LIBRARY]:
1027 Deps.append("$
(%s)" % T.ListFileMacro)
1029 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Type == TAB_C_CODE_FILE:
1030 T, CmdTarget, CmdTargetDict, CmdCppDict = self.ParserCCodeFile(T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict)
1031 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": CCodeDeps}
1032 CmdLine = self._BUILD_TARGET_TEMPLATE.Replace(TargetDict).rstrip().replace('\t$(OBJLIST', '$(OBJLIST')
1034 CmdLine = '%s%s' %(CmdLine, TAB_LINE_BREAK)
1035 if CCodeDeps or CmdLine:
1036 self.BuildTargetList.append(CmdLine)
1038 TargetDict = {"target
": self.PlaceMacro(T.Target.Path, self.Macros), "cmd
": "\n\t".join(T.Commands),"deps
": Deps}
1039 self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(TargetDict))
1041 def ParserCCodeFile(self, T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict):
1043 for item in self._AutoGenObject.Targets[Type]:
1044 CmdSumDict[item.Target.SubDir] = item.Target.BaseName
1045 for CppPath in item.Inputs:
1046 Path = self.PlaceMacro(CppPath.Path, self.Macros)
1047 if CmdCppDict.get(item.Target.SubDir):
1048 CmdCppDict[item.Target.SubDir].append(Path)
1050 CmdCppDict[item.Target.SubDir] = ['$(MAKE_FILE)', Path]
1051 if CppPath.Path in DependencyDict:
1052 for Temp in DependencyDict[CppPath.Path]:
1054 Path = self.PlaceMacro(Temp.Path, self.Macros)
1057 if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):
1058 CmdCppDict[item.Target.SubDir].append(Path)
1060 CommandList = T.Commands[:]
1061 for Item in CommandList[:]:
1062 SingleCommandList = Item.split()
1063 if len(SingleCommandList) > 0 and self.CheckCCCmd(SingleCommandList):
1064 for Temp in SingleCommandList:
1065 if Temp.startswith('/Fo'):
1066 CmdSign = '%s%s' % (Temp.rsplit(TAB_SLASH, 1)[0], TAB_SLASH)
1069 if CmdSign not in list(CmdTargetDict.keys()):
1070 CmdTargetDict[CmdSign] = Item.replace(Temp, CmdSign)
1072 CmdTargetDict[CmdSign] = "%s %s" % (CmdTargetDict[CmdSign], SingleCommandList[-1])
1073 Index = CommandList.index(Item)
1074 CommandList.pop(Index)
1075 if SingleCommandList[-1].endswith("%s%s.c
" % (TAB_SLASH, CmdSumDict[CmdSign[3:].rsplit(TAB_SLASH, 1)[0]])):
1076 Cpplist = CmdCppDict[T.Target.SubDir]
1077 Cpplist.insert(0, '$(OBJLIST_%d): ' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir))
1078 T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign])
1080 T.Commands.pop(Index)
1081 return T, CmdSumDict, CmdTargetDict, CmdCppDict
1083 def CheckCCCmd(self, CommandList):
1084 for cmd in CommandList:
1088 ## For creating makefile targets for dependent libraries
1089 def ProcessDependentLibrary(self):
1090 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1091 if not LibraryAutoGen.IsBinaryModule:
1092 self.LibraryBuildDirectoryList.append(self.PlaceMacro(LibraryAutoGen.BuildDir, self.Macros))
1094 ## Return a list containing source file's dependencies
1096 # @param FileList The list of source files
1097 # @param ForceInculeList The list of files which will be included forcely
1098 # @param SearchPathList The list of search path
1100 # @retval dict The mapping between source file path and its dependencies
1102 def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):
1105 Dependency[F] = GetDependencyList(self._AutoGenObject, self.FileCache, F, ForceInculeList, SearchPathList)
1109 ## CustomMakefile class
1111 # This class encapsules makefie and its generation for module. It uses template to generate
1112 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
1114 class CustomMakefile(BuildFile):
1115 ## template used to generate the makefile for module with custom makefile
1116 _TEMPLATE_ = TemplateString('''\
1120 # Platform Macro Definition
1122 PLATFORM_NAME = ${platform_name}
1123 PLATFORM_GUID = ${platform_guid}
1124 PLATFORM_VERSION = ${platform_version}
1125 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
1126 PLATFORM_DIR = ${platform_dir}
1127 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1130 # Module Macro Definition
1132 MODULE_NAME = ${module_name}
1133 MODULE_GUID = ${module_guid}
1134 MODULE_NAME_GUID = ${module_name_guid}
1135 MODULE_VERSION = ${module_version}
1136 MODULE_TYPE = ${module_type}
1137 MODULE_FILE = ${module_file}
1138 MODULE_FILE_BASE_NAME = ${module_file_base_name}
1139 BASE_NAME = $(MODULE_NAME)
1140 MODULE_RELATIVE_DIR = ${module_relative_directory}
1141 MODULE_DIR = ${module_dir}
1144 # Build Configuration Macro Definition
1146 ARCH = ${architecture}
1147 TOOLCHAIN = ${toolchain_tag}
1148 TOOLCHAIN_TAG = ${toolchain_tag}
1149 TARGET = ${build_target}
1152 # Build Directory Macro Definition
1154 # PLATFORM_BUILD_DIR = ${platform_build_directory}
1155 BUILD_DIR = ${platform_build_directory}
1156 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
1157 LIB_DIR = $(BIN_DIR)
1158 MODULE_BUILD_DIR = ${module_build_directory}
1159 OUTPUT_DIR = ${module_output_directory}
1160 DEBUG_DIR = ${module_debug_directory}
1161 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
1162 DEST_DIR_DEBUG = $(DEBUG_DIR)
1165 # Tools definitions specific to this module
1167 ${BEGIN}${module_tool_definitions}
1169 MAKE_FILE = ${makefile_path}
1172 # Shell Command Macro
1174 ${BEGIN}${shell_command_code} = ${shell_command}
1177 ${custom_makefile_content}
1180 # Target used when called from platform makefile, which will bypass the build of dependent libraries
1193 # Build Target used in multi-thread build mode, which no init target is needed
1199 # Initialization target: print build information and create necessary directories
1202 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
1203 ${BEGIN}\t-@${create_directory_command}\n${END}\
1207 ## Constructor of CustomMakefile
1209 # @param ModuleAutoGen Object of ModuleAutoGen class
1211 def __init__(self, ModuleAutoGen):
1212 BuildFile.__init__(self, ModuleAutoGen)
1213 self.PlatformInfo = self._AutoGenObject.PlatformInfo
1214 self.IntermediateDirectoryList = ["$
(DEBUG_DIR
)", "$
(OUTPUT_DIR
)"]
1215 self.DependencyHeaderFileSet = set()
1217 # Compose a dict object containing information used to do replacement in template
1219 def _TemplateDict(self):
1220 Separator = self._SEP_[self._FileType]
1221 MyAgo = self._AutoGenObject
1222 if self._FileType not in MyAgo.CustomMakefile:
1223 EdkLogger.error('build', OPTION_NOT_SUPPORTED, "No custom makefile
for %s" % self._FileType,
1224 ExtraData="[%s]" % str(MyAgo))
1225 MakefilePath = mws.join(
1227 MyAgo.CustomMakefile[self._FileType]
1230 CustomMakefile = open(MakefilePath, 'r').read()
1232 EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(MyAgo),
1233 ExtraData=MyAgo.CustomMakefile[self._FileType])
1237 for Tool in MyAgo.BuildOption:
1238 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
1241 for Attr in MyAgo.BuildOption[Tool]:
1242 if Attr == "FAMILY
":
1244 elif Attr == "PATH
":
1245 ToolsDef.append("%s = %s" % (Tool, MyAgo.BuildOption[Tool][Attr]))
1247 ToolsDef.append("%s_%s = %s" % (Tool, Attr, MyAgo.BuildOption[Tool][Attr]))
1250 MakefileName = self._FILE_NAME_[self._FileType]
1251 MakefileTemplateDict = {
1252 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1253 "makefile_path
" : os.path.join("$
(MODULE_BUILD_DIR
)", MakefileName),
1254 "platform_name
" : self.PlatformInfo.Name,
1255 "platform_guid
" : self.PlatformInfo.Guid,
1256 "platform_version
" : self.PlatformInfo.Version,
1257 "platform_relative_directory
": self.PlatformInfo.SourceDir,
1258 "platform_output_directory
" : self.PlatformInfo.OutputDir,
1259 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1261 "module_name
" : MyAgo.Name,
1262 "module_guid
" : MyAgo.Guid,
1263 "module_name_guid
" : MyAgo.UniqueBaseName,
1264 "module_version
" : MyAgo.Version,
1265 "module_type
" : MyAgo.ModuleType,
1266 "module_file
" : MyAgo.MetaFile,
1267 "module_file_base_name
" : MyAgo.MetaFile.BaseName,
1268 "module_relative_directory
" : MyAgo.SourceDir,
1269 "module_dir
" : mws.join (MyAgo.WorkspaceDir, MyAgo.SourceDir),
1271 "architecture
" : MyAgo.Arch,
1272 "toolchain_tag
" : MyAgo.ToolChain,
1273 "build_target
" : MyAgo.BuildTarget,
1275 "platform_build_directory
" : self.PlatformInfo.BuildDir,
1276 "module_build_directory
" : MyAgo.BuildDir,
1277 "module_output_directory
" : MyAgo.OutputDir,
1278 "module_debug_directory
" : MyAgo.DebugDir,
1280 "separator
" : Separator,
1281 "module_tool_definitions
" : ToolsDef,
1283 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1284 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1286 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1287 "custom_makefile_content
" : CustomMakefile
1290 return MakefileTemplateDict
1292 ## PlatformMakefile class
1294 # This class encapsules makefie and its generation for platform. It uses
1295 # template to generate the content of makefile. The content of makefile will be
1296 # got from PlatformAutoGen object.
1298 class PlatformMakefile(BuildFile):
1299 ## template used to generate the makefile for platform
1300 _TEMPLATE_ = TemplateString('''\
1304 # Platform Macro Definition
1306 PLATFORM_NAME = ${platform_name}
1307 PLATFORM_GUID = ${platform_guid}
1308 PLATFORM_VERSION = ${platform_version}
1309 PLATFORM_FILE = ${platform_file}
1310 PLATFORM_DIR = ${platform_dir}
1311 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1314 # Build Configuration Macro Definition
1316 TOOLCHAIN = ${toolchain_tag}
1317 TOOLCHAIN_TAG = ${toolchain_tag}
1318 TARGET = ${build_target}
1321 # Build Directory Macro Definition
1323 BUILD_DIR = ${platform_build_directory}
1324 FV_DIR = ${platform_build_directory}${separator}FV
1327 # Shell Command Macro
1329 ${BEGIN}${shell_command_code} = ${shell_command}
1333 MAKE_FILE = ${makefile_path}
1338 all: init build_libraries build_modules
1341 # Initialization target: print build information and create necessary directories
1344 \t-@echo Building ... $(PLATFORM_FILE) [${build_architecture_list}]
1345 \t${BEGIN}-@${create_directory_command}
1348 # library build target
1350 libraries: init build_libraries
1353 # module build target
1355 modules: init build_libraries build_modules
1358 # Build all libraries:
1361 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${library_makefile_list} pbuild
1362 ${END}\t@cd $(BUILD_DIR)
1365 # Build all modules:
1368 ${BEGIN}\t@"$
(MAKE
)" $(MAKE_FLAGS) -f ${module_makefile_list} pbuild
1369 ${END}\t@cd $(BUILD_DIR)
1372 # Clean intermediate files
1375 \t${BEGIN}-@${library_build_command} clean
1376 \t${END}${BEGIN}-@${module_build_command} clean
1377 \t${END}@cd $(BUILD_DIR)
1380 # Clean all generated files except to makefile
1383 ${BEGIN}\t${cleanall_command}
1387 # Clean all library files
1390 \t${BEGIN}-@${library_build_command} cleanall
1391 \t${END}@cd $(BUILD_DIR)\n
1394 ## Constructor of PlatformMakefile
1396 # @param ModuleAutoGen Object of PlatformAutoGen class
1398 def __init__(self, PlatformAutoGen):
1399 BuildFile.__init__(self, PlatformAutoGen)
1400 self.ModuleBuildCommandList = []
1401 self.ModuleMakefileList = []
1402 self.IntermediateDirectoryList = []
1403 self.ModuleBuildDirectoryList = []
1404 self.LibraryBuildDirectoryList = []
1405 self.LibraryMakeCommandList = []
1406 self.DependencyHeaderFileSet = set()
1408 # Compose a dict object containing information used to do replacement in template
1410 def _TemplateDict(self):
1411 Separator = self._SEP_[self._FileType]
1413 MyAgo = self._AutoGenObject
1414 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1415 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1416 ExtraData="[%s]" % str(MyAgo))
1418 self.IntermediateDirectoryList = ["$
(BUILD_DIR
)"]
1419 self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()
1420 self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()
1422 MakefileName = self._FILE_NAME_[self._FileType]
1423 LibraryMakefileList = []
1424 LibraryMakeCommandList = []
1425 for D in self.LibraryBuildDirectoryList:
1426 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1427 Makefile = os.path.join(D, MakefileName)
1428 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1429 LibraryMakefileList.append(Makefile)
1430 LibraryMakeCommandList.append(Command)
1431 self.LibraryMakeCommandList = LibraryMakeCommandList
1433 ModuleMakefileList = []
1434 ModuleMakeCommandList = []
1435 for D in self.ModuleBuildDirectoryList:
1436 D = self.PlaceMacro(D, {"BUILD_DIR
":MyAgo.BuildDir})
1437 Makefile = os.path.join(D, MakefileName)
1438 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1439 ModuleMakefileList.append(Makefile)
1440 ModuleMakeCommandList.append(Command)
1442 MakefileTemplateDict = {
1443 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1444 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1445 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1446 "makefile_name
" : MakefileName,
1447 "platform_name
" : MyAgo.Name,
1448 "platform_guid
" : MyAgo.Guid,
1449 "platform_version
" : MyAgo.Version,
1450 "platform_file
" : MyAgo.MetaFile,
1451 "platform_relative_directory
": MyAgo.SourceDir,
1452 "platform_output_directory
" : MyAgo.OutputDir,
1453 "platform_build_directory
" : MyAgo.BuildDir,
1454 "platform_dir
" : MyAgo.Macros["PLATFORM_DIR
"],
1456 "toolchain_tag
" : MyAgo.ToolChain,
1457 "build_target
" : MyAgo.BuildTarget,
1458 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1459 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1460 "build_architecture_list
" : MyAgo.Arch,
1461 "architecture
" : MyAgo.Arch,
1462 "separator
" : Separator,
1463 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1464 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1465 "library_makefile_list
" : LibraryMakefileList,
1466 "module_makefile_list
" : ModuleMakefileList,
1467 "library_build_command
" : LibraryMakeCommandList,
1468 "module_build_command
" : ModuleMakeCommandList,
1471 return MakefileTemplateDict
1473 ## Get the root directory list for intermediate files of all modules build
1475 # @retval list The list of directory
1477 def GetModuleBuildDirectoryList(self):
1479 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1480 if not ModuleAutoGen.IsBinaryModule:
1481 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1484 ## Get the root directory list for intermediate files of all libraries build
1486 # @retval list The list of directory
1488 def GetLibraryBuildDirectoryList(self):
1490 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1491 if not LibraryAutoGen.IsBinaryModule:
1492 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1495 ## TopLevelMakefile class
1497 # This class encapsules makefie and its generation for entrance makefile. It
1498 # uses template to generate the content of makefile. The content of makefile
1499 # will be got from WorkspaceAutoGen object.
1501 class TopLevelMakefile(BuildFile):
1502 ## template used to generate toplevel makefile
1503 _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}''')
1505 ## Constructor of TopLevelMakefile
1507 # @param Workspace Object of WorkspaceAutoGen class
1509 def __init__(self, Workspace):
1510 BuildFile.__init__(self, Workspace)
1511 self.IntermediateDirectoryList = []
1512 self.DependencyHeaderFileSet = set()
1514 # Compose a dict object containing information used to do replacement in template
1516 def _TemplateDict(self):
1517 Separator = self._SEP_[self._FileType]
1519 # any platform autogen object is ok because we just need common information
1520 MyAgo = self._AutoGenObject
1522 if "MAKE
" not in MyAgo.ToolDefinition or "PATH
" not in MyAgo.ToolDefinition["MAKE
"]:
1523 EdkLogger.error("build
", OPTION_MISSING, "No MAKE command defined
. Please check your tools_def
.txt
!",
1524 ExtraData="[%s]" % str(MyAgo))
1526 for Arch in MyAgo.ArchList:
1527 self.IntermediateDirectoryList.append(Separator.join(["$
(BUILD_DIR
)", Arch]))
1528 self.IntermediateDirectoryList.append("$
(FV_DIR
)")
1530 # TRICK: for not generating GenFds call in makefile if no FDF file
1532 if MyAgo.FdfFile is not None and MyAgo.FdfFile != "":
1533 FdfFileList = [MyAgo.FdfFile]
1534 # macros passed to GenFds
1536 MacroDict.update(GlobalData.gGlobalDefines)
1537 MacroDict.update(GlobalData.gCommandLineDefines)
1538 for MacroName in MacroDict:
1539 if MacroDict[MacroName] != "":
1540 MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
1542 MacroList.append('"%s"' % MacroName)
1546 # pass extra common options to external program called in makefile, currently GenFds.exe
1548 LogLevel = EdkLogger.GetLevel()
1549 if LogLevel == EdkLogger.VERBOSE:
1550 ExtraOption += " -v
"
1551 elif LogLevel <= EdkLogger.DEBUG_9:
1552 ExtraOption += " -d
%d" % (LogLevel - 1)
1553 elif LogLevel == EdkLogger.QUIET:
1554 ExtraOption += " -q
"
1556 if GlobalData.gCaseInsensitive:
1557 ExtraOption += " -c
"
1558 if not GlobalData.gEnableGenfdsMultiThread:
1559 ExtraOption += " --no
-genfds
-multi
-thread
"
1560 if GlobalData.gIgnoreSource:
1561 ExtraOption += " --ignore
-sources
"
1563 for pcd in GlobalData.BuildOptionPcd:
1565 pcdname = '.'.join(pcd[0:3])
1567 pcdname = '.'.join(pcd[0:2])
1568 if pcd[3].startswith('{'):
1569 ExtraOption += " --pcd
" + pcdname + '=' + 'H' + '"' + pcd[3] + '"'
1571 ExtraOption += " --pcd
" + pcdname + '=' + pcd[3]
1573 MakefileName = self._FILE_NAME_[self._FileType]
1574 SubBuildCommandList = []
1575 for A in MyAgo.ArchList:
1576 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join("$
(BUILD_DIR
)", A, MakefileName)}
1577 SubBuildCommandList.append(Command)
1579 MakefileTemplateDict = {
1580 "makefile_header
" : self._FILE_HEADER_[self._FileType],
1581 "makefile_path
" : os.path.join("$
(BUILD_DIR
)", MakefileName),
1582 "make_path
" : MyAgo.ToolDefinition["MAKE
"]["PATH
"],
1583 "platform_name
" : MyAgo.Name,
1584 "platform_guid
" : MyAgo.Guid,
1585 "platform_version
" : MyAgo.Version,
1586 "platform_build_directory
" : MyAgo.BuildDir,
1587 "conf_directory
" : GlobalData.gConfDirectory,
1589 "toolchain_tag
" : MyAgo.ToolChain,
1590 "build_target
" : MyAgo.BuildTarget,
1591 "shell_command_code
" : list(self._SHELL_CMD_[self._FileType].keys()),
1592 "shell_command
" : list(self._SHELL_CMD_[self._FileType].values()),
1593 'arch' : list(MyAgo.ArchList),
1594 "build_architecture_list
" : ','.join(MyAgo.ArchList),
1595 "separator
" : Separator,
1596 "create_directory_command
" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1597 "cleanall_command
" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1598 "sub_build_command
" : SubBuildCommandList,
1599 "fdf_file
" : FdfFileList,
1600 "active_platform
" : str(MyAgo),
1601 "fd
" : MyAgo.FdTargetList,
1602 "fv
" : MyAgo.FvTargetList,
1603 "cap
" : MyAgo.CapTargetList,
1604 "extra_options
" : ExtraOption,
1605 "macro
" : MacroList,
1608 return MakefileTemplateDict
1610 ## Get the root directory list for intermediate files of all modules build
1612 # @retval list The list of directory
1614 def GetModuleBuildDirectoryList(self):
1616 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1617 if not ModuleAutoGen.IsBinaryModule:
1618 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1621 ## Get the root directory list for intermediate files of all libraries build
1623 # @retval list The list of directory
1625 def GetLibraryBuildDirectoryList(self):
1627 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1628 if not LibraryAutoGen.IsBinaryModule:
1629 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1632 ## Find dependencies for one source file
1634 # By searching recursively "#include" directive in file, find out all the
1635 # files needed by given source file. The dependencies will be only searched
1636 # in given search path list.
1638 # @param File The source file
1639 # @param ForceInculeList The list of files which will be included forcely
1640 # @param SearchPathList The list of search path
1642 # @retval list The list of files the given source file depends on
1644 def GetDependencyList(AutoGenObject
, FileCache
, File
, ForceList
, SearchPathList
):
1645 EdkLogger
.debug(EdkLogger
.DEBUG_1
, "Try to get dependency files for %s" % File
)
1646 FileStack
= [File
] + ForceList
1647 DependencySet
= set()
1649 if AutoGenObject
.Arch
not in gDependencyDatabase
:
1650 gDependencyDatabase
[AutoGenObject
.Arch
] = {}
1651 DepDb
= gDependencyDatabase
[AutoGenObject
.Arch
]
1653 while len(FileStack
) > 0:
1656 FullPathDependList
= []
1658 for CacheFile
in FileCache
[F
]:
1659 FullPathDependList
.append(CacheFile
)
1660 if CacheFile
not in DependencySet
:
1661 FileStack
.append(CacheFile
)
1662 DependencySet
.update(FullPathDependList
)
1665 CurrentFileDependencyList
= []
1667 CurrentFileDependencyList
= DepDb
[F
]
1670 Fd
= open(F
.Path
, 'rb')
1671 FileContent
= Fd
.read()
1673 except BaseException
as X
:
1674 EdkLogger
.error("build", FILE_OPEN_FAILURE
, ExtraData
=F
.Path
+ "\n\t" + str(X
))
1675 if len(FileContent
) == 0:
1678 if FileContent
[0] == 0xff or FileContent
[0] == 0xfe:
1679 FileContent
= FileContent
.decode('utf-16')
1681 FileContent
= FileContent
.decode()
1683 # The file is not txt file. for example .mcb file
1685 IncludedFileList
= gIncludePattern
.findall(FileContent
)
1687 for Inc
in IncludedFileList
:
1689 # if there's macro used to reference header file, expand it
1690 HeaderList
= gMacroPattern
.findall(Inc
)
1691 if len(HeaderList
) == 1 and len(HeaderList
[0]) == 2:
1692 HeaderType
= HeaderList
[0][0]
1693 HeaderKey
= HeaderList
[0][1]
1694 if HeaderType
in gIncludeMacroConversion
:
1695 Inc
= gIncludeMacroConversion
[HeaderType
] % {"HeaderKey" : HeaderKey
}
1697 # not known macro used in #include, always build the file by
1698 # returning a empty dependency
1699 FileCache
[File
] = []
1701 Inc
= os
.path
.normpath(Inc
)
1702 CurrentFileDependencyList
.append(Inc
)
1703 DepDb
[F
] = CurrentFileDependencyList
1705 CurrentFilePath
= F
.Dir
1706 PathList
= [CurrentFilePath
] + SearchPathList
1707 for Inc
in CurrentFileDependencyList
:
1708 for SearchPath
in PathList
:
1709 FilePath
= os
.path
.join(SearchPath
, Inc
)
1710 if FilePath
in gIsFileMap
:
1711 if not gIsFileMap
[FilePath
]:
1713 # If isfile is called too many times, the performance is slow down.
1714 elif not os
.path
.isfile(FilePath
):
1715 gIsFileMap
[FilePath
] = False
1718 gIsFileMap
[FilePath
] = True
1719 FilePath
= PathClass(FilePath
)
1720 FullPathDependList
.append(FilePath
)
1721 if FilePath
not in DependencySet
:
1722 FileStack
.append(FilePath
)
1725 EdkLogger
.debug(EdkLogger
.DEBUG_9
, "%s included by %s was not found "\
1726 "in any given path:\n\t%s" % (Inc
, F
, "\n\t".join(SearchPathList
)))
1728 FileCache
[F
] = FullPathDependList
1729 DependencySet
.update(FullPathDependList
)
1731 DependencySet
.update(ForceList
)
1732 if File
in DependencySet
:
1733 DependencySet
.remove(File
)
1734 DependencyList
= list(DependencySet
) # remove duplicate ones
1736 return DependencyList
1738 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1739 if __name__
== '__main__':