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