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