]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/build/build.py
Sync BaseTool trunk (version r2610) into EDKII BaseTools.
[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
4afd3d04 4# Copyright (c) 2007 - 2013, 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
4afd3d04 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
4afd3d04 50VersionNumber = "0.51" + ' ' + gBUILD_VERSION\r
52302d4d 51__version__ = "%prog Version " + VersionNumber\r
4afd3d04 52__copyright__ = "Copyright (c) 2007 - 2013, Intel Corporation All rights reserved."\r
52302d4d
LG
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
4afd3d04 122\r
52302d4d
LG
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
4afd3d04 127\r
52302d4d 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
4afd3d04 316 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
0d2711a6 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
4afd3d04 672 # @param BaseName The full file path of image.\r
52302d4d
LG
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 840 # parse target.txt, tools_def.txt, and platform file\r
4afd3d04 841 self.LoadConfiguration()\r
0d2711a6
LG
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
4afd3d04 900 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
0d2711a6
LG
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
4afd3d04 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
4afd3d04 999 MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))\r
f3decdc3
LG
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 1078 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)\r
4afd3d04 1079\r
52302d4d
LG
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
4afd3d04 1130\r
52302d4d
LG
1131 if not ModuleIsPatch:\r
1132 continue\r
1133 #\r
1134 # Module includes the patchable load fix address PCDs.\r
4afd3d04 1135 # It will be fixed up later.\r
52302d4d
LG
1136 #\r
1137 PatchEfiImageList.append (OutputImageFile)\r
4afd3d04 1138\r
52302d4d
LG
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
4afd3d04 1158 for EfiImage in PatchEfiImageList:\r
52302d4d
LG
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
4afd3d04 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
4afd3d04 1181\r
52302d4d
LG
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
4afd3d04
LG
1187\r
1188 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize\r
52302d4d 1189 BtBaseAddr = TopMemoryAddress - RtSize\r
4afd3d04 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
4afd3d04 1199\r
52302d4d
LG
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
4afd3d04 1246\r
52302d4d 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 1294 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
4afd3d04 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 1385 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
4afd3d04 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
4afd3d04 1417 pModules = []\r
52302d4d
LG
1418 for Module in Pa.Platform.Modules:\r
1419 # Get ModuleAutoGen object to generate C code file and makefile\r
1420 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1421 if Ma == None:\r
1422 continue\r
1423 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'\r
1424 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1425 # for target which must generate AutoGen code and makefile\r
1426 if not self.SkipAutoGen or self.Target == 'genc':\r
1427 Ma.CreateCodeFile(True)\r
1428 if self.Target == "genc":\r
1429 continue\r
1430\r
1431 if not self.SkipAutoGen or self.Target == 'genmake':\r
1432 Ma.CreateMakeFile(True)\r
da92f276 1433 Ma.CreateAsBuiltInf()\r
52302d4d
LG
1434 if self.Target == "genmake":\r
1435 continue\r
4afd3d04 1436 pModules.append(Ma)\r
e8a47801 1437 self.Progress.Stop("done!")\r
4afd3d04
LG
1438\r
1439 for Ma in pModules:\r
52302d4d
LG
1440 # Generate build task for the module\r
1441 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))\r
1442 # Break build if any build thread has error\r
1443 if BuildTask.HasError():\r
1444 # we need a full version of makefile for platform\r
1445 ExitFlag.set()\r
1446 BuildTask.WaitForComplete()\r
1447 Pa.CreateMakeFile(False)\r
1448 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1449 # Start task scheduler\r
1450 if not BuildTask.IsOnGoing():\r
1451 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
1452\r
1453 # in case there's an interruption. we need a full version of makefile for platform\r
1454 Pa.CreateMakeFile(False)\r
1455 if BuildTask.HasError():\r
1456 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1457\r
64b2609f
LG
1458 #\r
1459 # Save temp tables to a TmpTableDict.\r
1460 #\r
1461 for Key in Wa.BuildDatabase._CACHE_:\r
1462 if Wa.BuildDatabase._CACHE_[Key]._RawData and Wa.BuildDatabase._CACHE_[Key]._RawData._Table and Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table:\r
1463 if TemporaryTablePattern.match(Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table):\r
1464 TmpTableDict[Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table] = Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Cur\r
1465 #\r
52302d4d
LG
1466 #\r
1467 # All modules have been put in build tasks queue. Tell task scheduler\r
1468 # to exit if all tasks are completed\r
1469 #\r
1470 ExitFlag.set()\r
1471 BuildTask.WaitForComplete()\r
1472\r
1473 #\r
1474 # Check for build error, and raise exception if one\r
1475 # has been signaled.\r
1476 #\r
1477 if BuildTask.HasError():\r
1478 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1479\r
1480 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1481 if self.Target in ["", "all", "fds"]:\r
0d2711a6 1482 for Arch in Wa.ArchList:\r
52302d4d
LG
1483 #\r
1484 # Check whether the set fix address is above 4G for 32bit image.\r
1485 #\r
1486 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1487 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
1488 #\r
1489 # Get Module List\r
1490 #\r
636f2be6 1491 ModuleList = {}\r
52302d4d
LG
1492 for Pa in Wa.AutoGenObjectList:\r
1493 for Ma in Pa.ModuleAutoGenList:\r
1494 if Ma == None:\r
1495 continue\r
1496 if not Ma.IsLibrary:\r
636f2be6 1497 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
1498 #\r
1499 # Rebase module to the preferred memory address before GenFds\r
1500 #\r
1501 MapBuffer = StringIO('')\r
636f2be6
LG
1502 if self.LoadFixAddress != 0:\r
1503 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
52302d4d 1504\r
0d2711a6 1505 if self.Fdf:\r
f3decdc3
LG
1506 #\r
1507 # Generate FD image if there's a FDF file found\r
1508 #\r
1509 LaunchCommand(Wa.BuildCommand + ["fds"], Wa.MakeFileDir)\r
52302d4d
LG
1510 #\r
1511 # Create MAP file for all platform FVs after GenFds.\r
1512 #\r
636f2be6 1513 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1514 #\r
1515 # Save MAP buffer into MAP file.\r
1516 #\r
1517 self._SaveMapFile(MapBuffer, Wa)\r
1518\r
1519 ## Generate GuidedSectionTools.txt in the FV directories.\r
1520 #\r
1521 def CreateGuidedSectionToolsFile(self):\r
0d2711a6
LG
1522 for BuildTarget in self.BuildTargetList:\r
1523 for ToolChain in self.ToolChainList:\r
1524 Wa = WorkspaceAutoGen(\r
1525 self.WorkspaceDir,\r
1526 self.PlatformFile,\r
1527 BuildTarget,\r
1528 ToolChain,\r
1529 self.ArchList,\r
1530 self.BuildDatabase,\r
1531 self.TargetTxt,\r
1532 self.ToolDef,\r
1533 self.Fdf,\r
1534 self.FdList,\r
1535 self.FvList,\r
1536 self.CapList,\r
1537 self.SkuId,\r
1538 self.UniFlag\r
1539 )\r
1540 FvDir = Wa.FvDir\r
1541 if not os.path.exists(FvDir):\r
1542 continue\r
1543\r
4afd3d04 1544 for Arch in self.ArchList:\r
52302d4d
LG
1545 # Build up the list of supported architectures for this build\r
1546 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)\r
4afd3d04 1547\r
52302d4d
LG
1548 # Look through the tool definitions for GUIDed tools\r
1549 guidAttribs = []\r
1550 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():\r
1551 if attrib.upper().endswith('_GUID'):\r
1552 split = attrib.split('_')\r
1553 thisPrefix = '_'.join(split[0:3]) + '_'\r
1554 if thisPrefix == prefix:\r
1555 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]\r
1556 guid = guid.lower()\r
1557 toolName = split[3]\r
1558 path = '_'.join(split[0:4]) + '_PATH'\r
1559 path = self.ToolDef.ToolsDefTxtDictionary[path]\r
1560 path = self.GetFullPathOfTool(path)\r
1561 guidAttribs.append((guid, toolName, path))\r
4afd3d04 1562\r
52302d4d
LG
1563 # Write out GuidedSecTools.txt\r
1564 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')\r
1565 toolsFile = open(toolsFile, 'wt')\r
1566 for guidedSectionTool in guidAttribs:\r
1567 print >> toolsFile, ' '.join(guidedSectionTool)\r
1568 toolsFile.close()\r
1569\r
1570 ## Returns the full path of the tool.\r
1571 #\r
1572 def GetFullPathOfTool (self, tool):\r
1573 if os.path.exists(tool):\r
1574 return os.path.realpath(tool)\r
1575 else:\r
1576 # We need to search for the tool using the\r
1577 # PATH environment variable.\r
1578 for dirInPath in os.environ['PATH'].split(os.pathsep):\r
1579 foundPath = os.path.join(dirInPath, tool)\r
1580 if os.path.exists(foundPath):\r
1581 return os.path.realpath(foundPath)\r
1582\r
1583 # If the tool was not found in the path then we just return\r
1584 # the input tool.\r
1585 return tool\r
1586\r
1587 ## Launch the module or platform build\r
1588 #\r
1589 def Launch(self):\r
0d2711a6 1590 if not self.ModuleFile:\r
52302d4d
LG
1591 if not self.SpawnMode or self.Target not in ["", "all"]:\r
1592 self.SpawnMode = False\r
1593 self._BuildPlatform()\r
1594 else:\r
1595 self._MultiThreadBuildPlatform()\r
1596 self.CreateGuidedSectionToolsFile()\r
1597 else:\r
1598 self.SpawnMode = False\r
1599 self._BuildModule()\r
1600\r
1601 ## Do some clean-up works when error occurred\r
1602 def Relinquish(self):\r
1603 OldLogLevel = EdkLogger.GetLevel()\r
1604 EdkLogger.SetLevel(EdkLogger.ERROR)\r
1605 #self.DumpBuildData()\r
1606 Utils.Progressor.Abort()\r
1607 if self.SpawnMode == True:\r
1608 BuildTask.Abort()\r
1609 EdkLogger.SetLevel(OldLogLevel)\r
1610\r
1611 def DumpBuildData(self):\r
1612 CacheDirectory = os.path.join(self.WorkspaceDir, gBuildCacheDir)\r
1613 Utils.CreateDirectory(CacheDirectory)\r
1614 Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))\r
1615 Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))\r
1616\r
1617 def RestoreBuildData(self):\r
1618 FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gFileTimeStampCache")\r
1619 if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):\r
1620 Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)\r
1621 if Utils.gFileTimeStampCache == None:\r
1622 Utils.gFileTimeStampCache = {}\r
1623\r
1624 FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gDependencyDatabase")\r
1625 if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):\r
1626 Utils.gDependencyDatabase = Utils.DataRestore(FilePath)\r
1627 if Utils.gDependencyDatabase == None:\r
1628 Utils.gDependencyDatabase = {}\r
1629\r
1630def ParseDefines(DefineList=[]):\r
1631 DefineDict = {}\r
1632 if DefineList != None:\r
1633 for Define in DefineList:\r
1634 DefineTokenList = Define.split("=", 1)\r
0d2711a6
LG
1635 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):\r
1636 EdkLogger.error('build', FORMAT_INVALID,\r
1637 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",\r
1638 ExtraData=DefineTokenList[0])\r
4afd3d04 1639\r
52302d4d 1640 if len(DefineTokenList) == 1:\r
0d2711a6 1641 DefineDict[DefineTokenList[0]] = "TRUE"\r
52302d4d
LG
1642 else:\r
1643 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()\r
1644 return DefineDict\r
1645\r
1646gParamCheck = []\r
1647def SingleCheckCallback(option, opt_str, value, parser):\r
1648 if option not in gParamCheck:\r
1649 setattr(parser.values, option.dest, value)\r
1650 gParamCheck.append(option)\r
1651 else:\r
1652 parser.error("Option %s only allows one instance in command line!" % option)\r
1653\r
1654## Parse command line options\r
1655#\r
1656# Using standard Python module optparse to parse command line option of this tool.\r
1657#\r
1658# @retval Opt A optparse.Values object containing the parsed options\r
1659# @retval Args Target of build command\r
1660#\r
1661def MyOptionParser():\r
1662 Parser = OptionParser(description=__copyright__,version=__version__,prog="build.exe",usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")\r
4afd3d04
LG
1663 Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32','X64','IPF','EBC','ARM', 'AARCH64'], dest="TargetArch",\r
1664 help="ARCHS is one of list: IA32, X64, IPF, ARM, AARCH64 or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.")\r
52302d4d
LG
1665 Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,\r
1666 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")\r
1667 Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,\r
1668 help="Build the module specified by the INF file name argument.")\r
64b2609f
LG
1669 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",\r
1670 action="append")\r
52302d4d
LG
1671 Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",\r
1672 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")\r
1673 Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,\r
1674 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")\r
1675\r
1676 Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,\r
1677 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
1678\r
1679 Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,\r
1680 help="The name of the FDF file to use, which overrides the setting in the DSC file.")\r
1681 Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],\r
1682 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")\r
1683 Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],\r
1684 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")\r
4234283c
LG
1685 Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],\r
1686 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")\r
52302d4d
LG
1687 Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")\r
1688 Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")\r
1689\r
0d2711a6 1690 Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.")\r
52302d4d
LG
1691\r
1692 Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")\r
1693 Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")\r
1694\r
1695 Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",\r
1696 help="Make use of silent mode of (n)make.")\r
1697 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
1698 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\\r
1699 "including library instances selected, final dependency expression, "\\r
1700 "and warning messages, etc.")\r
1701 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
1702 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
1703\r
1704 Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")\r
1705 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
1706 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
1707 "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
1708 Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",\r
1709 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
1710 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\\r
1711 "will override the setting in [BuildOptions] section of platform DSC.")\r
0d2711a6 1712 Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism")\r
52302d4d
LG
1713\r
1714 (Opt, Args)=Parser.parse_args()\r
1715 return (Opt, Args)\r
1716\r
1717## Tool entrance method\r
1718#\r
1719# This method mainly dispatch specific methods per the command line options.\r
1720# If no error found, return zero value so the caller of this tool can know\r
1721# if it's executed successfully or not.\r
1722#\r
1723# @retval 0 Tool was successful\r
1724# @retval 1 Tool failed\r
1725#\r
1726def Main():\r
1727 StartTime = time.time()\r
1728\r
1729 # Initialize log system\r
1730 EdkLogger.Initialize()\r
1731\r
1732 #\r
1733 # Parse the options and args\r
1734 #\r
1735 (Option, Target) = MyOptionParser()\r
1736 GlobalData.gOptions = Option\r
1737 GlobalData.gCaseInsensitive = Option.CaseInsensitive\r
1738\r
1739 # Set log level\r
1740 if Option.verbose != None:\r
1741 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
1742 elif Option.quiet != None:\r
1743 EdkLogger.SetLevel(EdkLogger.QUIET)\r
1744 elif Option.debug != None:\r
1745 EdkLogger.SetLevel(Option.debug + 1)\r
1746 else:\r
1747 EdkLogger.SetLevel(EdkLogger.INFO)\r
1748\r
1749 if Option.LogFile != None:\r
1750 EdkLogger.SetLogFile(Option.LogFile)\r
1751\r
1752 if Option.WarningAsError == True:\r
1753 EdkLogger.SetWarningAsError()\r
1754\r
1755 if platform.platform().find("Windows") >= 0:\r
1756 GlobalData.gIsWindows = True\r
1757 else:\r
1758 GlobalData.gIsWindows = False\r
1759\r
6780eef1
LG
1760 EdkLogger.quiet("Build environment: %s" % platform.platform())\r
1761 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));\r
52302d4d
LG
1762 ReturnCode = 0\r
1763 MyBuild = None\r
1764 try:\r
1765 if len(Target) == 0:\r
1766 Target = "all"\r
1767 elif len(Target) >= 2:\r
1768 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",\r
1769 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))\r
1770 else:\r
1771 Target = Target[0].lower()\r
1772\r
1773 if Target not in gSupportedTarget:\r
1774 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,\r
1775 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))\r
1776\r
52302d4d
LG
1777 #\r
1778 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH\r
1779 #\r
1780 CheckEnvVariable()\r
0d2711a6
LG
1781 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))\r
1782\r
52302d4d
LG
1783 Workspace = os.getenv("WORKSPACE")\r
1784 #\r
1785 # Get files real name in workspace dir\r
1786 #\r
1787 GlobalData.gAllFiles = Utils.DirCache(Workspace)\r
1788\r
1789 WorkingDirectory = os.getcwd()\r
1790 if not Option.ModuleFile:\r
1791 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))\r
1792 FileNum = len(FileList)\r
1793 if FileNum >= 2:\r
1794 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),\r
1795 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")\r
1796 elif FileNum == 1:\r
1797 Option.ModuleFile = NormFile(FileList[0], Workspace)\r
1798\r
1799 if Option.ModuleFile:\r
1800 if os.path.isabs (Option.ModuleFile):\r
1801 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:\r
1802 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)\r
1803 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)\r
1804 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)\r
1805 if ErrorCode != 0:\r
1806 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
1807\r
1808 if Option.PlatformFile != None:\r
1809 if os.path.isabs (Option.PlatformFile):\r
1810 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:\r
1811 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)\r
1812 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)\r
52302d4d
LG
1813\r
1814 if Option.FdfFile != None:\r
1815 if os.path.isabs (Option.FdfFile):\r
1816 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:\r
1817 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)\r
1818 Option.FdfFile = PathClass(Option.FdfFile, Workspace)\r
1819 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)\r
1820 if ErrorCode != 0:\r
1821 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
1822\r
f3decdc3
LG
1823 if Option.Flag != None and Option.Flag not in ['-c', '-s']:\r
1824 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")\r
1825\r
0d2711a6 1826 MyBuild = Build(Target, Workspace, Option)\r
64b2609f 1827 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)\r
52302d4d 1828 MyBuild.Launch()\r
64b2609f
LG
1829 # Drop temp tables to avoid database locked.\r
1830 for TmpTableName in TmpTableDict:\r
1831 SqlCommand = """drop table IF EXISTS %s""" % TmpTableName\r
1832 TmpTableDict[TmpTableName].execute(SqlCommand)\r
52302d4d
LG
1833 #MyBuild.DumpBuildData()\r
1834 except FatalError, X:\r
1835 if MyBuild != None:\r
1836 # for multi-thread build exits safely\r
1837 MyBuild.Relinquish()\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 ReturnCode = X.args[0]\r
1841 except Warning, X:\r
1842 # error from Fdf parser\r
1843 if MyBuild != None:\r
1844 # for multi-thread build exits safely\r
1845 MyBuild.Relinquish()\r
1846 if Option != None and Option.debug != None:\r
1847 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
1848 else:\r
1849 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError = False)\r
1850 ReturnCode = FORMAT_INVALID\r
1851 except KeyboardInterrupt:\r
1852 ReturnCode = ABORT_ERROR\r
1853 if Option != None and Option.debug != None:\r
1854 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
1855 except:\r
1856 if MyBuild != None:\r
1857 # for multi-thread build exits safely\r
1858 MyBuild.Relinquish()\r
1859\r
1860 # try to get the meta-file from the object causing exception\r
1861 Tb = sys.exc_info()[-1]\r
1862 MetaFile = GlobalData.gProcessingFile\r
1863 while Tb != None:\r
1864 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):\r
1865 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile\r
1866 Tb = Tb.tb_next\r
1867 EdkLogger.error(\r
1868 "\nbuild",\r
1869 CODE_ERROR,\r
1870 "Unknown fatal error when processing [%s]" % MetaFile,\r
1871 ExtraData="\n(Please send email to edk2-buildtools-devel@lists.sourceforge.net for help, attaching following call stack trace!)\n",\r
1872 RaiseError=False\r
1873 )\r
d0acc87a 1874 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
52302d4d
LG
1875 ReturnCode = CODE_ERROR\r
1876 finally:\r
1877 Utils.Progressor.Abort()\r
1878\r
1879 if ReturnCode == 0:\r
1880 Conclusion = "Done"\r
1881 elif ReturnCode == ABORT_ERROR:\r
1882 Conclusion = "Aborted"\r
1883 else:\r
1884 Conclusion = "Failed"\r
1885 FinishTime = time.time()\r
4234283c
LG
1886 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))\r
1887 BuildDurationStr = ""\r
1888 if BuildDuration.tm_yday > 1:\r
1889 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)"%(BuildDuration.tm_yday - 1)\r
1890 else:\r
1891 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)\r
52302d4d 1892 if MyBuild != None:\r
4234283c 1893 MyBuild.BuildReport.GenerateReport(BuildDurationStr)\r
52302d4d
LG
1894 MyBuild.Db.Close()\r
1895 EdkLogger.SetLevel(EdkLogger.QUIET)\r
6780eef1
LG
1896 EdkLogger.quiet("\n- %s -" % Conclusion)\r
1897 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))\r
4234283c 1898 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)\r
52302d4d
LG
1899 return ReturnCode\r
1900\r
1901if __name__ == '__main__':\r
1902 r = Main()\r
1903 ## 0-127 is a safe return range, and 1 is a standard default error\r
1904 if r < 0 or r > 127: r = 1\r
1905 sys.exit(r)\r
1906\r