]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/build/build.py
BaseTools: Support long file path in windows for misc functions
[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
1222 AutoGenObject.DataPipe.DataContainer = {"FfsCommand":FfsCommand}\r
0e7e7a26 1223 AutoGenObject.DataPipe.DataContainer = {"CommandTarget": self.Target}\r
673d09a2
FB
1224 self.Progress.Start("Generating makefile and code")\r
1225 data_pipe_file = os.path.join(AutoGenObject.BuildDir, "GlobalVar_%s_%s.bin" % (str(AutoGenObject.Guid),AutoGenObject.Arch))\r
1226 AutoGenObject.DataPipe.dump(data_pipe_file)\r
0e7e7a26 1227 autogen_rt,errorcode = self.StartAutoGen(mqueue, AutoGenObject.DataPipe, self.SkipAutoGen, PcdMaList, GlobalData.gCacheIR)\r
673d09a2
FB
1228 self.Progress.Stop("done!")\r
1229 if not autogen_rt:\r
1230 self.AutoGenMgr.TerminateWorkers()\r
1231 self.AutoGenMgr.join(0.1)\r
1232 raise FatalError(errorcode)\r
52302d4d
LG
1233 AutoGenObject.CreateCodeFile(False)\r
1234 AutoGenObject.CreateMakeFile(False)\r
673d09a2
FB
1235 else:\r
1236 # always recreate top/platform makefile when clean, just in case of inconsistency\r
1237 AutoGenObject.CreateCodeFile(True)\r
1238 AutoGenObject.CreateMakeFile(True)\r
52302d4d
LG
1239\r
1240 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
1241 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
1242\r
1243 BuildCommand = AutoGenObject.BuildCommand\r
4231a819 1244 if BuildCommand is None or len(BuildCommand) == 0:\r
0d2711a6
LG
1245 EdkLogger.error("build", OPTION_MISSING,\r
1246 "No build command found for this module. "\r
4afd3d04 1247 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
0d2711a6
LG
1248 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
1249 ExtraData=str(AutoGenObject))\r
52302d4d 1250\r
03af2753
HC
1251 makefile = GenMake.BuildFile(AutoGenObject)._FILE_NAME_[GenMake.gMakeType]\r
1252\r
03af2753
HC
1253 # run\r
1254 if Target == 'run':\r
03af2753
HC
1255 return True\r
1256\r
1257 # build modules\r
1258 if BuildModule:\r
1259 BuildCommand = BuildCommand + [Target]\r
1260 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
a0a2cd1e 1261 self.CreateAsBuiltInf()\r
b8ac0b7f
BF
1262 if GlobalData.gBinCacheDest:\r
1263 self.UpdateBuildCache()\r
1264 self.BuildModules = []\r
03af2753
HC
1265 return True\r
1266\r
1267 # build library\r
1268 if Target == 'libraries':\r
1269 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1270 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']\r
1271 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1272 return True\r
1273\r
1274 # build module\r
1275 if Target == 'modules':\r
1276 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1277 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']\r
1278 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1279 for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
1280 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']\r
1281 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
a0a2cd1e 1282 self.CreateAsBuiltInf()\r
b8ac0b7f
BF
1283 if GlobalData.gBinCacheDest:\r
1284 self.UpdateBuildCache()\r
1285 self.BuildModules = []\r
03af2753
HC
1286 return True\r
1287\r
1288 # cleanlib\r
1289 if Target == 'cleanlib':\r
1290 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1291 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))\r
1292 if os.path.exists(LibMakefile):\r
1293 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
1294 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1295 return True\r
1296\r
1297 # clean\r
1298 if Target == 'clean':\r
1299 for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
1300 ModMakefile = os.path.normpath(os.path.join(Mod, makefile))\r
1301 if os.path.exists(ModMakefile):\r
1302 NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']\r
1303 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1304 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1305 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))\r
1306 if os.path.exists(LibMakefile):\r
1307 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
1308 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1309 return True\r
1310\r
1311 # cleanall\r
1312 if Target == 'cleanall':\r
1313 try:\r
1314 #os.rmdir(AutoGenObject.BuildDir)\r
1315 RemoveDirectory(AutoGenObject.BuildDir, True)\r
5b0671c1 1316 except WindowsError as X:\r
03af2753
HC
1317 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1318 return True\r
1319\r
1320 ## Build a module or platform\r
1321 #\r
1322 # Create autogen code and makefile for a module or platform, and the launch\r
1323 # "make" command to build it\r
1324 #\r
1325 # @param Target The target of build command\r
1326 # @param Platform The platform file\r
1327 # @param Module The module file\r
1328 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
1329 # @param ToolChain The name of toolchain to build\r
1330 # @param Arch The arch of the module/platform\r
1331 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
1332 # for dependent modules/Libraries\r
1333 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
1334 # for dependent modules/Libraries\r
1335 #\r
1336 def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):\r
4231a819 1337 if AutoGenObject is None:\r
03af2753
HC
1338 return False\r
1339\r
1340 # skip file generation for cleanxxx targets, run and fds target\r
1341 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1342 # for target which must generate AutoGen code and makefile\r
1343 if not self.SkipAutoGen or Target == 'genc':\r
1344 self.Progress.Start("Generating code")\r
1345 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
1346 self.Progress.Stop("done!")\r
1347 if Target == "genc":\r
1348 return True\r
1349\r
1350 if not self.SkipAutoGen or Target == 'genmake':\r
1351 self.Progress.Start("Generating makefile")\r
1352 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)\r
1353 #AutoGenObject.CreateAsBuiltInf()\r
1354 self.Progress.Stop("done!")\r
1355 if Target == "genmake":\r
1356 return True\r
1357 else:\r
1358 # always recreate top/platform makefile when clean, just in case of inconsistency\r
673d09a2
FB
1359 AutoGenObject.CreateCodeFile(True)\r
1360 AutoGenObject.CreateMakeFile(True)\r
03af2753
HC
1361\r
1362 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
1363 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
1364\r
1365 BuildCommand = AutoGenObject.BuildCommand\r
4231a819 1366 if BuildCommand is None or len(BuildCommand) == 0:\r
03af2753
HC
1367 EdkLogger.error("build", OPTION_MISSING,\r
1368 "No build command found for this module. "\r
1369 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
1370 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
1371 ExtraData=str(AutoGenObject))\r
1372\r
b0e23cf3
YL
1373 # build modules\r
1374 if BuildModule:\r
1375 if Target != 'fds':\r
1376 BuildCommand = BuildCommand + [Target]\r
1b8eca8b 1377 AutoGenObject.BuildTime = LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
b0e23cf3 1378 self.CreateAsBuiltInf()\r
b8ac0b7f
BF
1379 if GlobalData.gBinCacheDest:\r
1380 self.UpdateBuildCache()\r
1381 self.BuildModules = []\r
b0e23cf3
YL
1382 return True\r
1383\r
03af2753
HC
1384 # genfds\r
1385 if Target == 'fds':\r
370544d1
DL
1386 if GenFdsApi(AutoGenObject.GenFdsCommandDict, self.Db):\r
1387 EdkLogger.error("build", COMMAND_FAILURE)\r
03af2753
HC
1388 return True\r
1389\r
1390 # run\r
1391 if Target == 'run':\r
03af2753
HC
1392 return True\r
1393\r
03af2753
HC
1394 # build library\r
1395 if Target == 'libraries':\r
1396 pass\r
1397\r
1398 # not build modules\r
1399\r
1400\r
1401 # cleanall\r
52302d4d
LG
1402 if Target == 'cleanall':\r
1403 try:\r
1404 #os.rmdir(AutoGenObject.BuildDir)\r
1405 RemoveDirectory(AutoGenObject.BuildDir, True)\r
5b0671c1 1406 except WindowsError as X:\r
52302d4d
LG
1407 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1408 return True\r
1409\r
6780eef1 1410 ## Rebase module image and Get function address for the input module list.\r
52302d4d
LG
1411 #\r
1412 def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):\r
1413 if ModeIsSmm:\r
1414 AddrIsOffset = False\r
98120f5f 1415 for InfFile in ModuleList:\r
da92f276
LG
1416 sys.stdout.write (".")\r
1417 sys.stdout.flush()\r
52302d4d
LG
1418 ModuleInfo = ModuleList[InfFile]\r
1419 ModuleName = ModuleInfo.BaseName\r
f3decdc3
LG
1420 ModuleOutputImage = ModuleInfo.Image.FileName\r
1421 ModuleDebugImage = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')\r
52302d4d
LG
1422 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1423 if not ModeIsSmm:\r
1424 BaseAddress = BaseAddress - ModuleInfo.Image.Size\r
1425 #\r
1426 # Update Image to new BaseAddress by GenFw tool\r
1427 #\r
f3decdc3 1428 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
47fea6af 1429 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
52302d4d
LG
1430 else:\r
1431 #\r
1432 # Set new address to the section header only for SMM driver.\r
1433 #\r
f3decdc3 1434 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
47fea6af 1435 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
52302d4d 1436 #\r
fb0b35e0 1437 # Collect function address from Map file\r
52302d4d 1438 #\r
f3decdc3 1439 ImageMapTable = ModuleOutputImage.replace('.efi', '.map')\r
52302d4d
LG
1440 FunctionList = []\r
1441 if os.path.exists(ImageMapTable):\r
1442 OrigImageBaseAddress = 0\r
47fea6af 1443 ImageMap = open(ImageMapTable, 'r')\r
52302d4d
LG
1444 for LinStr in ImageMap:\r
1445 if len (LinStr.strip()) == 0:\r
1446 continue\r
1447 #\r
1448 # Get the preferred address set on link time.\r
1449 #\r
1450 if LinStr.find ('Preferred load address is') != -1:\r
1451 StrList = LinStr.split()\r
1452 OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)\r
1453\r
1454 StrList = LinStr.split()\r
1455 if len (StrList) > 4:\r
47fea6af 1456 if StrList[3] == 'f' or StrList[3] == 'F':\r
52302d4d
LG
1457 Name = StrList[1]\r
1458 RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress\r
1459 FunctionList.append ((Name, RelativeAddress))\r
39879ef2 1460\r
52302d4d
LG
1461 ImageMap.close()\r
1462 #\r
1463 # Add general information.\r
1464 #\r
1465 if ModeIsSmm:\r
d943b0c3 1466 MapBuffer.append('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
52302d4d 1467 elif AddrIsOffset:\r
d943b0c3 1468 MapBuffer.append('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))\r
52302d4d 1469 else:\r
d943b0c3 1470 MapBuffer.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
52302d4d
LG
1471 #\r
1472 # Add guid and general seciton section.\r
1473 #\r
1474 TextSectionAddress = 0\r
1475 DataSectionAddress = 0\r
1476 for SectionHeader in ModuleInfo.Image.SectionHeaderList:\r
1477 if SectionHeader[0] == '.text':\r
1478 TextSectionAddress = SectionHeader[1]\r
1479 elif SectionHeader[0] in ['.data', '.sdata']:\r
1480 DataSectionAddress = SectionHeader[1]\r
1481 if AddrIsOffset:\r
d943b0c3 1482 MapBuffer.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))\r
52302d4d 1483 else:\r
d943b0c3 1484 MapBuffer.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))\r
f3decdc3
LG
1485 #\r
1486 # Add debug image full path.\r
1487 #\r
d943b0c3 1488 MapBuffer.append('(IMAGE=%s)\n\n' % (ModuleDebugImage))\r
52302d4d 1489 #\r
fb0b35e0 1490 # Add function address\r
52302d4d
LG
1491 #\r
1492 for Function in FunctionList:\r
1493 if AddrIsOffset:\r
d943b0c3 1494 MapBuffer.append(' -0x%010X %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))\r
52302d4d 1495 else:\r
d943b0c3 1496 MapBuffer.append(' 0x%010X %s\n' % (BaseAddress + Function[1], Function[0]))\r
52302d4d
LG
1497 ImageMap.close()\r
1498\r
1499 #\r
1500 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1501 #\r
1502 if ModeIsSmm:\r
1503 BaseAddress = BaseAddress + ModuleInfo.Image.Size\r
1504\r
1505 ## Collect MAP information of all FVs\r
1506 #\r
636f2be6 1507 def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):\r
0d2711a6 1508 if self.Fdf:\r
52302d4d 1509 # First get the XIP base address for FV map file.\r
636f2be6 1510 GuidPattern = re.compile("[-a-fA-F0-9]+")\r
eebc135f 1511 GuidName = re.compile(r"\(GUID=[-a-fA-F0-9]+")\r
9eb87141 1512 for FvName in Wa.FdfProfile.FvDict:\r
52302d4d
LG
1513 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')\r
1514 if not os.path.exists(FvMapBuffer):\r
1515 continue\r
1be2ed90 1516 FvMap = open(FvMapBuffer, 'r')\r
52302d4d
LG
1517 #skip FV size information\r
1518 FvMap.readline()\r
1519 FvMap.readline()\r
1520 FvMap.readline()\r
1521 FvMap.readline()\r
636f2be6
LG
1522 for Line in FvMap:\r
1523 MatchGuid = GuidPattern.match(Line)\r
4231a819 1524 if MatchGuid is not None:\r
636f2be6
LG
1525 #\r
1526 # Replace GUID with module name\r
1527 #\r
1528 GuidString = MatchGuid.group()\r
1529 if GuidString.upper() in ModuleList:\r
1530 Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)\r
d943b0c3 1531 MapBuffer.append(Line)\r
f3decdc3
LG
1532 #\r
1533 # Add the debug image full path.\r
1534 #\r
1535 MatchGuid = GuidName.match(Line)\r
4231a819 1536 if MatchGuid is not None:\r
f3decdc3
LG
1537 GuidString = MatchGuid.group().split("=")[1]\r
1538 if GuidString.upper() in ModuleList:\r
d943b0c3 1539 MapBuffer.append('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))\r
f3decdc3 1540\r
52302d4d
LG
1541 FvMap.close()\r
1542\r
1543 ## Collect MAP information of all modules\r
1544 #\r
1545 def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):\r
da92f276
LG
1546 sys.stdout.write ("Generate Load Module At Fix Address Map")\r
1547 sys.stdout.flush()\r
52302d4d
LG
1548 PatchEfiImageList = []\r
1549 PeiModuleList = {}\r
1550 BtModuleList = {}\r
1551 RtModuleList = {}\r
1552 SmmModuleList = {}\r
1553 PeiSize = 0\r
1554 BtSize = 0\r
1555 RtSize = 0\r
1556 # reserve 4K size in SMRAM to make SMM module address not from 0.\r
1557 SmmSize = 0x1000\r
636f2be6
LG
1558 for ModuleGuid in ModuleList:\r
1559 Module = ModuleList[ModuleGuid]\r
52302d4d 1560 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)\r
4afd3d04 1561\r
52302d4d
LG
1562 OutputImageFile = ''\r
1563 for ResultFile in Module.CodaTargetList:\r
1564 if str(ResultFile.Target).endswith('.efi'):\r
1565 #\r
1566 # module list for PEI, DXE, RUNTIME and SMM\r
1567 #\r
1568 OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')\r
1569 ImageClass = PeImageClass (OutputImageFile)\r
1570 if not ImageClass.IsValid:\r
1571 EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)\r
f3decdc3 1572 ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)\r
0c60e60b 1573 if Module.ModuleType in [SUP_MODULE_PEI_CORE, SUP_MODULE_PEIM, EDK_COMPONENT_TYPE_COMBINED_PEIM_DRIVER, EDK_COMPONENT_TYPE_PIC_PEIM, EDK_COMPONENT_TYPE_RELOCATABLE_PEIM, SUP_MODULE_DXE_CORE]:\r
52302d4d
LG
1574 PeiModuleList[Module.MetaFile] = ImageInfo\r
1575 PeiSize += ImageInfo.Image.Size\r
0c60e60b 1576 elif Module.ModuleType in [EDK_COMPONENT_TYPE_BS_DRIVER, SUP_MODULE_DXE_DRIVER, SUP_MODULE_UEFI_DRIVER]:\r
52302d4d
LG
1577 BtModuleList[Module.MetaFile] = ImageInfo\r
1578 BtSize += ImageInfo.Image.Size\r
0c60e60b 1579 elif Module.ModuleType in [SUP_MODULE_DXE_RUNTIME_DRIVER, EDK_COMPONENT_TYPE_RT_DRIVER, SUP_MODULE_DXE_SAL_DRIVER, EDK_COMPONENT_TYPE_SAL_RT_DRIVER]:\r
52302d4d 1580 RtModuleList[Module.MetaFile] = ImageInfo\r
52302d4d 1581 RtSize += ImageInfo.Image.Size\r
8bb63e37 1582 elif Module.ModuleType in [SUP_MODULE_SMM_CORE, SUP_MODULE_DXE_SMM_DRIVER, SUP_MODULE_MM_STANDALONE, SUP_MODULE_MM_CORE_STANDALONE]:\r
52302d4d
LG
1583 SmmModuleList[Module.MetaFile] = ImageInfo\r
1584 SmmSize += ImageInfo.Image.Size\r
8bb63e37 1585 if Module.ModuleType == SUP_MODULE_DXE_SMM_DRIVER:\r
888d7f19 1586 PiSpecVersion = Module.Module.Specification.get('PI_SPECIFICATION_VERSION', '0x00000000')\r
52302d4d 1587 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.\r
da92f276 1588 if int(PiSpecVersion, 16) < 0x0001000A:\r
52302d4d
LG
1589 BtModuleList[Module.MetaFile] = ImageInfo\r
1590 BtSize += ImageInfo.Image.Size\r
1591 break\r
1592 #\r
1593 # EFI image is final target.\r
1594 # Check EFI image contains patchable FixAddress related PCDs.\r
1595 #\r
1596 if OutputImageFile != '':\r
1597 ModuleIsPatch = False\r
1598 for Pcd in Module.ModulePcdList:\r
eece4292 1599 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:\r
52302d4d
LG
1600 ModuleIsPatch = True\r
1601 break\r
1602 if not ModuleIsPatch:\r
1603 for Pcd in Module.LibraryPcdList:\r
eece4292 1604 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:\r
52302d4d
LG
1605 ModuleIsPatch = True\r
1606 break\r
4afd3d04 1607\r
52302d4d
LG
1608 if not ModuleIsPatch:\r
1609 continue\r
1610 #\r
1611 # Module includes the patchable load fix address PCDs.\r
4afd3d04 1612 # It will be fixed up later.\r
52302d4d
LG
1613 #\r
1614 PatchEfiImageList.append (OutputImageFile)\r
4afd3d04 1615\r
52302d4d
LG
1616 #\r
1617 # Get Top Memory address\r
1618 #\r
1619 ReservedRuntimeMemorySize = 0\r
1620 TopMemoryAddress = 0\r
1621 if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:\r
1622 TopMemoryAddress = 0\r
1623 else:\r
1624 TopMemoryAddress = self.LoadFixAddress\r
1625 if TopMemoryAddress < RtSize + BtSize + PeiSize:\r
1626 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")\r
52302d4d
LG
1627\r
1628 #\r
1629 # Patch FixAddress related PCDs into EFI image\r
1630 #\r
4afd3d04 1631 for EfiImage in PatchEfiImageList:\r
52302d4d
LG
1632 EfiImageMap = EfiImage.replace('.efi', '.map')\r
1633 if not os.path.exists(EfiImageMap):\r
1634 continue\r
1635 #\r
1636 # Get PCD offset in EFI image by GenPatchPcdTable function\r
1637 #\r
4afd3d04 1638 PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)\r
52302d4d
LG
1639 #\r
1640 # Patch real PCD value by PatchPcdValue tool\r
1641 #\r
1642 for PcdInfo in PcdTable:\r
1643 ReturnValue = 0\r
1644 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:\r
b3e94a06 1645 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize // 0x1000))\r
52302d4d 1646 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:\r
b3e94a06 1647 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize // 0x1000))\r
52302d4d 1648 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:\r
b3e94a06 1649 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize // 0x1000))\r
52302d4d 1650 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:\r
b3e94a06 1651 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize // 0x1000))\r
52302d4d
LG
1652 if ReturnValue != 0:\r
1653 EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)\r
4afd3d04 1654\r
d943b0c3
FB
1655 MapBuffer.append('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize // 0x1000))\r
1656 MapBuffer.append('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize // 0x1000))\r
1657 MapBuffer.append('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize // 0x1000))\r
52302d4d 1658 if len (SmmModuleList) > 0:\r
d943b0c3 1659 MapBuffer.append('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize // 0x1000))\r
4afd3d04
LG
1660\r
1661 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize\r
52302d4d 1662 BtBaseAddr = TopMemoryAddress - RtSize\r
4afd3d04 1663 RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize\r
52302d4d
LG
1664\r
1665 self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)\r
1666 self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)\r
1667 self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)\r
47fea6af 1668 self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset=False, ModeIsSmm=True)\r
d943b0c3 1669 MapBuffer.append('\n\n')\r
da92f276
LG
1670 sys.stdout.write ("\n")\r
1671 sys.stdout.flush()\r
4afd3d04 1672\r
52302d4d
LG
1673 ## Save platform Map file\r
1674 #\r
1675 def _SaveMapFile (self, MapBuffer, Wa):\r
1676 #\r
1677 # Map file path is got.\r
1678 #\r
1679 MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')\r
1680 #\r
1681 # Save address map into MAP file.\r
1682 #\r
d943b0c3 1683 SaveFileOnChange(MapFilePath, ''.join(MapBuffer), False)\r
da92f276 1684 if self.LoadFixAddress != 0:\r
47fea6af 1685 sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath))\r
da92f276 1686 sys.stdout.flush()\r
52302d4d
LG
1687\r
1688 ## Build active platform for different build targets and different tool chains\r
1689 #\r
1690 def _BuildPlatform(self):\r
f0dc69e6 1691 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)\r
52302d4d 1692 for BuildTarget in self.BuildTargetList:\r
0d2711a6 1693 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
40b4e21d 1694 index = 0\r
52302d4d 1695 for ToolChain in self.ToolChainList:\r
0d2711a6
LG
1696 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
1697 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
40b4e21d
YZ
1698 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1699 index += 1\r
52302d4d
LG
1700 Wa = WorkspaceAutoGen(\r
1701 self.WorkspaceDir,\r
0d2711a6 1702 self.PlatformFile,\r
52302d4d
LG
1703 BuildTarget,\r
1704 ToolChain,\r
1705 self.ArchList,\r
1706 self.BuildDatabase,\r
1707 self.TargetTxt,\r
1708 self.ToolDef,\r
1709 self.Fdf,\r
1710 self.FdList,\r
1711 self.FvList,\r
4234283c 1712 self.CapList,\r
f3decdc3 1713 self.SkuId,\r
9508d0fa
LG
1714 self.UniFlag,\r
1715 self.Progress\r
52302d4d 1716 )\r
0d2711a6
LG
1717 self.Fdf = Wa.FdfFile\r
1718 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
52302d4d
LG
1719 self.BuildReport.AddPlatformReport(Wa)\r
1720 self.Progress.Stop("done!")\r
37de70b7
YZ
1721\r
1722 # Add ffs build to makefile\r
1723 CmdListDict = {}\r
1724 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
b1e27d17 1725 CmdListDict = self._GenFfsCmd(Wa.ArchList)\r
37de70b7 1726\r
03af2753 1727 for Arch in Wa.ArchList:\r
e8449e1d 1728 PcdMaList = []\r
03af2753
HC
1729 GlobalData.gGlobalDefines['ARCH'] = Arch\r
1730 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
a0a2cd1e
FB
1731 for Module in Pa.Platform.Modules:\r
1732 # Get ModuleAutoGen object to generate C code file and makefile\r
e8449e1d 1733 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)\r
4231a819 1734 if Ma is None:\r
a0a2cd1e 1735 continue\r
e8449e1d
FB
1736 if Ma.PcdIsDriver:\r
1737 Ma.PlatformInfo = Pa\r
673d09a2 1738 Ma.Workspace = Wa\r
e8449e1d 1739 PcdMaList.append(Ma)\r
a0a2cd1e 1740 self.BuildModules.append(Ma)\r
673d09a2 1741 self._BuildPa(self.Target, Pa, FfsCommand=CmdListDict,PcdMaList=PcdMaList)\r
4afd3d04 1742\r
52302d4d 1743 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1744 if self.Target in ["", "all", "fds"]:\r
0d2711a6
LG
1745 for Arch in Wa.ArchList:\r
1746 GlobalData.gGlobalDefines['ARCH'] = Arch\r
52302d4d
LG
1747 #\r
1748 # Check whether the set fix address is above 4G for 32bit image.\r
1749 #\r
1750 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
0d2711a6 1751 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS can't be set to larger than or equal to 4G for the platform with IA32 or ARM arch modules")\r
52302d4d
LG
1752 #\r
1753 # Get Module List\r
1754 #\r
636f2be6 1755 ModuleList = {}\r
52302d4d
LG
1756 for Pa in Wa.AutoGenObjectList:\r
1757 for Ma in Pa.ModuleAutoGenList:\r
4231a819 1758 if Ma is None:\r
52302d4d
LG
1759 continue\r
1760 if not Ma.IsLibrary:\r
636f2be6 1761 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d 1762\r
d943b0c3 1763 MapBuffer = []\r
636f2be6
LG
1764 if self.LoadFixAddress != 0:\r
1765 #\r
1766 # Rebase module to the preferred memory address before GenFds\r
1767 #\r
1768 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
0d2711a6 1769 if self.Fdf:\r
b0e23cf3
YL
1770 #\r
1771 # create FDS again for the updated EFI image\r
1772 #\r
1773 self._Build("fds", Wa)\r
52302d4d
LG
1774 #\r
1775 # Create MAP file for all platform FVs after GenFds.\r
1776 #\r
636f2be6 1777 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1778 #\r
1779 # Save MAP buffer into MAP file.\r
1780 #\r
1781 self._SaveMapFile (MapBuffer, Wa)\r
1782\r
1783 ## Build active module for different build targets, different tool chains and different archs\r
1784 #\r
1785 def _BuildModule(self):\r
1786 for BuildTarget in self.BuildTargetList:\r
0d2711a6 1787 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
40b4e21d 1788 index = 0\r
52302d4d 1789 for ToolChain in self.ToolChainList:\r
1b8eca8b 1790 WorkspaceAutoGenTime = time.time()\r
0d2711a6 1791 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
4afd3d04 1792 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
40b4e21d
YZ
1793 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1794 index += 1\r
52302d4d
LG
1795 #\r
1796 # module build needs platform build information, so get platform\r
1797 # AutoGen first\r
1798 #\r
1799 Wa = WorkspaceAutoGen(\r
1800 self.WorkspaceDir,\r
0d2711a6 1801 self.PlatformFile,\r
52302d4d
LG
1802 BuildTarget,\r
1803 ToolChain,\r
1804 self.ArchList,\r
1805 self.BuildDatabase,\r
1806 self.TargetTxt,\r
1807 self.ToolDef,\r
1808 self.Fdf,\r
1809 self.FdList,\r
1810 self.FvList,\r
4234283c 1811 self.CapList,\r
f3decdc3 1812 self.SkuId,\r
9508d0fa
LG
1813 self.UniFlag,\r
1814 self.Progress,\r
1815 self.ModuleFile\r
52302d4d 1816 )\r
0d2711a6
LG
1817 self.Fdf = Wa.FdfFile\r
1818 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
52302d4d 1819 Wa.CreateMakeFile(False)\r
37de70b7
YZ
1820 # Add ffs build to makefile\r
1821 CmdListDict = None\r
1822 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
b1e27d17 1823 CmdListDict = self._GenFfsCmd(Wa.ArchList)\r
0e7e7a26
SS
1824\r
1825 # Add Platform and Package level hash in share_data for module hash calculation later\r
1826 if GlobalData.gBinCacheSource or GlobalData.gBinCacheDest:\r
1827 GlobalData.gCacheIR[('PlatformHash')] = GlobalData.gPlatformHash\r
1828 for PkgName in GlobalData.gPackageHash.keys():\r
1829 GlobalData.gCacheIR[(PkgName, 'PackageHash')] = GlobalData.gPackageHash[PkgName]\r
1830 GlobalData.file_lock = mp.Lock()\r
94459080 1831 GlobalData.cache_lock = mp.Lock()\r
0e7e7a26
SS
1832 GlobalData.FfsCmd = CmdListDict\r
1833\r
52302d4d
LG
1834 self.Progress.Stop("done!")\r
1835 MaList = []\r
1b8eca8b
YZ
1836 ExitFlag = threading.Event()\r
1837 ExitFlag.clear()\r
1838 self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))\r
0d2711a6 1839 for Arch in Wa.ArchList:\r
1b8eca8b 1840 AutoGenStart = time.time()\r
0d2711a6 1841 GlobalData.gGlobalDefines['ARCH'] = Arch\r
16bad1fb 1842 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
0e7e7a26
SS
1843 GlobalData.libConstPcd = Pa.DataPipe.Get("LibConstPcd")\r
1844 GlobalData.Refes = Pa.DataPipe.Get("REFS")\r
16bad1fb 1845 for Module in Pa.Platform.Modules:\r
fbe53845 1846 if self.ModuleFile.Dir == Module.Dir and self.ModuleFile.Name == Module.Name:\r
e8449e1d 1847 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)\r
db4d47fd
CR
1848 if Ma is None:\r
1849 continue\r
19bf8314 1850 MaList.append(Ma)\r
0e7e7a26
SS
1851\r
1852 if GlobalData.gBinCacheSource and self.Target in [None, "", "all"]:\r
1853 Ma.GenModuleFilesHash(GlobalData.gCacheIR)\r
1854 Ma.GenPreMakefileHash(GlobalData.gCacheIR)\r
1855 if Ma.CanSkipbyPreMakefileCache(GlobalData.gCacheIR):\r
1856 self.HashSkipModules.append(Ma)\r
1857 EdkLogger.quiet("cache hit: %s[%s]" % (Ma.MetaFile.Path, Ma.Arch))\r
1858 continue\r
1859\r
119d8c42
YZ
1860 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'\r
1861 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1862 # for target which must generate AutoGen code and makefile\r
1863 if not self.SkipAutoGen or self.Target == 'genc':\r
cd498216 1864 self.Progress.Start("Generating code")\r
119d8c42 1865 Ma.CreateCodeFile(True)\r
cd498216
YZ
1866 self.Progress.Stop("done!")\r
1867 if self.Target == "genc":\r
1868 return True\r
119d8c42 1869 if not self.SkipAutoGen or self.Target == 'genmake':\r
cd498216 1870 self.Progress.Start("Generating makefile")\r
37de70b7
YZ
1871 if CmdListDict and self.Fdf and (Module.File, Arch) in CmdListDict:\r
1872 Ma.CreateMakeFile(True, CmdListDict[Module.File, Arch])\r
1873 del CmdListDict[Module.File, Arch]\r
1874 else:\r
1875 Ma.CreateMakeFile(True)\r
cd498216
YZ
1876 self.Progress.Stop("done!")\r
1877 if self.Target == "genmake":\r
1878 return True\r
0e7e7a26
SS
1879\r
1880 if GlobalData.gBinCacheSource and self.Target in [None, "", "all"]:\r
1881 Ma.GenMakeHeaderFilesHash(GlobalData.gCacheIR)\r
1882 Ma.GenMakeHash(GlobalData.gCacheIR)\r
1883 if Ma.CanSkipbyMakeCache(GlobalData.gCacheIR):\r
1884 self.HashSkipModules.append(Ma)\r
1885 EdkLogger.quiet("cache hit: %s[%s]" % (Ma.MetaFile.Path, Ma.Arch))\r
1886 continue\r
1887 else:\r
1888 EdkLogger.quiet("cache miss: %s[%s]" % (Ma.MetaFile.Path, Ma.Arch))\r
1889 Ma.PrintFirstMakeCacheMissFile(GlobalData.gCacheIR)\r
1890\r
16bad1fb 1891 self.BuildModules.append(Ma)\r
48b0bf64 1892 # Initialize all modules in tracking to 'FAIL'\r
c340c5bd 1893 GlobalData.gModuleBuildTracking[Ma] = 'FAIL'\r
1b8eca8b
YZ
1894 self.AutoGenTime += int(round((time.time() - AutoGenStart)))\r
1895 MakeStart = time.time()\r
1896 for Ma in self.BuildModules:\r
1897 if not Ma.IsBinaryModule:\r
673d09a2 1898 Bt = BuildTask.New(ModuleMakeUnit(Ma, Pa.BuildCommand,self.Target))\r
1b8eca8b
YZ
1899 # Break build if any build thread has error\r
1900 if BuildTask.HasError():\r
1901 # we need a full version of makefile for platform\r
1902 ExitFlag.set()\r
1903 BuildTask.WaitForComplete()\r
0eccea3f 1904 self.invalidateHash()\r
1b8eca8b
YZ
1905 Pa.CreateMakeFile(False)\r
1906 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1907 # Start task scheduler\r
1908 if not BuildTask.IsOnGoing():\r
1909 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
1910\r
1911 # in case there's an interruption. we need a full version of makefile for platform\r
1912 Pa.CreateMakeFile(False)\r
1913 if BuildTask.HasError():\r
0eccea3f 1914 self.invalidateHash()\r
1b8eca8b
YZ
1915 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1916 self.MakeTime += int(round((time.time() - MakeStart)))\r
1917\r
1918 MakeContiue = time.time()\r
1919 ExitFlag.set()\r
1920 BuildTask.WaitForComplete()\r
1921 self.CreateAsBuiltInf()\r
b8ac0b7f
BF
1922 if GlobalData.gBinCacheDest:\r
1923 self.UpdateBuildCache()\r
1924 self.BuildModules = []\r
1b8eca8b
YZ
1925 self.MakeTime += int(round((time.time() - MakeContiue)))\r
1926 if BuildTask.HasError():\r
0eccea3f 1927 self.invalidateHash()\r
1b8eca8b 1928 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
d5d56f1b
LG
1929\r
1930 self.BuildReport.AddPlatformReport(Wa, MaList)\r
52302d4d
LG
1931 if MaList == []:\r
1932 EdkLogger.error(\r
1933 'build',\r
1934 BUILD_ERROR,\r
1935 "Module for [%s] is not a component of active platform."\\r
1936 " Please make sure that the ARCH and inf file path are"\\r
47fea6af 1937 " given in the same as in [%s]" % \\r
0d2711a6 1938 (', '.join(Wa.ArchList), self.PlatformFile),\r
52302d4d
LG
1939 ExtraData=self.ModuleFile\r
1940 )\r
1941 # Create MAP file when Load Fix Address is enabled.\r
0d2711a6
LG
1942 if self.Target == "fds" and self.Fdf:\r
1943 for Arch in Wa.ArchList:\r
52302d4d
LG
1944 #\r
1945 # Check whether the set fix address is above 4G for 32bit image.\r
1946 #\r
1947 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1948 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
1949 #\r
1950 # Get Module List\r
1951 #\r
636f2be6 1952 ModuleList = {}\r
52302d4d
LG
1953 for Pa in Wa.AutoGenObjectList:\r
1954 for Ma in Pa.ModuleAutoGenList:\r
4231a819 1955 if Ma is None:\r
52302d4d
LG
1956 continue\r
1957 if not Ma.IsLibrary:\r
636f2be6 1958 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d 1959\r
d943b0c3 1960 MapBuffer = []\r
636f2be6
LG
1961 if self.LoadFixAddress != 0:\r
1962 #\r
1963 # Rebase module to the preferred memory address before GenFds\r
1964 #\r
1965 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
b0e23cf3
YL
1966 #\r
1967 # create FDS again for the updated EFI image\r
1968 #\r
1b8eca8b 1969 GenFdsStart = time.time()\r
b0e23cf3 1970 self._Build("fds", Wa)\r
1b8eca8b 1971 self.GenFdsTime += int(round((time.time() - GenFdsStart)))\r
52302d4d
LG
1972 #\r
1973 # Create MAP file for all platform FVs after GenFds.\r
1974 #\r
636f2be6 1975 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1976 #\r
1977 # Save MAP buffer into MAP file.\r
1978 #\r
1979 self._SaveMapFile (MapBuffer, Wa)\r
48b0bf64 1980 self.invalidateHash()\r
52302d4d 1981\r
b1e27d17 1982 def _GenFfsCmd(self,ArchList):\r
f7496d71 1983 # convert dictionary of Cmd:(Inf,Arch)\r
9eb87141
CJ
1984 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...\r
1985 CmdSetDict = defaultdict(set)\r
b1e27d17 1986 GenFfsDict = GenFds.GenFfsMakefile('', GlobalData.gFdfParser, self, ArchList, GlobalData)\r
37de70b7
YZ
1987 for Cmd in GenFfsDict:\r
1988 tmpInf, tmpArch = GenFfsDict[Cmd]\r
9eb87141
CJ
1989 CmdSetDict[tmpInf, tmpArch].add(Cmd)\r
1990 return CmdSetDict\r
37de70b7 1991\r
52302d4d
LG
1992 ## Build a platform in multi-thread mode\r
1993 #\r
1994 def _MultiThreadBuildPlatform(self):\r
f0dc69e6 1995 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)\r
52302d4d 1996 for BuildTarget in self.BuildTargetList:\r
0d2711a6 1997 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
40b4e21d 1998 index = 0\r
52302d4d 1999 for ToolChain in self.ToolChainList:\r
1b8eca8b 2000 WorkspaceAutoGenTime = time.time()\r
0d2711a6 2001 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
4afd3d04 2002 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
40b4e21d
YZ
2003 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
2004 index += 1\r
52302d4d
LG
2005 Wa = WorkspaceAutoGen(\r
2006 self.WorkspaceDir,\r
0d2711a6 2007 self.PlatformFile,\r
52302d4d
LG
2008 BuildTarget,\r
2009 ToolChain,\r
2010 self.ArchList,\r
2011 self.BuildDatabase,\r
2012 self.TargetTxt,\r
2013 self.ToolDef,\r
2014 self.Fdf,\r
2015 self.FdList,\r
2016 self.FvList,\r
4234283c 2017 self.CapList,\r
f3decdc3 2018 self.SkuId,\r
9508d0fa
LG
2019 self.UniFlag,\r
2020 self.Progress\r
52302d4d 2021 )\r
0d2711a6
LG
2022 self.Fdf = Wa.FdfFile\r
2023 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
52302d4d
LG
2024 self.BuildReport.AddPlatformReport(Wa)\r
2025 Wa.CreateMakeFile(False)\r
2026\r
37de70b7 2027 # Add ffs build to makefile\r
673d09a2 2028 CmdListDict = {}\r
37de70b7 2029 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
b1e27d17 2030 CmdListDict = self._GenFfsCmd(Wa.ArchList)\r
37de70b7 2031\r
0e7e7a26
SS
2032 # Add Platform and Package level hash in share_data for module hash calculation later\r
2033 if GlobalData.gBinCacheSource or GlobalData.gBinCacheDest:\r
2034 GlobalData.gCacheIR[('PlatformHash')] = GlobalData.gPlatformHash\r
2035 for PkgName in GlobalData.gPackageHash.keys():\r
2036 GlobalData.gCacheIR[(PkgName, 'PackageHash')] = GlobalData.gPackageHash[PkgName]\r
2037\r
52302d4d
LG
2038 # multi-thread exit flag\r
2039 ExitFlag = threading.Event()\r
2040 ExitFlag.clear()\r
1b8eca8b 2041 self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))\r
673d09a2 2042 self.BuildModules = []\r
0e7e7a26 2043 TotalModules = []\r
0d2711a6 2044 for Arch in Wa.ArchList:\r
e8449e1d 2045 PcdMaList = []\r
1b8eca8b 2046 AutoGenStart = time.time()\r
0d2711a6 2047 GlobalData.gGlobalDefines['ARCH'] = Arch\r
52302d4d 2048 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
4231a819 2049 if Pa is None:\r
52302d4d 2050 continue\r
a0a2cd1e
FB
2051 ModuleList = []\r
2052 for Inf in Pa.Platform.Modules:\r
2053 ModuleList.append(Inf)\r
2054 # Add the INF only list in FDF\r
4231a819 2055 if GlobalData.gFdfParser is not None:\r
a0a2cd1e
FB
2056 for InfName in GlobalData.gFdfParser.Profile.InfList:\r
2057 Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)\r
2058 if Inf in Pa.Platform.Modules:\r
2059 continue\r
2060 ModuleList.append(Inf)\r
673d09a2
FB
2061 Pa.DataPipe.DataContainer = {"FfsCommand":CmdListDict}\r
2062 Pa.DataPipe.DataContainer = {"Workspace_timestamp": Wa._SrcTimeStamp}\r
0e7e7a26 2063 Pa.DataPipe.DataContainer = {"CommandTarget": self.Target}\r
a0a2cd1e 2064 for Module in ModuleList:\r
52302d4d 2065 # Get ModuleAutoGen object to generate C code file and makefile\r
e8449e1d 2066 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)\r
f7496d71 2067\r
4231a819 2068 if Ma is None:\r
52302d4d 2069 continue\r
e8449e1d
FB
2070 if Ma.PcdIsDriver:\r
2071 Ma.PlatformInfo = Pa\r
673d09a2 2072 Ma.Workspace = Wa\r
e8449e1d 2073 PcdMaList.append(Ma)\r
0e7e7a26 2074 TotalModules.append(Ma)\r
48b0bf64 2075 # Initialize all modules in tracking to 'FAIL'\r
c340c5bd 2076 GlobalData.gModuleBuildTracking[Ma] = 'FAIL'\r
0e7e7a26 2077\r
673d09a2
FB
2078 mqueue = mp.Queue()\r
2079 for m in Pa.GetAllModuleInfo:\r
2080 mqueue.put(m)\r
2081 data_pipe_file = os.path.join(Pa.BuildDir, "GlobalVar_%s_%s.bin" % (str(Pa.Guid),Pa.Arch))\r
2082 Pa.DataPipe.dump(data_pipe_file)\r
0e7e7a26
SS
2083 autogen_rt, errorcode = self.StartAutoGen(mqueue, Pa.DataPipe, self.SkipAutoGen, PcdMaList, GlobalData.gCacheIR)\r
2084\r
2085 # Skip cache hit modules\r
2086 if GlobalData.gBinCacheSource:\r
2087 for Ma in TotalModules:\r
2088 if (Ma.MetaFile.Path, Ma.Arch) in GlobalData.gCacheIR and \\r
2089 GlobalData.gCacheIR[(Ma.MetaFile.Path, Ma.Arch)].PreMakeCacheHit:\r
2090 self.HashSkipModules.append(Ma)\r
2091 continue\r
2092 if (Ma.MetaFile.Path, Ma.Arch) in GlobalData.gCacheIR and \\r
2093 GlobalData.gCacheIR[(Ma.MetaFile.Path, Ma.Arch)].MakeCacheHit:\r
2094 self.HashSkipModules.append(Ma)\r
2095 continue\r
2096 self.BuildModules.append(Ma)\r
2097 else:\r
2098 self.BuildModules.extend(TotalModules)\r
1a624dd7 2099\r
673d09a2
FB
2100 if not autogen_rt:\r
2101 self.AutoGenMgr.TerminateWorkers()\r
2102 self.AutoGenMgr.join(0.1)\r
2103 raise FatalError(errorcode)\r
1a624dd7
FB
2104 self.AutoGenTime += int(round((time.time() - AutoGenStart)))\r
2105 self.Progress.Stop("done!")\r
0e7e7a26
SS
2106\r
2107 if GlobalData.gBinCacheSource:\r
2108 EdkLogger.quiet("Total cache hit driver num: %s, cache miss driver num: %s" % (len(set(self.HashSkipModules)), len(set(self.BuildModules))))\r
2109 CacheHitMa = set()\r
2110 CacheNotHitMa = set()\r
2111 for IR in GlobalData.gCacheIR.keys():\r
2112 if 'PlatformHash' in IR or 'PackageHash' in IR:\r
2113 continue\r
2114 if GlobalData.gCacheIR[IR].PreMakeCacheHit or GlobalData.gCacheIR[IR].MakeCacheHit:\r
2115 CacheHitMa.add(IR)\r
2116 else:\r
2117 # There might be binary module or module which has .inc files, not count for cache miss\r
2118 CacheNotHitMa.add(IR)\r
2119 EdkLogger.quiet("Total module num: %s, cache hit module num: %s" % (len(CacheHitMa)+len(CacheNotHitMa), len(CacheHitMa)))\r
2120\r
673d09a2 2121 for Arch in Wa.ArchList:\r
1b8eca8b 2122 MakeStart = time.time()\r
0e7e7a26 2123 for Ma in set(self.BuildModules):\r
52302d4d 2124 # Generate build task for the module\r
a0a2cd1e 2125 if not Ma.IsBinaryModule:\r
673d09a2 2126 Bt = BuildTask.New(ModuleMakeUnit(Ma, Pa.BuildCommand,self.Target))\r
52302d4d
LG
2127 # Break build if any build thread has error\r
2128 if BuildTask.HasError():\r
2129 # we need a full version of makefile for platform\r
2130 ExitFlag.set()\r
2131 BuildTask.WaitForComplete()\r
0eccea3f 2132 self.invalidateHash()\r
52302d4d
LG
2133 Pa.CreateMakeFile(False)\r
2134 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
2135 # Start task scheduler\r
2136 if not BuildTask.IsOnGoing():\r
2137 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
2138\r
2139 # in case there's an interruption. we need a full version of makefile for platform\r
2140 Pa.CreateMakeFile(False)\r
2141 if BuildTask.HasError():\r
0eccea3f 2142 self.invalidateHash()\r
52302d4d 2143 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1b8eca8b 2144 self.MakeTime += int(round((time.time() - MakeStart)))\r
52302d4d 2145\r
1b8eca8b 2146 MakeContiue = time.time()\r
2f818ed0 2147\r
64b2609f 2148 #\r
52302d4d
LG
2149 #\r
2150 # All modules have been put in build tasks queue. Tell task scheduler\r
2151 # to exit if all tasks are completed\r
2152 #\r
2153 ExitFlag.set()\r
2154 BuildTask.WaitForComplete()\r
a0a2cd1e 2155 self.CreateAsBuiltInf()\r
b8ac0b7f
BF
2156 if GlobalData.gBinCacheDest:\r
2157 self.UpdateBuildCache()\r
2158 self.BuildModules = []\r
1b8eca8b 2159 self.MakeTime += int(round((time.time() - MakeContiue)))\r
52302d4d
LG
2160 #\r
2161 # Check for build error, and raise exception if one\r
2162 # has been signaled.\r
2163 #\r
2164 if BuildTask.HasError():\r
0eccea3f 2165 self.invalidateHash()\r
52302d4d
LG
2166 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
2167\r
2168 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 2169 if self.Target in ["", "all", "fds"]:\r
0d2711a6 2170 for Arch in Wa.ArchList:\r
52302d4d
LG
2171 #\r
2172 # Check whether the set fix address is above 4G for 32bit image.\r
2173 #\r
2174 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
2175 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
2176 #\r
2177 # Get Module List\r
2178 #\r
636f2be6 2179 ModuleList = {}\r
52302d4d
LG
2180 for Pa in Wa.AutoGenObjectList:\r
2181 for Ma in Pa.ModuleAutoGenList:\r
4231a819 2182 if Ma is None:\r
52302d4d
LG
2183 continue\r
2184 if not Ma.IsLibrary:\r
636f2be6 2185 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
2186 #\r
2187 # Rebase module to the preferred memory address before GenFds\r
2188 #\r
d943b0c3 2189 MapBuffer = []\r
636f2be6
LG
2190 if self.LoadFixAddress != 0:\r
2191 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
52302d4d 2192\r
0d2711a6 2193 if self.Fdf:\r
f3decdc3
LG
2194 #\r
2195 # Generate FD image if there's a FDF file found\r
2196 #\r
1b8eca8b 2197 GenFdsStart = time.time()\r
370544d1
DL
2198 if GenFdsApi(Wa.GenFdsCommandDict, self.Db):\r
2199 EdkLogger.error("build", COMMAND_FAILURE)\r
03af2753 2200\r
52302d4d
LG
2201 #\r
2202 # Create MAP file for all platform FVs after GenFds.\r
2203 #\r
636f2be6 2204 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
1b8eca8b 2205 self.GenFdsTime += int(round((time.time() - GenFdsStart)))\r
52302d4d
LG
2206 #\r
2207 # Save MAP buffer into MAP file.\r
2208 #\r
2209 self._SaveMapFile(MapBuffer, Wa)\r
48b0bf64 2210 self.invalidateHash()\r
52302d4d
LG
2211\r
2212 ## Generate GuidedSectionTools.txt in the FV directories.\r
2213 #\r
2214 def CreateGuidedSectionToolsFile(self):\r
0d2711a6
LG
2215 for BuildTarget in self.BuildTargetList:\r
2216 for ToolChain in self.ToolChainList:\r
2217 Wa = WorkspaceAutoGen(\r
2218 self.WorkspaceDir,\r
2219 self.PlatformFile,\r
2220 BuildTarget,\r
2221 ToolChain,\r
2222 self.ArchList,\r
2223 self.BuildDatabase,\r
2224 self.TargetTxt,\r
2225 self.ToolDef,\r
2226 self.Fdf,\r
2227 self.FdList,\r
2228 self.FvList,\r
2229 self.CapList,\r
2230 self.SkuId,\r
2231 self.UniFlag\r
2232 )\r
2233 FvDir = Wa.FvDir\r
2234 if not os.path.exists(FvDir):\r
2235 continue\r
2236\r
4afd3d04 2237 for Arch in self.ArchList:\r
52302d4d
LG
2238 # Build up the list of supported architectures for this build\r
2239 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)\r
4afd3d04 2240\r
52302d4d
LG
2241 # Look through the tool definitions for GUIDed tools\r
2242 guidAttribs = []\r
3a041437 2243 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.items():\r
52302d4d
LG
2244 if attrib.upper().endswith('_GUID'):\r
2245 split = attrib.split('_')\r
2246 thisPrefix = '_'.join(split[0:3]) + '_'\r
2247 if thisPrefix == prefix:\r
2248 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]\r
2249 guid = guid.lower()\r
2250 toolName = split[3]\r
2251 path = '_'.join(split[0:4]) + '_PATH'\r
2252 path = self.ToolDef.ToolsDefTxtDictionary[path]\r
2253 path = self.GetFullPathOfTool(path)\r
2254 guidAttribs.append((guid, toolName, path))\r
4afd3d04 2255\r
52302d4d
LG
2256 # Write out GuidedSecTools.txt\r
2257 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')\r
2258 toolsFile = open(toolsFile, 'wt')\r
2259 for guidedSectionTool in guidAttribs:\r
72443dd2 2260 print(' '.join(guidedSectionTool), file=toolsFile)\r
52302d4d
LG
2261 toolsFile.close()\r
2262\r
2263 ## Returns the full path of the tool.\r
2264 #\r
2265 def GetFullPathOfTool (self, tool):\r
2266 if os.path.exists(tool):\r
2267 return os.path.realpath(tool)\r
2268 else:\r
2269 # We need to search for the tool using the\r
2270 # PATH environment variable.\r
2271 for dirInPath in os.environ['PATH'].split(os.pathsep):\r
2272 foundPath = os.path.join(dirInPath, tool)\r
2273 if os.path.exists(foundPath):\r
2274 return os.path.realpath(foundPath)\r
2275\r
2276 # If the tool was not found in the path then we just return\r
2277 # the input tool.\r
2278 return tool\r
2279\r
2280 ## Launch the module or platform build\r
2281 #\r
2282 def Launch(self):\r
0d2711a6 2283 if not self.ModuleFile:\r
52302d4d
LG
2284 if not self.SpawnMode or self.Target not in ["", "all"]:\r
2285 self.SpawnMode = False\r
2286 self._BuildPlatform()\r
2287 else:\r
2288 self._MultiThreadBuildPlatform()\r
2289 self.CreateGuidedSectionToolsFile()\r
2290 else:\r
2291 self.SpawnMode = False\r
2292 self._BuildModule()\r
2293\r
bcbdc755 2294 if self.Target == 'cleanall':\r
bcbdc755
YL
2295 RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)\r
2296\r
a0a2cd1e 2297 def CreateAsBuiltInf(self):\r
b8ac0b7f
BF
2298 for Module in self.BuildModules:\r
2299 Module.CreateAsBuiltInf()\r
2300\r
2301 def UpdateBuildCache(self):\r
db4d47fd
CR
2302 all_lib_set = set()\r
2303 all_mod_set = set()\r
a0a2cd1e 2304 for Module in self.BuildModules:\r
b8ac0b7f 2305 Module.CopyModuleToCache()\r
db4d47fd 2306 all_mod_set.add(Module)\r
83397f95 2307 for Module in self.HashSkipModules:\r
b8ac0b7f 2308 Module.CopyModuleToCache()\r
db4d47fd
CR
2309 all_mod_set.add(Module)\r
2310 for Module in all_mod_set:\r
2311 for lib in Module.LibraryAutoGenList:\r
2312 all_lib_set.add(lib)\r
2313 for lib in all_lib_set:\r
b8ac0b7f 2314 lib.CopyModuleToCache()\r
db4d47fd
CR
2315 all_lib_set.clear()\r
2316 all_mod_set.clear()\r
83397f95 2317 self.HashSkipModules = []\r
52302d4d
LG
2318 ## Do some clean-up works when error occurred\r
2319 def Relinquish(self):\r
2320 OldLogLevel = EdkLogger.GetLevel()\r
2321 EdkLogger.SetLevel(EdkLogger.ERROR)\r
52302d4d
LG
2322 Utils.Progressor.Abort()\r
2323 if self.SpawnMode == True:\r
2324 BuildTask.Abort()\r
2325 EdkLogger.SetLevel(OldLogLevel)\r
2326\r
52302d4d
LG
2327def ParseDefines(DefineList=[]):\r
2328 DefineDict = {}\r
4231a819 2329 if DefineList is not None:\r
52302d4d
LG
2330 for Define in DefineList:\r
2331 DefineTokenList = Define.split("=", 1)\r
0d2711a6
LG
2332 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):\r
2333 EdkLogger.error('build', FORMAT_INVALID,\r
2334 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",\r
2335 ExtraData=DefineTokenList[0])\r
4afd3d04 2336\r
52302d4d 2337 if len(DefineTokenList) == 1:\r
0d2711a6 2338 DefineDict[DefineTokenList[0]] = "TRUE"\r
52302d4d
LG
2339 else:\r
2340 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()\r
2341 return DefineDict\r
2342\r
c60fb00f 2343\r
52302d4d 2344\r
1b8eca8b
YZ
2345def LogBuildTime(Time):\r
2346 if Time:\r
2347 TimeDurStr = ''\r
2348 TimeDur = time.gmtime(Time)\r
2349 if TimeDur.tm_yday > 1:\r
2350 TimeDurStr = time.strftime("%H:%M:%S", TimeDur) + ", %d day(s)" % (TimeDur.tm_yday - 1)\r
2351 else:\r
2352 TimeDurStr = time.strftime("%H:%M:%S", TimeDur)\r
2353 return TimeDurStr\r
2354 else:\r
2355 return None\r
1a624dd7
FB
2356def ThreadNum():\r
2357 ThreadNumber = BuildOption.ThreadNumber\r
2358 if ThreadNumber is None:\r
2359 ThreadNumber = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]\r
2360 if ThreadNumber == '':\r
2361 ThreadNumber = 0\r
2362 else:\r
2363 ThreadNumber = int(ThreadNumber, 0)\r
1b8eca8b 2364\r
1a624dd7
FB
2365 if ThreadNumber == 0:\r
2366 try:\r
2367 ThreadNumber = multiprocessing.cpu_count()\r
2368 except (ImportError, NotImplementedError):\r
2369 ThreadNumber = 1\r
2370 return ThreadNumber\r
52302d4d
LG
2371## Tool entrance method\r
2372#\r
2373# This method mainly dispatch specific methods per the command line options.\r
2374# If no error found, return zero value so the caller of this tool can know\r
2375# if it's executed successfully or not.\r
2376#\r
2377# @retval 0 Tool was successful\r
2378# @retval 1 Tool failed\r
2379#\r
1a624dd7 2380LogQMaxSize = ThreadNum() * 10\r
52302d4d
LG
2381def Main():\r
2382 StartTime = time.time()\r
2383\r
636ed13a
FB
2384 #\r
2385 # Create a log Queue\r
2386 #\r
1a624dd7 2387 LogQ = mp.Queue(LogQMaxSize)\r
52302d4d 2388 # Initialize log system\r
636ed13a 2389 EdkLogger.LogClientInitialize(LogQ)\r
f0dc69e6 2390 GlobalData.gCommand = sys.argv[1:]\r
52302d4d
LG
2391 #\r
2392 # Parse the options and args\r
2393 #\r
c60fb00f 2394 Option, Target = BuildOption, BuildTarget\r
52302d4d
LG
2395 GlobalData.gOptions = Option\r
2396 GlobalData.gCaseInsensitive = Option.CaseInsensitive\r
2397\r
2398 # Set log level\r
636ed13a 2399 LogLevel = EdkLogger.INFO\r
4231a819 2400 if Option.verbose is not None:\r
52302d4d 2401 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
636ed13a 2402 LogLevel = EdkLogger.VERBOSE\r
4231a819 2403 elif Option.quiet is not None:\r
52302d4d 2404 EdkLogger.SetLevel(EdkLogger.QUIET)\r
636ed13a 2405 LogLevel = EdkLogger.QUIET\r
4231a819 2406 elif Option.debug is not None:\r
52302d4d 2407 EdkLogger.SetLevel(Option.debug + 1)\r
636ed13a 2408 LogLevel = Option.debug + 1\r
52302d4d
LG
2409 else:\r
2410 EdkLogger.SetLevel(EdkLogger.INFO)\r
2411\r
52302d4d
LG
2412 if Option.WarningAsError == True:\r
2413 EdkLogger.SetWarningAsError()\r
636ed13a
FB
2414 Log_Agent = LogAgent(LogQ,LogLevel,Option.LogFile)\r
2415 Log_Agent.start()\r
52302d4d
LG
2416\r
2417 if platform.platform().find("Windows") >= 0:\r
2418 GlobalData.gIsWindows = True\r
2419 else:\r
2420 GlobalData.gIsWindows = False\r
2421\r
6780eef1
LG
2422 EdkLogger.quiet("Build environment: %s" % platform.platform())\r
2423 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));\r
52302d4d
LG
2424 ReturnCode = 0\r
2425 MyBuild = None\r
09ae0f11 2426 BuildError = True\r
52302d4d
LG
2427 try:\r
2428 if len(Target) == 0:\r
2429 Target = "all"\r
2430 elif len(Target) >= 2:\r
2431 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",\r
47fea6af 2432 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))\r
52302d4d
LG
2433 else:\r
2434 Target = Target[0].lower()\r
2435\r
2436 if Target not in gSupportedTarget:\r
2437 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,\r
47fea6af 2438 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))\r
52302d4d 2439\r
52302d4d
LG
2440 #\r
2441 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH\r
2442 #\r
2443 CheckEnvVariable()\r
0d2711a6
LG
2444 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))\r
2445\r
52302d4d
LG
2446 Workspace = os.getenv("WORKSPACE")\r
2447 #\r
2448 # Get files real name in workspace dir\r
2449 #\r
2450 GlobalData.gAllFiles = Utils.DirCache(Workspace)\r
2451\r
2452 WorkingDirectory = os.getcwd()\r
2453 if not Option.ModuleFile:\r
2454 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))\r
2455 FileNum = len(FileList)\r
2456 if FileNum >= 2:\r
2457 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),\r
2458 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")\r
2459 elif FileNum == 1:\r
2460 Option.ModuleFile = NormFile(FileList[0], Workspace)\r
2461\r
2462 if Option.ModuleFile:\r
2463 if os.path.isabs (Option.ModuleFile):\r
2464 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:\r
2465 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)\r
2466 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)\r
2467 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)\r
2468 if ErrorCode != 0:\r
2469 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2470\r
4231a819 2471 if Option.PlatformFile is not None:\r
52302d4d
LG
2472 if os.path.isabs (Option.PlatformFile):\r
2473 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:\r
2474 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)\r
2475 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)\r
52302d4d 2476\r
4231a819 2477 if Option.FdfFile is not None:\r
52302d4d
LG
2478 if os.path.isabs (Option.FdfFile):\r
2479 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:\r
2480 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)\r
2481 Option.FdfFile = PathClass(Option.FdfFile, Workspace)\r
2482 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)\r
2483 if ErrorCode != 0:\r
2484 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2485\r
4231a819 2486 if Option.Flag is not None and Option.Flag not in ['-c', '-s']:\r
f3decdc3
LG
2487 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")\r
2488\r
636ed13a 2489 MyBuild = Build(Target, Workspace, Option,LogQ)\r
64b2609f 2490 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)\r
f0dc69e6
YZ
2491 if not (MyBuild.LaunchPrebuildFlag and os.path.exists(MyBuild.PlatformBuildPath)):\r
2492 MyBuild.Launch()\r
2f818ed0 2493\r
09ae0f11
YL
2494 #\r
2495 # All job done, no error found and no exception raised\r
2496 #\r
2497 BuildError = False\r
5b0671c1 2498 except FatalError as X:\r
4231a819 2499 if MyBuild is not None:\r
52302d4d
LG
2500 # for multi-thread build exits safely\r
2501 MyBuild.Relinquish()\r
4231a819 2502 if Option is not None and Option.debug is not None:\r
52302d4d
LG
2503 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2504 ReturnCode = X.args[0]\r
5b0671c1 2505 except Warning as X:\r
52302d4d 2506 # error from Fdf parser\r
4231a819 2507 if MyBuild is not None:\r
52302d4d
LG
2508 # for multi-thread build exits safely\r
2509 MyBuild.Relinquish()\r
4231a819 2510 if Option is not None and Option.debug is not None:\r
52302d4d
LG
2511 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2512 else:\r
47fea6af 2513 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)\r
52302d4d
LG
2514 ReturnCode = FORMAT_INVALID\r
2515 except KeyboardInterrupt:\r
673d09a2
FB
2516 if MyBuild is not None:\r
2517\r
2518 # for multi-thread build exits safely\r
2519 MyBuild.Relinquish()\r
52302d4d 2520 ReturnCode = ABORT_ERROR\r
4231a819 2521 if Option is not None and Option.debug is not None:\r
52302d4d
LG
2522 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2523 except:\r
4231a819 2524 if MyBuild is not None:\r
52302d4d
LG
2525 # for multi-thread build exits safely\r
2526 MyBuild.Relinquish()\r
2527\r
2528 # try to get the meta-file from the object causing exception\r
2529 Tb = sys.exc_info()[-1]\r
2530 MetaFile = GlobalData.gProcessingFile\r
4231a819 2531 while Tb is not None:\r
52302d4d
LG
2532 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):\r
2533 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile\r
2534 Tb = Tb.tb_next\r
2535 EdkLogger.error(\r
2536 "\nbuild",\r
2537 CODE_ERROR,\r
2538 "Unknown fatal error when processing [%s]" % MetaFile,\r
c1387446 2539 ExtraData="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR,\r
52302d4d
LG
2540 RaiseError=False\r
2541 )\r
d0acc87a 2542 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
52302d4d
LG
2543 ReturnCode = CODE_ERROR\r
2544 finally:\r
2545 Utils.Progressor.Abort()\r
97fa0ee9 2546 Utils.ClearDuplicatedInf()\r
52302d4d
LG
2547\r
2548 if ReturnCode == 0:\r
f0dc69e6 2549 try:\r
91048b0d 2550 MyBuild.LaunchPostbuild()\r
f0dc69e6
YZ
2551 Conclusion = "Done"\r
2552 except:\r
2553 Conclusion = "Failed"\r
52302d4d
LG
2554 elif ReturnCode == ABORT_ERROR:\r
2555 Conclusion = "Aborted"\r
2556 else:\r
2557 Conclusion = "Failed"\r
2558 FinishTime = time.time()\r
4234283c
LG
2559 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))\r
2560 BuildDurationStr = ""\r
2561 if BuildDuration.tm_yday > 1:\r
47fea6af 2562 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)" % (BuildDuration.tm_yday - 1)\r
4234283c
LG
2563 else:\r
2564 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)\r
4231a819 2565 if MyBuild is not None:\r
09ae0f11 2566 if not BuildError:\r
1b8eca8b 2567 MyBuild.BuildReport.GenerateReport(BuildDurationStr, LogBuildTime(MyBuild.AutoGenTime), LogBuildTime(MyBuild.MakeTime), LogBuildTime(MyBuild.GenFdsTime))\r
2f818ed0 2568\r
52302d4d 2569 EdkLogger.SetLevel(EdkLogger.QUIET)\r
6780eef1
LG
2570 EdkLogger.quiet("\n- %s -" % Conclusion)\r
2571 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))\r
4234283c 2572 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)\r
636ed13a
FB
2573 Log_Agent.kill()\r
2574 Log_Agent.join()\r
52302d4d
LG
2575 return ReturnCode\r
2576\r
2577if __name__ == '__main__':\r
673d09a2
FB
2578 try:\r
2579 mp.set_start_method('spawn')\r
2580 except:\r
2581 pass\r
52302d4d
LG
2582 r = Main()\r
2583 ## 0-127 is a safe return range, and 1 is a standard default error\r
2584 if r < 0 or r > 127: r = 1\r
2585 sys.exit(r)\r
2586\r