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