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