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