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