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