]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/AutoGen/GenMake.py
BaseTools: Limit command line length.
[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(MyAgo.OutputDir, ToolsDef)
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, RespFile, ToolsDef):
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 resp_file_number = 0
1008 for T in self._AutoGenObject.Targets[Type]:
1009 # Generate related macros if needed
1010 if T.GenFileListMacro and T.FileListMacro not in self.FileListMacros:
1011 self.FileListMacros[T.FileListMacro] = []
1012 if T.GenListFile and T.ListFileMacro not in self.ListFileMacros:
1013 self.ListFileMacros[T.ListFileMacro] = []
1014 if T.GenIncListFile and T.IncListFileMacro not in self.ListFileMacros:
1015 self.ListFileMacros[T.IncListFileMacro] = []
1016
1017 Deps = []
1018 CCodeDeps = []
1019 # Add force-dependencies
1020 for Dep in T.Dependencies:
1021 Deps.append(self.PlaceMacro(str(Dep), self.Macros))
1022 if Dep != '$(MAKE_FILE)':
1023 CCodeDeps.append(self.PlaceMacro(str(Dep), self.Macros))
1024 # Add inclusion-dependencies
1025 if len(T.Inputs) == 1 and T.Inputs[0] in FileDependencyDict:
1026 for F in FileDependencyDict[T.Inputs[0]]:
1027 Deps.append(self.PlaceMacro(str(F), self.Macros))
1028 # Add source-dependencies
1029 for F in T.Inputs:
1030 NewFile = self.PlaceMacro(str(F), self.Macros)
1031 # In order to use file list macro as dependency
1032 if T.GenListFile:
1033 # gnu tools need forward slash path separator, even on Windows
1034 self.ListFileMacros[T.ListFileMacro].append(str(F).replace ('\\', '/'))
1035 self.FileListMacros[T.FileListMacro].append(NewFile)
1036 elif T.GenFileListMacro:
1037 self.FileListMacros[T.FileListMacro].append(NewFile)
1038 else:
1039 Deps.append(NewFile)
1040 for key in self.FileListMacros:
1041 self.FileListMacros[key].sort()
1042 # Use file list macro as dependency
1043 if T.GenFileListMacro:
1044 Deps.append("$(%s)" % T.FileListMacro)
1045 if Type in [TAB_OBJECT_FILE, TAB_STATIC_LIBRARY]:
1046 Deps.append("$(%s)" % T.ListFileMacro)
1047
1048 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Type == TAB_C_CODE_FILE:
1049 T, CmdTarget, CmdTargetDict, CmdCppDict = self.ParserCCodeFile(T, Type, CmdSumDict, CmdTargetDict,
1050 CmdCppDict, DependencyDict, RespFile,
1051 ToolsDef, resp_file_number)
1052 resp_file_number += 1
1053 TargetDict = {"target": self.PlaceMacro(T.Target.Path, self.Macros), "cmd": "\n\t".join(T.Commands),"deps": CCodeDeps}
1054 CmdLine = self._BUILD_TARGET_TEMPLATE.Replace(TargetDict).rstrip().replace('\t$(OBJLIST', '$(OBJLIST')
1055 if T.Commands:
1056 CmdLine = '%s%s' %(CmdLine, TAB_LINE_BREAK)
1057 if CCodeDeps or CmdLine:
1058 self.BuildTargetList.append(CmdLine)
1059 else:
1060 TargetDict = {"target": self.PlaceMacro(T.Target.Path, self.Macros), "cmd": "\n\t".join(T.Commands),"deps": Deps}
1061 self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(TargetDict))
1062
1063 # Add a Makefile rule for targets generating multiple files.
1064 # The main output is a prerequisite for the other output files.
1065 for i in T.Outputs[1:]:
1066 AnnexeTargetDict = {"target": self.PlaceMacro(i.Path, self.Macros), "cmd": "", "deps": self.PlaceMacro(T.Target.Path, self.Macros)}
1067 self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(AnnexeTargetDict))
1068
1069 def ParserCCodeFile(self, T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict, RespFile, ToolsDef,
1070 resp_file_number):
1071 SaveFilePath = os.path.join(RespFile, "cc_resp_%s.txt" % resp_file_number)
1072 if not CmdSumDict:
1073 for item in self._AutoGenObject.Targets[Type]:
1074 CmdSumDict[item.Target.SubDir] = item.Target.BaseName
1075 for CppPath in item.Inputs:
1076 Path = self.PlaceMacro(CppPath.Path, self.Macros)
1077 if CmdCppDict.get(item.Target.SubDir):
1078 CmdCppDict[item.Target.SubDir].append(Path)
1079 else:
1080 CmdCppDict[item.Target.SubDir] = ['$(MAKE_FILE)', Path]
1081 if CppPath.Path in DependencyDict:
1082 for Temp in DependencyDict[CppPath.Path]:
1083 try:
1084 Path = self.PlaceMacro(Temp.Path, self.Macros)
1085 except:
1086 continue
1087 if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):
1088 CmdCppDict[item.Target.SubDir].append(Path)
1089 if T.Commands:
1090 CommandList = T.Commands[:]
1091 for Item in CommandList[:]:
1092 SingleCommandList = Item.split()
1093 if len(SingleCommandList) > 0 and self.CheckCCCmd(SingleCommandList):
1094 for Temp in SingleCommandList:
1095 if Temp.startswith('/Fo'):
1096 CmdSign = '%s%s' % (Temp.rsplit(TAB_SLASH, 1)[0], TAB_SLASH)
1097 break
1098 else:
1099 continue
1100 if CmdSign not in list(CmdTargetDict.keys()):
1101 cmd = Item.replace(Temp, CmdSign)
1102 if SingleCommandList[-1] in cmd:
1103 CmdTargetDict[CmdSign] = [cmd.replace(SingleCommandList[-1], "").rstrip(), SingleCommandList[-1]]
1104 else:
1105 # CmdTargetDict[CmdSign] = "%s %s" % (CmdTargetDict[CmdSign], SingleCommandList[-1])
1106 CmdTargetDict[CmdSign].append(SingleCommandList[-1])
1107 Index = CommandList.index(Item)
1108 CommandList.pop(Index)
1109 if SingleCommandList[-1].endswith("%s%s.c" % (TAB_SLASH, CmdSumDict[CmdSign[3:].rsplit(TAB_SLASH, 1)[0]])):
1110 Cpplist = CmdCppDict[T.Target.SubDir]
1111 Cpplist.insert(0, '$(OBJLIST_%d): ' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir))
1112 source_files = CmdTargetDict[CmdSign][1:]
1113 source_files.insert(0, " ")
1114 if len(source_files)>2:
1115 SaveFileOnChange(SaveFilePath, " ".join(source_files), False)
1116 T.Commands[Index] = '%s\n\t%s $(cc_resp_%s)' % (
1117 ' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign][0], resp_file_number)
1118 ToolsDef.append("cc_resp_%s = @%s" % (resp_file_number, SaveFilePath))
1119
1120 elif len(source_files)<=2 and len(" ".join(CmdTargetDict[CmdSign][:2]))>GlobalData.gCommandMaxLength:
1121 SaveFileOnChange(SaveFilePath, " ".join(source_files), False)
1122 T.Commands[Index] = '%s\n\t%s $(cc_resp_%s)' % (
1123 ' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign][0], resp_file_number)
1124 ToolsDef.append("cc_resp_%s = @%s" % (resp_file_number, SaveFilePath))
1125
1126 else:
1127 T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), " ".join(CmdTargetDict[CmdSign]))
1128 else:
1129 T.Commands.pop(Index)
1130 return T, CmdSumDict, CmdTargetDict, CmdCppDict
1131
1132 def CheckCCCmd(self, CommandList):
1133 for cmd in CommandList:
1134 if '$(CC)' in cmd:
1135 return True
1136 return False
1137 ## For creating makefile targets for dependent libraries
1138 def ProcessDependentLibrary(self):
1139 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1140 if not LibraryAutoGen.IsBinaryModule:
1141 self.LibraryBuildDirectoryList.append(self.PlaceMacro(LibraryAutoGen.BuildDir, self.Macros))
1142
1143 ## Return a list containing source file's dependencies
1144 #
1145 # @param FileList The list of source files
1146 # @param ForceInculeList The list of files which will be included forcely
1147 # @param SearchPathList The list of search path
1148 #
1149 # @retval dict The mapping between source file path and its dependencies
1150 #
1151 def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):
1152 Dependency = {}
1153 for F in FileList:
1154 Dependency[F] = GetDependencyList(self._AutoGenObject, self.FileCache, F, ForceInculeList, SearchPathList)
1155 return Dependency
1156
1157
1158 ## CustomMakefile class
1159 #
1160 # This class encapsules makefie and its generation for module. It uses template to generate
1161 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
1162 #
1163 class CustomMakefile(BuildFile):
1164 ## template used to generate the makefile for module with custom makefile
1165 _TEMPLATE_ = TemplateString('''\
1166 ${makefile_header}
1167
1168 #
1169 # Platform Macro Definition
1170 #
1171 PLATFORM_NAME = ${platform_name}
1172 PLATFORM_GUID = ${platform_guid}
1173 PLATFORM_VERSION = ${platform_version}
1174 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
1175 PLATFORM_DIR = ${platform_dir}
1176 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1177
1178 #
1179 # Module Macro Definition
1180 #
1181 MODULE_NAME = ${module_name}
1182 MODULE_GUID = ${module_guid}
1183 MODULE_NAME_GUID = ${module_name_guid}
1184 MODULE_VERSION = ${module_version}
1185 MODULE_TYPE = ${module_type}
1186 MODULE_FILE = ${module_file}
1187 MODULE_FILE_BASE_NAME = ${module_file_base_name}
1188 BASE_NAME = $(MODULE_NAME)
1189 MODULE_RELATIVE_DIR = ${module_relative_directory}
1190 MODULE_DIR = ${module_dir}
1191
1192 #
1193 # Build Configuration Macro Definition
1194 #
1195 ARCH = ${architecture}
1196 TOOLCHAIN = ${toolchain_tag}
1197 TOOLCHAIN_TAG = ${toolchain_tag}
1198 TARGET = ${build_target}
1199
1200 #
1201 # Build Directory Macro Definition
1202 #
1203 # PLATFORM_BUILD_DIR = ${platform_build_directory}
1204 BUILD_DIR = ${platform_build_directory}
1205 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
1206 LIB_DIR = $(BIN_DIR)
1207 MODULE_BUILD_DIR = ${module_build_directory}
1208 OUTPUT_DIR = ${module_output_directory}
1209 DEBUG_DIR = ${module_debug_directory}
1210 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
1211 DEST_DIR_DEBUG = $(DEBUG_DIR)
1212
1213 #
1214 # Tools definitions specific to this module
1215 #
1216 ${BEGIN}${module_tool_definitions}
1217 ${END}
1218 MAKE_FILE = ${makefile_path}
1219
1220 #
1221 # Shell Command Macro
1222 #
1223 ${BEGIN}${shell_command_code} = ${shell_command}
1224 ${END}
1225
1226 ${custom_makefile_content}
1227
1228 #
1229 # Target used when called from platform makefile, which will bypass the build of dependent libraries
1230 #
1231
1232 pbuild: init all
1233
1234
1235 #
1236 # ModuleTarget
1237 #
1238
1239 mbuild: init all
1240
1241 #
1242 # Build Target used in multi-thread build mode, which no init target is needed
1243 #
1244
1245 tbuild: all
1246
1247 #
1248 # Initialization target: print build information and create necessary directories
1249 #
1250 init:
1251 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
1252 ${BEGIN}\t-@${create_directory_command}\n${END}\
1253
1254 ''')
1255
1256 ## Constructor of CustomMakefile
1257 #
1258 # @param ModuleAutoGen Object of ModuleAutoGen class
1259 #
1260 def __init__(self, ModuleAutoGen):
1261 BuildFile.__init__(self, ModuleAutoGen)
1262 self.PlatformInfo = self._AutoGenObject.PlatformInfo
1263 self.IntermediateDirectoryList = ["$(DEBUG_DIR)", "$(OUTPUT_DIR)"]
1264 self.DependencyHeaderFileSet = set()
1265
1266 # Compose a dict object containing information used to do replacement in template
1267 @property
1268 def _TemplateDict(self):
1269 Separator = self._SEP_[self._Platform]
1270 MyAgo = self._AutoGenObject
1271 if self._FileType not in MyAgo.CustomMakefile:
1272 EdkLogger.error('build', OPTION_NOT_SUPPORTED, "No custom makefile for %s" % self._FileType,
1273 ExtraData="[%s]" % str(MyAgo))
1274 MakefilePath = mws.join(
1275 MyAgo.WorkspaceDir,
1276 MyAgo.CustomMakefile[self._FileType]
1277 )
1278 try:
1279 CustomMakefile = open(MakefilePath, 'r').read()
1280 except:
1281 EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(MyAgo),
1282 ExtraData=MyAgo.CustomMakefile[self._FileType])
1283
1284 # tools definitions
1285 ToolsDef = []
1286 for Tool in MyAgo.BuildOption:
1287 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
1288 if Tool == "MAKE":
1289 continue
1290 for Attr in MyAgo.BuildOption[Tool]:
1291 if Attr == "FAMILY":
1292 continue
1293 elif Attr == "PATH":
1294 ToolsDef.append("%s = %s" % (Tool, MyAgo.BuildOption[Tool][Attr]))
1295 else:
1296 ToolsDef.append("%s_%s = %s" % (Tool, Attr, MyAgo.BuildOption[Tool][Attr]))
1297 ToolsDef.append("")
1298
1299 MakefileName = self.getMakefileName()
1300 MakefileTemplateDict = {
1301 "makefile_header" : self._FILE_HEADER_[self._FileType],
1302 "makefile_path" : os.path.join("$(MODULE_BUILD_DIR)", MakefileName),
1303 "platform_name" : self.PlatformInfo.Name,
1304 "platform_guid" : self.PlatformInfo.Guid,
1305 "platform_version" : self.PlatformInfo.Version,
1306 "platform_relative_directory": self.PlatformInfo.SourceDir,
1307 "platform_output_directory" : self.PlatformInfo.OutputDir,
1308 "platform_dir" : MyAgo.Macros["PLATFORM_DIR"],
1309
1310 "module_name" : MyAgo.Name,
1311 "module_guid" : MyAgo.Guid,
1312 "module_name_guid" : MyAgo.UniqueBaseName,
1313 "module_version" : MyAgo.Version,
1314 "module_type" : MyAgo.ModuleType,
1315 "module_file" : MyAgo.MetaFile,
1316 "module_file_base_name" : MyAgo.MetaFile.BaseName,
1317 "module_relative_directory" : MyAgo.SourceDir,
1318 "module_dir" : mws.join (MyAgo.WorkspaceDir, MyAgo.SourceDir),
1319
1320 "architecture" : MyAgo.Arch,
1321 "toolchain_tag" : MyAgo.ToolChain,
1322 "build_target" : MyAgo.BuildTarget,
1323
1324 "platform_build_directory" : self.PlatformInfo.BuildDir,
1325 "module_build_directory" : MyAgo.BuildDir,
1326 "module_output_directory" : MyAgo.OutputDir,
1327 "module_debug_directory" : MyAgo.DebugDir,
1328
1329 "separator" : Separator,
1330 "module_tool_definitions" : ToolsDef,
1331
1332 "shell_command_code" : list(self._SHELL_CMD_[self._Platform].keys()),
1333 "shell_command" : list(self._SHELL_CMD_[self._Platform].values()),
1334
1335 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1336 "custom_makefile_content" : CustomMakefile
1337 }
1338
1339 return MakefileTemplateDict
1340
1341 ## PlatformMakefile class
1342 #
1343 # This class encapsules makefie and its generation for platform. It uses
1344 # template to generate the content of makefile. The content of makefile will be
1345 # got from PlatformAutoGen object.
1346 #
1347 class PlatformMakefile(BuildFile):
1348 ## template used to generate the makefile for platform
1349 _TEMPLATE_ = TemplateString('''\
1350 ${makefile_header}
1351
1352 #
1353 # Platform Macro Definition
1354 #
1355 PLATFORM_NAME = ${platform_name}
1356 PLATFORM_GUID = ${platform_guid}
1357 PLATFORM_VERSION = ${platform_version}
1358 PLATFORM_FILE = ${platform_file}
1359 PLATFORM_DIR = ${platform_dir}
1360 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1361
1362 #
1363 # Build Configuration Macro Definition
1364 #
1365 TOOLCHAIN = ${toolchain_tag}
1366 TOOLCHAIN_TAG = ${toolchain_tag}
1367 TARGET = ${build_target}
1368
1369 #
1370 # Build Directory Macro Definition
1371 #
1372 BUILD_DIR = ${platform_build_directory}
1373 FV_DIR = ${platform_build_directory}${separator}FV
1374
1375 #
1376 # Shell Command Macro
1377 #
1378 ${BEGIN}${shell_command_code} = ${shell_command}
1379 ${END}
1380
1381 MAKE = ${make_path}
1382 MAKE_FILE = ${makefile_path}
1383
1384 #
1385 # Default target
1386 #
1387 all: init build_libraries build_modules
1388
1389 #
1390 # Initialization target: print build information and create necessary directories
1391 #
1392 init:
1393 \t-@echo Building ... $(PLATFORM_FILE) [${build_architecture_list}]
1394 \t${BEGIN}-@${create_directory_command}
1395 \t${END}
1396 #
1397 # library build target
1398 #
1399 libraries: init build_libraries
1400
1401 #
1402 # module build target
1403 #
1404 modules: init build_libraries build_modules
1405
1406 #
1407 # Build all libraries:
1408 #
1409 build_libraries:
1410 ${BEGIN}\t@"$(MAKE)" $(MAKE_FLAGS) -f ${library_makefile_list} pbuild
1411 ${END}\t@cd $(BUILD_DIR)
1412
1413 #
1414 # Build all modules:
1415 #
1416 build_modules:
1417 ${BEGIN}\t@"$(MAKE)" $(MAKE_FLAGS) -f ${module_makefile_list} pbuild
1418 ${END}\t@cd $(BUILD_DIR)
1419
1420 #
1421 # Clean intermediate files
1422 #
1423 clean:
1424 \t${BEGIN}-@${library_build_command} clean
1425 \t${END}${BEGIN}-@${module_build_command} clean
1426 \t${END}@cd $(BUILD_DIR)
1427
1428 #
1429 # Clean all generated files except to makefile
1430 #
1431 cleanall:
1432 ${BEGIN}\t${cleanall_command}
1433 ${END}
1434
1435 #
1436 # Clean all library files
1437 #
1438 cleanlib:
1439 \t${BEGIN}-@${library_build_command} cleanall
1440 \t${END}@cd $(BUILD_DIR)\n
1441 ''')
1442
1443 ## Constructor of PlatformMakefile
1444 #
1445 # @param ModuleAutoGen Object of PlatformAutoGen class
1446 #
1447 def __init__(self, PlatformAutoGen):
1448 BuildFile.__init__(self, PlatformAutoGen)
1449 self.ModuleBuildCommandList = []
1450 self.ModuleMakefileList = []
1451 self.IntermediateDirectoryList = []
1452 self.ModuleBuildDirectoryList = []
1453 self.LibraryBuildDirectoryList = []
1454 self.LibraryMakeCommandList = []
1455 self.DependencyHeaderFileSet = set()
1456
1457 # Compose a dict object containing information used to do replacement in template
1458 @property
1459 def _TemplateDict(self):
1460 Separator = self._SEP_[self._Platform]
1461
1462 MyAgo = self._AutoGenObject
1463 if "MAKE" not in MyAgo.ToolDefinition or "PATH" not in MyAgo.ToolDefinition["MAKE"]:
1464 EdkLogger.error("build", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!",
1465 ExtraData="[%s]" % str(MyAgo))
1466
1467 self.IntermediateDirectoryList = ["$(BUILD_DIR)"]
1468 self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()
1469 self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()
1470
1471 MakefileName = self.getMakefileName()
1472 LibraryMakefileList = []
1473 LibraryMakeCommandList = []
1474 for D in self.LibraryBuildDirectoryList:
1475 D = self.PlaceMacro(D, {"BUILD_DIR":MyAgo.BuildDir})
1476 Makefile = os.path.join(D, MakefileName)
1477 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":Makefile}
1478 LibraryMakefileList.append(Makefile)
1479 LibraryMakeCommandList.append(Command)
1480 self.LibraryMakeCommandList = LibraryMakeCommandList
1481
1482 ModuleMakefileList = []
1483 ModuleMakeCommandList = []
1484 for D in self.ModuleBuildDirectoryList:
1485 D = self.PlaceMacro(D, {"BUILD_DIR":MyAgo.BuildDir})
1486 Makefile = os.path.join(D, MakefileName)
1487 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":Makefile}
1488 ModuleMakefileList.append(Makefile)
1489 ModuleMakeCommandList.append(Command)
1490
1491 MakefileTemplateDict = {
1492 "makefile_header" : self._FILE_HEADER_[self._FileType],
1493 "makefile_path" : os.path.join("$(BUILD_DIR)", MakefileName),
1494 "make_path" : MyAgo.ToolDefinition["MAKE"]["PATH"],
1495 "makefile_name" : MakefileName,
1496 "platform_name" : MyAgo.Name,
1497 "platform_guid" : MyAgo.Guid,
1498 "platform_version" : MyAgo.Version,
1499 "platform_file" : MyAgo.MetaFile,
1500 "platform_relative_directory": MyAgo.SourceDir,
1501 "platform_output_directory" : MyAgo.OutputDir,
1502 "platform_build_directory" : MyAgo.BuildDir,
1503 "platform_dir" : MyAgo.Macros["PLATFORM_DIR"],
1504
1505 "toolchain_tag" : MyAgo.ToolChain,
1506 "build_target" : MyAgo.BuildTarget,
1507 "shell_command_code" : list(self._SHELL_CMD_[self._Platform].keys()),
1508 "shell_command" : list(self._SHELL_CMD_[self._Platform].values()),
1509 "build_architecture_list" : MyAgo.Arch,
1510 "architecture" : MyAgo.Arch,
1511 "separator" : Separator,
1512 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1513 "cleanall_command" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1514 "library_makefile_list" : LibraryMakefileList,
1515 "module_makefile_list" : ModuleMakefileList,
1516 "library_build_command" : LibraryMakeCommandList,
1517 "module_build_command" : ModuleMakeCommandList,
1518 }
1519
1520 return MakefileTemplateDict
1521
1522 ## Get the root directory list for intermediate files of all modules build
1523 #
1524 # @retval list The list of directory
1525 #
1526 def GetModuleBuildDirectoryList(self):
1527 DirList = []
1528 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1529 if not ModuleAutoGen.IsBinaryModule:
1530 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1531 return DirList
1532
1533 ## Get the root directory list for intermediate files of all libraries build
1534 #
1535 # @retval list The list of directory
1536 #
1537 def GetLibraryBuildDirectoryList(self):
1538 DirList = []
1539 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1540 if not LibraryAutoGen.IsBinaryModule:
1541 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1542 return DirList
1543
1544 ## TopLevelMakefile class
1545 #
1546 # This class encapsules makefie and its generation for entrance makefile. It
1547 # uses template to generate the content of makefile. The content of makefile
1548 # will be got from WorkspaceAutoGen object.
1549 #
1550 class TopLevelMakefile(BuildFile):
1551 ## template used to generate toplevel makefile
1552 _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}''')
1553
1554 ## Constructor of TopLevelMakefile
1555 #
1556 # @param Workspace Object of WorkspaceAutoGen class
1557 #
1558 def __init__(self, Workspace):
1559 BuildFile.__init__(self, Workspace)
1560 self.IntermediateDirectoryList = []
1561 self.DependencyHeaderFileSet = set()
1562
1563 # Compose a dict object containing information used to do replacement in template
1564 @property
1565 def _TemplateDict(self):
1566 Separator = self._SEP_[self._Platform]
1567
1568 # any platform autogen object is ok because we just need common information
1569 MyAgo = self._AutoGenObject
1570
1571 if "MAKE" not in MyAgo.ToolDefinition or "PATH" not in MyAgo.ToolDefinition["MAKE"]:
1572 EdkLogger.error("build", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!",
1573 ExtraData="[%s]" % str(MyAgo))
1574
1575 for Arch in MyAgo.ArchList:
1576 self.IntermediateDirectoryList.append(Separator.join(["$(BUILD_DIR)", Arch]))
1577 self.IntermediateDirectoryList.append("$(FV_DIR)")
1578
1579 # TRICK: for not generating GenFds call in makefile if no FDF file
1580 MacroList = []
1581 if MyAgo.FdfFile is not None and MyAgo.FdfFile != "":
1582 FdfFileList = [MyAgo.FdfFile]
1583 # macros passed to GenFds
1584 MacroDict = {}
1585 MacroDict.update(GlobalData.gGlobalDefines)
1586 MacroDict.update(GlobalData.gCommandLineDefines)
1587 for MacroName in MacroDict:
1588 if MacroDict[MacroName] != "":
1589 MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
1590 else:
1591 MacroList.append('"%s"' % MacroName)
1592 else:
1593 FdfFileList = []
1594
1595 # pass extra common options to external program called in makefile, currently GenFds.exe
1596 ExtraOption = ''
1597 LogLevel = EdkLogger.GetLevel()
1598 if LogLevel == EdkLogger.VERBOSE:
1599 ExtraOption += " -v"
1600 elif LogLevel <= EdkLogger.DEBUG_9:
1601 ExtraOption += " -d %d" % (LogLevel - 1)
1602 elif LogLevel == EdkLogger.QUIET:
1603 ExtraOption += " -q"
1604
1605 if GlobalData.gCaseInsensitive:
1606 ExtraOption += " -c"
1607 if not GlobalData.gEnableGenfdsMultiThread:
1608 ExtraOption += " --no-genfds-multi-thread"
1609 if GlobalData.gIgnoreSource:
1610 ExtraOption += " --ignore-sources"
1611
1612 for pcd in GlobalData.BuildOptionPcd:
1613 if pcd[2]:
1614 pcdname = '.'.join(pcd[0:3])
1615 else:
1616 pcdname = '.'.join(pcd[0:2])
1617 if pcd[3].startswith('{'):
1618 ExtraOption += " --pcd " + pcdname + '=' + 'H' + '"' + pcd[3] + '"'
1619 else:
1620 ExtraOption += " --pcd " + pcdname + '=' + pcd[3]
1621
1622 MakefileName = self.getMakefileName()
1623 SubBuildCommandList = []
1624 for A in MyAgo.ArchList:
1625 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":os.path.join("$(BUILD_DIR)", A, MakefileName)}
1626 SubBuildCommandList.append(Command)
1627
1628 MakefileTemplateDict = {
1629 "makefile_header" : self._FILE_HEADER_[self._FileType],
1630 "makefile_path" : os.path.join("$(BUILD_DIR)", MakefileName),
1631 "make_path" : MyAgo.ToolDefinition["MAKE"]["PATH"],
1632 "platform_name" : MyAgo.Name,
1633 "platform_guid" : MyAgo.Guid,
1634 "platform_version" : MyAgo.Version,
1635 "platform_build_directory" : MyAgo.BuildDir,
1636 "conf_directory" : GlobalData.gConfDirectory,
1637
1638 "toolchain_tag" : MyAgo.ToolChain,
1639 "build_target" : MyAgo.BuildTarget,
1640 "shell_command_code" : list(self._SHELL_CMD_[self._Platform].keys()),
1641 "shell_command" : list(self._SHELL_CMD_[self._Platform].values()),
1642 'arch' : list(MyAgo.ArchList),
1643 "build_architecture_list" : ','.join(MyAgo.ArchList),
1644 "separator" : Separator,
1645 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1646 "cleanall_command" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1647 "sub_build_command" : SubBuildCommandList,
1648 "fdf_file" : FdfFileList,
1649 "active_platform" : str(MyAgo),
1650 "fd" : MyAgo.FdTargetList,
1651 "fv" : MyAgo.FvTargetList,
1652 "cap" : MyAgo.CapTargetList,
1653 "extra_options" : ExtraOption,
1654 "macro" : MacroList,
1655 }
1656
1657 return MakefileTemplateDict
1658
1659 ## Get the root directory list for intermediate files of all modules build
1660 #
1661 # @retval list The list of directory
1662 #
1663 def GetModuleBuildDirectoryList(self):
1664 DirList = []
1665 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1666 if not ModuleAutoGen.IsBinaryModule:
1667 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1668 return DirList
1669
1670 ## Get the root directory list for intermediate files of all libraries build
1671 #
1672 # @retval list The list of directory
1673 #
1674 def GetLibraryBuildDirectoryList(self):
1675 DirList = []
1676 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1677 if not LibraryAutoGen.IsBinaryModule:
1678 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1679 return DirList
1680
1681 ## Find dependencies for one source file
1682 #
1683 # By searching recursively "#include" directive in file, find out all the
1684 # files needed by given source file. The dependencies will be only searched
1685 # in given search path list.
1686 #
1687 # @param File The source file
1688 # @param ForceInculeList The list of files which will be included forcely
1689 # @param SearchPathList The list of search path
1690 #
1691 # @retval list The list of files the given source file depends on
1692 #
1693 def GetDependencyList(AutoGenObject, FileCache, File, ForceList, SearchPathList):
1694 EdkLogger.debug(EdkLogger.DEBUG_1, "Try to get dependency files for %s" % File)
1695 FileStack = [File] + ForceList
1696 DependencySet = set()
1697
1698 if AutoGenObject.Arch not in gDependencyDatabase:
1699 gDependencyDatabase[AutoGenObject.Arch] = {}
1700 DepDb = gDependencyDatabase[AutoGenObject.Arch]
1701
1702 while len(FileStack) > 0:
1703 F = FileStack.pop()
1704
1705 FullPathDependList = []
1706 if F in FileCache:
1707 for CacheFile in FileCache[F]:
1708 FullPathDependList.append(CacheFile)
1709 if CacheFile not in DependencySet:
1710 FileStack.append(CacheFile)
1711 DependencySet.update(FullPathDependList)
1712 continue
1713
1714 CurrentFileDependencyList = []
1715 if F in DepDb:
1716 CurrentFileDependencyList = DepDb[F]
1717 else:
1718 try:
1719 Fd = open(F.Path, 'rb')
1720 FileContent = Fd.read()
1721 Fd.close()
1722 except BaseException as X:
1723 EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=F.Path + "\n\t" + str(X))
1724 if len(FileContent) == 0:
1725 continue
1726 try:
1727 if FileContent[0] == 0xff or FileContent[0] == 0xfe:
1728 FileContent = FileContent.decode('utf-16')
1729 else:
1730 FileContent = FileContent.decode()
1731 except:
1732 # The file is not txt file. for example .mcb file
1733 continue
1734 IncludedFileList = gIncludePattern.findall(FileContent)
1735
1736 for Inc in IncludedFileList:
1737 Inc = Inc.strip()
1738 # if there's macro used to reference header file, expand it
1739 HeaderList = gMacroPattern.findall(Inc)
1740 if len(HeaderList) == 1 and len(HeaderList[0]) == 2:
1741 HeaderType = HeaderList[0][0]
1742 HeaderKey = HeaderList[0][1]
1743 if HeaderType in gIncludeMacroConversion:
1744 Inc = gIncludeMacroConversion[HeaderType] % {"HeaderKey" : HeaderKey}
1745 else:
1746 # not known macro used in #include, always build the file by
1747 # returning a empty dependency
1748 FileCache[File] = []
1749 return []
1750 Inc = os.path.normpath(Inc)
1751 CurrentFileDependencyList.append(Inc)
1752 DepDb[F] = CurrentFileDependencyList
1753
1754 CurrentFilePath = F.Dir
1755 PathList = [CurrentFilePath] + SearchPathList
1756 for Inc in CurrentFileDependencyList:
1757 for SearchPath in PathList:
1758 FilePath = os.path.join(SearchPath, Inc)
1759 if FilePath in gIsFileMap:
1760 if not gIsFileMap[FilePath]:
1761 continue
1762 # If isfile is called too many times, the performance is slow down.
1763 elif not os.path.isfile(FilePath):
1764 gIsFileMap[FilePath] = False
1765 continue
1766 else:
1767 gIsFileMap[FilePath] = True
1768 FilePath = PathClass(FilePath)
1769 FullPathDependList.append(FilePath)
1770 if FilePath not in DependencySet:
1771 FileStack.append(FilePath)
1772 break
1773 else:
1774 EdkLogger.debug(EdkLogger.DEBUG_9, "%s included by %s was not found "\
1775 "in any given path:\n\t%s" % (Inc, F, "\n\t".join(SearchPathList)))
1776
1777 FileCache[F] = FullPathDependList
1778 DependencySet.update(FullPathDependList)
1779
1780 DependencySet.update(ForceList)
1781 if File in DependencySet:
1782 DependencySet.remove(File)
1783 DependencyList = list(DependencySet) # remove duplicate ones
1784
1785 return DependencyList
1786
1787 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1788 if __name__ == '__main__':
1789 pass