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