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