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