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