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