]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/build/build.py
Sync EDKII BaseTools to BaseTools project r1971
[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
40d841f6 4# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>\r
52302d4d 5#\r
40d841f6 6# This program and the accompanying materials\r
52302d4d
LG
7# are licensed and made available under the terms and conditions of the BSD License\r
8# which accompanies this distribution. The full text of the license may be found at\r
9# http://opensource.org/licenses/bsd-license.php\r
10#\r
11# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13#\r
14\r
15##\r
16# Import Modules\r
17#\r
18import os\r
19import re\r
20import StringIO\r
21import sys\r
22import glob\r
23import time\r
24import platform\r
25import traceback\r
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
40d841f6
LG
1292 SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)\r
1293 MapBuffer.close()
636f2be6 1294 if self.LoadFixAddress != 0:
40d841f6 1295 sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" %(MapFilePath))
52302d4d
LG
1296 sys.stdout.flush()
1297\r
1298 ## Build active platform for different build targets and different tool chains\r
1299 #\r
1300 def _BuildPlatform(self):\r
1301 for BuildTarget in self.BuildTargetList:\r
1302 for ToolChain in self.ToolChainList:\r
1303 Wa = WorkspaceAutoGen(\r
1304 self.WorkspaceDir,\r
1305 self.Platform,\r
1306 BuildTarget,\r
1307 ToolChain,\r
1308 self.ArchList,\r
1309 self.BuildDatabase,\r
1310 self.TargetTxt,\r
1311 self.ToolDef,\r
1312 self.Fdf,\r
1313 self.FdList,\r
1314 self.FvList,\r
f3decdc3
LG
1315 self.SkuId,\r
1316 self.UniFlag\r
52302d4d
LG
1317 )\r
1318 self.BuildReport.AddPlatformReport(Wa)\r
1319 self.Progress.Stop("done!")\r
1320 self._Build(self.Target, Wa)\r
1321 \r
1322 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1323 if self.Target in ["", "all", "fds"]:\r
52302d4d
LG
1324 for Arch in self.ArchList:\r
1325 #\r
1326 # Check whether the set fix address is above 4G for 32bit image.\r
1327 #\r
1328 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1329 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
1330 #\r
1331 # Get Module List\r
1332 #\r
636f2be6 1333 ModuleList = {}\r
52302d4d
LG
1334 for Pa in Wa.AutoGenObjectList:\r
1335 for Ma in Pa.ModuleAutoGenList:\r
1336 if Ma == None:\r
1337 continue\r
1338 if not Ma.IsLibrary:\r
636f2be6 1339 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
1340\r
1341 MapBuffer = StringIO('')\r
636f2be6
LG
1342 if self.LoadFixAddress != 0:\r
1343 #\r
1344 # Rebase module to the preferred memory address before GenFds\r
1345 #\r
1346 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
f3decdc3
LG
1347 if self.Fdf != '':\r
1348 #\r
1349 # create FDS again for the updated EFI image\r
1350 #\r
1351 self._Build("fds", Wa)\r
52302d4d 1352 if self.Fdf != '':\r
52302d4d
LG
1353 #\r
1354 # Create MAP file for all platform FVs after GenFds.\r
1355 #\r
636f2be6 1356 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1357 #\r
1358 # Save MAP buffer into MAP file.\r
1359 #\r
1360 self._SaveMapFile (MapBuffer, Wa)\r
1361\r
1362 ## Build active module for different build targets, different tool chains and different archs\r
1363 #\r
1364 def _BuildModule(self):\r
1365 for BuildTarget in self.BuildTargetList:\r
1366 for ToolChain in self.ToolChainList:\r
1367 #\r
1368 # module build needs platform build information, so get platform\r
1369 # AutoGen first\r
1370 #\r
1371 Wa = WorkspaceAutoGen(\r
1372 self.WorkspaceDir,\r
1373 self.Platform,\r
1374 BuildTarget,\r
1375 ToolChain,\r
1376 self.ArchList,\r
1377 self.BuildDatabase,\r
1378 self.TargetTxt,\r
1379 self.ToolDef,\r
1380 self.Fdf,\r
1381 self.FdList,\r
1382 self.FvList,\r
f3decdc3
LG
1383 self.SkuId,\r
1384 self.UniFlag\r
52302d4d 1385 )\r
52302d4d
LG
1386 Wa.CreateMakeFile(False)\r
1387 self.Progress.Stop("done!")\r
1388 MaList = []\r
1389 for Arch in self.ArchList:\r
1390 Ma = ModuleAutoGen(Wa, self.ModuleFile, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1391 if Ma == None: continue\r
1392 MaList.append(Ma)\r
1393 self._Build(self.Target, Ma)\r
d5d56f1b
LG
1394\r
1395 self.BuildReport.AddPlatformReport(Wa, MaList)\r
52302d4d
LG
1396 if MaList == []:\r
1397 EdkLogger.error(\r
1398 'build',\r
1399 BUILD_ERROR,\r
1400 "Module for [%s] is not a component of active platform."\\r
1401 " Please make sure that the ARCH and inf file path are"\\r
1402 " given in the same as in [%s]" %\\r
1403 (', '.join(self.ArchList), self.Platform),\r
1404 ExtraData=self.ModuleFile\r
1405 )\r
1406 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1407 if self.Target == "fds" and self.Fdf != '':\r
52302d4d
LG
1408 for Arch in self.ArchList:\r
1409 #\r
1410 # Check whether the set fix address is above 4G for 32bit image.\r
1411 #\r
1412 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1413 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
1414 #\r
1415 # Get Module List\r
1416 #\r
636f2be6 1417 ModuleList = {}\r
52302d4d
LG
1418 for Pa in Wa.AutoGenObjectList:\r
1419 for Ma in Pa.ModuleAutoGenList:\r
1420 if Ma == None:\r
1421 continue\r
1422 if not Ma.IsLibrary:\r
636f2be6 1423 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
1424\r
1425 MapBuffer = StringIO('')\r
636f2be6
LG
1426 if self.LoadFixAddress != 0:\r
1427 #\r
1428 # Rebase module to the preferred memory address before GenFds\r
1429 #\r
1430 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
1431 #\r
1432 # create FDS again for the updated EFI image\r
1433 #\r
1434 self._Build("fds", Wa)\r
52302d4d
LG
1435 #\r
1436 # Create MAP file for all platform FVs after GenFds.\r
1437 #\r
636f2be6 1438 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1439 #\r
1440 # Save MAP buffer into MAP file.\r
1441 #\r
1442 self._SaveMapFile (MapBuffer, Wa)\r
1443\r
1444 ## Build a platform in multi-thread mode\r
1445 #\r
1446 def _MultiThreadBuildPlatform(self):\r
1447 for BuildTarget in self.BuildTargetList:\r
1448 for ToolChain in self.ToolChainList:\r
1449 Wa = WorkspaceAutoGen(\r
1450 self.WorkspaceDir,\r
1451 self.Platform,\r
1452 BuildTarget,\r
1453 ToolChain,\r
1454 self.ArchList,\r
1455 self.BuildDatabase,\r
1456 self.TargetTxt,\r
1457 self.ToolDef,\r
1458 self.Fdf,\r
1459 self.FdList,\r
1460 self.FvList,\r
f3decdc3
LG
1461 self.SkuId,\r
1462 self.UniFlag\r
52302d4d
LG
1463 )\r
1464 self.BuildReport.AddPlatformReport(Wa)\r
1465 Wa.CreateMakeFile(False)\r
1466\r
1467 # multi-thread exit flag\r
1468 ExitFlag = threading.Event()\r
1469 ExitFlag.clear()\r
1470 for Arch in self.ArchList:\r
1471 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
1472 if Pa == None:\r
1473 continue\r
1474 for Module in Pa.Platform.Modules:\r
1475 # Get ModuleAutoGen object to generate C code file and makefile\r
1476 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1477 if Ma == None:\r
1478 continue\r
1479 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'\r
1480 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1481 # for target which must generate AutoGen code and makefile\r
1482 if not self.SkipAutoGen or self.Target == 'genc':\r
1483 Ma.CreateCodeFile(True)\r
1484 if self.Target == "genc":\r
1485 continue\r
1486\r
1487 if not self.SkipAutoGen or self.Target == 'genmake':\r
1488 Ma.CreateMakeFile(True)\r
1489 if self.Target == "genmake":\r
1490 continue\r
1491 self.Progress.Stop("done!")\r
1492 # Generate build task for the module\r
1493 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))\r
1494 # Break build if any build thread has error\r
1495 if BuildTask.HasError():\r
1496 # we need a full version of makefile for platform\r
1497 ExitFlag.set()\r
1498 BuildTask.WaitForComplete()\r
1499 Pa.CreateMakeFile(False)\r
1500 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1501 # Start task scheduler\r
1502 if not BuildTask.IsOnGoing():\r
1503 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
1504\r
1505 # in case there's an interruption. we need a full version of makefile for platform\r
1506 Pa.CreateMakeFile(False)\r
1507 if BuildTask.HasError():\r
1508 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1509\r
1510 #\r
1511 # All modules have been put in build tasks queue. Tell task scheduler\r
1512 # to exit if all tasks are completed\r
1513 #\r
1514 ExitFlag.set()\r
1515 BuildTask.WaitForComplete()\r
1516\r
1517 #\r
1518 # Check for build error, and raise exception if one\r
1519 # has been signaled.\r
1520 #\r
1521 if BuildTask.HasError():\r
1522 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1523\r
1524 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1525 if self.Target in ["", "all", "fds"]:\r
52302d4d
LG
1526 for Arch in self.ArchList:\r
1527 #\r
1528 # Check whether the set fix address is above 4G for 32bit image.\r
1529 #\r
1530 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1531 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
1532 #\r
1533 # Get Module List\r
1534 #\r
636f2be6 1535 ModuleList = {}\r
52302d4d
LG
1536 for Pa in Wa.AutoGenObjectList:\r
1537 for Ma in Pa.ModuleAutoGenList:\r
1538 if Ma == None:\r
1539 continue\r
1540 if not Ma.IsLibrary:\r
636f2be6 1541 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
1542 #\r
1543 # Rebase module to the preferred memory address before GenFds\r
1544 #\r
1545 MapBuffer = StringIO('')\r
636f2be6
LG
1546 if self.LoadFixAddress != 0:\r
1547 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
52302d4d 1548\r
52302d4d 1549 if self.Fdf != '':\r
f3decdc3
LG
1550 #\r
1551 # Generate FD image if there's a FDF file found\r
1552 #\r
1553 LaunchCommand(Wa.BuildCommand + ["fds"], Wa.MakeFileDir)\r
52302d4d
LG
1554 #\r
1555 # Create MAP file for all platform FVs after GenFds.\r
1556 #\r
636f2be6 1557 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1558 #\r
1559 # Save MAP buffer into MAP file.\r
1560 #\r
1561 self._SaveMapFile(MapBuffer, Wa)\r
1562\r
1563 ## Generate GuidedSectionTools.txt in the FV directories.\r
1564 #\r
1565 def CreateGuidedSectionToolsFile(self):\r
1566 for Arch in self.ArchList:\r
1567 for BuildTarget in self.BuildTargetList:\r
1568 for ToolChain in self.ToolChainList:\r
1569 FvDir = os.path.join(\r
1570 self.WorkspaceDir,\r
1571 self.Platform.OutputDirectory,\r
1572 '_'.join((BuildTarget, ToolChain)),\r
1573 'FV'\r
1574 )\r
1575 if not os.path.exists(FvDir):\r
1576 continue\r
1577 # Build up the list of supported architectures for this build\r
1578 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)\r
1579\r
1580 # Look through the tool definitions for GUIDed tools\r
1581 guidAttribs = []\r
1582 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():\r
1583 if attrib.upper().endswith('_GUID'):\r
1584 split = attrib.split('_')\r
1585 thisPrefix = '_'.join(split[0:3]) + '_'\r
1586 if thisPrefix == prefix:\r
1587 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]\r
1588 guid = guid.lower()\r
1589 toolName = split[3]\r
1590 path = '_'.join(split[0:4]) + '_PATH'\r
1591 path = self.ToolDef.ToolsDefTxtDictionary[path]\r
1592 path = self.GetFullPathOfTool(path)\r
1593 guidAttribs.append((guid, toolName, path))\r
1594\r
1595 # Write out GuidedSecTools.txt\r
1596 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')\r
1597 toolsFile = open(toolsFile, 'wt')\r
1598 for guidedSectionTool in guidAttribs:\r
1599 print >> toolsFile, ' '.join(guidedSectionTool)\r
1600 toolsFile.close()\r
1601\r
1602 ## Returns the full path of the tool.\r
1603 #\r
1604 def GetFullPathOfTool (self, tool):\r
1605 if os.path.exists(tool):\r
1606 return os.path.realpath(tool)\r
1607 else:\r
1608 # We need to search for the tool using the\r
1609 # PATH environment variable.\r
1610 for dirInPath in os.environ['PATH'].split(os.pathsep):\r
1611 foundPath = os.path.join(dirInPath, tool)\r
1612 if os.path.exists(foundPath):\r
1613 return os.path.realpath(foundPath)\r
1614\r
1615 # If the tool was not found in the path then we just return\r
1616 # the input tool.\r
1617 return tool\r
1618\r
1619 ## Launch the module or platform build\r
1620 #\r
1621 def Launch(self):\r
1622 if self.ModuleFile == None or self.ModuleFile == "":\r
1623 if not self.SpawnMode or self.Target not in ["", "all"]:\r
1624 self.SpawnMode = False\r
1625 self._BuildPlatform()\r
1626 else:\r
1627 self._MultiThreadBuildPlatform()\r
1628 self.CreateGuidedSectionToolsFile()\r
1629 else:\r
1630 self.SpawnMode = False\r
1631 self._BuildModule()\r
1632\r
1633 ## Do some clean-up works when error occurred\r
1634 def Relinquish(self):\r
1635 OldLogLevel = EdkLogger.GetLevel()\r
1636 EdkLogger.SetLevel(EdkLogger.ERROR)\r
1637 #self.DumpBuildData()\r
1638 Utils.Progressor.Abort()\r
1639 if self.SpawnMode == True:\r
1640 BuildTask.Abort()\r
1641 EdkLogger.SetLevel(OldLogLevel)\r
1642\r
1643 def DumpBuildData(self):\r
1644 CacheDirectory = os.path.join(self.WorkspaceDir, gBuildCacheDir)\r
1645 Utils.CreateDirectory(CacheDirectory)\r
1646 Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))\r
1647 Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))\r
1648\r
1649 def RestoreBuildData(self):\r
1650 FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gFileTimeStampCache")\r
1651 if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):\r
1652 Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)\r
1653 if Utils.gFileTimeStampCache == None:\r
1654 Utils.gFileTimeStampCache = {}\r
1655\r
1656 FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gDependencyDatabase")\r
1657 if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):\r
1658 Utils.gDependencyDatabase = Utils.DataRestore(FilePath)\r
1659 if Utils.gDependencyDatabase == None:\r
1660 Utils.gDependencyDatabase = {}\r
1661\r
1662def ParseDefines(DefineList=[]):\r
1663 DefineDict = {}\r
1664 if DefineList != None:\r
1665 for Define in DefineList:\r
1666 DefineTokenList = Define.split("=", 1)\r
1667 if len(DefineTokenList) == 1:\r
1668 DefineDict[DefineTokenList[0]] = ""\r
1669 else:\r
1670 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()\r
1671 return DefineDict\r
1672\r
1673gParamCheck = []\r
1674def SingleCheckCallback(option, opt_str, value, parser):\r
1675 if option not in gParamCheck:\r
1676 setattr(parser.values, option.dest, value)\r
1677 gParamCheck.append(option)\r
1678 else:\r
1679 parser.error("Option %s only allows one instance in command line!" % option)\r
1680\r
1681## Parse command line options\r
1682#\r
1683# Using standard Python module optparse to parse command line option of this tool.\r
1684#\r
1685# @retval Opt A optparse.Values object containing the parsed options\r
1686# @retval Args Target of build command\r
1687#\r
1688def MyOptionParser():\r
1689 Parser = OptionParser(description=__copyright__,version=__version__,prog="build.exe",usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")\r
1690 Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32','X64','IPF','EBC','ARM'], dest="TargetArch",\r
1691 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
1692 Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,\r
1693 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")\r
1694 Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,\r
1695 help="Build the module specified by the INF file name argument.")\r
1696 Parser.add_option("-b", "--buildtarget", action="append", type="choice", choices=['DEBUG','RELEASE'], dest="BuildTarget",\r
1697 help="BuildTarget is one of list: DEBUG, RELEASE, which overrides target.txt's TARGET definition. To specify more TARGET, please repeat this option.")\r
1698 Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",\r
1699 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")\r
1700 Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,\r
1701 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")\r
1702\r
1703 Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,\r
1704 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
1705\r
1706 Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,\r
1707 help="The name of the FDF file to use, which overrides the setting in the DSC file.")\r
1708 Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],\r
1709 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")\r
1710 Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],\r
1711 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")\r
1712\r
1713 Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")\r
1714 Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")\r
1715\r
1716 Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", help="Don't check case of file name.")\r
1717\r
1718 # Parser.add_option("-D", "--define", action="append", dest="Defines", metavar="NAME[=[VALUE]]",\r
1719 # help="Define global macro which can be used in DSC/DEC/INF files.")\r
1720\r
1721 Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")\r
1722 Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")\r
1723\r
1724 Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",\r
1725 help="Make use of silent mode of (n)make.")\r
1726 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
1727 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\\r
1728 "including library instances selected, final dependency expression, "\\r
1729 "and warning messages, etc.")\r
1730 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
1731 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
1732\r
1733 Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")\r
1734 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
1735 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
1736 "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
1737 Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",\r
1738 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
1739 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\\r
1740 "will override the setting in [BuildOptions] section of platform DSC.")\r
52302d4d
LG
1741\r
1742 (Opt, Args)=Parser.parse_args()\r
1743 return (Opt, Args)\r
1744\r
1745## Tool entrance method\r
1746#\r
1747# This method mainly dispatch specific methods per the command line options.\r
1748# If no error found, return zero value so the caller of this tool can know\r
1749# if it's executed successfully or not.\r
1750#\r
1751# @retval 0 Tool was successful\r
1752# @retval 1 Tool failed\r
1753#\r
1754def Main():\r
1755 StartTime = time.time()\r
1756\r
1757 # Initialize log system\r
1758 EdkLogger.Initialize()\r
1759\r
1760 #\r
1761 # Parse the options and args\r
1762 #\r
1763 (Option, Target) = MyOptionParser()\r
1764 GlobalData.gOptions = Option\r
1765 GlobalData.gCaseInsensitive = Option.CaseInsensitive\r
1766\r
1767 # Set log level\r
1768 if Option.verbose != None:\r
1769 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
1770 elif Option.quiet != None:\r
1771 EdkLogger.SetLevel(EdkLogger.QUIET)\r
1772 elif Option.debug != None:\r
1773 EdkLogger.SetLevel(Option.debug + 1)\r
1774 else:\r
1775 EdkLogger.SetLevel(EdkLogger.INFO)\r
1776\r
1777 if Option.LogFile != None:\r
1778 EdkLogger.SetLogFile(Option.LogFile)\r
1779\r
1780 if Option.WarningAsError == True:\r
1781 EdkLogger.SetWarningAsError()\r
1782\r
1783 if platform.platform().find("Windows") >= 0:\r
1784 GlobalData.gIsWindows = True\r
1785 else:\r
1786 GlobalData.gIsWindows = False\r
1787\r
1788 EdkLogger.quiet(time.strftime("%H:%M:%S, %b.%d %Y ", time.localtime()) + "[%s]\n" % platform.platform())\r
1789 ReturnCode = 0\r
1790 MyBuild = None\r
1791 try:\r
1792 if len(Target) == 0:\r
1793 Target = "all"\r
1794 elif len(Target) >= 2:\r
1795 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",\r
1796 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))\r
1797 else:\r
1798 Target = Target[0].lower()\r
1799\r
1800 if Target not in gSupportedTarget:\r
1801 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,\r
1802 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))\r
1803\r
1804 GlobalData.gGlobalDefines = ParseDefines(Option.Macros)\r
1805 #\r
1806 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH\r
1807 #\r
1808 CheckEnvVariable()\r
1809 Workspace = os.getenv("WORKSPACE")\r
1810 #\r
1811 # Get files real name in workspace dir\r
1812 #\r
1813 GlobalData.gAllFiles = Utils.DirCache(Workspace)\r
1814\r
1815 WorkingDirectory = os.getcwd()\r
1816 if not Option.ModuleFile:\r
1817 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))\r
1818 FileNum = len(FileList)\r
1819 if FileNum >= 2:\r
1820 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),\r
1821 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")\r
1822 elif FileNum == 1:\r
1823 Option.ModuleFile = NormFile(FileList[0], Workspace)\r
1824\r
1825 if Option.ModuleFile:\r
1826 if os.path.isabs (Option.ModuleFile):\r
1827 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:\r
1828 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)\r
1829 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)\r
1830 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)\r
1831 if ErrorCode != 0:\r
1832 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
1833\r
1834 if Option.PlatformFile != None:\r
1835 if os.path.isabs (Option.PlatformFile):\r
1836 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:\r
1837 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)\r
1838 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)\r
1839 ErrorCode, ErrorInfo = Option.PlatformFile.Validate(".dsc", False)\r
1840 if ErrorCode != 0:\r
1841 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
1842\r
1843 if Option.FdfFile != None:\r
1844 if os.path.isabs (Option.FdfFile):\r
1845 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:\r
1846 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)\r
1847 Option.FdfFile = PathClass(Option.FdfFile, Workspace)\r
1848 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)\r
1849 if ErrorCode != 0:\r
1850 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
1851\r
f3decdc3
LG
1852 if Option.Flag != None and Option.Flag not in ['-c', '-s']:\r
1853 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")\r
1854\r
52302d4d
LG
1855 MyBuild = Build(Target, Workspace, Option.PlatformFile, Option.ModuleFile,\r
1856 Option.TargetArch, Option.ToolChain, Option.BuildTarget,\r
1857 Option.FdfFile, Option.RomImage, Option.FvImage,\r
1858 None, Option.SilentMode, Option.ThreadNumber,\r
1859 Option.SkipAutoGen, Option.Reparse, Option.SkuId, \r
f3decdc3 1860 Option.ReportFile, Option.ReportType, Option.Flag)\r
52302d4d
LG
1861 MyBuild.Launch()\r
1862 #MyBuild.DumpBuildData()\r
1863 except FatalError, X:\r
1864 if MyBuild != None:\r
1865 # for multi-thread build exits safely\r
1866 MyBuild.Relinquish()\r
1867 if Option != None and Option.debug != None:\r
1868 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
1869 ReturnCode = X.args[0]\r
1870 except Warning, X:\r
1871 # error from Fdf parser\r
1872 if MyBuild != None:\r
1873 # for multi-thread build exits safely\r
1874 MyBuild.Relinquish()\r
1875 if Option != None and Option.debug != None:\r
1876 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
1877 else:\r
1878 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError = False)\r
1879 ReturnCode = FORMAT_INVALID\r
1880 except KeyboardInterrupt:\r
1881 ReturnCode = ABORT_ERROR\r
1882 if Option != None and Option.debug != None:\r
1883 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
1884 except:\r
1885 if MyBuild != None:\r
1886 # for multi-thread build exits safely\r
1887 MyBuild.Relinquish()\r
1888\r
1889 # try to get the meta-file from the object causing exception\r
1890 Tb = sys.exc_info()[-1]\r
1891 MetaFile = GlobalData.gProcessingFile\r
1892 while Tb != None:\r
1893 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):\r
1894 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile\r
1895 Tb = Tb.tb_next\r
1896 EdkLogger.error(\r
1897 "\nbuild",\r
1898 CODE_ERROR,\r
1899 "Unknown fatal error when processing [%s]" % MetaFile,\r
1900 ExtraData="\n(Please send email to edk2-buildtools-devel@lists.sourceforge.net for help, attaching following call stack trace!)\n",\r
1901 RaiseError=False\r
1902 )\r
1903 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
1904 ReturnCode = CODE_ERROR\r
1905 finally:\r
1906 Utils.Progressor.Abort()\r
1907\r
1908 if ReturnCode == 0:\r
1909 Conclusion = "Done"\r
1910 elif ReturnCode == ABORT_ERROR:\r
1911 Conclusion = "Aborted"\r
1912 else:\r
1913 Conclusion = "Failed"\r
1914 FinishTime = time.time()\r
1915 BuildDuration = time.strftime("%M:%S", time.gmtime(int(round(FinishTime - StartTime))))\r
1916 if MyBuild != None:\r
1917 MyBuild.BuildReport.GenerateReport(BuildDuration)\r
1918 MyBuild.Db.Close()\r
1919 EdkLogger.SetLevel(EdkLogger.QUIET)\r
1920 EdkLogger.quiet("\n- %s -\n%s [%s]" % (Conclusion, time.strftime("%H:%M:%S, %b.%d %Y", time.localtime()), BuildDuration))\r
1921\r
1922 return ReturnCode\r
1923\r
1924if __name__ == '__main__':\r
1925 r = Main()\r
1926 ## 0-127 is a safe return range, and 1 is a standard default error\r
1927 if r < 0 or r > 127: r = 1\r
1928 sys.exit(r)\r
1929\r