]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/build/build.py
97271e634e6c19856b7a577ba263d7b4e88af769
[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 # Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
7 #
8 # This program and the accompanying materials
9 # are licensed and made available under the terms and conditions of the BSD License
10 # which accompanies this distribution. The full text of the license may be found at
11 # http://opensource.org/licenses/bsd-license.php
12 #
13 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #
16
17 ##
18 # Import Modules
19 #
20 from __future__ import print_function
21 import Common.LongFilePathOs as os
22 import re
23 from io import BytesIO
24 import sys
25 import glob
26 import time
27 import platform
28 import traceback
29 import encodings.ascii
30 import itertools
31 import multiprocessing
32
33 from struct import *
34 from threading import *
35 from optparse import OptionParser
36 from subprocess import *
37 from Common import Misc as Utils
38
39 from Common.LongFilePathSupport import OpenLongFilePath as open
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 WorkspaceDatabase
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, GenFdsApi
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 - 2018, 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 self.Db = WorkspaceDatabase()
831 self.BuildDatabase = self.Db.BuildObject
832 self.Platform = None
833 self.ToolChainFamily = None
834 self.LoadFixAddress = 0
835 self.UniFlag = BuildOptions.Flag
836 self.BuildModules = []
837 self.HashSkipModules = []
838 self.Db_Flag = False
839 self.LaunchPrebuildFlag = False
840 self.PlatformBuildPath = os.path.join(GlobalData.gConfDirectory, '.cache', '.PlatformBuild')
841 if BuildOptions.CommandLength:
842 GlobalData.gCommandMaxLength = BuildOptions.CommandLength
843
844 # print dot character during doing some time-consuming work
845 self.Progress = Utils.Progressor()
846 # print current build environment and configuration
847 EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))
848 if "PACKAGES_PATH" in os.environ:
849 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
850 EdkLogger.quiet("%-16s = %s" % ("PACKAGES_PATH", os.path.normcase(os.path.normpath(os.environ["PACKAGES_PATH"]))))
851 EdkLogger.quiet("%-16s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"]))
852 EdkLogger.quiet("%-16s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"]))
853 EdkLogger.quiet("%-16s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"]))
854 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))
855 if "EDK_TOOLS_BIN" in os.environ:
856 # Print the same path style with WORKSPACE env.
857 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os.path.normcase(os.path.normpath(os.environ["EDK_TOOLS_BIN"]))))
858 EdkLogger.quiet("%-16s = %s" % ("CONF_PATH", GlobalData.gConfDirectory))
859 self.InitPreBuild()
860 self.InitPostBuild()
861 if self.Prebuild:
862 EdkLogger.quiet("%-16s = %s" % ("PREBUILD", self.Prebuild))
863 if self.Postbuild:
864 EdkLogger.quiet("%-16s = %s" % ("POSTBUILD", self.Postbuild))
865 if self.Prebuild:
866 self.LaunchPrebuild()
867 self.TargetTxt = TargetTxtClassObject()
868 self.ToolDef = ToolDefClassObject()
869 if not (self.LaunchPrebuildFlag and os.path.exists(self.PlatformBuildPath)):
870 self.InitBuild()
871
872 EdkLogger.info("")
873 os.chdir(self.WorkspaceDir)
874
875 ## Load configuration
876 #
877 # This method will parse target.txt and get the build configurations.
878 #
879 def LoadConfiguration(self):
880 #
881 # Check target.txt and tools_def.txt and Init them
882 #
883 BuildConfigurationFile = os.path.normpath(os.path.join(GlobalData.gConfDirectory, gBuildConfiguration))
884 if os.path.isfile(BuildConfigurationFile) == True:
885 StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)
886
887 ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]
888 if ToolDefinitionFile == '':
889 ToolDefinitionFile = gToolsDefinition
890 ToolDefinitionFile = os.path.normpath(mws.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile))
891 if os.path.isfile(ToolDefinitionFile) == True:
892 StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)
893 else:
894 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)
895 else:
896 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)
897
898 # if no ARCH given in command line, get it from target.txt
899 if not self.ArchList:
900 self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH]
901 self.ArchList = tuple(self.ArchList)
902
903 # if no build target given in command line, get it from target.txt
904 if not self.BuildTargetList:
905 self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]
906
907 # if no tool chain given in command line, get it from target.txt
908 if not self.ToolChainList:
909 self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]
910 if self.ToolChainList is None or len(self.ToolChainList) == 0:
911 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")
912
913 # check if the tool chains are defined or not
914 NewToolChainList = []
915 for ToolChain in self.ToolChainList:
916 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:
917 EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)
918 else:
919 NewToolChainList.append(ToolChain)
920 # if no tool chain available, break the build
921 if len(NewToolChainList) == 0:
922 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
923 ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))
924 else:
925 self.ToolChainList = NewToolChainList
926
927 ToolChainFamily = []
928 ToolDefinition = self.ToolDef.ToolsDefTxtDatabase
929 for Tool in self.ToolChainList:
930 if TAB_TOD_DEFINES_FAMILY not in ToolDefinition or Tool not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \
931 or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool]:
932 EdkLogger.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool)
933 ToolChainFamily.append(TAB_COMPILER_MSFT)
934 else:
935 ToolChainFamily.append(ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool])
936 self.ToolChainFamily = ToolChainFamily
937
938 if self.ThreadNumber is None:
939 self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]
940 if self.ThreadNumber == '':
941 self.ThreadNumber = 0
942 else:
943 self.ThreadNumber = int(self.ThreadNumber, 0)
944
945 if self.ThreadNumber == 0:
946 try:
947 self.ThreadNumber = multiprocessing.cpu_count()
948 except (ImportError, NotImplementedError):
949 self.ThreadNumber = 1
950
951 if not self.PlatformFile:
952 PlatformFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM]
953 if not PlatformFile:
954 # Try to find one in current directory
955 WorkingDirectory = os.getcwd()
956 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))
957 FileNum = len(FileList)
958 if FileNum >= 2:
959 EdkLogger.error("build", OPTION_MISSING,
960 ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))
961 elif FileNum == 1:
962 PlatformFile = FileList[0]
963 else:
964 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
965 ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")
966
967 self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)
968
969 ## Initialize build configuration
970 #
971 # This method will parse DSC file and merge the configurations from
972 # command line and target.txt, then get the final build configurations.
973 #
974 def InitBuild(self):
975 # parse target.txt, tools_def.txt, and platform file
976 self.LoadConfiguration()
977
978 # Allow case-insensitive for those from command line or configuration file
979 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)
980 if ErrorCode != 0:
981 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
982
983
984 def InitPreBuild(self):
985 self.LoadConfiguration()
986 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)
987 if ErrorCode != 0:
988 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
989 if self.BuildTargetList:
990 GlobalData.gGlobalDefines['TARGET'] = self.BuildTargetList[0]
991 if self.ArchList:
992 GlobalData.gGlobalDefines['ARCH'] = self.ArchList[0]
993 if self.ToolChainList:
994 GlobalData.gGlobalDefines['TOOLCHAIN'] = self.ToolChainList[0]
995 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = self.ToolChainList[0]
996 if self.ToolChainFamily:
997 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[0]
998 if 'PREBUILD' in GlobalData.gCommandLineDefines:
999 self.Prebuild = GlobalData.gCommandLineDefines.get('PREBUILD')
1000 else:
1001 self.Db_Flag = True
1002 Platform = self.Db.MapPlatform(str(self.PlatformFile))
1003 self.Prebuild = str(Platform.Prebuild)
1004 if self.Prebuild:
1005 PrebuildList = []
1006 #
1007 # Evaluate all arguments and convert arguments that are WORKSPACE
1008 # relative paths to absolute paths. Filter arguments that look like
1009 # flags or do not follow the file/dir naming rules to avoid false
1010 # positives on this conversion.
1011 #
1012 for Arg in self.Prebuild.split():
1013 #
1014 # Do not modify Arg if it looks like a flag or an absolute file path
1015 #
1016 if Arg.startswith('-') or os.path.isabs(Arg):
1017 PrebuildList.append(Arg)
1018 continue
1019 #
1020 # Do not modify Arg if it does not look like a Workspace relative
1021 # path that starts with a valid package directory name
1022 #
1023 if not Arg[0].isalpha() or os.path.dirname(Arg) == '':
1024 PrebuildList.append(Arg)
1025 continue
1026 #
1027 # If Arg looks like a WORKSPACE relative path, then convert to an
1028 # absolute path and check to see if the file exists.
1029 #
1030 Temp = mws.join(self.WorkspaceDir, Arg)
1031 if os.path.isfile(Temp):
1032 Arg = Temp
1033 PrebuildList.append(Arg)
1034 self.Prebuild = ' '.join(PrebuildList)
1035 self.Prebuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)
1036
1037 def InitPostBuild(self):
1038 if 'POSTBUILD' in GlobalData.gCommandLineDefines:
1039 self.Postbuild = GlobalData.gCommandLineDefines.get('POSTBUILD')
1040 else:
1041 Platform = self.Db.MapPlatform(str(self.PlatformFile))
1042 self.Postbuild = str(Platform.Postbuild)
1043 if self.Postbuild:
1044 PostbuildList = []
1045 #
1046 # Evaluate all arguments and convert arguments that are WORKSPACE
1047 # relative paths to absolute paths. Filter arguments that look like
1048 # flags or do not follow the file/dir naming rules to avoid false
1049 # positives on this conversion.
1050 #
1051 for Arg in self.Postbuild.split():
1052 #
1053 # Do not modify Arg if it looks like a flag or an absolute file path
1054 #
1055 if Arg.startswith('-') or os.path.isabs(Arg):
1056 PostbuildList.append(Arg)
1057 continue
1058 #
1059 # Do not modify Arg if it does not look like a Workspace relative
1060 # path that starts with a valid package directory name
1061 #
1062 if not Arg[0].isalpha() or os.path.dirname(Arg) == '':
1063 PostbuildList.append(Arg)
1064 continue
1065 #
1066 # If Arg looks like a WORKSPACE relative path, then convert to an
1067 # absolute path and check to see if the file exists.
1068 #
1069 Temp = mws.join(self.WorkspaceDir, Arg)
1070 if os.path.isfile(Temp):
1071 Arg = Temp
1072 PostbuildList.append(Arg)
1073 self.Postbuild = ' '.join(PostbuildList)
1074 self.Postbuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)
1075
1076 def PassCommandOption(self, BuildTarget, TargetArch, ToolChain, PlatformFile, Target):
1077 BuildStr = ''
1078 if GlobalData.gCommand and isinstance(GlobalData.gCommand, list):
1079 BuildStr += ' ' + ' '.join(GlobalData.gCommand)
1080 TargetFlag = False
1081 ArchFlag = False
1082 ToolChainFlag = False
1083 PlatformFileFlag = False
1084
1085 if GlobalData.gOptions and not GlobalData.gOptions.BuildTarget:
1086 TargetFlag = True
1087 if GlobalData.gOptions and not GlobalData.gOptions.TargetArch:
1088 ArchFlag = True
1089 if GlobalData.gOptions and not GlobalData.gOptions.ToolChain:
1090 ToolChainFlag = True
1091 if GlobalData.gOptions and not GlobalData.gOptions.PlatformFile:
1092 PlatformFileFlag = True
1093
1094 if TargetFlag and BuildTarget:
1095 if isinstance(BuildTarget, list) or isinstance(BuildTarget, tuple):
1096 BuildStr += ' -b ' + ' -b '.join(BuildTarget)
1097 elif isinstance(BuildTarget, str):
1098 BuildStr += ' -b ' + BuildTarget
1099 if ArchFlag and TargetArch:
1100 if isinstance(TargetArch, list) or isinstance(TargetArch, tuple):
1101 BuildStr += ' -a ' + ' -a '.join(TargetArch)
1102 elif isinstance(TargetArch, str):
1103 BuildStr += ' -a ' + TargetArch
1104 if ToolChainFlag and ToolChain:
1105 if isinstance(ToolChain, list) or isinstance(ToolChain, tuple):
1106 BuildStr += ' -t ' + ' -t '.join(ToolChain)
1107 elif isinstance(ToolChain, str):
1108 BuildStr += ' -t ' + ToolChain
1109 if PlatformFileFlag and PlatformFile:
1110 if isinstance(PlatformFile, list) or isinstance(PlatformFile, tuple):
1111 BuildStr += ' -p ' + ' -p '.join(PlatformFile)
1112 elif isinstance(PlatformFile, str):
1113 BuildStr += ' -p' + PlatformFile
1114 BuildStr += ' --conf=' + GlobalData.gConfDirectory
1115 if Target:
1116 BuildStr += ' ' + Target
1117
1118 return BuildStr
1119
1120 def LaunchPrebuild(self):
1121 if self.Prebuild:
1122 EdkLogger.info("\n- Prebuild Start -\n")
1123 self.LaunchPrebuildFlag = True
1124 #
1125 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1126 # and preserve them for the rest of the main build step, because the child process environment will
1127 # evaporate as soon as it exits, we cannot get it in build step.
1128 #
1129 PrebuildEnvFile = os.path.join(GlobalData.gConfDirectory, '.cache', '.PrebuildEnv')
1130 if os.path.isfile(PrebuildEnvFile):
1131 os.remove(PrebuildEnvFile)
1132 if os.path.isfile(self.PlatformBuildPath):
1133 os.remove(self.PlatformBuildPath)
1134 if sys.platform == "win32":
1135 args = ' && '.join((self.Prebuild, 'set > ' + PrebuildEnvFile))
1136 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)
1137 else:
1138 args = ' && '.join((self.Prebuild, 'env > ' + PrebuildEnvFile))
1139 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)
1140
1141 # launch two threads to read the STDOUT and STDERR
1142 EndOfProcedure = Event()
1143 EndOfProcedure.clear()
1144 if Process.stdout:
1145 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))
1146 StdOutThread.setName("STDOUT-Redirector")
1147 StdOutThread.setDaemon(False)
1148 StdOutThread.start()
1149
1150 if Process.stderr:
1151 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))
1152 StdErrThread.setName("STDERR-Redirector")
1153 StdErrThread.setDaemon(False)
1154 StdErrThread.start()
1155 # waiting for program exit
1156 Process.wait()
1157
1158 if Process.stdout:
1159 StdOutThread.join()
1160 if Process.stderr:
1161 StdErrThread.join()
1162 if Process.returncode != 0 :
1163 EdkLogger.error("Prebuild", PREBUILD_ERROR, 'Prebuild process is not success!')
1164
1165 if os.path.exists(PrebuildEnvFile):
1166 f = open(PrebuildEnvFile)
1167 envs = f.readlines()
1168 f.close()
1169 envs = itertools.imap(lambda l: l.split('=', 1), envs)
1170 envs = itertools.ifilter(lambda l: len(l) == 2, envs)
1171 envs = itertools.imap(lambda l: [i.strip() for i in l], envs)
1172 os.environ.update(dict(envs))
1173 EdkLogger.info("\n- Prebuild Done -\n")
1174
1175 def LaunchPostbuild(self):
1176 if self.Postbuild:
1177 EdkLogger.info("\n- Postbuild Start -\n")
1178 if sys.platform == "win32":
1179 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)
1180 else:
1181 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)
1182 # launch two threads to read the STDOUT and STDERR
1183 EndOfProcedure = Event()
1184 EndOfProcedure.clear()
1185 if Process.stdout:
1186 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))
1187 StdOutThread.setName("STDOUT-Redirector")
1188 StdOutThread.setDaemon(False)
1189 StdOutThread.start()
1190
1191 if Process.stderr:
1192 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))
1193 StdErrThread.setName("STDERR-Redirector")
1194 StdErrThread.setDaemon(False)
1195 StdErrThread.start()
1196 # waiting for program exit
1197 Process.wait()
1198
1199 if Process.stdout:
1200 StdOutThread.join()
1201 if Process.stderr:
1202 StdErrThread.join()
1203 if Process.returncode != 0 :
1204 EdkLogger.error("Postbuild", POSTBUILD_ERROR, 'Postbuild process is not success!')
1205 EdkLogger.info("\n- Postbuild Done -\n")
1206 ## Build a module or platform
1207 #
1208 # Create autogen code and makefile for a module or platform, and the launch
1209 # "make" command to build it
1210 #
1211 # @param Target The target of build command
1212 # @param Platform The platform file
1213 # @param Module The module file
1214 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1215 # @param ToolChain The name of toolchain to build
1216 # @param Arch The arch of the module/platform
1217 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1218 # for dependent modules/Libraries
1219 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1220 # for dependent modules/Libraries
1221 #
1222 def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False, FfsCommand={}):
1223 if AutoGenObject is None:
1224 return False
1225
1226 # skip file generation for cleanxxx targets, run and fds target
1227 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1228 # for target which must generate AutoGen code and makefile
1229 if not self.SkipAutoGen or Target == 'genc':
1230 self.Progress.Start("Generating code")
1231 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
1232 self.Progress.Stop("done!")
1233 if Target == "genc":
1234 return True
1235
1236 if not self.SkipAutoGen or Target == 'genmake':
1237 self.Progress.Start("Generating makefile")
1238 AutoGenObject.CreateMakeFile(CreateDepsMakeFile, FfsCommand)
1239 self.Progress.Stop("done!")
1240 if Target == "genmake":
1241 return True
1242 else:
1243 # always recreate top/platform makefile when clean, just in case of inconsistency
1244 AutoGenObject.CreateCodeFile(False)
1245 AutoGenObject.CreateMakeFile(False)
1246
1247 if EdkLogger.GetLevel() == EdkLogger.QUIET:
1248 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
1249
1250 BuildCommand = AutoGenObject.BuildCommand
1251 if BuildCommand is None or len(BuildCommand) == 0:
1252 EdkLogger.error("build", OPTION_MISSING,
1253 "No build command found for this module. "
1254 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1255 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
1256 ExtraData=str(AutoGenObject))
1257
1258 makefile = GenMake.BuildFile(AutoGenObject)._FILE_NAME_[GenMake.gMakeType]
1259
1260 # run
1261 if Target == 'run':
1262 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))
1263 Command = '.\SecMain'
1264 os.chdir(RunDir)
1265 LaunchCommand(Command, RunDir)
1266 return True
1267
1268 # build modules
1269 if BuildModule:
1270 BuildCommand = BuildCommand + [Target]
1271 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
1272 self.CreateAsBuiltInf()
1273 return True
1274
1275 # build library
1276 if Target == 'libraries':
1277 for Lib in AutoGenObject.LibraryBuildDirectoryList:
1278 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']
1279 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1280 return True
1281
1282 # build module
1283 if Target == 'modules':
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 for Mod in AutoGenObject.ModuleBuildDirectoryList:
1288 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']
1289 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1290 self.CreateAsBuiltInf()
1291 return True
1292
1293 # cleanlib
1294 if Target == 'cleanlib':
1295 for Lib in AutoGenObject.LibraryBuildDirectoryList:
1296 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))
1297 if os.path.exists(LibMakefile):
1298 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
1299 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1300 return True
1301
1302 # clean
1303 if Target == 'clean':
1304 for Mod in AutoGenObject.ModuleBuildDirectoryList:
1305 ModMakefile = os.path.normpath(os.path.join(Mod, makefile))
1306 if os.path.exists(ModMakefile):
1307 NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']
1308 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1309 for Lib in AutoGenObject.LibraryBuildDirectoryList:
1310 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))
1311 if os.path.exists(LibMakefile):
1312 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
1313 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1314 return True
1315
1316 # cleanall
1317 if Target == 'cleanall':
1318 try:
1319 #os.rmdir(AutoGenObject.BuildDir)
1320 RemoveDirectory(AutoGenObject.BuildDir, True)
1321 except WindowsError as X:
1322 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
1323 return True
1324
1325 ## Build a module or platform
1326 #
1327 # Create autogen code and makefile for a module or platform, and the launch
1328 # "make" command to build it
1329 #
1330 # @param Target The target of build command
1331 # @param Platform The platform file
1332 # @param Module The module file
1333 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1334 # @param ToolChain The name of toolchain to build
1335 # @param Arch The arch of the module/platform
1336 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1337 # for dependent modules/Libraries
1338 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1339 # for dependent modules/Libraries
1340 #
1341 def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):
1342 if AutoGenObject is None:
1343 return False
1344
1345 # skip file generation for cleanxxx targets, run and fds target
1346 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1347 # for target which must generate AutoGen code and makefile
1348 if not self.SkipAutoGen or Target == 'genc':
1349 self.Progress.Start("Generating code")
1350 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
1351 self.Progress.Stop("done!")
1352 if Target == "genc":
1353 return True
1354
1355 if not self.SkipAutoGen or Target == 'genmake':
1356 self.Progress.Start("Generating makefile")
1357 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)
1358 #AutoGenObject.CreateAsBuiltInf()
1359 self.Progress.Stop("done!")
1360 if Target == "genmake":
1361 return True
1362 else:
1363 # always recreate top/platform makefile when clean, just in case of inconsistency
1364 AutoGenObject.CreateCodeFile(False)
1365 AutoGenObject.CreateMakeFile(False)
1366
1367 if EdkLogger.GetLevel() == EdkLogger.QUIET:
1368 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
1369
1370 BuildCommand = AutoGenObject.BuildCommand
1371 if BuildCommand is None or len(BuildCommand) == 0:
1372 EdkLogger.error("build", OPTION_MISSING,
1373 "No build command found for this module. "
1374 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1375 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
1376 ExtraData=str(AutoGenObject))
1377
1378 # build modules
1379 if BuildModule:
1380 if Target != 'fds':
1381 BuildCommand = BuildCommand + [Target]
1382 AutoGenObject.BuildTime = LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
1383 self.CreateAsBuiltInf()
1384 return True
1385
1386 # genfds
1387 if Target == 'fds':
1388 if GenFdsApi(AutoGenObject.GenFdsCommandDict, self.Db):
1389 EdkLogger.error("build", COMMAND_FAILURE)
1390 return True
1391
1392 # run
1393 if Target == 'run':
1394 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))
1395 Command = '.\SecMain'
1396 os.chdir(RunDir)
1397 LaunchCommand(Command, RunDir)
1398 return True
1399
1400 # build library
1401 if Target == 'libraries':
1402 pass
1403
1404 # not build modules
1405
1406
1407 # cleanall
1408 if Target == 'cleanall':
1409 try:
1410 #os.rmdir(AutoGenObject.BuildDir)
1411 RemoveDirectory(AutoGenObject.BuildDir, True)
1412 except WindowsError as X:
1413 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
1414 return True
1415
1416 ## Rebase module image and Get function address for the input module list.
1417 #
1418 def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):
1419 if ModeIsSmm:
1420 AddrIsOffset = False
1421 for InfFile in ModuleList:
1422 sys.stdout.write (".")
1423 sys.stdout.flush()
1424 ModuleInfo = ModuleList[InfFile]
1425 ModuleName = ModuleInfo.BaseName
1426 ModuleOutputImage = ModuleInfo.Image.FileName
1427 ModuleDebugImage = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')
1428 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1429 if not ModeIsSmm:
1430 BaseAddress = BaseAddress - ModuleInfo.Image.Size
1431 #
1432 # Update Image to new BaseAddress by GenFw tool
1433 #
1434 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
1435 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
1436 else:
1437 #
1438 # Set new address to the section header only for SMM driver.
1439 #
1440 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
1441 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
1442 #
1443 # Collect funtion address from Map file
1444 #
1445 ImageMapTable = ModuleOutputImage.replace('.efi', '.map')
1446 FunctionList = []
1447 if os.path.exists(ImageMapTable):
1448 OrigImageBaseAddress = 0
1449 ImageMap = open(ImageMapTable, 'r')
1450 for LinStr in ImageMap:
1451 if len (LinStr.strip()) == 0:
1452 continue
1453 #
1454 # Get the preferred address set on link time.
1455 #
1456 if LinStr.find ('Preferred load address is') != -1:
1457 StrList = LinStr.split()
1458 OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)
1459
1460 StrList = LinStr.split()
1461 if len (StrList) > 4:
1462 if StrList[3] == 'f' or StrList[3] == 'F':
1463 Name = StrList[1]
1464 RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress
1465 FunctionList.append ((Name, RelativeAddress))
1466 if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'):
1467 #
1468 # Get the real entry point address for IPF image.
1469 #
1470 ModuleInfo.Image.EntryPoint = RelativeAddress
1471 ImageMap.close()
1472 #
1473 # Add general information.
1474 #
1475 if ModeIsSmm:
1476 MapBuffer.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
1477 elif AddrIsOffset:
1478 MapBuffer.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))
1479 else:
1480 MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
1481 #
1482 # Add guid and general seciton section.
1483 #
1484 TextSectionAddress = 0
1485 DataSectionAddress = 0
1486 for SectionHeader in ModuleInfo.Image.SectionHeaderList:
1487 if SectionHeader[0] == '.text':
1488 TextSectionAddress = SectionHeader[1]
1489 elif SectionHeader[0] in ['.data', '.sdata']:
1490 DataSectionAddress = SectionHeader[1]
1491 if AddrIsOffset:
1492 MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))
1493 else:
1494 MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))
1495 #
1496 # Add debug image full path.
1497 #
1498 MapBuffer.write('(IMAGE=%s)\n\n' % (ModuleDebugImage))
1499 #
1500 # Add funtion address
1501 #
1502 for Function in FunctionList:
1503 if AddrIsOffset:
1504 MapBuffer.write(' -0x%010X %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))
1505 else:
1506 MapBuffer.write(' 0x%010X %s\n' % (BaseAddress + Function[1], Function[0]))
1507 ImageMap.close()
1508
1509 #
1510 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1511 #
1512 if ModeIsSmm:
1513 BaseAddress = BaseAddress + ModuleInfo.Image.Size
1514
1515 ## Collect MAP information of all FVs
1516 #
1517 def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):
1518 if self.Fdf:
1519 # First get the XIP base address for FV map file.
1520 GuidPattern = re.compile("[-a-fA-F0-9]+")
1521 GuidName = re.compile("\(GUID=[-a-fA-F0-9]+")
1522 for FvName in Wa.FdfProfile.FvDict:
1523 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')
1524 if not os.path.exists(FvMapBuffer):
1525 continue
1526 FvMap = open(FvMapBuffer, 'r')
1527 #skip FV size information
1528 FvMap.readline()
1529 FvMap.readline()
1530 FvMap.readline()
1531 FvMap.readline()
1532 for Line in FvMap:
1533 MatchGuid = GuidPattern.match(Line)
1534 if MatchGuid is not None:
1535 #
1536 # Replace GUID with module name
1537 #
1538 GuidString = MatchGuid.group()
1539 if GuidString.upper() in ModuleList:
1540 Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)
1541 MapBuffer.write(Line)
1542 #
1543 # Add the debug image full path.
1544 #
1545 MatchGuid = GuidName.match(Line)
1546 if MatchGuid is not None:
1547 GuidString = MatchGuid.group().split("=")[1]
1548 if GuidString.upper() in ModuleList:
1549 MapBuffer.write('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))
1550
1551 FvMap.close()
1552
1553 ## Collect MAP information of all modules
1554 #
1555 def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):
1556 sys.stdout.write ("Generate Load Module At Fix Address Map")
1557 sys.stdout.flush()
1558 PatchEfiImageList = []
1559 PeiModuleList = {}
1560 BtModuleList = {}
1561 RtModuleList = {}
1562 SmmModuleList = {}
1563 PeiSize = 0
1564 BtSize = 0
1565 RtSize = 0
1566 # reserve 4K size in SMRAM to make SMM module address not from 0.
1567 SmmSize = 0x1000
1568 IsIpfPlatform = False
1569 if 'IPF' in self.ArchList:
1570 IsIpfPlatform = True
1571 for ModuleGuid in ModuleList:
1572 Module = ModuleList[ModuleGuid]
1573 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)
1574
1575 OutputImageFile = ''
1576 for ResultFile in Module.CodaTargetList:
1577 if str(ResultFile.Target).endswith('.efi'):
1578 #
1579 # module list for PEI, DXE, RUNTIME and SMM
1580 #
1581 OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')
1582 ImageClass = PeImageClass (OutputImageFile)
1583 if not ImageClass.IsValid:
1584 EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)
1585 ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)
1586 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]:
1587 PeiModuleList[Module.MetaFile] = ImageInfo
1588 PeiSize += ImageInfo.Image.Size
1589 elif Module.ModuleType in [EDK_COMPONENT_TYPE_BS_DRIVER, SUP_MODULE_DXE_DRIVER, SUP_MODULE_UEFI_DRIVER]:
1590 BtModuleList[Module.MetaFile] = ImageInfo
1591 BtSize += ImageInfo.Image.Size
1592 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]:
1593 RtModuleList[Module.MetaFile] = ImageInfo
1594 #IPF runtime driver needs to be at 2 page alignment.
1595 if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0:
1596 ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000
1597 RtSize += ImageInfo.Image.Size
1598 elif Module.ModuleType in [SUP_MODULE_SMM_CORE, SUP_MODULE_DXE_SMM_DRIVER, SUP_MODULE_MM_STANDALONE, SUP_MODULE_MM_CORE_STANDALONE]:
1599 SmmModuleList[Module.MetaFile] = ImageInfo
1600 SmmSize += ImageInfo.Image.Size
1601 if Module.ModuleType == SUP_MODULE_DXE_SMM_DRIVER:
1602 PiSpecVersion = Module.Module.Specification.get('PI_SPECIFICATION_VERSION', '0x00000000')
1603 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1604 if int(PiSpecVersion, 16) < 0x0001000A:
1605 BtModuleList[Module.MetaFile] = ImageInfo
1606 BtSize += ImageInfo.Image.Size
1607 break
1608 #
1609 # EFI image is final target.
1610 # Check EFI image contains patchable FixAddress related PCDs.
1611 #
1612 if OutputImageFile != '':
1613 ModuleIsPatch = False
1614 for Pcd in Module.ModulePcdList:
1615 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:
1616 ModuleIsPatch = True
1617 break
1618 if not ModuleIsPatch:
1619 for Pcd in Module.LibraryPcdList:
1620 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:
1621 ModuleIsPatch = True
1622 break
1623
1624 if not ModuleIsPatch:
1625 continue
1626 #
1627 # Module includes the patchable load fix address PCDs.
1628 # It will be fixed up later.
1629 #
1630 PatchEfiImageList.append (OutputImageFile)
1631
1632 #
1633 # Get Top Memory address
1634 #
1635 ReservedRuntimeMemorySize = 0
1636 TopMemoryAddress = 0
1637 if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:
1638 TopMemoryAddress = 0
1639 else:
1640 TopMemoryAddress = self.LoadFixAddress
1641 if TopMemoryAddress < RtSize + BtSize + PeiSize:
1642 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1643 # Make IPF runtime driver at 2 page alignment.
1644 if IsIpfPlatform:
1645 ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000
1646 RtSize = RtSize + ReservedRuntimeMemorySize
1647
1648 #
1649 # Patch FixAddress related PCDs into EFI image
1650 #
1651 for EfiImage in PatchEfiImageList:
1652 EfiImageMap = EfiImage.replace('.efi', '.map')
1653 if not os.path.exists(EfiImageMap):
1654 continue
1655 #
1656 # Get PCD offset in EFI image by GenPatchPcdTable function
1657 #
1658 PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)
1659 #
1660 # Patch real PCD value by PatchPcdValue tool
1661 #
1662 for PcdInfo in PcdTable:
1663 ReturnValue = 0
1664 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:
1665 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize / 0x1000))
1666 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:
1667 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize / 0x1000))
1668 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:
1669 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize / 0x1000))
1670 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:
1671 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize / 0x1000))
1672 if ReturnValue != 0:
1673 EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)
1674
1675 MapBuffer.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize / 0x1000))
1676 MapBuffer.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize / 0x1000))
1677 MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize / 0x1000))
1678 if len (SmmModuleList) > 0:
1679 MapBuffer.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize / 0x1000))
1680
1681 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize
1682 BtBaseAddr = TopMemoryAddress - RtSize
1683 RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize
1684
1685 self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)
1686 self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)
1687 self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)
1688 self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset=False, ModeIsSmm=True)
1689 MapBuffer.write('\n\n')
1690 sys.stdout.write ("\n")
1691 sys.stdout.flush()
1692
1693 ## Save platform Map file
1694 #
1695 def _SaveMapFile (self, MapBuffer, Wa):
1696 #
1697 # Map file path is got.
1698 #
1699 MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')
1700 #
1701 # Save address map into MAP file.
1702 #
1703 SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)
1704 MapBuffer.close()
1705 if self.LoadFixAddress != 0:
1706 sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath))
1707 sys.stdout.flush()
1708
1709 ## Build active platform for different build targets and different tool chains
1710 #
1711 def _BuildPlatform(self):
1712 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1713 for BuildTarget in self.BuildTargetList:
1714 GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1715 index = 0
1716 for ToolChain in self.ToolChainList:
1717 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1718 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1719 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
1720 index += 1
1721 Wa = WorkspaceAutoGen(
1722 self.WorkspaceDir,
1723 self.PlatformFile,
1724 BuildTarget,
1725 ToolChain,
1726 self.ArchList,
1727 self.BuildDatabase,
1728 self.TargetTxt,
1729 self.ToolDef,
1730 self.Fdf,
1731 self.FdList,
1732 self.FvList,
1733 self.CapList,
1734 self.SkuId,
1735 self.UniFlag,
1736 self.Progress
1737 )
1738 self.Fdf = Wa.FdfFile
1739 self.LoadFixAddress = Wa.Platform.LoadFixAddress
1740 self.BuildReport.AddPlatformReport(Wa)
1741 self.Progress.Stop("done!")
1742
1743 # Add ffs build to makefile
1744 CmdListDict = {}
1745 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:
1746 CmdListDict = self._GenFfsCmd()
1747
1748 for Arch in Wa.ArchList:
1749 GlobalData.gGlobalDefines['ARCH'] = Arch
1750 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
1751 for Module in Pa.Platform.Modules:
1752 # Get ModuleAutoGen object to generate C code file and makefile
1753 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
1754 if Ma is None:
1755 continue
1756 self.BuildModules.append(Ma)
1757 self._BuildPa(self.Target, Pa, FfsCommand=CmdListDict)
1758
1759 # Create MAP file when Load Fix Address is enabled.
1760 if self.Target in ["", "all", "fds"]:
1761 for Arch in Wa.ArchList:
1762 GlobalData.gGlobalDefines['ARCH'] = Arch
1763 #
1764 # Check whether the set fix address is above 4G for 32bit image.
1765 #
1766 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1767 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")
1768 #
1769 # Get Module List
1770 #
1771 ModuleList = {}
1772 for Pa in Wa.AutoGenObjectList:
1773 for Ma in Pa.ModuleAutoGenList:
1774 if Ma is None:
1775 continue
1776 if not Ma.IsLibrary:
1777 ModuleList[Ma.Guid.upper()] = Ma
1778
1779 MapBuffer = BytesIO('')
1780 if self.LoadFixAddress != 0:
1781 #
1782 # Rebase module to the preferred memory address before GenFds
1783 #
1784 self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1785 if self.Fdf:
1786 #
1787 # create FDS again for the updated EFI image
1788 #
1789 self._Build("fds", Wa)
1790 #
1791 # Create MAP file for all platform FVs after GenFds.
1792 #
1793 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1794 #
1795 # Save MAP buffer into MAP file.
1796 #
1797 self._SaveMapFile (MapBuffer, Wa)
1798
1799 ## Build active module for different build targets, different tool chains and different archs
1800 #
1801 def _BuildModule(self):
1802 for BuildTarget in self.BuildTargetList:
1803 GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1804 index = 0
1805 for ToolChain in self.ToolChainList:
1806 WorkspaceAutoGenTime = time.time()
1807 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1808 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1809 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
1810 index += 1
1811 #
1812 # module build needs platform build information, so get platform
1813 # AutoGen first
1814 #
1815 Wa = WorkspaceAutoGen(
1816 self.WorkspaceDir,
1817 self.PlatformFile,
1818 BuildTarget,
1819 ToolChain,
1820 self.ArchList,
1821 self.BuildDatabase,
1822 self.TargetTxt,
1823 self.ToolDef,
1824 self.Fdf,
1825 self.FdList,
1826 self.FvList,
1827 self.CapList,
1828 self.SkuId,
1829 self.UniFlag,
1830 self.Progress,
1831 self.ModuleFile
1832 )
1833 self.Fdf = Wa.FdfFile
1834 self.LoadFixAddress = Wa.Platform.LoadFixAddress
1835 Wa.CreateMakeFile(False)
1836 # Add ffs build to makefile
1837 CmdListDict = None
1838 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:
1839 CmdListDict = self._GenFfsCmd()
1840 self.Progress.Stop("done!")
1841 MaList = []
1842 ExitFlag = threading.Event()
1843 ExitFlag.clear()
1844 self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))
1845 for Arch in Wa.ArchList:
1846 AutoGenStart = time.time()
1847 GlobalData.gGlobalDefines['ARCH'] = Arch
1848 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
1849 for Module in Pa.Platform.Modules:
1850 if self.ModuleFile.Dir == Module.Dir and self.ModuleFile.Name == Module.Name:
1851 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
1852 if Ma is None: continue
1853 MaList.append(Ma)
1854 if Ma.CanSkipbyHash():
1855 self.HashSkipModules.append(Ma)
1856 continue
1857 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1858 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1859 # for target which must generate AutoGen code and makefile
1860 if not self.SkipAutoGen or self.Target == 'genc':
1861 self.Progress.Start("Generating code")
1862 Ma.CreateCodeFile(True)
1863 self.Progress.Stop("done!")
1864 if self.Target == "genc":
1865 return True
1866 if not self.SkipAutoGen or self.Target == 'genmake':
1867 self.Progress.Start("Generating makefile")
1868 if CmdListDict and self.Fdf and (Module.File, Arch) in CmdListDict:
1869 Ma.CreateMakeFile(True, CmdListDict[Module.File, Arch])
1870 del CmdListDict[Module.File, Arch]
1871 else:
1872 Ma.CreateMakeFile(True)
1873 self.Progress.Stop("done!")
1874 if self.Target == "genmake":
1875 return True
1876 self.BuildModules.append(Ma)
1877 self.AutoGenTime += int(round((time.time() - AutoGenStart)))
1878 MakeStart = time.time()
1879 for Ma in self.BuildModules:
1880 if not Ma.IsBinaryModule:
1881 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))
1882 # Break build if any build thread has error
1883 if BuildTask.HasError():
1884 # we need a full version of makefile for platform
1885 ExitFlag.set()
1886 BuildTask.WaitForComplete()
1887 Pa.CreateMakeFile(False)
1888 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1889 # Start task scheduler
1890 if not BuildTask.IsOnGoing():
1891 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
1892
1893 # in case there's an interruption. we need a full version of makefile for platform
1894 Pa.CreateMakeFile(False)
1895 if BuildTask.HasError():
1896 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1897 self.MakeTime += int(round((time.time() - MakeStart)))
1898
1899 MakeContiue = time.time()
1900 ExitFlag.set()
1901 BuildTask.WaitForComplete()
1902 self.CreateAsBuiltInf()
1903 self.MakeTime += int(round((time.time() - MakeContiue)))
1904 if BuildTask.HasError():
1905 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1906
1907 self.BuildReport.AddPlatformReport(Wa, MaList)
1908 if MaList == []:
1909 EdkLogger.error(
1910 'build',
1911 BUILD_ERROR,
1912 "Module for [%s] is not a component of active platform."\
1913 " Please make sure that the ARCH and inf file path are"\
1914 " given in the same as in [%s]" % \
1915 (', '.join(Wa.ArchList), self.PlatformFile),
1916 ExtraData=self.ModuleFile
1917 )
1918 # Create MAP file when Load Fix Address is enabled.
1919 if self.Target == "fds" and self.Fdf:
1920 for Arch in Wa.ArchList:
1921 #
1922 # Check whether the set fix address is above 4G for 32bit image.
1923 #
1924 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1925 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")
1926 #
1927 # Get Module List
1928 #
1929 ModuleList = {}
1930 for Pa in Wa.AutoGenObjectList:
1931 for Ma in Pa.ModuleAutoGenList:
1932 if Ma is None:
1933 continue
1934 if not Ma.IsLibrary:
1935 ModuleList[Ma.Guid.upper()] = Ma
1936
1937 MapBuffer = BytesIO('')
1938 if self.LoadFixAddress != 0:
1939 #
1940 # Rebase module to the preferred memory address before GenFds
1941 #
1942 self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1943 #
1944 # create FDS again for the updated EFI image
1945 #
1946 GenFdsStart = time.time()
1947 self._Build("fds", Wa)
1948 self.GenFdsTime += int(round((time.time() - GenFdsStart)))
1949 #
1950 # Create MAP file for all platform FVs after GenFds.
1951 #
1952 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1953 #
1954 # Save MAP buffer into MAP file.
1955 #
1956 self._SaveMapFile (MapBuffer, Wa)
1957
1958 def _GenFfsCmd(self):
1959 # convert dictionary of Cmd:(Inf,Arch)
1960 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
1961 CmdSetDict = defaultdict(set)
1962 GenFfsDict = GenFds.GenFfsMakefile('', GlobalData.gFdfParser, self, self.ArchList, GlobalData)
1963 for Cmd in GenFfsDict:
1964 tmpInf, tmpArch = GenFfsDict[Cmd]
1965 CmdSetDict[tmpInf, tmpArch].add(Cmd)
1966 return CmdSetDict
1967
1968 ## Build a platform in multi-thread mode
1969 #
1970 def _MultiThreadBuildPlatform(self):
1971 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1972 for BuildTarget in self.BuildTargetList:
1973 GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1974 index = 0
1975 for ToolChain in self.ToolChainList:
1976 WorkspaceAutoGenTime = time.time()
1977 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1978 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1979 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
1980 index += 1
1981 Wa = WorkspaceAutoGen(
1982 self.WorkspaceDir,
1983 self.PlatformFile,
1984 BuildTarget,
1985 ToolChain,
1986 self.ArchList,
1987 self.BuildDatabase,
1988 self.TargetTxt,
1989 self.ToolDef,
1990 self.Fdf,
1991 self.FdList,
1992 self.FvList,
1993 self.CapList,
1994 self.SkuId,
1995 self.UniFlag,
1996 self.Progress
1997 )
1998 self.Fdf = Wa.FdfFile
1999 self.LoadFixAddress = Wa.Platform.LoadFixAddress
2000 self.BuildReport.AddPlatformReport(Wa)
2001 Wa.CreateMakeFile(False)
2002
2003 # Add ffs build to makefile
2004 CmdListDict = None
2005 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:
2006 CmdListDict = self._GenFfsCmd()
2007
2008 # multi-thread exit flag
2009 ExitFlag = threading.Event()
2010 ExitFlag.clear()
2011 self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))
2012 for Arch in Wa.ArchList:
2013 AutoGenStart = time.time()
2014 GlobalData.gGlobalDefines['ARCH'] = Arch
2015 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
2016 if Pa is None:
2017 continue
2018 ModuleList = []
2019 for Inf in Pa.Platform.Modules:
2020 ModuleList.append(Inf)
2021 # Add the INF only list in FDF
2022 if GlobalData.gFdfParser is not None:
2023 for InfName in GlobalData.gFdfParser.Profile.InfList:
2024 Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)
2025 if Inf in Pa.Platform.Modules:
2026 continue
2027 ModuleList.append(Inf)
2028 for Module in ModuleList:
2029 # Get ModuleAutoGen object to generate C code file and makefile
2030 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
2031
2032 if Ma is None:
2033 continue
2034 if Ma.CanSkipbyHash():
2035 self.HashSkipModules.append(Ma)
2036 continue
2037
2038 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
2039 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
2040 # for target which must generate AutoGen code and makefile
2041 if not self.SkipAutoGen or self.Target == 'genc':
2042 Ma.CreateCodeFile(True)
2043 if self.Target == "genc":
2044 continue
2045
2046 if not self.SkipAutoGen or self.Target == 'genmake':
2047 if CmdListDict and self.Fdf and (Module.File, Arch) in CmdListDict:
2048 Ma.CreateMakeFile(True, CmdListDict[Module.File, Arch])
2049 del CmdListDict[Module.File, Arch]
2050 else:
2051 Ma.CreateMakeFile(True)
2052 if self.Target == "genmake":
2053 continue
2054 self.BuildModules.append(Ma)
2055 self.Progress.Stop("done!")
2056 self.AutoGenTime += int(round((time.time() - AutoGenStart)))
2057 MakeStart = time.time()
2058 for Ma in self.BuildModules:
2059 # Generate build task for the module
2060 if not Ma.IsBinaryModule:
2061 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))
2062 # Break build if any build thread has error
2063 if BuildTask.HasError():
2064 # we need a full version of makefile for platform
2065 ExitFlag.set()
2066 BuildTask.WaitForComplete()
2067 Pa.CreateMakeFile(False)
2068 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
2069 # Start task scheduler
2070 if not BuildTask.IsOnGoing():
2071 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
2072
2073 # in case there's an interruption. we need a full version of makefile for platform
2074 Pa.CreateMakeFile(False)
2075 if BuildTask.HasError():
2076 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
2077 self.MakeTime += int(round((time.time() - MakeStart)))
2078
2079 MakeContiue = time.time()
2080
2081 #
2082 #
2083 # All modules have been put in build tasks queue. Tell task scheduler
2084 # to exit if all tasks are completed
2085 #
2086 ExitFlag.set()
2087 BuildTask.WaitForComplete()
2088 self.CreateAsBuiltInf()
2089 self.MakeTime += int(round((time.time() - MakeContiue)))
2090 #
2091 # Check for build error, and raise exception if one
2092 # has been signaled.
2093 #
2094 if BuildTask.HasError():
2095 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
2096
2097 # Create MAP file when Load Fix Address is enabled.
2098 if self.Target in ["", "all", "fds"]:
2099 for Arch in Wa.ArchList:
2100 #
2101 # Check whether the set fix address is above 4G for 32bit image.
2102 #
2103 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
2104 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")
2105 #
2106 # Get Module List
2107 #
2108 ModuleList = {}
2109 for Pa in Wa.AutoGenObjectList:
2110 for Ma in Pa.ModuleAutoGenList:
2111 if Ma is None:
2112 continue
2113 if not Ma.IsLibrary:
2114 ModuleList[Ma.Guid.upper()] = Ma
2115 #
2116 # Rebase module to the preferred memory address before GenFds
2117 #
2118 MapBuffer = BytesIO('')
2119 if self.LoadFixAddress != 0:
2120 self._CollectModuleMapBuffer(MapBuffer, ModuleList)
2121
2122 if self.Fdf:
2123 #
2124 # Generate FD image if there's a FDF file found
2125 #
2126 GenFdsStart = time.time()
2127 if GenFdsApi(Wa.GenFdsCommandDict, self.Db):
2128 EdkLogger.error("build", COMMAND_FAILURE)
2129
2130 #
2131 # Create MAP file for all platform FVs after GenFds.
2132 #
2133 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
2134 self.GenFdsTime += int(round((time.time() - GenFdsStart)))
2135 #
2136 # Save MAP buffer into MAP file.
2137 #
2138 self._SaveMapFile(MapBuffer, Wa)
2139
2140 ## Generate GuidedSectionTools.txt in the FV directories.
2141 #
2142 def CreateGuidedSectionToolsFile(self):
2143 for BuildTarget in self.BuildTargetList:
2144 for ToolChain in self.ToolChainList:
2145 Wa = WorkspaceAutoGen(
2146 self.WorkspaceDir,
2147 self.PlatformFile,
2148 BuildTarget,
2149 ToolChain,
2150 self.ArchList,
2151 self.BuildDatabase,
2152 self.TargetTxt,
2153 self.ToolDef,
2154 self.Fdf,
2155 self.FdList,
2156 self.FvList,
2157 self.CapList,
2158 self.SkuId,
2159 self.UniFlag
2160 )
2161 FvDir = Wa.FvDir
2162 if not os.path.exists(FvDir):
2163 continue
2164
2165 for Arch in self.ArchList:
2166 # Build up the list of supported architectures for this build
2167 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)
2168
2169 # Look through the tool definitions for GUIDed tools
2170 guidAttribs = []
2171 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():
2172 if attrib.upper().endswith('_GUID'):
2173 split = attrib.split('_')
2174 thisPrefix = '_'.join(split[0:3]) + '_'
2175 if thisPrefix == prefix:
2176 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]
2177 guid = guid.lower()
2178 toolName = split[3]
2179 path = '_'.join(split[0:4]) + '_PATH'
2180 path = self.ToolDef.ToolsDefTxtDictionary[path]
2181 path = self.GetFullPathOfTool(path)
2182 guidAttribs.append((guid, toolName, path))
2183
2184 # Write out GuidedSecTools.txt
2185 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')
2186 toolsFile = open(toolsFile, 'wt')
2187 for guidedSectionTool in guidAttribs:
2188 print(' '.join(guidedSectionTool), file=toolsFile)
2189 toolsFile.close()
2190
2191 ## Returns the full path of the tool.
2192 #
2193 def GetFullPathOfTool (self, tool):
2194 if os.path.exists(tool):
2195 return os.path.realpath(tool)
2196 else:
2197 # We need to search for the tool using the
2198 # PATH environment variable.
2199 for dirInPath in os.environ['PATH'].split(os.pathsep):
2200 foundPath = os.path.join(dirInPath, tool)
2201 if os.path.exists(foundPath):
2202 return os.path.realpath(foundPath)
2203
2204 # If the tool was not found in the path then we just return
2205 # the input tool.
2206 return tool
2207
2208 ## Launch the module or platform build
2209 #
2210 def Launch(self):
2211 if not self.ModuleFile:
2212 if not self.SpawnMode or self.Target not in ["", "all"]:
2213 self.SpawnMode = False
2214 self._BuildPlatform()
2215 else:
2216 self._MultiThreadBuildPlatform()
2217 self.CreateGuidedSectionToolsFile()
2218 else:
2219 self.SpawnMode = False
2220 self._BuildModule()
2221
2222 if self.Target == 'cleanall':
2223 RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)
2224
2225 def CreateAsBuiltInf(self):
2226 for Module in self.BuildModules:
2227 Module.CreateAsBuiltInf()
2228 for Module in self.HashSkipModules:
2229 Module.CreateAsBuiltInf(True)
2230 self.BuildModules = []
2231 self.HashSkipModules = []
2232 ## Do some clean-up works when error occurred
2233 def Relinquish(self):
2234 OldLogLevel = EdkLogger.GetLevel()
2235 EdkLogger.SetLevel(EdkLogger.ERROR)
2236 #self.DumpBuildData()
2237 Utils.Progressor.Abort()
2238 if self.SpawnMode == True:
2239 BuildTask.Abort()
2240 EdkLogger.SetLevel(OldLogLevel)
2241
2242 def DumpBuildData(self):
2243 CacheDirectory = os.path.dirname(GlobalData.gDatabasePath)
2244 Utils.CreateDirectory(CacheDirectory)
2245 Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))
2246 Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))
2247
2248 def RestoreBuildData(self):
2249 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gFileTimeStampCache")
2250 if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):
2251 Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)
2252 if Utils.gFileTimeStampCache is None:
2253 Utils.gFileTimeStampCache = {}
2254
2255 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gDependencyDatabase")
2256 if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):
2257 Utils.gDependencyDatabase = Utils.DataRestore(FilePath)
2258 if Utils.gDependencyDatabase is None:
2259 Utils.gDependencyDatabase = {}
2260
2261 def ParseDefines(DefineList=[]):
2262 DefineDict = {}
2263 if DefineList is not None:
2264 for Define in DefineList:
2265 DefineTokenList = Define.split("=", 1)
2266 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):
2267 EdkLogger.error('build', FORMAT_INVALID,
2268 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2269 ExtraData=DefineTokenList[0])
2270
2271 if len(DefineTokenList) == 1:
2272 DefineDict[DefineTokenList[0]] = "TRUE"
2273 else:
2274 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()
2275 return DefineDict
2276
2277 gParamCheck = []
2278 def SingleCheckCallback(option, opt_str, value, parser):
2279 if option not in gParamCheck:
2280 setattr(parser.values, option.dest, value)
2281 gParamCheck.append(option)
2282 else:
2283 parser.error("Option %s only allows one instance in command line!" % option)
2284
2285 def LogBuildTime(Time):
2286 if Time:
2287 TimeDurStr = ''
2288 TimeDur = time.gmtime(Time)
2289 if TimeDur.tm_yday > 1:
2290 TimeDurStr = time.strftime("%H:%M:%S", TimeDur) + ", %d day(s)" % (TimeDur.tm_yday - 1)
2291 else:
2292 TimeDurStr = time.strftime("%H:%M:%S", TimeDur)
2293 return TimeDurStr
2294 else:
2295 return None
2296
2297 ## Parse command line options
2298 #
2299 # Using standard Python module optparse to parse command line option of this tool.
2300 #
2301 # @retval Opt A optparse.Values object containing the parsed options
2302 # @retval Args Target of build command
2303 #
2304 def MyOptionParser():
2305 Parser = OptionParser(description=__copyright__, version=__version__, prog="build.exe", usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
2306 Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32', 'X64', 'IPF', 'EBC', 'ARM', 'AARCH64'], dest="TargetArch",
2307 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.")
2308 Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,
2309 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
2310 Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,
2311 help="Build the module specified by the INF file name argument.")
2312 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
2313 action="append")
2314 Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",
2315 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
2316 Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,
2317 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
2318
2319 Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,
2320 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 "\
2321 "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.")
2322
2323 Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,
2324 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
2325 Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],
2326 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
2327 Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],
2328 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
2329 Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],
2330 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
2331 Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")
2332 Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")
2333
2334 Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.")
2335
2336 Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")
2337 Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")
2338
2339 Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",
2340 help="Make use of silent mode of (n)make.")
2341 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
2342 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
2343 "including library instances selected, final dependency expression, "\
2344 "and warning messages, etc.")
2345 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
2346 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
2347
2348 Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")
2349 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=[],
2350 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]. "\
2351 "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]")
2352 Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",
2353 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. "\
2354 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
2355 "will override the setting in [BuildOptions] section of platform DSC.")
2356 Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism")
2357 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")
2358 Parser.add_option("--check-usage", action="store_true", dest="CheckUsage", default=False, help="Check usage content of entries listed in INF file.")
2359 Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")
2360 Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
2361 Parser.add_option("-l", "--cmd-len", action="store", type="int", dest="CommandLength", help="Specify the maximum line length of build command. Default is 4096.")
2362 Parser.add_option("--hash", action="store_true", dest="UseHashCache", default=False, help="Enable hash-based caching during build process.")
2363 Parser.add_option("--binary-destination", action="store", type="string", dest="BinCacheDest", help="Generate a cache of binary files in the specified directory.")
2364 Parser.add_option("--binary-source", action="store", type="string", dest="BinCacheSource", help="Consume a cache of binary files from the specified directory.")
2365 Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=False, help="Enable GenFds multi thread to generate ffs file.")
2366 (Opt, Args) = Parser.parse_args()
2367 return (Opt, Args)
2368
2369 ## Tool entrance method
2370 #
2371 # This method mainly dispatch specific methods per the command line options.
2372 # If no error found, return zero value so the caller of this tool can know
2373 # if it's executed successfully or not.
2374 #
2375 # @retval 0 Tool was successful
2376 # @retval 1 Tool failed
2377 #
2378 def Main():
2379 StartTime = time.time()
2380
2381 # Initialize log system
2382 EdkLogger.Initialize()
2383 GlobalData.gCommand = sys.argv[1:]
2384 #
2385 # Parse the options and args
2386 #
2387 (Option, Target) = MyOptionParser()
2388 GlobalData.gOptions = Option
2389 GlobalData.gCaseInsensitive = Option.CaseInsensitive
2390
2391 # Set log level
2392 if Option.verbose is not None:
2393 EdkLogger.SetLevel(EdkLogger.VERBOSE)
2394 elif Option.quiet is not None:
2395 EdkLogger.SetLevel(EdkLogger.QUIET)
2396 elif Option.debug is not None:
2397 EdkLogger.SetLevel(Option.debug + 1)
2398 else:
2399 EdkLogger.SetLevel(EdkLogger.INFO)
2400
2401 if Option.LogFile is not None:
2402 EdkLogger.SetLogFile(Option.LogFile)
2403
2404 if Option.WarningAsError == True:
2405 EdkLogger.SetWarningAsError()
2406
2407 if platform.platform().find("Windows") >= 0:
2408 GlobalData.gIsWindows = True
2409 else:
2410 GlobalData.gIsWindows = False
2411
2412 EdkLogger.quiet("Build environment: %s" % platform.platform())
2413 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));
2414 ReturnCode = 0
2415 MyBuild = None
2416 BuildError = True
2417 try:
2418 if len(Target) == 0:
2419 Target = "all"
2420 elif len(Target) >= 2:
2421 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",
2422 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))
2423 else:
2424 Target = Target[0].lower()
2425
2426 if Target not in gSupportedTarget:
2427 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,
2428 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))
2429
2430 #
2431 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2432 #
2433 CheckEnvVariable()
2434 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))
2435
2436 Workspace = os.getenv("WORKSPACE")
2437 #
2438 # Get files real name in workspace dir
2439 #
2440 GlobalData.gAllFiles = Utils.DirCache(Workspace)
2441
2442 WorkingDirectory = os.getcwd()
2443 if not Option.ModuleFile:
2444 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))
2445 FileNum = len(FileList)
2446 if FileNum >= 2:
2447 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),
2448 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2449 elif FileNum == 1:
2450 Option.ModuleFile = NormFile(FileList[0], Workspace)
2451
2452 if Option.ModuleFile:
2453 if os.path.isabs (Option.ModuleFile):
2454 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:
2455 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)
2456 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)
2457 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)
2458 if ErrorCode != 0:
2459 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
2460
2461 if Option.PlatformFile is not None:
2462 if os.path.isabs (Option.PlatformFile):
2463 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:
2464 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)
2465 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)
2466
2467 if Option.FdfFile is not None:
2468 if os.path.isabs (Option.FdfFile):
2469 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:
2470 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)
2471 Option.FdfFile = PathClass(Option.FdfFile, Workspace)
2472 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)
2473 if ErrorCode != 0:
2474 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
2475
2476 if Option.Flag is not None and Option.Flag not in ['-c', '-s']:
2477 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")
2478
2479 MyBuild = Build(Target, Workspace, Option)
2480 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)
2481 if not (MyBuild.LaunchPrebuildFlag and os.path.exists(MyBuild.PlatformBuildPath)):
2482 MyBuild.Launch()
2483
2484 #MyBuild.DumpBuildData()
2485 #
2486 # All job done, no error found and no exception raised
2487 #
2488 BuildError = False
2489 except FatalError as X:
2490 if MyBuild is not None:
2491 # for multi-thread build exits safely
2492 MyBuild.Relinquish()
2493 if Option is not None and Option.debug is not None:
2494 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2495 ReturnCode = X.args[0]
2496 except Warning as X:
2497 # error from Fdf parser
2498 if MyBuild is not None:
2499 # for multi-thread build exits safely
2500 MyBuild.Relinquish()
2501 if Option is not None and Option.debug is not None:
2502 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2503 else:
2504 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)
2505 ReturnCode = FORMAT_INVALID
2506 except KeyboardInterrupt:
2507 ReturnCode = ABORT_ERROR
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 except:
2511 if MyBuild is not None:
2512 # for multi-thread build exits safely
2513 MyBuild.Relinquish()
2514
2515 # try to get the meta-file from the object causing exception
2516 Tb = sys.exc_info()[-1]
2517 MetaFile = GlobalData.gProcessingFile
2518 while Tb is not None:
2519 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):
2520 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile
2521 Tb = Tb.tb_next
2522 EdkLogger.error(
2523 "\nbuild",
2524 CODE_ERROR,
2525 "Unknown fatal error when processing [%s]" % MetaFile,
2526 ExtraData="\n(Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!)\n",
2527 RaiseError=False
2528 )
2529 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2530 ReturnCode = CODE_ERROR
2531 finally:
2532 Utils.Progressor.Abort()
2533 Utils.ClearDuplicatedInf()
2534
2535 if ReturnCode == 0:
2536 try:
2537 MyBuild.LaunchPostbuild()
2538 Conclusion = "Done"
2539 except:
2540 Conclusion = "Failed"
2541 elif ReturnCode == ABORT_ERROR:
2542 Conclusion = "Aborted"
2543 else:
2544 Conclusion = "Failed"
2545 FinishTime = time.time()
2546 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))
2547 BuildDurationStr = ""
2548 if BuildDuration.tm_yday > 1:
2549 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)" % (BuildDuration.tm_yday - 1)
2550 else:
2551 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)
2552 if MyBuild is not None:
2553 if not BuildError:
2554 MyBuild.BuildReport.GenerateReport(BuildDurationStr, LogBuildTime(MyBuild.AutoGenTime), LogBuildTime(MyBuild.MakeTime), LogBuildTime(MyBuild.GenFdsTime))
2555
2556 EdkLogger.SetLevel(EdkLogger.QUIET)
2557 EdkLogger.quiet("\n- %s -" % Conclusion)
2558 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))
2559 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)
2560 return ReturnCode
2561
2562 if __name__ == '__main__':
2563 r = Main()
2564 ## 0-127 is a safe return range, and 1 is a standard default error
2565 if r < 0 or r > 127: r = 1
2566 sys.exit(r)
2567