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