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