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