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