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