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