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