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