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