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