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