]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/AutoGen/GenMake.py
f5d15c40ad3196e5ea56f375bec12c38d313c9ee
[mirror_edk2.git] / BaseTools / Source / Python / AutoGen / GenMake.py
1 ## @file
2 # Create makefile for MS nmake and GNU make
3 #
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
7 #
8
9 ## Import Modules
10 #
11 from __future__ import absolute_import
12 import Common.LongFilePathOs as os
13 import sys
14 import string
15 import re
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
26
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)
29
30 ## Regular expression for matching macro used in header file inclusion
31 gMacroPattern = re.compile("([_A-Z][_A-Z0-9]*)[ \t]*\((.+)\)", re.UNICODE)
32
33 gIsFileMap = {}
34
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,
54 }
55
56 NMAKE_FILETYPE = "nmake"
57 GMAKE_FILETYPE = "gmake"
58 WIN32_PLATFORM = "win32"
59 POSIX_PLATFORM = "posix"
60
61 ## BuildFile class
62 #
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.
65 #
66 class BuildFile(object):
67 ## template used to generate the build file (i.e. makefile if using make)
68 _TEMPLATE_ = TemplateString('')
69
70 _DEFAULT_FILE_NAME_ = "Makefile"
71
72 ## default file name for each type of build file
73 _FILE_NAME_ = {
74 NMAKE_FILETYPE : "Makefile",
75 GMAKE_FILETYPE : "GNUmakefile"
76 }
77
78 # Get Makefile name.
79 def getMakefileName(self):
80 if not self._FileType:
81 return self._DEFAULT_FILE_NAME_
82 else:
83 return self._FILE_NAME_[self._FileType]
84
85 ## Fixed header string for makefile
86 _MAKEFILE_HEADER = '''#
87 # DO NOT EDIT
88 # This file is auto-generated by build utility
89 #
90 # Module Name:
91 #
92 # %s
93 #
94 # Abstract:
95 #
96 # Auto-generated makefile for building modules, libraries or platform
97 #
98 '''
99
100 ## Header string for each type of build file
101 _FILE_HEADER_ = {
102 NMAKE_FILETYPE : _MAKEFILE_HEADER % _FILE_NAME_[NMAKE_FILETYPE],
103 GMAKE_FILETYPE : _MAKEFILE_HEADER % _FILE_NAME_[GMAKE_FILETYPE]
104 }
105
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
112 #
113 _SHELL_CMD_ = {
114 WIN32_PLATFORM : {
115 "CP" : "copy /y",
116 "MV" : "move /y",
117 "RM" : "del /f /q",
118 "MD" : "mkdir",
119 "RD" : "rmdir /s /q",
120 },
121
122 POSIX_PLATFORM : {
123 "CP" : "cp -f",
124 "MV" : "mv -f",
125 "RM" : "rm -f",
126 "MD" : "mkdir -p",
127 "RD" : "rm -r -f",
128 }
129 }
130
131 ## directory separator
132 _SEP_ = {
133 WIN32_PLATFORM : "\\",
134 POSIX_PLATFORM : "/"
135 }
136
137 ## directory creation template
138 _MD_TEMPLATE_ = {
139 WIN32_PLATFORM : 'if not exist %(dir)s $(MD) %(dir)s',
140 POSIX_PLATFORM : "$(MD) %(dir)s"
141 }
142
143 ## directory removal template
144 _RD_TEMPLATE_ = {
145 WIN32_PLATFORM : 'if exist %(dir)s $(RD) %(dir)s',
146 POSIX_PLATFORM : "$(RD) %(dir)s"
147 }
148 ## cp if exist
149 _CP_TEMPLATE_ = {
150 WIN32_PLATFORM : 'if exist %(Src)s $(CP) %(Src)s %(Dst)s',
151 POSIX_PLATFORM : "test -f %(Src)s && $(CP) %(Src)s %(Dst)s"
152 }
153
154 _CD_TEMPLATE_ = {
155 WIN32_PLATFORM : 'if exist %(dir)s cd %(dir)s',
156 POSIX_PLATFORM : "test -e %(dir)s && cd %(dir)s"
157 }
158
159 _MAKE_TEMPLATE_ = {
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'
162 }
163
164 _INCLUDE_CMD_ = {
165 NMAKE_FILETYPE : '!INCLUDE',
166 GMAKE_FILETYPE : "include"
167 }
168
169 _INC_FLAG_ = {TAB_COMPILER_MSFT : "/I", "GCC" : "-I", "INTEL" : "-I", "RVCT" : "-I", "NASM" : "-I"}
170
171 ## Constructor of BuildFile
172 #
173 # @param AutoGenObject Object of AutoGen class
174 #
175 def __init__(self, AutoGenObject):
176 self._AutoGenObject = AutoGenObject
177
178 MakePath = AutoGenObject.BuildOption.get('MAKE', {}).get('PATH')
179 if not MakePath:
180 self._FileType = ""
181 elif "nmake" in MakePath:
182 self._FileType = NMAKE_FILETYPE
183 else:
184 self._FileType = "gmake"
185
186 if sys.platform == "win32":
187 self._Platform = WIN32_PLATFORM
188 else:
189 self._Platform = POSIX_PLATFORM
190
191 ## Create build file.
192 #
193 # Only nmake and gmake are supported.
194 #
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.
197 #
198 def Generate(self):
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:
203 fd.write("")
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:
206 fd.write("")
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:
209 fd.write("")
210 return SaveFileOnChange(os.path.join(self._AutoGenObject.MakeFileDir, FileName), FileContent, False)
211
212 ## Return a list of directory creation command string
213 #
214 # @param DirList The list of directory to be created
215 #
216 # @retval list The directory creation command list
217 #
218 def GetCreateDirectoryCommand(self, DirList):
219 return [self._MD_TEMPLATE_[self._Platform] % {'dir':Dir} for Dir in DirList]
220
221 ## Return a list of directory removal command string
222 #
223 # @param DirList The list of directory to be removed
224 #
225 # @retval list The directory removal command list
226 #
227 def GetRemoveDirectoryCommand(self, DirList):
228 return [self._RD_TEMPLATE_[self._Platform] % {'dir':Dir} for Dir in DirList]
229
230 def PlaceMacro(self, Path, MacroDefinitions=None):
231 if Path.startswith("$("):
232 return Path
233 else:
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:
241 continue
242 if MacroValueLength <= PathLength and Path.startswith(MacroValue):
243 Path = "$(%s)%s" % (MacroName, Path[MacroValueLength:])
244 break
245 return Path
246
247 ## ModuleMakefile class
248 #
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.
251 #
252 class ModuleMakefile(BuildFile):
253 ## template used to generate the makefile for module
254 _TEMPLATE_ = TemplateString('''\
255 ${makefile_header}
256
257 #
258 # Platform Macro Definition
259 #
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}
266
267 #
268 # Module Macro Definition
269 #
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}
282
283 MODULE_ENTRY_POINT = ${module_entry_point}
284 ARCH_ENTRY_POINT = ${arch_entry_point}
285 IMAGE_ENTRY_POINT = ${image_entry_point}
286
287 ${BEGIN}${module_extra_defines}
288 ${END}
289 #
290 # Build Configuration Macro Definition
291 #
292 ARCH = ${architecture}
293 TOOLCHAIN = ${toolchain_tag}
294 TOOLCHAIN_TAG = ${toolchain_tag}
295 TARGET = ${build_target}
296
297 #
298 # Build Directory Macro Definition
299 #
300 # PLATFORM_BUILD_DIR = ${platform_build_directory}
301 BUILD_DIR = ${platform_build_directory}
302 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
303 LIB_DIR = $(BIN_DIR)
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)
309
310 #
311 # Shell Command Macro
312 #
313 ${BEGIN}${shell_command_code} = ${shell_command}
314 ${END}
315
316 #
317 # Tools definitions specific to this module
318 #
319 ${BEGIN}${module_tool_definitions}
320 ${END}
321 MAKE_FILE = ${makefile_path}
322
323 #
324 # Build Macro
325 #
326 ${BEGIN}${file_macro}
327 ${END}
328
329 #
330 # Overridable Target Macro Definitions
331 #
332 FORCE_REBUILD = force_build
333 INIT_TARGET = init
334 PCH_TARGET =
335 BC_TARGET = ${BEGIN}${backward_compatible_target} ${END}
336 CODA_TARGET = ${BEGIN}${remaining_build_target} \\
337 ${END}
338
339 #
340 # Default target, which will build dependent libraries in addition to source files
341 #
342
343 all: mbuild
344
345
346 #
347 # Target used when called from platform makefile, which will bypass the build of dependent libraries
348 #
349
350 pbuild: $(INIT_TARGET) $(BC_TARGET) $(PCH_TARGET) $(CODA_TARGET)
351
352 #
353 # ModuleTarget
354 #
355
356 mbuild: $(INIT_TARGET) $(BC_TARGET) gen_libs $(PCH_TARGET) $(CODA_TARGET)
357
358 #
359 # Build Target used in multi-thread build mode, which will bypass the init and gen_libs targets
360 #
361
362 tbuild: $(BC_TARGET) $(PCH_TARGET) $(CODA_TARGET)
363
364 #
365 # Phony target which is used to force executing commands for a target
366 #
367 force_build:
368 \t-@
369
370 #
371 # Target to update the FD
372 #
373
374 fds: mbuild gen_fds
375
376 #
377 # Initialization target: print build information and create necessary directories
378 #
379 init: info dirs
380
381 info:
382 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
383
384 dirs:
385 ${BEGIN}\t-@${create_directory_command}\n${END}
386
387 strdefs:
388 \t-@$(CP) $(DEBUG_DIR)${separator}AutoGen.h $(DEBUG_DIR)${separator}$(MODULE_NAME)StrDefs.h
389
390 #
391 # GenLibsTarget
392 #
393 gen_libs:
394 \t${BEGIN}@"$(MAKE)" $(MAKE_FLAGS) -f ${dependent_library_build_directory}${separator}${makefile_name}
395 \t${END}@cd $(MODULE_BUILD_DIR)
396
397 #
398 # Build Flash Device Image
399 #
400 gen_fds:
401 \t@"$(MAKE)" $(MAKE_FLAGS) -f $(BUILD_DIR)${separator}${makefile_name} fds
402 \t@cd $(MODULE_BUILD_DIR)
403
404 ${INCLUDETAG}
405
406 #
407 # Individual Object Build Targets
408 #
409 ${BEGIN}${file_build_target}
410 ${END}
411
412 #
413 # clean all intermediate files
414 #
415 clean:
416 \t${BEGIN}${clean_command}
417 \t${END}\t$(RM) AutoGenTimeStamp
418
419 #
420 # clean all generated files
421 #
422 cleanall:
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
427
428 #
429 # clean all dependent libraries built
430 #
431 cleanlib:
432 \t${BEGIN}-@${library_build_command} cleanall
433 \t${END}@cd $(MODULE_BUILD_DIR)\n\n''')
434
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")
437
438 ## Constructor of ModuleMakefile
439 #
440 # @param ModuleAutoGen Object of ModuleAutoGen class
441 #
442 def __init__(self, ModuleAutoGen):
443 BuildFile.__init__(self, ModuleAutoGen)
444 self.PlatformInfo = self._AutoGenObject.PlatformInfo
445
446 self.ResultFileList = []
447 self.IntermediateDirectoryList = ["$(DEBUG_DIR)", "$(OUTPUT_DIR)"]
448
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()
456 self.FileCache = {}
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()
474
475 # Compose a dict object containing information used to do replacement in template
476 @property
477 def _TemplateDict(self):
478 MyAgo = self._AutoGenObject
479 Separator = self._SEP_[self._Platform]
480
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))
486
487 # convert dependent libraries to build command
488 self.ProcessDependentLibrary()
489 if len(MyAgo.Module.ModuleEntryPointList) > 0:
490 ModuleEntryPoint = MyAgo.Module.ModuleEntryPointList[0]
491 else:
492 ModuleEntryPoint = "_ModuleEntryPoint"
493
494 ArchEntryPoint = ModuleEntryPoint
495
496 if MyAgo.Arch == "EBC":
497 # EBC compiler always use "EfiStart" as entry point. Only applies to EdkII modules
498 ImageEntryPoint = "EfiStart"
499 else:
500 # EdkII modules always use "_ModuleEntryPoint" as entry point
501 ImageEntryPoint = "_ModuleEntryPoint"
502
503 for k, v in MyAgo.Module.Defines.items():
504 if k not in MyAgo.Macros:
505 MyAgo.Macros[k] = v
506
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
513
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
518
519 # tools definitions
520 ToolsDef = []
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]
525 if Attr == "FAMILY":
526 continue
527 elif Attr == "PATH":
528 ToolsDef.append("%s = %s" % (Tool, Value))
529 else:
530 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
531 if Tool == "MAKE":
532 continue
533 # Remove duplicated include path, if any
534 if Attr == "FLAGS":
535 Value = RemoveDupOption(Value, IncPrefix, MyAgo.IncludePathList)
536 if Tool == "OPTROM" and PCI_COMPRESS_Flag:
537 ValueList = Value.split()
538 if ValueList:
539 for i, v in enumerate(ValueList):
540 if '-e' == v:
541 ValueList[i] = '-ec'
542 Value = ' '.join(ValueList)
543
544 ToolsDef.append("%s_%s = %s" % (Tool, Attr, Value))
545 ToolsDef.append("")
546
547 # generate the Response file and Response flag
548 RespDict = self.CommandExceedLimit()
549 RespFileList = os.path.join(MyAgo.OutputDir, 'respfilelist.txt')
550 if RespDict:
551 RespFileListContent = ''
552 for Resp in RespDict:
553 RespFile = os.path.join(MyAgo.OutputDir, str(Resp).lower() + '.txt')
554 StrList = RespDict[Resp].split(' ')
555 UnexpandMacro = []
556 NewStr = []
557 for Str in StrList:
558 if '$' in Str or '-MMD' in Str or '-MF' in Str:
559 UnexpandMacro.append(Str)
560 else:
561 NewStr.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)
569 else:
570 if os.path.exists(RespFileList):
571 os.remove(RespFileList)
572
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))
578
579 self.ProcessBuildTargetList()
580 self.ParserGenerateFfsCmd()
581
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(
586 {
587 "macro_name" : FileListMacro,
588 "source_file" : self.FileListMacros[FileListMacro]
589 }
590 )
591 FileMacroList.append(FileMacro)
592
593 # INC_LIST is special
594 FileMacro = ""
595 IncludePathList = []
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(
601 {
602 "macro_name" : "INC",
603 "source_file" : IncludePathList
604 }
605 )
606 FileMacroList.append(FileMacro)
607 # Add support when compiling .nasm source files
608 IncludePathList = []
609 asmsource = [item for item in MyAgo.SourceFileList if item.File.upper().endswith((".NASM",".ASM",".NASMB","S"))]
610 if asmsource:
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])
619 else:
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}))
623
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))
628 SaveFileOnChange(
629 ListFileName,
630 "\n".join(self.ListFileMacros[ListFileMacro]),
631 False
632 )
633
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))
638
639 BcTargetList = []
640
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)
646
647 package_rel_dir = MyAgo.SourceDir
648 current_dir = self.Macros["WORKSPACE"]
649 found = False
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'):
656 found = True
657 break
658 package_rel_dir = package_rel_dir[index + 1:]
659
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"],
671
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()],
683
684 "architecture" : MyAgo.Arch,
685 "toolchain_tag" : MyAgo.ToolChain,
686 "build_target" : MyAgo.BuildTarget,
687
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,
692
693 "separator" : Separator,
694 "module_tool_definitions" : ToolsDef,
695
696 "shell_command_code" : list(self._SHELL_CMD_[self._Platform].keys()),
697 "shell_command" : list(self._SHELL_CMD_[self._Platform].values()),
698
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")
714 ])
715 }
716
717 return MakefileTemplateDict
718
719 def ParserGenerateFfsCmd(self):
720 #Add Ffs cmd to self.BuildTargetList
721 OutputFile = ''
722 DepsFileList = []
723
724 for Cmd in self.GenFfsList:
725 if Cmd[2]:
726 for CopyCmd in Cmd[2]:
727 Src, Dst = CopyCmd
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})
735
736 FfsCmdList = Cmd[0]
737 for index, Str in enumerate(FfsCmdList):
738 if '-o' == Str:
739 OutputFile = FfsCmdList[index + 1]
740 if '-i' == Str or "-oi" == Str:
741 if DepsFileList == []:
742 DepsFileList = [FfsCmdList[index + 1]]
743 else:
744 DepsFileList.append(FfsCmdList[index + 1])
745 DepsFileString = ' '.join(DepsFileList).strip()
746 if DepsFileString == '':
747 continue
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)
755
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 = []
761
762 def ParseSecCmd(self, OutputFileList, CmdTuple):
763 for OutputFile in OutputFileList:
764 for SecCmdStr in CmdTuple:
765 SecDepsFileList = []
766 SecCmdList = SecCmdStr.split()
767 CmdName = SecCmdList[0]
768 for index, CmdItem in enumerate(SecCmdList):
769 if '-o' == CmdItem and OutputFile == SecCmdList[index + 1]:
770 index = index + 1
771 while index + 1 < len(SecCmdList):
772 if not SecCmdList[index+1].startswith('-'):
773 SecDepsFileList.append(SecCmdList[index + 1])
774 index = 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)
782 break
783 else:
784 continue
785
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 + ')')
790 return str
791
792 def CommandExceedLimit(self):
793 FlagDict = {
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},
801 }
802
803 RespDict = {}
804 FileTypeList = []
805 IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily]
806
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)
813
814 # calculate the command-line length
815 if FileTypeList:
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:
821 Tool = ''
822 SingleCommandLength = len(SingleCommand)
823 SingleCommandList = SingleCommand.split()
824 if len(SingleCommandList) > 0:
825 for Flag in FlagDict:
826 if '$('+ Flag +')' in SingleCommandList[0]:
827 Tool = Flag
828 break
829 if Tool:
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])
847 break
848 else:
849 break
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:
854 Str = item
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])
864 break
865 else:
866 break
867 SingleCommandLength += len(Str)
868
869 if SingleCommandLength > GlobalData.gCommandMaxLength:
870 FlagDict[Tool]['Value'] = True
871
872 # generate the response file content by combine the FLAGS and INC
873 for Flag in FlagDict:
874 if FlagDict[Flag]['Value']:
875 Key = Flag + '_RESP'
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])
889 break
890 else:
891 break
892
893 if self._AutoGenObject.ToolChainFamily == 'GCC':
894 RespDict[Key] = Value.replace('\\', '/')
895 else:
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)
901 return RespDict
902
903 def ProcessBuildTargetList(self):
904 #
905 # Search dependency file list for each source file
906 #
907 ForceIncludedFile = []
908 for File in self._AutoGenObject.AutoGenFileList:
909 if File.Ext == '.h':
910 ForceIncludedFile.append(File)
911 SourceFileList = []
912 OutPutFileList = []
913 for Target in self._AutoGenObject.IntroTargetList:
914 SourceFileList.extend(Target.Inputs)
915 OutPutFileList.extend(Target.Outputs)
916
917 if OutPutFileList:
918 for Item in OutPutFileList:
919 if Item in SourceFileList:
920 SourceFileList.remove(Item)
921
922 FileDependencyDict = {item:ForceIncludedFile for item in SourceFileList}
923
924 for Dependency in FileDependencyDict.values():
925 self.DependencyHeaderFileSet.update(set(Dependency))
926
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())
932
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'):
939 continue
940 headerFilesInMetaFileSet.add(aFileName.lower())
941
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())
946
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'):
957 continue
958 # Exclude autogen files
959 if aFileName in localAutoGenFileSet:
960 continue
961 # Exclude include out of local scope
962 if localSourceDir not in aFileName:
963 continue
964 # Exclude files covered by package includes
965 pathNeeded = True
966 for aIncludePath in parentMetaFileIncludes:
967 if aIncludePath in aFileName:
968 pathNeeded = False
969 break
970 if not pathNeeded:
971 continue
972 # Keep the file to be checked
973 headerFileDependencySet.add(aFileName)
974
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:
978 continue
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
983 )
984
985 for File,Dependency in FileDependencyDict.items():
986 if not Dependency:
987 continue
988
989 self._AutoGenObject.AutoGenDepSet |= set(Dependency)
990
991 CmdSumDict = {}
992 CmdTargetDict = {}
993 CmdCppDict = {}
994 DependencyDict = FileDependencyDict.copy()
995
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] = []
1012
1013 Deps = []
1014 CCodeDeps = []
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
1025 for F in T.Inputs:
1026 NewFile = self.PlaceMacro(str(F), self.Macros)
1027 # In order to use file list macro as dependency
1028 if T.GenListFile:
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)
1034 else:
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)
1043
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')
1048 if T.Commands:
1049 CmdLine = '%s%s' %(CmdLine, TAB_LINE_BREAK)
1050 if CCodeDeps or CmdLine:
1051 self.BuildTargetList.append(CmdLine)
1052 else:
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))
1055
1056 def ParserCCodeFile(self, T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict):
1057 if not CmdSumDict:
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)
1064 else:
1065 CmdCppDict[item.Target.SubDir] = ['$(MAKE_FILE)', Path]
1066 if CppPath.Path in DependencyDict:
1067 for Temp in DependencyDict[CppPath.Path]:
1068 try:
1069 Path = self.PlaceMacro(Temp.Path, self.Macros)
1070 except:
1071 continue
1072 if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):
1073 CmdCppDict[item.Target.SubDir].append(Path)
1074 if T.Commands:
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)
1082 break
1083 else: continue
1084 if CmdSign not in list(CmdTargetDict.keys()):
1085 CmdTargetDict[CmdSign] = Item.replace(Temp, CmdSign)
1086 else:
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])
1094 else:
1095 T.Commands.pop(Index)
1096 return T, CmdSumDict, CmdTargetDict, CmdCppDict
1097
1098 def CheckCCCmd(self, CommandList):
1099 for cmd in CommandList:
1100 if '$(CC)' in cmd:
1101 return True
1102 return False
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))
1108
1109 ## Return a list containing source file's dependencies
1110 #
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
1114 #
1115 # @retval dict The mapping between source file path and its dependencies
1116 #
1117 def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):
1118 Dependency = {}
1119 for F in FileList:
1120 Dependency[F] = GetDependencyList(self._AutoGenObject, self.FileCache, F, ForceInculeList, SearchPathList)
1121 return Dependency
1122
1123
1124 ## CustomMakefile class
1125 #
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.
1128 #
1129 class CustomMakefile(BuildFile):
1130 ## template used to generate the makefile for module with custom makefile
1131 _TEMPLATE_ = TemplateString('''\
1132 ${makefile_header}
1133
1134 #
1135 # Platform Macro Definition
1136 #
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}
1143
1144 #
1145 # Module Macro Definition
1146 #
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}
1157
1158 #
1159 # Build Configuration Macro Definition
1160 #
1161 ARCH = ${architecture}
1162 TOOLCHAIN = ${toolchain_tag}
1163 TOOLCHAIN_TAG = ${toolchain_tag}
1164 TARGET = ${build_target}
1165
1166 #
1167 # Build Directory Macro Definition
1168 #
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)
1178
1179 #
1180 # Tools definitions specific to this module
1181 #
1182 ${BEGIN}${module_tool_definitions}
1183 ${END}
1184 MAKE_FILE = ${makefile_path}
1185
1186 #
1187 # Shell Command Macro
1188 #
1189 ${BEGIN}${shell_command_code} = ${shell_command}
1190 ${END}
1191
1192 ${custom_makefile_content}
1193
1194 #
1195 # Target used when called from platform makefile, which will bypass the build of dependent libraries
1196 #
1197
1198 pbuild: init all
1199
1200
1201 #
1202 # ModuleTarget
1203 #
1204
1205 mbuild: init all
1206
1207 #
1208 # Build Target used in multi-thread build mode, which no init target is needed
1209 #
1210
1211 tbuild: all
1212
1213 #
1214 # Initialization target: print build information and create necessary directories
1215 #
1216 init:
1217 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
1218 ${BEGIN}\t-@${create_directory_command}\n${END}\
1219
1220 ''')
1221
1222 ## Constructor of CustomMakefile
1223 #
1224 # @param ModuleAutoGen Object of ModuleAutoGen class
1225 #
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()
1231
1232 # Compose a dict object containing information used to do replacement in template
1233 @property
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(
1241 MyAgo.WorkspaceDir,
1242 MyAgo.CustomMakefile[self._FileType]
1243 )
1244 try:
1245 CustomMakefile = open(MakefilePath, 'r').read()
1246 except:
1247 EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(MyAgo),
1248 ExtraData=MyAgo.CustomMakefile[self._FileType])
1249
1250 # tools definitions
1251 ToolsDef = []
1252 for Tool in MyAgo.BuildOption:
1253 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
1254 if Tool == "MAKE":
1255 continue
1256 for Attr in MyAgo.BuildOption[Tool]:
1257 if Attr == "FAMILY":
1258 continue
1259 elif Attr == "PATH":
1260 ToolsDef.append("%s = %s" % (Tool, MyAgo.BuildOption[Tool][Attr]))
1261 else:
1262 ToolsDef.append("%s_%s = %s" % (Tool, Attr, MyAgo.BuildOption[Tool][Attr]))
1263 ToolsDef.append("")
1264
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"],
1275
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),
1285
1286 "architecture" : MyAgo.Arch,
1287 "toolchain_tag" : MyAgo.ToolChain,
1288 "build_target" : MyAgo.BuildTarget,
1289
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,
1294
1295 "separator" : Separator,
1296 "module_tool_definitions" : ToolsDef,
1297
1298 "shell_command_code" : list(self._SHELL_CMD_[self._Platform].keys()),
1299 "shell_command" : list(self._SHELL_CMD_[self._Platform].values()),
1300
1301 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1302 "custom_makefile_content" : CustomMakefile
1303 }
1304
1305 return MakefileTemplateDict
1306
1307 ## PlatformMakefile class
1308 #
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.
1312 #
1313 class PlatformMakefile(BuildFile):
1314 ## template used to generate the makefile for platform
1315 _TEMPLATE_ = TemplateString('''\
1316 ${makefile_header}
1317
1318 #
1319 # Platform Macro Definition
1320 #
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}
1327
1328 #
1329 # Build Configuration Macro Definition
1330 #
1331 TOOLCHAIN = ${toolchain_tag}
1332 TOOLCHAIN_TAG = ${toolchain_tag}
1333 TARGET = ${build_target}
1334
1335 #
1336 # Build Directory Macro Definition
1337 #
1338 BUILD_DIR = ${platform_build_directory}
1339 FV_DIR = ${platform_build_directory}${separator}FV
1340
1341 #
1342 # Shell Command Macro
1343 #
1344 ${BEGIN}${shell_command_code} = ${shell_command}
1345 ${END}
1346
1347 MAKE = ${make_path}
1348 MAKE_FILE = ${makefile_path}
1349
1350 #
1351 # Default target
1352 #
1353 all: init build_libraries build_modules
1354
1355 #
1356 # Initialization target: print build information and create necessary directories
1357 #
1358 init:
1359 \t-@echo Building ... $(PLATFORM_FILE) [${build_architecture_list}]
1360 \t${BEGIN}-@${create_directory_command}
1361 \t${END}
1362 #
1363 # library build target
1364 #
1365 libraries: init build_libraries
1366
1367 #
1368 # module build target
1369 #
1370 modules: init build_libraries build_modules
1371
1372 #
1373 # Build all libraries:
1374 #
1375 build_libraries:
1376 ${BEGIN}\t@"$(MAKE)" $(MAKE_FLAGS) -f ${library_makefile_list} pbuild
1377 ${END}\t@cd $(BUILD_DIR)
1378
1379 #
1380 # Build all modules:
1381 #
1382 build_modules:
1383 ${BEGIN}\t@"$(MAKE)" $(MAKE_FLAGS) -f ${module_makefile_list} pbuild
1384 ${END}\t@cd $(BUILD_DIR)
1385
1386 #
1387 # Clean intermediate files
1388 #
1389 clean:
1390 \t${BEGIN}-@${library_build_command} clean
1391 \t${END}${BEGIN}-@${module_build_command} clean
1392 \t${END}@cd $(BUILD_DIR)
1393
1394 #
1395 # Clean all generated files except to makefile
1396 #
1397 cleanall:
1398 ${BEGIN}\t${cleanall_command}
1399 ${END}
1400
1401 #
1402 # Clean all library files
1403 #
1404 cleanlib:
1405 \t${BEGIN}-@${library_build_command} cleanall
1406 \t${END}@cd $(BUILD_DIR)\n
1407 ''')
1408
1409 ## Constructor of PlatformMakefile
1410 #
1411 # @param ModuleAutoGen Object of PlatformAutoGen class
1412 #
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()
1422
1423 # Compose a dict object containing information used to do replacement in template
1424 @property
1425 def _TemplateDict(self):
1426 Separator = self._SEP_[self._Platform]
1427
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))
1432
1433 self.IntermediateDirectoryList = ["$(BUILD_DIR)"]
1434 self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()
1435 self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()
1436
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
1447
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)
1456
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"],
1470
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,
1484 }
1485
1486 return MakefileTemplateDict
1487
1488 ## Get the root directory list for intermediate files of all modules build
1489 #
1490 # @retval list The list of directory
1491 #
1492 def GetModuleBuildDirectoryList(self):
1493 DirList = []
1494 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1495 if not ModuleAutoGen.IsBinaryModule:
1496 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1497 return DirList
1498
1499 ## Get the root directory list for intermediate files of all libraries build
1500 #
1501 # @retval list The list of directory
1502 #
1503 def GetLibraryBuildDirectoryList(self):
1504 DirList = []
1505 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1506 if not LibraryAutoGen.IsBinaryModule:
1507 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1508 return DirList
1509
1510 ## TopLevelMakefile class
1511 #
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.
1515 #
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}''')
1519
1520 ## Constructor of TopLevelMakefile
1521 #
1522 # @param Workspace Object of WorkspaceAutoGen class
1523 #
1524 def __init__(self, Workspace):
1525 BuildFile.__init__(self, Workspace)
1526 self.IntermediateDirectoryList = []
1527 self.DependencyHeaderFileSet = set()
1528
1529 # Compose a dict object containing information used to do replacement in template
1530 @property
1531 def _TemplateDict(self):
1532 Separator = self._SEP_[self._Platform]
1533
1534 # any platform autogen object is ok because we just need common information
1535 MyAgo = self._AutoGenObject
1536
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))
1540
1541 for Arch in MyAgo.ArchList:
1542 self.IntermediateDirectoryList.append(Separator.join(["$(BUILD_DIR)", Arch]))
1543 self.IntermediateDirectoryList.append("$(FV_DIR)")
1544
1545 # TRICK: for not generating GenFds call in makefile if no FDF file
1546 MacroList = []
1547 if MyAgo.FdfFile is not None and MyAgo.FdfFile != "":
1548 FdfFileList = [MyAgo.FdfFile]
1549 # macros passed to GenFds
1550 MacroDict = {}
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('\\', '\\\\')))
1556 else:
1557 MacroList.append('"%s"' % MacroName)
1558 else:
1559 FdfFileList = []
1560
1561 # pass extra common options to external program called in makefile, currently GenFds.exe
1562 ExtraOption = ''
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"
1570
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"
1577
1578 for pcd in GlobalData.BuildOptionPcd:
1579 if pcd[2]:
1580 pcdname = '.'.join(pcd[0:3])
1581 else:
1582 pcdname = '.'.join(pcd[0:2])
1583 if pcd[3].startswith('{'):
1584 ExtraOption += " --pcd " + pcdname + '=' + 'H' + '"' + pcd[3] + '"'
1585 else:
1586 ExtraOption += " --pcd " + pcdname + '=' + pcd[3]
1587
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)
1593
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,
1603
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,
1621 }
1622
1623 return MakefileTemplateDict
1624
1625 ## Get the root directory list for intermediate files of all modules build
1626 #
1627 # @retval list The list of directory
1628 #
1629 def GetModuleBuildDirectoryList(self):
1630 DirList = []
1631 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1632 if not ModuleAutoGen.IsBinaryModule:
1633 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1634 return DirList
1635
1636 ## Get the root directory list for intermediate files of all libraries build
1637 #
1638 # @retval list The list of directory
1639 #
1640 def GetLibraryBuildDirectoryList(self):
1641 DirList = []
1642 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1643 if not LibraryAutoGen.IsBinaryModule:
1644 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1645 return DirList
1646
1647 ## Find dependencies for one source file
1648 #
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.
1652 #
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
1656 #
1657 # @retval list The list of files the given source file depends on
1658 #
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()
1663
1664 if AutoGenObject.Arch not in gDependencyDatabase:
1665 gDependencyDatabase[AutoGenObject.Arch] = {}
1666 DepDb = gDependencyDatabase[AutoGenObject.Arch]
1667
1668 while len(FileStack) > 0:
1669 F = FileStack.pop()
1670
1671 FullPathDependList = []
1672 if F in FileCache:
1673 for CacheFile in FileCache[F]:
1674 FullPathDependList.append(CacheFile)
1675 if CacheFile not in DependencySet:
1676 FileStack.append(CacheFile)
1677 DependencySet.update(FullPathDependList)
1678 continue
1679
1680 CurrentFileDependencyList = []
1681 if F in DepDb:
1682 CurrentFileDependencyList = DepDb[F]
1683 else:
1684 try:
1685 Fd = open(F.Path, 'rb')
1686 FileContent = Fd.read()
1687 Fd.close()
1688 except BaseException as X:
1689 EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=F.Path + "\n\t" + str(X))
1690 if len(FileContent) == 0:
1691 continue
1692 try:
1693 if FileContent[0] == 0xff or FileContent[0] == 0xfe:
1694 FileContent = FileContent.decode('utf-16')
1695 else:
1696 FileContent = FileContent.decode()
1697 except:
1698 # The file is not txt file. for example .mcb file
1699 continue
1700 IncludedFileList = gIncludePattern.findall(FileContent)
1701
1702 for Inc in IncludedFileList:
1703 Inc = Inc.strip()
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}
1711 else:
1712 # not known macro used in #include, always build the file by
1713 # returning a empty dependency
1714 FileCache[File] = []
1715 return []
1716 Inc = os.path.normpath(Inc)
1717 CurrentFileDependencyList.append(Inc)
1718 DepDb[F] = CurrentFileDependencyList
1719
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]:
1727 continue
1728 # If isfile is called too many times, the performance is slow down.
1729 elif not os.path.isfile(FilePath):
1730 gIsFileMap[FilePath] = False
1731 continue
1732 else:
1733 gIsFileMap[FilePath] = True
1734 FilePath = PathClass(FilePath)
1735 FullPathDependList.append(FilePath)
1736 if FilePath not in DependencySet:
1737 FileStack.append(FilePath)
1738 break
1739 else:
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)))
1742
1743 FileCache[F] = FullPathDependList
1744 DependencySet.update(FullPathDependList)
1745
1746 DependencySet.update(ForceList)
1747 if File in DependencySet:
1748 DependencySet.remove(File)
1749 DependencyList = list(DependencySet) # remove duplicate ones
1750
1751 return DependencyList
1752
1753 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1754 if __name__ == '__main__':
1755 pass