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