]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - BaseTools/Source/Python/build/build.py
BaseTools/GenFds: register MM Modules and MM FV file types.
[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 - 2017, 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 - 2017, 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 platform.system() != 'Windows':\r
269 if not isinstance(Command, list):\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 self.TargetTxt = TargetTxtClassObject()\r
829 self.ToolDef = ToolDefClassObject()\r
830 if not (self.LaunchPrebuildFlag and os.path.exists(self.PlatformBuildPath)):\r
831 self.InitBuild()\r
832\r
833 EdkLogger.info("")\r
834 os.chdir(self.WorkspaceDir)\r
835\r
836 ## Load configuration\r
837 #\r
838 # This method will parse target.txt and get the build configurations.\r
839 #\r
840 def LoadConfiguration(self):\r
841 #\r
842 # Check target.txt and tools_def.txt and Init them\r
843 #\r
844 BuildConfigurationFile = os.path.normpath(os.path.join(GlobalData.gConfDirectory, gBuildConfiguration))\r
845 if os.path.isfile(BuildConfigurationFile) == True:\r
846 StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)\r
847\r
848 ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]\r
849 if ToolDefinitionFile == '':\r
850 ToolDefinitionFile = gToolsDefinition\r
851 ToolDefinitionFile = os.path.normpath(mws.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile))\r
852 if os.path.isfile(ToolDefinitionFile) == True:\r
853 StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)\r
854 else:\r
855 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)\r
856 else:\r
857 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)\r
858\r
859 # if no ARCH given in command line, get it from target.txt\r
860 if not self.ArchList:\r
861 self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH]\r
862 self.ArchList = tuple(self.ArchList)\r
863\r
864 # if no build target given in command line, get it from target.txt\r
865 if not self.BuildTargetList:\r
866 self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]\r
867\r
868 # if no tool chain given in command line, get it from target.txt\r
869 if not self.ToolChainList:\r
870 self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]\r
871 if self.ToolChainList == None or len(self.ToolChainList) == 0:\r
872 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")\r
873\r
874 # check if the tool chains are defined or not\r
875 NewToolChainList = []\r
876 for ToolChain in self.ToolChainList:\r
877 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:\r
878 EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)\r
879 else:\r
880 NewToolChainList.append(ToolChain)\r
881 # if no tool chain available, break the build\r
882 if len(NewToolChainList) == 0:\r
883 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
884 ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))\r
885 else:\r
886 self.ToolChainList = NewToolChainList\r
887\r
888 ToolChainFamily = []\r
889 ToolDefinition = self.ToolDef.ToolsDefTxtDatabase\r
890 for Tool in self.ToolChainList:\r
891 if TAB_TOD_DEFINES_FAMILY not in ToolDefinition or Tool not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \\r
892 or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool]:\r
893 EdkLogger.warn("No tool chain family found in configuration for %s. Default to MSFT." % Tool)\r
894 ToolChainFamily.append("MSFT")\r
895 else:\r
896 ToolChainFamily.append(ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool])\r
897 self.ToolChainFamily = ToolChainFamily\r
898\r
899 if self.ThreadNumber == None:\r
900 self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]\r
901 if self.ThreadNumber == '':\r
902 self.ThreadNumber = 0\r
903 else:\r
904 self.ThreadNumber = int(self.ThreadNumber, 0)\r
905\r
906 if self.ThreadNumber == 0:\r
907 self.ThreadNumber = 1\r
908\r
909 if not self.PlatformFile:\r
910 PlatformFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM]\r
911 if not PlatformFile:\r
912 # Try to find one in current directory\r
913 WorkingDirectory = os.getcwd()\r
914 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))\r
915 FileNum = len(FileList)\r
916 if FileNum >= 2:\r
917 EdkLogger.error("build", OPTION_MISSING,\r
918 ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))\r
919 elif FileNum == 1:\r
920 PlatformFile = FileList[0]\r
921 else:\r
922 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
923 ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")\r
924\r
925 self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)\r
926\r
927 ## Initialize build configuration\r
928 #\r
929 # This method will parse DSC file and merge the configurations from\r
930 # command line and target.txt, then get the final build configurations.\r
931 #\r
932 def InitBuild(self):\r
933 # parse target.txt, tools_def.txt, and platform file\r
934 self.LoadConfiguration()\r
935\r
936 # Allow case-insensitive for those from command line or configuration file\r
937 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)\r
938 if ErrorCode != 0:\r
939 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
940\r
941 # create metafile database\r
942 if not self.Db_Flag:\r
943 self.Db.InitDatabase()\r
944\r
945 def InitPreBuild(self):\r
946 self.LoadConfiguration()\r
947 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)\r
948 if ErrorCode != 0:\r
949 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
950 if self.BuildTargetList:\r
951 GlobalData.gGlobalDefines['TARGET'] = self.BuildTargetList[0]\r
952 if self.ArchList:\r
953 GlobalData.gGlobalDefines['ARCH'] = self.ArchList[0]\r
954 if self.ToolChainList:\r
955 GlobalData.gGlobalDefines['TOOLCHAIN'] = self.ToolChainList[0]\r
956 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = self.ToolChainList[0]\r
957 if self.ToolChainFamily:\r
958 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[0]\r
959 if 'PREBUILD' in GlobalData.gCommandLineDefines.keys():\r
960 self.Prebuild = GlobalData.gCommandLineDefines.get('PREBUILD')\r
961 else:\r
962 self.Db.InitDatabase()\r
963 self.Db_Flag = True\r
964 Platform = self.Db._MapPlatform(str(self.PlatformFile))\r
965 self.Prebuild = str(Platform.Prebuild)\r
966 if self.Prebuild:\r
967 PrebuildList = self.Prebuild.split()\r
968 if not os.path.isabs(PrebuildList[0]):\r
969 PrebuildList[0] = mws.join(self.WorkspaceDir, PrebuildList[0])\r
970 if os.path.isfile(PrebuildList[0]):\r
971 self.PrebuildScript = PrebuildList[0]\r
972 self.Prebuild = ' '.join(PrebuildList)\r
973 self.Prebuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList)\r
974 #self.LaunchPrebuild()\r
975 else:\r
976 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
977\r
978 def InitPostBuild(self):\r
979 if 'POSTBUILD' in GlobalData.gCommandLineDefines.keys():\r
980 self.Postbuild = GlobalData.gCommandLineDefines.get('POSTBUILD')\r
981 else:\r
982 Platform = self.Db._MapPlatform(str(self.PlatformFile))\r
983 self.Postbuild = str(Platform.Postbuild)\r
984 if self.Postbuild:\r
985 PostbuildList = self.Postbuild.split()\r
986 if not os.path.isabs(PostbuildList[0]):\r
987 PostbuildList[0] = mws.join(self.WorkspaceDir, PostbuildList[0])\r
988 if os.path.isfile(PostbuildList[0]):\r
989 self.PostbuildScript = PostbuildList[0]\r
990 self.Postbuild = ' '.join(PostbuildList)\r
991 self.Postbuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList)\r
992 else:\r
993 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
994\r
995 def PassCommandOption(self, BuildTarget, TargetArch, ToolChain):\r
996 BuildStr = ''\r
997 if GlobalData.gCommand and isinstance(GlobalData.gCommand, list):\r
998 BuildStr += ' ' + ' '.join(GlobalData.gCommand)\r
999 TargetFlag = False\r
1000 ArchFlag = False\r
1001 ToolChainFlag = False\r
1002\r
1003 if GlobalData.gOptions and not GlobalData.gOptions.BuildTarget:\r
1004 TargetFlag = True\r
1005 if GlobalData.gOptions and not GlobalData.gOptions.TargetArch:\r
1006 ArchFlag = True\r
1007 if GlobalData.gOptions and not GlobalData.gOptions.ToolChain:\r
1008 ToolChainFlag = True\r
1009\r
1010 if TargetFlag and BuildTarget:\r
1011 if isinstance(BuildTarget, list) or isinstance(BuildTarget, tuple):\r
1012 BuildStr += ' -b ' + ' -b '.join(BuildTarget)\r
1013 elif isinstance(BuildTarget, str):\r
1014 BuildStr += ' -b ' + BuildTarget\r
1015 if ArchFlag and TargetArch:\r
1016 if isinstance(TargetArch, list) or isinstance(TargetArch, tuple):\r
1017 BuildStr += ' -a ' + ' -a '.join(TargetArch)\r
1018 elif isinstance(TargetArch, str):\r
1019 BuildStr += ' -a ' + TargetArch\r
1020 if ToolChainFlag and ToolChain:\r
1021 if isinstance(ToolChain, list) or isinstance(ToolChain, tuple):\r
1022 BuildStr += ' -t ' + ' -t '.join(ToolChain)\r
1023 elif isinstance(ToolChain, str):\r
1024 BuildStr += ' -t ' + ToolChain\r
1025\r
1026 return BuildStr\r
1027\r
1028 def LaunchPrebuild(self):\r
1029 if self.Prebuild:\r
1030 EdkLogger.info("\n- Prebuild Start -\n")\r
1031 self.LaunchPrebuildFlag = True\r
1032 PrebuildEnvFile = os.path.join(GlobalData.gConfDirectory,'.cache','.PrebuildEnv')\r
1033 if os.path.isfile(PrebuildEnvFile):\r
1034 os.remove(PrebuildEnvFile)\r
1035 if os.path.isfile(self.PlatformBuildPath):\r
1036 os.remove(self.PlatformBuildPath)\r
1037 if sys.platform == "win32":\r
1038 args = ' && '.join((self.Prebuild, 'set > ' + PrebuildEnvFile))\r
1039 Process = Popen(args, stdout=PIPE, stderr=PIPE)\r
1040 else:\r
1041 args = ' && '.join((self.Prebuild, 'env > ' + PrebuildEnvFile))\r
1042 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)\r
1043\r
1044 # launch two threads to read the STDOUT and STDERR\r
1045 EndOfProcedure = Event()\r
1046 EndOfProcedure.clear()\r
1047 if Process.stdout:\r
1048 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))\r
1049 StdOutThread.setName("STDOUT-Redirector")\r
1050 StdOutThread.setDaemon(False)\r
1051 StdOutThread.start()\r
1052\r
1053 if Process.stderr:\r
1054 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))\r
1055 StdErrThread.setName("STDERR-Redirector")\r
1056 StdErrThread.setDaemon(False)\r
1057 StdErrThread.start()\r
1058 # waiting for program exit\r
1059 Process.wait()\r
1060\r
1061 if Process.stdout:\r
1062 StdOutThread.join()\r
1063 if Process.stderr:\r
1064 StdErrThread.join()\r
1065 if Process.returncode != 0 :\r
1066 EdkLogger.error("Prebuild", PREBUILD_ERROR, 'Prebuild process is not success!')\r
1067\r
1068 if os.path.exists(PrebuildEnvFile):\r
1069 f = open(PrebuildEnvFile)\r
1070 envs = f.readlines()\r
1071 f.close()\r
1072 envs = itertools.imap(lambda l: l.split('=',1), envs)\r
1073 envs = itertools.ifilter(lambda l: len(l) == 2, envs)\r
1074 envs = itertools.imap(lambda l: [i.strip() for i in l], envs)\r
1075 os.environ.update(dict(envs))\r
1076 EdkLogger.info("\n- Prebuild Done -\n")\r
1077\r
1078 def LaunchPostbuild(self):\r
1079 if self.Postbuild:\r
1080 EdkLogger.info("\n- Postbuild Start -\n")\r
1081 if sys.platform == "win32":\r
1082 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE)\r
1083 else:\r
1084 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)\r
1085 # launch two threads to read the STDOUT and STDERR\r
1086 EndOfProcedure = Event()\r
1087 EndOfProcedure.clear()\r
1088 if Process.stdout:\r
1089 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))\r
1090 StdOutThread.setName("STDOUT-Redirector")\r
1091 StdOutThread.setDaemon(False)\r
1092 StdOutThread.start()\r
1093\r
1094 if Process.stderr:\r
1095 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))\r
1096 StdErrThread.setName("STDERR-Redirector")\r
1097 StdErrThread.setDaemon(False)\r
1098 StdErrThread.start()\r
1099 # waiting for program exit\r
1100 Process.wait()\r
1101\r
1102 if Process.stdout:\r
1103 StdOutThread.join()\r
1104 if Process.stderr:\r
1105 StdErrThread.join()\r
1106 if Process.returncode != 0 :\r
1107 EdkLogger.error("Postbuild", POSTBUILD_ERROR, 'Postbuild process is not success!')\r
1108 EdkLogger.info("\n- Postbuild Done -\n")\r
1109 ## Build a module or platform\r
1110 #\r
1111 # Create autogen code and makefile for a module or platform, and the launch\r
1112 # "make" command to build it\r
1113 #\r
1114 # @param Target The target of build command\r
1115 # @param Platform The platform file\r
1116 # @param Module The module file\r
1117 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
1118 # @param ToolChain The name of toolchain to build\r
1119 # @param Arch The arch of the module/platform\r
1120 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
1121 # for dependent modules/Libraries\r
1122 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
1123 # for dependent modules/Libraries\r
1124 #\r
1125 def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):\r
1126 if AutoGenObject == None:\r
1127 return False\r
1128\r
1129 # skip file generation for cleanxxx targets, run and fds target\r
1130 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1131 # for target which must generate AutoGen code and makefile\r
1132 if not self.SkipAutoGen or Target == 'genc':\r
1133 self.Progress.Start("Generating code")\r
1134 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
1135 self.Progress.Stop("done!")\r
1136 if Target == "genc":\r
1137 return True\r
1138\r
1139 if not self.SkipAutoGen or Target == 'genmake':\r
1140 self.Progress.Start("Generating makefile")\r
1141 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)\r
1142 self.Progress.Stop("done!")\r
1143 if Target == "genmake":\r
1144 return True\r
1145 else:\r
1146 # always recreate top/platform makefile when clean, just in case of inconsistency\r
1147 AutoGenObject.CreateCodeFile(False)\r
1148 AutoGenObject.CreateMakeFile(False)\r
1149\r
1150 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
1151 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
1152\r
1153 BuildCommand = AutoGenObject.BuildCommand\r
1154 if BuildCommand == None or len(BuildCommand) == 0:\r
1155 EdkLogger.error("build", OPTION_MISSING,\r
1156 "No build command found for this module. "\r
1157 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
1158 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
1159 ExtraData=str(AutoGenObject))\r
1160\r
1161 makefile = GenMake.BuildFile(AutoGenObject)._FILE_NAME_[GenMake.gMakeType]\r
1162\r
1163 # run\r
1164 if Target == 'run':\r
1165 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))\r
1166 Command = '.\SecMain'\r
1167 os.chdir(RunDir)\r
1168 LaunchCommand(Command, RunDir)\r
1169 return True\r
1170\r
1171 # build modules\r
1172 if BuildModule:\r
1173 BuildCommand = BuildCommand + [Target]\r
1174 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
1175 self.CreateAsBuiltInf()\r
1176 return True\r
1177\r
1178 # build library\r
1179 if Target == 'libraries':\r
1180 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1181 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']\r
1182 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1183 return True\r
1184\r
1185 # build module\r
1186 if Target == 'modules':\r
1187 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1188 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']\r
1189 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1190 for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
1191 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']\r
1192 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1193 self.CreateAsBuiltInf()\r
1194 return True\r
1195\r
1196 # cleanlib\r
1197 if Target == 'cleanlib':\r
1198 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1199 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))\r
1200 if os.path.exists(LibMakefile):\r
1201 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
1202 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1203 return True\r
1204\r
1205 # clean\r
1206 if Target == 'clean':\r
1207 for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
1208 ModMakefile = os.path.normpath(os.path.join(Mod, makefile))\r
1209 if os.path.exists(ModMakefile):\r
1210 NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']\r
1211 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1212 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1213 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))\r
1214 if os.path.exists(LibMakefile):\r
1215 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
1216 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1217 return True\r
1218\r
1219 # cleanall\r
1220 if Target == 'cleanall':\r
1221 try:\r
1222 #os.rmdir(AutoGenObject.BuildDir)\r
1223 RemoveDirectory(AutoGenObject.BuildDir, True)\r
1224 except WindowsError, X:\r
1225 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1226 return True\r
1227\r
1228 ## Build a module or platform\r
1229 #\r
1230 # Create autogen code and makefile for a module or platform, and the launch\r
1231 # "make" command to build it\r
1232 #\r
1233 # @param Target The target of build command\r
1234 # @param Platform The platform file\r
1235 # @param Module The module file\r
1236 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
1237 # @param ToolChain The name of toolchain to build\r
1238 # @param Arch The arch of the module/platform\r
1239 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
1240 # for dependent modules/Libraries\r
1241 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
1242 # for dependent modules/Libraries\r
1243 #\r
1244 def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):\r
1245 if AutoGenObject == None:\r
1246 return False\r
1247\r
1248 # skip file generation for cleanxxx targets, run and fds target\r
1249 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1250 # for target which must generate AutoGen code and makefile\r
1251 if not self.SkipAutoGen or Target == 'genc':\r
1252 self.Progress.Start("Generating code")\r
1253 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
1254 self.Progress.Stop("done!")\r
1255 if Target == "genc":\r
1256 return True\r
1257\r
1258 if not self.SkipAutoGen or Target == 'genmake':\r
1259 self.Progress.Start("Generating makefile")\r
1260 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)\r
1261 #AutoGenObject.CreateAsBuiltInf()\r
1262 self.Progress.Stop("done!")\r
1263 if Target == "genmake":\r
1264 return True\r
1265 else:\r
1266 # always recreate top/platform makefile when clean, just in case of inconsistency\r
1267 AutoGenObject.CreateCodeFile(False)\r
1268 AutoGenObject.CreateMakeFile(False)\r
1269\r
1270 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
1271 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
1272\r
1273 BuildCommand = AutoGenObject.BuildCommand\r
1274 if BuildCommand == None or len(BuildCommand) == 0:\r
1275 EdkLogger.error("build", OPTION_MISSING,\r
1276 "No build command found for this module. "\r
1277 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
1278 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
1279 ExtraData=str(AutoGenObject))\r
1280\r
1281 # build modules\r
1282 if BuildModule:\r
1283 if Target != 'fds':\r
1284 BuildCommand = BuildCommand + [Target]\r
1285 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
1286 self.CreateAsBuiltInf()\r
1287 return True\r
1288\r
1289 # genfds\r
1290 if Target == 'fds':\r
1291 LaunchCommand(AutoGenObject.GenFdsCommand, AutoGenObject.MakeFileDir)\r
1292 return True\r
1293\r
1294 # run\r
1295 if Target == 'run':\r
1296 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))\r
1297 Command = '.\SecMain'\r
1298 os.chdir(RunDir)\r
1299 LaunchCommand(Command, RunDir)\r
1300 return True\r
1301\r
1302 # build library\r
1303 if Target == 'libraries':\r
1304 pass\r
1305\r
1306 # not build modules\r
1307\r
1308\r
1309 # cleanall\r
1310 if Target == 'cleanall':\r
1311 try:\r
1312 #os.rmdir(AutoGenObject.BuildDir)\r
1313 RemoveDirectory(AutoGenObject.BuildDir, True)\r
1314 except WindowsError, X:\r
1315 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1316 return True\r
1317\r
1318 ## Rebase module image and Get function address for the input module list.\r
1319 #\r
1320 def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):\r
1321 if ModeIsSmm:\r
1322 AddrIsOffset = False\r
1323 InfFileNameList = ModuleList.keys()\r
1324 #InfFileNameList.sort()\r
1325 for InfFile in InfFileNameList:\r
1326 sys.stdout.write (".")\r
1327 sys.stdout.flush()\r
1328 ModuleInfo = ModuleList[InfFile]\r
1329 ModuleName = ModuleInfo.BaseName\r
1330 ModuleOutputImage = ModuleInfo.Image.FileName\r
1331 ModuleDebugImage = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')\r
1332 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1333 if not ModeIsSmm:\r
1334 BaseAddress = BaseAddress - ModuleInfo.Image.Size\r
1335 #\r
1336 # Update Image to new BaseAddress by GenFw tool\r
1337 #\r
1338 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
1339 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
1340 else:\r
1341 #\r
1342 # Set new address to the section header only for SMM driver.\r
1343 #\r
1344 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
1345 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
1346 #\r
1347 # Collect funtion address from Map file\r
1348 #\r
1349 ImageMapTable = ModuleOutputImage.replace('.efi', '.map')\r
1350 FunctionList = []\r
1351 if os.path.exists(ImageMapTable):\r
1352 OrigImageBaseAddress = 0\r
1353 ImageMap = open(ImageMapTable, 'r')\r
1354 for LinStr in ImageMap:\r
1355 if len (LinStr.strip()) == 0:\r
1356 continue\r
1357 #\r
1358 # Get the preferred address set on link time.\r
1359 #\r
1360 if LinStr.find ('Preferred load address is') != -1:\r
1361 StrList = LinStr.split()\r
1362 OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)\r
1363\r
1364 StrList = LinStr.split()\r
1365 if len (StrList) > 4:\r
1366 if StrList[3] == 'f' or StrList[3] == 'F':\r
1367 Name = StrList[1]\r
1368 RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress\r
1369 FunctionList.append ((Name, RelativeAddress))\r
1370 if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'):\r
1371 #\r
1372 # Get the real entry point address for IPF image.\r
1373 #\r
1374 ModuleInfo.Image.EntryPoint = RelativeAddress\r
1375 ImageMap.close()\r
1376 #\r
1377 # Add general information.\r
1378 #\r
1379 if ModeIsSmm:\r
1380 MapBuffer.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1381 elif AddrIsOffset:\r
1382 MapBuffer.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))\r
1383 else:\r
1384 MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1385 #\r
1386 # Add guid and general seciton section.\r
1387 #\r
1388 TextSectionAddress = 0\r
1389 DataSectionAddress = 0\r
1390 for SectionHeader in ModuleInfo.Image.SectionHeaderList:\r
1391 if SectionHeader[0] == '.text':\r
1392 TextSectionAddress = SectionHeader[1]\r
1393 elif SectionHeader[0] in ['.data', '.sdata']:\r
1394 DataSectionAddress = SectionHeader[1]\r
1395 if AddrIsOffset:\r
1396 MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))\r
1397 else:\r
1398 MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))\r
1399 #\r
1400 # Add debug image full path.\r
1401 #\r
1402 MapBuffer.write('(IMAGE=%s)\n\n' % (ModuleDebugImage))\r
1403 #\r
1404 # Add funtion address\r
1405 #\r
1406 for Function in FunctionList:\r
1407 if AddrIsOffset:\r
1408 MapBuffer.write(' -0x%010X %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))\r
1409 else:\r
1410 MapBuffer.write(' 0x%010X %s\n' % (BaseAddress + Function[1], Function[0]))\r
1411 ImageMap.close()\r
1412\r
1413 #\r
1414 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1415 #\r
1416 if ModeIsSmm:\r
1417 BaseAddress = BaseAddress + ModuleInfo.Image.Size\r
1418\r
1419 ## Collect MAP information of all FVs\r
1420 #\r
1421 def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):\r
1422 if self.Fdf:\r
1423 # First get the XIP base address for FV map file.\r
1424 GuidPattern = re.compile("[-a-fA-F0-9]+")\r
1425 GuidName = re.compile("\(GUID=[-a-fA-F0-9]+")\r
1426 for FvName in Wa.FdfProfile.FvDict.keys():\r
1427 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')\r
1428 if not os.path.exists(FvMapBuffer):\r
1429 continue\r
1430 FvMap = open(FvMapBuffer, 'r')\r
1431 #skip FV size information\r
1432 FvMap.readline()\r
1433 FvMap.readline()\r
1434 FvMap.readline()\r
1435 FvMap.readline()\r
1436 for Line in FvMap:\r
1437 MatchGuid = GuidPattern.match(Line)\r
1438 if MatchGuid != None:\r
1439 #\r
1440 # Replace GUID with module name\r
1441 #\r
1442 GuidString = MatchGuid.group()\r
1443 if GuidString.upper() in ModuleList:\r
1444 Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)\r
1445 MapBuffer.write('%s' % (Line))\r
1446 #\r
1447 # Add the debug image full path.\r
1448 #\r
1449 MatchGuid = GuidName.match(Line)\r
1450 if MatchGuid != None:\r
1451 GuidString = MatchGuid.group().split("=")[1]\r
1452 if GuidString.upper() in ModuleList:\r
1453 MapBuffer.write('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))\r
1454\r
1455 FvMap.close()\r
1456\r
1457 ## Collect MAP information of all modules\r
1458 #\r
1459 def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):\r
1460 sys.stdout.write ("Generate Load Module At Fix Address Map")\r
1461 sys.stdout.flush()\r
1462 PatchEfiImageList = []\r
1463 PeiModuleList = {}\r
1464 BtModuleList = {}\r
1465 RtModuleList = {}\r
1466 SmmModuleList = {}\r
1467 PeiSize = 0\r
1468 BtSize = 0\r
1469 RtSize = 0\r
1470 # reserve 4K size in SMRAM to make SMM module address not from 0.\r
1471 SmmSize = 0x1000\r
1472 IsIpfPlatform = False\r
1473 if 'IPF' in self.ArchList:\r
1474 IsIpfPlatform = True\r
1475 for ModuleGuid in ModuleList:\r
1476 Module = ModuleList[ModuleGuid]\r
1477 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)\r
1478\r
1479 OutputImageFile = ''\r
1480 for ResultFile in Module.CodaTargetList:\r
1481 if str(ResultFile.Target).endswith('.efi'):\r
1482 #\r
1483 # module list for PEI, DXE, RUNTIME and SMM\r
1484 #\r
1485 OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')\r
1486 ImageClass = PeImageClass (OutputImageFile)\r
1487 if not ImageClass.IsValid:\r
1488 EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)\r
1489 ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)\r
1490 if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER', 'PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']:\r
1491 PeiModuleList[Module.MetaFile] = ImageInfo\r
1492 PeiSize += ImageInfo.Image.Size\r
1493 elif Module.ModuleType in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']:\r
1494 BtModuleList[Module.MetaFile] = ImageInfo\r
1495 BtSize += ImageInfo.Image.Size\r
1496 elif Module.ModuleType in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']:\r
1497 RtModuleList[Module.MetaFile] = ImageInfo\r
1498 #IPF runtime driver needs to be at 2 page alignment.\r
1499 if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0:\r
1500 ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000\r
1501 RtSize += ImageInfo.Image.Size\r
1502 elif Module.ModuleType in ['SMM_CORE', 'DXE_SMM_DRIVER']:\r
1503 SmmModuleList[Module.MetaFile] = ImageInfo\r
1504 SmmSize += ImageInfo.Image.Size\r
1505 if Module.ModuleType == 'DXE_SMM_DRIVER':\r
1506 PiSpecVersion = '0x00000000'\r
1507 if 'PI_SPECIFICATION_VERSION' in Module.Module.Specification:\r
1508 PiSpecVersion = Module.Module.Specification['PI_SPECIFICATION_VERSION']\r
1509 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.\r
1510 if int(PiSpecVersion, 16) < 0x0001000A:\r
1511 BtModuleList[Module.MetaFile] = ImageInfo\r
1512 BtSize += ImageInfo.Image.Size\r
1513 break\r
1514 #\r
1515 # EFI image is final target.\r
1516 # Check EFI image contains patchable FixAddress related PCDs.\r
1517 #\r
1518 if OutputImageFile != '':\r
1519 ModuleIsPatch = False\r
1520 for Pcd in Module.ModulePcdList:\r
1521 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:\r
1522 ModuleIsPatch = True\r
1523 break\r
1524 if not ModuleIsPatch:\r
1525 for Pcd in Module.LibraryPcdList:\r
1526 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:\r
1527 ModuleIsPatch = True\r
1528 break\r
1529\r
1530 if not ModuleIsPatch:\r
1531 continue\r
1532 #\r
1533 # Module includes the patchable load fix address PCDs.\r
1534 # It will be fixed up later.\r
1535 #\r
1536 PatchEfiImageList.append (OutputImageFile)\r
1537\r
1538 #\r
1539 # Get Top Memory address\r
1540 #\r
1541 ReservedRuntimeMemorySize = 0\r
1542 TopMemoryAddress = 0\r
1543 if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:\r
1544 TopMemoryAddress = 0\r
1545 else:\r
1546 TopMemoryAddress = self.LoadFixAddress\r
1547 if TopMemoryAddress < RtSize + BtSize + PeiSize:\r
1548 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")\r
1549 # Make IPF runtime driver at 2 page alignment.\r
1550 if IsIpfPlatform:\r
1551 ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000\r
1552 RtSize = RtSize + ReservedRuntimeMemorySize\r
1553\r
1554 #\r
1555 # Patch FixAddress related PCDs into EFI image\r
1556 #\r
1557 for EfiImage in PatchEfiImageList:\r
1558 EfiImageMap = EfiImage.replace('.efi', '.map')\r
1559 if not os.path.exists(EfiImageMap):\r
1560 continue\r
1561 #\r
1562 # Get PCD offset in EFI image by GenPatchPcdTable function\r
1563 #\r
1564 PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)\r
1565 #\r
1566 # Patch real PCD value by PatchPcdValue tool\r
1567 #\r
1568 for PcdInfo in PcdTable:\r
1569 ReturnValue = 0\r
1570 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:\r
1571 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize / 0x1000))\r
1572 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:\r
1573 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize / 0x1000))\r
1574 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:\r
1575 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize / 0x1000))\r
1576 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:\r
1577 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize / 0x1000))\r
1578 if ReturnValue != 0:\r
1579 EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)\r
1580\r
1581 MapBuffer.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize / 0x1000))\r
1582 MapBuffer.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize / 0x1000))\r
1583 MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize / 0x1000))\r
1584 if len (SmmModuleList) > 0:\r
1585 MapBuffer.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize / 0x1000))\r
1586\r
1587 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize\r
1588 BtBaseAddr = TopMemoryAddress - RtSize\r
1589 RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize\r
1590\r
1591 self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)\r
1592 self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)\r
1593 self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)\r
1594 self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset=False, ModeIsSmm=True)\r
1595 MapBuffer.write('\n\n')\r
1596 sys.stdout.write ("\n")\r
1597 sys.stdout.flush()\r
1598\r
1599 ## Save platform Map file\r
1600 #\r
1601 def _SaveMapFile (self, MapBuffer, Wa):\r
1602 #\r
1603 # Map file path is got.\r
1604 #\r
1605 MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')\r
1606 #\r
1607 # Save address map into MAP file.\r
1608 #\r
1609 SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)\r
1610 MapBuffer.close()\r
1611 if self.LoadFixAddress != 0:\r
1612 sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath))\r
1613 sys.stdout.flush()\r
1614\r
1615 ## Build active platform for different build targets and different tool chains\r
1616 #\r
1617 def _BuildPlatform(self):\r
1618 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)\r
1619 for BuildTarget in self.BuildTargetList:\r
1620 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
1621 index = 0\r
1622 for ToolChain in self.ToolChainList:\r
1623 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
1624 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
1625 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1626 index += 1\r
1627 Wa = WorkspaceAutoGen(\r
1628 self.WorkspaceDir,\r
1629 self.PlatformFile,\r
1630 BuildTarget,\r
1631 ToolChain,\r
1632 self.ArchList,\r
1633 self.BuildDatabase,\r
1634 self.TargetTxt,\r
1635 self.ToolDef,\r
1636 self.Fdf,\r
1637 self.FdList,\r
1638 self.FvList,\r
1639 self.CapList,\r
1640 self.SkuId,\r
1641 self.UniFlag,\r
1642 self.Progress\r
1643 )\r
1644 self.Fdf = Wa.FdfFile\r
1645 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
1646 self.BuildReport.AddPlatformReport(Wa)\r
1647 self.Progress.Stop("done!")\r
1648 for Arch in Wa.ArchList:\r
1649 GlobalData.gGlobalDefines['ARCH'] = Arch\r
1650 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
1651 for Module in Pa.Platform.Modules:\r
1652 # Get ModuleAutoGen object to generate C code file and makefile\r
1653 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1654 if Ma == None:\r
1655 continue\r
1656 self.BuildModules.append(Ma)\r
1657 self._BuildPa(self.Target, Pa)\r
1658\r
1659 # Create MAP file when Load Fix Address is enabled.\r
1660 if self.Target in ["", "all", "fds"]:\r
1661 for Arch in Wa.ArchList:\r
1662 GlobalData.gGlobalDefines['ARCH'] = Arch\r
1663 #\r
1664 # Check whether the set fix address is above 4G for 32bit image.\r
1665 #\r
1666 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1667 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
1668 #\r
1669 # Get Module List\r
1670 #\r
1671 ModuleList = {}\r
1672 for Pa in Wa.AutoGenObjectList:\r
1673 for Ma in Pa.ModuleAutoGenList:\r
1674 if Ma == None:\r
1675 continue\r
1676 if not Ma.IsLibrary:\r
1677 ModuleList[Ma.Guid.upper()] = Ma\r
1678\r
1679 MapBuffer = StringIO('')\r
1680 if self.LoadFixAddress != 0:\r
1681 #\r
1682 # Rebase module to the preferred memory address before GenFds\r
1683 #\r
1684 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
1685 if self.Fdf:\r
1686 #\r
1687 # create FDS again for the updated EFI image\r
1688 #\r
1689 self._Build("fds", Wa)\r
1690 #\r
1691 # Create MAP file for all platform FVs after GenFds.\r
1692 #\r
1693 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
1694 #\r
1695 # Save MAP buffer into MAP file.\r
1696 #\r
1697 self._SaveMapFile (MapBuffer, Wa)\r
1698\r
1699 ## Build active module for different build targets, different tool chains and different archs\r
1700 #\r
1701 def _BuildModule(self):\r
1702 for BuildTarget in self.BuildTargetList:\r
1703 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
1704 index = 0\r
1705 for ToolChain in self.ToolChainList:\r
1706 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
1707 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
1708 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1709 index += 1\r
1710 #\r
1711 # module build needs platform build information, so get platform\r
1712 # AutoGen first\r
1713 #\r
1714 Wa = WorkspaceAutoGen(\r
1715 self.WorkspaceDir,\r
1716 self.PlatformFile,\r
1717 BuildTarget,\r
1718 ToolChain,\r
1719 self.ArchList,\r
1720 self.BuildDatabase,\r
1721 self.TargetTxt,\r
1722 self.ToolDef,\r
1723 self.Fdf,\r
1724 self.FdList,\r
1725 self.FvList,\r
1726 self.CapList,\r
1727 self.SkuId,\r
1728 self.UniFlag,\r
1729 self.Progress,\r
1730 self.ModuleFile\r
1731 )\r
1732 self.Fdf = Wa.FdfFile\r
1733 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
1734 Wa.CreateMakeFile(False)\r
1735 self.Progress.Stop("done!")\r
1736 MaList = []\r
1737 for Arch in Wa.ArchList:\r
1738 GlobalData.gGlobalDefines['ARCH'] = Arch\r
1739 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
1740 for Module in Pa.Platform.Modules:\r
1741 if self.ModuleFile.Dir == Module.Dir and self.ModuleFile.File == Module.File:\r
1742 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1743 if Ma == None: continue\r
1744 MaList.append(Ma)\r
1745 self.BuildModules.append(Ma)\r
1746 if not Ma.IsBinaryModule:\r
1747 self._Build(self.Target, Ma, BuildModule=True)\r
1748\r
1749 self.BuildReport.AddPlatformReport(Wa, MaList)\r
1750 if MaList == []:\r
1751 EdkLogger.error(\r
1752 'build',\r
1753 BUILD_ERROR,\r
1754 "Module for [%s] is not a component of active platform."\\r
1755 " Please make sure that the ARCH and inf file path are"\\r
1756 " given in the same as in [%s]" % \\r
1757 (', '.join(Wa.ArchList), self.PlatformFile),\r
1758 ExtraData=self.ModuleFile\r
1759 )\r
1760 # Create MAP file when Load Fix Address is enabled.\r
1761 if self.Target == "fds" and self.Fdf:\r
1762 for Arch in Wa.ArchList:\r
1763 #\r
1764 # Check whether the set fix address is above 4G for 32bit image.\r
1765 #\r
1766 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1767 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
1768 #\r
1769 # Get Module List\r
1770 #\r
1771 ModuleList = {}\r
1772 for Pa in Wa.AutoGenObjectList:\r
1773 for Ma in Pa.ModuleAutoGenList:\r
1774 if Ma == None:\r
1775 continue\r
1776 if not Ma.IsLibrary:\r
1777 ModuleList[Ma.Guid.upper()] = Ma\r
1778\r
1779 MapBuffer = StringIO('')\r
1780 if self.LoadFixAddress != 0:\r
1781 #\r
1782 # Rebase module to the preferred memory address before GenFds\r
1783 #\r
1784 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
1785 #\r
1786 # create FDS again for the updated EFI image\r
1787 #\r
1788 self._Build("fds", Wa)\r
1789 #\r
1790 # Create MAP file for all platform FVs after GenFds.\r
1791 #\r
1792 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
1793 #\r
1794 # Save MAP buffer into MAP file.\r
1795 #\r
1796 self._SaveMapFile (MapBuffer, Wa)\r
1797\r
1798 ## Build a platform in multi-thread mode\r
1799 #\r
1800 def _MultiThreadBuildPlatform(self):\r
1801 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)\r
1802 for BuildTarget in self.BuildTargetList:\r
1803 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
1804 index = 0\r
1805 for ToolChain in self.ToolChainList:\r
1806 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
1807 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
1808 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1809 index += 1\r
1810 Wa = WorkspaceAutoGen(\r
1811 self.WorkspaceDir,\r
1812 self.PlatformFile,\r
1813 BuildTarget,\r
1814 ToolChain,\r
1815 self.ArchList,\r
1816 self.BuildDatabase,\r
1817 self.TargetTxt,\r
1818 self.ToolDef,\r
1819 self.Fdf,\r
1820 self.FdList,\r
1821 self.FvList,\r
1822 self.CapList,\r
1823 self.SkuId,\r
1824 self.UniFlag,\r
1825 self.Progress\r
1826 )\r
1827 self.Fdf = Wa.FdfFile\r
1828 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
1829 self.BuildReport.AddPlatformReport(Wa)\r
1830 Wa.CreateMakeFile(False)\r
1831\r
1832 # multi-thread exit flag\r
1833 ExitFlag = threading.Event()\r
1834 ExitFlag.clear()\r
1835 for Arch in Wa.ArchList:\r
1836 GlobalData.gGlobalDefines['ARCH'] = Arch\r
1837 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
1838 if Pa == None:\r
1839 continue\r
1840 ModuleList = []\r
1841 for Inf in Pa.Platform.Modules:\r
1842 ModuleList.append(Inf)\r
1843 # Add the INF only list in FDF\r
1844 if GlobalData.gFdfParser != None:\r
1845 for InfName in GlobalData.gFdfParser.Profile.InfList:\r
1846 Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)\r
1847 if Inf in Pa.Platform.Modules:\r
1848 continue\r
1849 ModuleList.append(Inf)\r
1850 for Module in ModuleList:\r
1851 # Get ModuleAutoGen object to generate C code file and makefile\r
1852 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1853 \r
1854 if Ma == None:\r
1855 continue\r
1856 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'\r
1857 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1858 # for target which must generate AutoGen code and makefile\r
1859 if not self.SkipAutoGen or self.Target == 'genc':\r
1860 Ma.CreateCodeFile(True)\r
1861 if self.Target == "genc":\r
1862 continue\r
1863\r
1864 if not self.SkipAutoGen or self.Target == 'genmake':\r
1865 Ma.CreateMakeFile(True)\r
1866 if self.Target == "genmake":\r
1867 continue\r
1868 self.BuildModules.append(Ma)\r
1869 self.Progress.Stop("done!")\r
1870\r
1871 for Ma in self.BuildModules:\r
1872 # Generate build task for the module\r
1873 if not Ma.IsBinaryModule:\r
1874 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))\r
1875 # Break build if any build thread has error\r
1876 if BuildTask.HasError():\r
1877 # we need a full version of makefile for platform\r
1878 ExitFlag.set()\r
1879 BuildTask.WaitForComplete()\r
1880 Pa.CreateMakeFile(False)\r
1881 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1882 # Start task scheduler\r
1883 if not BuildTask.IsOnGoing():\r
1884 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
1885\r
1886 # in case there's an interruption. we need a full version of makefile for platform\r
1887 Pa.CreateMakeFile(False)\r
1888 if BuildTask.HasError():\r
1889 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1890\r
1891 #\r
1892 # Save temp tables to a TmpTableDict.\r
1893 #\r
1894 for Key in Wa.BuildDatabase._CACHE_:\r
1895 if Wa.BuildDatabase._CACHE_[Key]._RawData and Wa.BuildDatabase._CACHE_[Key]._RawData._Table and Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table:\r
1896 if TemporaryTablePattern.match(Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table):\r
1897 TmpTableDict[Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table] = Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Cur\r
1898 #\r
1899 #\r
1900 # All modules have been put in build tasks queue. Tell task scheduler\r
1901 # to exit if all tasks are completed\r
1902 #\r
1903 ExitFlag.set()\r
1904 BuildTask.WaitForComplete()\r
1905 self.CreateAsBuiltInf()\r
1906\r
1907 #\r
1908 # Check for build error, and raise exception if one\r
1909 # has been signaled.\r
1910 #\r
1911 if BuildTask.HasError():\r
1912 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1913\r
1914 # Create MAP file when Load Fix Address is enabled.\r
1915 if self.Target in ["", "all", "fds"]:\r
1916 for Arch in Wa.ArchList:\r
1917 #\r
1918 # Check whether the set fix address is above 4G for 32bit image.\r
1919 #\r
1920 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1921 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
1922 #\r
1923 # Get Module List\r
1924 #\r
1925 ModuleList = {}\r
1926 for Pa in Wa.AutoGenObjectList:\r
1927 for Ma in Pa.ModuleAutoGenList:\r
1928 if Ma == None:\r
1929 continue\r
1930 if not Ma.IsLibrary:\r
1931 ModuleList[Ma.Guid.upper()] = Ma\r
1932 #\r
1933 # Rebase module to the preferred memory address before GenFds\r
1934 #\r
1935 MapBuffer = StringIO('')\r
1936 if self.LoadFixAddress != 0:\r
1937 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
1938\r
1939 if self.Fdf:\r
1940 #\r
1941 # Generate FD image if there's a FDF file found\r
1942 #\r
1943 LaunchCommand(Wa.GenFdsCommand, os.getcwd())\r
1944\r
1945 #\r
1946 # Create MAP file for all platform FVs after GenFds.\r
1947 #\r
1948 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
1949 #\r
1950 # Save MAP buffer into MAP file.\r
1951 #\r
1952 self._SaveMapFile(MapBuffer, Wa)\r
1953\r
1954 ## Generate GuidedSectionTools.txt in the FV directories.\r
1955 #\r
1956 def CreateGuidedSectionToolsFile(self):\r
1957 for BuildTarget in self.BuildTargetList:\r
1958 for ToolChain in self.ToolChainList:\r
1959 Wa = WorkspaceAutoGen(\r
1960 self.WorkspaceDir,\r
1961 self.PlatformFile,\r
1962 BuildTarget,\r
1963 ToolChain,\r
1964 self.ArchList,\r
1965 self.BuildDatabase,\r
1966 self.TargetTxt,\r
1967 self.ToolDef,\r
1968 self.Fdf,\r
1969 self.FdList,\r
1970 self.FvList,\r
1971 self.CapList,\r
1972 self.SkuId,\r
1973 self.UniFlag\r
1974 )\r
1975 FvDir = Wa.FvDir\r
1976 if not os.path.exists(FvDir):\r
1977 continue\r
1978\r
1979 for Arch in self.ArchList:\r
1980 # Build up the list of supported architectures for this build\r
1981 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)\r
1982\r
1983 # Look through the tool definitions for GUIDed tools\r
1984 guidAttribs = []\r
1985 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():\r
1986 if attrib.upper().endswith('_GUID'):\r
1987 split = attrib.split('_')\r
1988 thisPrefix = '_'.join(split[0:3]) + '_'\r
1989 if thisPrefix == prefix:\r
1990 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]\r
1991 guid = guid.lower()\r
1992 toolName = split[3]\r
1993 path = '_'.join(split[0:4]) + '_PATH'\r
1994 path = self.ToolDef.ToolsDefTxtDictionary[path]\r
1995 path = self.GetFullPathOfTool(path)\r
1996 guidAttribs.append((guid, toolName, path))\r
1997\r
1998 # Write out GuidedSecTools.txt\r
1999 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')\r
2000 toolsFile = open(toolsFile, 'wt')\r
2001 for guidedSectionTool in guidAttribs:\r
2002 print >> toolsFile, ' '.join(guidedSectionTool)\r
2003 toolsFile.close()\r
2004\r
2005 ## Returns the full path of the tool.\r
2006 #\r
2007 def GetFullPathOfTool (self, tool):\r
2008 if os.path.exists(tool):\r
2009 return os.path.realpath(tool)\r
2010 else:\r
2011 # We need to search for the tool using the\r
2012 # PATH environment variable.\r
2013 for dirInPath in os.environ['PATH'].split(os.pathsep):\r
2014 foundPath = os.path.join(dirInPath, tool)\r
2015 if os.path.exists(foundPath):\r
2016 return os.path.realpath(foundPath)\r
2017\r
2018 # If the tool was not found in the path then we just return\r
2019 # the input tool.\r
2020 return tool\r
2021\r
2022 ## Launch the module or platform build\r
2023 #\r
2024 def Launch(self):\r
2025 if not self.ModuleFile:\r
2026 if not self.SpawnMode or self.Target not in ["", "all"]:\r
2027 self.SpawnMode = False\r
2028 self._BuildPlatform()\r
2029 else:\r
2030 self._MultiThreadBuildPlatform()\r
2031 self.CreateGuidedSectionToolsFile()\r
2032 else:\r
2033 self.SpawnMode = False\r
2034 self._BuildModule()\r
2035\r
2036 if self.Target == 'cleanall':\r
2037 self.Db.Close()\r
2038 RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)\r
2039\r
2040 def CreateAsBuiltInf(self):\r
2041 for Module in self.BuildModules:\r
2042 Module.CreateAsBuiltInf()\r
2043 self.BuildModules = []\r
2044 ## Do some clean-up works when error occurred\r
2045 def Relinquish(self):\r
2046 OldLogLevel = EdkLogger.GetLevel()\r
2047 EdkLogger.SetLevel(EdkLogger.ERROR)\r
2048 #self.DumpBuildData()\r
2049 Utils.Progressor.Abort()\r
2050 if self.SpawnMode == True:\r
2051 BuildTask.Abort()\r
2052 EdkLogger.SetLevel(OldLogLevel)\r
2053\r
2054 def DumpBuildData(self):\r
2055 CacheDirectory = os.path.dirname(GlobalData.gDatabasePath)\r
2056 Utils.CreateDirectory(CacheDirectory)\r
2057 Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))\r
2058 Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))\r
2059\r
2060 def RestoreBuildData(self):\r
2061 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gFileTimeStampCache")\r
2062 if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):\r
2063 Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)\r
2064 if Utils.gFileTimeStampCache == None:\r
2065 Utils.gFileTimeStampCache = {}\r
2066\r
2067 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gDependencyDatabase")\r
2068 if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):\r
2069 Utils.gDependencyDatabase = Utils.DataRestore(FilePath)\r
2070 if Utils.gDependencyDatabase == None:\r
2071 Utils.gDependencyDatabase = {}\r
2072\r
2073def ParseDefines(DefineList=[]):\r
2074 DefineDict = {}\r
2075 if DefineList != None:\r
2076 for Define in DefineList:\r
2077 DefineTokenList = Define.split("=", 1)\r
2078 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):\r
2079 EdkLogger.error('build', FORMAT_INVALID,\r
2080 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",\r
2081 ExtraData=DefineTokenList[0])\r
2082\r
2083 if len(DefineTokenList) == 1:\r
2084 DefineDict[DefineTokenList[0]] = "TRUE"\r
2085 else:\r
2086 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()\r
2087 return DefineDict\r
2088\r
2089gParamCheck = []\r
2090def SingleCheckCallback(option, opt_str, value, parser):\r
2091 if option not in gParamCheck:\r
2092 setattr(parser.values, option.dest, value)\r
2093 gParamCheck.append(option)\r
2094 else:\r
2095 parser.error("Option %s only allows one instance in command line!" % option)\r
2096\r
2097## Parse command line options\r
2098#\r
2099# Using standard Python module optparse to parse command line option of this tool.\r
2100#\r
2101# @retval Opt A optparse.Values object containing the parsed options\r
2102# @retval Args Target of build command\r
2103#\r
2104def MyOptionParser():\r
2105 Parser = OptionParser(description=__copyright__, version=__version__, prog="build.exe", usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")\r
2106 Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32', 'X64', 'IPF', 'EBC', 'ARM', 'AARCH64'], dest="TargetArch",\r
2107 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
2108 Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,\r
2109 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")\r
2110 Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,\r
2111 help="Build the module specified by the INF file name argument.")\r
2112 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",\r
2113 action="append")\r
2114 Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",\r
2115 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")\r
2116 Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,\r
2117 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")\r
2118\r
2119 Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,\r
2120 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
2121\r
2122 Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,\r
2123 help="The name of the FDF file to use, which overrides the setting in the DSC file.")\r
2124 Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],\r
2125 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")\r
2126 Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],\r
2127 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")\r
2128 Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],\r
2129 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")\r
2130 Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")\r
2131 Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")\r
2132\r
2133 Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.")\r
2134\r
2135 Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")\r
2136 Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")\r
2137\r
2138 Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",\r
2139 help="Make use of silent mode of (n)make.")\r
2140 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
2141 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\\r
2142 "including library instances selected, final dependency expression, "\\r
2143 "and warning messages, etc.")\r
2144 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
2145 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
2146\r
2147 Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")\r
2148 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
2149 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
2150 "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
2151 Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",\r
2152 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
2153 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\\r
2154 "will override the setting in [BuildOptions] section of platform DSC.")\r
2155 Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism")\r
2156 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")\r
2157 Parser.add_option("--check-usage", action="store_true", dest="CheckUsage", default=False, help="Check usage content of entries listed in INF file.")\r
2158 Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")\r
2159 Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")\r
2160 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
2161\r
2162 (Opt, Args) = Parser.parse_args()\r
2163 return (Opt, Args)\r
2164\r
2165## Tool entrance method\r
2166#\r
2167# This method mainly dispatch specific methods per the command line options.\r
2168# If no error found, return zero value so the caller of this tool can know\r
2169# if it's executed successfully or not.\r
2170#\r
2171# @retval 0 Tool was successful\r
2172# @retval 1 Tool failed\r
2173#\r
2174def Main():\r
2175 StartTime = time.time()\r
2176\r
2177 # Initialize log system\r
2178 EdkLogger.Initialize()\r
2179 GlobalData.gCommand = sys.argv[1:]\r
2180 #\r
2181 # Parse the options and args\r
2182 #\r
2183 (Option, Target) = MyOptionParser()\r
2184 GlobalData.gOptions = Option\r
2185 GlobalData.gCaseInsensitive = Option.CaseInsensitive\r
2186\r
2187 # Set log level\r
2188 if Option.verbose != None:\r
2189 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
2190 elif Option.quiet != None:\r
2191 EdkLogger.SetLevel(EdkLogger.QUIET)\r
2192 elif Option.debug != None:\r
2193 EdkLogger.SetLevel(Option.debug + 1)\r
2194 else:\r
2195 EdkLogger.SetLevel(EdkLogger.INFO)\r
2196\r
2197 if Option.LogFile != None:\r
2198 EdkLogger.SetLogFile(Option.LogFile)\r
2199\r
2200 if Option.WarningAsError == True:\r
2201 EdkLogger.SetWarningAsError()\r
2202\r
2203 if platform.platform().find("Windows") >= 0:\r
2204 GlobalData.gIsWindows = True\r
2205 else:\r
2206 GlobalData.gIsWindows = False\r
2207\r
2208 EdkLogger.quiet("Build environment: %s" % platform.platform())\r
2209 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));\r
2210 ReturnCode = 0\r
2211 MyBuild = None\r
2212 BuildError = True\r
2213 try:\r
2214 if len(Target) == 0:\r
2215 Target = "all"\r
2216 elif len(Target) >= 2:\r
2217 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",\r
2218 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))\r
2219 else:\r
2220 Target = Target[0].lower()\r
2221\r
2222 if Target not in gSupportedTarget:\r
2223 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,\r
2224 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))\r
2225\r
2226 #\r
2227 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH\r
2228 #\r
2229 CheckEnvVariable()\r
2230 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))\r
2231\r
2232 Workspace = os.getenv("WORKSPACE")\r
2233 #\r
2234 # Get files real name in workspace dir\r
2235 #\r
2236 GlobalData.gAllFiles = Utils.DirCache(Workspace)\r
2237\r
2238 WorkingDirectory = os.getcwd()\r
2239 if not Option.ModuleFile:\r
2240 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))\r
2241 FileNum = len(FileList)\r
2242 if FileNum >= 2:\r
2243 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),\r
2244 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")\r
2245 elif FileNum == 1:\r
2246 Option.ModuleFile = NormFile(FileList[0], Workspace)\r
2247\r
2248 if Option.ModuleFile:\r
2249 if os.path.isabs (Option.ModuleFile):\r
2250 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:\r
2251 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)\r
2252 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)\r
2253 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)\r
2254 if ErrorCode != 0:\r
2255 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2256\r
2257 if Option.PlatformFile != None:\r
2258 if os.path.isabs (Option.PlatformFile):\r
2259 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:\r
2260 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)\r
2261 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)\r
2262\r
2263 if Option.FdfFile != None:\r
2264 if os.path.isabs (Option.FdfFile):\r
2265 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:\r
2266 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)\r
2267 Option.FdfFile = PathClass(Option.FdfFile, Workspace)\r
2268 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)\r
2269 if ErrorCode != 0:\r
2270 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2271\r
2272 if Option.Flag != None and Option.Flag not in ['-c', '-s']:\r
2273 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")\r
2274\r
2275 MyBuild = Build(Target, Workspace, Option)\r
2276 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)\r
2277 if not (MyBuild.LaunchPrebuildFlag and os.path.exists(MyBuild.PlatformBuildPath)):\r
2278 MyBuild.Launch()\r
2279 # Drop temp tables to avoid database locked.\r
2280 for TmpTableName in TmpTableDict:\r
2281 SqlCommand = """drop table IF EXISTS %s""" % TmpTableName\r
2282 TmpTableDict[TmpTableName].execute(SqlCommand)\r
2283 #MyBuild.DumpBuildData()\r
2284 #\r
2285 # All job done, no error found and no exception raised\r
2286 #\r
2287 BuildError = False\r
2288 except FatalError, X:\r
2289 if MyBuild != None:\r
2290 # for multi-thread build exits safely\r
2291 MyBuild.Relinquish()\r
2292 if Option != None and Option.debug != None:\r
2293 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2294 ReturnCode = X.args[0]\r
2295 except Warning, X:\r
2296 # error from Fdf parser\r
2297 if MyBuild != None:\r
2298 # for multi-thread build exits safely\r
2299 MyBuild.Relinquish()\r
2300 if Option != None and Option.debug != None:\r
2301 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2302 else:\r
2303 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)\r
2304 ReturnCode = FORMAT_INVALID\r
2305 except KeyboardInterrupt:\r
2306 ReturnCode = ABORT_ERROR\r
2307 if Option != None and Option.debug != None:\r
2308 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2309 except:\r
2310 if MyBuild != None:\r
2311 # for multi-thread build exits safely\r
2312 MyBuild.Relinquish()\r
2313\r
2314 # try to get the meta-file from the object causing exception\r
2315 Tb = sys.exc_info()[-1]\r
2316 MetaFile = GlobalData.gProcessingFile\r
2317 while Tb != None:\r
2318 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):\r
2319 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile\r
2320 Tb = Tb.tb_next\r
2321 EdkLogger.error(\r
2322 "\nbuild",\r
2323 CODE_ERROR,\r
2324 "Unknown fatal error when processing [%s]" % MetaFile,\r
2325 ExtraData="\n(Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!)\n",\r
2326 RaiseError=False\r
2327 )\r
2328 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2329 ReturnCode = CODE_ERROR\r
2330 finally:\r
2331 Utils.Progressor.Abort()\r
2332 Utils.ClearDuplicatedInf()\r
2333\r
2334 if ReturnCode == 0:\r
2335 try:\r
2336 MyBuild.LaunchPostbuild()\r
2337 Conclusion = "Done"\r
2338 except:\r
2339 Conclusion = "Failed"\r
2340 elif ReturnCode == ABORT_ERROR:\r
2341 Conclusion = "Aborted"\r
2342 else:\r
2343 Conclusion = "Failed"\r
2344 FinishTime = time.time()\r
2345 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))\r
2346 BuildDurationStr = ""\r
2347 if BuildDuration.tm_yday > 1:\r
2348 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)" % (BuildDuration.tm_yday - 1)\r
2349 else:\r
2350 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)\r
2351 if MyBuild != None:\r
2352 if not BuildError:\r
2353 MyBuild.BuildReport.GenerateReport(BuildDurationStr)\r
2354 MyBuild.Db.Close()\r
2355 EdkLogger.SetLevel(EdkLogger.QUIET)\r
2356 EdkLogger.quiet("\n- %s -" % Conclusion)\r
2357 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))\r
2358 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)\r
2359 return ReturnCode\r
2360\r
2361if __name__ == '__main__':\r
2362 r = Main()\r
2363 ## 0-127 is a safe return range, and 1 is a standard default error\r
2364 if r < 0 or r > 127: r = 1\r
2365 sys.exit(r)\r
2366\r