]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/build/build.py
Fix a bug that usb keybarod can not work well when it is inserted at a usb 2.0 hub.
[mirror_edk2.git] / BaseTools / Source / Python / build / build.py
CommitLineData
52302d4d
LG
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
18import os\r
19import re\r
20import StringIO\r
21import sys\r
22import glob\r
23import time\r
24import platform\r
25import traceback\r
26\r
27from struct import *\r
28from threading import *\r
29from optparse import OptionParser\r
30from subprocess import *\r
31from Common import Misc as Utils\r
32\r
33from Common.TargetTxtClassObject import *\r
34from Common.ToolDefClassObject import *\r
35from Common.DataType import *\r
36from AutoGen.AutoGen import *\r
37from Common.BuildToolError import *\r
38from Workspace.WorkspaceDatabase import *\r
39\r
40from BuildReport import BuildReport\r
41from GenPatchPcdTable.GenPatchPcdTable import *\r
42from PatchPcdValue.PatchPcdValue import *\r
43\r
44import Common.EdkLogger\r
45import Common.GlobalData as GlobalData\r
46\r
47# Version and Copyright\r
48VersionNumber = "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
53gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']\r
54\r
55## build configuration file\r
56gBuildConfiguration = "Conf/target.txt"\r
57gBuildCacheDir = "Conf/.cache"\r
58gToolsDefinition = "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
65def 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
87def 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
182def 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
208def 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
230def 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
286class 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
346class 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
367class 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
384class 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
651class 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
680class 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
d5d56f1b
LG
741 \r
742 #\r
743 # @attention Treat $(TARGET) in meta data files as special macro when it has only one build target.\r
744 # This is not a complete support for $(TARGET) macro as it can only support one build target in ONE\r
745 # invocation of build command. However, it should cover the frequent usage model that $(TARGET) macro\r
746 # is used in DSC files to specify different libraries & PCD setting for debug/release build.\r
747 #\r
748 if len(self.BuildTargetList) == 1:\r
749 self.Db._GlobalMacros.setdefault("TARGET", self.BuildTargetList[0])\r
750 \r
52302d4d
LG
751 self.InitBuild()\r
752\r
753 # print current build environment and configuration\r
754 EdkLogger.quiet("%-24s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))\r
755 EdkLogger.quiet("%-24s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"]))\r
756 EdkLogger.quiet("%-24s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"]))\r
757 EdkLogger.quiet("%-24s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"]))\r
758 EdkLogger.quiet("%-24s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))\r
759\r
760 EdkLogger.info('\n%-24s = %s' % ("TARGET_ARCH", ' '.join(self.ArchList)))\r
761 EdkLogger.info('%-24s = %s' % ("TARGET", ' '.join(self.BuildTargetList)))\r
762 EdkLogger.info('%-24s = %s' % ("TOOL_CHAIN_TAG", ' '.join(self.ToolChainList)))\r
763\r
764 EdkLogger.info('\n%-24s = %s' % ("Active Platform", self.PlatformFile))\r
765\r
766 if self.Fdf != None and self.Fdf != "":\r
767 EdkLogger.info('%-24s = %s' % ("Flash Image Definition", self.Fdf))\r
768\r
769 if self.ModuleFile != None and self.ModuleFile != "":\r
770 EdkLogger.info('%-24s = %s' % ("Active Module", self.ModuleFile))\r
771\r
772 os.chdir(self.WorkspaceDir)\r
773 self.Progress.Start("\nProcessing meta-data")\r
774\r
775 ## Load configuration\r
776 #\r
777 # This method will parse target.txt and get the build configurations.\r
778 #\r
779 def LoadConfiguration(self):\r
780 #\r
781 # Check target.txt and tools_def.txt and Init them\r
782 #\r
783 BuildConfigurationFile = os.path.normpath(os.path.join(self.WorkspaceDir, gBuildConfiguration))\r
784 if os.path.isfile(BuildConfigurationFile) == True:\r
785 StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)\r
786\r
787 ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]\r
788 if ToolDefinitionFile == '':\r
789 ToolDefinitionFile = gToolsDefinition\r
790 ToolDefinitionFile = os.path.normpath(os.path.join(self.WorkspaceDir, ToolDefinitionFile))\r
791 if os.path.isfile(ToolDefinitionFile) == True:\r
792 StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)\r
793 else:\r
794 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)\r
795 else:\r
796 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)\r
797\r
798 # if no ARCH given in command line, get it from target.txt\r
799 if self.ArchList == None or len(self.ArchList) == 0:\r
800 self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH]\r
801\r
802 # if no build target given in command line, get it from target.txt\r
803 if self.BuildTargetList == None or len(self.BuildTargetList) == 0:\r
804 self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]\r
805\r
806 # if no tool chain given in command line, get it from target.txt\r
807 if self.ToolChainList == None or len(self.ToolChainList) == 0:\r
808 self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]\r
809 if self.ToolChainList == None or len(self.ToolChainList) == 0:\r
810 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")\r
811\r
812 # check if the tool chains are defined or not\r
813 NewToolChainList = []\r
814 for ToolChain in self.ToolChainList:\r
815 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:\r
816 EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)\r
817 else:\r
818 NewToolChainList.append(ToolChain)\r
819 # if no tool chain available, break the build\r
820 if len(NewToolChainList) == 0:\r
821 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
822 ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))\r
823 else:\r
824 self.ToolChainList = NewToolChainList\r
825\r
826 if self.ThreadNumber == None:\r
827 self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]\r
828 if self.ThreadNumber == '':\r
829 self.ThreadNumber = 0\r
830 else:\r
831 self.ThreadNumber = int(self.ThreadNumber, 0)\r
832\r
833 if self.ThreadNumber == 0:\r
834 self.ThreadNumber = 1\r
835\r
836 if not self.PlatformFile:\r
837 PlatformFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM]\r
838 if not PlatformFile:\r
839 # Try to find one in current directory\r
840 WorkingDirectory = os.getcwd()\r
841 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))\r
842 FileNum = len(FileList)\r
843 if FileNum >= 2:\r
844 EdkLogger.error("build", OPTION_MISSING,\r
845 ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))\r
846 elif FileNum == 1:\r
847 PlatformFile = FileList[0]\r
848 else:\r
849 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
850 ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")\r
851\r
852 self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)\r
853 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)\r
854 if ErrorCode != 0:\r
855 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
856\r
857 ## Initialize build configuration\r
858 #\r
859 # This method will parse DSC file and merge the configurations from\r
860 # command line and target.txt, then get the final build configurations.\r
861 #\r
862 def InitBuild(self):\r
863 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc")\r
864 if ErrorCode != 0:\r
865 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
866\r
867 # create metafile database\r
868 self.Db.InitDatabase()\r
869\r
870 # we need information in platform description file to determine how to build\r
871 self.Platform = self.BuildDatabase[self.PlatformFile, 'COMMON']\r
872 if not self.Fdf:\r
873 self.Fdf = self.Platform.FlashDefinition\r
874 \r
875 LoadFixAddressString = None\r
876 if TAB_FIX_LOAD_TOP_MEMORY_ADDRESS in GlobalData.gGlobalDefines:\r
877 LoadFixAddressString = GlobalData.gGlobalDefines[TAB_FIX_LOAD_TOP_MEMORY_ADDRESS]\r
878 else:\r
879 LoadFixAddressString = self.Platform.LoadFixAddress\r
880\r
881 if LoadFixAddressString != None and LoadFixAddressString != '':\r
882 try:\r
883 if LoadFixAddressString.upper().startswith('0X'):\r
884 self.LoadFixAddress = int (LoadFixAddressString, 16)\r
885 else:\r
886 self.LoadFixAddress = int (LoadFixAddressString)\r
887 except:
888 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS %s is not valid dec or hex string" % (LoadFixAddressString))\r
889 if self.LoadFixAddress < 0:\r
890 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is set to the invalid negative value %s" % (LoadFixAddressString))\r
891 if self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress % 0x1000 != 0:\r
892 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is set to the invalid unaligned 4K value %s" % (LoadFixAddressString))\r
893\r
894 if self.SkuId == None or self.SkuId == '':\r
895 self.SkuId = self.Platform.SkuName\r
896\r
897 # check FD/FV build target\r
898 if self.Fdf == None or self.Fdf == "":\r
899 if self.FdList != []:\r
900 EdkLogger.info("No flash definition file found. FD [%s] will be ignored." % " ".join(self.FdList))\r
901 self.FdList = []\r
902 if self.FvList != []:\r
903 EdkLogger.info("No flash definition file found. FV [%s] will be ignored." % " ".join(self.FvList))\r
904 self.FvList = []\r
905 else:\r
906 FdfParserObj = FdfParser(str(self.Fdf))\r
907 FdfParserObj.ParseFile()\r
908 for fvname in self.FvList:\r
909 if fvname.upper() not in FdfParserObj.Profile.FvDict.keys():\r
910 EdkLogger.error("build", OPTION_VALUE_INVALID,\r
911 "No such an FV in FDF file: %s" % fvname)\r
912\r
913 #\r
914 # Merge Arch\r
915 #\r
916 if self.ArchList == None or len(self.ArchList) == 0:\r
917 ArchList = set(self.Platform.SupArchList)\r
918 else:\r
919 ArchList = set(self.ArchList) & set(self.Platform.SupArchList)\r
920 if len(ArchList) == 0:\r
921 EdkLogger.error("build", PARAMETER_INVALID,\r
922 ExtraData = "Active platform supports [%s] only, but [%s] is given."\r
923 % (" ".join(self.Platform.SupArchList), " ".join(self.ArchList)))\r
924 elif len(ArchList) != len(self.ArchList):\r
925 SkippedArchList = set(self.ArchList).symmetric_difference(set(self.Platform.SupArchList))\r
926 EdkLogger.verbose("\nArch [%s] is ignored because active platform supports [%s] but [%s] is specified !"\r
927 % (" ".join(SkippedArchList), " ".join(self.Platform.SupArchList), " ".join(self.ArchList)))\r
928 self.ArchList = tuple(ArchList)\r
929\r
930 # Merge build target\r
931 if self.BuildTargetList == None or len(self.BuildTargetList) == 0:\r
932 BuildTargetList = self.Platform.BuildTargets\r
933 else:\r
934 BuildTargetList = list(set(self.BuildTargetList) & set(self.Platform.BuildTargets))\r
935 if BuildTargetList == []:\r
936 EdkLogger.error("build", PARAMETER_INVALID, "Active platform only supports [%s], but [%s] is given"\r
937 % (" ".join(self.Platform.BuildTargets), " ".join(self.BuildTargetList)))\r
938 self.BuildTargetList = BuildTargetList\r
939\r
940 ## Build a module or platform\r
941 #\r
942 # Create autogen code and makfile for a module or platform, and the launch\r
943 # "make" command to build it\r
944 #\r
945 # @param Target The target of build command\r
946 # @param Platform The platform file\r
947 # @param Module The module file\r
948 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
949 # @param ToolChain The name of toolchain to build\r
950 # @param Arch The arch of the module/platform\r
951 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
952 # for dependent modules/Libraries\r
953 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
954 # for dependent modules/Libraries\r
955 #\r
956 def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True):\r
957 if AutoGenObject == None:\r
958 return False\r
959\r
960 # skip file generation for cleanxxx targets, run and fds target\r
961 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
962 # for target which must generate AutoGen code and makefile\r
963 if not self.SkipAutoGen or Target == 'genc':\r
964 self.Progress.Start("Generating code")\r
965 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
966 self.Progress.Stop("done!")\r
967 if Target == "genc":\r
968 return True\r
969\r
970 if not self.SkipAutoGen or Target == 'genmake':\r
971 self.Progress.Start("Generating makefile")\r
972 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)\r
973 self.Progress.Stop("done!")\r
974 if Target == "genmake":\r
975 return True\r
976 else:\r
977 # always recreate top/platform makefile when clean, just in case of inconsistency\r
978 AutoGenObject.CreateCodeFile(False)\r
979 AutoGenObject.CreateMakeFile(False)\r
980\r
981 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
982 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
983\r
984 BuildCommand = AutoGenObject.BuildCommand\r
985 if BuildCommand == None or len(BuildCommand) == 0:\r
986 EdkLogger.error("build", OPTION_MISSING, ExtraData="No MAKE command found for [%s, %s, %s]" % Key)\r
987\r
988 BuildCommand = BuildCommand + [Target]\r
989 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
990 if Target == 'cleanall':\r
991 try:\r
992 #os.rmdir(AutoGenObject.BuildDir)\r
993 RemoveDirectory(AutoGenObject.BuildDir, True)\r
994 except WindowsError, X:\r
995 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
996 return True\r
997\r
998 ## Rebase module image and Get function address for the inpug module list.\r
999 #\r
1000 def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):\r
1001 if ModeIsSmm:\r
1002 AddrIsOffset = False\r
1003 InfFileNameList = ModuleList.keys()\r
1004 #InfFileNameList.sort()\r
1005 for InfFile in InfFileNameList:\r
1006 sys.stdout.write (".")
1007 sys.stdout.flush()
1008 ModuleInfo = ModuleList[InfFile]\r
1009 ModuleName = ModuleInfo.BaseName\r
1010 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1011 if not ModeIsSmm:\r
1012 BaseAddress = BaseAddress - ModuleInfo.Image.Size\r
1013 #\r
1014 # Update Image to new BaseAddress by GenFw tool\r
1015 #\r
1016 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleInfo.Image.FileName], ModuleInfo.OutpuDir)\r
1017 else:\r
1018 #\r
1019 # Set new address to the section header only for SMM driver.\r
1020 #\r
1021 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleInfo.Image.FileName], ModuleInfo.OutpuDir)\r
1022 #\r
1023 # Collect funtion address from Map file\r
1024 #\r
1025 ImageMapTable = ModuleInfo.Image.FileName.replace('.efi', '.map')\r
1026 FunctionList = []\r
1027 if os.path.exists(ImageMapTable):\r
1028 OrigImageBaseAddress = 0\r
1029 ImageMap = open (ImageMapTable, 'r')\r
1030 for LinStr in ImageMap:\r
1031 if len (LinStr.strip()) == 0:\r
1032 continue\r
1033 #\r
1034 # Get the preferred address set on link time.\r
1035 #\r
1036 if LinStr.find ('Preferred load address is') != -1:\r
1037 StrList = LinStr.split()\r
1038 OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)\r
1039\r
1040 StrList = LinStr.split()\r
1041 if len (StrList) > 4:\r
1042 if StrList[3] == 'f' or StrList[3] =='F':\r
1043 Name = StrList[1]\r
1044 RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress\r
1045 FunctionList.append ((Name, RelativeAddress))\r
1046 if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'):\r
1047 #\r
1048 # Get the real entry point address for IPF image.\r
1049 #\r
1050 ModuleInfo.Image.EntryPoint = RelativeAddress\r
1051 ImageMap.close()\r
1052 #\r
1053 # Add general information.\r
1054 #\r
1055 if ModeIsSmm:\r
1056 MapBuffer.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1057 elif AddrIsOffset:\r
1058 MapBuffer.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))\r
1059 else:\r
1060 MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1061 #\r
1062 # Add guid and general seciton section.\r
1063 #\r
1064 TextSectionAddress = 0\r
1065 DataSectionAddress = 0\r
1066 for SectionHeader in ModuleInfo.Image.SectionHeaderList:\r
1067 if SectionHeader[0] == '.text':\r
1068 TextSectionAddress = SectionHeader[1]\r
1069 elif SectionHeader[0] in ['.data', '.sdata']:\r
1070 DataSectionAddress = SectionHeader[1]\r
1071 if AddrIsOffset:\r
1072 MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress))) \r
1073 else:\r
1074 MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress)) \r
1075 #\r
1076 # Add funtion address\r
1077 #\r
1078 for Function in FunctionList:\r
1079 if AddrIsOffset:\r
1080 MapBuffer.write(' -0x%010X %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))\r
1081 else:\r
1082 MapBuffer.write(' 0x%010X %s\n' % (BaseAddress + Function[1], Function[0]))\r
1083 ImageMap.close()\r
1084\r
1085 #\r
1086 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1087 #\r
1088 if ModeIsSmm:\r
1089 BaseAddress = BaseAddress + ModuleInfo.Image.Size\r
1090\r
1091 ## Collect MAP information of all FVs\r
1092 #\r
636f2be6 1093 def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):\r
52302d4d
LG
1094 if self.Fdf != '':\r
1095 # First get the XIP base address for FV map file.\r
636f2be6 1096 GuidPattern = re.compile("[-a-fA-F0-9]+")\r
52302d4d
LG
1097 for FvName in Wa.FdfProfile.FvDict.keys():\r
1098 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')\r
1099 if not os.path.exists(FvMapBuffer):\r
1100 continue\r
1101 FvMap = open (FvMapBuffer, 'r')\r
1102 #skip FV size information\r
1103 FvMap.readline()\r
1104 FvMap.readline()\r
1105 FvMap.readline()\r
1106 FvMap.readline()\r
636f2be6
LG
1107 for Line in FvMap:\r
1108 MatchGuid = GuidPattern.match(Line)\r
1109 if MatchGuid != None:\r
1110 #\r
1111 # Replace GUID with module name\r
1112 #\r
1113 GuidString = MatchGuid.group()\r
1114 if GuidString.upper() in ModuleList:\r
1115 Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)\r
1116 MapBuffer.write('%s' % (Line))\r
52302d4d
LG
1117 FvMap.close()\r
1118\r
1119 ## Collect MAP information of all modules\r
1120 #\r
1121 def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):\r
1122 sys.stdout.write ("Generate Load Module At Fix Address Map")
1123 sys.stdout.flush()
1124 PatchEfiImageList = []\r
1125 PeiModuleList = {}\r
1126 BtModuleList = {}\r
1127 RtModuleList = {}\r
1128 SmmModuleList = {}\r
1129 PeiSize = 0\r
1130 BtSize = 0\r
1131 RtSize = 0\r
1132 # reserve 4K size in SMRAM to make SMM module address not from 0.\r
1133 SmmSize = 0x1000\r
1134 IsIpfPlatform = False\r
1135 if 'IPF' in self.ArchList:\r
1136 IsIpfPlatform = True\r
636f2be6
LG
1137 for ModuleGuid in ModuleList:\r
1138 Module = ModuleList[ModuleGuid]\r
52302d4d
LG
1139 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)\r
1140 \r
1141 OutputImageFile = ''\r
1142 for ResultFile in Module.CodaTargetList:\r
1143 if str(ResultFile.Target).endswith('.efi'):\r
1144 #\r
1145 # module list for PEI, DXE, RUNTIME and SMM\r
1146 #\r
1147 OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')\r
1148 ImageClass = PeImageClass (OutputImageFile)\r
1149 if not ImageClass.IsValid:\r
1150 EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)\r
1151 ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, ImageClass)\r
1152 if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER','PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']:\r
1153 PeiModuleList[Module.MetaFile] = ImageInfo\r
1154 PeiSize += ImageInfo.Image.Size\r
1155 elif Module.ModuleType in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']:\r
1156 BtModuleList[Module.MetaFile] = ImageInfo\r
1157 BtSize += ImageInfo.Image.Size\r
1158 elif Module.ModuleType in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']:\r
1159 RtModuleList[Module.MetaFile] = ImageInfo\r
1160 #IPF runtime driver needs to be at 2 page alignment.\r
1161 if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0:\r
1162 ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000\r
1163 RtSize += ImageInfo.Image.Size\r
1164 elif Module.ModuleType in ['SMM_CORE', 'DXE_SMM_DRIVER']:\r
1165 SmmModuleList[Module.MetaFile] = ImageInfo\r
1166 SmmSize += ImageInfo.Image.Size\r
1167 if Module.ModuleType == 'DXE_SMM_DRIVER':\r
1168 PiSpecVersion = 0
1169 if 'PI_SPECIFICATION_VERSION' in Module.Module.Specification:
1170 PiSpecVersion = Module.Module.Specification['PI_SPECIFICATION_VERSION']
1171 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.\r
1172 if PiSpecVersion < 0x0001000A:\r
1173 BtModuleList[Module.MetaFile] = ImageInfo\r
1174 BtSize += ImageInfo.Image.Size\r
1175 break\r
1176 #\r
1177 # EFI image is final target.\r
1178 # Check EFI image contains patchable FixAddress related PCDs.\r
1179 #\r
1180 if OutputImageFile != '':\r
1181 ModuleIsPatch = False\r
1182 for Pcd in Module.ModulePcdList:\r
1183 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:\r
1184 ModuleIsPatch = True\r
1185 break\r
1186 if not ModuleIsPatch:\r
1187 for Pcd in Module.LibraryPcdList:\r
1188 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:\r
1189 ModuleIsPatch = True\r
1190 break\r
1191 \r
1192 if not ModuleIsPatch:\r
1193 continue\r
1194 #\r
1195 # Module includes the patchable load fix address PCDs.\r
1196 # It will be fixed up later. \r
1197 #\r
1198 PatchEfiImageList.append (OutputImageFile)\r
1199 \r
1200 #\r
1201 # Get Top Memory address\r
1202 #\r
1203 ReservedRuntimeMemorySize = 0\r
1204 TopMemoryAddress = 0\r
1205 if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:\r
1206 TopMemoryAddress = 0\r
1207 else:\r
1208 TopMemoryAddress = self.LoadFixAddress\r
1209 if TopMemoryAddress < RtSize + BtSize + PeiSize:\r
1210 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")\r
1211 # Make IPF runtime driver at 2 page alignment.\r
1212 if IsIpfPlatform:\r
1213 ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000\r
1214 RtSize = RtSize + ReservedRuntimeMemorySize\r
1215\r
1216 #\r
1217 # Patch FixAddress related PCDs into EFI image\r
1218 #\r
1219 for EfiImage in PatchEfiImageList: \r
1220 EfiImageMap = EfiImage.replace('.efi', '.map')\r
1221 if not os.path.exists(EfiImageMap):\r
1222 continue\r
1223 #\r
1224 # Get PCD offset in EFI image by GenPatchPcdTable function\r
1225 #\r
1226 PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)
1227 #\r
1228 # Patch real PCD value by PatchPcdValue tool\r
1229 #\r
1230 for PcdInfo in PcdTable:\r
1231 ReturnValue = 0\r
1232 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:\r
1233 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize/0x1000))\r
1234 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:\r
1235 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize/0x1000))\r
1236 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:\r
1237 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize/0x1000))\r
1238 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:\r
1239 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize/0x1000))\r
1240 if ReturnValue != 0:\r
1241 EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)\r
1242 \r
1243 MapBuffer.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize/0x1000))\r
1244 MapBuffer.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize/0x1000))\r
1245 MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize/0x1000))\r
1246 if len (SmmModuleList) > 0:\r
1247 MapBuffer.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize/0x1000))\r
1248 \r
1249 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize\r
1250 BtBaseAddr = TopMemoryAddress - RtSize\r
1251 RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize\r
1252\r
1253 self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)\r
1254 self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)\r
1255 self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)\r
1256 self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset = False, ModeIsSmm = True)\r
1257 MapBuffer.write('\n\n')\r
1258 sys.stdout.write ("\n")
1259 sys.stdout.flush()
1260 \r
1261 ## Save platform Map file\r
1262 #\r
1263 def _SaveMapFile (self, MapBuffer, Wa):\r
1264 #\r
1265 # Map file path is got.\r
1266 #\r
1267 MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')\r
1268 #\r
1269 # Save address map into MAP file.\r
1270 #\r
1271 SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)\r
1272 MapBuffer.close()\r
636f2be6
LG
1273 if self.LoadFixAddress != 0:
1274 sys.stdout.write ("\nLoad Module At Fix Address Map file saved to %s\n" %(MapFilePath))
52302d4d
LG
1275 sys.stdout.flush()
1276\r
1277 ## Build active platform for different build targets and different tool chains\r
1278 #\r
1279 def _BuildPlatform(self):\r
1280 for BuildTarget in self.BuildTargetList:\r
1281 for ToolChain in self.ToolChainList:\r
1282 Wa = WorkspaceAutoGen(\r
1283 self.WorkspaceDir,\r
1284 self.Platform,\r
1285 BuildTarget,\r
1286 ToolChain,\r
1287 self.ArchList,\r
1288 self.BuildDatabase,\r
1289 self.TargetTxt,\r
1290 self.ToolDef,\r
1291 self.Fdf,\r
1292 self.FdList,\r
1293 self.FvList,\r
1294 self.SkuId\r
1295 )\r
1296 self.BuildReport.AddPlatformReport(Wa)\r
1297 self.Progress.Stop("done!")\r
1298 self._Build(self.Target, Wa)\r
1299 \r
1300 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1301 if self.Target in ["", "all", "fds"]:\r
52302d4d
LG
1302 for Arch in self.ArchList:\r
1303 #\r
1304 # Check whether the set fix address is above 4G for 32bit image.\r
1305 #\r
1306 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1307 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
1308 #\r
1309 # Get Module List\r
1310 #\r
636f2be6 1311 ModuleList = {}\r
52302d4d
LG
1312 for Pa in Wa.AutoGenObjectList:\r
1313 for Ma in Pa.ModuleAutoGenList:\r
1314 if Ma == None:\r
1315 continue\r
1316 if not Ma.IsLibrary:\r
636f2be6 1317 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
1318\r
1319 MapBuffer = StringIO('')\r
636f2be6
LG
1320 if self.LoadFixAddress != 0:\r
1321 #\r
1322 # Rebase module to the preferred memory address before GenFds\r
1323 #\r
1324 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
52302d4d
LG
1325 if self.Fdf != '':\r
1326 #\r
1327 # create FDS again for the updated EFI image\r
1328 #\r
1329 self._Build("fds", Wa)\r
1330 #\r
1331 # Create MAP file for all platform FVs after GenFds.\r
1332 #\r
636f2be6 1333 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1334 #\r
1335 # Save MAP buffer into MAP file.\r
1336 #\r
1337 self._SaveMapFile (MapBuffer, Wa)\r
1338\r
1339 ## Build active module for different build targets, different tool chains and different archs\r
1340 #\r
1341 def _BuildModule(self):\r
1342 for BuildTarget in self.BuildTargetList:\r
1343 for ToolChain in self.ToolChainList:\r
1344 #\r
1345 # module build needs platform build information, so get platform\r
1346 # AutoGen first\r
1347 #\r
1348 Wa = WorkspaceAutoGen(\r
1349 self.WorkspaceDir,\r
1350 self.Platform,\r
1351 BuildTarget,\r
1352 ToolChain,\r
1353 self.ArchList,\r
1354 self.BuildDatabase,\r
1355 self.TargetTxt,\r
1356 self.ToolDef,\r
1357 self.Fdf,\r
1358 self.FdList,\r
1359 self.FvList,\r
1360 self.SkuId\r
1361 )\r
52302d4d
LG
1362 Wa.CreateMakeFile(False)\r
1363 self.Progress.Stop("done!")\r
1364 MaList = []\r
1365 for Arch in self.ArchList:\r
1366 Ma = ModuleAutoGen(Wa, self.ModuleFile, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1367 if Ma == None: continue\r
1368 MaList.append(Ma)\r
1369 self._Build(self.Target, Ma)\r
d5d56f1b
LG
1370\r
1371 self.BuildReport.AddPlatformReport(Wa, MaList)\r
52302d4d
LG
1372 if MaList == []:\r
1373 EdkLogger.error(\r
1374 'build',\r
1375 BUILD_ERROR,\r
1376 "Module for [%s] is not a component of active platform."\\r
1377 " Please make sure that the ARCH and inf file path are"\\r
1378 " given in the same as in [%s]" %\\r
1379 (', '.join(self.ArchList), self.Platform),\r
1380 ExtraData=self.ModuleFile\r
1381 )\r
1382 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1383 if self.Target == "fds" and self.Fdf != '':\r
52302d4d
LG
1384 for Arch in self.ArchList:\r
1385 #\r
1386 # Check whether the set fix address is above 4G for 32bit image.\r
1387 #\r
1388 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1389 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
1390 #\r
1391 # Get Module List\r
1392 #\r
636f2be6 1393 ModuleList = {}\r
52302d4d
LG
1394 for Pa in Wa.AutoGenObjectList:\r
1395 for Ma in Pa.ModuleAutoGenList:\r
1396 if Ma == None:\r
1397 continue\r
1398 if not Ma.IsLibrary:\r
636f2be6 1399 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
1400\r
1401 MapBuffer = StringIO('')\r
636f2be6
LG
1402 if self.LoadFixAddress != 0:\r
1403 #\r
1404 # Rebase module to the preferred memory address before GenFds\r
1405 #\r
1406 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
1407 #\r
1408 # create FDS again for the updated EFI image\r
1409 #\r
1410 self._Build("fds", Wa)\r
52302d4d
LG
1411 #\r
1412 # Create MAP file for all platform FVs after GenFds.\r
1413 #\r
636f2be6 1414 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1415 #\r
1416 # Save MAP buffer into MAP file.\r
1417 #\r
1418 self._SaveMapFile (MapBuffer, Wa)\r
1419\r
1420 ## Build a platform in multi-thread mode\r
1421 #\r
1422 def _MultiThreadBuildPlatform(self):\r
1423 for BuildTarget in self.BuildTargetList:\r
1424 for ToolChain in self.ToolChainList:\r
1425 Wa = WorkspaceAutoGen(\r
1426 self.WorkspaceDir,\r
1427 self.Platform,\r
1428 BuildTarget,\r
1429 ToolChain,\r
1430 self.ArchList,\r
1431 self.BuildDatabase,\r
1432 self.TargetTxt,\r
1433 self.ToolDef,\r
1434 self.Fdf,\r
1435 self.FdList,\r
1436 self.FvList,\r
1437 self.SkuId\r
1438 )\r
1439 self.BuildReport.AddPlatformReport(Wa)\r
1440 Wa.CreateMakeFile(False)\r
1441\r
1442 # multi-thread exit flag\r
1443 ExitFlag = threading.Event()\r
1444 ExitFlag.clear()\r
1445 for Arch in self.ArchList:\r
1446 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
1447 if Pa == None:\r
1448 continue\r
1449 for Module in Pa.Platform.Modules:\r
1450 # Get ModuleAutoGen object to generate C code file and makefile\r
1451 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1452 if Ma == None:\r
1453 continue\r
1454 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'\r
1455 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1456 # for target which must generate AutoGen code and makefile\r
1457 if not self.SkipAutoGen or self.Target == 'genc':\r
1458 Ma.CreateCodeFile(True)\r
1459 if self.Target == "genc":\r
1460 continue\r
1461\r
1462 if not self.SkipAutoGen or self.Target == 'genmake':\r
1463 Ma.CreateMakeFile(True)\r
1464 if self.Target == "genmake":\r
1465 continue\r
1466 self.Progress.Stop("done!")\r
1467 # Generate build task for the module\r
1468 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))\r
1469 # Break build if any build thread has error\r
1470 if BuildTask.HasError():\r
1471 # we need a full version of makefile for platform\r
1472 ExitFlag.set()\r
1473 BuildTask.WaitForComplete()\r
1474 Pa.CreateMakeFile(False)\r
1475 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1476 # Start task scheduler\r
1477 if not BuildTask.IsOnGoing():\r
1478 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
1479\r
1480 # in case there's an interruption. we need a full version of makefile for platform\r
1481 Pa.CreateMakeFile(False)\r
1482 if BuildTask.HasError():\r
1483 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1484\r
1485 #\r
1486 # All modules have been put in build tasks queue. Tell task scheduler\r
1487 # to exit if all tasks are completed\r
1488 #\r
1489 ExitFlag.set()\r
1490 BuildTask.WaitForComplete()\r
1491\r
1492 #\r
1493 # Check for build error, and raise exception if one\r
1494 # has been signaled.\r
1495 #\r
1496 if BuildTask.HasError():\r
1497 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1498\r
1499 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1500 if self.Target in ["", "all", "fds"]:\r
52302d4d
LG
1501 for Arch in self.ArchList:\r
1502 #\r
1503 # Check whether the set fix address is above 4G for 32bit image.\r
1504 #\r
1505 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1506 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
1507 #\r
1508 # Get Module List\r
1509 #\r
636f2be6 1510 ModuleList = {}\r
52302d4d
LG
1511 for Pa in Wa.AutoGenObjectList:\r
1512 for Ma in Pa.ModuleAutoGenList:\r
1513 if Ma == None:\r
1514 continue\r
1515 if not Ma.IsLibrary:\r
636f2be6 1516 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
1517 #\r
1518 # Rebase module to the preferred memory address before GenFds\r
1519 #\r
1520 MapBuffer = StringIO('')\r
636f2be6
LG
1521 if self.LoadFixAddress != 0:\r
1522 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
52302d4d
LG
1523\r
1524 # Generate FD image if there's a FDF file found\r
1525 if self.Fdf != '' and self.Target in ["", "all", "fds"]:\r
1526 LaunchCommand(Wa.BuildCommand + ["fds"], Wa.MakeFileDir)\r
1527\r
1528 # Create MAP file for all platform FV after GenFds\r
636f2be6 1529 if self.Target in ["", "all", "fds"]:\r
52302d4d
LG
1530 if self.Fdf != '':\r
1531 #\r
1532 # Create MAP file for all platform FVs after GenFds.\r
1533 #\r
636f2be6 1534 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1535 #\r
1536 # Save MAP buffer into MAP file.\r
1537 #\r
1538 self._SaveMapFile(MapBuffer, Wa)\r
1539\r
1540 ## Generate GuidedSectionTools.txt in the FV directories.\r
1541 #\r
1542 def CreateGuidedSectionToolsFile(self):\r
1543 for Arch in self.ArchList:\r
1544 for BuildTarget in self.BuildTargetList:\r
1545 for ToolChain in self.ToolChainList:\r
1546 FvDir = os.path.join(\r
1547 self.WorkspaceDir,\r
1548 self.Platform.OutputDirectory,\r
1549 '_'.join((BuildTarget, ToolChain)),\r
1550 'FV'\r
1551 )\r
1552 if not os.path.exists(FvDir):\r
1553 continue\r
1554 # Build up the list of supported architectures for this build\r
1555 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)\r
1556\r
1557 # Look through the tool definitions for GUIDed tools\r
1558 guidAttribs = []\r
1559 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():\r
1560 if attrib.upper().endswith('_GUID'):\r
1561 split = attrib.split('_')\r
1562 thisPrefix = '_'.join(split[0:3]) + '_'\r
1563 if thisPrefix == prefix:\r
1564 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]\r
1565 guid = guid.lower()\r
1566 toolName = split[3]\r
1567 path = '_'.join(split[0:4]) + '_PATH'\r
1568 path = self.ToolDef.ToolsDefTxtDictionary[path]\r
1569 path = self.GetFullPathOfTool(path)\r
1570 guidAttribs.append((guid, toolName, path))\r
1571\r
1572 # Write out GuidedSecTools.txt\r
1573 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')\r
1574 toolsFile = open(toolsFile, 'wt')\r
1575 for guidedSectionTool in guidAttribs:\r
1576 print >> toolsFile, ' '.join(guidedSectionTool)\r
1577 toolsFile.close()\r
1578\r
1579 ## Returns the full path of the tool.\r
1580 #\r
1581 def GetFullPathOfTool (self, tool):\r
1582 if os.path.exists(tool):\r
1583 return os.path.realpath(tool)\r
1584 else:\r
1585 # We need to search for the tool using the\r
1586 # PATH environment variable.\r
1587 for dirInPath in os.environ['PATH'].split(os.pathsep):\r
1588 foundPath = os.path.join(dirInPath, tool)\r
1589 if os.path.exists(foundPath):\r
1590 return os.path.realpath(foundPath)\r
1591\r
1592 # If the tool was not found in the path then we just return\r
1593 # the input tool.\r
1594 return tool\r
1595\r
1596 ## Launch the module or platform build\r
1597 #\r
1598 def Launch(self):\r
1599 if self.ModuleFile == None or self.ModuleFile == "":\r
1600 if not self.SpawnMode or self.Target not in ["", "all"]:\r
1601 self.SpawnMode = False\r
1602 self._BuildPlatform()\r
1603 else:\r
1604 self._MultiThreadBuildPlatform()\r
1605 self.CreateGuidedSectionToolsFile()\r
1606 else:\r
1607 self.SpawnMode = False\r
1608 self._BuildModule()\r
1609\r
1610 ## Do some clean-up works when error occurred\r
1611 def Relinquish(self):\r
1612 OldLogLevel = EdkLogger.GetLevel()\r
1613 EdkLogger.SetLevel(EdkLogger.ERROR)\r
1614 #self.DumpBuildData()\r
1615 Utils.Progressor.Abort()\r
1616 if self.SpawnMode == True:\r
1617 BuildTask.Abort()\r
1618 EdkLogger.SetLevel(OldLogLevel)\r
1619\r
1620 def DumpBuildData(self):\r
1621 CacheDirectory = os.path.join(self.WorkspaceDir, gBuildCacheDir)\r
1622 Utils.CreateDirectory(CacheDirectory)\r
1623 Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))\r
1624 Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))\r
1625\r
1626 def RestoreBuildData(self):\r
1627 FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gFileTimeStampCache")\r
1628 if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):\r
1629 Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)\r
1630 if Utils.gFileTimeStampCache == None:\r
1631 Utils.gFileTimeStampCache = {}\r
1632\r
1633 FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gDependencyDatabase")\r
1634 if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):\r
1635 Utils.gDependencyDatabase = Utils.DataRestore(FilePath)\r
1636 if Utils.gDependencyDatabase == None:\r
1637 Utils.gDependencyDatabase = {}\r
1638\r
1639def ParseDefines(DefineList=[]):\r
1640 DefineDict = {}\r
1641 if DefineList != None:\r
1642 for Define in DefineList:\r
1643 DefineTokenList = Define.split("=", 1)\r
1644 if len(DefineTokenList) == 1:\r
1645 DefineDict[DefineTokenList[0]] = ""\r
1646 else:\r
1647 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()\r
1648 return DefineDict\r
1649\r
1650gParamCheck = []\r
1651def SingleCheckCallback(option, opt_str, value, parser):\r
1652 if option not in gParamCheck:\r
1653 setattr(parser.values, option.dest, value)\r
1654 gParamCheck.append(option)\r
1655 else:\r
1656 parser.error("Option %s only allows one instance in command line!" % option)\r
1657\r
1658## Parse command line options\r
1659#\r
1660# Using standard Python module optparse to parse command line option of this tool.\r
1661#\r
1662# @retval Opt A optparse.Values object containing the parsed options\r
1663# @retval Args Target of build command\r
1664#\r
1665def MyOptionParser():\r
1666 Parser = OptionParser(description=__copyright__,version=__version__,prog="build.exe",usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")\r
1667 Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32','X64','IPF','EBC','ARM'], dest="TargetArch",\r
1668 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
1669 Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,\r
1670 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")\r
1671 Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,\r
1672 help="Build the module specified by the INF file name argument.")\r
1673 Parser.add_option("-b", "--buildtarget", action="append", type="choice", choices=['DEBUG','RELEASE'], dest="BuildTarget",\r
1674 help="BuildTarget is one of list: DEBUG, RELEASE, which overrides target.txt's TARGET definition. To specify more TARGET, please repeat this option.")\r
1675 Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",\r
1676 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")\r
1677 Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,\r
1678 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")\r
1679\r
1680 Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,\r
1681 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
1682\r
1683 Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,\r
1684 help="The name of the FDF file to use, which overrides the setting in the DSC file.")\r
1685 Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],\r
1686 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")\r
1687 Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],\r
1688 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")\r
1689\r
1690 Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")\r
1691 Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")\r
1692\r
1693 Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", help="Don't check case of file name.")\r
1694\r
1695 # Parser.add_option("-D", "--define", action="append", dest="Defines", metavar="NAME[=[VALUE]]",\r
1696 # help="Define global macro which can be used in DSC/DEC/INF files.")\r
1697\r
1698 Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")\r
1699 Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")\r
1700\r
1701 Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",\r
1702 help="Make use of silent mode of (n)make.")\r
1703 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
1704 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\\r
1705 "including library instances selected, final dependency expression, "\\r
1706 "and warning messages, etc.")\r
1707 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
1708 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
1709\r
1710 Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")\r
1711 Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD','LIBRARY','FLASH','DEPEX','BUILD_FLAGS','FIXED_ADDRESS', 'EXECUTION_ORDER'], dest="ReportType", default=[],\r
1712 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
1713 "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
1714\r
1715 (Opt, Args)=Parser.parse_args()\r
1716 return (Opt, Args)\r
1717\r
1718## Tool entrance method\r
1719#\r
1720# This method mainly dispatch specific methods per the command line options.\r
1721# If no error found, return zero value so the caller of this tool can know\r
1722# if it's executed successfully or not.\r
1723#\r
1724# @retval 0 Tool was successful\r
1725# @retval 1 Tool failed\r
1726#\r
1727def Main():\r
1728 StartTime = time.time()\r
1729\r
1730 # Initialize log system\r
1731 EdkLogger.Initialize()\r
1732\r
1733 #\r
1734 # Parse the options and args\r
1735 #\r
1736 (Option, Target) = MyOptionParser()\r
1737 GlobalData.gOptions = Option\r
1738 GlobalData.gCaseInsensitive = Option.CaseInsensitive\r
1739\r
1740 # Set log level\r
1741 if Option.verbose != None:\r
1742 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
1743 elif Option.quiet != None:\r
1744 EdkLogger.SetLevel(EdkLogger.QUIET)\r
1745 elif Option.debug != None:\r
1746 EdkLogger.SetLevel(Option.debug + 1)\r
1747 else:\r
1748 EdkLogger.SetLevel(EdkLogger.INFO)\r
1749\r
1750 if Option.LogFile != None:\r
1751 EdkLogger.SetLogFile(Option.LogFile)\r
1752\r
1753 if Option.WarningAsError == True:\r
1754 EdkLogger.SetWarningAsError()\r
1755\r
1756 if platform.platform().find("Windows") >= 0:\r
1757 GlobalData.gIsWindows = True\r
1758 else:\r
1759 GlobalData.gIsWindows = False\r
1760\r
1761 EdkLogger.quiet(time.strftime("%H:%M:%S, %b.%d %Y ", time.localtime()) + "[%s]\n" % platform.platform())\r
1762 ReturnCode = 0\r
1763 MyBuild = None\r
1764 try:\r
1765 if len(Target) == 0:\r
1766 Target = "all"\r
1767 elif len(Target) >= 2:\r
1768 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",\r
1769 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))\r
1770 else:\r
1771 Target = Target[0].lower()\r
1772\r
1773 if Target not in gSupportedTarget:\r
1774 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,\r
1775 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))\r
1776\r
1777 GlobalData.gGlobalDefines = ParseDefines(Option.Macros)\r
1778 #\r
1779 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH\r
1780 #\r
1781 CheckEnvVariable()\r
1782 Workspace = os.getenv("WORKSPACE")\r
1783 #\r
1784 # Get files real name in workspace dir\r
1785 #\r
1786 GlobalData.gAllFiles = Utils.DirCache(Workspace)\r
1787\r
1788 WorkingDirectory = os.getcwd()\r
1789 if not Option.ModuleFile:\r
1790 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))\r
1791 FileNum = len(FileList)\r
1792 if FileNum >= 2:\r
1793 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),\r
1794 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")\r
1795 elif FileNum == 1:\r
1796 Option.ModuleFile = NormFile(FileList[0], Workspace)\r
1797\r
1798 if Option.ModuleFile:\r
1799 if os.path.isabs (Option.ModuleFile):\r
1800 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:\r
1801 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)\r
1802 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)\r
1803 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)\r
1804 if ErrorCode != 0:\r
1805 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
1806\r
1807 if Option.PlatformFile != None:\r
1808 if os.path.isabs (Option.PlatformFile):\r
1809 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:\r
1810 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)\r
1811 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)\r
1812 ErrorCode, ErrorInfo = Option.PlatformFile.Validate(".dsc", False)\r
1813 if ErrorCode != 0:\r
1814 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
1815\r
1816 if Option.FdfFile != None:\r
1817 if os.path.isabs (Option.FdfFile):\r
1818 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:\r
1819 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)\r
1820 Option.FdfFile = PathClass(Option.FdfFile, Workspace)\r
1821 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)\r
1822 if ErrorCode != 0:\r
1823 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
1824\r
1825 MyBuild = Build(Target, Workspace, Option.PlatformFile, Option.ModuleFile,\r
1826 Option.TargetArch, Option.ToolChain, Option.BuildTarget,\r
1827 Option.FdfFile, Option.RomImage, Option.FvImage,\r
1828 None, Option.SilentMode, Option.ThreadNumber,\r
1829 Option.SkipAutoGen, Option.Reparse, Option.SkuId, \r
1830 Option.ReportFile, Option.ReportType)\r
1831 MyBuild.Launch()\r
1832 #MyBuild.DumpBuildData()\r
1833 except FatalError, X:\r
1834 if MyBuild != None:\r
1835 # for multi-thread build exits safely\r
1836 MyBuild.Relinquish()\r
1837 if Option != None and Option.debug != None:\r
1838 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
1839 ReturnCode = X.args[0]\r
1840 except Warning, X:\r
1841 # error from Fdf parser\r
1842 if MyBuild != None:\r
1843 # for multi-thread build exits safely\r
1844 MyBuild.Relinquish()\r
1845 if Option != None and Option.debug != None:\r
1846 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
1847 else:\r
1848 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError = False)\r
1849 ReturnCode = FORMAT_INVALID\r
1850 except KeyboardInterrupt:\r
1851 ReturnCode = ABORT_ERROR\r
1852 if Option != None and Option.debug != None:\r
1853 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
1854 except:\r
1855 if MyBuild != None:\r
1856 # for multi-thread build exits safely\r
1857 MyBuild.Relinquish()\r
1858\r
1859 # try to get the meta-file from the object causing exception\r
1860 Tb = sys.exc_info()[-1]\r
1861 MetaFile = GlobalData.gProcessingFile\r
1862 while Tb != None:\r
1863 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):\r
1864 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile\r
1865 Tb = Tb.tb_next\r
1866 EdkLogger.error(\r
1867 "\nbuild",\r
1868 CODE_ERROR,\r
1869 "Unknown fatal error when processing [%s]" % MetaFile,\r
1870 ExtraData="\n(Please send email to edk2-buildtools-devel@lists.sourceforge.net for help, attaching following call stack trace!)\n",\r
1871 RaiseError=False\r
1872 )\r
1873 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
1874 ReturnCode = CODE_ERROR\r
1875 finally:\r
1876 Utils.Progressor.Abort()\r
1877\r
1878 if ReturnCode == 0:\r
1879 Conclusion = "Done"\r
1880 elif ReturnCode == ABORT_ERROR:\r
1881 Conclusion = "Aborted"\r
1882 else:\r
1883 Conclusion = "Failed"\r
1884 FinishTime = time.time()\r
1885 BuildDuration = time.strftime("%M:%S", time.gmtime(int(round(FinishTime - StartTime))))\r
1886 if MyBuild != None:\r
1887 MyBuild.BuildReport.GenerateReport(BuildDuration)\r
1888 MyBuild.Db.Close()\r
1889 EdkLogger.SetLevel(EdkLogger.QUIET)\r
1890 EdkLogger.quiet("\n- %s -\n%s [%s]" % (Conclusion, time.strftime("%H:%M:%S, %b.%d %Y", time.localtime()), BuildDuration))\r
1891\r
1892 return ReturnCode\r
1893\r
1894if __name__ == '__main__':\r
1895 r = Main()\r
1896 ## 0-127 is a safe return range, and 1 is a standard default error\r
1897 if r < 0 or r > 127: r = 1\r
1898 sys.exit(r)\r
1899\r