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