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