1## @file 2# build a platform or a module 3# 4# Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR> 5# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR> 6# 7# This program and the accompanying materials 8# are licensed and made available under the terms and conditions of the BSD License 9# which accompanies this distribution. The full text of the license may be found at 10# http://opensource.org/licenses/bsd-license.php 11# 12# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14# 15 16## 17# Import Modules 18# 19import Common.LongFilePathOs as os 20import re 21import StringIO 22import sys 23import glob 24import time 25import platform 26import traceback 27import encodings.ascii 28 29from struct import * 30from threading import * 31from optparse import OptionParser 32from subprocess import * 33from Common import Misc as Utils 34 35from Common.LongFilePathSupport import OpenLongFilePath as open 36from Common.LongFilePathSupport import LongFilePath 37from Common.TargetTxtClassObject import * 38from Common.ToolDefClassObject import * 39from Common.DataType import * 40from Common.BuildVersion import gBUILD_VERSION 41from AutoGen.AutoGen import * 42from Common.BuildToolError import * 43from Workspace.WorkspaceDatabase import * 44 45from BuildReport import BuildReport 46from GenPatchPcdTable.GenPatchPcdTable import * 47from PatchPcdValue.PatchPcdValue import * 48 49import Common.EdkLogger 50import Common.GlobalData as GlobalData 51 52# Version and Copyright 53VersionNumber = "0.60" + ' ' + gBUILD_VERSION 54__version__ = "%prog Version " + VersionNumber 55__copyright__ = "Copyright (c) 2007 - 2014, Intel Corporation All rights reserved." 56 57## standard targets of build command 58gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run'] 59 60## build configuration file 61gBuildConfiguration = "target.txt" 62gToolsDefinition = "tools_def.txt" 63 64TemporaryTablePattern = re.compile(r'^_\d+_\d+_[a-fA-F0-9]+$') 65TmpTableDict = {} 66 67## Check environment PATH variable to make sure the specified tool is found 68# 69# If the tool is found in the PATH, then True is returned 70# Otherwise, False is returned 71# 72def IsToolInPath(tool): 73 if os.environ.has_key('PATHEXT'): 74 extns = os.environ['PATHEXT'].split(os.path.pathsep) 75 else: 76 extns = ('',) 77 for pathDir in os.environ['PATH'].split(os.path.pathsep): 78 for ext in extns: 79 if os.path.exists(os.path.join(pathDir, tool + ext)): 80 return True 81 return False 82 83## Check environment variables 84# 85# Check environment variables that must be set for build. Currently they are 86# 87# WORKSPACE The directory all packages/platforms start from 88# EDK_TOOLS_PATH The directory contains all tools needed by the build 89# PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH 90# 91# If any of above environment variable is not set or has error, the build 92# will be broken. 93# 94def CheckEnvVariable(): 95 # check WORKSPACE 96 if "WORKSPACE" not in os.environ: 97 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found", 98 ExtraData="WORKSPACE") 99 100 WorkspaceDir = os.path.normcase(os.path.normpath(os.environ["WORKSPACE"])) 101 if not os.path.exists(WorkspaceDir): 102 EdkLogger.error("build", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData="%s" % WorkspaceDir) 103 elif ' ' in WorkspaceDir: 104 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path", 105 ExtraData=WorkspaceDir) 106 os.environ["WORKSPACE"] = WorkspaceDir 107 108 # 109 # Check EFI_SOURCE (Edk build convention). EDK_SOURCE will always point to ECP 110 # 111 if "ECP_SOURCE" not in os.environ: 112 os.environ["ECP_SOURCE"] = os.path.join(WorkspaceDir, GlobalData.gEdkCompatibilityPkg) 113 if "EFI_SOURCE" not in os.environ: 114 os.environ["EFI_SOURCE"] = os.environ["ECP_SOURCE"] 115 if "EDK_SOURCE" not in os.environ: 116 os.environ["EDK_SOURCE"] = os.environ["ECP_SOURCE"] 117 118 # 119 # Unify case of characters on case-insensitive systems 120 # 121 EfiSourceDir = os.path.normcase(os.path.normpath(os.environ["EFI_SOURCE"])) 122 EdkSourceDir = os.path.normcase(os.path.normpath(os.environ["EDK_SOURCE"])) 123 EcpSourceDir = os.path.normcase(os.path.normpath(os.environ["ECP_SOURCE"])) 124 125 os.environ["EFI_SOURCE"] = EfiSourceDir 126 os.environ["EDK_SOURCE"] = EdkSourceDir 127 os.environ["ECP_SOURCE"] = EcpSourceDir 128 os.environ["EDK_TOOLS_PATH"] = os.path.normcase(os.environ["EDK_TOOLS_PATH"]) 129 130 if not os.path.exists(EcpSourceDir): 131 EdkLogger.verbose("ECP_SOURCE = %s doesn't exist. Edk modules could not be built." % EcpSourceDir) 132 elif ' ' in EcpSourceDir: 133 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in ECP_SOURCE path", 134 ExtraData=EcpSourceDir) 135 if not os.path.exists(EdkSourceDir): 136 if EdkSourceDir == EcpSourceDir: 137 EdkLogger.verbose("EDK_SOURCE = %s doesn't exist. Edk modules could not be built." % EdkSourceDir) 138 else: 139 EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE does not exist", 140 ExtraData=EdkSourceDir) 141 elif ' ' in EdkSourceDir: 142 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EDK_SOURCE path", 143 ExtraData=EdkSourceDir) 144 if not os.path.exists(EfiSourceDir): 145 if EfiSourceDir == EcpSourceDir: 146 EdkLogger.verbose("EFI_SOURCE = %s doesn't exist. Edk modules could not be built." % EfiSourceDir) 147 else: 148 EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE does not exist", 149 ExtraData=EfiSourceDir) 150 elif ' ' in EfiSourceDir: 151 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EFI_SOURCE path", 152 ExtraData=EfiSourceDir) 153 154 # change absolute path to relative path to WORKSPACE 155 if EfiSourceDir.upper().find(WorkspaceDir.upper()) != 0: 156 EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE is not under WORKSPACE", 157 ExtraData="WORKSPACE = %s\n EFI_SOURCE = %s" % (WorkspaceDir, EfiSourceDir)) 158 if EdkSourceDir.upper().find(WorkspaceDir.upper()) != 0: 159 EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE is not under WORKSPACE", 160 ExtraData="WORKSPACE = %s\n EDK_SOURCE = %s" % (WorkspaceDir, EdkSourceDir)) 161 if EcpSourceDir.upper().find(WorkspaceDir.upper()) != 0: 162 EdkLogger.error("build", PARAMETER_INVALID, "ECP_SOURCE is not under WORKSPACE", 163 ExtraData="WORKSPACE = %s\n ECP_SOURCE = %s" % (WorkspaceDir, EcpSourceDir)) 164 165 # check EDK_TOOLS_PATH 166 if "EDK_TOOLS_PATH" not in os.environ: 167 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found", 168 ExtraData="EDK_TOOLS_PATH") 169 170 # check PATH 171 if "PATH" not in os.environ: 172 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found", 173 ExtraData="PATH") 174 175 GlobalData.gWorkspace = WorkspaceDir 176 GlobalData.gEfiSource = EfiSourceDir 177 GlobalData.gEdkSource = EdkSourceDir 178 GlobalData.gEcpSource = EcpSourceDir 179 180 GlobalData.gGlobalDefines["WORKSPACE"] = WorkspaceDir 181 GlobalData.gGlobalDefines["EFI_SOURCE"] = EfiSourceDir 182 GlobalData.gGlobalDefines["EDK_SOURCE"] = EdkSourceDir 183 GlobalData.gGlobalDefines["ECP_SOURCE"] = EcpSourceDir 184 GlobalData.gGlobalDefines["EDK_TOOLS_PATH"] = os.environ["EDK_TOOLS_PATH"] 185 186## Get normalized file path 187# 188# Convert the path to be local format, and remove the WORKSPACE path at the 189# beginning if the file path is given in full path. 190# 191# @param FilePath File path to be normalized 192# @param Workspace Workspace path which the FilePath will be checked against 193# 194# @retval string The normalized file path 195# 196def NormFile(FilePath, Workspace): 197 # check if the path is absolute or relative 198 if os.path.isabs(FilePath): 199 FileFullPath = os.path.normpath(FilePath) 200 else: 201 FileFullPath = os.path.normpath(os.path.join(Workspace, FilePath)) 202 203 # check if the file path exists or not 204 if not os.path.isfile(FileFullPath): 205 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath) 206 207 # remove workspace directory from the beginning part of the file path 208 if Workspace[-1] in ["\\", "/"]: 209 return FileFullPath[len(Workspace):] 210 else: 211 return FileFullPath[(len(Workspace) + 1):] 212 213## Get the output of an external program 214# 215# This is the entrance method of thread reading output of an external program and 216# putting them in STDOUT/STDERR of current program. 217# 218# @param From The stream message read from 219# @param To The stream message put on 220# @param ExitFlag The flag used to indicate stopping reading 221# 222def ReadMessage(From, To, ExitFlag): 223 while True: 224 # read one line a time 225 Line = From.readline() 226 # empty string means "end" 227 if Line != None and Line != "": 228 To(Line.rstrip()) 229 else: 230 break 231 if ExitFlag.isSet(): 232 break 233 234## Launch an external program 235# 236# This method will call subprocess.Popen to execute an external program with 237# given options in specified directory. Because of the dead-lock issue during 238# redirecting output of the external program, threads are used to to do the 239# redirection work. 240# 241# @param Command A list or string containing the call of the program 242# @param WorkingDir The directory in which the program will be running 243# 244def LaunchCommand(Command, WorkingDir): 245 # if working directory doesn't exist, Popen() will raise an exception 246 if not os.path.isdir(WorkingDir): 247 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=WorkingDir) 248 249 # Command is used as the first Argument in following Popen(). 250 # It could be a string or sequence. We find that if command is a string in following Popen(), 251 # ubuntu may fail with an error message that the command is not found. 252 # So here we may need convert command from string to list instance. 253 if not isinstance(Command, list): 254 if platform.system() != 'Windows': 255 Command = Command.split() 256 257 Proc = None 258 EndOfProcedure = None 259 try: 260 # launch the command 261 Proc = Popen(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir, bufsize=-1) 262 263 # launch two threads to read the STDOUT and STDERR 264 EndOfProcedure = Event() 265 EndOfProcedure.clear() 266 if Proc.stdout: 267 StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure)) 268 StdOutThread.setName("STDOUT-Redirector") 269 StdOutThread.setDaemon(False) 270 StdOutThread.start() 271 272 if Proc.stderr: 273 StdErrThread = Thread(target=ReadMessage, args=(Proc.stderr, EdkLogger.quiet, EndOfProcedure)) 274 StdErrThread.setName("STDERR-Redirector") 275 StdErrThread.setDaemon(False) 276 StdErrThread.start() 277 278 # waiting for program exit 279 Proc.wait() 280 except: # in case of aborting 281 # terminate the threads redirecting the program output 282 if EndOfProcedure != None: 283 EndOfProcedure.set() 284 if Proc == None: 285 if type(Command) != type(""): 286 Command = " ".join(Command) 287 EdkLogger.error("build", COMMAND_FAILURE, "Failed to start command", ExtraData="%s [%s]" % (Command, WorkingDir)) 288 289 if Proc.stdout: 290 StdOutThread.join() 291 if Proc.stderr: 292 StdErrThread.join() 293 294 # check the return code of the program 295 if Proc.returncode != 0: 296 if type(Command) != type(""): 297 Command = " ".join(Command) 298 EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir)) 299 300## The smallest unit that can be built in multi-thread build mode 301# 302# This is the base class of build unit. The "Obj" parameter must provide 303# __str__(), __eq__() and __hash__() methods. Otherwise there could be build units 304# missing build. 305# 306# Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects. 307# 308class BuildUnit: 309 ## The constructor 310 # 311 # @param self The object pointer 312 # @param Obj The object the build is working on 313 # @param Target The build target name, one of gSupportedTarget 314 # @param Dependency The BuildUnit(s) which must be completed in advance 315 # @param WorkingDir The directory build command starts in 316 # 317 def __init__(self, Obj, BuildCommand, Target, Dependency, WorkingDir="."): 318 self.BuildObject = Obj 319 self.Dependency = Dependency 320 self.WorkingDir = WorkingDir 321 self.Target = Target 322 self.BuildCommand = BuildCommand 323 if not BuildCommand: 324 EdkLogger.error("build", OPTION_MISSING, 325 "No build command found for this module. " 326 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." % 327 (Obj.BuildTarget, Obj.ToolChain, Obj.Arch), 328 ExtraData=str(Obj)) 329 330 331 ## str() method 332 # 333 # It just returns the string representation of self.BuildObject 334 # 335 # @param self The object pointer 336 # 337 def __str__(self): 338 return str(self.BuildObject) 339 340 ## "==" operator method 341 # 342 # It just compares self.BuildObject with "Other". So self.BuildObject must 343 # provide its own __eq__() method. 344 # 345 # @param self The object pointer 346 # @param Other The other BuildUnit object compared to 347 # 348 def __eq__(self, Other): 349 return Other != None and self.BuildObject == Other.BuildObject \ 350 and self.BuildObject.Arch == Other.BuildObject.Arch 351 352 ## hash() method 353 # 354 # It just returns the hash value of self.BuildObject which must be hashable. 355 # 356 # @param self The object pointer 357 # 358 def __hash__(self): 359 return hash(self.BuildObject) + hash(self.BuildObject.Arch) 360 361 def __repr__(self): 362 return repr(self.BuildObject) 363 364## The smallest module unit that can be built by nmake/make command in multi-thread build mode 365# 366# This class is for module build by nmake/make build system. The "Obj" parameter 367# must provide __str__(), __eq__() and __hash__() methods. Otherwise there could 368# be make units missing build. 369# 370# Currently the "Obj" should be only ModuleAutoGen object. 371# 372class ModuleMakeUnit(BuildUnit): 373 ## The constructor 374 # 375 # @param self The object pointer 376 # @param Obj The ModuleAutoGen object the build is working on 377 # @param Target The build target name, one of gSupportedTarget 378 # 379 def __init__(self, Obj, Target): 380 Dependency = [ModuleMakeUnit(La, Target) for La in Obj.LibraryAutoGenList] 381 BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir) 382 if Target in [None, "", "all"]: 383 self.Target = "tbuild" 384 385## The smallest platform unit that can be built by nmake/make command in multi-thread build mode 386# 387# This class is for platform build by nmake/make build system. The "Obj" parameter 388# must provide __str__(), __eq__() and __hash__() methods. Otherwise there could 389# be make units missing build. 390# 391# Currently the "Obj" should be only PlatformAutoGen object. 392# 393class PlatformMakeUnit(BuildUnit): 394 ## The constructor 395 # 396 # @param self The object pointer 397 # @param Obj The PlatformAutoGen object the build is working on 398 # @param Target The build target name, one of gSupportedTarget 399 # 400 def __init__(self, Obj, Target): 401 Dependency = [ModuleMakeUnit(Lib, Target) for Lib in self.BuildObject.LibraryAutoGenList] 402 Dependency.extend([ModuleMakeUnit(Mod, Target) for Mod in self.BuildObject.ModuleAutoGenList]) 403 BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir) 404 405## The class representing the task of a module build or platform build 406# 407# This class manages the build tasks in multi-thread build mode. Its jobs include 408# scheduling thread running, catching thread error, monitor the thread status, etc. 409# 410class BuildTask: 411 # queue for tasks waiting for schedule 412 _PendingQueue = sdict() 413 _PendingQueueLock = threading.Lock() 414 415 # queue for tasks ready for running 416 _ReadyQueue = sdict() 417 _ReadyQueueLock = threading.Lock() 418 419 # queue for run tasks 420 _RunningQueue = sdict() 421 _RunningQueueLock = threading.Lock() 422 423 # queue containing all build tasks, in case duplicate build 424 _TaskQueue = sdict() 425 426 # flag indicating error occurs in a running thread 427 _ErrorFlag = threading.Event() 428 _ErrorFlag.clear() 429 _ErrorMessage = "" 430 431 # BoundedSemaphore object used to control the number of running threads 432 _Thread = None 433 434 # flag indicating if the scheduler is started or not 435 _SchedulerStopped = threading.Event() 436 _SchedulerStopped.set() 437 438 ## Start the task scheduler thread 439 # 440 # @param MaxThreadNumber The maximum thread number 441 # @param ExitFlag Flag used to end the scheduler 442 # 443 @staticmethod 444 def StartScheduler(MaxThreadNumber, ExitFlag): 445 SchedulerThread = Thread(target=BuildTask.Scheduler, args=(MaxThreadNumber, ExitFlag)) 446 SchedulerThread.setName("Build-Task-Scheduler") 447 SchedulerThread.setDaemon(False) 448 SchedulerThread.start() 449 # wait for the scheduler to be started, especially useful in Linux 450 while not BuildTask.IsOnGoing(): 451 time.sleep(0.01) 452 453 ## Scheduler method 454 # 455 # @param MaxThreadNumber The maximum thread number 456 # @param ExitFlag Flag used to end the scheduler 457 # 458 @staticmethod 459 def Scheduler(MaxThreadNumber, ExitFlag): 460 BuildTask._SchedulerStopped.clear() 461 try: 462 # use BoundedSemaphore to control the maximum running threads 463 BuildTask._Thread = BoundedSemaphore(MaxThreadNumber) 464 # 465 # scheduling loop, which will exits when no pending/ready task and 466 # indicated to do so, or there's error in running thread 467 # 468 while (len(BuildTask._PendingQueue) > 0 or len(BuildTask._ReadyQueue) > 0 \ 469 or not ExitFlag.isSet()) and not BuildTask._ErrorFlag.isSet(): 470 EdkLogger.debug(EdkLogger.DEBUG_8, "Pending Queue (%d), Ready Queue (%d)" 471 % (len(BuildTask._PendingQueue), len(BuildTask._ReadyQueue))) 472 473 # get all pending tasks 474 BuildTask._PendingQueueLock.acquire() 475 BuildObjectList = BuildTask._PendingQueue.keys() 476 # 477 # check if their dependency is resolved, and if true, move them 478 # into ready queue 479 # 480 for BuildObject in BuildObjectList: 481 Bt = BuildTask._PendingQueue[BuildObject] 482 if Bt.IsReady(): 483 BuildTask._ReadyQueue[BuildObject] = BuildTask._PendingQueue.pop(BuildObject) 484 BuildTask._PendingQueueLock.release() 485 486 # launch build thread until the maximum number of threads is reached 487 while not BuildTask._ErrorFlag.isSet(): 488 # empty ready queue, do nothing further 489 if len(BuildTask._ReadyQueue) == 0: 490 break 491 492 # wait for active thread(s) exit 493 BuildTask._Thread.acquire(True) 494 495 # start a new build thread 496 Bo = BuildTask._ReadyQueue.keys()[0] 497 Bt = BuildTask._ReadyQueue.pop(Bo) 498 499 # move into running queue 500 BuildTask._RunningQueueLock.acquire() 501 BuildTask._RunningQueue[Bo] = Bt 502 BuildTask._RunningQueueLock.release() 503 504 Bt.Start() 505 # avoid tense loop 506 time.sleep(0.01) 507 508 # avoid tense loop 509 time.sleep(0.01) 510 511 # wait for all running threads exit 512 if BuildTask._ErrorFlag.isSet(): 513 EdkLogger.quiet("\nWaiting for all build threads exit...") 514 # while not BuildTask._ErrorFlag.isSet() and \ 515 while len(BuildTask._RunningQueue) > 0: 516 EdkLogger.verbose("Waiting for thread ending...(%d)" % len(BuildTask._RunningQueue)) 517 EdkLogger.debug(EdkLogger.DEBUG_8, "Threads [%s]" % ", ".join([Th.getName() for Th in threading.enumerate()])) 518 # avoid tense loop 519 time.sleep(0.1) 520 except BaseException, X: 521 # 522 # TRICK: hide the output of threads left runing, so that the user can 523 # catch the error message easily 524 # 525 EdkLogger.SetLevel(EdkLogger.ERROR) 526 BuildTask._ErrorFlag.set() 527 BuildTask._ErrorMessage = "build thread scheduler error\n\t%s" % str(X) 528 529 BuildTask._PendingQueue.clear() 530 BuildTask._ReadyQueue.clear() 531 BuildTask._RunningQueue.clear() 532 BuildTask._TaskQueue.clear() 533 BuildTask._SchedulerStopped.set() 534 535 ## Wait for all running method exit 536 # 537 @staticmethod 538 def WaitForComplete(): 539 BuildTask._SchedulerStopped.wait() 540 541 ## Check if the scheduler is running or not 542 # 543 @staticmethod 544 def IsOnGoing(): 545 return not BuildTask._SchedulerStopped.isSet() 546 547 ## Abort the build 548 @staticmethod 549 def Abort(): 550 if BuildTask.IsOnGoing(): 551 BuildTask._ErrorFlag.set() 552 BuildTask.WaitForComplete() 553 554 ## Check if there's error in running thread 555 # 556 # Since the main thread cannot catch exceptions in other thread, we have to 557 # use threading.Event to communicate this formation to main thread. 558 # 559 @staticmethod 560 def HasError(): 561 return BuildTask._ErrorFlag.isSet() 562 563 ## Get error message in running thread 564 # 565 # Since the main thread cannot catch exceptions in other thread, we have to 566 # use a static variable to communicate this message to main thread. 567 # 568 @staticmethod 569 def GetErrorMessage(): 570 return BuildTask._ErrorMessage 571 572 ## Factory method to create a BuildTask object 573 # 574 # This method will check if a module is building or has been built. And if 575 # true, just return the associated BuildTask object in the _TaskQueue. If 576 # not, create and return a new BuildTask object. The new BuildTask object 577 # will be appended to the _PendingQueue for scheduling later. 578 # 579 # @param BuildItem A BuildUnit object representing a build object 580 # @param Dependency The dependent build object of BuildItem 581 # 582 @staticmethod 583 def New(BuildItem, Dependency=None): 584 if BuildItem in BuildTask._TaskQueue: 585 Bt = BuildTask._TaskQueue[BuildItem] 586 return Bt 587 588 Bt = BuildTask() 589 Bt._Init(BuildItem, Dependency) 590 BuildTask._TaskQueue[BuildItem] = Bt 591 592 BuildTask._PendingQueueLock.acquire() 593 BuildTask._PendingQueue[BuildItem] = Bt 594 BuildTask._PendingQueueLock.release() 595 596 return Bt 597 598 ## The real constructor of BuildTask 599 # 600 # @param BuildItem A BuildUnit object representing a build object 601 # @param Dependency The dependent build object of BuildItem 602 # 603 def _Init(self, BuildItem, Dependency=None): 604 self.BuildItem = BuildItem 605 606 self.DependencyList = [] 607 if Dependency == None: 608 Dependency = BuildItem.Dependency 609 else: 610 Dependency.extend(BuildItem.Dependency) 611 self.AddDependency(Dependency) 612 # flag indicating build completes, used to avoid unnecessary re-build 613 self.CompleteFlag = False 614 615 ## Check if all dependent build tasks are completed or not 616 # 617 def IsReady(self): 618 ReadyFlag = True 619 for Dep in self.DependencyList: 620 if Dep.CompleteFlag == True: 621 continue 622 ReadyFlag = False 623 break 624 625 return ReadyFlag 626 627 ## Add dependent build task 628 # 629 # @param Dependency The list of dependent build objects 630 # 631 def AddDependency(self, Dependency): 632 for Dep in Dependency: 633 if not Dep.BuildObject.IsBinaryModule: 634 self.DependencyList.append(BuildTask.New(Dep)) # BuildTask list 635 636 ## The thread wrapper of LaunchCommand function 637 # 638 # @param Command A list or string contains the call of the command 639 # @param WorkingDir The directory in which the program will be running 640 # 641 def _CommandThread(self, Command, WorkingDir): 642 try: 643 LaunchCommand(Command, WorkingDir) 644 self.CompleteFlag = True 645 except: 646 # 647 # TRICK: hide the output of threads left runing, so that the user can 648 # catch the error message easily 649 # 650 if not BuildTask._ErrorFlag.isSet(): 651 GlobalData.gBuildingModule = "%s [%s, %s, %s]" % (str(self.BuildItem.BuildObject), 652 self.BuildItem.BuildObject.Arch, 653 self.BuildItem.BuildObject.ToolChain, 654 self.BuildItem.BuildObject.BuildTarget 655 ) 656 EdkLogger.SetLevel(EdkLogger.ERROR) 657 BuildTask._ErrorFlag.set() 658 BuildTask._ErrorMessage = "%s broken\n %s [%s]" % \ 659 (threading.currentThread().getName(), Command, WorkingDir) 660 # indicate there's a thread is available for another build task 661 BuildTask._RunningQueueLock.acquire() 662 BuildTask._RunningQueue.pop(self.BuildItem) 663 BuildTask._RunningQueueLock.release() 664 BuildTask._Thread.release() 665 666 ## Start build task thread 667 # 668 def Start(self): 669 EdkLogger.quiet("Building ... %s" % repr(self.BuildItem)) 670 Command = self.BuildItem.BuildCommand + [self.BuildItem.Target] 671 self.BuildTread = Thread(target=self._CommandThread, args=(Command, self.BuildItem.WorkingDir)) 672 self.BuildTread.setName("build thread") 673 self.BuildTread.setDaemon(False) 674 self.BuildTread.start() 675 676## The class contains the information related to EFI image 677# 678class PeImageInfo(): 679 ## Constructor 680 # 681 # Constructor will load all required image information. 682 # 683 # @param BaseName The full file path of image. 684 # @param Guid The GUID for image. 685 # @param Arch Arch of this image. 686 # @param OutputDir The output directory for image. 687 # @param DebugDir The debug directory for image. 688 # @param ImageClass PeImage Information 689 # 690 def __init__(self, BaseName, Guid, Arch, OutputDir, DebugDir, ImageClass): 691 self.BaseName = BaseName 692 self.Guid = Guid 693 self.Arch = Arch 694 self.OutputDir = OutputDir 695 self.DebugDir = DebugDir 696 self.Image = ImageClass 697 self.Image.Size = (self.Image.Size / 0x1000 + 1) * 0x1000 698 699## The class implementing the EDK2 build process 700# 701# The build process includes: 702# 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf 703# 2. Parse DSC file of active platform 704# 3. Parse FDF file if any 705# 4. Establish build database, including parse all other files (module, package) 706# 5. Create AutoGen files (C code file, depex file, makefile) if necessary 707# 6. Call build command 708# 709class Build(): 710 ## Constructor 711 # 712 # Constructor will load all necessary configurations, parse platform, modules 713 # and packages and the establish a database for AutoGen. 714 # 715 # @param Target The build command target, one of gSupportedTarget 716 # @param WorkspaceDir The directory of workspace 717 # @param BuildOptions Build options passed from command line 718 # 719 def __init__(self, Target, WorkspaceDir, BuildOptions): 720 self.WorkspaceDir = WorkspaceDir 721 self.Target = Target 722 self.PlatformFile = BuildOptions.PlatformFile 723 self.ModuleFile = BuildOptions.ModuleFile 724 self.ArchList = BuildOptions.TargetArch 725 self.ToolChainList = BuildOptions.ToolChain 726 self.BuildTargetList= BuildOptions.BuildTarget 727 self.Fdf = BuildOptions.FdfFile 728 self.FdList = BuildOptions.RomImage 729 self.FvList = BuildOptions.FvImage 730 self.CapList = BuildOptions.CapName 731 self.SilentMode = BuildOptions.SilentMode 732 self.ThreadNumber = BuildOptions.ThreadNumber 733 self.SkipAutoGen = BuildOptions.SkipAutoGen 734 self.Reparse = BuildOptions.Reparse 735 self.SkuId = BuildOptions.SkuId 736 self.ConfDirectory = BuildOptions.ConfDirectory 737 self.SpawnMode = True 738 self.BuildReport = BuildReport(BuildOptions.ReportFile, BuildOptions.ReportType) 739 self.TargetTxt = TargetTxtClassObject() 740 self.ToolDef = ToolDefClassObject() 741 #Set global flag for build mode 742 GlobalData.gIgnoreSource = BuildOptions.IgnoreSources 743 744 if self.ConfDirectory: 745 # Get alternate Conf location, if it is absolute, then just use the absolute directory name 746 ConfDirectoryPath = os.path.normpath(self.ConfDirectory) 747 748 if not os.path.isabs(ConfDirectoryPath): 749 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE 750 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf 751 ConfDirectoryPath = os.path.join(self.WorkspaceDir, ConfDirectoryPath) 752 else: 753 # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf 754 ConfDirectoryPath = os.path.join(self.WorkspaceDir, 'Conf') 755 GlobalData.gConfDirectory = ConfDirectoryPath 756 GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath)) 757 758 if BuildOptions.DisableCache: 759 self.Db = WorkspaceDatabase(":memory:") 760 else: 761 self.Db = WorkspaceDatabase(GlobalData.gDatabasePath, self.Reparse) 762 self.BuildDatabase = self.Db.BuildObject 763 self.Platform = None 764 self.LoadFixAddress = 0 765 self.UniFlag = BuildOptions.Flag 766 self.BuildModules = [] 767 768 # print dot character during doing some time-consuming work 769 self.Progress = Utils.Progressor() 770 771 self.InitBuild() 772 773 # print current build environment and configuration 774 EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"])) 775 EdkLogger.quiet("%-16s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"])) 776 EdkLogger.quiet("%-16s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"])) 777 EdkLogger.quiet("%-16s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"])) 778 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"])) 779 780 EdkLogger.info("") 781 782 os.chdir(self.WorkspaceDir) 783 784 ## Load configuration 785 # 786 # This method will parse target.txt and get the build configurations. 787 # 788 def LoadConfiguration(self): 789 # 790 # Check target.txt and tools_def.txt and Init them 791 # 792 BuildConfigurationFile = os.path.normpath(os.path.join(GlobalData.gConfDirectory, gBuildConfiguration)) 793 if os.path.isfile(BuildConfigurationFile) == True: 794 StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile) 795 796 ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF] 797 if ToolDefinitionFile == '': 798 ToolDefinitionFile = gToolsDefinition 799 ToolDefinitionFile = os.path.normpath(os.path.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile)) 800 if os.path.isfile(ToolDefinitionFile) == True: 801 StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile) 802 else: 803 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile) 804 else: 805 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile) 806 807 # if no ARCH given in command line, get it from target.txt 808 if not self.ArchList: 809 self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH] 810 self.ArchList = tuple(self.ArchList) 811 812 # if no build target given in command line, get it from target.txt 813 if not self.BuildTargetList: 814 self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET] 815 816 # if no tool chain given in command line, get it from target.txt 817 if not self.ToolChainList: 818 self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG] 819 if self.ToolChainList == None or len(self.ToolChainList) == 0: 820 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n") 821 822 # check if the tool chains are defined or not 823 NewToolChainList = [] 824 for ToolChain in self.ToolChainList: 825 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]: 826 EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain) 827 else: 828 NewToolChainList.append(ToolChain) 829 # if no tool chain available, break the build 830 if len(NewToolChainList) == 0: 831 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, 832 ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList)) 833 else: 834 self.ToolChainList = NewToolChainList 835 836 if self.ThreadNumber == None: 837 self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER] 838 if self.ThreadNumber == '': 839 self.ThreadNumber = 0 840 else: 841 self.ThreadNumber = int(self.ThreadNumber, 0) 842 843 if self.ThreadNumber == 0: 844 self.ThreadNumber = 1 845 846 if not self.PlatformFile: 847 PlatformFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM] 848 if not PlatformFile: 849 # Try to find one in current directory 850 WorkingDirectory = os.getcwd() 851 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc'))) 852 FileNum = len(FileList) 853 if FileNum >= 2: 854 EdkLogger.error("build", OPTION_MISSING, 855 ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory)) 856 elif FileNum == 1: 857 PlatformFile = FileList[0] 858 else: 859 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, 860 ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n") 861 862 self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir) 863 864 ## Initialize build configuration 865 # 866 # This method will parse DSC file and merge the configurations from 867 # command line and target.txt, then get the final build configurations. 868 # 869 def InitBuild(self): 870 # parse target.txt, tools_def.txt, and platform file 871 self.LoadConfiguration() 872 873 # Allow case-insensitive for those from command line or configuration file 874 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False) 875 if ErrorCode != 0: 876 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo) 877 878 # create metafile database 879 self.Db.InitDatabase() 880 881 ## Build a module or platform 882 # 883 # Create autogen code and makefile for a module or platform, and the launch 884 # "make" command to build it 885 # 886 # @param Target The target of build command 887 # @param Platform The platform file 888 # @param Module The module file 889 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE" 890 # @param ToolChain The name of toolchain to build 891 # @param Arch The arch of the module/platform 892 # @param CreateDepModuleCodeFile Flag used to indicate creating code 893 # for dependent modules/Libraries 894 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile 895 # for dependent modules/Libraries 896 # 897 def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False): 898 if AutoGenObject == None: 899 return False 900 901 # skip file generation for cleanxxx targets, run and fds target 902 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']: 903 # for target which must generate AutoGen code and makefile 904 if not self.SkipAutoGen or Target == 'genc': 905 self.Progress.Start("Generating code") 906 AutoGenObject.CreateCodeFile(CreateDepsCodeFile) 907 self.Progress.Stop("done!") 908 if Target == "genc": 909 return True 910 911 if not self.SkipAutoGen or Target == 'genmake': 912 self.Progress.Start("Generating makefile") 913 AutoGenObject.CreateMakeFile(CreateDepsMakeFile) 914 self.Progress.Stop("done!") 915 if Target == "genmake": 916 return True 917 else: 918 # always recreate top/platform makefile when clean, just in case of inconsistency 919 AutoGenObject.CreateCodeFile(False) 920 AutoGenObject.CreateMakeFile(False) 921 922 if EdkLogger.GetLevel() == EdkLogger.QUIET: 923 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject)) 924 925 BuildCommand = AutoGenObject.BuildCommand 926 if BuildCommand == None or len(BuildCommand) == 0: 927 EdkLogger.error("build", OPTION_MISSING, 928 "No build command found for this module. " 929 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." % 930 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch), 931 ExtraData=str(AutoGenObject)) 932 933 makefile = GenMake.BuildFile(AutoGenObject)._FILE_NAME_[GenMake.gMakeType] 934 935 # run 936 if Target == 'run': 937 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH'])) 938 Command = '.\SecMain' 939 os.chdir(RunDir) 940 LaunchCommand(Command, RunDir) 941 return True 942 943 # build modules 944 if BuildModule: 945 BuildCommand = BuildCommand + [Target] 946 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir) 947 self.CreateAsBuiltInf() 948 return True 949 950 # build library 951 if Target == 'libraries': 952 for Lib in AutoGenObject.LibraryBuildDirectoryList: 953 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild'] 954 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir) 955 return True 956 957 # build module 958 if Target == 'modules': 959 for Lib in AutoGenObject.LibraryBuildDirectoryList: 960 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild'] 961 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir) 962 for Mod in AutoGenObject.ModuleBuildDirectoryList: 963 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild'] 964 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir) 965 self.CreateAsBuiltInf() 966 return True 967 968 # cleanlib 969 if Target == 'cleanlib': 970 for Lib in AutoGenObject.LibraryBuildDirectoryList: 971 LibMakefile = os.path.normpath(os.path.join(Lib, makefile)) 972 if os.path.exists(LibMakefile): 973 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall'] 974 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir) 975 return True 976 977 # clean 978 if Target == 'clean': 979 for Mod in AutoGenObject.ModuleBuildDirectoryList: 980 ModMakefile = os.path.normpath(os.path.join(Mod, makefile)) 981 if os.path.exists(ModMakefile): 982 NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall'] 983 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir) 984 for Lib in AutoGenObject.LibraryBuildDirectoryList: 985 LibMakefile = os.path.normpath(os.path.join(Lib, makefile)) 986 if os.path.exists(LibMakefile): 987 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall'] 988 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir) 989 return True 990 991 # cleanall 992 if Target == 'cleanall': 993 try: 994 #os.rmdir(AutoGenObject.BuildDir) 995 RemoveDirectory(AutoGenObject.BuildDir, True) 996 except WindowsError, X: 997 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X)) 998 return True 999 1000 ## Build a module or platform 1001 # 1002 # Create autogen code and makefile for a module or platform, and the launch 1003 # "make" command to build it 1004 # 1005 # @param Target The target of build command 1006 # @param Platform The platform file 1007 # @param Module The module file 1008 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE" 1009 # @param ToolChain The name of toolchain to build 1010 # @param Arch The arch of the module/platform 1011 # @param CreateDepModuleCodeFile Flag used to indicate creating code 1012 # for dependent modules/Libraries 1013 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile 1014 # for dependent modules/Libraries 1015 # 1016 def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False): 1017 if AutoGenObject == None: 1018 return False 1019 1020 # skip file generation for cleanxxx targets, run and fds target 1021 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']: 1022 # for target which must generate AutoGen code and makefile 1023 if not self.SkipAutoGen or Target == 'genc': 1024 self.Progress.Start("Generating code") 1025 AutoGenObject.CreateCodeFile(CreateDepsCodeFile) 1026 self.Progress.Stop("done!") 1027 if Target == "genc": 1028 return True 1029 1030 if not self.SkipAutoGen or Target == 'genmake': 1031 self.Progress.Start("Generating makefile") 1032 AutoGenObject.CreateMakeFile(CreateDepsMakeFile) 1033 #AutoGenObject.CreateAsBuiltInf() 1034 self.Progress.Stop("done!") 1035 if Target == "genmake": 1036 return True 1037 else: 1038 # always recreate top/platform makefile when clean, just in case of inconsistency 1039 AutoGenObject.CreateCodeFile(False) 1040 AutoGenObject.CreateMakeFile(False) 1041 1042 if EdkLogger.GetLevel() == EdkLogger.QUIET: 1043 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject)) 1044 1045 BuildCommand = AutoGenObject.BuildCommand 1046 if BuildCommand == None or len(BuildCommand) == 0: 1047 EdkLogger.error("build", OPTION_MISSING, 1048 "No build command found for this module. " 1049 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." % 1050 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch), 1051 ExtraData=str(AutoGenObject)) 1052 1053 # build modules 1054 if BuildModule: 1055 if Target != 'fds': 1056 BuildCommand = BuildCommand + [Target] 1057 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir) 1058 self.CreateAsBuiltInf() 1059 return True 1060 1061 # genfds 1062 if Target == 'fds': 1063 LaunchCommand(AutoGenObject.GenFdsCommand, AutoGenObject.MakeFileDir) 1064 return True 1065 1066 # run 1067 if Target == 'run': 1068 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH'])) 1069 Command = '.\SecMain' 1070 os.chdir(RunDir) 1071 LaunchCommand(Command, RunDir) 1072 return True 1073 1074 # build library 1075 if Target == 'libraries': 1076 pass 1077 1078 # not build modules 1079 1080 1081 # cleanall 1082 if Target == 'cleanall': 1083 try: 1084 #os.rmdir(AutoGenObject.BuildDir) 1085 RemoveDirectory(AutoGenObject.BuildDir, True) 1086 except WindowsError, X: 1087 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X)) 1088 return True 1089 1090 ## Rebase module image and Get function address for the input module list. 1091 # 1092 def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False): 1093 if ModeIsSmm: 1094 AddrIsOffset = False 1095 InfFileNameList = ModuleList.keys() 1096 #InfFileNameList.sort() 1097 for InfFile in InfFileNameList: 1098 sys.stdout.write (".") 1099 sys.stdout.flush() 1100 ModuleInfo = ModuleList[InfFile] 1101 ModuleName = ModuleInfo.BaseName 1102 ModuleOutputImage = ModuleInfo.Image.FileName 1103 ModuleDebugImage = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi') 1104 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top. 1105 if not ModeIsSmm: 1106 BaseAddress = BaseAddress - ModuleInfo.Image.Size 1107 # 1108 # Update Image to new BaseAddress by GenFw tool 1109 # 1110 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir) 1111 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir) 1112 else: 1113 # 1114 # Set new address to the section header only for SMM driver. 1115 # 1116 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir) 1117 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir) 1118 # 1119 # Collect funtion address from Map file 1120 # 1121 ImageMapTable = ModuleOutputImage.replace('.efi', '.map') 1122 FunctionList = [] 1123 if os.path.exists(ImageMapTable): 1124 OrigImageBaseAddress = 0 1125 ImageMap = open (ImageMapTable, 'r') 1126 for LinStr in ImageMap: 1127 if len (LinStr.strip()) == 0: 1128 continue 1129 # 1130 # Get the preferred address set on link time. 1131 # 1132 if LinStr.find ('Preferred load address is') != -1: 1133 StrList = LinStr.split() 1134 OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16) 1135 1136 StrList = LinStr.split() 1137 if len (StrList) > 4: 1138 if StrList[3] == 'f' or StrList[3] =='F': 1139 Name = StrList[1] 1140 RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress 1141 FunctionList.append ((Name, RelativeAddress)) 1142 if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'): 1143 # 1144 # Get the real entry point address for IPF image. 1145 # 1146 ModuleInfo.Image.EntryPoint = RelativeAddress 1147 ImageMap.close() 1148 # 1149 # Add general information. 1150 # 1151 if ModeIsSmm: 1152 MapBuffer.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint)) 1153 elif AddrIsOffset: 1154 MapBuffer.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint))) 1155 else: 1156 MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint)) 1157 # 1158 # Add guid and general seciton section. 1159 # 1160 TextSectionAddress = 0 1161 DataSectionAddress = 0 1162 for SectionHeader in ModuleInfo.Image.SectionHeaderList: 1163 if SectionHeader[0] == '.text': 1164 TextSectionAddress = SectionHeader[1] 1165 elif SectionHeader[0] in ['.data', '.sdata']: 1166 DataSectionAddress = SectionHeader[1] 1167 if AddrIsOffset: 1168 MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress))) 1169 else: 1170 MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress)) 1171 # 1172 # Add debug image full path. 1173 # 1174 MapBuffer.write('(IMAGE=%s)\n\n' % (ModuleDebugImage)) 1175 # 1176 # Add funtion address 1177 # 1178 for Function in FunctionList: 1179 if AddrIsOffset: 1180 MapBuffer.write(' -0x%010X %s\n' % (0 - (BaseAddress + Function[1]), Function[0])) 1181 else: 1182 MapBuffer.write(' 0x%010X %s\n' % (BaseAddress + Function[1], Function[0])) 1183 ImageMap.close() 1184 1185 # 1186 # for SMM module in SMRAM, the SMRAM will be allocated from base to top. 1187 # 1188 if ModeIsSmm: 1189 BaseAddress = BaseAddress + ModuleInfo.Image.Size 1190 1191 ## Collect MAP information of all FVs 1192 # 1193 def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList): 1194 if self.Fdf: 1195 # First get the XIP base address for FV map file. 1196 GuidPattern = re.compile("[-a-fA-F0-9]+") 1197 GuidName = re.compile("\(GUID=[-a-fA-F0-9]+") 1198 for FvName in Wa.FdfProfile.FvDict.keys(): 1199 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map') 1200 if not os.path.exists(FvMapBuffer): 1201 continue 1202 FvMap = open(FvMapBuffer, 'r') 1203 #skip FV size information 1204 FvMap.readline() 1205 FvMap.readline() 1206 FvMap.readline() 1207 FvMap.readline() 1208 for Line in FvMap: 1209 MatchGuid = GuidPattern.match(Line) 1210 if MatchGuid != None: 1211 # 1212 # Replace GUID with module name 1213 # 1214 GuidString = MatchGuid.group() 1215 if GuidString.upper() in ModuleList: 1216 Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name) 1217 MapBuffer.write('%s' % (Line)) 1218 # 1219 # Add the debug image full path. 1220 # 1221 MatchGuid = GuidName.match(Line) 1222 if MatchGuid != None: 1223 GuidString = MatchGuid.group().split("=")[1] 1224 if GuidString.upper() in ModuleList: 1225 MapBuffer.write('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi'))) 1226 1227 FvMap.close() 1228 1229 ## Collect MAP information of all modules 1230 # 1231 def _CollectModuleMapBuffer (self, MapBuffer, ModuleList): 1232 sys.stdout.write ("Generate Load Module At Fix Address Map") 1233 sys.stdout.flush() 1234 PatchEfiImageList = [] 1235 PeiModuleList = {} 1236 BtModuleList = {} 1237 RtModuleList = {} 1238 SmmModuleList = {} 1239 PeiSize = 0 1240 BtSize = 0 1241 RtSize = 0 1242 # reserve 4K size in SMRAM to make SMM module address not from 0. 1243 SmmSize = 0x1000 1244 IsIpfPlatform = False 1245 if 'IPF' in self.ArchList: 1246 IsIpfPlatform = True 1247 for ModuleGuid in ModuleList: 1248 Module = ModuleList[ModuleGuid] 1249 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget) 1250 1251 OutputImageFile = '' 1252 for ResultFile in Module.CodaTargetList: 1253 if str(ResultFile.Target).endswith('.efi'): 1254 # 1255 # module list for PEI, DXE, RUNTIME and SMM 1256 # 1257 OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi') 1258 ImageClass = PeImageClass (OutputImageFile) 1259 if not ImageClass.IsValid: 1260 EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo) 1261 ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass) 1262 if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER','PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']: 1263 PeiModuleList[Module.MetaFile] = ImageInfo 1264 PeiSize += ImageInfo.Image.Size 1265 elif Module.ModuleType in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']: 1266 BtModuleList[Module.MetaFile] = ImageInfo 1267 BtSize += ImageInfo.Image.Size 1268 elif Module.ModuleType in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']: 1269 RtModuleList[Module.MetaFile] = ImageInfo 1270 #IPF runtime driver needs to be at 2 page alignment. 1271 if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0: 1272 ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000 1273 RtSize += ImageInfo.Image.Size 1274 elif Module.ModuleType in ['SMM_CORE', 'DXE_SMM_DRIVER']: 1275 SmmModuleList[Module.MetaFile] = ImageInfo 1276 SmmSize += ImageInfo.Image.Size 1277 if Module.ModuleType == 'DXE_SMM_DRIVER': 1278 PiSpecVersion = '0x00000000' 1279 if 'PI_SPECIFICATION_VERSION' in Module.Module.Specification: 1280 PiSpecVersion = Module.Module.Specification['PI_SPECIFICATION_VERSION'] 1281 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver. 1282 if int(PiSpecVersion, 16) < 0x0001000A: 1283 BtModuleList[Module.MetaFile] = ImageInfo 1284 BtSize += ImageInfo.Image.Size 1285 break 1286 # 1287 # EFI image is final target. 1288 # Check EFI image contains patchable FixAddress related PCDs. 1289 # 1290 if OutputImageFile != '': 1291 ModuleIsPatch = False 1292 for Pcd in Module.ModulePcdList: 1293 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST: 1294 ModuleIsPatch = True 1295 break 1296 if not ModuleIsPatch: 1297 for Pcd in Module.LibraryPcdList: 1298 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST: 1299 ModuleIsPatch = True 1300 break 1301 1302 if not ModuleIsPatch: 1303 continue 1304 # 1305 # Module includes the patchable load fix address PCDs. 1306 # It will be fixed up later. 1307 # 1308 PatchEfiImageList.append (OutputImageFile) 1309 1310 # 1311 # Get Top Memory address 1312 # 1313 ReservedRuntimeMemorySize = 0 1314 TopMemoryAddress = 0 1315 if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF: 1316 TopMemoryAddress = 0 1317 else: 1318 TopMemoryAddress = self.LoadFixAddress 1319 if TopMemoryAddress < RtSize + BtSize + PeiSize: 1320 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver") 1321 # Make IPF runtime driver at 2 page alignment. 1322 if IsIpfPlatform: 1323 ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000 1324 RtSize = RtSize + ReservedRuntimeMemorySize 1325 1326 # 1327 # Patch FixAddress related PCDs into EFI image 1328 # 1329 for EfiImage in PatchEfiImageList: 1330 EfiImageMap = EfiImage.replace('.efi', '.map') 1331 if not os.path.exists(EfiImageMap): 1332 continue 1333 # 1334 # Get PCD offset in EFI image by GenPatchPcdTable function 1335 # 1336 PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage) 1337 # 1338 # Patch real PCD value by PatchPcdValue tool 1339 # 1340 for PcdInfo in PcdTable: 1341 ReturnValue = 0 1342 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE: 1343 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize/0x1000)) 1344 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE: 1345 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize/0x1000)) 1346 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE: 1347 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize/0x1000)) 1348 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0: 1349 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize/0x1000)) 1350 if ReturnValue != 0: 1351 EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo) 1352 1353 MapBuffer.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize/0x1000)) 1354 MapBuffer.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize/0x1000)) 1355 MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize/0x1000)) 1356 if len (SmmModuleList) > 0: 1357 MapBuffer.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize/0x1000)) 1358 1359 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize 1360 BtBaseAddr = TopMemoryAddress - RtSize 1361 RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize 1362 1363 self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0) 1364 self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0) 1365 self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0) 1366 self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset = False, ModeIsSmm = True) 1367 MapBuffer.write('\n\n') 1368 sys.stdout.write ("\n") 1369 sys.stdout.flush() 1370 1371 ## Save platform Map file 1372 # 1373 def _SaveMapFile (self, MapBuffer, Wa): 1374 # 1375 # Map file path is got. 1376 # 1377 MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map') 1378 # 1379 # Save address map into MAP file. 1380 # 1381 SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False) 1382 MapBuffer.close() 1383 if self.LoadFixAddress != 0: 1384 sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" %(MapFilePath)) 1385 sys.stdout.flush() 1386 1387 ## Build active platform for different build targets and different tool chains 1388 # 1389 def _BuildPlatform(self): 1390 for BuildTarget in self.BuildTargetList: 1391 GlobalData.gGlobalDefines['TARGET'] = BuildTarget 1392 for ToolChain in self.ToolChainList: 1393 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain 1394 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain 1395 Wa = WorkspaceAutoGen( 1396 self.WorkspaceDir, 1397 self.PlatformFile, 1398 BuildTarget, 1399 ToolChain, 1400 self.ArchList, 1401 self.BuildDatabase, 1402 self.TargetTxt, 1403 self.ToolDef, 1404 self.Fdf, 1405 self.FdList, 1406 self.FvList, 1407 self.CapList, 1408 self.SkuId, 1409 self.UniFlag, 1410 self.Progress 1411 ) 1412 self.Fdf = Wa.FdfFile 1413 self.LoadFixAddress = Wa.Platform.LoadFixAddress 1414 self.BuildReport.AddPlatformReport(Wa) 1415 self.Progress.Stop("done!") 1416 for Arch in Wa.ArchList: 1417 GlobalData.gGlobalDefines['ARCH'] = Arch 1418 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch) 1419 for Module in Pa.Platform.Modules: 1420 # Get ModuleAutoGen object to generate C code file and makefile 1421 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile) 1422 if Ma == None: 1423 continue 1424 self.BuildModules.append(Ma) 1425 self._BuildPa(self.Target, Pa) 1426 1427 # Create MAP file when Load Fix Address is enabled. 1428 if self.Target in ["", "all", "fds"]: 1429 for Arch in Wa.ArchList: 1430 GlobalData.gGlobalDefines['ARCH'] = Arch 1431 # 1432 # Check whether the set fix address is above 4G for 32bit image. 1433 # 1434 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000: 1435 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS can't be set to larger than or equal to 4G for the platform with IA32 or ARM arch modules") 1436 # 1437 # Get Module List 1438 # 1439 ModuleList = {} 1440 for Pa in Wa.AutoGenObjectList: 1441 for Ma in Pa.ModuleAutoGenList: 1442 if Ma == None: 1443 continue 1444 if not Ma.IsLibrary: 1445 ModuleList[Ma.Guid.upper()] = Ma 1446 1447 MapBuffer = StringIO('') 1448 if self.LoadFixAddress != 0: 1449 # 1450 # Rebase module to the preferred memory address before GenFds 1451 # 1452 self._CollectModuleMapBuffer(MapBuffer, ModuleList) 1453 if self.Fdf: 1454 # 1455 # create FDS again for the updated EFI image 1456 # 1457 self._Build("fds", Wa) 1458 # 1459 # Create MAP file for all platform FVs after GenFds. 1460 # 1461 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList) 1462 # 1463 # Save MAP buffer into MAP file. 1464 # 1465 self._SaveMapFile (MapBuffer, Wa) 1466 1467 ## Build active module for different build targets, different tool chains and different archs 1468 # 1469 def _BuildModule(self): 1470 for BuildTarget in self.BuildTargetList: 1471 GlobalData.gGlobalDefines['TARGET'] = BuildTarget 1472 for ToolChain in self.ToolChainList: 1473 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain 1474 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain 1475 # 1476 # module build needs platform build information, so get platform 1477 # AutoGen first 1478 # 1479 Wa = WorkspaceAutoGen( 1480 self.WorkspaceDir, 1481 self.PlatformFile, 1482 BuildTarget, 1483 ToolChain, 1484 self.ArchList, 1485 self.BuildDatabase, 1486 self.TargetTxt, 1487 self.ToolDef, 1488 self.Fdf, 1489 self.FdList, 1490 self.FvList, 1491 self.CapList, 1492 self.SkuId, 1493 self.UniFlag, 1494 self.Progress, 1495 self.ModuleFile 1496 ) 1497 self.Fdf = Wa.FdfFile 1498 self.LoadFixAddress = Wa.Platform.LoadFixAddress 1499 Wa.CreateMakeFile(False) 1500 self.Progress.Stop("done!") 1501 MaList = [] 1502 for Arch in Wa.ArchList: 1503 GlobalData.gGlobalDefines['ARCH'] = Arch 1504 Ma = ModuleAutoGen(Wa, self.ModuleFile, BuildTarget, ToolChain, Arch, self.PlatformFile) 1505 if Ma == None: continue 1506 MaList.append(Ma) 1507 self.BuildModules.append(Ma) 1508 if not Ma.IsBinaryModule: 1509 self._Build(self.Target, Ma, BuildModule=True) 1510 1511 self.BuildReport.AddPlatformReport(Wa, MaList) 1512 if MaList == []: 1513 EdkLogger.error( 1514 'build', 1515 BUILD_ERROR, 1516 "Module for [%s] is not a component of active platform."\ 1517 " Please make sure that the ARCH and inf file path are"\ 1518 " given in the same as in [%s]" %\ 1519 (', '.join(Wa.ArchList), self.PlatformFile), 1520 ExtraData=self.ModuleFile 1521 ) 1522 # Create MAP file when Load Fix Address is enabled. 1523 if self.Target == "fds" and self.Fdf: 1524 for Arch in Wa.ArchList: 1525 # 1526 # Check whether the set fix address is above 4G for 32bit image. 1527 # 1528 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000: 1529 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS can't be set to larger than or equal to 4G for the platorm with IA32 or ARM arch modules") 1530 # 1531 # Get Module List 1532 # 1533 ModuleList = {} 1534 for Pa in Wa.AutoGenObjectList: 1535 for Ma in Pa.ModuleAutoGenList: 1536 if Ma == None: 1537 continue 1538 if not Ma.IsLibrary: 1539 ModuleList[Ma.Guid.upper()] = Ma 1540 1541 MapBuffer = StringIO('') 1542 if self.LoadFixAddress != 0: 1543 # 1544 # Rebase module to the preferred memory address before GenFds 1545 # 1546 self._CollectModuleMapBuffer(MapBuffer, ModuleList) 1547 # 1548 # create FDS again for the updated EFI image 1549 # 1550 self._Build("fds", Wa) 1551 # 1552 # Create MAP file for all platform FVs after GenFds. 1553 # 1554 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList) 1555 # 1556 # Save MAP buffer into MAP file. 1557 # 1558 self._SaveMapFile (MapBuffer, Wa) 1559 1560 ## Build a platform in multi-thread mode 1561 # 1562 def _MultiThreadBuildPlatform(self): 1563 for BuildTarget in self.BuildTargetList: 1564 GlobalData.gGlobalDefines['TARGET'] = BuildTarget 1565 for ToolChain in self.ToolChainList: 1566 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain 1567 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain 1568 Wa = WorkspaceAutoGen( 1569 self.WorkspaceDir, 1570 self.PlatformFile, 1571 BuildTarget, 1572 ToolChain, 1573 self.ArchList, 1574 self.BuildDatabase, 1575 self.TargetTxt, 1576 self.ToolDef, 1577 self.Fdf, 1578 self.FdList, 1579 self.FvList, 1580 self.CapList, 1581 self.SkuId, 1582 self.UniFlag, 1583 self.Progress 1584 ) 1585 self.Fdf = Wa.FdfFile 1586 self.LoadFixAddress = Wa.Platform.LoadFixAddress 1587 self.BuildReport.AddPlatformReport(Wa) 1588 Wa.CreateMakeFile(False) 1589 1590 # multi-thread exit flag 1591 ExitFlag = threading.Event() 1592 ExitFlag.clear() 1593 for Arch in Wa.ArchList: 1594 GlobalData.gGlobalDefines['ARCH'] = Arch 1595 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch) 1596 if Pa == None: 1597 continue 1598 ModuleList = [] 1599 for Inf in Pa.Platform.Modules: 1600 ModuleList.append(Inf) 1601 # Add the INF only list in FDF 1602 if GlobalData.gFdfParser != None: 1603 for InfName in GlobalData.gFdfParser.Profile.InfList: 1604 Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch) 1605 if Inf in Pa.Platform.Modules: 1606 continue 1607 ModuleList.append(Inf) 1608 for Module in ModuleList: 1609 # Get ModuleAutoGen object to generate C code file and makefile 1610 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile) 1611 1612 if Ma == None: 1613 continue 1614 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds' 1615 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']: 1616 # for target which must generate AutoGen code and makefile 1617 if not self.SkipAutoGen or self.Target == 'genc': 1618 Ma.CreateCodeFile(True) 1619 if self.Target == "genc": 1620 continue 1621 1622 if not self.SkipAutoGen or self.Target == 'genmake': 1623 Ma.CreateMakeFile(True) 1624 if self.Target == "genmake": 1625 continue 1626 self.BuildModules.append(Ma) 1627 self.Progress.Stop("done!") 1628 1629 for Ma in self.BuildModules: 1630 # Generate build task for the module 1631 if not Ma.IsBinaryModule: 1632 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target)) 1633 # Break build if any build thread has error 1634 if BuildTask.HasError(): 1635 # we need a full version of makefile for platform 1636 ExitFlag.set() 1637 BuildTask.WaitForComplete() 1638 Pa.CreateMakeFile(False) 1639 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule) 1640 # Start task scheduler 1641 if not BuildTask.IsOnGoing(): 1642 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag) 1643 1644 # in case there's an interruption. we need a full version of makefile for platform 1645 Pa.CreateMakeFile(False) 1646 if BuildTask.HasError(): 1647 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule) 1648 1649 # 1650 # Save temp tables to a TmpTableDict. 1651 # 1652 for Key in Wa.BuildDatabase._CACHE_: 1653 if Wa.BuildDatabase._CACHE_[Key]._RawData and Wa.BuildDatabase._CACHE_[Key]._RawData._Table and Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table: 1654 if TemporaryTablePattern.match(Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table): 1655 TmpTableDict[Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table] = Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Cur 1656 # 1657 # 1658 # All modules have been put in build tasks queue. Tell task scheduler 1659 # to exit if all tasks are completed 1660 # 1661 ExitFlag.set() 1662 BuildTask.WaitForComplete() 1663 self.CreateAsBuiltInf() 1664 1665 # 1666 # Check for build error, and raise exception if one 1667 # has been signaled. 1668 # 1669 if BuildTask.HasError(): 1670 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule) 1671 1672 # Create MAP file when Load Fix Address is enabled. 1673 if self.Target in ["", "all", "fds"]: 1674 for Arch in Wa.ArchList: 1675 # 1676 # Check whether the set fix address is above 4G for 32bit image. 1677 # 1678 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000: 1679 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS can't be set to larger than or equal to 4G for the platorm with IA32 or ARM arch modules") 1680 # 1681 # Get Module List 1682 # 1683 ModuleList = {} 1684 for Pa in Wa.AutoGenObjectList: 1685 for Ma in Pa.ModuleAutoGenList: 1686 if Ma == None: 1687 continue 1688 if not Ma.IsLibrary: 1689 ModuleList[Ma.Guid.upper()] = Ma 1690 # 1691 # Rebase module to the preferred memory address before GenFds 1692 # 1693 MapBuffer = StringIO('') 1694 if self.LoadFixAddress != 0: 1695 self._CollectModuleMapBuffer(MapBuffer, ModuleList) 1696 1697 if self.Fdf: 1698 # 1699 # Generate FD image if there's a FDF file found 1700 # 1701 LaunchCommand(Wa.GenFdsCommand, os.getcwd()) 1702 1703 # 1704 # Create MAP file for all platform FVs after GenFds. 1705 # 1706 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList) 1707 # 1708 # Save MAP buffer into MAP file. 1709 # 1710 self._SaveMapFile(MapBuffer, Wa) 1711 1712 ## Generate GuidedSectionTools.txt in the FV directories. 1713 # 1714 def CreateGuidedSectionToolsFile(self): 1715 for BuildTarget in self.BuildTargetList: 1716 for ToolChain in self.ToolChainList: 1717 Wa = WorkspaceAutoGen( 1718 self.WorkspaceDir, 1719 self.PlatformFile, 1720 BuildTarget, 1721 ToolChain, 1722 self.ArchList, 1723 self.BuildDatabase, 1724 self.TargetTxt, 1725 self.ToolDef, 1726 self.Fdf, 1727 self.FdList, 1728 self.FvList, 1729 self.CapList, 1730 self.SkuId, 1731 self.UniFlag 1732 ) 1733 FvDir = Wa.FvDir 1734 if not os.path.exists(FvDir): 1735 continue 1736 1737 for Arch in self.ArchList: 1738 # Build up the list of supported architectures for this build 1739 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch) 1740 1741 # Look through the tool definitions for GUIDed tools 1742 guidAttribs = [] 1743 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems(): 1744 if attrib.upper().endswith('_GUID'): 1745 split = attrib.split('_') 1746 thisPrefix = '_'.join(split[0:3]) + '_' 1747 if thisPrefix == prefix: 1748 guid = self.ToolDef.ToolsDefTxtDictionary[attrib] 1749 guid = guid.lower() 1750 toolName = split[3] 1751 path = '_'.join(split[0:4]) + '_PATH' 1752 path = self.ToolDef.ToolsDefTxtDictionary[path] 1753 path = self.GetFullPathOfTool(path) 1754 guidAttribs.append((guid, toolName, path)) 1755 1756 # Write out GuidedSecTools.txt 1757 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt') 1758 toolsFile = open(toolsFile, 'wt') 1759 for guidedSectionTool in guidAttribs: 1760 print >> toolsFile, ' '.join(guidedSectionTool) 1761 toolsFile.close() 1762 1763 ## Returns the full path of the tool. 1764 # 1765 def GetFullPathOfTool (self, tool): 1766 if os.path.exists(tool): 1767 return os.path.realpath(tool) 1768 else: 1769 # We need to search for the tool using the 1770 # PATH environment variable. 1771 for dirInPath in os.environ['PATH'].split(os.pathsep): 1772 foundPath = os.path.join(dirInPath, tool) 1773 if os.path.exists(foundPath): 1774 return os.path.realpath(foundPath) 1775 1776 # If the tool was not found in the path then we just return 1777 # the input tool. 1778 return tool 1779 1780 ## Launch the module or platform build 1781 # 1782 def Launch(self): 1783 if not self.ModuleFile: 1784 if not self.SpawnMode or self.Target not in ["", "all"]: 1785 self.SpawnMode = False 1786 self._BuildPlatform() 1787 else: 1788 self._MultiThreadBuildPlatform() 1789 self.CreateGuidedSectionToolsFile() 1790 else: 1791 self.SpawnMode = False 1792 self._BuildModule() 1793 1794 if self.Target == 'cleanall': 1795 self.Db.Close() 1796 RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True) 1797 1798 def CreateAsBuiltInf(self): 1799 for Module in self.BuildModules: 1800 Module.CreateAsBuiltInf() 1801 self.BuildModules = [] 1802 ## Do some clean-up works when error occurred 1803 def Relinquish(self): 1804 OldLogLevel = EdkLogger.GetLevel() 1805 EdkLogger.SetLevel(EdkLogger.ERROR) 1806 #self.DumpBuildData() 1807 Utils.Progressor.Abort() 1808 if self.SpawnMode == True: 1809 BuildTask.Abort() 1810 EdkLogger.SetLevel(OldLogLevel) 1811 1812 def DumpBuildData(self): 1813 CacheDirectory = os.path.dirname(GlobalData.gDatabasePath) 1814 Utils.CreateDirectory(CacheDirectory) 1815 Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache")) 1816 Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase")) 1817 1818 def RestoreBuildData(self): 1819 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gFileTimeStampCache") 1820 if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath): 1821 Utils.gFileTimeStampCache = Utils.DataRestore(FilePath) 1822 if Utils.gFileTimeStampCache == None: 1823 Utils.gFileTimeStampCache = {} 1824 1825 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gDependencyDatabase") 1826 if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath): 1827 Utils.gDependencyDatabase = Utils.DataRestore(FilePath) 1828 if Utils.gDependencyDatabase == None: 1829 Utils.gDependencyDatabase = {} 1830 1831def ParseDefines(DefineList=[]): 1832 DefineDict = {} 1833 if DefineList != None: 1834 for Define in DefineList: 1835 DefineTokenList = Define.split("=", 1) 1836 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]): 1837 EdkLogger.error('build', FORMAT_INVALID, 1838 "The macro name must be in the pattern [A-Z][A-Z0-9_]*", 1839 ExtraData=DefineTokenList[0]) 1840 1841 if len(DefineTokenList) == 1: 1842 DefineDict[DefineTokenList[0]] = "TRUE" 1843 else: 1844 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip() 1845 return DefineDict 1846 1847gParamCheck = [] 1848def SingleCheckCallback(option, opt_str, value, parser): 1849 if option not in gParamCheck: 1850 setattr(parser.values, option.dest, value) 1851 gParamCheck.append(option) 1852 else: 1853 parser.error("Option %s only allows one instance in command line!" % option) 1854 1855## Parse command line options 1856# 1857# Using standard Python module optparse to parse command line option of this tool. 1858# 1859# @retval Opt A optparse.Values object containing the parsed options 1860# @retval Args Target of build command 1861# 1862def MyOptionParser(): 1863 Parser = OptionParser(description=__copyright__,version=__version__,prog="build.exe",usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]") 1864 Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32','X64','IPF','EBC','ARM', 'AARCH64'], dest="TargetArch", 1865 help="ARCHS is one of list: IA32, X64, IPF, ARM, AARCH64 or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.") 1866 Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback, 1867 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.") 1868 Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback, 1869 help="Build the module specified by the INF file name argument.") 1870 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.", 1871 action="append") 1872 Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain", 1873 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.") 1874 Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback, 1875 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.") 1876 1877 Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback, 1878 help="Build the platform using multi-threaded compiler. The value overrides target.txt's MAX_CONCURRENT_THREAD_NUMBER. Less than 2 will disable multi-thread builds.") 1879 1880 Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback, 1881 help="The name of the FDF file to use, which overrides the setting in the DSC file.") 1882 Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[], 1883 help="The name of FD to be generated. The name must be from [FD] section in FDF file.") 1884 Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[], 1885 help="The name of FV to be generated. The name must be from [FV] section in FDF file.") 1886 Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[], 1887 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.") 1888 Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.") 1889 Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.") 1890 1891 Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.") 1892 1893 Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.") 1894 Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.") 1895 1896 Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode", 1897 help="Make use of silent mode of (n)make.") 1898 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.") 1899 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\ 1900 "including library instances selected, final dependency expression, "\ 1901 "and warning messages, etc.") 1902 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.") 1903 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".") 1904 1905 Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.") 1906 Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD','LIBRARY','FLASH','DEPEX','BUILD_FLAGS','FIXED_ADDRESS', 'EXECUTION_ORDER'], dest="ReportType", default=[], 1907 help="Flags that control the type of build report to generate. Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, EXECUTION_ORDER]. "\ 1908 "To specify more than one flag, repeat this option on the command line and the default flag set is [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS]") 1909 Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag", 1910 help="Specify the specific option to parse EDK UNI file. Must be one of: [-c, -s]. -c is for EDK framework UNI file, and -s is for EDK UEFI UNI file. "\ 1911 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\ 1912 "will override the setting in [BuildOptions] section of platform DSC.") 1913 Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism") 1914 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.") 1915 Parser.add_option("--check-usage", action="store_true", dest="CheckUsage", default=False, help="Check usage content of entries listed in INF file.") 1916 Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files") 1917 1918 (Opt, Args)=Parser.parse_args() 1919 return (Opt, Args) 1920 1921## Tool entrance method 1922# 1923# This method mainly dispatch specific methods per the command line options. 1924# If no error found, return zero value so the caller of this tool can know 1925# if it's executed successfully or not. 1926# 1927# @retval 0 Tool was successful 1928# @retval 1 Tool failed 1929# 1930def Main(): 1931 StartTime = time.time() 1932 1933 # Initialize log system 1934 EdkLogger.Initialize() 1935 1936 # 1937 # Parse the options and args 1938 # 1939 (Option, Target) = MyOptionParser() 1940 GlobalData.gOptions = Option 1941 GlobalData.gCaseInsensitive = Option.CaseInsensitive 1942 1943 # Set log level 1944 if Option.verbose != None: 1945 EdkLogger.SetLevel(EdkLogger.VERBOSE) 1946 elif Option.quiet != None: 1947 EdkLogger.SetLevel(EdkLogger.QUIET) 1948 elif Option.debug != None: 1949 EdkLogger.SetLevel(Option.debug + 1) 1950 else: 1951 EdkLogger.SetLevel(EdkLogger.INFO) 1952 1953 if Option.LogFile != None: 1954 EdkLogger.SetLogFile(Option.LogFile) 1955 1956 if Option.WarningAsError == True: 1957 EdkLogger.SetWarningAsError() 1958 1959 if platform.platform().find("Windows") >= 0: 1960 GlobalData.gIsWindows = True 1961 else: 1962 GlobalData.gIsWindows = False 1963 1964 EdkLogger.quiet("Build environment: %s" % platform.platform()) 1965 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime())); 1966 ReturnCode = 0 1967 MyBuild = None 1968 try: 1969 if len(Target) == 0: 1970 Target = "all" 1971 elif len(Target) >= 2: 1972 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.", 1973 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget))) 1974 else: 1975 Target = Target[0].lower() 1976 1977 if Target not in gSupportedTarget: 1978 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target, 1979 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget))) 1980 1981 # 1982 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH 1983 # 1984 CheckEnvVariable() 1985 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros)) 1986 1987 Workspace = os.getenv("WORKSPACE") 1988 # 1989 # Get files real name in workspace dir 1990 # 1991 GlobalData.gAllFiles = Utils.DirCache(Workspace) 1992 1993 WorkingDirectory = os.getcwd() 1994 if not Option.ModuleFile: 1995 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf'))) 1996 FileNum = len(FileList) 1997 if FileNum >= 2: 1998 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory), 1999 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.") 2000 elif FileNum == 1: 2001 Option.ModuleFile = NormFile(FileList[0], Workspace) 2002 2003 if Option.ModuleFile: 2004 if os.path.isabs (Option.ModuleFile): 2005 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0: 2006 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace) 2007 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace) 2008 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False) 2009 if ErrorCode != 0: 2010 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo) 2011 2012 if Option.PlatformFile != None: 2013 if os.path.isabs (Option.PlatformFile): 2014 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0: 2015 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace) 2016 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace) 2017 2018 if Option.FdfFile != None: 2019 if os.path.isabs (Option.FdfFile): 2020 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0: 2021 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace) 2022 Option.FdfFile = PathClass(Option.FdfFile, Workspace) 2023 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False) 2024 if ErrorCode != 0: 2025 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo) 2026 2027 if Option.Flag != None and Option.Flag not in ['-c', '-s']: 2028 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s") 2029 2030 MyBuild = Build(Target, Workspace, Option) 2031 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList) 2032 MyBuild.Launch() 2033 # Drop temp tables to avoid database locked. 2034 for TmpTableName in TmpTableDict: 2035 SqlCommand = """drop table IF EXISTS %s""" % TmpTableName 2036 TmpTableDict[TmpTableName].execute(SqlCommand) 2037 #MyBuild.DumpBuildData() 2038 except FatalError, X: 2039 if MyBuild != None: 2040 # for multi-thread build exits safely 2041 MyBuild.Relinquish() 2042 if Option != None and Option.debug != None: 2043 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc()) 2044 ReturnCode = X.args[0] 2045 except Warning, X: 2046 # error from Fdf parser 2047 if MyBuild != None: 2048 # for multi-thread build exits safely 2049 MyBuild.Relinquish() 2050 if Option != None and Option.debug != None: 2051 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc()) 2052 else: 2053 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError = False) 2054 ReturnCode = FORMAT_INVALID 2055 except KeyboardInterrupt: 2056 ReturnCode = ABORT_ERROR 2057 if Option != None and Option.debug != None: 2058 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc()) 2059 except: 2060 if MyBuild != None: 2061 # for multi-thread build exits safely 2062 MyBuild.Relinquish() 2063 2064 # try to get the meta-file from the object causing exception 2065 Tb = sys.exc_info()[-1] 2066 MetaFile = GlobalData.gProcessingFile 2067 while Tb != None: 2068 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'): 2069 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile 2070 Tb = Tb.tb_next 2071 EdkLogger.error( 2072 "\nbuild", 2073 CODE_ERROR, 2074 "Unknown fatal error when processing [%s]" % MetaFile, 2075 ExtraData="\n(Please send email to edk2-devel@lists.sourceforge.net for help, attaching following call stack trace!)\n", 2076 RaiseError=False 2077 ) 2078 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc()) 2079 ReturnCode = CODE_ERROR 2080 finally: 2081 Utils.Progressor.Abort() 2082 Utils.ClearDuplicatedInf() 2083 2084 if ReturnCode == 0: 2085 Conclusion = "Done" 2086 elif ReturnCode == ABORT_ERROR: 2087 Conclusion = "Aborted" 2088 else: 2089 Conclusion = "Failed" 2090 FinishTime = time.time() 2091 BuildDuration = time.gmtime(int(round(FinishTime - StartTime))) 2092 BuildDurationStr = "" 2093 if BuildDuration.tm_yday > 1: 2094 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)"%(BuildDuration.tm_yday - 1) 2095 else: 2096 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) 2097 if MyBuild != None: 2098 MyBuild.BuildReport.GenerateReport(BuildDurationStr) 2099 MyBuild.Db.Close() 2100 EdkLogger.SetLevel(EdkLogger.QUIET) 2101 EdkLogger.quiet("\n- %s -" % Conclusion) 2102 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime())) 2103 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr) 2104 return ReturnCode 2105 2106if __name__ == '__main__': 2107 r = Main() 2108 ## 0-127 is a safe return range, and 1 is a standard default error 2109 if r < 0 or r > 127: r = 1 2110 sys.exit(r) 2111 2112