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