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