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