2 # build a platform or a module
\r
4 # Copyright (c) 2007, Intel Corporation
\r
6 # All rights reserved. This program and the accompanying materials
\r
7 # are licensed and made available under the terms and conditions of the BSD License
\r
8 # which accompanies this distribution. The full text of the license may be found at
\r
9 # http://opensource.org/licenses/bsd-license.php
\r
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
\r
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
\r
24 from threading import *
\r
25 from optparse import OptionParser
\r
26 from subprocess import *
\r
27 from Common import Misc as Utils
\r
29 from Common.TargetTxtClassObject import *
\r
30 from Common.ToolDefClassObject import *
\r
31 from Common.EdkIIWorkspaceBuild import *
\r
32 from Common.DataType import *
\r
33 from AutoGen.AutoGen import *
\r
34 from GenFds.FdfParser import *
\r
35 from Common.BuildToolError import *
\r
36 #from Common.Misc import *
\r
37 import Common.EdkLogger
\r
39 # Version and Copyright
\r
40 VersionNumber = "0.02"
\r
41 __version__ = "%prog Version " + VersionNumber
\r
42 __copyright__ = "Copyright (c) 2007, Intel Corporation All rights reserved."
\r
44 ## standard targets of build command
\r
45 gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
\r
47 ## build configuration file
\r
48 gBuildConfiguration = "Conf/target.txt"
\r
49 gBuildCacheDir = "Conf/.cache"
\r
51 ## Check environment variables
\r
53 # Check environment variables that must be set for build. Currently they are
\r
55 # WORKSPACE The directory all packages/platforms start from
\r
56 # EDK_TOOLS_PATH The directory contains all tools needed by the build
\r
57 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
\r
59 # If any of above environment variable is not set or has error, the build
\r
62 def CheckEnvVariable():
\r
64 if "WORKSPACE" not in os.environ:
\r
65 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Please set environment variable: WORKSPACE!\n")
\r
67 # check EDK_TOOLS_PATH
\r
68 if "EDK_TOOLS_PATH" not in os.environ == None:
\r
69 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Please set environment variable: EDK_TOOLS_PATH!\n")
\r
72 if "PATH" not in os.environ:
\r
73 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Please set environment variable: PATH!\n")
\r
75 PathString = os.environ["PATH"]
\r
76 ToolPath = os.path.normpath(os.path.join(os.environ["EDK_TOOLS_PATH"], 'Bin', sys.platform.title()))
\r
78 if PathString.find(ToolPath) == -1:
\r
79 os.environ['PATH'] = os.path.pathsep.join((os.environ['PATH'], ToolPath))
\r
81 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Please execute %s to set %s in environment variable: PATH!\n"
\r
82 % (os.path.normpath(os.path.join(PathString, 'edksetup.bat')), ToolPath))
\r
84 ## Get normalized file path
\r
86 # Convert the path to be local format, and remove the WORKSPACE path at the
\r
87 # beginning if the file path is given in full path.
\r
89 # @param FilePath File path to be normalized
\r
90 # @param Workspace Workspace path which the FilePath will be checked against
\r
92 # @retval string The normalized file path
\r
94 def NormFile(FilePath, Workspace):
\r
95 # check if the path is absolute or relative
\r
96 if os.path.isabs(FilePath):
\r
97 FileFullPath = os.path.normpath(FilePath)
\r
99 FileFullPath = os.path.normpath(os.path.join(Workspace, FilePath))
\r
101 # check if the file path exists or not
\r
102 if not os.path.isfile(FileFullPath):
\r
103 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath)
\r
105 # remove workspace directory from the beginning part of the file path
\r
106 if Workspace[-1] in ["\\", "/"]:
\r
107 return FileFullPath[len(Workspace):]
\r
109 return FileFullPath[(len(Workspace) + 1):]
\r
111 ## Get the output of an external program
\r
113 # This is the entrance method of thread reading output of an external program and
\r
114 # putting them in STDOUT/STDERR of current program.
\r
116 # @param From The stream message read from
\r
117 # @param To The stream message put on
\r
118 # @param ExitFlag The flag used to indicate stopping reading
\r
120 def ReadMessage(From, To, ExitFlag):
\r
122 # read one line a time
\r
123 Line = From.readline()
\r
124 # empty string means "end"
\r
125 if Line != None and Line != "":
\r
129 if ExitFlag.isSet():
\r
132 ## Launch an external program
\r
134 # This method will call subprocess.Popen to execute an external program with
\r
135 # given options in specified directory. Because of the dead-lock issue during
\r
136 # redirecting output of the external program, threads are used to to do the
\r
137 # redirection work.
\r
139 # @param Command A list or string containing the call of the program
\r
140 # @param WorkingDir The directory in which the program will be running
\r
142 def LaunchCommand(Command, WorkingDir):
\r
143 # if working directory doesn't exist, Popen() will raise an exception
\r
144 if not os.path.isdir(WorkingDir):
\r
145 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=WorkingDir)
\r
148 EndOfProcedure = None
\r
150 # launch the command
\r
151 Proc = Popen(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir)
\r
153 # launch two threads to read the STDOUT and STDERR
\r
154 EndOfProcedure = Event()
\r
155 EndOfProcedure.clear()
\r
157 StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure))
\r
158 StdOutThread.setName("STDOUT-Redirector")
\r
159 StdOutThread.setDaemon(False)
\r
160 StdOutThread.start()
\r
163 StdErrThread = Thread(target=ReadMessage, args=(Proc.stderr, EdkLogger.quiet, EndOfProcedure))
\r
164 StdErrThread.setName("STDERR-Redirector")
\r
165 StdErrThread.setDaemon(False)
\r
166 StdErrThread.start()
\r
168 # waiting for program exit
\r
170 except: # in case of aborting
\r
171 # terminate the threads redirecting the program output
\r
172 if EndOfProcedure != None:
\r
173 EndOfProcedure.set()
\r
175 if type(Command) != type(""):
\r
176 Command = " ".join(Command)
\r
177 EdkLogger.error("build", COMMAND_FAILURE, "Failed to start command", ExtraData="%s [%s]" % (Command, WorkingDir))
\r
180 StdOutThread.join()
\r
182 StdErrThread.join()
\r
184 # check the return code of the program
\r
185 if Proc.returncode != 0:
\r
186 if type(Command) != type(""):
\r
187 Command = " ".join(Command)
\r
188 EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir))
\r
190 ## The smallest unit that can be built in multi-thread build mode
\r
192 # This is the base class of build unit. The "Obj" parameter must provide
\r
193 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
\r
196 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
\r
201 # @param self The object pointer
\r
202 # @param Obj The object the build is working on
\r
203 # @param Target The build target name, one of gSupportedTarget
\r
204 # @param Dependency The BuildUnit(s) which must be completed in advance
\r
205 # @param WorkingDir The directory build command starts in
\r
207 def __init__(self, Obj, BuildComamnd, Target, Dependency, WorkingDir="."):
\r
208 self.BuildObject = Obj
\r
209 self.Dependency = Dependency
\r
210 self.WorkingDir = WorkingDir
\r
211 self.Target = Target
\r
212 self.BuildCommand = BuildComamnd
\r
216 # It just returns the string representaion of self.BuildObject
\r
218 # @param self The object pointer
\r
221 return str(self.BuildObject)
\r
223 ## "==" operator method
\r
225 # It just compares self.BuildObject with "Other". So self.BuildObject must
\r
226 # provide its own __eq__() method.
\r
228 # @param self The object pointer
\r
229 # @param Other The other BuildUnit object compared to
\r
231 def __eq__(self, Other):
\r
232 return Other != None and self.BuildObject == Other.BuildObject
\r
236 # It just returns the hash value of self.BuildObject which must be hashable.
\r
238 # @param self The object pointer
\r
240 def __hash__(self):
\r
241 return hash(self.BuildObject)
\r
243 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
\r
245 # This class is for module build by nmake/make build system. The "Obj" parameter
\r
246 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
\r
247 # be make units missing build.
\r
249 # Currently the "Obj" should be only ModuleAutoGen object.
\r
251 class ModuleMakeUnit(BuildUnit):
\r
254 # @param self The object pointer
\r
255 # @param Obj The ModuleAutoGen object the build is working on
\r
256 # @param Target The build target name, one of gSupportedTarget
\r
258 def __init__(self, Obj, Target):
\r
259 Dependency = [ModuleMakeUnit(La, Target) for La in Obj.BuildInfo.LibraryAutoGenList]
\r
260 BuildUnit.__init__(self, Obj, Obj.GetBuildCommand(), Target, Dependency, Obj.GetMakeFileDir())
\r
261 if Target in [None, "", "all"]:
\r
262 self.Target = "pbuild"
\r
264 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
\r
266 # This class is for platform build by nmake/make build system. The "Obj" parameter
\r
267 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
\r
268 # be make units missing build.
\r
270 # Currently the "Obj" should be only PlatformAutoGen object.
\r
272 class PlatformMakeUnit(BuildUnit):
\r
275 # @param self The object pointer
\r
276 # @param Obj The PlatformAutoGen object the build is working on
\r
277 # @param Target The build target name, one of gSupportedTarget
\r
279 def __init__(self, Obj, Target):
\r
280 Dependency = [ModuleMakeUnit(Lib, Target) for Lib in self.BuildObject.BuildInfo.LibraryAutoGenList]
\r
281 Dependency.extend([ModuleMakeUnit(Mod, Target) for Mod in self.BuildObject.BuildInfo.ModuleAutoGenList])
\r
282 BuildUnit.__init__(self, Obj, Obj.GetBuildCommand(), Target, Dependency, Obj.GetMakeFileDir())
\r
284 ## The class representing the task of a module build or platform build
\r
286 # This class manages the build tasks in multi-thread build mode. Its jobs include
\r
287 # scheduling thread running, catching thread error, monitor the thread status, etc.
\r
290 # queue for tasks waiting for schedule
\r
291 _PendingQueue = sdict()
\r
292 _PendingQueueLock = threading.Lock()
\r
294 # queue for tasks ready for running
\r
295 _ReadyQueue = sdict()
\r
296 _ReadyQueueLock = threading.Lock()
\r
298 # queue for run tasks
\r
299 _RunningQueue = sdict()
\r
300 _RunningQueueLock = threading.Lock()
\r
302 # queue containing all build tasks, in case duplicate build
\r
303 _TaskQueue = sdict()
\r
305 # flag indicating error occurs in a running thread
\r
306 _ErrorFlag = threading.Event()
\r
310 # BoundedSemaphore object used to control the number of running threads
\r
313 # flag indicating if the scheduler is started or not
\r
314 _SchedulerStopped = threading.Event()
\r
315 _SchedulerStopped.set()
\r
317 ## Start the task scheduler thread
\r
319 # @param MaxThreadNumber The maximum thread number
\r
320 # @param ExitFlag Flag used to end the scheduler
\r
323 def StartScheduler(MaxThreadNumber, ExitFlag):
\r
324 BuildTask._PendingQueue.clear()
\r
325 BuildTask._ReadyQueue.clear()
\r
326 BuildTask._RunningQueue.clear()
\r
327 BuildTask._TaskQueue.clear()
\r
328 BuildTask._ErrorFlag.clear()
\r
329 BuildTask._ErrorMessage = ""
\r
330 BuildTask._Thread = None
\r
332 SchedulerThread = Thread(target=BuildTask.Scheduler, args=(MaxThreadNumber, ExitFlag))
\r
333 SchedulerThread.setName("Build-Task-Scheduler")
\r
334 SchedulerThread.setDaemon(False)
\r
335 SchedulerThread.start()
\r
337 ## Scheduler method
\r
339 # @param MaxThreadNumber The maximum thread number
\r
340 # @param ExitFlag Flag used to end the scheduler
\r
343 def Scheduler(MaxThreadNumber, ExitFlag):
\r
344 BuildTask._SchedulerStopped.clear()
\r
346 # use BoundedSemaphore to control the maximum running threads
\r
347 BuildTask._Thread = BoundedSemaphore(MaxThreadNumber)
\r
349 # scheduling loop, which will exits when no pending/ready task and
\r
350 # indicated to do so, or there's error in running thread
\r
352 while (len(BuildTask._PendingQueue) > 0 or len(BuildTask._ReadyQueue) > 0 \
\r
353 or not ExitFlag.isSet()) and not BuildTask._ErrorFlag.isSet():
\r
354 EdkLogger.debug(EdkLogger.DEBUG_9, "Pending Queue (%d), Ready Queue (%d)"
\r
355 % (len(BuildTask._PendingQueue), len(BuildTask._ReadyQueue)))
\r
356 # get all pending tasks
\r
357 BuildTask._PendingQueueLock.acquire()
\r
358 BuildObjectList = BuildTask._PendingQueue.keys()
\r
359 BuildTask._PendingQueueLock.release()
\r
362 # check if their dependency is resolved, and if true, move them
\r
365 for BuildObject in BuildObjectList:
\r
366 Bt = BuildTask._PendingQueue[BuildObject]
\r
368 BuildTask._PendingQueueLock.acquire()
\r
369 BuildTask._ReadyQueue[BuildObject] = BuildTask._PendingQueue.pop(BuildObject)
\r
370 BuildTask._PendingQueueLock.release()
\r
372 # launch build thread until the maximum number of threads is reached
\r
373 while not BuildTask._ErrorFlag.isSet():
\r
374 # empty ready queue, do nothing further
\r
375 if len(BuildTask._ReadyQueue) == 0:
\r
378 # wait for active thread(s) exit
\r
379 BuildTask._Thread.acquire(True)
\r
381 # start a new build thread
\r
382 Bo = BuildTask._ReadyQueue.keys()[0]
\r
383 Bt = BuildTask._ReadyQueue.pop(Bo)
\r
385 # move into running queue
\r
386 BuildTask._RunningQueueLock.acquire()
\r
387 BuildTask._RunningQueue[Bo] = Bt
\r
388 BuildTask._RunningQueueLock.release()
\r
395 # wait for all running threads exit
\r
396 if BuildTask._ErrorFlag.isSet():
\r
397 EdkLogger.quiet("\nWaiting for all Command-Threads exit...")
\r
398 # while not BuildTask._ErrorFlag.isSet() and \
\r
399 while len(BuildTask._RunningQueue) > 0:
\r
400 EdkLogger.verbose("Waiting for thread ending...(%d)" % len(BuildTask._RunningQueue))
\r
401 EdkLogger.debug(EdkLogger.DEBUG_9, "Threads [%s]" % ", ".join([Th.getName() for Th in threading.enumerate()]))
\r
404 except BaseException, X:
\r
406 # TRICK: hide the output of threads left runing, so that the user can
\r
407 # catch the error message easily
\r
409 EdkLogger.SetLevel(EdkLogger.QUIET)
\r
410 BuildTask._ErrorFlag.set()
\r
411 BuildTask._ErrorMessage = "build thread scheduler error\n\t%s" % str(X)
\r
412 BuildTask._SchedulerStopped.set()
\r
414 ## Wait for all running method exit
\r
417 def WaitForComplete():
\r
418 BuildTask._SchedulerStopped.wait()
\r
420 ## Check if the scheduler is running or not
\r
424 return not BuildTask._SchedulerStopped.isSet()
\r
429 if BuildTask.IsOnGoing():
\r
430 BuildTask._ErrorFlag.set()
\r
431 BuildTask.WaitForComplete()
\r
433 ## Check if there's error in running thread
\r
435 # Since the main thread cannot catch exceptions in other thread, we have to
\r
436 # use threading.Event to communicate this formation to main thread.
\r
440 return BuildTask._ErrorFlag.isSet()
\r
442 ## Get error message in running thread
\r
444 # Since the main thread cannot catch exceptions in other thread, we have to
\r
445 # use a static variable to communicate this message to main thread.
\r
448 def GetErrorMessage():
\r
449 return BuildTask._ErrorMessage
\r
451 ## Factory method to create a BuildTask object
\r
453 # This method will check if a module is building or has been built. And if
\r
454 # true, just return the associated BuildTask object in the _TaskQueue. If
\r
455 # not, create and return a new BuildTask object. The new BuildTask object
\r
456 # will be appended to the _PendingQueue for scheduling later.
\r
458 # @param BuildItem A BuildUnit object representing a build object
\r
459 # @param Dependency The dependent build object of BuildItem
\r
462 def New(BuildItem, Dependency=None):
\r
463 if BuildItem in BuildTask._TaskQueue:
\r
464 Bt = BuildTask._TaskQueue[BuildItem]
\r
468 Bt._Init(BuildItem, Dependency)
\r
469 BuildTask._TaskQueue[BuildItem] = Bt
\r
471 BuildTask._PendingQueueLock.acquire()
\r
472 BuildTask._PendingQueue[BuildItem] = Bt
\r
473 BuildTask._PendingQueueLock.release()
\r
477 ## The real constructor of BuildTask
\r
479 # @param BuildItem A BuildUnit object representing a build object
\r
480 # @param Dependency The dependent build object of BuildItem
\r
482 def _Init(self, BuildItem, Dependency=None):
\r
483 self.BuildItem = BuildItem
\r
485 self.DependencyList = []
\r
486 if Dependency == None:
\r
487 Dependency = BuildItem.Dependency
\r
489 Dependency.extend(BuildItem.Dependency)
\r
490 self.AddDependency(Dependency)
\r
491 # flag indicating build completes, used to avoid unnecessary re-build
\r
492 self.CompleteFlag = False
\r
494 ## Check if all dependent build tasks are completed or not
\r
498 for Dep in self.DependencyList:
\r
499 if Dep.CompleteFlag == True:
\r
506 ## Add dependent build task
\r
508 # @param Dependency The list of dependent build objects
\r
510 def AddDependency(self, Dependency):
\r
511 for Dep in Dependency:
\r
512 self.DependencyList.append(BuildTask.New(Dep)) # BuildTask list
\r
514 ## The thread wrapper of LaunchCommand function
\r
516 # @param Command A list or string contains the call of the command
\r
517 # @param WorkingDir The directory in which the program will be running
\r
519 def _CommandThread(self, Command, WorkingDir):
\r
521 LaunchCommand(Command, WorkingDir)
\r
522 self.CompleteFlag = True
\r
525 # TRICK: hide the output of threads left runing, so that the user can
\r
526 # catch the error message easily
\r
528 EdkLogger.SetLevel(EdkLogger.QUIET)
\r
529 BuildTask._ErrorFlag.set()
\r
530 BuildTask._ErrorMessage = "%s broken\n %s [%s]" % \
\r
531 (threading.currentThread().getName(), Command, WorkingDir)
\r
532 # indicate there's a thread is available for another build task
\r
533 BuildTask._RunningQueueLock.acquire()
\r
534 BuildTask._RunningQueue.pop(self.BuildItem)
\r
535 BuildTask._RunningQueueLock.release()
\r
536 BuildTask._Thread.release()
\r
538 ## Start build task thread
\r
541 Command = self.BuildItem.BuildCommand + (self.BuildItem.Target,)
\r
542 self.BuildTread = Thread(target=self._CommandThread, args=(Command, self.BuildItem.WorkingDir))
\r
543 self.BuildTread.setName("Command-Thread")
\r
544 self.BuildTread.setDaemon(False)
\r
545 self.BuildTread.start()
\r
547 ## The class implementing the EDK2 build process
\r
549 # The build process includes:
\r
550 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
\r
551 # 2. Parse DSC file of active platform
\r
552 # 3. Parse FDF file if any
\r
553 # 4. Establish build database, including parse all other files (module, package)
\r
554 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
\r
555 # 6. Call build command
\r
560 # Constructor will load all necessary configurations, parse platform, modules
\r
561 # and packages and the establish a database for AutoGen.
\r
563 # @param Target The build command target, one of gSupportedTarget
\r
564 # @param WorkspaceDir The directory of workspace
\r
565 # @param Platform The DSC file of active platform
\r
566 # @param Module The INF file of active module, if any
\r
567 # @param Arch The Arch list of platform or module
\r
568 # @param ToolChain The name list of toolchain
\r
569 # @param BuildTarget The "DEBUG" or "RELEASE" build
\r
570 # @param FlashDefinition The FDF file of active platform
\r
571 # @param FdList=[] The FD names to be individually built
\r
572 # @param FvList=[] The FV names to be individually built
\r
573 # @param MakefileType The type of makefile (for MSFT make or GNU make)
\r
574 # @param SpawnMode Indicate multi-thread build mode
\r
575 # @param ThreadNumber The maximum number of thread if in multi-thread build mode
\r
577 def __init__(self, Target, WorkspaceDir, Platform, Module, Arch, ToolChain, BuildTarget,
\r
578 FlashDefinition, FdList=[], FvList=[], MakefileType="nmake", SpawnMode=False, ThreadNumber=2):
\r
580 self.WorkspaceDir = WorkspaceDir
\r
582 self.Target = Target
\r
583 self.PlatformFile = Platform
\r
584 self.ModuleFile = Module
\r
585 self.ArchList = Arch
\r
586 self.ToolChainList = ToolChain
\r
587 self.BuildTargetList= BuildTarget
\r
588 self.Fdf = FlashDefinition
\r
589 self.FdList = FdList
\r
590 self.FvList = FvList
\r
591 self.MakefileType = MakefileType
\r
592 self.SpawnMode = SpawnMode
\r
593 self.ThreadNumber = ThreadNumber
\r
595 self.TargetTxt = TargetTxtClassObject()
\r
596 self.ToolDef = ToolDefClassObject()
\r
598 # print dot charater during doing some time-consuming work
\r
599 self.Progress = Utils.Progressor()
\r
601 # parse target.txt, tools_def.txt, and platform file
\r
602 self.Progress.Start("Loading build configuration")
\r
603 self.RestoreBuildData()
\r
604 self.LoadConfiguration()
\r
605 self.Progress.Stop("done!")
\r
607 self.Progress.Start("Parsing platform/modules/packages")
\r
609 self.Progress.Stop("done!")
\r
611 # print current build environment and configuration
\r
613 EdkLogger.quiet("%-24s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))
\r
614 EdkLogger.quiet("%-24s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))
\r
616 EdkLogger.info('%-24s = %s' % ("TARGET_ARCH", ' '.join(self.ArchList)))
\r
617 EdkLogger.info('%-24s = %s' % ("TARGET", ' '.join(self.BuildTargetList)))
\r
618 EdkLogger.info('%-24s = %s' % ("TOOL_CHAIN_TAG", ' '.join(self.ToolChainList)))
\r
621 if self.PlatformFile != None and self.PlatformFile != "":
\r
622 EdkLogger.info('%-24s = %s' % ("Active Platform", self.PlatformFile))
\r
624 if self.Fdf != None and self.Fdf != "":
\r
625 EdkLogger.info('%-24s = %s' % ("Flash Image Definition", self.Fdf))
\r
627 if self.ModuleFile != None and self.ModuleFile != "":
\r
628 EdkLogger.info('%-24s = %s' % ("Active Module", self.ModuleFile))
\r
631 EdkLogger.verbose('%-24s = %s' % ("Max Thread Number", self.ThreadNumber))
\r
633 # establish build database, INF/DEC files will be parsed in this stage
\r
634 self.Progress.Start("\nEstablishing build database")
\r
636 if self.Fdf != None and self.Fdf != "":
\r
637 FdfFile = os.path.join(self.WorkspaceDir, self.Fdf)
\r
639 Fdf = FdfParser(FdfFile)
\r
642 PcdSet = Fdf.Profile.PcdDict
\r
646 self.Ewb.GenBuildDatabase(PcdSet)
\r
647 self.Platform = self.Ewb.Build[self.ArchList[0]].PlatformDatabase[self.PlatformFile]
\r
649 except BaseException, X:
\r
650 if isinstance(X, Warning):
\r
651 EdkLogger.error(X.ToolName, BUILD_ERROR, X.message, X.FileName, X.LineNumber, RaiseError = False)
\r
653 self.Progress.Stop("done!")
\r
655 ## Load configuration
\r
657 # This method will parse target.txt and get the build configurations.
\r
659 def LoadConfiguration(self):
\r
661 # Check target.txt and tools_def.txt and Init them
\r
663 BuildConfigurationFile = os.path.normpath(os.path.join(self.WorkspaceDir, gBuildConfiguration))
\r
664 if os.path.isfile(BuildConfigurationFile) == True:
\r
665 StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)
\r
667 ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]
\r
668 ToolDefinitionFile = os.path.normpath(os.path.join(self.WorkspaceDir, ToolDefinitionFile))
\r
669 if os.path.isfile(ToolDefinitionFile) == True:
\r
670 StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)
\r
672 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)
\r
674 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)
\r
676 # if no ARCH given in command line, get it from target.txt
\r
677 if self.ArchList == None or len(self.ArchList) == 0:
\r
678 self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH]
\r
679 if len(self.ArchList) == 0:
\r
680 self.ArchList = ARCH_LIST
\r
682 # if no build target given in command line, get it from target.txt
\r
683 if self.BuildTargetList == None or len(self.BuildTargetList) == 0:
\r
684 self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]
\r
685 if self.BuildTargetList == None or len(self.BuildTargetList) == 0:
\r
686 self.BuildTargetList = ['DEBUG', 'RELEASE']
\r
688 # if no tool chain given in command line, get it from target.txt
\r
689 if self.ToolChainList == None or len(self.ToolChainList) == 0:
\r
690 self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]
\r
691 if self.ToolChainList == None or len(self.ToolChainList) == 0:
\r
692 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")
\r
694 # check if the tool chains are defined or not
\r
695 NewToolChainList = []
\r
696 for ToolChain in self.ToolChainList:
\r
697 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:
\r
698 EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)
\r
700 NewToolChainList.append(ToolChain)
\r
701 # if no tool chain available, break the build
\r
702 if len(NewToolChainList) == 0:
\r
703 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
\r
704 ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))
\r
706 self.ToolChainList = NewToolChainList
\r
708 if self.ThreadNumber == None or self.ThreadNumber == "":
\r
709 self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]
\r
710 if self.ThreadNumber == '':
\r
711 self.ThreadNumber = 0
\r
713 self.ThreadNumber = int(self.ThreadNumber, 0)
\r
715 if self.ThreadNumber == 0:
\r
716 self.SpawnMode = False
\r
717 elif self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MULTIPLE_THREAD].lower() in ["enable", "true"]:
\r
718 self.SpawnMode = True
\r
720 if self.PlatformFile == None:
\r
721 self.PlatformFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM]
\r
722 if self.PlatformFile == None or self.PlatformFile == "":
\r
723 WorkingDirectory = os.getcwd()
\r
724 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))
\r
725 FileNum = len(FileList)
\r
727 EdkLogger.error("build", None, "There are %d DSC files in %s.\n" % (FileNum, WorkingDirectory))
\r
729 self.PlatformFile = NormFile(FileList[0], self.WorkspaceDir)
\r
731 self.PlatformFile = NormFile(self.PlatformFile, self.WorkspaceDir)
\r
733 ## Initialize build configuration
\r
735 # This method will parse DSC file and merge the configurations from
\r
736 # command line and target.txt, then get the final build configurations.
\r
738 def InitBuild(self):
\r
739 if self.PlatformFile == None or self.PlatformFile == "":
\r
740 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE,
\r
741 ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")
\r
743 Wb = WorkspaceBuild(self.PlatformFile, self.WorkspaceDir)
\r
745 if self.Fdf != None:
\r
746 self.Fdf = NormFile(self.Fdf, self.WorkspaceDir)
\r
751 # parse FDF file to get PCD information
\r
752 if self.Fdf != None and self.Fdf != "":
\r
753 if Wb.Fdf == None or Wb.Fdf == "":
\r
756 Wb.FdTargetList.extend(self.FdList)
\r
757 Wb.FvTargetList.extend(self.FvList)
\r
760 if self.FdList != []:
\r
761 EdkLogger.info("No flash definition file found. FD [%s] will be ignored." % " ".join(self.FdList))
\r
762 if self.FvList != []:
\r
763 EdkLogger.info("No flash definition file found. FV [%s] will be ignored." % " ".join(self.FvList))
\r
765 Wb.TargetTxt = self.TargetTxt
\r
766 Wb.ToolDef = self.ToolDef
\r
770 if self.ArchList == None or len(self.ArchList) == 0:
\r
771 ArchList = Wb.SupArchList
\r
773 ArchList = list(set(self.ArchList) & set(Wb.SupArchList))
\r
774 if len(ArchList) == 0:
\r
775 EdkLogger.error("build", PARAMETER_INVALID,
\r
776 ExtraData = "Active platform supports [%s] only, but [%s] is given."
\r
777 % (" ".join(Wb.SupArchList), " ".join(self.ArchList)))
\r
778 elif len(ArchList) != len(self.ArchList):
\r
779 SkippedArchList = set(self.ArchList).symmetric_difference(set(Wb.SupArchList))
\r
780 EdkLogger.verbose("\nArch [%s] is ignored because active platform supports [%s] but [%s] is specified !"
\r
781 % (" ".join(SkippedArchList), " ".join(Wb.SupArchList), " ".join(self.ArchList)))
\r
782 self.ArchList = ArchList
\r
784 # Merge build target
\r
785 if self.BuildTargetList == None or len(self.BuildTargetList) == 0:
\r
786 BuildTargetList = Wb.BuildTarget
\r
788 BuildTargetList = list(set(self.BuildTargetList) & set(Wb.BuildTarget))
\r
789 if BuildTargetList == []:
\r
790 EdkLogger.error("build", PARAMETER_INVALID, "Active platform only supports [%s], but [%s] is given"
\r
791 % (" ".join(Wb.BuildTarget), " ".join(self.BuildTargetList)))
\r
792 self.BuildTargetList = BuildTargetList
\r
796 ## Build a module or platform
\r
798 # Create autogen code and makfile for a module or platform, and the launch
\r
799 # "make" command to build it
\r
801 # @param Target The target of build command
\r
802 # @param Platform The platform file
\r
803 # @param Module The module file
\r
804 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
\r
805 # @param ToolChain The name of toolchain to build
\r
806 # @param Arch The arch of the module/platform
\r
807 # @param CreateDepModuleCodeFile Flag used to indicate creating code
\r
808 # for dependent modules/Libraries
\r
809 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
\r
810 # for dependent modules/Libraries
\r
812 def _Build(self, Target, Platform, Module, BuildTarget, ToolChain, Arch, CreateDepModuleCodeFile=True, CreateDepModuleMakeFile=True):
\r
813 # skip file generation for some targets
\r
814 if Target not in ['clean', 'cleanlib', 'cleanall', 'run']:
\r
816 # no need to generate code/makefile for dependent modules/libraries
\r
817 # if the target is 'fds'
\r
819 if Target == 'fds':
\r
820 CreateDepModuleCodeFile = False
\r
821 CreateDepModuleMakeFile = False
\r
822 CreateDepModuleAutoGenObject = True
\r
824 CreateDepModuleAutoGenObject = False
\r
827 self.Progress.Start("Generating code/makefile for module")
\r
828 AutoGenResult = ModuleAutoGen.New(self.Ewb, Platform, Module, BuildTarget,
\r
831 self.Progress.Start("Generating code/makefile for platform")
\r
832 AutoGenResult = PlatformAutoGen.New(self.Ewb, Platform, BuildTarget,
\r
833 ToolChain, Arch, CreateDepModuleAutoGenObject)
\r
834 if AutoGenResult == None:
\r
837 # for target which must generate AutoGen code and makefile
\r
838 AutoGenResult.CreateCodeFile(CreateDepModuleCodeFile)
\r
839 if Target == "genc":
\r
840 self.Progress.Stop("done!")
\r
843 AutoGenResult.CreateMakeFile(CreateDepModuleMakeFile)
\r
844 if Target == "genmake":
\r
845 self.Progress.Stop("done!")
\r
848 self.Progress.Stop("done!")
\r
851 AutoGenResult = ModuleAutoGen.New(self.Ewb, Platform, Module, BuildTarget,
\r
854 AutoGenResult = PlatformAutoGen.New(self.Ewb, Platform, BuildTarget,
\r
855 ToolChain, Arch, False)
\r
856 if AutoGenResult == None:
\r
860 BuildCommand = AutoGenResult.GetBuildCommand()
\r
861 if BuildCommand == None or len(BuildCommand) == 0:
\r
862 EdkLogger.error("build", OPTION_MISSING, ExtraData="No MAKE command found for [%s, %s, %s]" % Key)
\r
864 BuildCommand = BuildCommand + (Target,)
\r
865 LaunchCommand(BuildCommand, os.path.join(self.WorkspaceDir, AutoGenResult.GetMakeFileDir()))
\r
867 ## Build active platform for different build targets and different tool chains
\r
869 def _BuildPlatform(self):
\r
870 for BuildTarget in self.BuildTargetList:
\r
871 for ToolChain in self.ToolChainList:
\r
872 self._Build(self.Target, self.PlatformFile, None, BuildTarget, ToolChain, self.ArchList)
\r
874 ## Build active module for different build targets, different tool chains and different archs
\r
876 def _BuildModule(self):
\r
877 for BuildTarget in self.BuildTargetList:
\r
878 for ToolChain in self.ToolChainList:
\r
880 # module build needs platform build information, so get platform
\r
883 if self.Target == 'fds':
\r
885 # we need to re-generate the command in platform's Makefile
\r
886 # in case the user changed command line option for 'fds' target
\r
888 PlatformAutoGen.New(self.Ewb, self.PlatformFile, BuildTarget, ToolChain, self.ArchList, True)
\r
889 self._Build("genmake", self.PlatformFile, None, BuildTarget, ToolChain, self.ArchList, False, False)
\r
891 PlatformAutoGen.New(self.Ewb, self.PlatformFile, BuildTarget, ToolChain, self.ArchList)
\r
893 for Arch in self.ArchList:
\r
894 self._Build(self.Target, self.PlatformFile, self.ModuleFile, BuildTarget, ToolChain, Arch)
\r
896 ## Build a platform in multi-thread mode
\r
898 def _MultiThreadBuildPlatform(self):
\r
899 for BuildTarget in self.BuildTargetList:
\r
900 for ToolChain in self.ToolChainList:
\r
901 Pa = PlatformAutoGen.New(self.Ewb, self.PlatformFile, BuildTarget, ToolChain, self.ArchList)
\r
904 # multi-thread exit flag
\r
905 ExitFlag = threading.Event()
\r
907 for Arch in self.ArchList:
\r
908 for Module in Pa.Platform[Arch].Modules:
\r
909 # Get ModuleAutoGen object to generate C code file and makefile
\r
910 Ma = ModuleAutoGen.New(self.Ewb, self.PlatformFile, Module, BuildTarget, ToolChain, Arch)
\r
913 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
\r
914 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
\r
915 # for target which must generate AutoGen code and makefile
\r
916 Ma.CreateCodeFile(True)
\r
917 if self.Target == "genc":
\r
920 Ma.CreateMakeFile(True)
\r
921 if self.Target == "genmake":
\r
923 # Generate build task for the module
\r
924 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))
\r
925 # Break build if any build thread has error
\r
926 if BuildTask.HasError():
\r
927 # we need a full version of makefile for platform
\r
929 BuildTask.WaitForComplete()
\r
930 Pa.CreateModuleAutoGen()
\r
931 Pa.CreateMakeFile(False)
\r
932 EdkLogger.error("build", BUILD_ERROR, BuildTask.GetErrorMessage())
\r
933 # Start task scheduler
\r
934 if not BuildTask.IsOnGoing():
\r
935 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
\r
938 # All modules have been put in build tasks queue. Tell task scheduler
\r
939 # to exit if all tasks are completed
\r
942 BuildTask.WaitForComplete()
\r
943 # in case there's an interruption. we need a full version of makefile for platform
\r
944 Pa.CreateModuleAutoGen()
\r
945 Pa.CreateMakeFile(False)
\r
946 if BuildTask.HasError():
\r
947 EdkLogger.error("build", BUILD_ERROR, BuildTask.GetErrorMessage())
\r
949 # Generate FD image if there's a FDF file found
\r
950 if self.Fdf != '' and self.Target in ["", "all", "fds"]:
\r
951 LaunchCommand(Pa.GetBuildCommand() + ("fds",), Pa.GetMakeFileDir())
\r
953 ## Generate GuidedSectionTools.txt in the FV directories.
\r
955 def CreateGuidedSectionToolsFile(self):
\r
956 for Dsc in self.Ewb.DscDatabase.keys():
\r
957 for Arch in self.ArchList:
\r
958 for BuildTarget in self.BuildTargetList:
\r
959 for ToolChain in self.ToolChainList:
\r
960 FvDir = os.path.join(
\r
962 self.Ewb.Build[Arch].PlatformDatabase[Dsc].OutputDirectory,
\r
963 '_'.join((BuildTarget, ToolChain)),
\r
966 if not os.path.exists(FvDir):
\r
968 # Build up the list of supported architectures for this build
\r
969 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)
\r
971 # Look through the tool definitions for GUIDed tools
\r
973 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():
\r
974 if attrib.upper().endswith('_GUID'):
\r
975 split = attrib.split('_')
\r
976 thisPrefix = '_'.join(split[0:3]) + '_'
\r
977 if thisPrefix == prefix:
\r
978 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]
\r
979 guid = guid.lower()
\r
980 toolName = split[3]
\r
981 path = '_'.join(split[0:4]) + '_PATH'
\r
982 path = self.ToolDef.ToolsDefTxtDictionary[path]
\r
983 path = self.GetFullPathOfTool(path)
\r
984 guidAttribs.append((guid, toolName, path))
\r
986 # Write out GuidedSecTools.txt
\r
987 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')
\r
988 toolsFile = open(toolsFile, 'wt')
\r
989 for guidedSectionTool in guidAttribs:
\r
990 print >> toolsFile, ' '.join(guidedSectionTool)
\r
993 ## Returns the full path of the tool.
\r
995 def GetFullPathOfTool (self, tool):
\r
996 if os.path.exists(tool):
\r
997 return os.path.realpath(tool)
\r
999 # We need to search for the tool using the
\r
1000 # PATH environment variable.
\r
1001 for dirInPath in os.environ['PATH'].split(os.pathsep):
\r
1002 foundPath = os.path.join(dirInPath, tool)
\r
1003 if os.path.exists(foundPath):
\r
1004 return os.path.realpath(foundPath)
\r
1006 # If the tool was not found in the path then we just return
\r
1010 ## Launch the module or platform build
\r
1013 if self.ModuleFile == None or self.ModuleFile == "":
\r
1014 if not self.SpawnMode or self.Target not in ["", "all"]:
\r
1015 self.SpawnMode = False
\r
1016 self._BuildPlatform()
\r
1018 self._MultiThreadBuildPlatform()
\r
1019 self.CreateGuidedSectionToolsFile()
\r
1021 self.SpawnMode = False
\r
1022 self._BuildModule()
\r
1024 ## Do some clean-up works when error occurred
\r
1025 def Relinquish(self):
\r
1026 self.DumpBuildData()
\r
1027 Utils.Progressor.Abort()
\r
1028 if self.SpawnMode == True:
\r
1031 def DumpBuildData(self):
\r
1032 CacheDirectory = os.path.join(self.WorkspaceDir, gBuildCacheDir)
\r
1033 Utils.CreateDirectory(CacheDirectory)
\r
1034 Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))
\r
1035 Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))
\r
1037 def RestoreBuildData(self):
\r
1038 FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gFileTimeStampCache")
\r
1039 if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):
\r
1040 Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)
\r
1041 if Utils.gFileTimeStampCache == None:
\r
1042 Utils.gFileTimeStampCache = {}
\r
1044 FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gDependencyDatabase")
\r
1045 if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):
\r
1046 Utils.gDependencyDatabase = Utils.DataRestore(FilePath)
\r
1047 if Utils.gDependencyDatabase == None:
\r
1048 Utils.gDependencyDatabase = {}
\r
1050 ## Parse command line options
\r
1052 # Using standard Python module optparse to parse command line option of this tool.
\r
1054 # @retval Opt A optparse.Values object containing the parsed options
\r
1055 # @retval Args Target of build command
\r
1057 def MyOptionParser():
\r
1058 Parser = OptionParser(description=__copyright__,version=__version__,prog="build.exe",usage="%prog [options] [target]")
\r
1059 Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32','X64','IPF','EBC'], dest="TargetArch",
\r
1060 help="ARCHS is one of list: IA32, X64, IPF or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.")
\r
1061 Parser.add_option("-p", "--platform", action="store", type="string", dest="PlatformFile",
\r
1062 help="Build the platform specified by the DSC file name argument, overrides target.txt's ACTIVE_PLATFORM definition.")
\r
1063 Parser.add_option("-m", "--module", action="store", type="string", dest="ModuleFile",
\r
1064 help="Build the module specified by the INF file name argument.")
\r
1065 Parser.add_option("-b", "--buildtarget", action="append", type="choice", choices=['DEBUG','RELEASE'], dest="BuildTarget",
\r
1066 help="BuildTarget is one of list: DEBUG, RELEASE, which overrides target.txt's TARGET definition. To specify more TARGET, please repeat this option.")
\r
1067 Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",
\r
1068 help="Using the Tool Chain Tagname to build the platform, overrides target.txt's TOOL_CHAIN_TAG definition.")
\r
1069 Parser.add_option("-s", "--spawn", action="store_true", type=None, dest="SpawnMode",
\r
1070 help="If this flag is specified, as soon as a module can be built, the build will start, without waiting for AutoGen to complete remaining modules. While this option provides feedback that looks fast, due to overhead of the AutoGen function, this option is slower than letting AutoGen complete before starting the MAKE phase.")
\r
1071 Parser.add_option("-n", action="store", type="int", dest="ThreadNumber",
\r
1072 help="Build the platform using multi-threaded compiler, this option must combine with spawn option. The value overrides target.txt's MULTIPLE_THREAD and MAX_CONCURRENT_THREAD_NUMBER, less than 2 will disable multi-thread builds.")
\r
1073 Parser.add_option("-f", "--fdf", action="store", type="string", dest="FdfFile",
\r
1074 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
\r
1075 Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],
\r
1076 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
\r
1077 Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],
\r
1078 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
\r
1079 Parser.add_option("-k", "--msft", action="store_const", dest="MakefileType", const="nmake", help="Make Option: Generate only NMAKE Makefiles: Makefile")
\r
1080 Parser.add_option("-g", "--gcc", action="store_const", dest="MakefileType", const="gmake", help="Make Option: Generate only GMAKE Makefiles: GNUmakefile")
\r
1081 Parser.add_option("-l", "--all", action="store_const", dest="MakefileType", const="all", help="Make Option: Generate both NMAKE and GMAKE makefiles.")
\r
1083 Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")
\r
1084 Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Putlog in specified file as well as on console.")
\r
1085 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
\r
1086 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
\r
1087 "including library instances selected, final dependency expression, "\
\r
1088 "and warning messages, etc.")
\r
1089 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
\r
1091 (Opt, Args)=Parser.parse_args()
\r
1092 return (Opt, Args)
\r
1094 ## Tool entrance method
\r
1096 # This method mainly dispatch specific methods per the command line options.
\r
1097 # If no error found, return zero value so the caller of this tool can know
\r
1098 # if it's executed successfully or not.
\r
1100 # @retval 0 Tool was successful
\r
1101 # @retval 1 Tool failed
\r
1104 StartTime = time.clock()
\r
1106 # Parse the options and args
\r
1108 (Option, Target) = MyOptionParser()
\r
1110 if len(Target) == 0:
\r
1112 elif len(Target) >= 2:
\r
1113 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than on targets are not supported.",
\r
1114 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))
\r
1116 Target = Target[0].lower()
\r
1118 if Option.verbose != None:
\r
1119 EdkLogger.SetLevel(EdkLogger.VERBOSE)
\r
1120 elif Option.quiet != None:
\r
1121 EdkLogger.SetLevel(EdkLogger.QUIET)
\r
1122 elif Option.debug != None:
\r
1123 EdkLogger.SetLevel(Option.debug + 1)
\r
1125 EdkLogger.SetLevel(EdkLogger.INFO)
\r
1127 if Option.LogFile != None:
\r
1128 EdkLogger.SetLogFile(Option.LogFile)
\r
1130 if Option.WarningAsError == True:
\r
1131 EdkLogger.SetWarningAsError()
\r
1133 EdkLogger.quiet(time.strftime("%H:%M:%S, %b.%d %Y ", time.localtime()) + "[00:00]" + "\n")
\r
1138 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
\r
1140 CheckEnvVariable()
\r
1141 Workspace = os.getenv("WORKSPACE")
\r
1143 WorkingDirectory = os.getcwd()
\r
1144 if Option.ModuleFile != None:
\r
1145 Option.ModuleFile = NormFile(Option.ModuleFile, Workspace)
\r
1147 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))
\r
1148 FileNum = len(FileList)
\r
1150 EdkLogger.error("build", None, "There are %d INF files in %s.\n" % (FileNum, WorkingDirectory))
\r
1151 elif FileNum == 1:
\r
1152 Option.ModuleFile = NormFile(FileList[0], Workspace)
\r
1154 if Option.PlatformFile != None:
\r
1155 Option.PlatformFile = NormFile(Option.PlatformFile, Workspace)
\r
1157 if Option.FdfFile != None:
\r
1158 Option.FdfFile = NormFile(Option.FdfFile, Workspace)
\r
1160 MyBuild = Build(Target, Workspace, Option.PlatformFile, Option.ModuleFile, Option.TargetArch,
\r
1161 Option.ToolChain, Option.BuildTarget, Option.FdfFile, Option.RomImage, Option.FvImage,
\r
1162 Option.MakefileType, Option.SpawnMode, Option.ThreadNumber)
\r
1164 MyBuild.DumpBuildData()
\r
1165 except BaseException, X:
\r
1166 if MyBuild != None:
\r
1167 # for multi-thread build exits safely
\r
1168 MyBuild.Relinquish()
\r
1169 EdkLogger.quiet("")
\r
1170 if Option != None and Option.debug != None:
\r
1171 EdkLogger.quiet(traceback.format_exc())
\r
1173 EdkLogger.quiet(str(X))
\r
1176 Utils.Progressor.Abort()
\r
1178 FinishTime = time.clock()
\r
1179 BuildDuration = time.strftime("%M:%S", time.gmtime(int(round(FinishTime - StartTime))))
\r
1180 EdkLogger.quiet("\n%s [%s]" % (time.strftime("%H:%M:%S, %b.%d %Y", time.localtime()), BuildDuration))
\r
1184 if __name__ == '__main__':
\r