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