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