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