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