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