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