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