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