]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/AutoGen/GenMake.py
da406e6ff468e41794a2d5a25d12b06056a2e6fe
[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 - 2021, Intel Corporation. All rights reserved.<BR>
5 # Copyright (c) 2020 - 2021, 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", "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 MakePath = AutoGenObject.ToolDefinition.get('MAKE', {}).get('PATH')
181 if "nmake" in MakePath:
182 self._FileType = NMAKE_FILETYPE
183 else:
184 self._FileType = GMAKE_FILETYPE
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 sorted(list(MyAgo.BuildOption)):
523 Appended = False
524 for Attr in sorted(list(MyAgo.BuildOption[Tool])):
525 Value = MyAgo.BuildOption[Tool][Attr]
526 if Attr == "FAMILY":
527 continue
528 elif Attr == "PATH":
529 ToolsDef.append("%s = %s" % (Tool, Value))
530 Appended = True
531 else:
532 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
533 if Tool == "MAKE":
534 continue
535 # Remove duplicated include path, if any
536 if Attr == "FLAGS":
537 Value = RemoveDupOption(Value, IncPrefix, MyAgo.IncludePathList)
538 if Tool == "OPTROM" and PCI_COMPRESS_Flag:
539 ValueList = Value.split()
540 if ValueList:
541 for i, v in enumerate(ValueList):
542 if '-e' == v:
543 ValueList[i] = '-ec'
544 Value = ' '.join(ValueList)
545
546 ToolsDef.append("%s_%s = %s" % (Tool, Attr, Value))
547 Appended = True
548 if Appended:
549 ToolsDef.append("")
550
551 # generate the Response file and Response flag
552 RespDict = self.CommandExceedLimit()
553 RespFileList = os.path.join(MyAgo.OutputDir, 'respfilelist.txt')
554 if RespDict:
555 RespFileListContent = ''
556 for Resp in RespDict:
557 RespFile = os.path.join(MyAgo.OutputDir, str(Resp).lower() + '.txt')
558 StrList = RespDict[Resp].split(' ')
559 UnexpandMacro = []
560 NewStr = []
561 for Str in StrList:
562 if '$' in Str or '-MMD' in Str or '-MF' in Str:
563 UnexpandMacro.append(Str)
564 else:
565 NewStr.append(Str)
566 UnexpandMacroStr = ' '.join(UnexpandMacro)
567 NewRespStr = ' '.join(NewStr)
568 SaveFileOnChange(RespFile, NewRespStr, False)
569 ToolsDef.append("%s = %s" % (Resp, UnexpandMacroStr + ' @' + RespFile))
570 RespFileListContent += '@' + RespFile + TAB_LINE_BREAK
571 RespFileListContent += NewRespStr + TAB_LINE_BREAK
572 SaveFileOnChange(RespFileList, RespFileListContent, False)
573 else:
574 if os.path.exists(RespFileList):
575 os.remove(RespFileList)
576
577 # convert source files and binary files to build targets
578 self.ResultFileList = [str(T.Target) for T in MyAgo.CodaTargetList]
579 if len(self.ResultFileList) == 0 and len(MyAgo.SourceFileList) != 0:
580 EdkLogger.error("build", AUTOGEN_ERROR, "Nothing to build",
581 ExtraData="[%s]" % str(MyAgo))
582
583 self.ProcessBuildTargetList(MyAgo.OutputDir, ToolsDef)
584 self.ParserGenerateFfsCmd()
585
586 # Generate macros used to represent input files
587 FileMacroList = [] # macro name = file list
588 for FileListMacro in self.FileListMacros:
589 FileMacro = self._FILE_MACRO_TEMPLATE.Replace(
590 {
591 "macro_name" : FileListMacro,
592 "source_file" : self.FileListMacros[FileListMacro]
593 }
594 )
595 FileMacroList.append(FileMacro)
596
597 # INC_LIST is special
598 FileMacro = ""
599 IncludePathList = []
600 for P in MyAgo.IncludePathList:
601 IncludePathList.append(IncPrefix + self.PlaceMacro(P, self.Macros))
602 if FileBuildRule.INC_LIST_MACRO in self.ListFileMacros:
603 self.ListFileMacros[FileBuildRule.INC_LIST_MACRO].append(IncPrefix + P)
604 FileMacro += self._FILE_MACRO_TEMPLATE.Replace(
605 {
606 "macro_name" : "INC",
607 "source_file" : IncludePathList
608 }
609 )
610 FileMacroList.append(FileMacro)
611 # Add support when compiling .nasm source files
612 IncludePathList = []
613 asmsource = [item for item in MyAgo.SourceFileList if item.File.upper().endswith((".NASM",".ASM",".NASMB","S"))]
614 if asmsource:
615 for P in MyAgo.IncludePathList:
616 IncludePath = self._INC_FLAG_['NASM'] + self.PlaceMacro(P, self.Macros)
617 if IncludePath.endswith(os.sep):
618 IncludePath = IncludePath.rstrip(os.sep)
619 # When compiling .nasm files, need to add a literal backslash at each path.
620 # In nmake makfiles, a trailing literal backslash must be escaped with a caret ('^').
621 # It is otherwise replaced with a space (' '). This is not necessary for GNU makfefiles.
622 if P == MyAgo.IncludePathList[-1] and self._Platform == WIN32_PLATFORM and self._FileType == NMAKE_FILETYPE:
623 IncludePath = ''.join([IncludePath, '^', os.sep])
624 else:
625 IncludePath = os.path.join(IncludePath, '')
626 IncludePathList.append(IncludePath)
627 FileMacroList.append(self._FILE_MACRO_TEMPLATE.Replace({"macro_name": "NASM_INC", "source_file": IncludePathList}))
628
629 # Generate macros used to represent files containing list of input files
630 for ListFileMacro in self.ListFileMacros:
631 ListFileName = os.path.join(MyAgo.OutputDir, "%s.lst" % ListFileMacro.lower()[:len(ListFileMacro) - 5])
632 FileMacroList.append("%s = %s" % (ListFileMacro, ListFileName))
633 SaveFileOnChange(
634 ListFileName,
635 "\n".join(self.ListFileMacros[ListFileMacro]),
636 False
637 )
638
639 # Generate objlist used to create .obj file
640 for Type in self.ObjTargetDict:
641 NewLine = ' '.join(list(self.ObjTargetDict[Type]))
642 FileMacroList.append("OBJLIST_%s = %s" % (list(self.ObjTargetDict.keys()).index(Type), NewLine))
643
644 BcTargetList = []
645
646 MakefileName = self.getMakefileName()
647 LibraryMakeCommandList = []
648 for D in self.LibraryBuildDirectoryList:
649 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":os.path.join(D, MakefileName)}
650 LibraryMakeCommandList.append(Command)
651
652 package_rel_dir = MyAgo.SourceDir
653 current_dir = self.Macros["WORKSPACE"]
654 found = False
655 while not found and os.sep in package_rel_dir:
656 index = package_rel_dir.index(os.sep)
657 current_dir = mws.join(current_dir, package_rel_dir[:index])
658 if os.path.exists(current_dir):
659 for fl in os.listdir(current_dir):
660 if fl.endswith('.dec'):
661 found = True
662 break
663 package_rel_dir = package_rel_dir[index + 1:]
664
665 MakefileTemplateDict = {
666 "makefile_header" : self._FILE_HEADER_[self._FileType],
667 "makefile_path" : os.path.join("$(MODULE_BUILD_DIR)", MakefileName),
668 "makefile_name" : MakefileName,
669 "platform_name" : self.PlatformInfo.Name,
670 "platform_guid" : self.PlatformInfo.Guid,
671 "platform_version" : self.PlatformInfo.Version,
672 "platform_relative_directory": self.PlatformInfo.SourceDir,
673 "platform_output_directory" : self.PlatformInfo.OutputDir,
674 "ffs_output_directory" : MyAgo.Macros["FFS_OUTPUT_DIR"],
675 "platform_dir" : MyAgo.Macros["PLATFORM_DIR"],
676
677 "module_name" : MyAgo.Name,
678 "module_guid" : MyAgo.Guid,
679 "module_name_guid" : MyAgo.UniqueBaseName,
680 "module_version" : MyAgo.Version,
681 "module_type" : MyAgo.ModuleType,
682 "module_file" : MyAgo.MetaFile.Name,
683 "module_file_base_name" : MyAgo.MetaFile.BaseName,
684 "module_relative_directory" : MyAgo.SourceDir,
685 "module_dir" : mws.join (self.Macros["WORKSPACE"], MyAgo.SourceDir),
686 "package_relative_directory": package_rel_dir,
687 "module_extra_defines" : ["%s = %s" % (k, v) for k, v in MyAgo.Module.Defines.items()],
688
689 "architecture" : MyAgo.Arch,
690 "toolchain_tag" : MyAgo.ToolChain,
691 "build_target" : MyAgo.BuildTarget,
692
693 "platform_build_directory" : self.PlatformInfo.BuildDir,
694 "module_build_directory" : MyAgo.BuildDir,
695 "module_output_directory" : MyAgo.OutputDir,
696 "module_debug_directory" : MyAgo.DebugDir,
697
698 "separator" : Separator,
699 "module_tool_definitions" : ToolsDef,
700
701 "shell_command_code" : list(self._SHELL_CMD_[self._Platform].keys()),
702 "shell_command" : list(self._SHELL_CMD_[self._Platform].values()),
703
704 "module_entry_point" : ModuleEntryPoint,
705 "image_entry_point" : ImageEntryPoint,
706 "arch_entry_point" : ArchEntryPoint,
707 "remaining_build_target" : self.ResultFileList,
708 "common_dependency_file" : self.CommonFileDependency,
709 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
710 "clean_command" : self.GetRemoveDirectoryCommand(["$(OUTPUT_DIR)"]),
711 "cleanall_command" : self.GetRemoveDirectoryCommand(["$(DEBUG_DIR)", "$(OUTPUT_DIR)"]),
712 "dependent_library_build_directory" : self.LibraryBuildDirectoryList,
713 "library_build_command" : LibraryMakeCommandList,
714 "file_macro" : FileMacroList,
715 "file_build_target" : self.BuildTargetList,
716 "backward_compatible_target": BcTargetList,
717 "INCLUDETAG" : "\n".join([self._INCLUDE_CMD_[self._FileType] + " " + os.path.join("$(MODULE_BUILD_DIR)","dependency"),
718 self._INCLUDE_CMD_[self._FileType] + " " + os.path.join("$(MODULE_BUILD_DIR)","deps_target")
719 ])
720 }
721
722 return MakefileTemplateDict
723
724 def ParserGenerateFfsCmd(self):
725 #Add Ffs cmd to self.BuildTargetList
726 OutputFile = ''
727 DepsFileList = []
728
729 for Cmd in self.GenFfsList:
730 if Cmd[2]:
731 for CopyCmd in Cmd[2]:
732 Src, Dst = CopyCmd
733 Src = self.ReplaceMacro(Src)
734 Dst = self.ReplaceMacro(Dst)
735 if Dst not in self.ResultFileList:
736 self.ResultFileList.append(Dst)
737 if '%s :' %(Dst) not in self.BuildTargetList:
738 self.BuildTargetList.append("%s : %s" %(Dst,Src))
739 self.BuildTargetList.append('\t' + self._CP_TEMPLATE_[self._Platform] %{'Src': Src, 'Dst': Dst})
740
741 FfsCmdList = Cmd[0]
742 for index, Str in enumerate(FfsCmdList):
743 if '-o' == Str:
744 OutputFile = FfsCmdList[index + 1]
745 if '-i' == Str or "-oi" == Str:
746 if DepsFileList == []:
747 DepsFileList = [FfsCmdList[index + 1]]
748 else:
749 DepsFileList.append(FfsCmdList[index + 1])
750 DepsFileString = ' '.join(DepsFileList).strip()
751 if DepsFileString == '':
752 continue
753 OutputFile = self.ReplaceMacro(OutputFile)
754 self.ResultFileList.append(OutputFile)
755 DepsFileString = self.ReplaceMacro(DepsFileString)
756 self.BuildTargetList.append('%s : %s' % (OutputFile, DepsFileString))
757 CmdString = ' '.join(FfsCmdList).strip()
758 CmdString = self.ReplaceMacro(CmdString)
759 self.BuildTargetList.append('\t%s' % CmdString)
760
761 self.ParseSecCmd(DepsFileList, Cmd[1])
762 for SecOutputFile, SecDepsFile, SecCmd in self.FfsOutputFileList :
763 self.BuildTargetList.append('%s : %s' % (self.ReplaceMacro(SecOutputFile), self.ReplaceMacro(SecDepsFile)))
764 self.BuildTargetList.append('\t%s' % self.ReplaceMacro(SecCmd))
765 self.FfsOutputFileList = []
766
767 def ParseSecCmd(self, OutputFileList, CmdTuple):
768 for OutputFile in OutputFileList:
769 for SecCmdStr in CmdTuple:
770 SecDepsFileList = []
771 SecCmdList = SecCmdStr.split()
772 CmdName = SecCmdList[0]
773 for index, CmdItem in enumerate(SecCmdList):
774 if '-o' == CmdItem and OutputFile == SecCmdList[index + 1]:
775 index = index + 1
776 while index + 1 < len(SecCmdList):
777 if not SecCmdList[index+1].startswith('-'):
778 SecDepsFileList.append(SecCmdList[index + 1])
779 index = index + 1
780 if CmdName == 'Trim':
781 SecDepsFileList.append(os.path.join('$(DEBUG_DIR)', os.path.basename(OutputFile).replace('offset', 'efi')))
782 if OutputFile.endswith('.ui') or OutputFile.endswith('.ver'):
783 SecDepsFileList.append(os.path.join('$(MODULE_DIR)', '$(MODULE_FILE)'))
784 self.FfsOutputFileList.append((OutputFile, ' '.join(SecDepsFileList), SecCmdStr))
785 if len(SecDepsFileList) > 0:
786 self.ParseSecCmd(SecDepsFileList, CmdTuple)
787 break
788 else:
789 continue
790
791 def ReplaceMacro(self, str):
792 for Macro in self.MacroList:
793 if self._AutoGenObject.Macros[Macro] and os.path.normcase(self._AutoGenObject.Macros[Macro]) in os.path.normcase(str):
794 replace_dir = str[os.path.normcase(str).index(os.path.normcase(self._AutoGenObject.Macros[Macro])): os.path.normcase(str).index(
795 os.path.normcase(self._AutoGenObject.Macros[Macro])) + len(self._AutoGenObject.Macros[Macro])]
796 str = str.replace(replace_dir, '$(' + Macro + ')')
797 return str
798
799 def CommandExceedLimit(self):
800 FlagDict = {
801 'CC' : { 'Macro' : '$(CC_FLAGS)', 'Value' : False},
802 'PP' : { 'Macro' : '$(PP_FLAGS)', 'Value' : False},
803 'APP' : { 'Macro' : '$(APP_FLAGS)', 'Value' : False},
804 'ASLPP' : { 'Macro' : '$(ASLPP_FLAGS)', 'Value' : False},
805 'VFRPP' : { 'Macro' : '$(VFRPP_FLAGS)', 'Value' : False},
806 'ASM' : { 'Macro' : '$(ASM_FLAGS)', 'Value' : False},
807 'ASLCC' : { 'Macro' : '$(ASLCC_FLAGS)', 'Value' : False},
808 }
809
810 RespDict = {}
811 FileTypeList = []
812 IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily]
813
814 # base on the source files to decide the file type
815 for File in self._AutoGenObject.SourceFileList:
816 for type in self._AutoGenObject.FileTypes:
817 if File in self._AutoGenObject.FileTypes[type]:
818 if type not in FileTypeList:
819 FileTypeList.append(type)
820
821 # calculate the command-line length
822 if FileTypeList:
823 for type in FileTypeList:
824 BuildTargets = self._AutoGenObject.BuildRules[type].BuildTargets
825 for Target in BuildTargets:
826 CommandList = BuildTargets[Target].Commands
827 for SingleCommand in CommandList:
828 Tool = ''
829 SingleCommandLength = len(SingleCommand)
830 SingleCommandList = SingleCommand.split()
831 if len(SingleCommandList) > 0:
832 for Flag in FlagDict:
833 if '$('+ Flag +')' in SingleCommandList[0]:
834 Tool = Flag
835 break
836 if Tool:
837 if 'PATH' not in self._AutoGenObject.BuildOption[Tool]:
838 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))
839 SingleCommandLength += len(self._AutoGenObject.BuildOption[Tool]['PATH'])
840 for item in SingleCommandList[1:]:
841 if FlagDict[Tool]['Macro'] in item:
842 if 'FLAGS' not in self._AutoGenObject.BuildOption[Tool]:
843 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))
844 Str = self._AutoGenObject.BuildOption[Tool]['FLAGS']
845 for Option in self._AutoGenObject.BuildOption:
846 for Attr in self._AutoGenObject.BuildOption[Option]:
847 if Str.find(Option + '_' + Attr) != -1:
848 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
849 while(Str.find('$(') != -1):
850 for macro in self._AutoGenObject.Macros:
851 MacroName = '$('+ macro + ')'
852 if (Str.find(MacroName) != -1):
853 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
854 break
855 else:
856 break
857 SingleCommandLength += len(Str)
858 elif '$(INC)' in item:
859 SingleCommandLength += self._AutoGenObject.IncludePathLength + len(IncPrefix) * len(self._AutoGenObject.IncludePathList)
860 elif item.find('$(') != -1:
861 Str = item
862 for Option in self._AutoGenObject.BuildOption:
863 for Attr in self._AutoGenObject.BuildOption[Option]:
864 if Str.find(Option + '_' + Attr) != -1:
865 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
866 while(Str.find('$(') != -1):
867 for macro in self._AutoGenObject.Macros:
868 MacroName = '$('+ macro + ')'
869 if (Str.find(MacroName) != -1):
870 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])
871 break
872 else:
873 break
874 SingleCommandLength += len(Str)
875
876 if SingleCommandLength > GlobalData.gCommandMaxLength:
877 FlagDict[Tool]['Value'] = True
878
879 # generate the response file content by combine the FLAGS and INC
880 for Flag in FlagDict:
881 if FlagDict[Flag]['Value']:
882 Key = Flag + '_RESP'
883 RespMacro = FlagDict[Flag]['Macro'].replace('FLAGS', 'RESP')
884 Value = self._AutoGenObject.BuildOption[Flag]['FLAGS']
885 for inc in self._AutoGenObject.IncludePathList:
886 Value += ' ' + IncPrefix + inc
887 for Option in self._AutoGenObject.BuildOption:
888 for Attr in self._AutoGenObject.BuildOption[Option]:
889 if Value.find(Option + '_' + Attr) != -1:
890 Value = Value.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])
891 while (Value.find('$(') != -1):
892 for macro in self._AutoGenObject.Macros:
893 MacroName = '$('+ macro + ')'
894 if (Value.find(MacroName) != -1):
895 Value = Value.replace(MacroName, self._AutoGenObject.Macros[macro])
896 break
897 else:
898 break
899
900 if self._AutoGenObject.ToolChainFamily == 'GCC':
901 RespDict[Key] = Value.replace('\\', '/')
902 else:
903 RespDict[Key] = Value
904 for Target in BuildTargets:
905 for i, SingleCommand in enumerate(BuildTargets[Target].Commands):
906 if FlagDict[Flag]['Macro'] in SingleCommand:
907 BuildTargets[Target].Commands[i] = SingleCommand.replace('$(INC)', '').replace(FlagDict[Flag]['Macro'], RespMacro)
908 return RespDict
909
910 def ProcessBuildTargetList(self, RespFile, ToolsDef):
911 #
912 # Search dependency file list for each source file
913 #
914 ForceIncludedFile = []
915 for File in self._AutoGenObject.AutoGenFileList:
916 if File.Ext == '.h':
917 ForceIncludedFile.append(File)
918 SourceFileList = []
919 OutPutFileList = []
920 for Target in self._AutoGenObject.IntroTargetList:
921 SourceFileList.extend(Target.Inputs)
922 OutPutFileList.extend(Target.Outputs)
923
924 if OutPutFileList:
925 for Item in OutPutFileList:
926 if Item in SourceFileList:
927 SourceFileList.remove(Item)
928
929 FileDependencyDict = {item:ForceIncludedFile for item in SourceFileList}
930
931 for Dependency in FileDependencyDict.values():
932 self.DependencyHeaderFileSet.update(set(Dependency))
933
934 # Get a set of unique package includes from MetaFile
935 parentMetaFileIncludes = set()
936 for aInclude in self._AutoGenObject.PackageIncludePathList:
937 aIncludeName = str(aInclude)
938 parentMetaFileIncludes.add(aIncludeName.lower())
939
940 # Check if header files are listed in metafile
941 # Get a set of unique module header source files from MetaFile
942 headerFilesInMetaFileSet = set()
943 for aFile in self._AutoGenObject.SourceFileList:
944 aFileName = str(aFile)
945 if not aFileName.endswith('.h'):
946 continue
947 headerFilesInMetaFileSet.add(aFileName.lower())
948
949 # Get a set of unique module autogen files
950 localAutoGenFileSet = set()
951 for aFile in self._AutoGenObject.AutoGenFileList:
952 localAutoGenFileSet.add(str(aFile).lower())
953
954 # Get a set of unique module dependency header files
955 # Exclude autogen files and files not in the source directory
956 # and files that are under the package include list
957 headerFileDependencySet = set()
958 localSourceDir = str(self._AutoGenObject.SourceDir).lower()
959 for Dependency in FileDependencyDict.values():
960 for aFile in Dependency:
961 aFileName = str(aFile).lower()
962 # Exclude non-header files
963 if not aFileName.endswith('.h'):
964 continue
965 # Exclude autogen files
966 if aFileName in localAutoGenFileSet:
967 continue
968 # Exclude include out of local scope
969 if localSourceDir not in aFileName:
970 continue
971 # Exclude files covered by package includes
972 pathNeeded = True
973 for aIncludePath in parentMetaFileIncludes:
974 if aIncludePath in aFileName:
975 pathNeeded = False
976 break
977 if not pathNeeded:
978 continue
979 # Keep the file to be checked
980 headerFileDependencySet.add(aFileName)
981
982 # Check if a module dependency header file is missing from the module's MetaFile
983 for aFile in headerFileDependencySet:
984 if aFile in headerFilesInMetaFileSet:
985 continue
986 if GlobalData.gUseHashCache:
987 GlobalData.gModuleBuildTracking[self._AutoGenObject] = 'FAIL_METAFILE'
988 EdkLogger.warn("build","Module MetaFile [Sources] is missing local header!",
989 ExtraData = "Local Header: " + aFile + " not found in " + self._AutoGenObject.MetaFile.Path
990 )
991
992 for File,Dependency in FileDependencyDict.items():
993 if not Dependency:
994 continue
995
996 self._AutoGenObject.AutoGenDepSet |= set(Dependency)
997
998 CmdSumDict = {}
999 CmdTargetDict = {}
1000 CmdCppDict = {}
1001 DependencyDict = FileDependencyDict.copy()
1002
1003 # Convert target description object to target string in makefile
1004 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and TAB_C_CODE_FILE in self._AutoGenObject.Targets:
1005 for T in self._AutoGenObject.Targets[TAB_C_CODE_FILE]:
1006 NewFile = self.PlaceMacro(str(T), self.Macros)
1007 if not self.ObjTargetDict.get(T.Target.SubDir):
1008 self.ObjTargetDict[T.Target.SubDir] = set()
1009 self.ObjTargetDict[T.Target.SubDir].add(NewFile)
1010 for Type in self._AutoGenObject.Targets:
1011 resp_file_number = 0
1012 for T in self._AutoGenObject.Targets[Type]:
1013 # Generate related macros if needed
1014 if T.GenFileListMacro and T.FileListMacro not in self.FileListMacros:
1015 self.FileListMacros[T.FileListMacro] = []
1016 if T.GenListFile and T.ListFileMacro not in self.ListFileMacros:
1017 self.ListFileMacros[T.ListFileMacro] = []
1018 if T.GenIncListFile and T.IncListFileMacro not in self.ListFileMacros:
1019 self.ListFileMacros[T.IncListFileMacro] = []
1020
1021 Deps = []
1022 CCodeDeps = []
1023 # Add force-dependencies
1024 for Dep in T.Dependencies:
1025 Deps.append(self.PlaceMacro(str(Dep), self.Macros))
1026 if Dep != '$(MAKE_FILE)':
1027 CCodeDeps.append(self.PlaceMacro(str(Dep), self.Macros))
1028 # Add inclusion-dependencies
1029 if len(T.Inputs) == 1 and T.Inputs[0] in FileDependencyDict:
1030 for F in FileDependencyDict[T.Inputs[0]]:
1031 Deps.append(self.PlaceMacro(str(F), self.Macros))
1032 # Add source-dependencies
1033 for F in T.Inputs:
1034 NewFile = self.PlaceMacro(str(F), self.Macros)
1035 # In order to use file list macro as dependency
1036 if T.GenListFile:
1037 # gnu tools need forward slash path separator, even on Windows
1038 self.ListFileMacros[T.ListFileMacro].append(str(F).replace ('\\', '/'))
1039 self.FileListMacros[T.FileListMacro].append(NewFile)
1040 elif T.GenFileListMacro:
1041 self.FileListMacros[T.FileListMacro].append(NewFile)
1042 else:
1043 Deps.append(NewFile)
1044 for key in self.FileListMacros:
1045 self.FileListMacros[key].sort()
1046 # Use file list macro as dependency
1047 if T.GenFileListMacro:
1048 Deps.append("$(%s)" % T.FileListMacro)
1049 if Type in [TAB_OBJECT_FILE, TAB_STATIC_LIBRARY]:
1050 Deps.append("$(%s)" % T.ListFileMacro)
1051
1052 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Type == TAB_C_CODE_FILE:
1053 T, CmdTarget, CmdTargetDict, CmdCppDict = self.ParserCCodeFile(T, Type, CmdSumDict, CmdTargetDict,
1054 CmdCppDict, DependencyDict, RespFile,
1055 ToolsDef, resp_file_number)
1056 resp_file_number += 1
1057 TargetDict = {"target": self.PlaceMacro(T.Target.Path, self.Macros), "cmd": "\n\t".join(T.Commands),"deps": CCodeDeps}
1058 CmdLine = self._BUILD_TARGET_TEMPLATE.Replace(TargetDict).rstrip().replace('\t$(OBJLIST', '$(OBJLIST')
1059 if T.Commands:
1060 CmdLine = '%s%s' %(CmdLine, TAB_LINE_BREAK)
1061 if CCodeDeps or CmdLine:
1062 self.BuildTargetList.append(CmdLine)
1063 else:
1064 TargetDict = {"target": self.PlaceMacro(T.Target.Path, self.Macros), "cmd": "\n\t".join(T.Commands),"deps": Deps}
1065 self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(TargetDict))
1066
1067 # Add a Makefile rule for targets generating multiple files.
1068 # The main output is a prerequisite for the other output files.
1069 for i in T.Outputs[1:]:
1070 AnnexeTargetDict = {"target": self.PlaceMacro(i.Path, self.Macros), "cmd": "", "deps": self.PlaceMacro(T.Target.Path, self.Macros)}
1071 self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(AnnexeTargetDict))
1072
1073 def ParserCCodeFile(self, T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict, RespFile, ToolsDef,
1074 resp_file_number):
1075 SaveFilePath = os.path.join(RespFile, "cc_resp_%s.txt" % resp_file_number)
1076 if not CmdSumDict:
1077 for item in self._AutoGenObject.Targets[Type]:
1078 CmdSumDict[item.Target.SubDir] = item.Target.BaseName
1079 for CppPath in item.Inputs:
1080 Path = self.PlaceMacro(CppPath.Path, self.Macros)
1081 if CmdCppDict.get(item.Target.SubDir):
1082 CmdCppDict[item.Target.SubDir].append(Path)
1083 else:
1084 CmdCppDict[item.Target.SubDir] = ['$(MAKE_FILE)', Path]
1085 if CppPath.Path in DependencyDict:
1086 for Temp in DependencyDict[CppPath.Path]:
1087 try:
1088 Path = self.PlaceMacro(Temp.Path, self.Macros)
1089 except:
1090 continue
1091 if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):
1092 CmdCppDict[item.Target.SubDir].append(Path)
1093 if T.Commands:
1094 CommandList = T.Commands[:]
1095 for Item in CommandList[:]:
1096 SingleCommandList = Item.split()
1097 if len(SingleCommandList) > 0 and self.CheckCCCmd(SingleCommandList):
1098 for Temp in SingleCommandList:
1099 if Temp.startswith('/Fo'):
1100 CmdSign = '%s%s' % (Temp.rsplit(TAB_SLASH, 1)[0], TAB_SLASH)
1101 break
1102 else:
1103 continue
1104 if CmdSign not in list(CmdTargetDict.keys()):
1105 cmd = Item.replace(Temp, CmdSign)
1106 if SingleCommandList[-1] in cmd:
1107 CmdTargetDict[CmdSign] = [cmd.replace(SingleCommandList[-1], "").rstrip(), SingleCommandList[-1]]
1108 else:
1109 # CmdTargetDict[CmdSign] = "%s %s" % (CmdTargetDict[CmdSign], SingleCommandList[-1])
1110 CmdTargetDict[CmdSign].append(SingleCommandList[-1])
1111 Index = CommandList.index(Item)
1112 CommandList.pop(Index)
1113 if SingleCommandList[-1].endswith("%s%s.c" % (TAB_SLASH, CmdSumDict[CmdSign[3:].rsplit(TAB_SLASH, 1)[0]])):
1114 Cpplist = CmdCppDict[T.Target.SubDir]
1115 Cpplist.insert(0, '$(OBJLIST_%d): ' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir))
1116 source_files = CmdTargetDict[CmdSign][1:]
1117 source_files.insert(0, " ")
1118 if len(source_files)>2:
1119 SaveFileOnChange(SaveFilePath, " ".join(source_files), False)
1120 T.Commands[Index] = '%s\n\t%s $(cc_resp_%s)' % (
1121 ' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign][0], resp_file_number)
1122 ToolsDef.append("cc_resp_%s = @%s" % (resp_file_number, SaveFilePath))
1123
1124 elif len(source_files)<=2 and len(" ".join(CmdTargetDict[CmdSign][:2]))>GlobalData.gCommandMaxLength:
1125 SaveFileOnChange(SaveFilePath, " ".join(source_files), False)
1126 T.Commands[Index] = '%s\n\t%s $(cc_resp_%s)' % (
1127 ' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign][0], resp_file_number)
1128 ToolsDef.append("cc_resp_%s = @%s" % (resp_file_number, SaveFilePath))
1129
1130 else:
1131 T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), " ".join(CmdTargetDict[CmdSign]))
1132 else:
1133 T.Commands.pop(Index)
1134 return T, CmdSumDict, CmdTargetDict, CmdCppDict
1135
1136 def CheckCCCmd(self, CommandList):
1137 for cmd in CommandList:
1138 if '$(CC)' in cmd:
1139 return True
1140 return False
1141 ## For creating makefile targets for dependent libraries
1142 def ProcessDependentLibrary(self):
1143 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1144 if not LibraryAutoGen.IsBinaryModule:
1145 self.LibraryBuildDirectoryList.append(self.PlaceMacro(LibraryAutoGen.BuildDir, self.Macros))
1146
1147 ## Return a list containing source file's dependencies
1148 #
1149 # @param FileList The list of source files
1150 # @param ForceInculeList The list of files which will be included forcely
1151 # @param SearchPathList The list of search path
1152 #
1153 # @retval dict The mapping between source file path and its dependencies
1154 #
1155 def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):
1156 Dependency = {}
1157 for F in FileList:
1158 Dependency[F] = GetDependencyList(self._AutoGenObject, self.FileCache, F, ForceInculeList, SearchPathList)
1159 return Dependency
1160
1161
1162 ## CustomMakefile class
1163 #
1164 # This class encapsules makefie and its generation for module. It uses template to generate
1165 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
1166 #
1167 class CustomMakefile(BuildFile):
1168 ## template used to generate the makefile for module with custom makefile
1169 _TEMPLATE_ = TemplateString('''\
1170 ${makefile_header}
1171
1172 #
1173 # Platform Macro Definition
1174 #
1175 PLATFORM_NAME = ${platform_name}
1176 PLATFORM_GUID = ${platform_guid}
1177 PLATFORM_VERSION = ${platform_version}
1178 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
1179 PLATFORM_DIR = ${platform_dir}
1180 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1181
1182 #
1183 # Module Macro Definition
1184 #
1185 MODULE_NAME = ${module_name}
1186 MODULE_GUID = ${module_guid}
1187 MODULE_NAME_GUID = ${module_name_guid}
1188 MODULE_VERSION = ${module_version}
1189 MODULE_TYPE = ${module_type}
1190 MODULE_FILE = ${module_file}
1191 MODULE_FILE_BASE_NAME = ${module_file_base_name}
1192 BASE_NAME = $(MODULE_NAME)
1193 MODULE_RELATIVE_DIR = ${module_relative_directory}
1194 MODULE_DIR = ${module_dir}
1195
1196 #
1197 # Build Configuration Macro Definition
1198 #
1199 ARCH = ${architecture}
1200 TOOLCHAIN = ${toolchain_tag}
1201 TOOLCHAIN_TAG = ${toolchain_tag}
1202 TARGET = ${build_target}
1203
1204 #
1205 # Build Directory Macro Definition
1206 #
1207 # PLATFORM_BUILD_DIR = ${platform_build_directory}
1208 BUILD_DIR = ${platform_build_directory}
1209 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
1210 LIB_DIR = $(BIN_DIR)
1211 MODULE_BUILD_DIR = ${module_build_directory}
1212 OUTPUT_DIR = ${module_output_directory}
1213 DEBUG_DIR = ${module_debug_directory}
1214 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
1215 DEST_DIR_DEBUG = $(DEBUG_DIR)
1216
1217 #
1218 # Tools definitions specific to this module
1219 #
1220 ${BEGIN}${module_tool_definitions}
1221 ${END}
1222 MAKE_FILE = ${makefile_path}
1223
1224 #
1225 # Shell Command Macro
1226 #
1227 ${BEGIN}${shell_command_code} = ${shell_command}
1228 ${END}
1229
1230 ${custom_makefile_content}
1231
1232 #
1233 # Target used when called from platform makefile, which will bypass the build of dependent libraries
1234 #
1235
1236 pbuild: init all
1237
1238
1239 #
1240 # ModuleTarget
1241 #
1242
1243 mbuild: init all
1244
1245 #
1246 # Build Target used in multi-thread build mode, which no init target is needed
1247 #
1248
1249 tbuild: all
1250
1251 #
1252 # Initialization target: print build information and create necessary directories
1253 #
1254 init:
1255 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
1256 ${BEGIN}\t-@${create_directory_command}\n${END}\
1257
1258 ''')
1259
1260 ## Constructor of CustomMakefile
1261 #
1262 # @param ModuleAutoGen Object of ModuleAutoGen class
1263 #
1264 def __init__(self, ModuleAutoGen):
1265 BuildFile.__init__(self, ModuleAutoGen)
1266 self.PlatformInfo = self._AutoGenObject.PlatformInfo
1267 self.IntermediateDirectoryList = ["$(DEBUG_DIR)", "$(OUTPUT_DIR)"]
1268 self.DependencyHeaderFileSet = set()
1269
1270 # Compose a dict object containing information used to do replacement in template
1271 @property
1272 def _TemplateDict(self):
1273 Separator = self._SEP_[self._Platform]
1274 MyAgo = self._AutoGenObject
1275 if self._FileType not in MyAgo.CustomMakefile:
1276 EdkLogger.error('build', OPTION_NOT_SUPPORTED, "No custom makefile for %s" % self._FileType,
1277 ExtraData="[%s]" % str(MyAgo))
1278 MakefilePath = mws.join(
1279 MyAgo.WorkspaceDir,
1280 MyAgo.CustomMakefile[self._FileType]
1281 )
1282 try:
1283 CustomMakefile = open(MakefilePath, 'r').read()
1284 except:
1285 EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(MyAgo),
1286 ExtraData=MyAgo.CustomMakefile[self._FileType])
1287
1288 # tools definitions
1289 ToolsDef = []
1290 for Tool in MyAgo.BuildOption:
1291 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
1292 if Tool == "MAKE":
1293 continue
1294 for Attr in MyAgo.BuildOption[Tool]:
1295 if Attr == "FAMILY":
1296 continue
1297 elif Attr == "PATH":
1298 ToolsDef.append("%s = %s" % (Tool, MyAgo.BuildOption[Tool][Attr]))
1299 else:
1300 ToolsDef.append("%s_%s = %s" % (Tool, Attr, MyAgo.BuildOption[Tool][Attr]))
1301 ToolsDef.append("")
1302
1303 MakefileName = self.getMakefileName()
1304 MakefileTemplateDict = {
1305 "makefile_header" : self._FILE_HEADER_[self._FileType],
1306 "makefile_path" : os.path.join("$(MODULE_BUILD_DIR)", MakefileName),
1307 "platform_name" : self.PlatformInfo.Name,
1308 "platform_guid" : self.PlatformInfo.Guid,
1309 "platform_version" : self.PlatformInfo.Version,
1310 "platform_relative_directory": self.PlatformInfo.SourceDir,
1311 "platform_output_directory" : self.PlatformInfo.OutputDir,
1312 "platform_dir" : MyAgo.Macros["PLATFORM_DIR"],
1313
1314 "module_name" : MyAgo.Name,
1315 "module_guid" : MyAgo.Guid,
1316 "module_name_guid" : MyAgo.UniqueBaseName,
1317 "module_version" : MyAgo.Version,
1318 "module_type" : MyAgo.ModuleType,
1319 "module_file" : MyAgo.MetaFile,
1320 "module_file_base_name" : MyAgo.MetaFile.BaseName,
1321 "module_relative_directory" : MyAgo.SourceDir,
1322 "module_dir" : mws.join (MyAgo.WorkspaceDir, MyAgo.SourceDir),
1323
1324 "architecture" : MyAgo.Arch,
1325 "toolchain_tag" : MyAgo.ToolChain,
1326 "build_target" : MyAgo.BuildTarget,
1327
1328 "platform_build_directory" : self.PlatformInfo.BuildDir,
1329 "module_build_directory" : MyAgo.BuildDir,
1330 "module_output_directory" : MyAgo.OutputDir,
1331 "module_debug_directory" : MyAgo.DebugDir,
1332
1333 "separator" : Separator,
1334 "module_tool_definitions" : ToolsDef,
1335
1336 "shell_command_code" : list(self._SHELL_CMD_[self._Platform].keys()),
1337 "shell_command" : list(self._SHELL_CMD_[self._Platform].values()),
1338
1339 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1340 "custom_makefile_content" : CustomMakefile
1341 }
1342
1343 return MakefileTemplateDict
1344
1345 ## PlatformMakefile class
1346 #
1347 # This class encapsules makefie and its generation for platform. It uses
1348 # template to generate the content of makefile. The content of makefile will be
1349 # got from PlatformAutoGen object.
1350 #
1351 class PlatformMakefile(BuildFile):
1352 ## template used to generate the makefile for platform
1353 _TEMPLATE_ = TemplateString('''\
1354 ${makefile_header}
1355
1356 #
1357 # Platform Macro Definition
1358 #
1359 PLATFORM_NAME = ${platform_name}
1360 PLATFORM_GUID = ${platform_guid}
1361 PLATFORM_VERSION = ${platform_version}
1362 PLATFORM_FILE = ${platform_file}
1363 PLATFORM_DIR = ${platform_dir}
1364 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1365
1366 #
1367 # Build Configuration Macro Definition
1368 #
1369 TOOLCHAIN = ${toolchain_tag}
1370 TOOLCHAIN_TAG = ${toolchain_tag}
1371 TARGET = ${build_target}
1372
1373 #
1374 # Build Directory Macro Definition
1375 #
1376 BUILD_DIR = ${platform_build_directory}
1377 FV_DIR = ${platform_build_directory}${separator}FV
1378
1379 #
1380 # Shell Command Macro
1381 #
1382 ${BEGIN}${shell_command_code} = ${shell_command}
1383 ${END}
1384
1385 MAKE = ${make_path}
1386 MAKE_FILE = ${makefile_path}
1387
1388 #
1389 # Default target
1390 #
1391 all: init build_libraries build_modules
1392
1393 #
1394 # Initialization target: print build information and create necessary directories
1395 #
1396 init:
1397 \t-@echo Building ... $(PLATFORM_FILE) [${build_architecture_list}]
1398 \t${BEGIN}-@${create_directory_command}
1399 \t${END}
1400 #
1401 # library build target
1402 #
1403 libraries: init build_libraries
1404
1405 #
1406 # module build target
1407 #
1408 modules: init build_libraries build_modules
1409
1410 #
1411 # Build all libraries:
1412 #
1413 build_libraries:
1414 ${BEGIN}\t@"$(MAKE)" $(MAKE_FLAGS) -f ${library_makefile_list} pbuild
1415 ${END}\t@cd $(BUILD_DIR)
1416
1417 #
1418 # Build all modules:
1419 #
1420 build_modules:
1421 ${BEGIN}\t@"$(MAKE)" $(MAKE_FLAGS) -f ${module_makefile_list} pbuild
1422 ${END}\t@cd $(BUILD_DIR)
1423
1424 #
1425 # Clean intermediate files
1426 #
1427 clean:
1428 \t${BEGIN}-@${library_build_command} clean
1429 \t${END}${BEGIN}-@${module_build_command} clean
1430 \t${END}@cd $(BUILD_DIR)
1431
1432 #
1433 # Clean all generated files except to makefile
1434 #
1435 cleanall:
1436 ${BEGIN}\t${cleanall_command}
1437 ${END}
1438
1439 #
1440 # Clean all library files
1441 #
1442 cleanlib:
1443 \t${BEGIN}-@${library_build_command} cleanall
1444 \t${END}@cd $(BUILD_DIR)\n
1445 ''')
1446
1447 ## Constructor of PlatformMakefile
1448 #
1449 # @param ModuleAutoGen Object of PlatformAutoGen class
1450 #
1451 def __init__(self, PlatformAutoGen):
1452 BuildFile.__init__(self, PlatformAutoGen)
1453 self.ModuleBuildCommandList = []
1454 self.ModuleMakefileList = []
1455 self.IntermediateDirectoryList = []
1456 self.ModuleBuildDirectoryList = []
1457 self.LibraryBuildDirectoryList = []
1458 self.LibraryMakeCommandList = []
1459 self.DependencyHeaderFileSet = set()
1460
1461 # Compose a dict object containing information used to do replacement in template
1462 @property
1463 def _TemplateDict(self):
1464 Separator = self._SEP_[self._Platform]
1465
1466 MyAgo = self._AutoGenObject
1467 if "MAKE" not in MyAgo.ToolDefinition or "PATH" not in MyAgo.ToolDefinition["MAKE"]:
1468 EdkLogger.error("build", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!",
1469 ExtraData="[%s]" % str(MyAgo))
1470
1471 self.IntermediateDirectoryList = ["$(BUILD_DIR)"]
1472 self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()
1473 self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()
1474
1475 MakefileName = self.getMakefileName()
1476 LibraryMakefileList = []
1477 LibraryMakeCommandList = []
1478 for D in self.LibraryBuildDirectoryList:
1479 D = self.PlaceMacro(D, {"BUILD_DIR":MyAgo.BuildDir})
1480 Makefile = os.path.join(D, MakefileName)
1481 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":Makefile}
1482 LibraryMakefileList.append(Makefile)
1483 LibraryMakeCommandList.append(Command)
1484 self.LibraryMakeCommandList = LibraryMakeCommandList
1485
1486 ModuleMakefileList = []
1487 ModuleMakeCommandList = []
1488 for D in self.ModuleBuildDirectoryList:
1489 D = self.PlaceMacro(D, {"BUILD_DIR":MyAgo.BuildDir})
1490 Makefile = os.path.join(D, MakefileName)
1491 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":Makefile}
1492 ModuleMakefileList.append(Makefile)
1493 ModuleMakeCommandList.append(Command)
1494
1495 MakefileTemplateDict = {
1496 "makefile_header" : self._FILE_HEADER_[self._FileType],
1497 "makefile_path" : os.path.join("$(BUILD_DIR)", MakefileName),
1498 "make_path" : MyAgo.ToolDefinition["MAKE"]["PATH"],
1499 "makefile_name" : MakefileName,
1500 "platform_name" : MyAgo.Name,
1501 "platform_guid" : MyAgo.Guid,
1502 "platform_version" : MyAgo.Version,
1503 "platform_file" : MyAgo.MetaFile,
1504 "platform_relative_directory": MyAgo.SourceDir,
1505 "platform_output_directory" : MyAgo.OutputDir,
1506 "platform_build_directory" : MyAgo.BuildDir,
1507 "platform_dir" : MyAgo.Macros["PLATFORM_DIR"],
1508
1509 "toolchain_tag" : MyAgo.ToolChain,
1510 "build_target" : MyAgo.BuildTarget,
1511 "shell_command_code" : list(self._SHELL_CMD_[self._Platform].keys()),
1512 "shell_command" : list(self._SHELL_CMD_[self._Platform].values()),
1513 "build_architecture_list" : MyAgo.Arch,
1514 "architecture" : MyAgo.Arch,
1515 "separator" : Separator,
1516 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1517 "cleanall_command" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1518 "library_makefile_list" : LibraryMakefileList,
1519 "module_makefile_list" : ModuleMakefileList,
1520 "library_build_command" : LibraryMakeCommandList,
1521 "module_build_command" : ModuleMakeCommandList,
1522 }
1523
1524 return MakefileTemplateDict
1525
1526 ## Get the root directory list for intermediate files of all modules build
1527 #
1528 # @retval list The list of directory
1529 #
1530 def GetModuleBuildDirectoryList(self):
1531 DirList = []
1532 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1533 if not ModuleAutoGen.IsBinaryModule:
1534 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1535 return DirList
1536
1537 ## Get the root directory list for intermediate files of all libraries build
1538 #
1539 # @retval list The list of directory
1540 #
1541 def GetLibraryBuildDirectoryList(self):
1542 DirList = []
1543 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1544 if not LibraryAutoGen.IsBinaryModule:
1545 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1546 return DirList
1547
1548 ## TopLevelMakefile class
1549 #
1550 # This class encapsules makefie and its generation for entrance makefile. It
1551 # uses template to generate the content of makefile. The content of makefile
1552 # will be got from WorkspaceAutoGen object.
1553 #
1554 class TopLevelMakefile(BuildFile):
1555 ## template used to generate toplevel makefile
1556 _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}''')
1557
1558 ## Constructor of TopLevelMakefile
1559 #
1560 # @param Workspace Object of WorkspaceAutoGen class
1561 #
1562 def __init__(self, Workspace):
1563 BuildFile.__init__(self, Workspace)
1564 self.IntermediateDirectoryList = []
1565 self.DependencyHeaderFileSet = set()
1566
1567 # Compose a dict object containing information used to do replacement in template
1568 @property
1569 def _TemplateDict(self):
1570 Separator = self._SEP_[self._Platform]
1571
1572 # any platform autogen object is ok because we just need common information
1573 MyAgo = self._AutoGenObject
1574
1575 if "MAKE" not in MyAgo.ToolDefinition or "PATH" not in MyAgo.ToolDefinition["MAKE"]:
1576 EdkLogger.error("build", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!",
1577 ExtraData="[%s]" % str(MyAgo))
1578
1579 for Arch in MyAgo.ArchList:
1580 self.IntermediateDirectoryList.append(Separator.join(["$(BUILD_DIR)", Arch]))
1581 self.IntermediateDirectoryList.append("$(FV_DIR)")
1582
1583 # TRICK: for not generating GenFds call in makefile if no FDF file
1584 MacroList = []
1585 if MyAgo.FdfFile is not None and MyAgo.FdfFile != "":
1586 FdfFileList = [MyAgo.FdfFile]
1587 # macros passed to GenFds
1588 MacroDict = {}
1589 MacroDict.update(GlobalData.gGlobalDefines)
1590 MacroDict.update(GlobalData.gCommandLineDefines)
1591 for MacroName in MacroDict:
1592 if MacroDict[MacroName] != "":
1593 MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
1594 else:
1595 MacroList.append('"%s"' % MacroName)
1596 else:
1597 FdfFileList = []
1598
1599 # pass extra common options to external program called in makefile, currently GenFds.exe
1600 ExtraOption = ''
1601 LogLevel = EdkLogger.GetLevel()
1602 if LogLevel == EdkLogger.VERBOSE:
1603 ExtraOption += " -v"
1604 elif LogLevel <= EdkLogger.DEBUG_9:
1605 ExtraOption += " -d %d" % (LogLevel - 1)
1606 elif LogLevel == EdkLogger.QUIET:
1607 ExtraOption += " -q"
1608
1609 if GlobalData.gCaseInsensitive:
1610 ExtraOption += " -c"
1611 if not GlobalData.gEnableGenfdsMultiThread:
1612 ExtraOption += " --no-genfds-multi-thread"
1613 if GlobalData.gIgnoreSource:
1614 ExtraOption += " --ignore-sources"
1615
1616 for pcd in GlobalData.BuildOptionPcd:
1617 if pcd[2]:
1618 pcdname = '.'.join(pcd[0:3])
1619 else:
1620 pcdname = '.'.join(pcd[0:2])
1621 if pcd[3].startswith('{'):
1622 ExtraOption += " --pcd " + pcdname + '=' + 'H' + '"' + pcd[3] + '"'
1623 else:
1624 ExtraOption += " --pcd " + pcdname + '=' + pcd[3]
1625
1626 MakefileName = self.getMakefileName()
1627 SubBuildCommandList = []
1628 for A in MyAgo.ArchList:
1629 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":os.path.join("$(BUILD_DIR)", A, MakefileName)}
1630 SubBuildCommandList.append(Command)
1631
1632 MakefileTemplateDict = {
1633 "makefile_header" : self._FILE_HEADER_[self._FileType],
1634 "makefile_path" : os.path.join("$(BUILD_DIR)", MakefileName),
1635 "make_path" : MyAgo.ToolDefinition["MAKE"]["PATH"],
1636 "platform_name" : MyAgo.Name,
1637 "platform_guid" : MyAgo.Guid,
1638 "platform_version" : MyAgo.Version,
1639 "platform_build_directory" : MyAgo.BuildDir,
1640 "conf_directory" : GlobalData.gConfDirectory,
1641
1642 "toolchain_tag" : MyAgo.ToolChain,
1643 "build_target" : MyAgo.BuildTarget,
1644 "shell_command_code" : list(self._SHELL_CMD_[self._Platform].keys()),
1645 "shell_command" : list(self._SHELL_CMD_[self._Platform].values()),
1646 'arch' : list(MyAgo.ArchList),
1647 "build_architecture_list" : ','.join(MyAgo.ArchList),
1648 "separator" : Separator,
1649 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1650 "cleanall_command" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1651 "sub_build_command" : SubBuildCommandList,
1652 "fdf_file" : FdfFileList,
1653 "active_platform" : str(MyAgo),
1654 "fd" : MyAgo.FdTargetList,
1655 "fv" : MyAgo.FvTargetList,
1656 "cap" : MyAgo.CapTargetList,
1657 "extra_options" : ExtraOption,
1658 "macro" : MacroList,
1659 }
1660
1661 return MakefileTemplateDict
1662
1663 ## Get the root directory list for intermediate files of all modules build
1664 #
1665 # @retval list The list of directory
1666 #
1667 def GetModuleBuildDirectoryList(self):
1668 DirList = []
1669 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1670 if not ModuleAutoGen.IsBinaryModule:
1671 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1672 return DirList
1673
1674 ## Get the root directory list for intermediate files of all libraries build
1675 #
1676 # @retval list The list of directory
1677 #
1678 def GetLibraryBuildDirectoryList(self):
1679 DirList = []
1680 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1681 if not LibraryAutoGen.IsBinaryModule:
1682 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1683 return DirList
1684
1685 ## Find dependencies for one source file
1686 #
1687 # By searching recursively "#include" directive in file, find out all the
1688 # files needed by given source file. The dependencies will be only searched
1689 # in given search path list.
1690 #
1691 # @param File The source file
1692 # @param ForceInculeList The list of files which will be included forcely
1693 # @param SearchPathList The list of search path
1694 #
1695 # @retval list The list of files the given source file depends on
1696 #
1697 def GetDependencyList(AutoGenObject, FileCache, File, ForceList, SearchPathList):
1698 EdkLogger.debug(EdkLogger.DEBUG_1, "Try to get dependency files for %s" % File)
1699 FileStack = [File] + ForceList
1700 DependencySet = set()
1701
1702 if AutoGenObject.Arch not in gDependencyDatabase:
1703 gDependencyDatabase[AutoGenObject.Arch] = {}
1704 DepDb = gDependencyDatabase[AutoGenObject.Arch]
1705
1706 while len(FileStack) > 0:
1707 F = FileStack.pop()
1708
1709 FullPathDependList = []
1710 if F in FileCache:
1711 for CacheFile in FileCache[F]:
1712 FullPathDependList.append(CacheFile)
1713 if CacheFile not in DependencySet:
1714 FileStack.append(CacheFile)
1715 DependencySet.update(FullPathDependList)
1716 continue
1717
1718 CurrentFileDependencyList = []
1719 if F in DepDb:
1720 CurrentFileDependencyList = DepDb[F]
1721 else:
1722 try:
1723 Fd = open(F.Path, 'rb')
1724 FileContent = Fd.read()
1725 Fd.close()
1726 except BaseException as X:
1727 EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=F.Path + "\n\t" + str(X))
1728 if len(FileContent) == 0:
1729 continue
1730 try:
1731 if FileContent[0] == 0xff or FileContent[0] == 0xfe:
1732 FileContent = FileContent.decode('utf-16')
1733 else:
1734 FileContent = FileContent.decode()
1735 except:
1736 # The file is not txt file. for example .mcb file
1737 continue
1738 IncludedFileList = gIncludePattern.findall(FileContent)
1739
1740 for Inc in IncludedFileList:
1741 Inc = Inc.strip()
1742 # if there's macro used to reference header file, expand it
1743 HeaderList = gMacroPattern.findall(Inc)
1744 if len(HeaderList) == 1 and len(HeaderList[0]) == 2:
1745 HeaderType = HeaderList[0][0]
1746 HeaderKey = HeaderList[0][1]
1747 if HeaderType in gIncludeMacroConversion:
1748 Inc = gIncludeMacroConversion[HeaderType] % {"HeaderKey" : HeaderKey}
1749 else:
1750 # not known macro used in #include, always build the file by
1751 # returning a empty dependency
1752 FileCache[File] = []
1753 return []
1754 Inc = os.path.normpath(Inc)
1755 CurrentFileDependencyList.append(Inc)
1756 DepDb[F] = CurrentFileDependencyList
1757
1758 CurrentFilePath = F.Dir
1759 PathList = [CurrentFilePath] + SearchPathList
1760 for Inc in CurrentFileDependencyList:
1761 for SearchPath in PathList:
1762 FilePath = os.path.join(SearchPath, Inc)
1763 if FilePath in gIsFileMap:
1764 if not gIsFileMap[FilePath]:
1765 continue
1766 # If isfile is called too many times, the performance is slow down.
1767 elif not os.path.isfile(FilePath):
1768 gIsFileMap[FilePath] = False
1769 continue
1770 else:
1771 gIsFileMap[FilePath] = True
1772 FilePath = PathClass(FilePath)
1773 FullPathDependList.append(FilePath)
1774 if FilePath not in DependencySet:
1775 FileStack.append(FilePath)
1776 break
1777 else:
1778 EdkLogger.debug(EdkLogger.DEBUG_9, "%s included by %s was not found "\
1779 "in any given path:\n\t%s" % (Inc, F, "\n\t".join(SearchPathList)))
1780
1781 FileCache[F] = FullPathDependList
1782 DependencySet.update(FullPathDependList)
1783
1784 DependencySet.update(ForceList)
1785 if File in DependencySet:
1786 DependencySet.remove(File)
1787 DependencyList = list(DependencySet) # remove duplicate ones
1788
1789 return DependencyList
1790
1791 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1792 if __name__ == '__main__':
1793 pass