]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/AutoGen/GenMake.py
BaseTools: Improve GetDependencyList function
[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 - 2018, Intel Corporation. All rights reserved.<BR>
5 # SPDX-License-Identifier: BSD-2-Clause-Patent
6 #
7
8 ## Import Modules
9 #
10 from __future__ import absolute_import
11 import Common.LongFilePathOs as os
12 import sys
13 import string
14 import re
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
25
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)
28
29 ## Regular expression for matching macro used in header file inclusion
30 gMacroPattern = re.compile("([_A-Z][_A-Z0-9]*)[ \t]*\((.+)\)", re.UNICODE)
31
32 gIsFileMap = {}
33
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,
53 }
54
55 ## default makefile type
56 gMakeType = ""
57 if sys.platform == "win32":
58 gMakeType = "nmake"
59 else:
60 gMakeType = "gmake"
61
62
63 ## BuildFile class
64 #
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.
67 #
68 class BuildFile(object):
69 ## template used to generate the build file (i.e. makefile if using make)
70 _TEMPLATE_ = TemplateString('')
71
72 _DEFAULT_FILE_NAME_ = "Makefile"
73
74 ## default file name for each type of build file
75 _FILE_NAME_ = {
76 "nmake" : "Makefile",
77 "gmake" : "GNUmakefile"
78 }
79
80 ## Fixed header string for makefile
81 _MAKEFILE_HEADER = '''#
82 # DO NOT EDIT
83 # This file is auto-generated by build utility
84 #
85 # Module Name:
86 #
87 # %s
88 #
89 # Abstract:
90 #
91 # Auto-generated makefile for building modules, libraries or platform
92 #
93 '''
94
95 ## Header string for each type of build file
96 _FILE_HEADER_ = {
97 "nmake" : _MAKEFILE_HEADER % _FILE_NAME_["nmake"],
98 "gmake" : _MAKEFILE_HEADER % _FILE_NAME_["gmake"]
99 }
100
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
107 #
108 _SHELL_CMD_ = {
109 "nmake" : {
110 "CP" : "copy /y",
111 "MV" : "move /y",
112 "RM" : "del /f /q",
113 "MD" : "mkdir",
114 "RD" : "rmdir /s /q",
115 },
116
117 "gmake" : {
118 "CP" : "cp -f",
119 "MV" : "mv -f",
120 "RM" : "rm -f",
121 "MD" : "mkdir -p",
122 "RD" : "rm -r -f",
123 }
124 }
125
126 ## directory separator
127 _SEP_ = {
128 "nmake" : "\\",
129 "gmake" : "/"
130 }
131
132 ## directory creation template
133 _MD_TEMPLATE_ = {
134 "nmake" : 'if not exist %(dir)s $(MD) %(dir)s',
135 "gmake" : "$(MD) %(dir)s"
136 }
137
138 ## directory removal template
139 _RD_TEMPLATE_ = {
140 "nmake" : 'if exist %(dir)s $(RD) %(dir)s',
141 "gmake" : "$(RD) %(dir)s"
142 }
143 ## cp if exist
144 _CP_TEMPLATE_ = {
145 "nmake" : 'if exist %(Src)s $(CP) %(Src)s %(Dst)s',
146 "gmake" : "test -f %(Src)s && $(CP) %(Src)s %(Dst)s"
147 }
148
149 _CD_TEMPLATE_ = {
150 "nmake" : 'if exist %(dir)s cd %(dir)s',
151 "gmake" : "test -e %(dir)s && cd %(dir)s"
152 }
153
154 _MAKE_TEMPLATE_ = {
155 "nmake" : 'if exist %(file)s "$(MAKE)" $(MAKE_FLAGS) -f %(file)s',
156 "gmake" : 'test -e %(file)s && "$(MAKE)" $(MAKE_FLAGS) -f %(file)s'
157 }
158
159 _INCLUDE_CMD_ = {
160 "nmake" : '!INCLUDE',
161 "gmake" : "include"
162 }
163
164 _INC_FLAG_ = {TAB_COMPILER_MSFT : "/I", "GCC" : "-I", "INTEL" : "-I", "RVCT" : "-I", "NASM" : "-I"}
165
166 ## Constructor of BuildFile
167 #
168 # @param AutoGenObject Object of AutoGen class
169 #
170 def __init__(self, AutoGenObject):
171 self._AutoGenObject = AutoGenObject
172 self._FileType = gMakeType
173
174 ## Create build file
175 #
176 # @param FileType Type of build file. Only nmake and gmake are supported now.
177 #
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
180 #
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 return SaveFileOnChange(os.path.join(self._AutoGenObject.MakeFileDir, FileName), FileContent, False)
189
190 ## Return a list of directory creation command string
191 #
192 # @param DirList The list of directory to be created
193 #
194 # @retval list The directory creation command list
195 #
196 def GetCreateDirectoryCommand(self, DirList):
197 return [self._MD_TEMPLATE_[self._FileType] % {'dir':Dir} for Dir in DirList]
198
199 ## Return a list of directory removal command string
200 #
201 # @param DirList The list of directory to be removed
202 #
203 # @retval list The directory removal command list
204 #
205 def GetRemoveDirectoryCommand(self, DirList):
206 return [self._RD_TEMPLATE_[self._FileType] % {'dir':Dir} for Dir in DirList]
207
208 def PlaceMacro(self, Path, MacroDefinitions=None):
209 if Path.startswith("$("):
210 return Path
211 else:
212 if MacroDefinitions is None:
213 MacroDefinitions = {}
214 PathLength = len(Path)
215 for MacroName in MacroDefinitions:
216 MacroValue = MacroDefinitions[MacroName]
217 MacroValueLength = len(MacroValue)
218 if MacroValueLength == 0:
219 continue
220 if MacroValueLength <= PathLength and Path.startswith(MacroValue):
221 Path = "$(%s)%s" % (MacroName, Path[MacroValueLength:])
222 break
223 return Path
224
225 ## ModuleMakefile class
226 #
227 # This class encapsules makefie and its generation for module. It uses template to generate
228 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
229 #
230 class ModuleMakefile(BuildFile):
231 ## template used to generate the makefile for module
232 _TEMPLATE_ = TemplateString('''\
233 ${makefile_header}
234
235 #
236 # Platform Macro Definition
237 #
238 PLATFORM_NAME = ${platform_name}
239 PLATFORM_GUID = ${platform_guid}
240 PLATFORM_VERSION = ${platform_version}
241 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
242 PLATFORM_DIR = ${platform_dir}
243 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
244
245 #
246 # Module Macro Definition
247 #
248 MODULE_NAME = ${module_name}
249 MODULE_GUID = ${module_guid}
250 MODULE_NAME_GUID = ${module_name_guid}
251 MODULE_VERSION = ${module_version}
252 MODULE_TYPE = ${module_type}
253 MODULE_FILE = ${module_file}
254 MODULE_FILE_BASE_NAME = ${module_file_base_name}
255 BASE_NAME = $(MODULE_NAME)
256 MODULE_RELATIVE_DIR = ${module_relative_directory}
257 PACKAGE_RELATIVE_DIR = ${package_relative_directory}
258 MODULE_DIR = ${module_dir}
259 FFS_OUTPUT_DIR = ${ffs_output_directory}
260
261 MODULE_ENTRY_POINT = ${module_entry_point}
262 ARCH_ENTRY_POINT = ${arch_entry_point}
263 IMAGE_ENTRY_POINT = ${image_entry_point}
264
265 ${BEGIN}${module_extra_defines}
266 ${END}
267 #
268 # Build Configuration Macro Definition
269 #
270 ARCH = ${architecture}
271 TOOLCHAIN = ${toolchain_tag}
272 TOOLCHAIN_TAG = ${toolchain_tag}
273 TARGET = ${build_target}
274
275 #
276 # Build Directory Macro Definition
277 #
278 # PLATFORM_BUILD_DIR = ${platform_build_directory}
279 BUILD_DIR = ${platform_build_directory}
280 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
281 LIB_DIR = $(BIN_DIR)
282 MODULE_BUILD_DIR = ${module_build_directory}
283 OUTPUT_DIR = ${module_output_directory}
284 DEBUG_DIR = ${module_debug_directory}
285 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
286 DEST_DIR_DEBUG = $(DEBUG_DIR)
287
288 #
289 # Shell Command Macro
290 #
291 ${BEGIN}${shell_command_code} = ${shell_command}
292 ${END}
293
294 #
295 # Tools definitions specific to this module
296 #
297 ${BEGIN}${module_tool_definitions}
298 ${END}
299 MAKE_FILE = ${makefile_path}
300
301 #
302 # Build Macro
303 #
304 ${BEGIN}${file_macro}
305 ${END}
306
307 COMMON_DEPS = ${BEGIN}${common_dependency_file} \\
308 ${END}
309
310 #
311 # Overridable Target Macro Definitions
312 #
313 FORCE_REBUILD = force_build
314 INIT_TARGET = init
315 PCH_TARGET =
316 BC_TARGET = ${BEGIN}${backward_compatible_target} ${END}
317 CODA_TARGET = ${BEGIN}${remaining_build_target} \\
318 ${END}
319
320 #
321 # Default target, which will build dependent libraries in addition to source files
322 #
323
324 all: mbuild
325
326
327 #
328 # Target used when called from platform makefile, which will bypass the build of dependent libraries
329 #
330
331 pbuild: $(INIT_TARGET) $(BC_TARGET) $(PCH_TARGET) $(CODA_TARGET)
332
333 #
334 # ModuleTarget
335 #
336
337 mbuild: $(INIT_TARGET) $(BC_TARGET) gen_libs $(PCH_TARGET) $(CODA_TARGET)
338
339 #
340 # Build Target used in multi-thread build mode, which will bypass the init and gen_libs targets
341 #
342
343 tbuild: $(BC_TARGET) $(PCH_TARGET) $(CODA_TARGET)
344
345 #
346 # Phony target which is used to force executing commands for a target
347 #
348 force_build:
349 \t-@
350
351 #
352 # Target to update the FD
353 #
354
355 fds: mbuild gen_fds
356
357 #
358 # Initialization target: print build information and create necessary directories
359 #
360 init: info dirs
361
362 info:
363 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
364
365 dirs:
366 ${BEGIN}\t-@${create_directory_command}\n${END}
367
368 strdefs:
369 \t-@$(CP) $(DEBUG_DIR)${separator}AutoGen.h $(DEBUG_DIR)${separator}$(MODULE_NAME)StrDefs.h
370
371 #
372 # GenLibsTarget
373 #
374 gen_libs:
375 \t${BEGIN}@"$(MAKE)" $(MAKE_FLAGS) -f ${dependent_library_build_directory}${separator}${makefile_name}
376 \t${END}@cd $(MODULE_BUILD_DIR)
377
378 #
379 # Build Flash Device Image
380 #
381 gen_fds:
382 \t@"$(MAKE)" $(MAKE_FLAGS) -f $(BUILD_DIR)${separator}${makefile_name} fds
383 \t@cd $(MODULE_BUILD_DIR)
384
385 #
386 # Individual Object Build Targets
387 #
388 ${BEGIN}${file_build_target}
389 ${END}
390
391 #
392 # clean all intermediate files
393 #
394 clean:
395 \t${BEGIN}${clean_command}
396 \t${END}\t$(RM) AutoGenTimeStamp
397
398 #
399 # clean all generated files
400 #
401 cleanall:
402 ${BEGIN}\t${cleanall_command}
403 ${END}\t$(RM) *.pdb *.idb > NUL 2>&1
404 \t$(RM) $(BIN_DIR)${separator}$(MODULE_NAME).efi
405 \t$(RM) AutoGenTimeStamp
406
407 #
408 # clean all dependent libraries built
409 #
410 cleanlib:
411 \t${BEGIN}-@${library_build_command} cleanall
412 \t${END}@cd $(MODULE_BUILD_DIR)\n\n''')
413
414 _FILE_MACRO_TEMPLATE = TemplateString("${macro_name} = ${BEGIN} \\\n ${source_file}${END}\n")
415 _BUILD_TARGET_TEMPLATE = TemplateString("${BEGIN}${target} : ${deps}\n${END}\t${cmd}\n")
416
417 ## Constructor of ModuleMakefile
418 #
419 # @param ModuleAutoGen Object of ModuleAutoGen class
420 #
421 def __init__(self, ModuleAutoGen):
422 BuildFile.__init__(self, ModuleAutoGen)
423 self.PlatformInfo = self._AutoGenObject.PlatformInfo
424
425 self.ResultFileList = []
426 self.IntermediateDirectoryList = ["$(DEBUG_DIR)", "$(OUTPUT_DIR)"]
427
428 self.FileBuildTargetList = [] # [(src, target string)]
429 self.BuildTargetList = [] # [target string]
430 self.PendingBuildTargetList = [] # [FileBuildRule objects]
431 self.CommonFileDependency = []
432 self.FileListMacros = {}
433 self.ListFileMacros = {}
434 self.ObjTargetDict = OrderedDict()
435 self.FileCache = {}
436 self.LibraryBuildCommandList = []
437 self.LibraryFileList = []
438 self.LibraryMakefileList = []
439 self.LibraryBuildDirectoryList = []
440 self.SystemLibraryList = []
441 self.Macros = OrderedDict()
442 self.Macros["OUTPUT_DIR" ] = self._AutoGenObject.Macros["OUTPUT_DIR"]
443 self.Macros["DEBUG_DIR" ] = self._AutoGenObject.Macros["DEBUG_DIR"]
444 self.Macros["MODULE_BUILD_DIR"] = self._AutoGenObject.Macros["MODULE_BUILD_DIR"]
445 self.Macros["BIN_DIR" ] = self._AutoGenObject.Macros["BIN_DIR"]
446 self.Macros["BUILD_DIR" ] = self._AutoGenObject.Macros["BUILD_DIR"]
447 self.Macros["WORKSPACE" ] = self._AutoGenObject.Macros["WORKSPACE"]
448 self.Macros["FFS_OUTPUT_DIR" ] = self._AutoGenObject.Macros["FFS_OUTPUT_DIR"]
449 self.GenFfsList = ModuleAutoGen.GenFfsList
450 self.MacroList = ['FFS_OUTPUT_DIR', 'MODULE_GUID', 'OUTPUT_DIR']
451 self.FfsOutputFileList = []
452
453 # Compose a dict object containing information used to do replacement in template
454 @property
455 def _TemplateDict(self):
456 if self._FileType not in self._SEP_:
457 EdkLogger.error("build", PARAMETER_INVALID, "Invalid Makefile type [%s]" % self._FileType,
458 ExtraData="[%s]" % str(self._AutoGenObject))
459 MyAgo = self._AutoGenObject
460 Separator = self._SEP_[self._FileType]
461
462 # break build if no source files and binary files are found
463 if len(MyAgo.SourceFileList) == 0 and len(MyAgo.BinaryFileList) == 0:
464 EdkLogger.error("build", AUTOGEN_ERROR, "No files to be built in module [%s, %s, %s]"
465 % (MyAgo.BuildTarget, MyAgo.ToolChain, MyAgo.Arch),
466 ExtraData="[%s]" % str(MyAgo))
467
468 # convert dependent libraries to build command
469 self.ProcessDependentLibrary()
470 if len(MyAgo.Module.ModuleEntryPointList) > 0:
471 ModuleEntryPoint = MyAgo.Module.ModuleEntryPointList[0]
472 else:
473 ModuleEntryPoint = "_ModuleEntryPoint"
474
475 ArchEntryPoint = ModuleEntryPoint
476
477 if MyAgo.Arch == "EBC":
478 # EBC compiler always use "EfiStart" as entry point. Only applies to EdkII modules
479 ImageEntryPoint = "EfiStart"
480 else:
481 # EdkII modules always use "_ModuleEntryPoint" as entry point
482 ImageEntryPoint = "_ModuleEntryPoint"
483
484 for k, v in MyAgo.Module.Defines.items():
485 if k not in MyAgo.Macros:
486 MyAgo.Macros[k] = v
487
488 if 'MODULE_ENTRY_POINT' not in MyAgo.Macros:
489 MyAgo.Macros['MODULE_ENTRY_POINT'] = ModuleEntryPoint
490 if 'ARCH_ENTRY_POINT' not in MyAgo.Macros:
491 MyAgo.Macros['ARCH_ENTRY_POINT'] = ArchEntryPoint
492 if 'IMAGE_ENTRY_POINT' not in MyAgo.Macros:
493 MyAgo.Macros['IMAGE_ENTRY_POINT'] = ImageEntryPoint
494
495 PCI_COMPRESS_Flag = False
496 for k, v in MyAgo.Module.Defines.items():
497 if 'PCI_COMPRESS' == k and 'TRUE' == v:
498 PCI_COMPRESS_Flag = True
499
500 # tools definitions
501 ToolsDef = []
502 IncPrefix = self._INC_FLAG_[MyAgo.ToolChainFamily]
503 for Tool in MyAgo.BuildOption:
504 for Attr in MyAgo.BuildOption[Tool]:
505 Value = MyAgo.BuildOption[Tool][Attr]
506 if Attr == "FAMILY":
507 continue
508 elif Attr == "PATH":
509 ToolsDef.append("%s = %s" % (Tool, Value))
510 else:
511 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
512 if Tool == "MAKE":
513 continue
514 # Remove duplicated include path, if any
515 if Attr == "FLAGS":
516 Value = RemoveDupOption(Value, IncPrefix, MyAgo.IncludePathList)
517 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Tool == 'CC' and '/GM' in Value:
518 Value = Value.replace(' /MP', '')
519 MyAgo.BuildOption[Tool][Attr] = Value
520 if Tool == "OPTROM" and PCI_COMPRESS_Flag:
521 ValueList = Value.split()
522 if ValueList:
523 for i, v in enumerate(ValueList):
524 if '-e' == v:
525 ValueList[i] = '-ec'
526 Value = ' '.join(ValueList)
527
528 ToolsDef.append("%s_%s = %s" % (Tool, Attr, Value))
529 ToolsDef.append("")
530
531 # generate the Response file and Response flag
532 RespDict = self.CommandExceedLimit()
533 RespFileList = os.path.join(MyAgo.OutputDir, 'respfilelist.txt')
534 if RespDict:
535 RespFileListContent = ''
536 for Resp in RespDict:
537 RespFile = os.path.join(MyAgo.OutputDir, str(Resp).lower() + '.txt')
538 StrList = RespDict[Resp].split(' ')
539 UnexpandMacro = []
540 NewStr = []
541 for Str in StrList:
542 if '$' in Str:
543 UnexpandMacro.append(Str)
544 else:
545 NewStr.append(Str)
546 UnexpandMacroStr = ' '.join(UnexpandMacro)
547 NewRespStr = ' '.join(NewStr)
548 SaveFileOnChange(RespFile, NewRespStr, False)
549 ToolsDef.append("%s = %s" % (Resp, UnexpandMacroStr + ' @' + RespFile))
550 RespFileListContent += '@' + RespFile + TAB_LINE_BREAK
551 RespFileListContent += NewRespStr + TAB_LINE_BREAK
552 SaveFileOnChange(RespFileList, RespFileListContent, False)
553 else:
554 if os.path.exists(RespFileList):
555 os.remove(RespFileList)
556
557 # convert source files and binary files to build targets
558 self.ResultFileList = [str(T.Target) for T in MyAgo.CodaTargetList]
559 if len(self.ResultFileList) == 0 and len(MyAgo.SourceFileList) != 0:
560 EdkLogger.error("build", AUTOGEN_ERROR, "Nothing to build",
561 ExtraData="[%s]" % str(MyAgo))
562
563 self.ProcessBuildTargetList()
564 self.ParserGenerateFfsCmd()
565
566 # Generate macros used to represent input files
567 FileMacroList = [] # macro name = file list
568 for FileListMacro in self.FileListMacros:
569 FileMacro = self._FILE_MACRO_TEMPLATE.Replace(
570 {
571 "macro_name" : FileListMacro,
572 "source_file" : self.FileListMacros[FileListMacro]
573 }
574 )
575 FileMacroList.append(FileMacro)
576
577 # INC_LIST is special
578 FileMacro = ""
579 IncludePathList = []
580 for P in MyAgo.IncludePathList:
581 IncludePathList.append(IncPrefix + self.PlaceMacro(P, self.Macros))
582 if FileBuildRule.INC_LIST_MACRO in self.ListFileMacros:
583 self.ListFileMacros[FileBuildRule.INC_LIST_MACRO].append(IncPrefix + P)
584 FileMacro += self._FILE_MACRO_TEMPLATE.Replace(
585 {
586 "macro_name" : "INC",
587 "source_file" : IncludePathList
588 }
589 )
590 FileMacroList.append(FileMacro)
591 # Add support when compiling .nasm source files
592 for File in self.FileCache.keys():
593 if not str(File).endswith('.nasm'):
594 continue
595 IncludePathList = []
596 for P in MyAgo.IncludePathList:
597 IncludePath = self._INC_FLAG_['NASM'] + self.PlaceMacro(P, self.Macros)
598 if IncludePath.endswith(os.sep):
599 IncludePath = IncludePath.rstrip(os.sep)
600 # When compiling .nasm files, need to add a literal backslash at each path
601 # To specify a literal backslash at the end of the line, precede it with a caret (^)
602 if P == MyAgo.IncludePathList[-1] and os.sep == '\\':
603 IncludePath = ''.join([IncludePath, '^', os.sep])
604 else:
605 IncludePath = os.path.join(IncludePath, '')
606 IncludePathList.append(IncludePath)
607 FileMacroList.append(self._FILE_MACRO_TEMPLATE.Replace({"macro_name": "NASM_INC", "source_file": IncludePathList}))
608 break
609
610 # Generate macros used to represent files containing list of input files
611 for ListFileMacro in self.ListFileMacros:
612 ListFileName = os.path.join(MyAgo.OutputDir, "%s.lst" % ListFileMacro.lower()[:len(ListFileMacro) - 5])
613 FileMacroList.append("%s = %s" % (ListFileMacro, ListFileName))
614 SaveFileOnChange(
615 ListFileName,
616 "\n".join(self.ListFileMacros[ListFileMacro]),
617 False
618 )
619
620 # Generate objlist used to create .obj file
621 for Type in self.ObjTargetDict:
622 NewLine = ' '.join(list(self.ObjTargetDict[Type]))
623 FileMacroList.append("OBJLIST_%s = %s" % (list(self.ObjTargetDict.keys()).index(Type), NewLine))
624
625 BcTargetList = []
626
627 MakefileName = self._FILE_NAME_[self._FileType]
628 LibraryMakeCommandList = []
629 for D in self.LibraryBuildDirectoryList:
630 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join(D, MakefileName)}
631 LibraryMakeCommandList.append(Command)
632
633 package_rel_dir = MyAgo.SourceDir
634 current_dir = self.Macros["WORKSPACE"]
635 found = False
636 while not found and os.sep in package_rel_dir:
637 index = package_rel_dir.index(os.sep)
638 current_dir = mws.join(current_dir, package_rel_dir[:index])
639 if os.path.exists(current_dir):
640 for fl in os.listdir(current_dir):
641 if fl.endswith('.dec'):
642 found = True
643 break
644 package_rel_dir = package_rel_dir[index + 1:]
645
646 MakefileTemplateDict = {
647 "makefile_header" : self._FILE_HEADER_[self._FileType],
648 "makefile_path" : os.path.join("$(MODULE_BUILD_DIR)", MakefileName),
649 "makefile_name" : MakefileName,
650 "platform_name" : self.PlatformInfo.Name,
651 "platform_guid" : self.PlatformInfo.Guid,
652 "platform_version" : self.PlatformInfo.Version,
653 "platform_relative_directory": self.PlatformInfo.SourceDir,
654 "platform_output_directory" : self.PlatformInfo.OutputDir,
655 "ffs_output_directory" : MyAgo.Macros["FFS_OUTPUT_DIR"],
656 "platform_dir" : MyAgo.Macros["PLATFORM_DIR"],
657
658 "module_name" : MyAgo.Name,
659 "module_guid" : MyAgo.Guid,
660 "module_name_guid" : MyAgo.UniqueBaseName,
661 "module_version" : MyAgo.Version,
662 "module_type" : MyAgo.ModuleType,
663 "module_file" : MyAgo.MetaFile.Name,
664 "module_file_base_name" : MyAgo.MetaFile.BaseName,
665 "module_relative_directory" : MyAgo.SourceDir,
666 "module_dir" : mws.join (self.Macros["WORKSPACE"], MyAgo.SourceDir),
667 "package_relative_directory": package_rel_dir,
668 "module_extra_defines" : ["%s = %s" % (k, v) for k, v in MyAgo.Module.Defines.items()],
669
670 "architecture" : MyAgo.Arch,
671 "toolchain_tag" : MyAgo.ToolChain,
672 "build_target" : MyAgo.BuildTarget,
673
674 "platform_build_directory" : self.PlatformInfo.BuildDir,
675 "module_build_directory" : MyAgo.BuildDir,
676 "module_output_directory" : MyAgo.OutputDir,
677 "module_debug_directory" : MyAgo.DebugDir,
678
679 "separator" : Separator,
680 "module_tool_definitions" : ToolsDef,
681
682 "shell_command_code" : list(self._SHELL_CMD_[self._FileType].keys()),
683 "shell_command" : list(self._SHELL_CMD_[self._FileType].values()),
684
685 "module_entry_point" : ModuleEntryPoint,
686 "image_entry_point" : ImageEntryPoint,
687 "arch_entry_point" : ArchEntryPoint,
688 "remaining_build_target" : self.ResultFileList,
689 "common_dependency_file" : self.CommonFileDependency,
690 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
691 "clean_command" : self.GetRemoveDirectoryCommand(["$(OUTPUT_DIR)"]),
692 "cleanall_command" : self.GetRemoveDirectoryCommand(["$(DEBUG_DIR)", "$(OUTPUT_DIR)"]),
693 "dependent_library_build_directory" : self.LibraryBuildDirectoryList,
694 "library_build_command" : LibraryMakeCommandList,
695 "file_macro" : FileMacroList,
696 "file_build_target" : self.BuildTargetList,
697 "backward_compatible_target": BcTargetList,
698 }
699
700 return MakefileTemplateDict
701
702 def ParserGenerateFfsCmd(self):
703 #Add Ffs cmd to self.BuildTargetList
704 OutputFile = ''
705 DepsFileList = []
706
707 for Cmd in self.GenFfsList:
708 if Cmd[2]:
709 for CopyCmd in Cmd[2]:
710 Src, Dst = CopyCmd
711 Src = self.ReplaceMacro(Src)
712 Dst = self.ReplaceMacro(Dst)
713 if Dst not in self.ResultFileList:
714 self.ResultFileList.append(Dst)
715 if '%s :' %(Dst) not in self.BuildTargetList:
716 self.BuildTargetList.append("%s :" %(Dst))
717 self.BuildTargetList.append('\t' + self._CP_TEMPLATE_[self._FileType] %{'Src': Src, 'Dst': Dst})
718
719 FfsCmdList = Cmd[0]
720 for index, Str in enumerate(FfsCmdList):
721 if '-o' == Str:
722 OutputFile = FfsCmdList[index + 1]
723 if '-i' == Str or "-oi" == Str:
724 if DepsFileList == []:
725 DepsFileList = [FfsCmdList[index + 1]]
726 else:
727 DepsFileList.append(FfsCmdList[index + 1])
728 DepsFileString = ' '.join(DepsFileList).strip()
729 if DepsFileString == '':
730 continue
731 OutputFile = self.ReplaceMacro(OutputFile)
732 self.ResultFileList.append(OutputFile)
733 DepsFileString = self.ReplaceMacro(DepsFileString)
734 self.BuildTargetList.append('%s : %s' % (OutputFile, DepsFileString))
735 CmdString = ' '.join(FfsCmdList).strip()
736 CmdString = self.ReplaceMacro(CmdString)
737 self.BuildTargetList.append('\t%s' % CmdString)
738
739 self.ParseSecCmd(DepsFileList, Cmd[1])
740 for SecOutputFile, SecDepsFile, SecCmd in self.FfsOutputFileList :
741 self.BuildTargetList.append('%s : %s' % (self.ReplaceMacro(SecOutputFile), self.ReplaceMacro(SecDepsFile)))
742 self.BuildTargetList.append('\t%s' % self.ReplaceMacro(SecCmd))
743 self.FfsOutputFileList = []
744
745 def ParseSecCmd(self, OutputFileList, CmdTuple):
746 for OutputFile in OutputFileList:
747 for SecCmdStr in CmdTuple:
748 SecDepsFileList = []
749 SecCmdList = SecCmdStr.split()
750 CmdName = SecCmdList[0]
751 for index, CmdItem in enumerate(SecCmdList):
752 if '-o' == CmdItem and OutputFile == SecCmdList[index + 1]:
753 index = index + 1
754 while index + 1 < len(SecCmdList):
755 if not SecCmdList[index+1].startswith('-'):
756 SecDepsFileList.append(SecCmdList[index + 1])
757 index = index + 1
758 if CmdName == 'Trim':
759 SecDepsFileList.append(os.path.join('$(DEBUG_DIR)', os.path.basename(OutputFile).replace('offset', 'efi')))
760 if OutputFile.endswith('.ui') or OutputFile.endswith('.ver'):
761 SecDepsFileList.append(os.path.join('$(MODULE_DIR)', '$(MODULE_FILE)'))
762 self.FfsOutputFileList.append((OutputFile, ' '.join(SecDepsFileList), SecCmdStr))
763 if len(SecDepsFileList) > 0:
764 self.ParseSecCmd(SecDepsFileList, CmdTuple)
765 break
766 else:
767 continue
768
769 def ReplaceMacro(self, str):
770 for Macro in self.MacroList:
771 if self._AutoGenObject.Macros[Macro] and self._AutoGenObject.Macros[Macro] in str:
772 str = str.replace(self._AutoGenObject.Macros[Macro], '$(' + Macro + ')')
773 return str
774
775 def CommandExceedLimit(self):
776 FlagDict = {
777 'CC' : { 'Macro' : '$(CC_FLAGS)', 'Value' : False},
778 'PP' : { 'Macro' : '$(PP_FLAGS)', 'Value' : False},
779 'APP' : { 'Macro' : '$(APP_FLAGS)', 'Value' : False},
780 'ASLPP' : { 'Macro' : '$(ASLPP_FLAGS)', 'Value' : False},
781 'VFRPP' : { 'Macro' : '$(VFRPP_FLAGS)', 'Value' : False},
782 'ASM' : { 'Macro' : '$(ASM_FLAGS)', 'Value' : False},
783 'ASLCC' : { 'Macro' : '$(ASLCC_FLAGS)', 'Value' : False},
784 }
785
786 RespDict = {}
787 FileTypeList = []
788 IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily]
789
790 # base on the source files to decide the file type
791 for File in self._AutoGenObject.SourceFileList:
792 for type in self._AutoGenObject.FileTypes:
793 if File in self._AutoGenObject.FileTypes[type]:
794 if type not in FileTypeList:
795 FileTypeList.append(type)
796
797 # calculate the command-line length
798 if FileTypeList:
799 for type in FileTypeList:
800 BuildTargets = self._AutoGenObject.BuildRules[type].BuildTargets
801 for Target in BuildTargets:
802 CommandList = BuildTargets[Target].Commands
803 for SingleCommand in CommandList:
804 Tool = ''
805 SingleCommandLength = len(SingleCommand)
806 SingleCommandList = SingleCommand.split()
807 if len(SingleCommandList) > 0:
808 for Flag in FlagDict:
809 if '$('+ Flag +')' in SingleCommandList[0]:
810 Tool = Flag
811 break
812 if Tool:
813 if 'PATH' not in self._AutoGenObject.BuildOption[Tool]:
814 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))
815 SingleCommandLength += len(self._AutoGenObject.BuildOption[Tool]['PATH'])
816 for item in SingleCommandList[1:]:
817 if FlagDict[Tool]['Macro'] in item:
818 if 'FLAGS' not in self._AutoGenObject.BuildOption[Tool]:
819 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))
820 Str = self._AutoGenObject.BuildOption[Tool]['FLAGS']
821 for Option in self._AutoGenObject.BuildOption:
822 for Attr in self._AutoGenObject.BuildOption[Option]:
823 if Str.find(Option + '_' + Attr) != -1:
824 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
825 while(Str.find('$(') != -1):
826 for macro in self._AutoGenObject.Macros:
827 MacroName = '$('+ macro + ')'
828 if (Str.find(MacroName) != -1):
829 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
830 break
831 else:
832 break
833 SingleCommandLength += len(Str)
834 elif '$(INC)' in item:
835 SingleCommandLength += self._AutoGenObject.IncludePathLength + len(IncPrefix) * len(self._AutoGenObject.IncludePathList)
836 elif item.find('$(') != -1:
837 Str = item
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
852 if SingleCommandLength > GlobalData.gCommandMaxLength:
853 FlagDict[Tool]['Value'] = True
854
855 # generate the response file content by combine the FLAGS and INC
856 for Flag in FlagDict:
857 if FlagDict[Flag]['Value']:
858 Key = Flag + '_RESP'
859 RespMacro = FlagDict[Flag]['Macro'].replace('FLAGS', 'RESP')
860 Value = self._AutoGenObject.BuildOption[Flag]['FLAGS']
861 for inc in self._AutoGenObject.IncludePathList:
862 Value += ' ' + IncPrefix + inc
863 for Option in self._AutoGenObject.BuildOption:
864 for Attr in self._AutoGenObject.BuildOption[Option]:
865 if Value.find(Option + '_' + Attr) != -1:
866 Value = Value.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
867 while (Value.find('$(') != -1):
868 for macro in self._AutoGenObject.Macros:
869 MacroName = '$('+ macro + ')'
870 if (Value.find(MacroName) != -1):
871 Value = Value.replace(MacroName, self._AutoGenObject.Macros[macro])
872 break
873 else:
874 break
875
876 if self._AutoGenObject.ToolChainFamily == 'GCC':
877 RespDict[Key] = Value.replace('\\', '/')
878 else:
879 RespDict[Key] = Value
880 for Target in BuildTargets:
881 for i, SingleCommand in enumerate(BuildTargets[Target].Commands):
882 if FlagDict[Flag]['Macro'] in SingleCommand:
883 BuildTargets[Target].Commands[i] = SingleCommand.replace('$(INC)', '').replace(FlagDict[Flag]['Macro'], RespMacro)
884 return RespDict
885
886 def ProcessBuildTargetList(self):
887 #
888 # Search dependency file list for each source file
889 #
890 ForceIncludedFile = []
891 for File in self._AutoGenObject.AutoGenFileList:
892 if File.Ext == '.h':
893 ForceIncludedFile.append(File)
894 SourceFileList = []
895 OutPutFileList = []
896 for Target in self._AutoGenObject.IntroTargetList:
897 SourceFileList.extend(Target.Inputs)
898 OutPutFileList.extend(Target.Outputs)
899
900 if OutPutFileList:
901 for Item in OutPutFileList:
902 if Item in SourceFileList:
903 SourceFileList.remove(Item)
904
905 FileDependencyDict = self.GetFileDependency(
906 SourceFileList,
907 ForceIncludedFile,
908 self._AutoGenObject.IncludePathList + self._AutoGenObject.BuildOptionIncPathList
909 )
910
911 self.DependencyHeaderFileSet = set()
912 if FileDependencyDict:
913 for Dependency in FileDependencyDict.values():
914 self.DependencyHeaderFileSet.update(set(Dependency))
915
916 # Get a set of unique package includes from MetaFile
917 parentMetaFileIncludes = set()
918 for aInclude in self._AutoGenObject.PackageIncludePathList:
919 aIncludeName = str(aInclude)
920 parentMetaFileIncludes.add(aIncludeName.lower())
921
922 # Check if header files are listed in metafile
923 # Get a set of unique module header source files from MetaFile
924 headerFilesInMetaFileSet = set()
925 for aFile in self._AutoGenObject.SourceFileList:
926 aFileName = str(aFile)
927 if not aFileName.endswith('.h'):
928 continue
929 headerFilesInMetaFileSet.add(aFileName.lower())
930
931 # Get a set of unique module autogen files
932 localAutoGenFileSet = set()
933 for aFile in self._AutoGenObject.AutoGenFileList:
934 localAutoGenFileSet.add(str(aFile).lower())
935
936 # Get a set of unique module dependency header files
937 # Exclude autogen files and files not in the source directory
938 # and files that are under the package include list
939 headerFileDependencySet = set()
940 localSourceDir = str(self._AutoGenObject.SourceDir).lower()
941 for Dependency in FileDependencyDict.values():
942 for aFile in Dependency:
943 aFileName = str(aFile).lower()
944 # Exclude non-header files
945 if not aFileName.endswith('.h'):
946 continue
947 # Exclude autogen files
948 if aFileName in localAutoGenFileSet:
949 continue
950 # Exclude include out of local scope
951 if localSourceDir not in aFileName:
952 continue
953 # Exclude files covered by package includes
954 pathNeeded = True
955 for aIncludePath in parentMetaFileIncludes:
956 if aIncludePath in aFileName:
957 pathNeeded = False
958 break
959 if not pathNeeded:
960 continue
961 # Keep the file to be checked
962 headerFileDependencySet.add(aFileName)
963
964 # Check if a module dependency header file is missing from the module's MetaFile
965 for aFile in headerFileDependencySet:
966 if aFile in headerFilesInMetaFileSet:
967 continue
968 if GlobalData.gUseHashCache:
969 GlobalData.gModuleBuildTracking[self._AutoGenObject] = 'FAIL_METAFILE'
970 EdkLogger.warn("build","Module MetaFile [Sources] is missing local header!",
971 ExtraData = "Local Header: " + aFile + " not found in " + self._AutoGenObject.MetaFile.Path
972 )
973
974 DepSet = None
975 for File,Dependency in FileDependencyDict.items():
976 if not Dependency:
977 FileDependencyDict[File] = ['$(FORCE_REBUILD)']
978 continue
979
980 self._AutoGenObject.AutoGenDepSet |= set(Dependency)
981
982 # skip non-C files
983 if File.Ext not in [".c", ".C"] or File.Name == "AutoGen.c":
984 continue
985 elif DepSet is None:
986 DepSet = set(Dependency)
987 else:
988 DepSet &= set(Dependency)
989 # in case nothing in SourceFileList
990 if DepSet is None:
991 DepSet = set()
992 #
993 # Extract common files list in the dependency files
994 #
995 for File in DepSet:
996 self.CommonFileDependency.append(self.PlaceMacro(File.Path, self.Macros))
997
998 CmdSumDict = {}
999 CmdTargetDict = {}
1000 CmdCppDict = {}
1001 DependencyDict = FileDependencyDict.copy()
1002 for File in FileDependencyDict:
1003 # skip non-C files
1004 if File.Ext not in [".c", ".C"] or File.Name == "AutoGen.c":
1005 continue
1006 NewDepSet = set(FileDependencyDict[File])
1007 NewDepSet -= DepSet
1008 FileDependencyDict[File] = ["$(COMMON_DEPS)"] + list(NewDepSet)
1009 DependencyDict[File] = list(NewDepSet)
1010
1011 # Convert target description object to target string in makefile
1012 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and TAB_C_CODE_FILE in self._AutoGenObject.Targets:
1013 for T in self._AutoGenObject.Targets[TAB_C_CODE_FILE]:
1014 NewFile = self.PlaceMacro(str(T), self.Macros)
1015 if not self.ObjTargetDict.get(T.Target.SubDir):
1016 self.ObjTargetDict[T.Target.SubDir] = set()
1017 self.ObjTargetDict[T.Target.SubDir].add(NewFile)
1018 for Type in self._AutoGenObject.Targets:
1019 for T in self._AutoGenObject.Targets[Type]:
1020 # Generate related macros if needed
1021 if T.GenFileListMacro and T.FileListMacro not in self.FileListMacros:
1022 self.FileListMacros[T.FileListMacro] = []
1023 if T.GenListFile and T.ListFileMacro not in self.ListFileMacros:
1024 self.ListFileMacros[T.ListFileMacro] = []
1025 if T.GenIncListFile and T.IncListFileMacro not in self.ListFileMacros:
1026 self.ListFileMacros[T.IncListFileMacro] = []
1027
1028 Deps = []
1029 CCodeDeps = []
1030 # Add force-dependencies
1031 for Dep in T.Dependencies:
1032 Deps.append(self.PlaceMacro(str(Dep), self.Macros))
1033 if Dep != '$(MAKE_FILE)':
1034 CCodeDeps.append(self.PlaceMacro(str(Dep), self.Macros))
1035 # Add inclusion-dependencies
1036 if len(T.Inputs) == 1 and T.Inputs[0] in FileDependencyDict:
1037 for F in FileDependencyDict[T.Inputs[0]]:
1038 Deps.append(self.PlaceMacro(str(F), self.Macros))
1039 # Add source-dependencies
1040 for F in T.Inputs:
1041 NewFile = self.PlaceMacro(str(F), self.Macros)
1042 # In order to use file list macro as dependency
1043 if T.GenListFile:
1044 # gnu tools need forward slash path separator, even on Windows
1045 self.ListFileMacros[T.ListFileMacro].append(str(F).replace ('\\', '/'))
1046 self.FileListMacros[T.FileListMacro].append(NewFile)
1047 elif T.GenFileListMacro:
1048 self.FileListMacros[T.FileListMacro].append(NewFile)
1049 else:
1050 Deps.append(NewFile)
1051 for key in self.FileListMacros:
1052 self.FileListMacros[key].sort()
1053 # Use file list macro as dependency
1054 if T.GenFileListMacro:
1055 Deps.append("$(%s)" % T.FileListMacro)
1056 if Type in [TAB_OBJECT_FILE, TAB_STATIC_LIBRARY]:
1057 Deps.append("$(%s)" % T.ListFileMacro)
1058
1059 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Type == TAB_C_CODE_FILE:
1060 T, CmdTarget, CmdTargetDict, CmdCppDict = self.ParserCCodeFile(T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict)
1061 TargetDict = {"target": self.PlaceMacro(T.Target.Path, self.Macros), "cmd": "\n\t".join(T.Commands),"deps": CCodeDeps}
1062 CmdLine = self._BUILD_TARGET_TEMPLATE.Replace(TargetDict).rstrip().replace('\t$(OBJLIST', '$(OBJLIST')
1063 if T.Commands:
1064 CmdLine = '%s%s' %(CmdLine, TAB_LINE_BREAK)
1065 if CCodeDeps or CmdLine:
1066 self.BuildTargetList.append(CmdLine)
1067 else:
1068 TargetDict = {"target": self.PlaceMacro(T.Target.Path, self.Macros), "cmd": "\n\t".join(T.Commands),"deps": Deps}
1069 self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(TargetDict))
1070
1071 def ParserCCodeFile(self, T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict):
1072 if not CmdSumDict:
1073 for item in self._AutoGenObject.Targets[Type]:
1074 CmdSumDict[item.Target.SubDir] = item.Target.BaseName
1075 for CppPath in item.Inputs:
1076 Path = self.PlaceMacro(CppPath.Path, self.Macros)
1077 if CmdCppDict.get(item.Target.SubDir):
1078 CmdCppDict[item.Target.SubDir].append(Path)
1079 else:
1080 CmdCppDict[item.Target.SubDir] = ['$(MAKE_FILE)', Path]
1081 if CppPath.Path in DependencyDict:
1082 for Temp in DependencyDict[CppPath.Path]:
1083 try:
1084 Path = self.PlaceMacro(Temp.Path, self.Macros)
1085 except:
1086 continue
1087 if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):
1088 CmdCppDict[item.Target.SubDir].append(Path)
1089 if T.Commands:
1090 CommandList = T.Commands[:]
1091 for Item in CommandList[:]:
1092 SingleCommandList = Item.split()
1093 if len(SingleCommandList) > 0 and self.CheckCCCmd(SingleCommandList):
1094 for Temp in SingleCommandList:
1095 if Temp.startswith('/Fo'):
1096 CmdSign = '%s%s' % (Temp.rsplit(TAB_SLASH, 1)[0], TAB_SLASH)
1097 break
1098 else: continue
1099 if CmdSign not in list(CmdTargetDict.keys()):
1100 CmdTargetDict[CmdSign] = Item.replace(Temp, CmdSign)
1101 else:
1102 CmdTargetDict[CmdSign] = "%s %s" % (CmdTargetDict[CmdSign], SingleCommandList[-1])
1103 Index = CommandList.index(Item)
1104 CommandList.pop(Index)
1105 if SingleCommandList[-1].endswith("%s%s.c" % (TAB_SLASH, CmdSumDict[CmdSign[3:].rsplit(TAB_SLASH, 1)[0]])):
1106 Cpplist = CmdCppDict[T.Target.SubDir]
1107 Cpplist.insert(0, '$(OBJLIST_%d): $(COMMON_DEPS)' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir))
1108 T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign])
1109 else:
1110 T.Commands.pop(Index)
1111 return T, CmdSumDict, CmdTargetDict, CmdCppDict
1112
1113 def CheckCCCmd(self, CommandList):
1114 for cmd in CommandList:
1115 if '$(CC)' in cmd:
1116 return True
1117 return False
1118 ## For creating makefile targets for dependent libraries
1119 def ProcessDependentLibrary(self):
1120 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1121 if not LibraryAutoGen.IsBinaryModule:
1122 self.LibraryBuildDirectoryList.append(self.PlaceMacro(LibraryAutoGen.BuildDir, self.Macros))
1123
1124 ## Return a list containing source file's dependencies
1125 #
1126 # @param FileList The list of source files
1127 # @param ForceInculeList The list of files which will be included forcely
1128 # @param SearchPathList The list of search path
1129 #
1130 # @retval dict The mapping between source file path and its dependencies
1131 #
1132 def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):
1133 Dependency = {}
1134 for F in FileList:
1135 Dependency[F] = GetDependencyList(self._AutoGenObject, self.FileCache, F, ForceInculeList, SearchPathList)
1136 return Dependency
1137
1138
1139 ## CustomMakefile class
1140 #
1141 # This class encapsules makefie and its generation for module. It uses template to generate
1142 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
1143 #
1144 class CustomMakefile(BuildFile):
1145 ## template used to generate the makefile for module with custom makefile
1146 _TEMPLATE_ = TemplateString('''\
1147 ${makefile_header}
1148
1149 #
1150 # Platform Macro Definition
1151 #
1152 PLATFORM_NAME = ${platform_name}
1153 PLATFORM_GUID = ${platform_guid}
1154 PLATFORM_VERSION = ${platform_version}
1155 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
1156 PLATFORM_DIR = ${platform_dir}
1157 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1158
1159 #
1160 # Module Macro Definition
1161 #
1162 MODULE_NAME = ${module_name}
1163 MODULE_GUID = ${module_guid}
1164 MODULE_NAME_GUID = ${module_name_guid}
1165 MODULE_VERSION = ${module_version}
1166 MODULE_TYPE = ${module_type}
1167 MODULE_FILE = ${module_file}
1168 MODULE_FILE_BASE_NAME = ${module_file_base_name}
1169 BASE_NAME = $(MODULE_NAME)
1170 MODULE_RELATIVE_DIR = ${module_relative_directory}
1171 MODULE_DIR = ${module_dir}
1172
1173 #
1174 # Build Configuration Macro Definition
1175 #
1176 ARCH = ${architecture}
1177 TOOLCHAIN = ${toolchain_tag}
1178 TOOLCHAIN_TAG = ${toolchain_tag}
1179 TARGET = ${build_target}
1180
1181 #
1182 # Build Directory Macro Definition
1183 #
1184 # PLATFORM_BUILD_DIR = ${platform_build_directory}
1185 BUILD_DIR = ${platform_build_directory}
1186 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
1187 LIB_DIR = $(BIN_DIR)
1188 MODULE_BUILD_DIR = ${module_build_directory}
1189 OUTPUT_DIR = ${module_output_directory}
1190 DEBUG_DIR = ${module_debug_directory}
1191 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
1192 DEST_DIR_DEBUG = $(DEBUG_DIR)
1193
1194 #
1195 # Tools definitions specific to this module
1196 #
1197 ${BEGIN}${module_tool_definitions}
1198 ${END}
1199 MAKE_FILE = ${makefile_path}
1200
1201 #
1202 # Shell Command Macro
1203 #
1204 ${BEGIN}${shell_command_code} = ${shell_command}
1205 ${END}
1206
1207 ${custom_makefile_content}
1208
1209 #
1210 # Target used when called from platform makefile, which will bypass the build of dependent libraries
1211 #
1212
1213 pbuild: init all
1214
1215
1216 #
1217 # ModuleTarget
1218 #
1219
1220 mbuild: init all
1221
1222 #
1223 # Build Target used in multi-thread build mode, which no init target is needed
1224 #
1225
1226 tbuild: all
1227
1228 #
1229 # Initialization target: print build information and create necessary directories
1230 #
1231 init:
1232 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
1233 ${BEGIN}\t-@${create_directory_command}\n${END}\
1234
1235 ''')
1236
1237 ## Constructor of CustomMakefile
1238 #
1239 # @param ModuleAutoGen Object of ModuleAutoGen class
1240 #
1241 def __init__(self, ModuleAutoGen):
1242 BuildFile.__init__(self, ModuleAutoGen)
1243 self.PlatformInfo = self._AutoGenObject.PlatformInfo
1244 self.IntermediateDirectoryList = ["$(DEBUG_DIR)", "$(OUTPUT_DIR)"]
1245
1246 # Compose a dict object containing information used to do replacement in template
1247 @property
1248 def _TemplateDict(self):
1249 Separator = self._SEP_[self._FileType]
1250 MyAgo = self._AutoGenObject
1251 if self._FileType not in MyAgo.CustomMakefile:
1252 EdkLogger.error('build', OPTION_NOT_SUPPORTED, "No custom makefile for %s" % self._FileType,
1253 ExtraData="[%s]" % str(MyAgo))
1254 MakefilePath = mws.join(
1255 MyAgo.WorkspaceDir,
1256 MyAgo.CustomMakefile[self._FileType]
1257 )
1258 try:
1259 CustomMakefile = open(MakefilePath, 'r').read()
1260 except:
1261 EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(MyAgo),
1262 ExtraData=MyAgo.CustomMakefile[self._FileType])
1263
1264 # tools definitions
1265 ToolsDef = []
1266 for Tool in MyAgo.BuildOption:
1267 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
1268 if Tool == "MAKE":
1269 continue
1270 for Attr in MyAgo.BuildOption[Tool]:
1271 if Attr == "FAMILY":
1272 continue
1273 elif Attr == "PATH":
1274 ToolsDef.append("%s = %s" % (Tool, MyAgo.BuildOption[Tool][Attr]))
1275 else:
1276 ToolsDef.append("%s_%s = %s" % (Tool, Attr, MyAgo.BuildOption[Tool][Attr]))
1277 ToolsDef.append("")
1278
1279 MakefileName = self._FILE_NAME_[self._FileType]
1280 MakefileTemplateDict = {
1281 "makefile_header" : self._FILE_HEADER_[self._FileType],
1282 "makefile_path" : os.path.join("$(MODULE_BUILD_DIR)", MakefileName),
1283 "platform_name" : self.PlatformInfo.Name,
1284 "platform_guid" : self.PlatformInfo.Guid,
1285 "platform_version" : self.PlatformInfo.Version,
1286 "platform_relative_directory": self.PlatformInfo.SourceDir,
1287 "platform_output_directory" : self.PlatformInfo.OutputDir,
1288 "platform_dir" : MyAgo.Macros["PLATFORM_DIR"],
1289
1290 "module_name" : MyAgo.Name,
1291 "module_guid" : MyAgo.Guid,
1292 "module_name_guid" : MyAgo.UniqueBaseName,
1293 "module_version" : MyAgo.Version,
1294 "module_type" : MyAgo.ModuleType,
1295 "module_file" : MyAgo.MetaFile,
1296 "module_file_base_name" : MyAgo.MetaFile.BaseName,
1297 "module_relative_directory" : MyAgo.SourceDir,
1298 "module_dir" : mws.join (MyAgo.WorkspaceDir, MyAgo.SourceDir),
1299
1300 "architecture" : MyAgo.Arch,
1301 "toolchain_tag" : MyAgo.ToolChain,
1302 "build_target" : MyAgo.BuildTarget,
1303
1304 "platform_build_directory" : self.PlatformInfo.BuildDir,
1305 "module_build_directory" : MyAgo.BuildDir,
1306 "module_output_directory" : MyAgo.OutputDir,
1307 "module_debug_directory" : MyAgo.DebugDir,
1308
1309 "separator" : Separator,
1310 "module_tool_definitions" : ToolsDef,
1311
1312 "shell_command_code" : list(self._SHELL_CMD_[self._FileType].keys()),
1313 "shell_command" : list(self._SHELL_CMD_[self._FileType].values()),
1314
1315 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1316 "custom_makefile_content" : CustomMakefile
1317 }
1318
1319 return MakefileTemplateDict
1320
1321 ## PlatformMakefile class
1322 #
1323 # This class encapsules makefie and its generation for platform. It uses
1324 # template to generate the content of makefile. The content of makefile will be
1325 # got from PlatformAutoGen object.
1326 #
1327 class PlatformMakefile(BuildFile):
1328 ## template used to generate the makefile for platform
1329 _TEMPLATE_ = TemplateString('''\
1330 ${makefile_header}
1331
1332 #
1333 # Platform Macro Definition
1334 #
1335 PLATFORM_NAME = ${platform_name}
1336 PLATFORM_GUID = ${platform_guid}
1337 PLATFORM_VERSION = ${platform_version}
1338 PLATFORM_FILE = ${platform_file}
1339 PLATFORM_DIR = ${platform_dir}
1340 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1341
1342 #
1343 # Build Configuration Macro Definition
1344 #
1345 TOOLCHAIN = ${toolchain_tag}
1346 TOOLCHAIN_TAG = ${toolchain_tag}
1347 TARGET = ${build_target}
1348
1349 #
1350 # Build Directory Macro Definition
1351 #
1352 BUILD_DIR = ${platform_build_directory}
1353 FV_DIR = ${platform_build_directory}${separator}FV
1354
1355 #
1356 # Shell Command Macro
1357 #
1358 ${BEGIN}${shell_command_code} = ${shell_command}
1359 ${END}
1360
1361 MAKE = ${make_path}
1362 MAKE_FILE = ${makefile_path}
1363
1364 #
1365 # Default target
1366 #
1367 all: init build_libraries build_modules
1368
1369 #
1370 # Initialization target: print build information and create necessary directories
1371 #
1372 init:
1373 \t-@echo Building ... $(PLATFORM_FILE) [${build_architecture_list}]
1374 \t${BEGIN}-@${create_directory_command}
1375 \t${END}
1376 #
1377 # library build target
1378 #
1379 libraries: init build_libraries
1380
1381 #
1382 # module build target
1383 #
1384 modules: init build_libraries build_modules
1385
1386 #
1387 # Build all libraries:
1388 #
1389 build_libraries:
1390 ${BEGIN}\t@"$(MAKE)" $(MAKE_FLAGS) -f ${library_makefile_list} pbuild
1391 ${END}\t@cd $(BUILD_DIR)
1392
1393 #
1394 # Build all modules:
1395 #
1396 build_modules:
1397 ${BEGIN}\t@"$(MAKE)" $(MAKE_FLAGS) -f ${module_makefile_list} pbuild
1398 ${END}\t@cd $(BUILD_DIR)
1399
1400 #
1401 # Clean intermediate files
1402 #
1403 clean:
1404 \t${BEGIN}-@${library_build_command} clean
1405 \t${END}${BEGIN}-@${module_build_command} clean
1406 \t${END}@cd $(BUILD_DIR)
1407
1408 #
1409 # Clean all generated files except to makefile
1410 #
1411 cleanall:
1412 ${BEGIN}\t${cleanall_command}
1413 ${END}
1414
1415 #
1416 # Clean all library files
1417 #
1418 cleanlib:
1419 \t${BEGIN}-@${library_build_command} cleanall
1420 \t${END}@cd $(BUILD_DIR)\n
1421 ''')
1422
1423 ## Constructor of PlatformMakefile
1424 #
1425 # @param ModuleAutoGen Object of PlatformAutoGen class
1426 #
1427 def __init__(self, PlatformAutoGen):
1428 BuildFile.__init__(self, PlatformAutoGen)
1429 self.ModuleBuildCommandList = []
1430 self.ModuleMakefileList = []
1431 self.IntermediateDirectoryList = []
1432 self.ModuleBuildDirectoryList = []
1433 self.LibraryBuildDirectoryList = []
1434 self.LibraryMakeCommandList = []
1435
1436 # Compose a dict object containing information used to do replacement in template
1437 @property
1438 def _TemplateDict(self):
1439 Separator = self._SEP_[self._FileType]
1440
1441 MyAgo = self._AutoGenObject
1442 if "MAKE" not in MyAgo.ToolDefinition or "PATH" not in MyAgo.ToolDefinition["MAKE"]:
1443 EdkLogger.error("build", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!",
1444 ExtraData="[%s]" % str(MyAgo))
1445
1446 self.IntermediateDirectoryList = ["$(BUILD_DIR)"]
1447 self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()
1448 self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()
1449
1450 MakefileName = self._FILE_NAME_[self._FileType]
1451 LibraryMakefileList = []
1452 LibraryMakeCommandList = []
1453 for D in self.LibraryBuildDirectoryList:
1454 D = self.PlaceMacro(D, {"BUILD_DIR":MyAgo.BuildDir})
1455 Makefile = os.path.join(D, MakefileName)
1456 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1457 LibraryMakefileList.append(Makefile)
1458 LibraryMakeCommandList.append(Command)
1459 self.LibraryMakeCommandList = LibraryMakeCommandList
1460
1461 ModuleMakefileList = []
1462 ModuleMakeCommandList = []
1463 for D in self.ModuleBuildDirectoryList:
1464 D = self.PlaceMacro(D, {"BUILD_DIR":MyAgo.BuildDir})
1465 Makefile = os.path.join(D, MakefileName)
1466 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1467 ModuleMakefileList.append(Makefile)
1468 ModuleMakeCommandList.append(Command)
1469
1470 MakefileTemplateDict = {
1471 "makefile_header" : self._FILE_HEADER_[self._FileType],
1472 "makefile_path" : os.path.join("$(BUILD_DIR)", MakefileName),
1473 "make_path" : MyAgo.ToolDefinition["MAKE"]["PATH"],
1474 "makefile_name" : MakefileName,
1475 "platform_name" : MyAgo.Name,
1476 "platform_guid" : MyAgo.Guid,
1477 "platform_version" : MyAgo.Version,
1478 "platform_file" : MyAgo.MetaFile,
1479 "platform_relative_directory": MyAgo.SourceDir,
1480 "platform_output_directory" : MyAgo.OutputDir,
1481 "platform_build_directory" : MyAgo.BuildDir,
1482 "platform_dir" : MyAgo.Macros["PLATFORM_DIR"],
1483
1484 "toolchain_tag" : MyAgo.ToolChain,
1485 "build_target" : MyAgo.BuildTarget,
1486 "shell_command_code" : list(self._SHELL_CMD_[self._FileType].keys()),
1487 "shell_command" : list(self._SHELL_CMD_[self._FileType].values()),
1488 "build_architecture_list" : MyAgo.Arch,
1489 "architecture" : MyAgo.Arch,
1490 "separator" : Separator,
1491 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1492 "cleanall_command" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1493 "library_makefile_list" : LibraryMakefileList,
1494 "module_makefile_list" : ModuleMakefileList,
1495 "library_build_command" : LibraryMakeCommandList,
1496 "module_build_command" : ModuleMakeCommandList,
1497 }
1498
1499 return MakefileTemplateDict
1500
1501 ## Get the root directory list for intermediate files of all modules build
1502 #
1503 # @retval list The list of directory
1504 #
1505 def GetModuleBuildDirectoryList(self):
1506 DirList = []
1507 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1508 if not ModuleAutoGen.IsBinaryModule:
1509 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1510 return DirList
1511
1512 ## Get the root directory list for intermediate files of all libraries build
1513 #
1514 # @retval list The list of directory
1515 #
1516 def GetLibraryBuildDirectoryList(self):
1517 DirList = []
1518 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1519 if not LibraryAutoGen.IsBinaryModule:
1520 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1521 return DirList
1522
1523 ## TopLevelMakefile class
1524 #
1525 # This class encapsules makefie and its generation for entrance makefile. It
1526 # uses template to generate the content of makefile. The content of makefile
1527 # will be got from WorkspaceAutoGen object.
1528 #
1529 class TopLevelMakefile(BuildFile):
1530 ## template used to generate toplevel makefile
1531 _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}''')
1532
1533 ## Constructor of TopLevelMakefile
1534 #
1535 # @param Workspace Object of WorkspaceAutoGen class
1536 #
1537 def __init__(self, Workspace):
1538 BuildFile.__init__(self, Workspace)
1539 self.IntermediateDirectoryList = []
1540
1541 # Compose a dict object containing information used to do replacement in template
1542 @property
1543 def _TemplateDict(self):
1544 Separator = self._SEP_[self._FileType]
1545
1546 # any platform autogen object is ok because we just need common information
1547 MyAgo = self._AutoGenObject
1548
1549 if "MAKE" not in MyAgo.ToolDefinition or "PATH" not in MyAgo.ToolDefinition["MAKE"]:
1550 EdkLogger.error("build", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!",
1551 ExtraData="[%s]" % str(MyAgo))
1552
1553 for Arch in MyAgo.ArchList:
1554 self.IntermediateDirectoryList.append(Separator.join(["$(BUILD_DIR)", Arch]))
1555 self.IntermediateDirectoryList.append("$(FV_DIR)")
1556
1557 # TRICK: for not generating GenFds call in makefile if no FDF file
1558 MacroList = []
1559 if MyAgo.FdfFile is not None and MyAgo.FdfFile != "":
1560 FdfFileList = [MyAgo.FdfFile]
1561 # macros passed to GenFds
1562 MacroDict = {}
1563 MacroDict.update(GlobalData.gGlobalDefines)
1564 MacroDict.update(GlobalData.gCommandLineDefines)
1565 for MacroName in MacroDict:
1566 if MacroDict[MacroName] != "":
1567 MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
1568 else:
1569 MacroList.append('"%s"' % MacroName)
1570 else:
1571 FdfFileList = []
1572
1573 # pass extra common options to external program called in makefile, currently GenFds.exe
1574 ExtraOption = ''
1575 LogLevel = EdkLogger.GetLevel()
1576 if LogLevel == EdkLogger.VERBOSE:
1577 ExtraOption += " -v"
1578 elif LogLevel <= EdkLogger.DEBUG_9:
1579 ExtraOption += " -d %d" % (LogLevel - 1)
1580 elif LogLevel == EdkLogger.QUIET:
1581 ExtraOption += " -q"
1582
1583 if GlobalData.gCaseInsensitive:
1584 ExtraOption += " -c"
1585 if not GlobalData.gEnableGenfdsMultiThread:
1586 ExtraOption += " --no-genfds-multi-thread"
1587 if GlobalData.gIgnoreSource:
1588 ExtraOption += " --ignore-sources"
1589
1590 for pcd in GlobalData.BuildOptionPcd:
1591 if pcd[2]:
1592 pcdname = '.'.join(pcd[0:3])
1593 else:
1594 pcdname = '.'.join(pcd[0:2])
1595 if pcd[3].startswith('{'):
1596 ExtraOption += " --pcd " + pcdname + '=' + 'H' + '"' + pcd[3] + '"'
1597 else:
1598 ExtraOption += " --pcd " + pcdname + '=' + pcd[3]
1599
1600 MakefileName = self._FILE_NAME_[self._FileType]
1601 SubBuildCommandList = []
1602 for A in MyAgo.ArchList:
1603 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join("$(BUILD_DIR)", A, MakefileName)}
1604 SubBuildCommandList.append(Command)
1605
1606 MakefileTemplateDict = {
1607 "makefile_header" : self._FILE_HEADER_[self._FileType],
1608 "makefile_path" : os.path.join("$(BUILD_DIR)", MakefileName),
1609 "make_path" : MyAgo.ToolDefinition["MAKE"]["PATH"],
1610 "platform_name" : MyAgo.Name,
1611 "platform_guid" : MyAgo.Guid,
1612 "platform_version" : MyAgo.Version,
1613 "platform_build_directory" : MyAgo.BuildDir,
1614 "conf_directory" : GlobalData.gConfDirectory,
1615
1616 "toolchain_tag" : MyAgo.ToolChain,
1617 "build_target" : MyAgo.BuildTarget,
1618 "shell_command_code" : list(self._SHELL_CMD_[self._FileType].keys()),
1619 "shell_command" : list(self._SHELL_CMD_[self._FileType].values()),
1620 'arch' : list(MyAgo.ArchList),
1621 "build_architecture_list" : ','.join(MyAgo.ArchList),
1622 "separator" : Separator,
1623 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1624 "cleanall_command" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1625 "sub_build_command" : SubBuildCommandList,
1626 "fdf_file" : FdfFileList,
1627 "active_platform" : str(MyAgo),
1628 "fd" : MyAgo.FdTargetList,
1629 "fv" : MyAgo.FvTargetList,
1630 "cap" : MyAgo.CapTargetList,
1631 "extra_options" : ExtraOption,
1632 "macro" : MacroList,
1633 }
1634
1635 return MakefileTemplateDict
1636
1637 ## Get the root directory list for intermediate files of all modules build
1638 #
1639 # @retval list The list of directory
1640 #
1641 def GetModuleBuildDirectoryList(self):
1642 DirList = []
1643 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1644 if not ModuleAutoGen.IsBinaryModule:
1645 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1646 return DirList
1647
1648 ## Get the root directory list for intermediate files of all libraries build
1649 #
1650 # @retval list The list of directory
1651 #
1652 def GetLibraryBuildDirectoryList(self):
1653 DirList = []
1654 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1655 if not LibraryAutoGen.IsBinaryModule:
1656 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1657 return DirList
1658
1659 ## Find dependencies for one source file
1660 #
1661 # By searching recursively "#include" directive in file, find out all the
1662 # files needed by given source file. The dependencies will be only searched
1663 # in given search path list.
1664 #
1665 # @param File The source file
1666 # @param ForceInculeList The list of files which will be included forcely
1667 # @param SearchPathList The list of search path
1668 #
1669 # @retval list The list of files the given source file depends on
1670 #
1671 def GetDependencyList(AutoGenObject, FileCache, File, ForceList, SearchPathList):
1672 EdkLogger.debug(EdkLogger.DEBUG_1, "Try to get dependency files for %s" % File)
1673 FileStack = [File] + ForceList
1674 DependencySet = set()
1675
1676 if AutoGenObject.Arch not in gDependencyDatabase:
1677 gDependencyDatabase[AutoGenObject.Arch] = {}
1678 DepDb = gDependencyDatabase[AutoGenObject.Arch]
1679
1680 while len(FileStack) > 0:
1681 F = FileStack.pop()
1682
1683 FullPathDependList = []
1684 if F in FileCache:
1685 for CacheFile in FileCache[F]:
1686 FullPathDependList.append(CacheFile)
1687 if CacheFile not in DependencySet:
1688 FileStack.append(CacheFile)
1689 DependencySet.update(FullPathDependList)
1690 continue
1691
1692 CurrentFileDependencyList = []
1693 if F in DepDb:
1694 CurrentFileDependencyList = DepDb[F]
1695 else:
1696 try:
1697 with open(F.Path, 'rb') as Fd:
1698 FileContent = Fd.read(1)
1699 Fd.seek(0)
1700 if not FileContent:
1701 continue
1702 if FileContent[0] == 0xff or FileContent[0] == 0xfe:
1703 FileContent2 = Fd.read()
1704 FileContent2 = FileContent2.decode('utf-16')
1705 IncludedFileList = gIncludePattern.findall(FileContent2)
1706 else:
1707 FileLines = Fd.readlines()
1708 FileContent2 = [line for line in FileLines if str(line).lstrip("#\t ")[:8] == "include "]
1709 simpleFileContent="".join(FileContent2)
1710
1711 IncludedFileList = gIncludePattern.findall(simpleFileContent)
1712 except BaseException as X:
1713 EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=F.Path + "\n\t" + str(X))
1714 if not FileContent:
1715 continue
1716
1717 for Inc in IncludedFileList:
1718 Inc = Inc.strip()
1719 # if there's macro used to reference header file, expand it
1720 HeaderList = gMacroPattern.findall(Inc)
1721 if len(HeaderList) == 1 and len(HeaderList[0]) == 2:
1722 HeaderType = HeaderList[0][0]
1723 HeaderKey = HeaderList[0][1]
1724 if HeaderType in gIncludeMacroConversion:
1725 Inc = gIncludeMacroConversion[HeaderType] % {"HeaderKey" : HeaderKey}
1726 else:
1727 # not known macro used in #include, always build the file by
1728 # returning a empty dependency
1729 FileCache[File] = []
1730 return []
1731 Inc = os.path.normpath(Inc)
1732 CurrentFileDependencyList.append(Inc)
1733 DepDb[F] = CurrentFileDependencyList
1734
1735 CurrentFilePath = F.Dir
1736 PathList = [CurrentFilePath] + SearchPathList
1737 for Inc in CurrentFileDependencyList:
1738 for SearchPath in PathList:
1739 FilePath = os.path.join(SearchPath, Inc)
1740 if FilePath in gIsFileMap:
1741 if not gIsFileMap[FilePath]:
1742 continue
1743 # If isfile is called too many times, the performance is slow down.
1744 elif not os.path.isfile(FilePath):
1745 gIsFileMap[FilePath] = False
1746 continue
1747 else:
1748 gIsFileMap[FilePath] = True
1749 FilePath = PathClass(FilePath)
1750 FullPathDependList.append(FilePath)
1751 if FilePath not in DependencySet:
1752 FileStack.append(FilePath)
1753 break
1754 else:
1755 EdkLogger.debug(EdkLogger.DEBUG_9, "%s included by %s was not found "\
1756 "in any given path:\n\t%s" % (Inc, F, "\n\t".join(SearchPathList)))
1757
1758 FileCache[F] = FullPathDependList
1759 DependencySet.update(FullPathDependList)
1760
1761 DependencySet.update(ForceList)
1762 if File in DependencySet:
1763 DependencySet.remove(File)
1764 DependencyList = list(DependencySet) # remove duplicate ones
1765
1766 return DependencyList
1767
1768 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1769 if __name__ == '__main__':
1770 pass