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