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