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