]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/AutoGen/GenMake.py
Basetools: It went wrong when use os.linesep
[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" : self._SHELL_CMD_[self._FileType].keys(),
679 "shell_command" : 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 separater, 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 dependecies 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, 'r')
1042 except BaseException as X:
1043 EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=F.Path + "\n\t" + str(X))
1044
1045 FileContent = Fd.read()
1046 Fd.close()
1047 if len(FileContent) == 0:
1048 continue
1049
1050 if FileContent[0] == 0xff or FileContent[0] == 0xfe:
1051 FileContent = unicode(FileContent, "utf-16")
1052 IncludedFileList = gIncludePattern.findall(FileContent)
1053
1054 for Inc in IncludedFileList:
1055 Inc = Inc.strip()
1056 # if there's macro used to reference header file, expand it
1057 HeaderList = gMacroPattern.findall(Inc)
1058 if len(HeaderList) == 1 and len(HeaderList[0]) == 2:
1059 HeaderType = HeaderList[0][0]
1060 HeaderKey = HeaderList[0][1]
1061 if HeaderType in gIncludeMacroConversion:
1062 Inc = gIncludeMacroConversion[HeaderType] % {"HeaderKey" : HeaderKey}
1063 else:
1064 # not known macro used in #include, always build the file by
1065 # returning a empty dependency
1066 self.FileCache[File] = []
1067 return []
1068 Inc = os.path.normpath(Inc)
1069 CurrentFileDependencyList.append(Inc)
1070 DepDb[F] = CurrentFileDependencyList
1071
1072 CurrentFilePath = F.Dir
1073 PathList = [CurrentFilePath] + SearchPathList
1074 for Inc in CurrentFileDependencyList:
1075 for SearchPath in PathList:
1076 FilePath = os.path.join(SearchPath, Inc)
1077 if FilePath in gIsFileMap:
1078 if not gIsFileMap[FilePath]:
1079 continue
1080 # If isfile is called too many times, the performance is slow down.
1081 elif not os.path.isfile(FilePath):
1082 gIsFileMap[FilePath] = False
1083 continue
1084 else:
1085 gIsFileMap[FilePath] = True
1086 FilePath = PathClass(FilePath)
1087 FullPathDependList.append(FilePath)
1088 if FilePath not in DependencySet:
1089 FileStack.append(FilePath)
1090 break
1091 else:
1092 EdkLogger.debug(EdkLogger.DEBUG_9, "%s included by %s was not found "\
1093 "in any given path:\n\t%s" % (Inc, F, "\n\t".join(SearchPathList)))
1094
1095 self.FileCache[F] = FullPathDependList
1096 DependencySet.update(FullPathDependList)
1097
1098 DependencySet.update(ForceList)
1099 if File in DependencySet:
1100 DependencySet.remove(File)
1101 DependencyList = list(DependencySet) # remove duplicate ones
1102
1103 return DependencyList
1104
1105 ## CustomMakefile class
1106 #
1107 # This class encapsules makefie and its generation for module. It uses template to generate
1108 # the content of makefile. The content of makefile will be got from ModuleAutoGen object.
1109 #
1110 class CustomMakefile(BuildFile):
1111 ## template used to generate the makefile for module with custom makefile
1112 _TEMPLATE_ = TemplateString('''\
1113 ${makefile_header}
1114
1115 #
1116 # Platform Macro Definition
1117 #
1118 PLATFORM_NAME = ${platform_name}
1119 PLATFORM_GUID = ${platform_guid}
1120 PLATFORM_VERSION = ${platform_version}
1121 PLATFORM_RELATIVE_DIR = ${platform_relative_directory}
1122 PLATFORM_DIR = ${platform_dir}
1123 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1124
1125 #
1126 # Module Macro Definition
1127 #
1128 MODULE_NAME = ${module_name}
1129 MODULE_GUID = ${module_guid}
1130 MODULE_NAME_GUID = ${module_name_guid}
1131 MODULE_VERSION = ${module_version}
1132 MODULE_TYPE = ${module_type}
1133 MODULE_FILE = ${module_file}
1134 MODULE_FILE_BASE_NAME = ${module_file_base_name}
1135 BASE_NAME = $(MODULE_NAME)
1136 MODULE_RELATIVE_DIR = ${module_relative_directory}
1137 MODULE_DIR = ${module_dir}
1138
1139 #
1140 # Build Configuration Macro Definition
1141 #
1142 ARCH = ${architecture}
1143 TOOLCHAIN = ${toolchain_tag}
1144 TOOLCHAIN_TAG = ${toolchain_tag}
1145 TARGET = ${build_target}
1146
1147 #
1148 # Build Directory Macro Definition
1149 #
1150 # PLATFORM_BUILD_DIR = ${platform_build_directory}
1151 BUILD_DIR = ${platform_build_directory}
1152 BIN_DIR = $(BUILD_DIR)${separator}${architecture}
1153 LIB_DIR = $(BIN_DIR)
1154 MODULE_BUILD_DIR = ${module_build_directory}
1155 OUTPUT_DIR = ${module_output_directory}
1156 DEBUG_DIR = ${module_debug_directory}
1157 DEST_DIR_OUTPUT = $(OUTPUT_DIR)
1158 DEST_DIR_DEBUG = $(DEBUG_DIR)
1159
1160 #
1161 # Tools definitions specific to this module
1162 #
1163 ${BEGIN}${module_tool_definitions}
1164 ${END}
1165 MAKE_FILE = ${makefile_path}
1166
1167 #
1168 # Shell Command Macro
1169 #
1170 ${BEGIN}${shell_command_code} = ${shell_command}
1171 ${END}
1172
1173 ${custom_makefile_content}
1174
1175 #
1176 # Target used when called from platform makefile, which will bypass the build of dependent libraries
1177 #
1178
1179 pbuild: init all
1180
1181
1182 #
1183 # ModuleTarget
1184 #
1185
1186 mbuild: init all
1187
1188 #
1189 # Build Target used in multi-thread build mode, which no init target is needed
1190 #
1191
1192 tbuild: all
1193
1194 #
1195 # Initialization target: print build information and create necessary directories
1196 #
1197 init:
1198 \t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]
1199 ${BEGIN}\t-@${create_directory_command}\n${END}\
1200
1201 ''')
1202
1203 ## Constructor of CustomMakefile
1204 #
1205 # @param ModuleAutoGen Object of ModuleAutoGen class
1206 #
1207 def __init__(self, ModuleAutoGen):
1208 BuildFile.__init__(self, ModuleAutoGen)
1209 self.PlatformInfo = self._AutoGenObject.PlatformInfo
1210 self.IntermediateDirectoryList = ["$(DEBUG_DIR)", "$(OUTPUT_DIR)"]
1211
1212 # Compose a dict object containing information used to do replacement in template
1213 @property
1214 def _TemplateDict(self):
1215 Separator = self._SEP_[self._FileType]
1216 MyAgo = self._AutoGenObject
1217 if self._FileType not in MyAgo.CustomMakefile:
1218 EdkLogger.error('build', OPTION_NOT_SUPPORTED, "No custom makefile for %s" % self._FileType,
1219 ExtraData="[%s]" % str(MyAgo))
1220 MakefilePath = mws.join(
1221 MyAgo.WorkspaceDir,
1222 MyAgo.CustomMakefile[self._FileType]
1223 )
1224 try:
1225 CustomMakefile = open(MakefilePath, 'r').read()
1226 except:
1227 EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(MyAgo),
1228 ExtraData=MyAgo.CustomMakefile[self._FileType])
1229
1230 # tools definitions
1231 ToolsDef = []
1232 for Tool in MyAgo.BuildOption:
1233 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.
1234 if Tool == "MAKE":
1235 continue
1236 for Attr in MyAgo.BuildOption[Tool]:
1237 if Attr == "FAMILY":
1238 continue
1239 elif Attr == "PATH":
1240 ToolsDef.append("%s = %s" % (Tool, MyAgo.BuildOption[Tool][Attr]))
1241 else:
1242 ToolsDef.append("%s_%s = %s" % (Tool, Attr, MyAgo.BuildOption[Tool][Attr]))
1243 ToolsDef.append("")
1244
1245 MakefileName = self._FILE_NAME_[self._FileType]
1246 MakefileTemplateDict = {
1247 "makefile_header" : self._FILE_HEADER_[self._FileType],
1248 "makefile_path" : os.path.join("$(MODULE_BUILD_DIR)", MakefileName),
1249 "platform_name" : self.PlatformInfo.Name,
1250 "platform_guid" : self.PlatformInfo.Guid,
1251 "platform_version" : self.PlatformInfo.Version,
1252 "platform_relative_directory": self.PlatformInfo.SourceDir,
1253 "platform_output_directory" : self.PlatformInfo.OutputDir,
1254 "platform_dir" : MyAgo.Macros["PLATFORM_DIR"],
1255
1256 "module_name" : MyAgo.Name,
1257 "module_guid" : MyAgo.Guid,
1258 "module_name_guid" : MyAgo.UniqueBaseName,
1259 "module_version" : MyAgo.Version,
1260 "module_type" : MyAgo.ModuleType,
1261 "module_file" : MyAgo.MetaFile,
1262 "module_file_base_name" : MyAgo.MetaFile.BaseName,
1263 "module_relative_directory" : MyAgo.SourceDir,
1264 "module_dir" : mws.join (MyAgo.WorkspaceDir, MyAgo.SourceDir),
1265
1266 "architecture" : MyAgo.Arch,
1267 "toolchain_tag" : MyAgo.ToolChain,
1268 "build_target" : MyAgo.BuildTarget,
1269
1270 "platform_build_directory" : self.PlatformInfo.BuildDir,
1271 "module_build_directory" : MyAgo.BuildDir,
1272 "module_output_directory" : MyAgo.OutputDir,
1273 "module_debug_directory" : MyAgo.DebugDir,
1274
1275 "separator" : Separator,
1276 "module_tool_definitions" : ToolsDef,
1277
1278 "shell_command_code" : self._SHELL_CMD_[self._FileType].keys(),
1279 "shell_command" : self._SHELL_CMD_[self._FileType].values(),
1280
1281 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1282 "custom_makefile_content" : CustomMakefile
1283 }
1284
1285 return MakefileTemplateDict
1286
1287 ## PlatformMakefile class
1288 #
1289 # This class encapsules makefie and its generation for platform. It uses
1290 # template to generate the content of makefile. The content of makefile will be
1291 # got from PlatformAutoGen object.
1292 #
1293 class PlatformMakefile(BuildFile):
1294 ## template used to generate the makefile for platform
1295 _TEMPLATE_ = TemplateString('''\
1296 ${makefile_header}
1297
1298 #
1299 # Platform Macro Definition
1300 #
1301 PLATFORM_NAME = ${platform_name}
1302 PLATFORM_GUID = ${platform_guid}
1303 PLATFORM_VERSION = ${platform_version}
1304 PLATFORM_FILE = ${platform_file}
1305 PLATFORM_DIR = ${platform_dir}
1306 PLATFORM_OUTPUT_DIR = ${platform_output_directory}
1307
1308 #
1309 # Build Configuration Macro Definition
1310 #
1311 TOOLCHAIN = ${toolchain_tag}
1312 TOOLCHAIN_TAG = ${toolchain_tag}
1313 TARGET = ${build_target}
1314
1315 #
1316 # Build Directory Macro Definition
1317 #
1318 BUILD_DIR = ${platform_build_directory}
1319 FV_DIR = ${platform_build_directory}${separator}FV
1320
1321 #
1322 # Shell Command Macro
1323 #
1324 ${BEGIN}${shell_command_code} = ${shell_command}
1325 ${END}
1326
1327 MAKE = ${make_path}
1328 MAKE_FILE = ${makefile_path}
1329
1330 #
1331 # Default target
1332 #
1333 all: init build_libraries build_modules
1334
1335 #
1336 # Initialization target: print build information and create necessary directories
1337 #
1338 init:
1339 \t-@echo Building ... $(PLATFORM_FILE) [${build_architecture_list}]
1340 \t${BEGIN}-@${create_directory_command}
1341 \t${END}
1342 #
1343 # library build target
1344 #
1345 libraries: init build_libraries
1346
1347 #
1348 # module build target
1349 #
1350 modules: init build_libraries build_modules
1351
1352 #
1353 # Build all libraries:
1354 #
1355 build_libraries:
1356 ${BEGIN}\t@"$(MAKE)" $(MAKE_FLAGS) -f ${library_makefile_list} pbuild
1357 ${END}\t@cd $(BUILD_DIR)
1358
1359 #
1360 # Build all modules:
1361 #
1362 build_modules:
1363 ${BEGIN}\t@"$(MAKE)" $(MAKE_FLAGS) -f ${module_makefile_list} pbuild
1364 ${END}\t@cd $(BUILD_DIR)
1365
1366 #
1367 # Clean intermediate files
1368 #
1369 clean:
1370 \t${BEGIN}-@${library_build_command} clean
1371 \t${END}${BEGIN}-@${module_build_command} clean
1372 \t${END}@cd $(BUILD_DIR)
1373
1374 #
1375 # Clean all generated files except to makefile
1376 #
1377 cleanall:
1378 ${BEGIN}\t${cleanall_command}
1379 ${END}
1380
1381 #
1382 # Clean all library files
1383 #
1384 cleanlib:
1385 \t${BEGIN}-@${library_build_command} cleanall
1386 \t${END}@cd $(BUILD_DIR)\n
1387 ''')
1388
1389 ## Constructor of PlatformMakefile
1390 #
1391 # @param ModuleAutoGen Object of PlatformAutoGen class
1392 #
1393 def __init__(self, PlatformAutoGen):
1394 BuildFile.__init__(self, PlatformAutoGen)
1395 self.ModuleBuildCommandList = []
1396 self.ModuleMakefileList = []
1397 self.IntermediateDirectoryList = []
1398 self.ModuleBuildDirectoryList = []
1399 self.LibraryBuildDirectoryList = []
1400 self.LibraryMakeCommandList = []
1401
1402 # Compose a dict object containing information used to do replacement in template
1403 @property
1404 def _TemplateDict(self):
1405 Separator = self._SEP_[self._FileType]
1406
1407 MyAgo = self._AutoGenObject
1408 if "MAKE" not in MyAgo.ToolDefinition or "PATH" not in MyAgo.ToolDefinition["MAKE"]:
1409 EdkLogger.error("build", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!",
1410 ExtraData="[%s]" % str(MyAgo))
1411
1412 self.IntermediateDirectoryList = ["$(BUILD_DIR)"]
1413 self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()
1414 self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()
1415
1416 MakefileName = self._FILE_NAME_[self._FileType]
1417 LibraryMakefileList = []
1418 LibraryMakeCommandList = []
1419 for D in self.LibraryBuildDirectoryList:
1420 D = self.PlaceMacro(D, {"BUILD_DIR":MyAgo.BuildDir})
1421 Makefile = os.path.join(D, MakefileName)
1422 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1423 LibraryMakefileList.append(Makefile)
1424 LibraryMakeCommandList.append(Command)
1425 self.LibraryMakeCommandList = LibraryMakeCommandList
1426
1427 ModuleMakefileList = []
1428 ModuleMakeCommandList = []
1429 for D in self.ModuleBuildDirectoryList:
1430 D = self.PlaceMacro(D, {"BUILD_DIR":MyAgo.BuildDir})
1431 Makefile = os.path.join(D, MakefileName)
1432 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}
1433 ModuleMakefileList.append(Makefile)
1434 ModuleMakeCommandList.append(Command)
1435
1436 MakefileTemplateDict = {
1437 "makefile_header" : self._FILE_HEADER_[self._FileType],
1438 "makefile_path" : os.path.join("$(BUILD_DIR)", MakefileName),
1439 "make_path" : MyAgo.ToolDefinition["MAKE"]["PATH"],
1440 "makefile_name" : MakefileName,
1441 "platform_name" : MyAgo.Name,
1442 "platform_guid" : MyAgo.Guid,
1443 "platform_version" : MyAgo.Version,
1444 "platform_file" : MyAgo.MetaFile,
1445 "platform_relative_directory": MyAgo.SourceDir,
1446 "platform_output_directory" : MyAgo.OutputDir,
1447 "platform_build_directory" : MyAgo.BuildDir,
1448 "platform_dir" : MyAgo.Macros["PLATFORM_DIR"],
1449
1450 "toolchain_tag" : MyAgo.ToolChain,
1451 "build_target" : MyAgo.BuildTarget,
1452 "shell_command_code" : self._SHELL_CMD_[self._FileType].keys(),
1453 "shell_command" : self._SHELL_CMD_[self._FileType].values(),
1454 "build_architecture_list" : MyAgo.Arch,
1455 "architecture" : MyAgo.Arch,
1456 "separator" : Separator,
1457 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1458 "cleanall_command" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1459 "library_makefile_list" : LibraryMakefileList,
1460 "module_makefile_list" : ModuleMakefileList,
1461 "library_build_command" : LibraryMakeCommandList,
1462 "module_build_command" : ModuleMakeCommandList,
1463 }
1464
1465 return MakefileTemplateDict
1466
1467 ## Get the root directory list for intermediate files of all modules build
1468 #
1469 # @retval list The list of directory
1470 #
1471 def GetModuleBuildDirectoryList(self):
1472 DirList = []
1473 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1474 if not ModuleAutoGen.IsBinaryModule:
1475 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1476 return DirList
1477
1478 ## Get the root directory list for intermediate files of all libraries build
1479 #
1480 # @retval list The list of directory
1481 #
1482 def GetLibraryBuildDirectoryList(self):
1483 DirList = []
1484 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1485 if not LibraryAutoGen.IsBinaryModule:
1486 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1487 return DirList
1488
1489 ## TopLevelMakefile class
1490 #
1491 # This class encapsules makefie and its generation for entrance makefile. It
1492 # uses template to generate the content of makefile. The content of makefile
1493 # will be got from WorkspaceAutoGen object.
1494 #
1495 class TopLevelMakefile(BuildFile):
1496 ## template used to generate toplevel makefile
1497 _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}''')
1498
1499 ## Constructor of TopLevelMakefile
1500 #
1501 # @param Workspace Object of WorkspaceAutoGen class
1502 #
1503 def __init__(self, Workspace):
1504 BuildFile.__init__(self, Workspace)
1505 self.IntermediateDirectoryList = []
1506
1507 # Compose a dict object containing information used to do replacement in template
1508 @property
1509 def _TemplateDict(self):
1510 Separator = self._SEP_[self._FileType]
1511
1512 # any platform autogen object is ok because we just need common information
1513 MyAgo = self._AutoGenObject
1514
1515 if "MAKE" not in MyAgo.ToolDefinition or "PATH" not in MyAgo.ToolDefinition["MAKE"]:
1516 EdkLogger.error("build", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!",
1517 ExtraData="[%s]" % str(MyAgo))
1518
1519 for Arch in MyAgo.ArchList:
1520 self.IntermediateDirectoryList.append(Separator.join(["$(BUILD_DIR)", Arch]))
1521 self.IntermediateDirectoryList.append("$(FV_DIR)")
1522
1523 # TRICK: for not generating GenFds call in makefile if no FDF file
1524 MacroList = []
1525 if MyAgo.FdfFile is not None and MyAgo.FdfFile != "":
1526 FdfFileList = [MyAgo.FdfFile]
1527 # macros passed to GenFds
1528 MacroDict = {}
1529 MacroDict.update(GlobalData.gGlobalDefines)
1530 MacroDict.update(GlobalData.gCommandLineDefines)
1531 for MacroName in MacroDict:
1532 if MacroDict[MacroName] != "":
1533 MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
1534 else:
1535 MacroList.append('"%s"' % MacroName)
1536 else:
1537 FdfFileList = []
1538
1539 # pass extra common options to external program called in makefile, currently GenFds.exe
1540 ExtraOption = ''
1541 LogLevel = EdkLogger.GetLevel()
1542 if LogLevel == EdkLogger.VERBOSE:
1543 ExtraOption += " -v"
1544 elif LogLevel <= EdkLogger.DEBUG_9:
1545 ExtraOption += " -d %d" % (LogLevel - 1)
1546 elif LogLevel == EdkLogger.QUIET:
1547 ExtraOption += " -q"
1548
1549 if GlobalData.gCaseInsensitive:
1550 ExtraOption += " -c"
1551 if GlobalData.gEnableGenfdsMultiThread:
1552 ExtraOption += " --genfds-multi-thread"
1553 if GlobalData.gIgnoreSource:
1554 ExtraOption += " --ignore-sources"
1555
1556 for pcd in GlobalData.BuildOptionPcd:
1557 if pcd[2]:
1558 pcdname = '.'.join(pcd[0:3])
1559 else:
1560 pcdname = '.'.join(pcd[0:2])
1561 if pcd[3].startswith('{'):
1562 ExtraOption += " --pcd " + pcdname + '=' + 'H' + '"' + pcd[3] + '"'
1563 else:
1564 ExtraOption += " --pcd " + pcdname + '=' + pcd[3]
1565
1566 MakefileName = self._FILE_NAME_[self._FileType]
1567 SubBuildCommandList = []
1568 for A in MyAgo.ArchList:
1569 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join("$(BUILD_DIR)", A, MakefileName)}
1570 SubBuildCommandList.append(Command)
1571
1572 MakefileTemplateDict = {
1573 "makefile_header" : self._FILE_HEADER_[self._FileType],
1574 "makefile_path" : os.path.join("$(BUILD_DIR)", MakefileName),
1575 "make_path" : MyAgo.ToolDefinition["MAKE"]["PATH"],
1576 "platform_name" : MyAgo.Name,
1577 "platform_guid" : MyAgo.Guid,
1578 "platform_version" : MyAgo.Version,
1579 "platform_build_directory" : MyAgo.BuildDir,
1580 "conf_directory" : GlobalData.gConfDirectory,
1581
1582 "toolchain_tag" : MyAgo.ToolChain,
1583 "build_target" : MyAgo.BuildTarget,
1584 "shell_command_code" : self._SHELL_CMD_[self._FileType].keys(),
1585 "shell_command" : self._SHELL_CMD_[self._FileType].values(),
1586 'arch' : list(MyAgo.ArchList),
1587 "build_architecture_list" : ','.join(MyAgo.ArchList),
1588 "separator" : Separator,
1589 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),
1590 "cleanall_command" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),
1591 "sub_build_command" : SubBuildCommandList,
1592 "fdf_file" : FdfFileList,
1593 "active_platform" : str(MyAgo),
1594 "fd" : MyAgo.FdTargetList,
1595 "fv" : MyAgo.FvTargetList,
1596 "cap" : MyAgo.CapTargetList,
1597 "extra_options" : ExtraOption,
1598 "macro" : MacroList,
1599 }
1600
1601 return MakefileTemplateDict
1602
1603 ## Get the root directory list for intermediate files of all modules build
1604 #
1605 # @retval list The list of directory
1606 #
1607 def GetModuleBuildDirectoryList(self):
1608 DirList = []
1609 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:
1610 if not ModuleAutoGen.IsBinaryModule:
1611 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))
1612 return DirList
1613
1614 ## Get the root directory list for intermediate files of all libraries build
1615 #
1616 # @retval list The list of directory
1617 #
1618 def GetLibraryBuildDirectoryList(self):
1619 DirList = []
1620 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:
1621 if not LibraryAutoGen.IsBinaryModule:
1622 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))
1623 return DirList
1624
1625 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1626 if __name__ == '__main__':
1627 pass
1628