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