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