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