]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/AutoGen/GenMake.py
BaseTools: not include the undefined macro in response file
[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
236PLATFORM_DIR = $(WORKSPACE)${separator}${platform_relative_directory}\r
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
b442ad5c
YL
600 for fl in os.listdir(current_dir):\r
601 if fl.endswith('.dec'):\r
602 found = True\r
603 break\r
604 package_rel_dir = package_rel_dir[index + 1:]\r
97fa0ee9 605\r
f51461c8
LG
606 MakefileTemplateDict = {\r
607 "makefile_header" : self._FILE_HEADER_[self._FileType],\r
608 "makefile_path" : os.path.join("$(MODULE_BUILD_DIR)", MakefileName),\r
609 "makefile_name" : MakefileName,\r
610 "platform_name" : self.PlatformInfo.Name,\r
611 "platform_guid" : self.PlatformInfo.Guid,\r
612 "platform_version" : self.PlatformInfo.Version,\r
613 "platform_relative_directory": self.PlatformInfo.SourceDir,\r
614 "platform_output_directory" : self.PlatformInfo.OutputDir,\r
615\r
616 "module_name" : self._AutoGenObject.Name,\r
617 "module_guid" : self._AutoGenObject.Guid,\r
867d1cd4 618 "module_name_guid" : self._AutoGenObject._GetUniqueBaseName(),\r
f51461c8
LG
619 "module_version" : self._AutoGenObject.Version,\r
620 "module_type" : self._AutoGenObject.ModuleType,\r
621 "module_file" : self._AutoGenObject.MetaFile.Name,\r
622 "module_file_base_name" : self._AutoGenObject.MetaFile.BaseName,\r
623 "module_relative_directory" : self._AutoGenObject.SourceDir,\r
01e418d6 624 "module_dir" : mws.join (self.Macros["WORKSPACE"], self._AutoGenObject.SourceDir),\r
97fa0ee9
YL
625 "package_relative_directory": package_rel_dir,\r
626 "module_extra_defines" : ["%s = %s" % (k, v) for k, v in self._AutoGenObject.Module.Defines.iteritems()],\r
f51461c8
LG
627\r
628 "architecture" : self._AutoGenObject.Arch,\r
629 "toolchain_tag" : self._AutoGenObject.ToolChain,\r
630 "build_target" : self._AutoGenObject.BuildTarget,\r
631\r
632 "platform_build_directory" : self.PlatformInfo.BuildDir,\r
633 "module_build_directory" : self._AutoGenObject.BuildDir,\r
634 "module_output_directory" : self._AutoGenObject.OutputDir,\r
635 "module_debug_directory" : self._AutoGenObject.DebugDir,\r
636\r
637 "separator" : Separator,\r
638 "module_tool_definitions" : ToolsDef,\r
639\r
640 "shell_command_code" : self._SHELL_CMD_[self._FileType].keys(),\r
641 "shell_command" : self._SHELL_CMD_[self._FileType].values(),\r
642\r
643 "module_entry_point" : ModuleEntryPoint,\r
644 "image_entry_point" : ImageEntryPoint,\r
645 "arch_entry_point" : ArchEntryPoint,\r
646 "remaining_build_target" : self.ResultFileList,\r
647 "common_dependency_file" : self.CommonFileDependency,\r
648 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),\r
649 "clean_command" : self.GetRemoveDirectoryCommand(["$(OUTPUT_DIR)"]),\r
650 "cleanall_command" : self.GetRemoveDirectoryCommand(["$(DEBUG_DIR)", "$(OUTPUT_DIR)"]),\r
651 "dependent_library_build_directory" : self.LibraryBuildDirectoryList,\r
652 "library_build_command" : LibraryMakeCommandList,\r
653 "file_macro" : FileMacroList,\r
654 "file_build_target" : self.BuildTargetList,\r
655 "backward_compatible_target": BcTargetList,\r
656 }\r
657\r
658 return MakefileTemplateDict\r
659\r
725cdb8f
YZ
660 def CommandExceedLimit(self):\r
661 FlagDict = {\r
662 'CC' : { 'Macro' : '$(CC_FLAGS)', 'Value' : False},\r
663 'PP' : { 'Macro' : '$(PP_FLAGS)', 'Value' : False},\r
664 'APP' : { 'Macro' : '$(APP_FLAGS)', 'Value' : False},\r
665 'ASLPP' : { 'Macro' : '$(ASLPP_FLAGS)', 'Value' : False},\r
666 'VFRPP' : { 'Macro' : '$(VFRPP_FLAGS)', 'Value' : False},\r
667 'ASM' : { 'Macro' : '$(ASM_FLAGS)', 'Value' : False},\r
668 'ASLCC' : { 'Macro' : '$(ASLCC_FLAGS)', 'Value' : False},\r
669 }\r
670\r
671 RespDict = {}\r
672 FileTypeList = []\r
673 IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily]\r
674\r
675 # base on the source files to decide the file type\r
676 for File in self._AutoGenObject.SourceFileList:\r
677 for type in self._AutoGenObject.FileTypes:\r
678 if File in self._AutoGenObject.FileTypes[type]:\r
679 if type not in FileTypeList:\r
680 FileTypeList.append(type)\r
681\r
682 # calculate the command-line length\r
683 if FileTypeList:\r
684 for type in FileTypeList:\r
685 BuildTargets = self._AutoGenObject.BuildRules[type].BuildTargets\r
686 for Target in BuildTargets:\r
687 CommandList = BuildTargets[Target].Commands\r
688 for SingleCommand in CommandList:\r
689 Tool = ''\r
690 SingleCommandLength = len(SingleCommand)\r
691 SingleCommandList = SingleCommand.split()\r
692 if len(SingleCommandList) > 0:\r
693 for Flag in FlagDict.keys():\r
694 if '$('+ Flag +')' in SingleCommandList[0]:\r
695 Tool = Flag\r
696 break\r
697 if Tool:\r
698 SingleCommandLength += len(self._AutoGenObject._BuildOption[Tool]['PATH'])\r
699 for item in SingleCommandList[1:]:\r
700 if FlagDict[Tool]['Macro'] in item:\r
701 Str = self._AutoGenObject._BuildOption[Tool]['FLAGS']\r
3570e332
YZ
702 for Option in self._AutoGenObject.BuildOption.keys():\r
703 for Attr in self._AutoGenObject.BuildOption[Option]:\r
704 if Str.find(Option + '_' + Attr) != -1:\r
705 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])\r
725cdb8f
YZ
706 while(Str.find('$(') != -1):\r
707 for macro in self._AutoGenObject.Macros.keys():\r
708 MacroName = '$('+ macro + ')'\r
709 if (Str.find(MacroName) != -1):\r
710 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])\r
711 break\r
712 else:\r
3570e332 713 break\r
725cdb8f
YZ
714 SingleCommandLength += len(Str)\r
715 elif '$(INC)' in item:\r
716 SingleCommandLength += self._AutoGenObject.IncludePathLength + len(IncPrefix) * len(self._AutoGenObject._IncludePathList)\r
717 elif item.find('$(') != -1:\r
718 Str = item\r
719 for Option in self._AutoGenObject.BuildOption.keys():\r
720 for Attr in self._AutoGenObject.BuildOption[Option]:\r
721 if Str.find(Option + '_' + Attr) != -1:\r
722 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])\r
723 while(Str.find('$(') != -1):\r
724 for macro in self._AutoGenObject.Macros.keys():\r
725 MacroName = '$('+ macro + ')'\r
726 if (Str.find(MacroName) != -1):\r
727 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])\r
728 break\r
729 else:\r
3570e332 730 break\r
725cdb8f
YZ
731 SingleCommandLength += len(Str)\r
732\r
733 if SingleCommandLength > GlobalData.gCommandMaxLength:\r
734 FlagDict[Tool]['Value'] = True\r
735\r
736 # generate the response file content by combine the FLAGS and INC\r
737 for Flag in FlagDict.keys():\r
738 if FlagDict[Flag]['Value']:\r
739 Key = Flag + '_RESP'\r
740 RespMacro = FlagDict[Flag]['Macro'].replace('FLAGS', 'RESP')\r
741 Value = self._AutoGenObject.BuildOption[Flag]['FLAGS']\r
742 for inc in self._AutoGenObject._IncludePathList:\r
743 Value += ' ' + IncPrefix + inc\r
3570e332
YZ
744 for Option in self._AutoGenObject.BuildOption.keys():\r
745 for Attr in self._AutoGenObject.BuildOption[Option]:\r
746 if Value.find(Option + '_' + Attr) != -1:\r
747 Value = Value.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])\r
725cdb8f
YZ
748 while (Value.find('$(') != -1):\r
749 for macro in self._AutoGenObject.Macros.keys():\r
750 MacroName = '$('+ macro + ')'\r
751 if (Value.find(MacroName) != -1):\r
752 Value = Value.replace(MacroName, self._AutoGenObject.Macros[macro])\r
753 break\r
754 else:\r
3570e332 755 break\r
725cdb8f
YZ
756 RespDict[Key] = Value\r
757 for Target in BuildTargets:\r
758 for i, SingleCommand in enumerate(BuildTargets[Target].Commands):\r
759 if FlagDict[Flag]['Macro'] in SingleCommand:\r
760 BuildTargets[Target].Commands[i] = SingleCommand.replace('$(INC)','').replace(FlagDict[Flag]['Macro'], RespMacro)\r
761 return RespDict\r
762\r
f51461c8
LG
763 def ProcessBuildTargetList(self):\r
764 #\r
765 # Search dependency file list for each source file\r
766 #\r
767 ForceIncludedFile = []\r
768 for File in self._AutoGenObject.AutoGenFileList:\r
769 if File.Ext == '.h':\r
770 ForceIncludedFile.append(File)\r
771 SourceFileList = []\r
772 for Target in self._AutoGenObject.IntroTargetList:\r
773 SourceFileList.extend(Target.Inputs)\r
774\r
775 self.FileDependency = self.GetFileDependency(\r
776 SourceFileList,\r
777 ForceIncludedFile,\r
778 self._AutoGenObject.IncludePathList + self._AutoGenObject.BuildOptionIncPathList\r
779 )\r
780 DepSet = None\r
781 for File in self.FileDependency:\r
782 if not self.FileDependency[File]:\r
783 self.FileDependency[File] = ['$(FORCE_REBUILD)']\r
784 continue\r
785 # skip non-C files\r
786 if File.Ext not in [".c", ".C"] or File.Name == "AutoGen.c":\r
787 continue\r
788 elif DepSet == None:\r
789 DepSet = set(self.FileDependency[File])\r
790 else:\r
791 DepSet &= set(self.FileDependency[File])\r
792 # in case nothing in SourceFileList\r
793 if DepSet == None:\r
794 DepSet = set()\r
795 #\r
796 # Extract common files list in the dependency files\r
797 #\r
798 for File in DepSet:\r
799 self.CommonFileDependency.append(self.PlaceMacro(File.Path, self.Macros))\r
800\r
801 for File in self.FileDependency:\r
802 # skip non-C files\r
803 if File.Ext not in [".c", ".C"] or File.Name == "AutoGen.c":\r
804 continue\r
805 NewDepSet = set(self.FileDependency[File])\r
806 NewDepSet -= DepSet\r
807 self.FileDependency[File] = ["$(COMMON_DEPS)"] + list(NewDepSet)\r
808\r
809 # Convert target description object to target string in makefile\r
810 for Type in self._AutoGenObject.Targets:\r
811 for T in self._AutoGenObject.Targets[Type]:\r
812 # Generate related macros if needed\r
813 if T.GenFileListMacro and T.FileListMacro not in self.FileListMacros:\r
814 self.FileListMacros[T.FileListMacro] = []\r
815 if T.GenListFile and T.ListFileMacro not in self.ListFileMacros:\r
816 self.ListFileMacros[T.ListFileMacro] = []\r
817 if T.GenIncListFile and T.IncListFileMacro not in self.ListFileMacros:\r
818 self.ListFileMacros[T.IncListFileMacro] = []\r
819\r
820 Deps = []\r
821 # Add force-dependencies\r
822 for Dep in T.Dependencies:\r
823 Deps.append(self.PlaceMacro(str(Dep), self.Macros))\r
824 # Add inclusion-dependencies\r
825 if len(T.Inputs) == 1 and T.Inputs[0] in self.FileDependency:\r
826 for F in self.FileDependency[T.Inputs[0]]:\r
827 Deps.append(self.PlaceMacro(str(F), self.Macros))\r
828 # Add source-dependencies\r
829 for F in T.Inputs:\r
830 NewFile = self.PlaceMacro(str(F), self.Macros)\r
831 # In order to use file list macro as dependency\r
832 if T.GenListFile:\r
285a1754
SD
833 # gnu tools need forward slash path separater, even on Windows\r
834 self.ListFileMacros[T.ListFileMacro].append(str(F).replace ('\\', '/'))\r
f51461c8
LG
835 self.FileListMacros[T.FileListMacro].append(NewFile)\r
836 elif T.GenFileListMacro:\r
837 self.FileListMacros[T.FileListMacro].append(NewFile)\r
838 else:\r
839 Deps.append(NewFile)\r
840\r
841 # Use file list macro as dependency\r
842 if T.GenFileListMacro:\r
843 Deps.append("$(%s)" % T.FileListMacro)\r
844\r
845 TargetDict = {\r
846 "target" : self.PlaceMacro(T.Target.Path, self.Macros),\r
847 "cmd" : "\n\t".join(T.Commands),\r
848 "deps" : Deps\r
849 }\r
850 self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(TargetDict))\r
851\r
852 ## For creating makefile targets for dependent libraries\r
853 def ProcessDependentLibrary(self):\r
854 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:\r
855 self.LibraryBuildDirectoryList.append(self.PlaceMacro(LibraryAutoGen.BuildDir, self.Macros))\r
856\r
857 ## Return a list containing source file's dependencies\r
858 #\r
859 # @param FileList The list of source files\r
860 # @param ForceInculeList The list of files which will be included forcely\r
861 # @param SearchPathList The list of search path\r
862 #\r
863 # @retval dict The mapping between source file path and its dependencies\r
864 #\r
865 def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):\r
866 Dependency = {}\r
867 for F in FileList:\r
868 Dependency[F] = self.GetDependencyList(F, ForceInculeList, SearchPathList)\r
869 return Dependency\r
870\r
871 ## Find dependencies for one source file\r
872 #\r
873 # By searching recursively "#include" directive in file, find out all the\r
874 # files needed by given source file. The dependecies will be only searched\r
875 # in given search path list.\r
876 #\r
877 # @param File The source file\r
878 # @param ForceInculeList The list of files which will be included forcely\r
879 # @param SearchPathList The list of search path\r
880 #\r
881 # @retval list The list of files the given source file depends on\r
882 #\r
883 def GetDependencyList(self, File, ForceList, SearchPathList):\r
884 EdkLogger.debug(EdkLogger.DEBUG_1, "Try to get dependency files for %s" % File)\r
885 FileStack = [File] + ForceList\r
886 DependencySet = set()\r
887\r
888 if self._AutoGenObject.Arch not in gDependencyDatabase:\r
889 gDependencyDatabase[self._AutoGenObject.Arch] = {}\r
890 DepDb = gDependencyDatabase[self._AutoGenObject.Arch]\r
891\r
892 while len(FileStack) > 0:\r
893 F = FileStack.pop()\r
894\r
895 FullPathDependList = []\r
896 if F in self.FileCache:\r
897 for CacheFile in self.FileCache[F]:\r
898 FullPathDependList.append(CacheFile)\r
899 if CacheFile not in DependencySet:\r
900 FileStack.append(CacheFile)\r
901 DependencySet.update(FullPathDependList)\r
902 continue\r
903\r
904 CurrentFileDependencyList = []\r
905 if F in DepDb:\r
906 CurrentFileDependencyList = DepDb[F]\r
907 else:\r
908 try:\r
909 Fd = open(F.Path, 'r')\r
910 except BaseException, X:\r
47fea6af 911 EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=F.Path + "\n\t" + str(X))\r
f51461c8
LG
912\r
913 FileContent = Fd.read()\r
914 Fd.close()\r
915 if len(FileContent) == 0:\r
916 continue\r
917\r
918 if FileContent[0] == 0xff or FileContent[0] == 0xfe:\r
919 FileContent = unicode(FileContent, "utf-16")\r
920 IncludedFileList = gIncludePattern.findall(FileContent)\r
921\r
922 for Inc in IncludedFileList:\r
923 Inc = Inc.strip()\r
924 # if there's macro used to reference header file, expand it\r
925 HeaderList = gMacroPattern.findall(Inc)\r
926 if len(HeaderList) == 1 and len(HeaderList[0]) == 2:\r
927 HeaderType = HeaderList[0][0]\r
928 HeaderKey = HeaderList[0][1]\r
929 if HeaderType in gIncludeMacroConversion:\r
930 Inc = gIncludeMacroConversion[HeaderType] % {"HeaderKey" : HeaderKey}\r
931 else:\r
932 # not known macro used in #include, always build the file by\r
933 # returning a empty dependency\r
934 self.FileCache[File] = []\r
935 return []\r
936 Inc = os.path.normpath(Inc)\r
937 CurrentFileDependencyList.append(Inc)\r
938 DepDb[F] = CurrentFileDependencyList\r
939\r
940 CurrentFilePath = F.Dir\r
941 PathList = [CurrentFilePath] + SearchPathList\r
942 for Inc in CurrentFileDependencyList:\r
943 for SearchPath in PathList:\r
944 FilePath = os.path.join(SearchPath, Inc)\r
945 if FilePath in gIsFileMap:\r
946 if not gIsFileMap[FilePath]:\r
947 continue\r
948 # If isfile is called too many times, the performance is slow down.\r
949 elif not os.path.isfile(FilePath):\r
950 gIsFileMap[FilePath] = False\r
951 continue\r
952 else:\r
953 gIsFileMap[FilePath] = True\r
954 FilePath = PathClass(FilePath)\r
955 FullPathDependList.append(FilePath)\r
956 if FilePath not in DependencySet:\r
957 FileStack.append(FilePath)\r
958 break\r
959 else:\r
960 EdkLogger.debug(EdkLogger.DEBUG_9, "%s included by %s was not found "\\r
961 "in any given path:\n\t%s" % (Inc, F, "\n\t".join(SearchPathList)))\r
962\r
963 self.FileCache[F] = FullPathDependList\r
964 DependencySet.update(FullPathDependList)\r
965\r
966 DependencySet.update(ForceList)\r
967 if File in DependencySet:\r
968 DependencySet.remove(File)\r
969 DependencyList = list(DependencySet) # remove duplicate ones\r
970\r
971 return DependencyList\r
972\r
973 _TemplateDict = property(_CreateTemplateDict)\r
974\r
975## CustomMakefile class\r
976#\r
977# This class encapsules makefie and its generation for module. It uses template to generate\r
978# the content of makefile. The content of makefile will be got from ModuleAutoGen object.\r
979#\r
980class CustomMakefile(BuildFile):\r
981 ## template used to generate the makefile for module with custom makefile\r
982 _TEMPLATE_ = TemplateString('''\\r
983${makefile_header}\r
984\r
985#\r
986# Platform Macro Definition\r
987#\r
988PLATFORM_NAME = ${platform_name}\r
989PLATFORM_GUID = ${platform_guid}\r
990PLATFORM_VERSION = ${platform_version}\r
991PLATFORM_RELATIVE_DIR = ${platform_relative_directory}\r
992PLATFORM_DIR = $(WORKSPACE)${separator}${platform_relative_directory}\r
993PLATFORM_OUTPUT_DIR = ${platform_output_directory}\r
994\r
995#\r
996# Module Macro Definition\r
997#\r
998MODULE_NAME = ${module_name}\r
999MODULE_GUID = ${module_guid}\r
867d1cd4 1000MODULE_NAME_GUID = ${module_name_guid}\r
f51461c8
LG
1001MODULE_VERSION = ${module_version}\r
1002MODULE_TYPE = ${module_type}\r
1003MODULE_FILE = ${module_file}\r
1004MODULE_FILE_BASE_NAME = ${module_file_base_name}\r
1005BASE_NAME = $(MODULE_NAME)\r
1006MODULE_RELATIVE_DIR = ${module_relative_directory}\r
01e418d6 1007MODULE_DIR = ${module_dir}\r
f51461c8
LG
1008\r
1009#\r
1010# Build Configuration Macro Definition\r
1011#\r
1012ARCH = ${architecture}\r
1013TOOLCHAIN = ${toolchain_tag}\r
1014TOOLCHAIN_TAG = ${toolchain_tag}\r
1015TARGET = ${build_target}\r
1016\r
1017#\r
1018# Build Directory Macro Definition\r
1019#\r
1020# PLATFORM_BUILD_DIR = ${platform_build_directory}\r
1021BUILD_DIR = ${platform_build_directory}\r
1022BIN_DIR = $(BUILD_DIR)${separator}${architecture}\r
1023LIB_DIR = $(BIN_DIR)\r
1024MODULE_BUILD_DIR = ${module_build_directory}\r
1025OUTPUT_DIR = ${module_output_directory}\r
1026DEBUG_DIR = ${module_debug_directory}\r
1027DEST_DIR_OUTPUT = $(OUTPUT_DIR)\r
1028DEST_DIR_DEBUG = $(DEBUG_DIR)\r
1029\r
1030#\r
1031# Tools definitions specific to this module\r
1032#\r
1033${BEGIN}${module_tool_definitions}\r
1034${END}\r
1035MAKE_FILE = ${makefile_path}\r
1036\r
1037#\r
1038# Shell Command Macro\r
1039#\r
1040${BEGIN}${shell_command_code} = ${shell_command}\r
1041${END}\r
1042\r
1043${custom_makefile_content}\r
1044\r
1045#\r
1046# Target used when called from platform makefile, which will bypass the build of dependent libraries\r
1047#\r
1048\r
1049pbuild: init all\r
1050\r
1051\r
1052#\r
1053# ModuleTarget\r
1054#\r
1055\r
1056mbuild: init all\r
1057\r
1058#\r
1059# Build Target used in multi-thread build mode, which no init target is needed\r
1060#\r
1061\r
1062tbuild: all\r
1063\r
1064#\r
1065# Initialization target: print build information and create necessary directories\r
1066#\r
1067init:\r
1068\t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]\r
1069${BEGIN}\t-@${create_directory_command}\n${END}\\r
1070\r
1071''')\r
1072\r
1073 ## Constructor of CustomMakefile\r
1074 #\r
1075 # @param ModuleAutoGen Object of ModuleAutoGen class\r
1076 #\r
1077 def __init__(self, ModuleAutoGen):\r
1078 BuildFile.__init__(self, ModuleAutoGen)\r
1079 self.PlatformInfo = self._AutoGenObject.PlatformInfo\r
1080 self.IntermediateDirectoryList = ["$(DEBUG_DIR)", "$(OUTPUT_DIR)"]\r
1081\r
1082 # Compose a dict object containing information used to do replacement in template\r
1083 def _CreateTemplateDict(self):\r
1084 Separator = self._SEP_[self._FileType]\r
1085 if self._FileType not in self._AutoGenObject.CustomMakefile:\r
1086 EdkLogger.error('build', OPTION_NOT_SUPPORTED, "No custom makefile for %s" % self._FileType,\r
1087 ExtraData="[%s]" % str(self._AutoGenObject))\r
01e418d6 1088 MakefilePath = mws.join(\r
f51461c8
LG
1089 self._AutoGenObject.WorkspaceDir,\r
1090 self._AutoGenObject.CustomMakefile[self._FileType]\r
1091 )\r
1092 try:\r
1093 CustomMakefile = open(MakefilePath, 'r').read()\r
1094 except:\r
1095 EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(self._AutoGenObject),\r
1096 ExtraData=self._AutoGenObject.CustomMakefile[self._FileType])\r
1097\r
1098 # tools definitions\r
1099 ToolsDef = []\r
1100 for Tool in self._AutoGenObject.BuildOption:\r
1101 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.\r
1102 if Tool == "MAKE":\r
1103 continue\r
1104 for Attr in self._AutoGenObject.BuildOption[Tool]:\r
1105 if Attr == "FAMILY":\r
1106 continue\r
1107 elif Attr == "PATH":\r
1108 ToolsDef.append("%s = %s" % (Tool, self._AutoGenObject.BuildOption[Tool][Attr]))\r
1109 else:\r
1110 ToolsDef.append("%s_%s = %s" % (Tool, Attr, self._AutoGenObject.BuildOption[Tool][Attr]))\r
1111 ToolsDef.append("")\r
1112\r
1113 MakefileName = self._FILE_NAME_[self._FileType]\r
1114 MakefileTemplateDict = {\r
1115 "makefile_header" : self._FILE_HEADER_[self._FileType],\r
1116 "makefile_path" : os.path.join("$(MODULE_BUILD_DIR)", MakefileName),\r
1117 "platform_name" : self.PlatformInfo.Name,\r
1118 "platform_guid" : self.PlatformInfo.Guid,\r
1119 "platform_version" : self.PlatformInfo.Version,\r
1120 "platform_relative_directory": self.PlatformInfo.SourceDir,\r
1121 "platform_output_directory" : self.PlatformInfo.OutputDir,\r
1122\r
1123 "module_name" : self._AutoGenObject.Name,\r
1124 "module_guid" : self._AutoGenObject.Guid,\r
867d1cd4 1125 "module_name_guid" : self._AutoGenObject._GetUniqueBaseName(),\r
f51461c8
LG
1126 "module_version" : self._AutoGenObject.Version,\r
1127 "module_type" : self._AutoGenObject.ModuleType,\r
1128 "module_file" : self._AutoGenObject.MetaFile,\r
1129 "module_file_base_name" : self._AutoGenObject.MetaFile.BaseName,\r
1130 "module_relative_directory" : self._AutoGenObject.SourceDir,\r
01e418d6 1131 "module_dir" : mws.join (self._AutoGenObject.WorkspaceDir, self._AutoGenObject.SourceDir),\r
f51461c8
LG
1132\r
1133 "architecture" : self._AutoGenObject.Arch,\r
1134 "toolchain_tag" : self._AutoGenObject.ToolChain,\r
1135 "build_target" : self._AutoGenObject.BuildTarget,\r
1136\r
1137 "platform_build_directory" : self.PlatformInfo.BuildDir,\r
1138 "module_build_directory" : self._AutoGenObject.BuildDir,\r
1139 "module_output_directory" : self._AutoGenObject.OutputDir,\r
1140 "module_debug_directory" : self._AutoGenObject.DebugDir,\r
1141\r
1142 "separator" : Separator,\r
1143 "module_tool_definitions" : ToolsDef,\r
1144\r
1145 "shell_command_code" : self._SHELL_CMD_[self._FileType].keys(),\r
1146 "shell_command" : self._SHELL_CMD_[self._FileType].values(),\r
1147\r
1148 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),\r
1149 "custom_makefile_content" : CustomMakefile\r
1150 }\r
1151\r
1152 return MakefileTemplateDict\r
1153\r
1154 _TemplateDict = property(_CreateTemplateDict)\r
1155\r
1156## PlatformMakefile class\r
1157#\r
1158# This class encapsules makefie and its generation for platform. It uses\r
1159# template to generate the content of makefile. The content of makefile will be\r
1160# got from PlatformAutoGen object.\r
1161#\r
1162class PlatformMakefile(BuildFile):\r
1163 ## template used to generate the makefile for platform\r
1164 _TEMPLATE_ = TemplateString('''\\r
1165${makefile_header}\r
1166\r
1167#\r
1168# Platform Macro Definition\r
1169#\r
1170PLATFORM_NAME = ${platform_name}\r
1171PLATFORM_GUID = ${platform_guid}\r
1172PLATFORM_VERSION = ${platform_version}\r
1173PLATFORM_FILE = ${platform_file}\r
1174PLATFORM_DIR = $(WORKSPACE)${separator}${platform_relative_directory}\r
1175PLATFORM_OUTPUT_DIR = ${platform_output_directory}\r
1176\r
1177#\r
1178# Build Configuration Macro Definition\r
1179#\r
1180TOOLCHAIN = ${toolchain_tag}\r
1181TOOLCHAIN_TAG = ${toolchain_tag}\r
1182TARGET = ${build_target}\r
1183\r
1184#\r
1185# Build Directory Macro Definition\r
1186#\r
1187BUILD_DIR = ${platform_build_directory}\r
1188FV_DIR = ${platform_build_directory}${separator}FV\r
1189\r
1190#\r
1191# Shell Command Macro\r
1192#\r
1193${BEGIN}${shell_command_code} = ${shell_command}\r
1194${END}\r
1195\r
1196MAKE = ${make_path}\r
1197MAKE_FILE = ${makefile_path}\r
1198\r
1199#\r
1200# Default target\r
1201#\r
1202all: init build_libraries build_modules\r
1203\r
1204#\r
1205# Initialization target: print build information and create necessary directories\r
1206#\r
1207init:\r
1208\t-@echo Building ... $(PLATFORM_FILE) [${build_architecture_list}]\r
1209\t${BEGIN}-@${create_directory_command}\r
1210\t${END}\r
1211#\r
1212# library build target\r
1213#\r
1214libraries: init build_libraries\r
1215\r
1216#\r
1217# module build target\r
1218#\r
1219modules: init build_libraries build_modules\r
1220\r
1221#\r
1222# Build all libraries:\r
1223#\r
1224build_libraries:\r
1225${BEGIN}\t@"$(MAKE)" $(MAKE_FLAGS) -f ${library_makefile_list} pbuild\r
1226${END}\t@cd $(BUILD_DIR)\r
1227\r
1228#\r
1229# Build all modules:\r
1230#\r
1231build_modules:\r
1232${BEGIN}\t@"$(MAKE)" $(MAKE_FLAGS) -f ${module_makefile_list} pbuild\r
1233${END}\t@cd $(BUILD_DIR)\r
1234\r
1235#\r
1236# Clean intermediate files\r
1237#\r
1238clean:\r
1239\t${BEGIN}-@${library_build_command} clean\r
1240\t${END}${BEGIN}-@${module_build_command} clean\r
1241\t${END}@cd $(BUILD_DIR)\r
1242\r
1243#\r
1244# Clean all generated files except to makefile\r
1245#\r
1246cleanall:\r
1247${BEGIN}\t${cleanall_command}\r
1248${END}\r
1249\r
1250#\r
1251# Clean all library files\r
1252#\r
1253cleanlib:\r
1254\t${BEGIN}-@${library_build_command} cleanall\r
1255\t${END}@cd $(BUILD_DIR)\n\r
1256''')\r
1257\r
1258 ## Constructor of PlatformMakefile\r
1259 #\r
1260 # @param ModuleAutoGen Object of PlatformAutoGen class\r
1261 #\r
1262 def __init__(self, PlatformAutoGen):\r
1263 BuildFile.__init__(self, PlatformAutoGen)\r
1264 self.ModuleBuildCommandList = []\r
1265 self.ModuleMakefileList = []\r
1266 self.IntermediateDirectoryList = []\r
1267 self.ModuleBuildDirectoryList = []\r
1268 self.LibraryBuildDirectoryList = []\r
03af2753 1269 self.LibraryMakeCommandList = []\r
f51461c8
LG
1270\r
1271 # Compose a dict object containing information used to do replacement in template\r
1272 def _CreateTemplateDict(self):\r
1273 Separator = self._SEP_[self._FileType]\r
1274\r
1275 PlatformInfo = self._AutoGenObject\r
1276 if "MAKE" not in PlatformInfo.ToolDefinition or "PATH" not in PlatformInfo.ToolDefinition["MAKE"]:\r
1277 EdkLogger.error("build", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!",\r
1278 ExtraData="[%s]" % str(self._AutoGenObject))\r
1279\r
1280 self.IntermediateDirectoryList = ["$(BUILD_DIR)"]\r
1281 self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()\r
1282 self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()\r
1283\r
1284 MakefileName = self._FILE_NAME_[self._FileType]\r
1285 LibraryMakefileList = []\r
1286 LibraryMakeCommandList = []\r
1287 for D in self.LibraryBuildDirectoryList:\r
1288 D = self.PlaceMacro(D, {"BUILD_DIR":PlatformInfo.BuildDir})\r
1289 Makefile = os.path.join(D, MakefileName)\r
1290 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}\r
1291 LibraryMakefileList.append(Makefile)\r
1292 LibraryMakeCommandList.append(Command)\r
03af2753 1293 self.LibraryMakeCommandList = LibraryMakeCommandList\r
f51461c8
LG
1294\r
1295 ModuleMakefileList = []\r
1296 ModuleMakeCommandList = []\r
1297 for D in self.ModuleBuildDirectoryList:\r
1298 D = self.PlaceMacro(D, {"BUILD_DIR":PlatformInfo.BuildDir})\r
1299 Makefile = os.path.join(D, MakefileName)\r
1300 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":Makefile}\r
1301 ModuleMakefileList.append(Makefile)\r
1302 ModuleMakeCommandList.append(Command)\r
1303\r
1304 MakefileTemplateDict = {\r
1305 "makefile_header" : self._FILE_HEADER_[self._FileType],\r
1306 "makefile_path" : os.path.join("$(BUILD_DIR)", MakefileName),\r
1307 "make_path" : PlatformInfo.ToolDefinition["MAKE"]["PATH"],\r
1308 "makefile_name" : MakefileName,\r
1309 "platform_name" : PlatformInfo.Name,\r
1310 "platform_guid" : PlatformInfo.Guid,\r
1311 "platform_version" : PlatformInfo.Version,\r
1312 "platform_file" : self._AutoGenObject.MetaFile,\r
1313 "platform_relative_directory": PlatformInfo.SourceDir,\r
1314 "platform_output_directory" : PlatformInfo.OutputDir,\r
1315 "platform_build_directory" : PlatformInfo.BuildDir,\r
1316\r
1317 "toolchain_tag" : PlatformInfo.ToolChain,\r
1318 "build_target" : PlatformInfo.BuildTarget,\r
1319 "shell_command_code" : self._SHELL_CMD_[self._FileType].keys(),\r
1320 "shell_command" : self._SHELL_CMD_[self._FileType].values(),\r
1321 "build_architecture_list" : self._AutoGenObject.Arch,\r
1322 "architecture" : self._AutoGenObject.Arch,\r
1323 "separator" : Separator,\r
1324 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),\r
1325 "cleanall_command" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),\r
1326 "library_makefile_list" : LibraryMakefileList,\r
1327 "module_makefile_list" : ModuleMakefileList,\r
1328 "library_build_command" : LibraryMakeCommandList,\r
1329 "module_build_command" : ModuleMakeCommandList,\r
1330 }\r
1331\r
1332 return MakefileTemplateDict\r
1333\r
1334 ## Get the root directory list for intermediate files of all modules build\r
1335 #\r
1336 # @retval list The list of directory\r
1337 #\r
1338 def GetModuleBuildDirectoryList(self):\r
1339 DirList = []\r
1340 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:\r
97fa0ee9
YL
1341 if not ModuleAutoGen.IsBinaryModule:\r
1342 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))\r
f51461c8
LG
1343 return DirList\r
1344\r
1345 ## Get the root directory list for intermediate files of all libraries build\r
1346 #\r
1347 # @retval list The list of directory\r
1348 #\r
1349 def GetLibraryBuildDirectoryList(self):\r
1350 DirList = []\r
1351 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:\r
97fa0ee9
YL
1352 if not LibraryAutoGen.IsBinaryModule:\r
1353 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))\r
f51461c8
LG
1354 return DirList\r
1355\r
1356 _TemplateDict = property(_CreateTemplateDict)\r
1357\r
1358## TopLevelMakefile class\r
1359#\r
1360# This class encapsules makefie and its generation for entrance makefile. It\r
1361# uses template to generate the content of makefile. The content of makefile\r
1362# will be got from WorkspaceAutoGen object.\r
1363#\r
1364class TopLevelMakefile(BuildFile):\r
1365 ## template used to generate toplevel makefile\r
97fa0ee9 1366 _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
1367\r
1368 ## Constructor of TopLevelMakefile\r
1369 #\r
1370 # @param Workspace Object of WorkspaceAutoGen class\r
1371 #\r
1372 def __init__(self, Workspace):\r
1373 BuildFile.__init__(self, Workspace)\r
1374 self.IntermediateDirectoryList = []\r
1375\r
1376 # Compose a dict object containing information used to do replacement in template\r
1377 def _CreateTemplateDict(self):\r
1378 Separator = self._SEP_[self._FileType]\r
1379\r
1380 # any platform autogen object is ok because we just need common information\r
1381 PlatformInfo = self._AutoGenObject\r
1382\r
1383 if "MAKE" not in PlatformInfo.ToolDefinition or "PATH" not in PlatformInfo.ToolDefinition["MAKE"]:\r
1384 EdkLogger.error("build", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!",\r
1385 ExtraData="[%s]" % str(self._AutoGenObject))\r
1386\r
1387 for Arch in PlatformInfo.ArchList:\r
1388 self.IntermediateDirectoryList.append(Separator.join(["$(BUILD_DIR)", Arch]))\r
1389 self.IntermediateDirectoryList.append("$(FV_DIR)")\r
1390\r
1391 # TRICK: for not generating GenFds call in makefile if no FDF file\r
1392 MacroList = []\r
1393 if PlatformInfo.FdfFile != None and PlatformInfo.FdfFile != "":\r
1394 FdfFileList = [PlatformInfo.FdfFile]\r
1395 # macros passed to GenFds\r
1396 MacroList.append('"%s=%s"' % ("EFI_SOURCE", GlobalData.gEfiSource.replace('\\', '\\\\')))\r
1397 MacroList.append('"%s=%s"' % ("EDK_SOURCE", GlobalData.gEdkSource.replace('\\', '\\\\')))\r
1398 MacroDict = {}\r
1399 MacroDict.update(GlobalData.gGlobalDefines)\r
1400 MacroDict.update(GlobalData.gCommandLineDefines)\r
1401 MacroDict.pop("EFI_SOURCE", "dummy")\r
1402 MacroDict.pop("EDK_SOURCE", "dummy")\r
1403 for MacroName in MacroDict:\r
1404 if MacroDict[MacroName] != "":\r
1405 MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))\r
1406 else:\r
1407 MacroList.append('"%s"' % MacroName)\r
1408 else:\r
1409 FdfFileList = []\r
1410\r
1411 # pass extra common options to external program called in makefile, currently GenFds.exe\r
1412 ExtraOption = ''\r
1413 LogLevel = EdkLogger.GetLevel()\r
1414 if LogLevel == EdkLogger.VERBOSE:\r
1415 ExtraOption += " -v"\r
1416 elif LogLevel <= EdkLogger.DEBUG_9:\r
1417 ExtraOption += " -d %d" % (LogLevel - 1)\r
1418 elif LogLevel == EdkLogger.QUIET:\r
1419 ExtraOption += " -q"\r
1420\r
1421 if GlobalData.gCaseInsensitive:\r
1422 ExtraOption += " -c"\r
1423\r
97fa0ee9
YL
1424 if GlobalData.gIgnoreSource:\r
1425 ExtraOption += " --ignore-sources"\r
1426\r
f51461c8
LG
1427 MakefileName = self._FILE_NAME_[self._FileType]\r
1428 SubBuildCommandList = []\r
1429 for A in PlatformInfo.ArchList:\r
1430 Command = self._MAKE_TEMPLATE_[self._FileType] % {"file":os.path.join("$(BUILD_DIR)", A, MakefileName)}\r
1431 SubBuildCommandList.append(Command)\r
1432\r
1433 MakefileTemplateDict = {\r
1434 "makefile_header" : self._FILE_HEADER_[self._FileType],\r
1435 "makefile_path" : os.path.join("$(BUILD_DIR)", MakefileName),\r
1436 "make_path" : PlatformInfo.ToolDefinition["MAKE"]["PATH"],\r
1437 "platform_name" : PlatformInfo.Name,\r
1438 "platform_guid" : PlatformInfo.Guid,\r
1439 "platform_version" : PlatformInfo.Version,\r
1440 "platform_build_directory" : PlatformInfo.BuildDir,\r
97fa0ee9 1441 "conf_directory" : GlobalData.gConfDirectory,\r
f51461c8
LG
1442\r
1443 "toolchain_tag" : PlatformInfo.ToolChain,\r
1444 "build_target" : PlatformInfo.BuildTarget,\r
1445 "shell_command_code" : self._SHELL_CMD_[self._FileType].keys(),\r
1446 "shell_command" : self._SHELL_CMD_[self._FileType].values(),\r
1447 'arch' : list(PlatformInfo.ArchList),\r
1448 "build_architecture_list" : ','.join(PlatformInfo.ArchList),\r
1449 "separator" : Separator,\r
1450 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),\r
1451 "cleanall_command" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),\r
1452 "sub_build_command" : SubBuildCommandList,\r
1453 "fdf_file" : FdfFileList,\r
1454 "active_platform" : str(PlatformInfo),\r
1455 "fd" : PlatformInfo.FdTargetList,\r
1456 "fv" : PlatformInfo.FvTargetList,\r
1457 "cap" : PlatformInfo.CapTargetList,\r
1458 "extra_options" : ExtraOption,\r
1459 "macro" : MacroList,\r
1460 }\r
1461\r
1462 return MakefileTemplateDict\r
1463\r
1464 ## Get the root directory list for intermediate files of all modules build\r
1465 #\r
1466 # @retval list The list of directory\r
1467 #\r
1468 def GetModuleBuildDirectoryList(self):\r
1469 DirList = []\r
1470 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:\r
97fa0ee9
YL
1471 if not ModuleAutoGen.IsBinaryModule:\r
1472 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))\r
f51461c8
LG
1473 return DirList\r
1474\r
1475 ## Get the root directory list for intermediate files of all libraries build\r
1476 #\r
1477 # @retval list The list of directory\r
1478 #\r
1479 def GetLibraryBuildDirectoryList(self):\r
1480 DirList = []\r
1481 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:\r
97fa0ee9
YL
1482 if not LibraryAutoGen.IsBinaryModule:\r
1483 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))\r
f51461c8
LG
1484 return DirList\r
1485\r
1486 _TemplateDict = property(_CreateTemplateDict)\r
1487\r
1488# This acts like the main() function for the script, unless it is 'import'ed into another script.\r
1489if __name__ == '__main__':\r
1490 pass\r
1491\r