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