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