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