]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/build/build.py
Fix ‘build run’ doesn’t work for NT32 X64 build.
[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 - 2014, 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 # genfds
936 if Target == 'fds':
937 LaunchCommand(AutoGenObject.GenFdsCommand, AutoGenObject.MakeFileDir)
938 return True
939
940 # run
941 if Target == 'run':
942 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))
943 Command = '.\SecMain'
944 os.chdir(RunDir)
945 LaunchCommand(Command, RunDir)
946 return True
947
948 # build modules
949 if BuildModule:
950 BuildCommand = BuildCommand + [Target]
951 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
952 self.CreateAsBuiltInf()
953 return True
954
955 # build library
956 if Target == 'libraries':
957 for Lib in AutoGenObject.LibraryBuildDirectoryList:
958 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']
959 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
960 return True
961
962 # build module
963 if Target == 'modules':
964 for Lib in AutoGenObject.LibraryBuildDirectoryList:
965 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']
966 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
967 for Mod in AutoGenObject.ModuleBuildDirectoryList:
968 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']
969 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
970 self.CreateAsBuiltInf()
971 return True
972
973 # cleanlib
974 if Target == 'cleanlib':
975 for Lib in AutoGenObject.LibraryBuildDirectoryList:
976 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))
977 if os.path.exists(LibMakefile):
978 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
979 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
980 return True
981
982 # clean
983 if Target == 'clean':
984 for Mod in AutoGenObject.ModuleBuildDirectoryList:
985 ModMakefile = os.path.normpath(os.path.join(Mod, makefile))
986 if os.path.exists(ModMakefile):
987 NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']
988 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
989 for Lib in AutoGenObject.LibraryBuildDirectoryList:
990 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))
991 if os.path.exists(LibMakefile):
992 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
993 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
994 return True
995
996 # cleanall
997 if Target == 'cleanall':
998 try:
999 #os.rmdir(AutoGenObject.BuildDir)
1000 RemoveDirectory(AutoGenObject.BuildDir, True)
1001 except WindowsError, X:
1002 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
1003 return True
1004
1005 ## Build a module or platform
1006 #
1007 # Create autogen code and makefile for a module or platform, and the launch
1008 # "make" command to build it
1009 #
1010 # @param Target The target of build command
1011 # @param Platform The platform file
1012 # @param Module The module file
1013 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1014 # @param ToolChain The name of toolchain to build
1015 # @param Arch The arch of the module/platform
1016 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1017 # for dependent modules/Libraries
1018 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1019 # for dependent modules/Libraries
1020 #
1021 def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):
1022 if AutoGenObject == None:
1023 return False
1024
1025 # skip file generation for cleanxxx targets, run and fds target
1026 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1027 # for target which must generate AutoGen code and makefile
1028 if not self.SkipAutoGen or Target == 'genc':
1029 self.Progress.Start("Generating code")
1030 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
1031 self.Progress.Stop("done!")
1032 if Target == "genc":
1033 return True
1034
1035 if not self.SkipAutoGen or Target == 'genmake':
1036 self.Progress.Start("Generating makefile")
1037 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)
1038 #AutoGenObject.CreateAsBuiltInf()
1039 self.Progress.Stop("done!")
1040 if Target == "genmake":
1041 return True
1042 else:
1043 # always recreate top/platform makefile when clean, just in case of inconsistency
1044 AutoGenObject.CreateCodeFile(False)
1045 AutoGenObject.CreateMakeFile(False)
1046
1047 if EdkLogger.GetLevel() == EdkLogger.QUIET:
1048 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
1049
1050 BuildCommand = AutoGenObject.BuildCommand
1051 if BuildCommand == None or len(BuildCommand) == 0:
1052 EdkLogger.error("build", OPTION_MISSING,
1053 "No build command found for this module. "
1054 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1055 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
1056 ExtraData=str(AutoGenObject))
1057
1058 # genfds
1059 if Target == 'fds':
1060 LaunchCommand(AutoGenObject.GenFdsCommand, AutoGenObject.MakeFileDir)
1061 return True
1062
1063 # run
1064 if Target == 'run':
1065 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))
1066 Command = '.\SecMain'
1067 os.chdir(RunDir)
1068 LaunchCommand(Command, RunDir)
1069 return True
1070
1071 # build modules
1072 BuildCommand = BuildCommand + [Target]
1073 if BuildModule:
1074 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
1075 self.CreateAsBuiltInf()
1076 return True
1077
1078 # build library
1079 if Target == 'libraries':
1080 pass
1081
1082 # not build modules
1083
1084
1085 # cleanall
1086 if Target == 'cleanall':
1087 try:
1088 #os.rmdir(AutoGenObject.BuildDir)
1089 RemoveDirectory(AutoGenObject.BuildDir, True)
1090 except WindowsError, X:
1091 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
1092 return True
1093
1094 ## Rebase module image and Get function address for the input module list.
1095 #
1096 def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):
1097 if ModeIsSmm:
1098 AddrIsOffset = False
1099 InfFileNameList = ModuleList.keys()
1100 #InfFileNameList.sort()
1101 for InfFile in InfFileNameList:
1102 sys.stdout.write (".")
1103 sys.stdout.flush()
1104 ModuleInfo = ModuleList[InfFile]
1105 ModuleName = ModuleInfo.BaseName
1106 ModuleOutputImage = ModuleInfo.Image.FileName
1107 ModuleDebugImage = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')
1108 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1109 if not ModeIsSmm:
1110 BaseAddress = BaseAddress - ModuleInfo.Image.Size
1111 #
1112 # Update Image to new BaseAddress by GenFw tool
1113 #
1114 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
1115 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
1116 else:
1117 #
1118 # Set new address to the section header only for SMM driver.
1119 #
1120 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
1121 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
1122 #
1123 # Collect funtion address from Map file
1124 #
1125 ImageMapTable = ModuleOutputImage.replace('.efi', '.map')
1126 FunctionList = []
1127 if os.path.exists(ImageMapTable):
1128 OrigImageBaseAddress = 0
1129 ImageMap = open (ImageMapTable, 'r')
1130 for LinStr in ImageMap:
1131 if len (LinStr.strip()) == 0:
1132 continue
1133 #
1134 # Get the preferred address set on link time.
1135 #
1136 if LinStr.find ('Preferred load address is') != -1:
1137 StrList = LinStr.split()
1138 OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)
1139
1140 StrList = LinStr.split()
1141 if len (StrList) > 4:
1142 if StrList[3] == 'f' or StrList[3] =='F':
1143 Name = StrList[1]
1144 RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress
1145 FunctionList.append ((Name, RelativeAddress))
1146 if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'):
1147 #
1148 # Get the real entry point address for IPF image.
1149 #
1150 ModuleInfo.Image.EntryPoint = RelativeAddress
1151 ImageMap.close()
1152 #
1153 # Add general information.
1154 #
1155 if ModeIsSmm:
1156 MapBuffer.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
1157 elif AddrIsOffset:
1158 MapBuffer.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))
1159 else:
1160 MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
1161 #
1162 # Add guid and general seciton section.
1163 #
1164 TextSectionAddress = 0
1165 DataSectionAddress = 0
1166 for SectionHeader in ModuleInfo.Image.SectionHeaderList:
1167 if SectionHeader[0] == '.text':
1168 TextSectionAddress = SectionHeader[1]
1169 elif SectionHeader[0] in ['.data', '.sdata']:
1170 DataSectionAddress = SectionHeader[1]
1171 if AddrIsOffset:
1172 MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))
1173 else:
1174 MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))
1175 #
1176 # Add debug image full path.
1177 #
1178 MapBuffer.write('(IMAGE=%s)\n\n' % (ModuleDebugImage))
1179 #
1180 # Add funtion address
1181 #
1182 for Function in FunctionList:
1183 if AddrIsOffset:
1184 MapBuffer.write(' -0x%010X %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))
1185 else:
1186 MapBuffer.write(' 0x%010X %s\n' % (BaseAddress + Function[1], Function[0]))
1187 ImageMap.close()
1188
1189 #
1190 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1191 #
1192 if ModeIsSmm:
1193 BaseAddress = BaseAddress + ModuleInfo.Image.Size
1194
1195 ## Collect MAP information of all FVs
1196 #
1197 def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):
1198 if self.Fdf:
1199 # First get the XIP base address for FV map file.
1200 GuidPattern = re.compile("[-a-fA-F0-9]+")
1201 GuidName = re.compile("\(GUID=[-a-fA-F0-9]+")
1202 for FvName in Wa.FdfProfile.FvDict.keys():
1203 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')
1204 if not os.path.exists(FvMapBuffer):
1205 continue
1206 FvMap = open(FvMapBuffer, 'r')
1207 #skip FV size information
1208 FvMap.readline()
1209 FvMap.readline()
1210 FvMap.readline()
1211 FvMap.readline()
1212 for Line in FvMap:
1213 MatchGuid = GuidPattern.match(Line)
1214 if MatchGuid != None:
1215 #
1216 # Replace GUID with module name
1217 #
1218 GuidString = MatchGuid.group()
1219 if GuidString.upper() in ModuleList:
1220 Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)
1221 MapBuffer.write('%s' % (Line))
1222 #
1223 # Add the debug image full path.
1224 #
1225 MatchGuid = GuidName.match(Line)
1226 if MatchGuid != None:
1227 GuidString = MatchGuid.group().split("=")[1]
1228 if GuidString.upper() in ModuleList:
1229 MapBuffer.write('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))
1230
1231 FvMap.close()
1232
1233 ## Collect MAP information of all modules
1234 #
1235 def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):
1236 sys.stdout.write ("Generate Load Module At Fix Address Map")
1237 sys.stdout.flush()
1238 PatchEfiImageList = []
1239 PeiModuleList = {}
1240 BtModuleList = {}
1241 RtModuleList = {}
1242 SmmModuleList = {}
1243 PeiSize = 0
1244 BtSize = 0
1245 RtSize = 0
1246 # reserve 4K size in SMRAM to make SMM module address not from 0.
1247 SmmSize = 0x1000
1248 IsIpfPlatform = False
1249 if 'IPF' in self.ArchList:
1250 IsIpfPlatform = True
1251 for ModuleGuid in ModuleList:
1252 Module = ModuleList[ModuleGuid]
1253 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)
1254
1255 OutputImageFile = ''
1256 for ResultFile in Module.CodaTargetList:
1257 if str(ResultFile.Target).endswith('.efi'):
1258 #
1259 # module list for PEI, DXE, RUNTIME and SMM
1260 #
1261 OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')
1262 ImageClass = PeImageClass (OutputImageFile)
1263 if not ImageClass.IsValid:
1264 EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)
1265 ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)
1266 if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER','PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']:
1267 PeiModuleList[Module.MetaFile] = ImageInfo
1268 PeiSize += ImageInfo.Image.Size
1269 elif Module.ModuleType in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']:
1270 BtModuleList[Module.MetaFile] = ImageInfo
1271 BtSize += ImageInfo.Image.Size
1272 elif Module.ModuleType in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']:
1273 RtModuleList[Module.MetaFile] = ImageInfo
1274 #IPF runtime driver needs to be at 2 page alignment.
1275 if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0:
1276 ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000
1277 RtSize += ImageInfo.Image.Size
1278 elif Module.ModuleType in ['SMM_CORE', 'DXE_SMM_DRIVER']:
1279 SmmModuleList[Module.MetaFile] = ImageInfo
1280 SmmSize += ImageInfo.Image.Size
1281 if Module.ModuleType == 'DXE_SMM_DRIVER':
1282 PiSpecVersion = '0x00000000'
1283 if 'PI_SPECIFICATION_VERSION' in Module.Module.Specification:
1284 PiSpecVersion = Module.Module.Specification['PI_SPECIFICATION_VERSION']
1285 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1286 if int(PiSpecVersion, 16) < 0x0001000A:
1287 BtModuleList[Module.MetaFile] = ImageInfo
1288 BtSize += ImageInfo.Image.Size
1289 break
1290 #
1291 # EFI image is final target.
1292 # Check EFI image contains patchable FixAddress related PCDs.
1293 #
1294 if OutputImageFile != '':
1295 ModuleIsPatch = False
1296 for Pcd in Module.ModulePcdList:
1297 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:
1298 ModuleIsPatch = True
1299 break
1300 if not ModuleIsPatch:
1301 for Pcd in Module.LibraryPcdList:
1302 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:
1303 ModuleIsPatch = True
1304 break
1305
1306 if not ModuleIsPatch:
1307 continue
1308 #
1309 # Module includes the patchable load fix address PCDs.
1310 # It will be fixed up later.
1311 #
1312 PatchEfiImageList.append (OutputImageFile)
1313
1314 #
1315 # Get Top Memory address
1316 #
1317 ReservedRuntimeMemorySize = 0
1318 TopMemoryAddress = 0
1319 if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:
1320 TopMemoryAddress = 0
1321 else:
1322 TopMemoryAddress = self.LoadFixAddress
1323 if TopMemoryAddress < RtSize + BtSize + PeiSize:
1324 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1325 # Make IPF runtime driver at 2 page alignment.
1326 if IsIpfPlatform:
1327 ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000
1328 RtSize = RtSize + ReservedRuntimeMemorySize
1329
1330 #
1331 # Patch FixAddress related PCDs into EFI image
1332 #
1333 for EfiImage in PatchEfiImageList:
1334 EfiImageMap = EfiImage.replace('.efi', '.map')
1335 if not os.path.exists(EfiImageMap):
1336 continue
1337 #
1338 # Get PCD offset in EFI image by GenPatchPcdTable function
1339 #
1340 PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)
1341 #
1342 # Patch real PCD value by PatchPcdValue tool
1343 #
1344 for PcdInfo in PcdTable:
1345 ReturnValue = 0
1346 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:
1347 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize/0x1000))
1348 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:
1349 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize/0x1000))
1350 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:
1351 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize/0x1000))
1352 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:
1353 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize/0x1000))
1354 if ReturnValue != 0:
1355 EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)
1356
1357 MapBuffer.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize/0x1000))
1358 MapBuffer.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize/0x1000))
1359 MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize/0x1000))
1360 if len (SmmModuleList) > 0:
1361 MapBuffer.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize/0x1000))
1362
1363 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize
1364 BtBaseAddr = TopMemoryAddress - RtSize
1365 RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize
1366
1367 self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)
1368 self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)
1369 self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)
1370 self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset = False, ModeIsSmm = True)
1371 MapBuffer.write('\n\n')
1372 sys.stdout.write ("\n")
1373 sys.stdout.flush()
1374
1375 ## Save platform Map file
1376 #
1377 def _SaveMapFile (self, MapBuffer, Wa):
1378 #
1379 # Map file path is got.
1380 #
1381 MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')
1382 #
1383 # Save address map into MAP file.
1384 #
1385 SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)
1386 MapBuffer.close()
1387 if self.LoadFixAddress != 0:
1388 sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" %(MapFilePath))
1389 sys.stdout.flush()
1390
1391 ## Build active platform for different build targets and different tool chains
1392 #
1393 def _BuildPlatform(self):
1394 for BuildTarget in self.BuildTargetList:
1395 GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1396 for ToolChain in self.ToolChainList:
1397 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1398 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1399 Wa = WorkspaceAutoGen(
1400 self.WorkspaceDir,
1401 self.PlatformFile,
1402 BuildTarget,
1403 ToolChain,
1404 self.ArchList,
1405 self.BuildDatabase,
1406 self.TargetTxt,
1407 self.ToolDef,
1408 self.Fdf,
1409 self.FdList,
1410 self.FvList,
1411 self.CapList,
1412 self.SkuId,
1413 self.UniFlag,
1414 self.Progress
1415 )
1416 self.Fdf = Wa.FdfFile
1417 self.LoadFixAddress = Wa.Platform.LoadFixAddress
1418 self.BuildReport.AddPlatformReport(Wa)
1419 self.Progress.Stop("done!")
1420 for Arch in Wa.ArchList:
1421 GlobalData.gGlobalDefines['ARCH'] = Arch
1422 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
1423 for Module in Pa.Platform.Modules:
1424 # Get ModuleAutoGen object to generate C code file and makefile
1425 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
1426 if Ma == None:
1427 continue
1428 self.BuildModules.append(Ma)
1429 self._BuildPa(self.Target, Pa)
1430
1431 # Create MAP file when Load Fix Address is enabled.
1432 if self.Target in ["", "all", "fds"]:
1433 for Arch in Wa.ArchList:
1434 GlobalData.gGlobalDefines['ARCH'] = Arch
1435 #
1436 # Check whether the set fix address is above 4G for 32bit image.
1437 #
1438 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1439 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")
1440 #
1441 # Get Module List
1442 #
1443 ModuleList = {}
1444 for Pa in Wa.AutoGenObjectList:
1445 for Ma in Pa.ModuleAutoGenList:
1446 if Ma == None:
1447 continue
1448 if not Ma.IsLibrary:
1449 ModuleList[Ma.Guid.upper()] = Ma
1450
1451 MapBuffer = StringIO('')
1452 if self.LoadFixAddress != 0:
1453 #
1454 # Rebase module to the preferred memory address before GenFds
1455 #
1456 self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1457 if self.Fdf:
1458 #
1459 # create FDS again for the updated EFI image
1460 #
1461 self._Build("fds", Wa)
1462 if self.Fdf:
1463 #
1464 # Create MAP file for all platform FVs after GenFds.
1465 #
1466 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1467 #
1468 # Save MAP buffer into MAP file.
1469 #
1470 self._SaveMapFile (MapBuffer, Wa)
1471
1472 ## Build active module for different build targets, different tool chains and different archs
1473 #
1474 def _BuildModule(self):
1475 for BuildTarget in self.BuildTargetList:
1476 GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1477 for ToolChain in self.ToolChainList:
1478 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1479 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1480 #
1481 # module build needs platform build information, so get platform
1482 # AutoGen first
1483 #
1484 Wa = WorkspaceAutoGen(
1485 self.WorkspaceDir,
1486 self.PlatformFile,
1487 BuildTarget,
1488 ToolChain,
1489 self.ArchList,
1490 self.BuildDatabase,
1491 self.TargetTxt,
1492 self.ToolDef,
1493 self.Fdf,
1494 self.FdList,
1495 self.FvList,
1496 self.CapList,
1497 self.SkuId,
1498 self.UniFlag,
1499 self.Progress,
1500 self.ModuleFile
1501 )
1502 self.Fdf = Wa.FdfFile
1503 self.LoadFixAddress = Wa.Platform.LoadFixAddress
1504 Wa.CreateMakeFile(False)
1505 self.Progress.Stop("done!")
1506 MaList = []
1507 for Arch in Wa.ArchList:
1508 GlobalData.gGlobalDefines['ARCH'] = Arch
1509 Ma = ModuleAutoGen(Wa, self.ModuleFile, BuildTarget, ToolChain, Arch, self.PlatformFile)
1510 if Ma == None: continue
1511 MaList.append(Ma)
1512 self.BuildModules.append(Ma)
1513 if not Ma.IsBinaryModule:
1514 self._Build(self.Target, Ma, BuildModule=True)
1515
1516 self.BuildReport.AddPlatformReport(Wa, MaList)
1517 if MaList == []:
1518 EdkLogger.error(
1519 'build',
1520 BUILD_ERROR,
1521 "Module for [%s] is not a component of active platform."\
1522 " Please make sure that the ARCH and inf file path are"\
1523 " given in the same as in [%s]" %\
1524 (', '.join(Wa.ArchList), self.PlatformFile),
1525 ExtraData=self.ModuleFile
1526 )
1527 # Create MAP file when Load Fix Address is enabled.
1528 if self.Target == "fds" and self.Fdf:
1529 for Arch in Wa.ArchList:
1530 #
1531 # Check whether the set fix address is above 4G for 32bit image.
1532 #
1533 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1534 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")
1535 #
1536 # Get Module List
1537 #
1538 ModuleList = {}
1539 for Pa in Wa.AutoGenObjectList:
1540 for Ma in Pa.ModuleAutoGenList:
1541 if Ma == None:
1542 continue
1543 if not Ma.IsLibrary:
1544 ModuleList[Ma.Guid.upper()] = Ma
1545
1546 MapBuffer = StringIO('')
1547 if self.LoadFixAddress != 0:
1548 #
1549 # Rebase module to the preferred memory address before GenFds
1550 #
1551 self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1552 #
1553 # create FDS again for the updated EFI image
1554 #
1555 self._Build("fds", Wa)
1556 #
1557 # Create MAP file for all platform FVs after GenFds.
1558 #
1559 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1560 #
1561 # Save MAP buffer into MAP file.
1562 #
1563 self._SaveMapFile (MapBuffer, Wa)
1564
1565 ## Build a platform in multi-thread mode
1566 #
1567 def _MultiThreadBuildPlatform(self):
1568 for BuildTarget in self.BuildTargetList:
1569 GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1570 for ToolChain in self.ToolChainList:
1571 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1572 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1573 Wa = WorkspaceAutoGen(
1574 self.WorkspaceDir,
1575 self.PlatformFile,
1576 BuildTarget,
1577 ToolChain,
1578 self.ArchList,
1579 self.BuildDatabase,
1580 self.TargetTxt,
1581 self.ToolDef,
1582 self.Fdf,
1583 self.FdList,
1584 self.FvList,
1585 self.CapList,
1586 self.SkuId,
1587 self.UniFlag,
1588 self.Progress
1589 )
1590 self.Fdf = Wa.FdfFile
1591 self.LoadFixAddress = Wa.Platform.LoadFixAddress
1592 self.BuildReport.AddPlatformReport(Wa)
1593 Wa.CreateMakeFile(False)
1594
1595 # multi-thread exit flag
1596 ExitFlag = threading.Event()
1597 ExitFlag.clear()
1598 for Arch in Wa.ArchList:
1599 GlobalData.gGlobalDefines['ARCH'] = Arch
1600 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
1601 if Pa == None:
1602 continue
1603 ModuleList = []
1604 for Inf in Pa.Platform.Modules:
1605 ModuleList.append(Inf)
1606 # Add the INF only list in FDF
1607 if GlobalData.gFdfParser != None:
1608 for InfName in GlobalData.gFdfParser.Profile.InfList:
1609 Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)
1610 if Inf in Pa.Platform.Modules:
1611 continue
1612 ModuleList.append(Inf)
1613 for Module in ModuleList:
1614 # Get ModuleAutoGen object to generate C code file and makefile
1615 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
1616
1617 if Ma == None:
1618 continue
1619 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1620 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1621 # for target which must generate AutoGen code and makefile
1622 if not self.SkipAutoGen or self.Target == 'genc':
1623 Ma.CreateCodeFile(True)
1624 if self.Target == "genc":
1625 continue
1626
1627 if not self.SkipAutoGen or self.Target == 'genmake':
1628 Ma.CreateMakeFile(True)
1629 if self.Target == "genmake":
1630 continue
1631 self.BuildModules.append(Ma)
1632 self.Progress.Stop("done!")
1633
1634 for Ma in self.BuildModules:
1635 # Generate build task for the module
1636 if not Ma.IsBinaryModule:
1637 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))
1638 # Break build if any build thread has error
1639 if BuildTask.HasError():
1640 # we need a full version of makefile for platform
1641 ExitFlag.set()
1642 BuildTask.WaitForComplete()
1643 Pa.CreateMakeFile(False)
1644 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1645 # Start task scheduler
1646 if not BuildTask.IsOnGoing():
1647 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
1648
1649 # in case there's an interruption. we need a full version of makefile for platform
1650 Pa.CreateMakeFile(False)
1651 if BuildTask.HasError():
1652 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1653
1654 #
1655 # Save temp tables to a TmpTableDict.
1656 #
1657 for Key in Wa.BuildDatabase._CACHE_:
1658 if Wa.BuildDatabase._CACHE_[Key]._RawData and Wa.BuildDatabase._CACHE_[Key]._RawData._Table and Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table:
1659 if TemporaryTablePattern.match(Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table):
1660 TmpTableDict[Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table] = Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Cur
1661 #
1662 #
1663 # All modules have been put in build tasks queue. Tell task scheduler
1664 # to exit if all tasks are completed
1665 #
1666 ExitFlag.set()
1667 BuildTask.WaitForComplete()
1668 self.CreateAsBuiltInf()
1669
1670 #
1671 # Check for build error, and raise exception if one
1672 # has been signaled.
1673 #
1674 if BuildTask.HasError():
1675 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1676
1677 # Create MAP file when Load Fix Address is enabled.
1678 if self.Target in ["", "all", "fds"]:
1679 for Arch in Wa.ArchList:
1680 #
1681 # Check whether the set fix address is above 4G for 32bit image.
1682 #
1683 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1684 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")
1685 #
1686 # Get Module List
1687 #
1688 ModuleList = {}
1689 for Pa in Wa.AutoGenObjectList:
1690 for Ma in Pa.ModuleAutoGenList:
1691 if Ma == None:
1692 continue
1693 if not Ma.IsLibrary:
1694 ModuleList[Ma.Guid.upper()] = Ma
1695 #
1696 # Rebase module to the preferred memory address before GenFds
1697 #
1698 MapBuffer = StringIO('')
1699 if self.LoadFixAddress != 0:
1700 self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1701
1702 if self.Fdf:
1703 #
1704 # Generate FD image if there's a FDF file found
1705 #
1706 LaunchCommand(Wa.GenFdsCommand, os.getcwd())
1707
1708 #
1709 # Create MAP file for all platform FVs after GenFds.
1710 #
1711 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1712 #
1713 # Save MAP buffer into MAP file.
1714 #
1715 self._SaveMapFile(MapBuffer, Wa)
1716
1717 ## Generate GuidedSectionTools.txt in the FV directories.
1718 #
1719 def CreateGuidedSectionToolsFile(self):
1720 for BuildTarget in self.BuildTargetList:
1721 for ToolChain in self.ToolChainList:
1722 Wa = WorkspaceAutoGen(
1723 self.WorkspaceDir,
1724 self.PlatformFile,
1725 BuildTarget,
1726 ToolChain,
1727 self.ArchList,
1728 self.BuildDatabase,
1729 self.TargetTxt,
1730 self.ToolDef,
1731 self.Fdf,
1732 self.FdList,
1733 self.FvList,
1734 self.CapList,
1735 self.SkuId,
1736 self.UniFlag
1737 )
1738 FvDir = Wa.FvDir
1739 if not os.path.exists(FvDir):
1740 continue
1741
1742 for Arch in self.ArchList:
1743 # Build up the list of supported architectures for this build
1744 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)
1745
1746 # Look through the tool definitions for GUIDed tools
1747 guidAttribs = []
1748 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():
1749 if attrib.upper().endswith('_GUID'):
1750 split = attrib.split('_')
1751 thisPrefix = '_'.join(split[0:3]) + '_'
1752 if thisPrefix == prefix:
1753 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]
1754 guid = guid.lower()
1755 toolName = split[3]
1756 path = '_'.join(split[0:4]) + '_PATH'
1757 path = self.ToolDef.ToolsDefTxtDictionary[path]
1758 path = self.GetFullPathOfTool(path)
1759 guidAttribs.append((guid, toolName, path))
1760
1761 # Write out GuidedSecTools.txt
1762 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')
1763 toolsFile = open(toolsFile, 'wt')
1764 for guidedSectionTool in guidAttribs:
1765 print >> toolsFile, ' '.join(guidedSectionTool)
1766 toolsFile.close()
1767
1768 ## Returns the full path of the tool.
1769 #
1770 def GetFullPathOfTool (self, tool):
1771 if os.path.exists(tool):
1772 return os.path.realpath(tool)
1773 else:
1774 # We need to search for the tool using the
1775 # PATH environment variable.
1776 for dirInPath in os.environ['PATH'].split(os.pathsep):
1777 foundPath = os.path.join(dirInPath, tool)
1778 if os.path.exists(foundPath):
1779 return os.path.realpath(foundPath)
1780
1781 # If the tool was not found in the path then we just return
1782 # the input tool.
1783 return tool
1784
1785 ## Launch the module or platform build
1786 #
1787 def Launch(self):
1788 if not self.ModuleFile:
1789 if not self.SpawnMode or self.Target not in ["", "all"]:
1790 self.SpawnMode = False
1791 self._BuildPlatform()
1792 else:
1793 self._MultiThreadBuildPlatform()
1794 self.CreateGuidedSectionToolsFile()
1795 else:
1796 self.SpawnMode = False
1797 self._BuildModule()
1798
1799 if self.Target == 'cleanall':
1800 self.Db.Close()
1801 RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)
1802
1803 def CreateAsBuiltInf(self):
1804 for Module in self.BuildModules:
1805 Module.CreateAsBuiltInf()
1806 self.BuildModules = []
1807 ## Do some clean-up works when error occurred
1808 def Relinquish(self):
1809 OldLogLevel = EdkLogger.GetLevel()
1810 EdkLogger.SetLevel(EdkLogger.ERROR)
1811 #self.DumpBuildData()
1812 Utils.Progressor.Abort()
1813 if self.SpawnMode == True:
1814 BuildTask.Abort()
1815 EdkLogger.SetLevel(OldLogLevel)
1816
1817 def DumpBuildData(self):
1818 CacheDirectory = os.path.dirname(GlobalData.gDatabasePath)
1819 Utils.CreateDirectory(CacheDirectory)
1820 Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))
1821 Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))
1822
1823 def RestoreBuildData(self):
1824 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gFileTimeStampCache")
1825 if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):
1826 Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)
1827 if Utils.gFileTimeStampCache == None:
1828 Utils.gFileTimeStampCache = {}
1829
1830 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gDependencyDatabase")
1831 if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):
1832 Utils.gDependencyDatabase = Utils.DataRestore(FilePath)
1833 if Utils.gDependencyDatabase == None:
1834 Utils.gDependencyDatabase = {}
1835
1836 def ParseDefines(DefineList=[]):
1837 DefineDict = {}
1838 if DefineList != None:
1839 for Define in DefineList:
1840 DefineTokenList = Define.split("=", 1)
1841 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):
1842 EdkLogger.error('build', FORMAT_INVALID,
1843 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
1844 ExtraData=DefineTokenList[0])
1845
1846 if len(DefineTokenList) == 1:
1847 DefineDict[DefineTokenList[0]] = "TRUE"
1848 else:
1849 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()
1850 return DefineDict
1851
1852 gParamCheck = []
1853 def SingleCheckCallback(option, opt_str, value, parser):
1854 if option not in gParamCheck:
1855 setattr(parser.values, option.dest, value)
1856 gParamCheck.append(option)
1857 else:
1858 parser.error("Option %s only allows one instance in command line!" % option)
1859
1860 ## Parse command line options
1861 #
1862 # Using standard Python module optparse to parse command line option of this tool.
1863 #
1864 # @retval Opt A optparse.Values object containing the parsed options
1865 # @retval Args Target of build command
1866 #
1867 def MyOptionParser():
1868 Parser = OptionParser(description=__copyright__,version=__version__,prog="build.exe",usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
1869 Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32','X64','IPF','EBC','ARM', 'AARCH64'], dest="TargetArch",
1870 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.")
1871 Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,
1872 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
1873 Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,
1874 help="Build the module specified by the INF file name argument.")
1875 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
1876 action="append")
1877 Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",
1878 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
1879 Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,
1880 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
1881
1882 Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,
1883 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.")
1884
1885 Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,
1886 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
1887 Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],
1888 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
1889 Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],
1890 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
1891 Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],
1892 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
1893 Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")
1894 Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")
1895
1896 Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.")
1897
1898 Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")
1899 Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")
1900
1901 Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",
1902 help="Make use of silent mode of (n)make.")
1903 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
1904 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
1905 "including library instances selected, final dependency expression, "\
1906 "and warning messages, etc.")
1907 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
1908 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
1909
1910 Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")
1911 Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD','LIBRARY','FLASH','DEPEX','BUILD_FLAGS','FIXED_ADDRESS', 'EXECUTION_ORDER'], dest="ReportType", default=[],
1912 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]. "\
1913 "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]")
1914 Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",
1915 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. "\
1916 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
1917 "will override the setting in [BuildOptions] section of platform DSC.")
1918 Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism")
1919 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")
1920 Parser.add_option("--check-usage", action="store_true", dest="CheckUsage", default=False, help="Check usage content of entries listed in INF file.")
1921 Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")
1922
1923 (Opt, Args)=Parser.parse_args()
1924 return (Opt, Args)
1925
1926 ## Tool entrance method
1927 #
1928 # This method mainly dispatch specific methods per the command line options.
1929 # If no error found, return zero value so the caller of this tool can know
1930 # if it's executed successfully or not.
1931 #
1932 # @retval 0 Tool was successful
1933 # @retval 1 Tool failed
1934 #
1935 def Main():
1936 StartTime = time.time()
1937
1938 # Initialize log system
1939 EdkLogger.Initialize()
1940
1941 #
1942 # Parse the options and args
1943 #
1944 (Option, Target) = MyOptionParser()
1945 GlobalData.gOptions = Option
1946 GlobalData.gCaseInsensitive = Option.CaseInsensitive
1947
1948 # Set log level
1949 if Option.verbose != None:
1950 EdkLogger.SetLevel(EdkLogger.VERBOSE)
1951 elif Option.quiet != None:
1952 EdkLogger.SetLevel(EdkLogger.QUIET)
1953 elif Option.debug != None:
1954 EdkLogger.SetLevel(Option.debug + 1)
1955 else:
1956 EdkLogger.SetLevel(EdkLogger.INFO)
1957
1958 if Option.LogFile != None:
1959 EdkLogger.SetLogFile(Option.LogFile)
1960
1961 if Option.WarningAsError == True:
1962 EdkLogger.SetWarningAsError()
1963
1964 if platform.platform().find("Windows") >= 0:
1965 GlobalData.gIsWindows = True
1966 else:
1967 GlobalData.gIsWindows = False
1968
1969 EdkLogger.quiet("Build environment: %s" % platform.platform())
1970 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));
1971 ReturnCode = 0
1972 MyBuild = None
1973 try:
1974 if len(Target) == 0:
1975 Target = "all"
1976 elif len(Target) >= 2:
1977 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",
1978 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))
1979 else:
1980 Target = Target[0].lower()
1981
1982 if Target not in gSupportedTarget:
1983 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,
1984 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))
1985
1986 #
1987 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
1988 #
1989 CheckEnvVariable()
1990 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))
1991
1992 Workspace = os.getenv("WORKSPACE")
1993 #
1994 # Get files real name in workspace dir
1995 #
1996 GlobalData.gAllFiles = Utils.DirCache(Workspace)
1997
1998 WorkingDirectory = os.getcwd()
1999 if not Option.ModuleFile:
2000 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))
2001 FileNum = len(FileList)
2002 if FileNum >= 2:
2003 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),
2004 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2005 elif FileNum == 1:
2006 Option.ModuleFile = NormFile(FileList[0], Workspace)
2007
2008 if Option.ModuleFile:
2009 if os.path.isabs (Option.ModuleFile):
2010 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:
2011 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)
2012 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)
2013 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)
2014 if ErrorCode != 0:
2015 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
2016
2017 if Option.PlatformFile != None:
2018 if os.path.isabs (Option.PlatformFile):
2019 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:
2020 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)
2021 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)
2022
2023 if Option.FdfFile != None:
2024 if os.path.isabs (Option.FdfFile):
2025 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:
2026 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)
2027 Option.FdfFile = PathClass(Option.FdfFile, Workspace)
2028 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)
2029 if ErrorCode != 0:
2030 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
2031
2032 if Option.Flag != None and Option.Flag not in ['-c', '-s']:
2033 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")
2034
2035 MyBuild = Build(Target, Workspace, Option)
2036 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)
2037 MyBuild.Launch()
2038 # Drop temp tables to avoid database locked.
2039 for TmpTableName in TmpTableDict:
2040 SqlCommand = """drop table IF EXISTS %s""" % TmpTableName
2041 TmpTableDict[TmpTableName].execute(SqlCommand)
2042 #MyBuild.DumpBuildData()
2043 except FatalError, X:
2044 if MyBuild != None:
2045 # for multi-thread build exits safely
2046 MyBuild.Relinquish()
2047 if Option != None and Option.debug != None:
2048 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2049 ReturnCode = X.args[0]
2050 except Warning, X:
2051 # error from Fdf parser
2052 if MyBuild != None:
2053 # for multi-thread build exits safely
2054 MyBuild.Relinquish()
2055 if Option != None and Option.debug != None:
2056 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2057 else:
2058 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError = False)
2059 ReturnCode = FORMAT_INVALID
2060 except KeyboardInterrupt:
2061 ReturnCode = ABORT_ERROR
2062 if Option != None and Option.debug != None:
2063 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2064 except:
2065 if MyBuild != None:
2066 # for multi-thread build exits safely
2067 MyBuild.Relinquish()
2068
2069 # try to get the meta-file from the object causing exception
2070 Tb = sys.exc_info()[-1]
2071 MetaFile = GlobalData.gProcessingFile
2072 while Tb != None:
2073 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):
2074 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile
2075 Tb = Tb.tb_next
2076 EdkLogger.error(
2077 "\nbuild",
2078 CODE_ERROR,
2079 "Unknown fatal error when processing [%s]" % MetaFile,
2080 ExtraData="\n(Please send email to edk2-devel@lists.sourceforge.net for help, attaching following call stack trace!)\n",
2081 RaiseError=False
2082 )
2083 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2084 ReturnCode = CODE_ERROR
2085 finally:
2086 Utils.Progressor.Abort()
2087 Utils.ClearDuplicatedInf()
2088
2089 if ReturnCode == 0:
2090 Conclusion = "Done"
2091 elif ReturnCode == ABORT_ERROR:
2092 Conclusion = "Aborted"
2093 else:
2094 Conclusion = "Failed"
2095 FinishTime = time.time()
2096 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))
2097 BuildDurationStr = ""
2098 if BuildDuration.tm_yday > 1:
2099 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)"%(BuildDuration.tm_yday - 1)
2100 else:
2101 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)
2102 if MyBuild != None:
2103 MyBuild.BuildReport.GenerateReport(BuildDurationStr)
2104 MyBuild.Db.Close()
2105 EdkLogger.SetLevel(EdkLogger.QUIET)
2106 EdkLogger.quiet("\n- %s -" % Conclusion)
2107 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))
2108 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)
2109 return ReturnCode
2110
2111 if __name__ == '__main__':
2112 r = Main()
2113 ## 0-127 is a safe return range, and 1 is a standard default error
2114 if r < 0 or r > 127: r = 1
2115 sys.exit(r)
2116