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