]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/AutoGen/GenMake.py
BaseTools: Remove caret in NASM_INC macro
[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
LG
578\r
579 self.ProcessBuildTargetList()\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
789 if self._AutoGenObject.Macros[Macro] and self._AutoGenObject.Macros[Macro] in str:\r
790 str = str.replace(self._AutoGenObject.Macros[Macro], '$(' + Macro + ')')\r
791 return str\r
792\r
725cdb8f
YZ
793 def CommandExceedLimit(self):\r
794 FlagDict = {\r
795 'CC' : { 'Macro' : '$(CC_FLAGS)', 'Value' : False},\r
796 'PP' : { 'Macro' : '$(PP_FLAGS)', 'Value' : False},\r
797 'APP' : { 'Macro' : '$(APP_FLAGS)', 'Value' : False},\r
798 'ASLPP' : { 'Macro' : '$(ASLPP_FLAGS)', 'Value' : False},\r
799 'VFRPP' : { 'Macro' : '$(VFRPP_FLAGS)', 'Value' : False},\r
800 'ASM' : { 'Macro' : '$(ASM_FLAGS)', 'Value' : False},\r
801 'ASLCC' : { 'Macro' : '$(ASLCC_FLAGS)', 'Value' : False},\r
802 }\r
803\r
804 RespDict = {}\r
805 FileTypeList = []\r
806 IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily]\r
807\r
808 # base on the source files to decide the file type\r
809 for File in self._AutoGenObject.SourceFileList:\r
810 for type in self._AutoGenObject.FileTypes:\r
811 if File in self._AutoGenObject.FileTypes[type]:\r
812 if type not in FileTypeList:\r
813 FileTypeList.append(type)\r
814\r
815 # calculate the command-line length\r
816 if FileTypeList:\r
817 for type in FileTypeList:\r
818 BuildTargets = self._AutoGenObject.BuildRules[type].BuildTargets\r
819 for Target in BuildTargets:\r
820 CommandList = BuildTargets[Target].Commands\r
821 for SingleCommand in CommandList:\r
822 Tool = ''\r
823 SingleCommandLength = len(SingleCommand)\r
824 SingleCommandList = SingleCommand.split()\r
825 if len(SingleCommandList) > 0:\r
9eb87141 826 for Flag in FlagDict:\r
725cdb8f
YZ
827 if '$('+ Flag +')' in SingleCommandList[0]:\r
828 Tool = Flag\r
829 break\r
830 if Tool:\r
b23414f6 831 if 'PATH' not in self._AutoGenObject.BuildOption[Tool]:\r
70d0a754 832 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 833 SingleCommandLength += len(self._AutoGenObject.BuildOption[Tool]['PATH'])\r
725cdb8f
YZ
834 for item in SingleCommandList[1:]:\r
835 if FlagDict[Tool]['Macro'] in item:\r
b23414f6 836 if 'FLAGS' not in self._AutoGenObject.BuildOption[Tool]:\r
70d0a754 837 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 838 Str = self._AutoGenObject.BuildOption[Tool]['FLAGS']\r
9eb87141 839 for Option in self._AutoGenObject.BuildOption:\r
3570e332
YZ
840 for Attr in self._AutoGenObject.BuildOption[Option]:\r
841 if Str.find(Option + '_' + Attr) != -1:\r
842 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])\r
725cdb8f 843 while(Str.find('$(') != -1):\r
9eb87141 844 for macro in self._AutoGenObject.Macros:\r
725cdb8f
YZ
845 MacroName = '$('+ macro + ')'\r
846 if (Str.find(MacroName) != -1):\r
847 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])\r
848 break\r
849 else:\r
3570e332 850 break\r
725cdb8f
YZ
851 SingleCommandLength += len(Str)\r
852 elif '$(INC)' in item:\r
b23414f6 853 SingleCommandLength += self._AutoGenObject.IncludePathLength + len(IncPrefix) * len(self._AutoGenObject.IncludePathList)\r
725cdb8f
YZ
854 elif item.find('$(') != -1:\r
855 Str = item\r
9eb87141 856 for Option in self._AutoGenObject.BuildOption:\r
725cdb8f
YZ
857 for Attr in self._AutoGenObject.BuildOption[Option]:\r
858 if Str.find(Option + '_' + Attr) != -1:\r
859 Str = Str.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])\r
860 while(Str.find('$(') != -1):\r
9eb87141 861 for macro in self._AutoGenObject.Macros:\r
725cdb8f
YZ
862 MacroName = '$('+ macro + ')'\r
863 if (Str.find(MacroName) != -1):\r
864 Str = Str.replace(MacroName, self._AutoGenObject.Macros[macro])\r
865 break\r
866 else:\r
3570e332 867 break\r
725cdb8f
YZ
868 SingleCommandLength += len(Str)\r
869\r
870 if SingleCommandLength > GlobalData.gCommandMaxLength:\r
871 FlagDict[Tool]['Value'] = True\r
872\r
873 # generate the response file content by combine the FLAGS and INC\r
9eb87141 874 for Flag in FlagDict:\r
725cdb8f
YZ
875 if FlagDict[Flag]['Value']:\r
876 Key = Flag + '_RESP'\r
877 RespMacro = FlagDict[Flag]['Macro'].replace('FLAGS', 'RESP')\r
878 Value = self._AutoGenObject.BuildOption[Flag]['FLAGS']\r
b23414f6 879 for inc in self._AutoGenObject.IncludePathList:\r
725cdb8f 880 Value += ' ' + IncPrefix + inc\r
9eb87141 881 for Option in self._AutoGenObject.BuildOption:\r
3570e332
YZ
882 for Attr in self._AutoGenObject.BuildOption[Option]:\r
883 if Value.find(Option + '_' + Attr) != -1:\r
884 Value = Value.replace('$(' + Option + '_' + Attr + ')', self._AutoGenObject.BuildOption[Option][Attr])\r
725cdb8f 885 while (Value.find('$(') != -1):\r
9eb87141 886 for macro in self._AutoGenObject.Macros:\r
725cdb8f
YZ
887 MacroName = '$('+ macro + ')'\r
888 if (Value.find(MacroName) != -1):\r
889 Value = Value.replace(MacroName, self._AutoGenObject.Macros[macro])\r
890 break\r
891 else:\r
3570e332 892 break\r
669b6cc6
YZ
893\r
894 if self._AutoGenObject.ToolChainFamily == 'GCC':\r
895 RespDict[Key] = Value.replace('\\', '/')\r
896 else:\r
897 RespDict[Key] = Value\r
725cdb8f
YZ
898 for Target in BuildTargets:\r
899 for i, SingleCommand in enumerate(BuildTargets[Target].Commands):\r
900 if FlagDict[Flag]['Macro'] in SingleCommand:\r
ccaa7754 901 BuildTargets[Target].Commands[i] = SingleCommand.replace('$(INC)', '').replace(FlagDict[Flag]['Macro'], RespMacro)\r
725cdb8f
YZ
902 return RespDict\r
903\r
f51461c8
LG
904 def ProcessBuildTargetList(self):\r
905 #\r
906 # Search dependency file list for each source file\r
907 #\r
908 ForceIncludedFile = []\r
909 for File in self._AutoGenObject.AutoGenFileList:\r
910 if File.Ext == '.h':\r
911 ForceIncludedFile.append(File)\r
912 SourceFileList = []\r
a3a47370 913 OutPutFileList = []\r
f51461c8
LG
914 for Target in self._AutoGenObject.IntroTargetList:\r
915 SourceFileList.extend(Target.Inputs)\r
a3a47370
YZ
916 OutPutFileList.extend(Target.Outputs)\r
917\r
918 if OutPutFileList:\r
919 for Item in OutPutFileList:\r
920 if Item in SourceFileList:\r
921 SourceFileList.remove(Item)\r
f51461c8 922\r
0c3e8e99 923 FileDependencyDict = {item:ForceIncludedFile for item in SourceFileList}\r
4747b92c 924\r
0c3e8e99
BF
925 for Dependency in FileDependencyDict.values():\r
926 self.DependencyHeaderFileSet.update(set(Dependency))\r
0e7e7a26 927\r
82407bd1
RC
928 # Get a set of unique package includes from MetaFile\r
929 parentMetaFileIncludes = set()\r
930 for aInclude in self._AutoGenObject.PackageIncludePathList:\r
931 aIncludeName = str(aInclude)\r
932 parentMetaFileIncludes.add(aIncludeName.lower())\r
933\r
1fa6699e 934 # Check if header files are listed in metafile\r
82407bd1 935 # Get a set of unique module header source files from MetaFile\r
1fa6699e
RC
936 headerFilesInMetaFileSet = set()\r
937 for aFile in self._AutoGenObject.SourceFileList:\r
938 aFileName = str(aFile)\r
939 if not aFileName.endswith('.h'):\r
940 continue\r
941 headerFilesInMetaFileSet.add(aFileName.lower())\r
942\r
82407bd1 943 # Get a set of unique module autogen files\r
1fa6699e
RC
944 localAutoGenFileSet = set()\r
945 for aFile in self._AutoGenObject.AutoGenFileList:\r
946 localAutoGenFileSet.add(str(aFile).lower())\r
947\r
82407bd1 948 # Get a set of unique module dependency header files\r
1fa6699e 949 # Exclude autogen files and files not in the source directory\r
82407bd1 950 # and files that are under the package include list\r
1fa6699e
RC
951 headerFileDependencySet = set()\r
952 localSourceDir = str(self._AutoGenObject.SourceDir).lower()\r
953 for Dependency in FileDependencyDict.values():\r
954 for aFile in Dependency:\r
955 aFileName = str(aFile).lower()\r
82407bd1 956 # Exclude non-header files\r
1fa6699e
RC
957 if not aFileName.endswith('.h'):\r
958 continue\r
82407bd1 959 # Exclude autogen files\r
1fa6699e
RC
960 if aFileName in localAutoGenFileSet:\r
961 continue\r
82407bd1 962 # Exclude include out of local scope\r
1fa6699e
RC
963 if localSourceDir not in aFileName:\r
964 continue\r
82407bd1
RC
965 # Exclude files covered by package includes\r
966 pathNeeded = True\r
967 for aIncludePath in parentMetaFileIncludes:\r
968 if aIncludePath in aFileName:\r
969 pathNeeded = False\r
970 break\r
971 if not pathNeeded:\r
972 continue\r
973 # Keep the file to be checked\r
1fa6699e
RC
974 headerFileDependencySet.add(aFileName)\r
975\r
976 # Check if a module dependency header file is missing from the module's MetaFile\r
977 for aFile in headerFileDependencySet:\r
978 if aFile in headerFilesInMetaFileSet:\r
979 continue\r
48b0bf64 980 if GlobalData.gUseHashCache:\r
c340c5bd 981 GlobalData.gModuleBuildTracking[self._AutoGenObject] = 'FAIL_METAFILE'\r
1fa6699e
RC
982 EdkLogger.warn("build","Module MetaFile [Sources] is missing local header!",\r
983 ExtraData = "Local Header: " + aFile + " not found in " + self._AutoGenObject.MetaFile.Path\r
984 )\r
985\r
0f78fd73
JC
986 for File,Dependency in FileDependencyDict.items():\r
987 if not Dependency:\r
f51461c8 988 continue\r
c17956e0 989\r
0f78fd73 990 self._AutoGenObject.AutoGenDepSet |= set(Dependency)\r
c17956e0 991\r
05217d21
FZ
992 CmdSumDict = {}\r
993 CmdTargetDict = {}\r
994 CmdCppDict = {}\r
995 DependencyDict = FileDependencyDict.copy()\r
f51461c8
LG
996\r
997 # Convert target description object to target string in makefile\r
35c2af00
FZ
998 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and TAB_C_CODE_FILE in self._AutoGenObject.Targets:\r
999 for T in self._AutoGenObject.Targets[TAB_C_CODE_FILE]:\r
1000 NewFile = self.PlaceMacro(str(T), self.Macros)\r
1001 if not self.ObjTargetDict.get(T.Target.SubDir):\r
1002 self.ObjTargetDict[T.Target.SubDir] = set()\r
1003 self.ObjTargetDict[T.Target.SubDir].add(NewFile)\r
f51461c8 1004 for Type in self._AutoGenObject.Targets:\r
1ccc4d89 1005 for T in self._AutoGenObject.Targets[Type]:\r
f51461c8
LG
1006 # Generate related macros if needed\r
1007 if T.GenFileListMacro and T.FileListMacro not in self.FileListMacros:\r
1008 self.FileListMacros[T.FileListMacro] = []\r
1009 if T.GenListFile and T.ListFileMacro not in self.ListFileMacros:\r
1010 self.ListFileMacros[T.ListFileMacro] = []\r
1011 if T.GenIncListFile and T.IncListFileMacro not in self.ListFileMacros:\r
1012 self.ListFileMacros[T.IncListFileMacro] = []\r
1013\r
1014 Deps = []\r
05217d21 1015 CCodeDeps = []\r
f51461c8
LG
1016 # Add force-dependencies\r
1017 for Dep in T.Dependencies:\r
1018 Deps.append(self.PlaceMacro(str(Dep), self.Macros))\r
05217d21
FZ
1019 if Dep != '$(MAKE_FILE)':\r
1020 CCodeDeps.append(self.PlaceMacro(str(Dep), self.Macros))\r
f51461c8 1021 # Add inclusion-dependencies\r
0f78fd73
JC
1022 if len(T.Inputs) == 1 and T.Inputs[0] in FileDependencyDict:\r
1023 for F in FileDependencyDict[T.Inputs[0]]:\r
f51461c8
LG
1024 Deps.append(self.PlaceMacro(str(F), self.Macros))\r
1025 # Add source-dependencies\r
1026 for F in T.Inputs:\r
1027 NewFile = self.PlaceMacro(str(F), self.Macros)\r
1028 # In order to use file list macro as dependency\r
1029 if T.GenListFile:\r
fb0b35e0 1030 # gnu tools need forward slash path separator, even on Windows\r
285a1754 1031 self.ListFileMacros[T.ListFileMacro].append(str(F).replace ('\\', '/'))\r
f51461c8
LG
1032 self.FileListMacros[T.FileListMacro].append(NewFile)\r
1033 elif T.GenFileListMacro:\r
1034 self.FileListMacros[T.FileListMacro].append(NewFile)\r
1035 else:\r
1036 Deps.append(NewFile)\r
959791dd
FB
1037 for key in self.FileListMacros:\r
1038 self.FileListMacros[key].sort()\r
f51461c8
LG
1039 # Use file list macro as dependency\r
1040 if T.GenFileListMacro:\r
1041 Deps.append("$(%s)" % T.FileListMacro)\r
1c62af9e
YZ
1042 if Type in [TAB_OBJECT_FILE, TAB_STATIC_LIBRARY]:\r
1043 Deps.append("$(%s)" % T.ListFileMacro)\r
f51461c8 1044\r
05217d21
FZ
1045 if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Type == TAB_C_CODE_FILE:\r
1046 T, CmdTarget, CmdTargetDict, CmdCppDict = self.ParserCCodeFile(T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict)\r
1047 TargetDict = {"target": self.PlaceMacro(T.Target.Path, self.Macros), "cmd": "\n\t".join(T.Commands),"deps": CCodeDeps}\r
1048 CmdLine = self._BUILD_TARGET_TEMPLATE.Replace(TargetDict).rstrip().replace('\t$(OBJLIST', '$(OBJLIST')\r
1049 if T.Commands:\r
1050 CmdLine = '%s%s' %(CmdLine, TAB_LINE_BREAK)\r
1051 if CCodeDeps or CmdLine:\r
1052 self.BuildTargetList.append(CmdLine)\r
1053 else:\r
1054 TargetDict = {"target": self.PlaceMacro(T.Target.Path, self.Macros), "cmd": "\n\t".join(T.Commands),"deps": Deps}\r
1055 self.BuildTargetList.append(self._BUILD_TARGET_TEMPLATE.Replace(TargetDict))\r
1056\r
1057 def ParserCCodeFile(self, T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, DependencyDict):\r
1058 if not CmdSumDict:\r
1059 for item in self._AutoGenObject.Targets[Type]:\r
1060 CmdSumDict[item.Target.SubDir] = item.Target.BaseName\r
1061 for CppPath in item.Inputs:\r
1062 Path = self.PlaceMacro(CppPath.Path, self.Macros)\r
1063 if CmdCppDict.get(item.Target.SubDir):\r
1064 CmdCppDict[item.Target.SubDir].append(Path)\r
1065 else:\r
1066 CmdCppDict[item.Target.SubDir] = ['$(MAKE_FILE)', Path]\r
1067 if CppPath.Path in DependencyDict:\r
0c3e8e99
BF
1068 for Temp in DependencyDict[CppPath.Path]:\r
1069 try:\r
1070 Path = self.PlaceMacro(Temp.Path, self.Macros)\r
1071 except:\r
1072 continue\r
1073 if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):\r
1074 CmdCppDict[item.Target.SubDir].append(Path)\r
05217d21
FZ
1075 if T.Commands:\r
1076 CommandList = T.Commands[:]\r
1077 for Item in CommandList[:]:\r
1078 SingleCommandList = Item.split()\r
c9b3fe15 1079 if len(SingleCommandList) > 0 and self.CheckCCCmd(SingleCommandList):\r
05217d21
FZ
1080 for Temp in SingleCommandList:\r
1081 if Temp.startswith('/Fo'):\r
1082 CmdSign = '%s%s' % (Temp.rsplit(TAB_SLASH, 1)[0], TAB_SLASH)\r
1083 break\r
1084 else: continue\r
1085 if CmdSign not in list(CmdTargetDict.keys()):\r
1086 CmdTargetDict[CmdSign] = Item.replace(Temp, CmdSign)\r
1087 else:\r
1088 CmdTargetDict[CmdSign] = "%s %s" % (CmdTargetDict[CmdSign], SingleCommandList[-1])\r
1089 Index = CommandList.index(Item)\r
1090 CommandList.pop(Index)\r
bb824f68 1091 if SingleCommandList[-1].endswith("%s%s.c" % (TAB_SLASH, CmdSumDict[CmdSign[3:].rsplit(TAB_SLASH, 1)[0]])):\r
05217d21 1092 Cpplist = CmdCppDict[T.Target.SubDir]\r
0c3e8e99 1093 Cpplist.insert(0, '$(OBJLIST_%d): ' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir))\r
05217d21
FZ
1094 T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign])\r
1095 else:\r
1096 T.Commands.pop(Index)\r
1097 return T, CmdSumDict, CmdTargetDict, CmdCppDict\r
f51461c8 1098\r
c9b3fe15
BF
1099 def CheckCCCmd(self, CommandList):\r
1100 for cmd in CommandList:\r
1101 if '$(CC)' in cmd:\r
1102 return True\r
1103 return False\r
f51461c8
LG
1104 ## For creating makefile targets for dependent libraries\r
1105 def ProcessDependentLibrary(self):\r
1106 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:\r
0e7e7a26 1107 if not LibraryAutoGen.IsBinaryModule:\r
8832c79d 1108 self.LibraryBuildDirectoryList.append(self.PlaceMacro(LibraryAutoGen.BuildDir, self.Macros))\r
f51461c8
LG
1109\r
1110 ## Return a list containing source file's dependencies\r
1111 #\r
1112 # @param FileList The list of source files\r
1113 # @param ForceInculeList The list of files which will be included forcely\r
1114 # @param SearchPathList The list of search path\r
1115 #\r
1116 # @retval dict The mapping between source file path and its dependencies\r
1117 #\r
1118 def GetFileDependency(self, FileList, ForceInculeList, SearchPathList):\r
1119 Dependency = {}\r
1120 for F in FileList:\r
0e7e7a26 1121 Dependency[F] = GetDependencyList(self._AutoGenObject, self.FileCache, F, ForceInculeList, SearchPathList)\r
f51461c8
LG
1122 return Dependency\r
1123\r
f51461c8 1124\r
f51461c8
LG
1125## CustomMakefile class\r
1126#\r
1127# This class encapsules makefie and its generation for module. It uses template to generate\r
1128# the content of makefile. The content of makefile will be got from ModuleAutoGen object.\r
1129#\r
1130class CustomMakefile(BuildFile):\r
1131 ## template used to generate the makefile for module with custom makefile\r
1132 _TEMPLATE_ = TemplateString('''\\r
1133${makefile_header}\r
1134\r
1135#\r
1136# Platform Macro Definition\r
1137#\r
1138PLATFORM_NAME = ${platform_name}\r
1139PLATFORM_GUID = ${platform_guid}\r
1140PLATFORM_VERSION = ${platform_version}\r
1141PLATFORM_RELATIVE_DIR = ${platform_relative_directory}\r
7a5f1426 1142PLATFORM_DIR = ${platform_dir}\r
f51461c8
LG
1143PLATFORM_OUTPUT_DIR = ${platform_output_directory}\r
1144\r
1145#\r
1146# Module Macro Definition\r
1147#\r
1148MODULE_NAME = ${module_name}\r
1149MODULE_GUID = ${module_guid}\r
867d1cd4 1150MODULE_NAME_GUID = ${module_name_guid}\r
f51461c8
LG
1151MODULE_VERSION = ${module_version}\r
1152MODULE_TYPE = ${module_type}\r
1153MODULE_FILE = ${module_file}\r
1154MODULE_FILE_BASE_NAME = ${module_file_base_name}\r
1155BASE_NAME = $(MODULE_NAME)\r
1156MODULE_RELATIVE_DIR = ${module_relative_directory}\r
01e418d6 1157MODULE_DIR = ${module_dir}\r
f51461c8
LG
1158\r
1159#\r
1160# Build Configuration Macro Definition\r
1161#\r
1162ARCH = ${architecture}\r
1163TOOLCHAIN = ${toolchain_tag}\r
1164TOOLCHAIN_TAG = ${toolchain_tag}\r
1165TARGET = ${build_target}\r
1166\r
1167#\r
1168# Build Directory Macro Definition\r
1169#\r
1170# PLATFORM_BUILD_DIR = ${platform_build_directory}\r
1171BUILD_DIR = ${platform_build_directory}\r
1172BIN_DIR = $(BUILD_DIR)${separator}${architecture}\r
1173LIB_DIR = $(BIN_DIR)\r
1174MODULE_BUILD_DIR = ${module_build_directory}\r
1175OUTPUT_DIR = ${module_output_directory}\r
1176DEBUG_DIR = ${module_debug_directory}\r
1177DEST_DIR_OUTPUT = $(OUTPUT_DIR)\r
1178DEST_DIR_DEBUG = $(DEBUG_DIR)\r
1179\r
1180#\r
1181# Tools definitions specific to this module\r
1182#\r
1183${BEGIN}${module_tool_definitions}\r
1184${END}\r
1185MAKE_FILE = ${makefile_path}\r
1186\r
1187#\r
1188# Shell Command Macro\r
1189#\r
1190${BEGIN}${shell_command_code} = ${shell_command}\r
1191${END}\r
1192\r
1193${custom_makefile_content}\r
1194\r
1195#\r
1196# Target used when called from platform makefile, which will bypass the build of dependent libraries\r
1197#\r
1198\r
1199pbuild: init all\r
1200\r
1201\r
1202#\r
1203# ModuleTarget\r
1204#\r
1205\r
1206mbuild: init all\r
1207\r
1208#\r
1209# Build Target used in multi-thread build mode, which no init target is needed\r
1210#\r
1211\r
1212tbuild: all\r
1213\r
1214#\r
1215# Initialization target: print build information and create necessary directories\r
1216#\r
1217init:\r
1218\t-@echo Building ... $(MODULE_DIR)${separator}$(MODULE_FILE) [$(ARCH)]\r
1219${BEGIN}\t-@${create_directory_command}\n${END}\\r
1220\r
1221''')\r
1222\r
1223 ## Constructor of CustomMakefile\r
1224 #\r
1225 # @param ModuleAutoGen Object of ModuleAutoGen class\r
1226 #\r
1227 def __init__(self, ModuleAutoGen):\r
1228 BuildFile.__init__(self, ModuleAutoGen)\r
1229 self.PlatformInfo = self._AutoGenObject.PlatformInfo\r
1230 self.IntermediateDirectoryList = ["$(DEBUG_DIR)", "$(OUTPUT_DIR)"]\r
4747b92c 1231 self.DependencyHeaderFileSet = set()\r
f51461c8
LG
1232\r
1233 # Compose a dict object containing information used to do replacement in template\r
4c92c81d
CJ
1234 @property\r
1235 def _TemplateDict(self):\r
818283de 1236 Separator = self._SEP_[self._Platform]\r
7c12d613
JC
1237 MyAgo = self._AutoGenObject\r
1238 if self._FileType not in MyAgo.CustomMakefile:\r
f51461c8 1239 EdkLogger.error('build', OPTION_NOT_SUPPORTED, "No custom makefile for %s" % self._FileType,\r
7c12d613 1240 ExtraData="[%s]" % str(MyAgo))\r
01e418d6 1241 MakefilePath = mws.join(\r
7c12d613
JC
1242 MyAgo.WorkspaceDir,\r
1243 MyAgo.CustomMakefile[self._FileType]\r
f51461c8
LG
1244 )\r
1245 try:\r
1246 CustomMakefile = open(MakefilePath, 'r').read()\r
1247 except:\r
7c12d613
JC
1248 EdkLogger.error('build', FILE_OPEN_FAILURE, File=str(MyAgo),\r
1249 ExtraData=MyAgo.CustomMakefile[self._FileType])\r
f51461c8
LG
1250\r
1251 # tools definitions\r
1252 ToolsDef = []\r
7c12d613 1253 for Tool in MyAgo.BuildOption:\r
f51461c8
LG
1254 # Don't generate MAKE_FLAGS in makefile. It's put in environment variable.\r
1255 if Tool == "MAKE":\r
1256 continue\r
7c12d613 1257 for Attr in MyAgo.BuildOption[Tool]:\r
f51461c8
LG
1258 if Attr == "FAMILY":\r
1259 continue\r
1260 elif Attr == "PATH":\r
7c12d613 1261 ToolsDef.append("%s = %s" % (Tool, MyAgo.BuildOption[Tool][Attr]))\r
f51461c8 1262 else:\r
7c12d613 1263 ToolsDef.append("%s_%s = %s" % (Tool, Attr, MyAgo.BuildOption[Tool][Attr]))\r
f51461c8
LG
1264 ToolsDef.append("")\r
1265\r
818283de 1266 MakefileName = self.getMakefileName()\r
f51461c8
LG
1267 MakefileTemplateDict = {\r
1268 "makefile_header" : self._FILE_HEADER_[self._FileType],\r
1269 "makefile_path" : os.path.join("$(MODULE_BUILD_DIR)", MakefileName),\r
1270 "platform_name" : self.PlatformInfo.Name,\r
1271 "platform_guid" : self.PlatformInfo.Guid,\r
1272 "platform_version" : self.PlatformInfo.Version,\r
1273 "platform_relative_directory": self.PlatformInfo.SourceDir,\r
1274 "platform_output_directory" : self.PlatformInfo.OutputDir,\r
7c12d613
JC
1275 "platform_dir" : MyAgo.Macros["PLATFORM_DIR"],\r
1276\r
1277 "module_name" : MyAgo.Name,\r
1278 "module_guid" : MyAgo.Guid,\r
1279 "module_name_guid" : MyAgo.UniqueBaseName,\r
1280 "module_version" : MyAgo.Version,\r
1281 "module_type" : MyAgo.ModuleType,\r
1282 "module_file" : MyAgo.MetaFile,\r
1283 "module_file_base_name" : MyAgo.MetaFile.BaseName,\r
1284 "module_relative_directory" : MyAgo.SourceDir,\r
1285 "module_dir" : mws.join (MyAgo.WorkspaceDir, MyAgo.SourceDir),\r
1286\r
1287 "architecture" : MyAgo.Arch,\r
1288 "toolchain_tag" : MyAgo.ToolChain,\r
1289 "build_target" : MyAgo.BuildTarget,\r
f51461c8
LG
1290\r
1291 "platform_build_directory" : self.PlatformInfo.BuildDir,\r
7c12d613
JC
1292 "module_build_directory" : MyAgo.BuildDir,\r
1293 "module_output_directory" : MyAgo.OutputDir,\r
1294 "module_debug_directory" : MyAgo.DebugDir,\r
f51461c8
LG
1295\r
1296 "separator" : Separator,\r
1297 "module_tool_definitions" : ToolsDef,\r
1298\r
818283de
PG
1299 "shell_command_code" : list(self._SHELL_CMD_[self._Platform].keys()),\r
1300 "shell_command" : list(self._SHELL_CMD_[self._Platform].values()),\r
f51461c8
LG
1301\r
1302 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),\r
1303 "custom_makefile_content" : CustomMakefile\r
1304 }\r
1305\r
1306 return MakefileTemplateDict\r
1307\r
f51461c8
LG
1308## PlatformMakefile class\r
1309#\r
1310# This class encapsules makefie and its generation for platform. It uses\r
1311# template to generate the content of makefile. The content of makefile will be\r
1312# got from PlatformAutoGen object.\r
1313#\r
1314class PlatformMakefile(BuildFile):\r
1315 ## template used to generate the makefile for platform\r
1316 _TEMPLATE_ = TemplateString('''\\r
1317${makefile_header}\r
1318\r
1319#\r
1320# Platform Macro Definition\r
1321#\r
1322PLATFORM_NAME = ${platform_name}\r
1323PLATFORM_GUID = ${platform_guid}\r
1324PLATFORM_VERSION = ${platform_version}\r
1325PLATFORM_FILE = ${platform_file}\r
7a5f1426 1326PLATFORM_DIR = ${platform_dir}\r
f51461c8
LG
1327PLATFORM_OUTPUT_DIR = ${platform_output_directory}\r
1328\r
1329#\r
1330# Build Configuration Macro Definition\r
1331#\r
1332TOOLCHAIN = ${toolchain_tag}\r
1333TOOLCHAIN_TAG = ${toolchain_tag}\r
1334TARGET = ${build_target}\r
1335\r
1336#\r
1337# Build Directory Macro Definition\r
1338#\r
1339BUILD_DIR = ${platform_build_directory}\r
1340FV_DIR = ${platform_build_directory}${separator}FV\r
1341\r
1342#\r
1343# Shell Command Macro\r
1344#\r
1345${BEGIN}${shell_command_code} = ${shell_command}\r
1346${END}\r
1347\r
1348MAKE = ${make_path}\r
1349MAKE_FILE = ${makefile_path}\r
1350\r
1351#\r
1352# Default target\r
1353#\r
1354all: init build_libraries build_modules\r
1355\r
1356#\r
1357# Initialization target: print build information and create necessary directories\r
1358#\r
1359init:\r
1360\t-@echo Building ... $(PLATFORM_FILE) [${build_architecture_list}]\r
1361\t${BEGIN}-@${create_directory_command}\r
1362\t${END}\r
1363#\r
1364# library build target\r
1365#\r
1366libraries: init build_libraries\r
1367\r
1368#\r
1369# module build target\r
1370#\r
1371modules: init build_libraries build_modules\r
1372\r
1373#\r
1374# Build all libraries:\r
1375#\r
1376build_libraries:\r
1377${BEGIN}\t@"$(MAKE)" $(MAKE_FLAGS) -f ${library_makefile_list} pbuild\r
1378${END}\t@cd $(BUILD_DIR)\r
1379\r
1380#\r
1381# Build all modules:\r
1382#\r
1383build_modules:\r
1384${BEGIN}\t@"$(MAKE)" $(MAKE_FLAGS) -f ${module_makefile_list} pbuild\r
1385${END}\t@cd $(BUILD_DIR)\r
1386\r
1387#\r
1388# Clean intermediate files\r
1389#\r
1390clean:\r
1391\t${BEGIN}-@${library_build_command} clean\r
1392\t${END}${BEGIN}-@${module_build_command} clean\r
1393\t${END}@cd $(BUILD_DIR)\r
1394\r
1395#\r
1396# Clean all generated files except to makefile\r
1397#\r
1398cleanall:\r
1399${BEGIN}\t${cleanall_command}\r
1400${END}\r
1401\r
1402#\r
1403# Clean all library files\r
1404#\r
1405cleanlib:\r
1406\t${BEGIN}-@${library_build_command} cleanall\r
1407\t${END}@cd $(BUILD_DIR)\n\r
1408''')\r
1409\r
1410 ## Constructor of PlatformMakefile\r
1411 #\r
1412 # @param ModuleAutoGen Object of PlatformAutoGen class\r
1413 #\r
1414 def __init__(self, PlatformAutoGen):\r
1415 BuildFile.__init__(self, PlatformAutoGen)\r
1416 self.ModuleBuildCommandList = []\r
1417 self.ModuleMakefileList = []\r
1418 self.IntermediateDirectoryList = []\r
1419 self.ModuleBuildDirectoryList = []\r
1420 self.LibraryBuildDirectoryList = []\r
03af2753 1421 self.LibraryMakeCommandList = []\r
4747b92c 1422 self.DependencyHeaderFileSet = set()\r
f51461c8
LG
1423\r
1424 # Compose a dict object containing information used to do replacement in template\r
4c92c81d
CJ
1425 @property\r
1426 def _TemplateDict(self):\r
818283de 1427 Separator = self._SEP_[self._Platform]\r
f51461c8 1428\r
7c12d613
JC
1429 MyAgo = self._AutoGenObject\r
1430 if "MAKE" not in MyAgo.ToolDefinition or "PATH" not in MyAgo.ToolDefinition["MAKE"]:\r
f51461c8 1431 EdkLogger.error("build", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!",\r
7c12d613 1432 ExtraData="[%s]" % str(MyAgo))\r
f51461c8
LG
1433\r
1434 self.IntermediateDirectoryList = ["$(BUILD_DIR)"]\r
1435 self.ModuleBuildDirectoryList = self.GetModuleBuildDirectoryList()\r
1436 self.LibraryBuildDirectoryList = self.GetLibraryBuildDirectoryList()\r
1437\r
818283de 1438 MakefileName = self.getMakefileName()\r
f51461c8
LG
1439 LibraryMakefileList = []\r
1440 LibraryMakeCommandList = []\r
1441 for D in self.LibraryBuildDirectoryList:\r
7c12d613 1442 D = self.PlaceMacro(D, {"BUILD_DIR":MyAgo.BuildDir})\r
f51461c8 1443 Makefile = os.path.join(D, MakefileName)\r
818283de 1444 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":Makefile}\r
f51461c8
LG
1445 LibraryMakefileList.append(Makefile)\r
1446 LibraryMakeCommandList.append(Command)\r
03af2753 1447 self.LibraryMakeCommandList = LibraryMakeCommandList\r
f51461c8
LG
1448\r
1449 ModuleMakefileList = []\r
1450 ModuleMakeCommandList = []\r
1451 for D in self.ModuleBuildDirectoryList:\r
7c12d613 1452 D = self.PlaceMacro(D, {"BUILD_DIR":MyAgo.BuildDir})\r
f51461c8 1453 Makefile = os.path.join(D, MakefileName)\r
818283de 1454 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":Makefile}\r
f51461c8
LG
1455 ModuleMakefileList.append(Makefile)\r
1456 ModuleMakeCommandList.append(Command)\r
1457\r
1458 MakefileTemplateDict = {\r
1459 "makefile_header" : self._FILE_HEADER_[self._FileType],\r
1460 "makefile_path" : os.path.join("$(BUILD_DIR)", MakefileName),\r
7c12d613 1461 "make_path" : MyAgo.ToolDefinition["MAKE"]["PATH"],\r
f51461c8 1462 "makefile_name" : MakefileName,\r
7c12d613
JC
1463 "platform_name" : MyAgo.Name,\r
1464 "platform_guid" : MyAgo.Guid,\r
1465 "platform_version" : MyAgo.Version,\r
1466 "platform_file" : MyAgo.MetaFile,\r
1467 "platform_relative_directory": MyAgo.SourceDir,\r
1468 "platform_output_directory" : MyAgo.OutputDir,\r
1469 "platform_build_directory" : MyAgo.BuildDir,\r
1470 "platform_dir" : MyAgo.Macros["PLATFORM_DIR"],\r
1471\r
1472 "toolchain_tag" : MyAgo.ToolChain,\r
1473 "build_target" : MyAgo.BuildTarget,\r
818283de
PG
1474 "shell_command_code" : list(self._SHELL_CMD_[self._Platform].keys()),\r
1475 "shell_command" : list(self._SHELL_CMD_[self._Platform].values()),\r
7c12d613
JC
1476 "build_architecture_list" : MyAgo.Arch,\r
1477 "architecture" : MyAgo.Arch,\r
f51461c8
LG
1478 "separator" : Separator,\r
1479 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),\r
1480 "cleanall_command" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),\r
1481 "library_makefile_list" : LibraryMakefileList,\r
1482 "module_makefile_list" : ModuleMakefileList,\r
1483 "library_build_command" : LibraryMakeCommandList,\r
1484 "module_build_command" : ModuleMakeCommandList,\r
1485 }\r
1486\r
1487 return MakefileTemplateDict\r
1488\r
1489 ## Get the root directory list for intermediate files of all modules build\r
1490 #\r
1491 # @retval list The list of directory\r
1492 #\r
1493 def GetModuleBuildDirectoryList(self):\r
1494 DirList = []\r
1495 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:\r
97fa0ee9
YL
1496 if not ModuleAutoGen.IsBinaryModule:\r
1497 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))\r
f51461c8
LG
1498 return DirList\r
1499\r
1500 ## Get the root directory list for intermediate files of all libraries build\r
1501 #\r
1502 # @retval list The list of directory\r
1503 #\r
1504 def GetLibraryBuildDirectoryList(self):\r
1505 DirList = []\r
1506 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:\r
0e7e7a26 1507 if not LibraryAutoGen.IsBinaryModule:\r
97fa0ee9 1508 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))\r
f51461c8
LG
1509 return DirList\r
1510\r
f51461c8
LG
1511## TopLevelMakefile class\r
1512#\r
1513# This class encapsules makefie and its generation for entrance makefile. It\r
1514# uses template to generate the content of makefile. The content of makefile\r
1515# will be got from WorkspaceAutoGen object.\r
1516#\r
1517class TopLevelMakefile(BuildFile):\r
1518 ## template used to generate toplevel makefile\r
97fa0ee9 1519 _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
1520\r
1521 ## Constructor of TopLevelMakefile\r
1522 #\r
1523 # @param Workspace Object of WorkspaceAutoGen class\r
1524 #\r
1525 def __init__(self, Workspace):\r
1526 BuildFile.__init__(self, Workspace)\r
1527 self.IntermediateDirectoryList = []\r
4747b92c 1528 self.DependencyHeaderFileSet = set()\r
f51461c8
LG
1529\r
1530 # Compose a dict object containing information used to do replacement in template\r
4c92c81d
CJ
1531 @property\r
1532 def _TemplateDict(self):\r
818283de 1533 Separator = self._SEP_[self._Platform]\r
f51461c8
LG
1534\r
1535 # any platform autogen object is ok because we just need common information\r
7c12d613 1536 MyAgo = self._AutoGenObject\r
f51461c8 1537\r
7c12d613 1538 if "MAKE" not in MyAgo.ToolDefinition or "PATH" not in MyAgo.ToolDefinition["MAKE"]:\r
f51461c8 1539 EdkLogger.error("build", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!",\r
7c12d613 1540 ExtraData="[%s]" % str(MyAgo))\r
f51461c8 1541\r
7c12d613 1542 for Arch in MyAgo.ArchList:\r
f51461c8
LG
1543 self.IntermediateDirectoryList.append(Separator.join(["$(BUILD_DIR)", Arch]))\r
1544 self.IntermediateDirectoryList.append("$(FV_DIR)")\r
1545\r
1546 # TRICK: for not generating GenFds call in makefile if no FDF file\r
1547 MacroList = []\r
7c12d613
JC
1548 if MyAgo.FdfFile is not None and MyAgo.FdfFile != "":\r
1549 FdfFileList = [MyAgo.FdfFile]\r
f51461c8 1550 # macros passed to GenFds\r
f51461c8
LG
1551 MacroDict = {}\r
1552 MacroDict.update(GlobalData.gGlobalDefines)\r
1553 MacroDict.update(GlobalData.gCommandLineDefines)\r
f51461c8
LG
1554 for MacroName in MacroDict:\r
1555 if MacroDict[MacroName] != "":\r
1556 MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))\r
1557 else:\r
1558 MacroList.append('"%s"' % MacroName)\r
1559 else:\r
1560 FdfFileList = []\r
1561\r
1562 # pass extra common options to external program called in makefile, currently GenFds.exe\r
1563 ExtraOption = ''\r
1564 LogLevel = EdkLogger.GetLevel()\r
1565 if LogLevel == EdkLogger.VERBOSE:\r
1566 ExtraOption += " -v"\r
1567 elif LogLevel <= EdkLogger.DEBUG_9:\r
1568 ExtraOption += " -d %d" % (LogLevel - 1)\r
1569 elif LogLevel == EdkLogger.QUIET:\r
1570 ExtraOption += " -q"\r
1571\r
1572 if GlobalData.gCaseInsensitive:\r
1573 ExtraOption += " -c"\r
7809492c
FB
1574 if not GlobalData.gEnableGenfdsMultiThread:\r
1575 ExtraOption += " --no-genfds-multi-thread"\r
97fa0ee9
YL
1576 if GlobalData.gIgnoreSource:\r
1577 ExtraOption += " --ignore-sources"\r
1578\r
0f228f19
B
1579 for pcd in GlobalData.BuildOptionPcd:\r
1580 if pcd[2]:\r
1581 pcdname = '.'.join(pcd[0:3])\r
1582 else:\r
1583 pcdname = '.'.join(pcd[0:2])\r
1584 if pcd[3].startswith('{'):\r
1585 ExtraOption += " --pcd " + pcdname + '=' + 'H' + '"' + pcd[3] + '"'\r
1586 else:\r
1587 ExtraOption += " --pcd " + pcdname + '=' + pcd[3]\r
6b17c11b 1588\r
818283de 1589 MakefileName = self.getMakefileName()\r
f51461c8 1590 SubBuildCommandList = []\r
7c12d613 1591 for A in MyAgo.ArchList:\r
818283de 1592 Command = self._MAKE_TEMPLATE_[self._Platform] % {"file":os.path.join("$(BUILD_DIR)", A, MakefileName)}\r
f51461c8
LG
1593 SubBuildCommandList.append(Command)\r
1594\r
1595 MakefileTemplateDict = {\r
1596 "makefile_header" : self._FILE_HEADER_[self._FileType],\r
1597 "makefile_path" : os.path.join("$(BUILD_DIR)", MakefileName),\r
7c12d613
JC
1598 "make_path" : MyAgo.ToolDefinition["MAKE"]["PATH"],\r
1599 "platform_name" : MyAgo.Name,\r
1600 "platform_guid" : MyAgo.Guid,\r
1601 "platform_version" : MyAgo.Version,\r
1602 "platform_build_directory" : MyAgo.BuildDir,\r
97fa0ee9 1603 "conf_directory" : GlobalData.gConfDirectory,\r
f51461c8 1604\r
7c12d613
JC
1605 "toolchain_tag" : MyAgo.ToolChain,\r
1606 "build_target" : MyAgo.BuildTarget,\r
818283de
PG
1607 "shell_command_code" : list(self._SHELL_CMD_[self._Platform].keys()),\r
1608 "shell_command" : list(self._SHELL_CMD_[self._Platform].values()),\r
7c12d613
JC
1609 'arch' : list(MyAgo.ArchList),\r
1610 "build_architecture_list" : ','.join(MyAgo.ArchList),\r
f51461c8
LG
1611 "separator" : Separator,\r
1612 "create_directory_command" : self.GetCreateDirectoryCommand(self.IntermediateDirectoryList),\r
1613 "cleanall_command" : self.GetRemoveDirectoryCommand(self.IntermediateDirectoryList),\r
1614 "sub_build_command" : SubBuildCommandList,\r
1615 "fdf_file" : FdfFileList,\r
7c12d613
JC
1616 "active_platform" : str(MyAgo),\r
1617 "fd" : MyAgo.FdTargetList,\r
1618 "fv" : MyAgo.FvTargetList,\r
1619 "cap" : MyAgo.CapTargetList,\r
f51461c8
LG
1620 "extra_options" : ExtraOption,\r
1621 "macro" : MacroList,\r
1622 }\r
1623\r
1624 return MakefileTemplateDict\r
1625\r
1626 ## Get the root directory list for intermediate files of all modules build\r
1627 #\r
1628 # @retval list The list of directory\r
1629 #\r
1630 def GetModuleBuildDirectoryList(self):\r
1631 DirList = []\r
1632 for ModuleAutoGen in self._AutoGenObject.ModuleAutoGenList:\r
97fa0ee9
YL
1633 if not ModuleAutoGen.IsBinaryModule:\r
1634 DirList.append(os.path.join(self._AutoGenObject.BuildDir, ModuleAutoGen.BuildDir))\r
f51461c8
LG
1635 return DirList\r
1636\r
1637 ## Get the root directory list for intermediate files of all libraries build\r
1638 #\r
1639 # @retval list The list of directory\r
1640 #\r
1641 def GetLibraryBuildDirectoryList(self):\r
1642 DirList = []\r
1643 for LibraryAutoGen in self._AutoGenObject.LibraryAutoGenList:\r
0e7e7a26 1644 if not LibraryAutoGen.IsBinaryModule:\r
97fa0ee9 1645 DirList.append(os.path.join(self._AutoGenObject.BuildDir, LibraryAutoGen.BuildDir))\r
f51461c8
LG
1646 return DirList\r
1647\r
0e7e7a26
SS
1648## Find dependencies for one source file\r
1649#\r
1650# By searching recursively "#include" directive in file, find out all the\r
1651# files needed by given source file. The dependencies will be only searched\r
1652# in given search path list.\r
1653#\r
1654# @param File The source file\r
1655# @param ForceInculeList The list of files which will be included forcely\r
1656# @param SearchPathList The list of search path\r
1657#\r
1658# @retval list The list of files the given source file depends on\r
1659#\r
1660def GetDependencyList(AutoGenObject, FileCache, File, ForceList, SearchPathList):\r
1661 EdkLogger.debug(EdkLogger.DEBUG_1, "Try to get dependency files for %s" % File)\r
1662 FileStack = [File] + ForceList\r
1663 DependencySet = set()\r
1664\r
1665 if AutoGenObject.Arch not in gDependencyDatabase:\r
1666 gDependencyDatabase[AutoGenObject.Arch] = {}\r
1667 DepDb = gDependencyDatabase[AutoGenObject.Arch]\r
1668\r
1669 while len(FileStack) > 0:\r
1670 F = FileStack.pop()\r
1671\r
1672 FullPathDependList = []\r
1673 if F in FileCache:\r
1674 for CacheFile in FileCache[F]:\r
1675 FullPathDependList.append(CacheFile)\r
1676 if CacheFile not in DependencySet:\r
1677 FileStack.append(CacheFile)\r
1678 DependencySet.update(FullPathDependList)\r
1679 continue\r
1680\r
1681 CurrentFileDependencyList = []\r
1682 if F in DepDb:\r
1683 CurrentFileDependencyList = DepDb[F]\r
1684 else:\r
1685 try:\r
fcdedafd
LG
1686 Fd = open(F.Path, 'rb')\r
1687 FileContent = Fd.read()\r
1688 Fd.close()\r
0e7e7a26
SS
1689 except BaseException as X:\r
1690 EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=F.Path + "\n\t" + str(X))\r
fcdedafd
LG
1691 if len(FileContent) == 0:\r
1692 continue\r
1693 try:\r
1694 if FileContent[0] == 0xff or FileContent[0] == 0xfe:\r
1695 FileContent = FileContent.decode('utf-16')\r
1696 else:\r
1697 FileContent = FileContent.decode()\r
1698 except:\r
1699 # The file is not txt file. for example .mcb file\r
0e7e7a26 1700 continue\r
fcdedafd 1701 IncludedFileList = gIncludePattern.findall(FileContent)\r
0e7e7a26
SS
1702\r
1703 for Inc in IncludedFileList:\r
1704 Inc = Inc.strip()\r
1705 # if there's macro used to reference header file, expand it\r
1706 HeaderList = gMacroPattern.findall(Inc)\r
1707 if len(HeaderList) == 1 and len(HeaderList[0]) == 2:\r
1708 HeaderType = HeaderList[0][0]\r
1709 HeaderKey = HeaderList[0][1]\r
1710 if HeaderType in gIncludeMacroConversion:\r
1711 Inc = gIncludeMacroConversion[HeaderType] % {"HeaderKey" : HeaderKey}\r
1712 else:\r
1713 # not known macro used in #include, always build the file by\r
1714 # returning a empty dependency\r
1715 FileCache[File] = []\r
1716 return []\r
1717 Inc = os.path.normpath(Inc)\r
1718 CurrentFileDependencyList.append(Inc)\r
1719 DepDb[F] = CurrentFileDependencyList\r
1720\r
1721 CurrentFilePath = F.Dir\r
1722 PathList = [CurrentFilePath] + SearchPathList\r
1723 for Inc in CurrentFileDependencyList:\r
1724 for SearchPath in PathList:\r
1725 FilePath = os.path.join(SearchPath, Inc)\r
1726 if FilePath in gIsFileMap:\r
1727 if not gIsFileMap[FilePath]:\r
1728 continue\r
1729 # If isfile is called too many times, the performance is slow down.\r
1730 elif not os.path.isfile(FilePath):\r
1731 gIsFileMap[FilePath] = False\r
1732 continue\r
1733 else:\r
1734 gIsFileMap[FilePath] = True\r
1735 FilePath = PathClass(FilePath)\r
1736 FullPathDependList.append(FilePath)\r
1737 if FilePath not in DependencySet:\r
1738 FileStack.append(FilePath)\r
1739 break\r
1740 else:\r
1741 EdkLogger.debug(EdkLogger.DEBUG_9, "%s included by %s was not found "\\r
1742 "in any given path:\n\t%s" % (Inc, F, "\n\t".join(SearchPathList)))\r
1743\r
1744 FileCache[F] = FullPathDependList\r
1745 DependencySet.update(FullPathDependList)\r
1746\r
1747 DependencySet.update(ForceList)\r
1748 if File in DependencySet:\r
1749 DependencySet.remove(File)\r
1750 DependencyList = list(DependencySet) # remove duplicate ones\r
1751\r
1752 return DependencyList\r
1753\r
f51461c8
LG
1754# This acts like the main() function for the script, unless it is 'import'ed into another script.\r
1755if __name__ == '__main__':\r
e32f7bc9 1756 pass\r