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