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