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