]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/build/build.py
BaseTools: Clean up source files
[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
52302d4d 6#\r
40d841f6 7# This program and the accompanying materials\r
52302d4d
LG
8# are licensed and made available under the terms and conditions of the BSD License\r
9# which accompanies this distribution. The full text of the license may be found at\r
10# http://opensource.org/licenses/bsd-license.php\r
11#\r
12# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14#\r
15\r
16##\r
17# Import Modules\r
18#\r
72443dd2 19from __future__ import print_function\r
1be2ed90 20import Common.LongFilePathOs as os\r
52302d4d 21import re\r
86379ac4 22from io import BytesIO\r
52302d4d
LG
23import sys\r
24import glob\r
25import time\r
26import platform\r
27import traceback\r
4afd3d04 28import encodings.ascii\r
f0dc69e6 29import itertools\r
29af38b0 30import multiprocessing\r
52302d4d
LG
31\r
32from struct import *\r
33from threading import *\r
34from optparse import OptionParser\r
35from subprocess import *\r
36from Common import Misc as Utils\r
37\r
1be2ed90
HC
38from Common.LongFilePathSupport import OpenLongFilePath as open\r
39from Common.LongFilePathSupport import LongFilePath\r
52302d4d
LG
40from Common.TargetTxtClassObject import *\r
41from Common.ToolDefClassObject import *\r
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
46from Workspace.WorkspaceDatabase import *\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
37de70b7 55from GenFds.GenFds import GenFds\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
4231a819 247 if Line is not None and Line != "":\r
52302d4d
LG
248 To(Line.rstrip())\r
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
508 BuildObjectList = BuildTask._PendingQueue.keys()\r
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
LG
728 self.Image = ImageClass\r
729 self.Image.Size = (self.Image.Size / 0x1000 + 1) * 0x1000\r
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
0d2711a6
LG
830 if BuildOptions.DisableCache:\r
831 self.Db = WorkspaceDatabase(":memory:")\r
832 else:\r
97fa0ee9
YL
833 self.Db = WorkspaceDatabase(GlobalData.gDatabasePath, self.Reparse)\r
834 self.BuildDatabase = self.Db.BuildObject\r
835 self.Platform = None\r
40b4e21d 836 self.ToolChainFamily = None\r
52302d4d 837 self.LoadFixAddress = 0\r
0d2711a6 838 self.UniFlag = BuildOptions.Flag\r
a0a2cd1e 839 self.BuildModules = []\r
83397f95 840 self.HashSkipModules = []\r
f0dc69e6
YZ
841 self.Db_Flag = False\r
842 self.LaunchPrebuildFlag = False\r
ccaa7754 843 self.PlatformBuildPath = os.path.join(GlobalData.gConfDirectory, '.cache', '.PlatformBuild')\r
725cdb8f
YZ
844 if BuildOptions.CommandLength:\r
845 GlobalData.gCommandMaxLength = BuildOptions.CommandLength\r
846\r
e56468c0 847 # print dot character during doing some time-consuming work\r
52302d4d 848 self.Progress = Utils.Progressor()\r
52302d4d 849 # print current build environment and configuration\r
0d2711a6 850 EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))\r
f25da33d 851 if "PACKAGES_PATH" in os.environ:\r
f7496d71 852 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.\r
f25da33d 853 EdkLogger.quiet("%-16s = %s" % ("PACKAGES_PATH", os.path.normcase(os.path.normpath(os.environ["PACKAGES_PATH"]))))\r
0d2711a6
LG
854 EdkLogger.quiet("%-16s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"]))\r
855 EdkLogger.quiet("%-16s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"]))\r
856 EdkLogger.quiet("%-16s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"]))\r
857 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))\r
f25da33d 858 if "EDK_TOOLS_BIN" in os.environ:\r
f7496d71 859 # Print the same path style with WORKSPACE env.\r
f25da33d 860 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os.path.normcase(os.path.normpath(os.environ["EDK_TOOLS_BIN"]))))\r
00bcb5c2 861 EdkLogger.quiet("%-16s = %s" % ("CONF_PATH", GlobalData.gConfDirectory))\r
f0dc69e6
YZ
862 self.InitPreBuild()\r
863 self.InitPostBuild()\r
af9c4e5e
MK
864 if self.Prebuild:\r
865 EdkLogger.quiet("%-16s = %s" % ("PREBUILD", self.Prebuild))\r
866 if self.Postbuild:\r
867 EdkLogger.quiet("%-16s = %s" % ("POSTBUILD", self.Postbuild))\r
868 if self.Prebuild:\r
f0dc69e6 869 self.LaunchPrebuild()\r
a0c9ce31
YZ
870 self.TargetTxt = TargetTxtClassObject()\r
871 self.ToolDef = ToolDefClassObject()\r
f0dc69e6
YZ
872 if not (self.LaunchPrebuildFlag and os.path.exists(self.PlatformBuildPath)):\r
873 self.InitBuild()\r
52302d4d 874\r
f0dc69e6 875 EdkLogger.info("")\r
52302d4d 876 os.chdir(self.WorkspaceDir)\r
52302d4d
LG
877\r
878 ## Load configuration\r
879 #\r
880 # This method will parse target.txt and get the build configurations.\r
881 #\r
882 def LoadConfiguration(self):\r
883 #\r
884 # Check target.txt and tools_def.txt and Init them\r
885 #\r
97fa0ee9 886 BuildConfigurationFile = os.path.normpath(os.path.join(GlobalData.gConfDirectory, gBuildConfiguration))\r
52302d4d
LG
887 if os.path.isfile(BuildConfigurationFile) == True:\r
888 StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)\r
889\r
890 ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]\r
891 if ToolDefinitionFile == '':\r
892 ToolDefinitionFile = gToolsDefinition\r
05cc51ad 893 ToolDefinitionFile = os.path.normpath(mws.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile))\r
52302d4d
LG
894 if os.path.isfile(ToolDefinitionFile) == True:\r
895 StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)\r
896 else:\r
897 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)\r
898 else:\r
899 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)\r
900\r
901 # if no ARCH given in command line, get it from target.txt\r
0d2711a6 902 if not self.ArchList:\r
52302d4d 903 self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH]\r
0d2711a6 904 self.ArchList = tuple(self.ArchList)\r
52302d4d
LG
905\r
906 # if no build target given in command line, get it from target.txt\r
0d2711a6 907 if not self.BuildTargetList:\r
52302d4d
LG
908 self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]\r
909\r
910 # if no tool chain given in command line, get it from target.txt\r
0d2711a6 911 if not self.ToolChainList:\r
52302d4d 912 self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]\r
4231a819 913 if self.ToolChainList is None or len(self.ToolChainList) == 0:\r
52302d4d
LG
914 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")\r
915\r
916 # check if the tool chains are defined or not\r
917 NewToolChainList = []\r
918 for ToolChain in self.ToolChainList:\r
919 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:\r
920 EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)\r
921 else:\r
922 NewToolChainList.append(ToolChain)\r
923 # if no tool chain available, break the build\r
924 if len(NewToolChainList) == 0:\r
925 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
926 ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))\r
927 else:\r
928 self.ToolChainList = NewToolChainList\r
929\r
40b4e21d
YZ
930 ToolChainFamily = []\r
931 ToolDefinition = self.ToolDef.ToolsDefTxtDatabase\r
932 for Tool in self.ToolChainList:\r
933 if TAB_TOD_DEFINES_FAMILY not in ToolDefinition or Tool not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \\r
934 or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool]:\r
688c7d21 935 EdkLogger.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool)\r
40b4e21d
YZ
936 ToolChainFamily.append("MSFT")\r
937 else:\r
938 ToolChainFamily.append(ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool])\r
939 self.ToolChainFamily = ToolChainFamily\r
940\r
4231a819 941 if self.ThreadNumber is None:\r
52302d4d
LG
942 self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]\r
943 if self.ThreadNumber == '':\r
944 self.ThreadNumber = 0\r
945 else:\r
946 self.ThreadNumber = int(self.ThreadNumber, 0)\r
947\r
948 if self.ThreadNumber == 0:\r
29af38b0
YF
949 try:\r
950 self.ThreadNumber = multiprocessing.cpu_count()\r
951 except (ImportError, NotImplementedError):\r
952 self.ThreadNumber = 1\r
52302d4d
LG
953\r
954 if not self.PlatformFile:\r
955 PlatformFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM]\r
956 if not PlatformFile:\r
957 # Try to find one in current directory\r
958 WorkingDirectory = os.getcwd()\r
959 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))\r
960 FileNum = len(FileList)\r
961 if FileNum >= 2:\r
962 EdkLogger.error("build", OPTION_MISSING,\r
963 ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))\r
964 elif FileNum == 1:\r
965 PlatformFile = FileList[0]\r
966 else:\r
967 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
968 ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")\r
969\r
970 self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)\r
52302d4d
LG
971\r
972 ## Initialize build configuration\r
973 #\r
974 # This method will parse DSC file and merge the configurations from\r
975 # command line and target.txt, then get the final build configurations.\r
976 #\r
977 def InitBuild(self):\r
0d2711a6 978 # parse target.txt, tools_def.txt, and platform file\r
4afd3d04 979 self.LoadConfiguration()\r
0d2711a6
LG
980\r
981 # Allow case-insensitive for those from command line or configuration file\r
982 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)\r
52302d4d
LG
983 if ErrorCode != 0:\r
984 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
985\r
986 # create metafile database\r
f0dc69e6
YZ
987 if not self.Db_Flag:\r
988 self.Db.InitDatabase()\r
989\r
990 def InitPreBuild(self):\r
991 self.LoadConfiguration()\r
d429fcd0
YZ
992 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)\r
993 if ErrorCode != 0:\r
994 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
f0dc69e6
YZ
995 if self.BuildTargetList:\r
996 GlobalData.gGlobalDefines['TARGET'] = self.BuildTargetList[0]\r
997 if self.ArchList:\r
998 GlobalData.gGlobalDefines['ARCH'] = self.ArchList[0]\r
999 if self.ToolChainList:\r
1000 GlobalData.gGlobalDefines['TOOLCHAIN'] = self.ToolChainList[0]\r
1001 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = self.ToolChainList[0]\r
40b4e21d
YZ
1002 if self.ToolChainFamily:\r
1003 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[0]\r
9eb87141 1004 if 'PREBUILD' in GlobalData.gCommandLineDefines:\r
f0dc69e6
YZ
1005 self.Prebuild = GlobalData.gCommandLineDefines.get('PREBUILD')\r
1006 else:\r
1007 self.Db.InitDatabase()\r
1008 self.Db_Flag = True\r
1009 Platform = self.Db._MapPlatform(str(self.PlatformFile))\r
1010 self.Prebuild = str(Platform.Prebuild)\r
1011 if self.Prebuild:\r
af9c4e5e
MK
1012 PrebuildList = []\r
1013 #\r
1014 # Evaluate all arguments and convert arguments that are WORKSPACE\r
1015 # relative paths to absolute paths. Filter arguments that look like\r
1016 # flags or do not follow the file/dir naming rules to avoid false\r
1017 # positives on this conversion.\r
1018 #\r
1019 for Arg in self.Prebuild.split():\r
1020 #\r
1021 # Do not modify Arg if it looks like a flag or an absolute file path\r
1022 #\r
1023 if Arg.startswith('-') or os.path.isabs(Arg):\r
1024 PrebuildList.append(Arg)\r
1025 continue\r
1026 #\r
1027 # Do not modify Arg if it does not look like a Workspace relative\r
1028 # path that starts with a valid package directory name\r
1029 #\r
1030 if not Arg[0].isalpha() or os.path.dirname(Arg) == '':\r
1031 PrebuildList.append(Arg)\r
1032 continue\r
1033 #\r
1034 # If Arg looks like a WORKSPACE relative path, then convert to an\r
1035 # absolute path and check to see if the file exists.\r
1036 #\r
1037 Temp = mws.join(self.WorkspaceDir, Arg)\r
1038 if os.path.isfile(Temp):\r
1039 Arg = Temp\r
1040 PrebuildList.append(Arg)\r
1041 self.Prebuild = ' '.join(PrebuildList)\r
1042 self.Prebuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)\r
52302d4d 1043\r
f0dc69e6 1044 def InitPostBuild(self):\r
9eb87141 1045 if 'POSTBUILD' in GlobalData.gCommandLineDefines:\r
f0dc69e6
YZ
1046 self.Postbuild = GlobalData.gCommandLineDefines.get('POSTBUILD')\r
1047 else:\r
1048 Platform = self.Db._MapPlatform(str(self.PlatformFile))\r
1049 self.Postbuild = str(Platform.Postbuild)\r
1050 if self.Postbuild:\r
af9c4e5e
MK
1051 PostbuildList = []\r
1052 #\r
1053 # Evaluate all arguments and convert arguments that are WORKSPACE\r
1054 # relative paths to absolute paths. Filter arguments that look like\r
1055 # flags or do not follow the file/dir naming rules to avoid false\r
1056 # positives on this conversion.\r
1057 #\r
1058 for Arg in self.Postbuild.split():\r
1059 #\r
1060 # Do not modify Arg if it looks like a flag or an absolute file path\r
1061 #\r
1062 if Arg.startswith('-') or os.path.isabs(Arg):\r
1063 PostbuildList.append(Arg)\r
1064 continue\r
1065 #\r
1066 # Do not modify Arg if it does not look like a Workspace relative\r
1067 # path that starts with a valid package directory name\r
1068 #\r
1069 if not Arg[0].isalpha() or os.path.dirname(Arg) == '':\r
1070 PostbuildList.append(Arg)\r
1071 continue\r
1072 #\r
1073 # If Arg looks like a WORKSPACE relative path, then convert to an\r
1074 # absolute path and check to see if the file exists.\r
1075 #\r
1076 Temp = mws.join(self.WorkspaceDir, Arg)\r
1077 if os.path.isfile(Temp):\r
1078 Arg = Temp\r
1079 PostbuildList.append(Arg)\r
1080 self.Postbuild = ' '.join(PostbuildList)\r
1081 self.Postbuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)\r
1082\r
1083 def PassCommandOption(self, BuildTarget, TargetArch, ToolChain, PlatformFile, Target):\r
f0dc69e6
YZ
1084 BuildStr = ''\r
1085 if GlobalData.gCommand and isinstance(GlobalData.gCommand, list):\r
1086 BuildStr += ' ' + ' '.join(GlobalData.gCommand)\r
1087 TargetFlag = False\r
1088 ArchFlag = False\r
1089 ToolChainFlag = False\r
af9c4e5e 1090 PlatformFileFlag = False\r
f0dc69e6
YZ
1091\r
1092 if GlobalData.gOptions and not GlobalData.gOptions.BuildTarget:\r
1093 TargetFlag = True\r
1094 if GlobalData.gOptions and not GlobalData.gOptions.TargetArch:\r
1095 ArchFlag = True\r
1096 if GlobalData.gOptions and not GlobalData.gOptions.ToolChain:\r
1097 ToolChainFlag = True\r
af9c4e5e
MK
1098 if GlobalData.gOptions and not GlobalData.gOptions.PlatformFile:\r
1099 PlatformFileFlag = True\r
f0dc69e6
YZ
1100\r
1101 if TargetFlag and BuildTarget:\r
1102 if isinstance(BuildTarget, list) or isinstance(BuildTarget, tuple):\r
1103 BuildStr += ' -b ' + ' -b '.join(BuildTarget)\r
1104 elif isinstance(BuildTarget, str):\r
1105 BuildStr += ' -b ' + BuildTarget\r
1106 if ArchFlag and TargetArch:\r
1107 if isinstance(TargetArch, list) or isinstance(TargetArch, tuple):\r
1108 BuildStr += ' -a ' + ' -a '.join(TargetArch)\r
1109 elif isinstance(TargetArch, str):\r
1110 BuildStr += ' -a ' + TargetArch\r
1111 if ToolChainFlag and ToolChain:\r
1112 if isinstance(ToolChain, list) or isinstance(ToolChain, tuple):\r
1113 BuildStr += ' -t ' + ' -t '.join(ToolChain)\r
1114 elif isinstance(ToolChain, str):\r
1115 BuildStr += ' -t ' + ToolChain\r
af9c4e5e
MK
1116 if PlatformFileFlag and PlatformFile:\r
1117 if isinstance(PlatformFile, list) or isinstance(PlatformFile, tuple):\r
1118 BuildStr += ' -p ' + ' -p '.join(PlatformFile)\r
1119 elif isinstance(PlatformFile, str):\r
1120 BuildStr += ' -p' + PlatformFile\r
1121 BuildStr += ' --conf=' + GlobalData.gConfDirectory\r
1122 if Target:\r
1123 BuildStr += ' ' + Target\r
f0dc69e6
YZ
1124\r
1125 return BuildStr\r
1126\r
1127 def LaunchPrebuild(self):\r
1128 if self.Prebuild:\r
1129 EdkLogger.info("\n- Prebuild Start -\n")\r
1130 self.LaunchPrebuildFlag = True\r
134bbe88
YZ
1131 #\r
1132 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script\r
1133 # and preserve them for the rest of the main build step, because the child process environment will\r
1134 # evaporate as soon as it exits, we cannot get it in build step.\r
1135 #\r
ccaa7754 1136 PrebuildEnvFile = os.path.join(GlobalData.gConfDirectory, '.cache', '.PrebuildEnv')\r
f0dc69e6
YZ
1137 if os.path.isfile(PrebuildEnvFile):\r
1138 os.remove(PrebuildEnvFile)\r
1139 if os.path.isfile(self.PlatformBuildPath):\r
1140 os.remove(self.PlatformBuildPath)\r
1141 if sys.platform == "win32":\r
1142 args = ' && '.join((self.Prebuild, 'set > ' + PrebuildEnvFile))\r
b926f2f2 1143 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)\r
f0dc69e6
YZ
1144 else:\r
1145 args = ' && '.join((self.Prebuild, 'env > ' + PrebuildEnvFile))\r
34816e7e 1146 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)\r
f0dc69e6
YZ
1147\r
1148 # launch two threads to read the STDOUT and STDERR\r
1149 EndOfProcedure = Event()\r
1150 EndOfProcedure.clear()\r
1151 if Process.stdout:\r
1152 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))\r
1153 StdOutThread.setName("STDOUT-Redirector")\r
1154 StdOutThread.setDaemon(False)\r
1155 StdOutThread.start()\r
1156\r
1157 if Process.stderr:\r
1158 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))\r
1159 StdErrThread.setName("STDERR-Redirector")\r
1160 StdErrThread.setDaemon(False)\r
1161 StdErrThread.start()\r
1162 # waiting for program exit\r
1163 Process.wait()\r
1164\r
1165 if Process.stdout:\r
1166 StdOutThread.join()\r
1167 if Process.stderr:\r
1168 StdErrThread.join()\r
1169 if Process.returncode != 0 :\r
1170 EdkLogger.error("Prebuild", PREBUILD_ERROR, 'Prebuild process is not success!')\r
1171\r
1172 if os.path.exists(PrebuildEnvFile):\r
1173 f = open(PrebuildEnvFile)\r
1174 envs = f.readlines()\r
1175 f.close()\r
ccaa7754 1176 envs = itertools.imap(lambda l: l.split('=', 1), envs)\r
f0dc69e6
YZ
1177 envs = itertools.ifilter(lambda l: len(l) == 2, envs)\r
1178 envs = itertools.imap(lambda l: [i.strip() for i in l], envs)\r
1179 os.environ.update(dict(envs))\r
1180 EdkLogger.info("\n- Prebuild Done -\n")\r
1181\r
91048b0d 1182 def LaunchPostbuild(self):\r
f0dc69e6
YZ
1183 if self.Postbuild:\r
1184 EdkLogger.info("\n- Postbuild Start -\n")\r
1185 if sys.platform == "win32":\r
b926f2f2 1186 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)\r
f0dc69e6 1187 else:\r
34816e7e 1188 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)\r
f0dc69e6
YZ
1189 # launch two threads to read the STDOUT and STDERR\r
1190 EndOfProcedure = Event()\r
1191 EndOfProcedure.clear()\r
1192 if Process.stdout:\r
1193 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))\r
1194 StdOutThread.setName("STDOUT-Redirector")\r
1195 StdOutThread.setDaemon(False)\r
1196 StdOutThread.start()\r
1197\r
1198 if Process.stderr:\r
1199 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))\r
1200 StdErrThread.setName("STDERR-Redirector")\r
1201 StdErrThread.setDaemon(False)\r
1202 StdErrThread.start()\r
1203 # waiting for program exit\r
1204 Process.wait()\r
1205\r
1206 if Process.stdout:\r
1207 StdOutThread.join()\r
1208 if Process.stderr:\r
1209 StdErrThread.join()\r
1210 if Process.returncode != 0 :\r
1211 EdkLogger.error("Postbuild", POSTBUILD_ERROR, 'Postbuild process is not success!')\r
1212 EdkLogger.info("\n- Postbuild Done -\n")\r
52302d4d
LG
1213 ## Build a module or platform\r
1214 #\r
08dd311f 1215 # Create autogen code and makefile for a module or platform, and the launch\r
52302d4d
LG
1216 # "make" command to build it\r
1217 #\r
1218 # @param Target The target of build command\r
1219 # @param Platform The platform file\r
1220 # @param Module The module file\r
1221 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
1222 # @param ToolChain The name of toolchain to build\r
1223 # @param Arch The arch of the module/platform\r
1224 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
1225 # for dependent modules/Libraries\r
1226 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
1227 # for dependent modules/Libraries\r
1228 #\r
37de70b7 1229 def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False, FfsCommand={}):\r
4231a819 1230 if AutoGenObject is None:\r
52302d4d
LG
1231 return False\r
1232\r
1233 # skip file generation for cleanxxx targets, run and fds target\r
1234 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1235 # for target which must generate AutoGen code and makefile\r
1236 if not self.SkipAutoGen or Target == 'genc':\r
1237 self.Progress.Start("Generating code")\r
1238 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
1239 self.Progress.Stop("done!")\r
1240 if Target == "genc":\r
1241 return True\r
1242\r
1243 if not self.SkipAutoGen or Target == 'genmake':\r
1244 self.Progress.Start("Generating makefile")\r
37de70b7 1245 AutoGenObject.CreateMakeFile(CreateDepsMakeFile, FfsCommand)\r
52302d4d
LG
1246 self.Progress.Stop("done!")\r
1247 if Target == "genmake":\r
1248 return True\r
1249 else:\r
1250 # always recreate top/platform makefile when clean, just in case of inconsistency\r
1251 AutoGenObject.CreateCodeFile(False)\r
1252 AutoGenObject.CreateMakeFile(False)\r
1253\r
1254 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
1255 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
1256\r
1257 BuildCommand = AutoGenObject.BuildCommand\r
4231a819 1258 if BuildCommand is None or len(BuildCommand) == 0:\r
0d2711a6
LG
1259 EdkLogger.error("build", OPTION_MISSING,\r
1260 "No build command found for this module. "\r
4afd3d04 1261 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
0d2711a6
LG
1262 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
1263 ExtraData=str(AutoGenObject))\r
52302d4d 1264\r
03af2753
HC
1265 makefile = GenMake.BuildFile(AutoGenObject)._FILE_NAME_[GenMake.gMakeType]\r
1266\r
03af2753
HC
1267 # run\r
1268 if Target == 'run':\r
997a5d1b 1269 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))\r
03af2753
HC
1270 Command = '.\SecMain'\r
1271 os.chdir(RunDir)\r
1272 LaunchCommand(Command, RunDir)\r
1273 return True\r
1274\r
1275 # build modules\r
1276 if BuildModule:\r
1277 BuildCommand = BuildCommand + [Target]\r
1278 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
a0a2cd1e 1279 self.CreateAsBuiltInf()\r
03af2753
HC
1280 return True\r
1281\r
1282 # build library\r
1283 if Target == 'libraries':\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 return True\r
1288\r
1289 # build module\r
1290 if Target == 'modules':\r
1291 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1292 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']\r
1293 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1294 for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
1295 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']\r
1296 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
a0a2cd1e 1297 self.CreateAsBuiltInf()\r
03af2753
HC
1298 return True\r
1299\r
1300 # cleanlib\r
1301 if Target == 'cleanlib':\r
1302 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1303 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))\r
1304 if os.path.exists(LibMakefile):\r
1305 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
1306 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1307 return True\r
1308\r
1309 # clean\r
1310 if Target == 'clean':\r
1311 for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
1312 ModMakefile = os.path.normpath(os.path.join(Mod, makefile))\r
1313 if os.path.exists(ModMakefile):\r
1314 NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']\r
1315 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1316 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1317 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))\r
1318 if os.path.exists(LibMakefile):\r
1319 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
1320 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1321 return True\r
1322\r
1323 # cleanall\r
1324 if Target == 'cleanall':\r
1325 try:\r
1326 #os.rmdir(AutoGenObject.BuildDir)\r
1327 RemoveDirectory(AutoGenObject.BuildDir, True)\r
5b0671c1 1328 except WindowsError as X:\r
03af2753
HC
1329 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1330 return True\r
1331\r
1332 ## Build a module or platform\r
1333 #\r
1334 # Create autogen code and makefile for a module or platform, and the launch\r
1335 # "make" command to build it\r
1336 #\r
1337 # @param Target The target of build command\r
1338 # @param Platform The platform file\r
1339 # @param Module The module file\r
1340 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
1341 # @param ToolChain The name of toolchain to build\r
1342 # @param Arch The arch of the module/platform\r
1343 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
1344 # for dependent modules/Libraries\r
1345 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
1346 # for dependent modules/Libraries\r
1347 #\r
1348 def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):\r
4231a819 1349 if AutoGenObject is None:\r
03af2753
HC
1350 return False\r
1351\r
1352 # skip file generation for cleanxxx targets, run and fds target\r
1353 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1354 # for target which must generate AutoGen code and makefile\r
1355 if not self.SkipAutoGen or Target == 'genc':\r
1356 self.Progress.Start("Generating code")\r
1357 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
1358 self.Progress.Stop("done!")\r
1359 if Target == "genc":\r
1360 return True\r
1361\r
1362 if not self.SkipAutoGen or Target == 'genmake':\r
1363 self.Progress.Start("Generating makefile")\r
1364 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)\r
1365 #AutoGenObject.CreateAsBuiltInf()\r
1366 self.Progress.Stop("done!")\r
1367 if Target == "genmake":\r
1368 return True\r
1369 else:\r
1370 # always recreate top/platform makefile when clean, just in case of inconsistency\r
1371 AutoGenObject.CreateCodeFile(False)\r
1372 AutoGenObject.CreateMakeFile(False)\r
1373\r
1374 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
1375 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
1376\r
1377 BuildCommand = AutoGenObject.BuildCommand\r
4231a819 1378 if BuildCommand is None or len(BuildCommand) == 0:\r
03af2753
HC
1379 EdkLogger.error("build", OPTION_MISSING,\r
1380 "No build command found for this module. "\r
1381 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
1382 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
1383 ExtraData=str(AutoGenObject))\r
1384\r
b0e23cf3
YL
1385 # build modules\r
1386 if BuildModule:\r
1387 if Target != 'fds':\r
1388 BuildCommand = BuildCommand + [Target]\r
1b8eca8b 1389 AutoGenObject.BuildTime = LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
b0e23cf3
YL
1390 self.CreateAsBuiltInf()\r
1391 return True\r
1392\r
03af2753
HC
1393 # genfds\r
1394 if Target == 'fds':\r
1395 LaunchCommand(AutoGenObject.GenFdsCommand, AutoGenObject.MakeFileDir)\r
1396 return True\r
1397\r
1398 # run\r
1399 if Target == 'run':\r
997a5d1b 1400 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))\r
03af2753
HC
1401 Command = '.\SecMain'\r
1402 os.chdir(RunDir)\r
1403 LaunchCommand(Command, RunDir)\r
1404 return True\r
1405\r
03af2753
HC
1406 # build library\r
1407 if Target == 'libraries':\r
1408 pass\r
1409\r
1410 # not build modules\r
1411\r
1412\r
1413 # cleanall\r
52302d4d
LG
1414 if Target == 'cleanall':\r
1415 try:\r
1416 #os.rmdir(AutoGenObject.BuildDir)\r
1417 RemoveDirectory(AutoGenObject.BuildDir, True)\r
5b0671c1 1418 except WindowsError as X:\r
52302d4d
LG
1419 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1420 return True\r
1421\r
6780eef1 1422 ## Rebase module image and Get function address for the input module list.\r
52302d4d
LG
1423 #\r
1424 def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):\r
1425 if ModeIsSmm:\r
1426 AddrIsOffset = False\r
98120f5f 1427 for InfFile in ModuleList:\r
da92f276
LG
1428 sys.stdout.write (".")\r
1429 sys.stdout.flush()\r
52302d4d
LG
1430 ModuleInfo = ModuleList[InfFile]\r
1431 ModuleName = ModuleInfo.BaseName\r
f3decdc3
LG
1432 ModuleOutputImage = ModuleInfo.Image.FileName\r
1433 ModuleDebugImage = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')\r
52302d4d
LG
1434 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1435 if not ModeIsSmm:\r
1436 BaseAddress = BaseAddress - ModuleInfo.Image.Size\r
1437 #\r
1438 # Update Image to new BaseAddress by GenFw tool\r
1439 #\r
f3decdc3 1440 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
47fea6af 1441 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
52302d4d
LG
1442 else:\r
1443 #\r
1444 # Set new address to the section header only for SMM driver.\r
1445 #\r
f3decdc3 1446 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
47fea6af 1447 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
52302d4d
LG
1448 #\r
1449 # Collect funtion address from Map file\r
1450 #\r
f3decdc3 1451 ImageMapTable = ModuleOutputImage.replace('.efi', '.map')\r
52302d4d
LG
1452 FunctionList = []\r
1453 if os.path.exists(ImageMapTable):\r
1454 OrigImageBaseAddress = 0\r
47fea6af 1455 ImageMap = open(ImageMapTable, 'r')\r
52302d4d
LG
1456 for LinStr in ImageMap:\r
1457 if len (LinStr.strip()) == 0:\r
1458 continue\r
1459 #\r
1460 # Get the preferred address set on link time.\r
1461 #\r
1462 if LinStr.find ('Preferred load address is') != -1:\r
1463 StrList = LinStr.split()\r
1464 OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)\r
1465\r
1466 StrList = LinStr.split()\r
1467 if len (StrList) > 4:\r
47fea6af 1468 if StrList[3] == 'f' or StrList[3] == 'F':\r
52302d4d
LG
1469 Name = StrList[1]\r
1470 RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress\r
1471 FunctionList.append ((Name, RelativeAddress))\r
1472 if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'):\r
1473 #\r
1474 # Get the real entry point address for IPF image.\r
1475 #\r
1476 ModuleInfo.Image.EntryPoint = RelativeAddress\r
1477 ImageMap.close()\r
1478 #\r
1479 # Add general information.\r
1480 #\r
1481 if ModeIsSmm:\r
1482 MapBuffer.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1483 elif AddrIsOffset:\r
1484 MapBuffer.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))\r
1485 else:\r
1486 MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1487 #\r
1488 # Add guid and general seciton section.\r
1489 #\r
1490 TextSectionAddress = 0\r
1491 DataSectionAddress = 0\r
1492 for SectionHeader in ModuleInfo.Image.SectionHeaderList:\r
1493 if SectionHeader[0] == '.text':\r
1494 TextSectionAddress = SectionHeader[1]\r
1495 elif SectionHeader[0] in ['.data', '.sdata']:\r
1496 DataSectionAddress = SectionHeader[1]\r
1497 if AddrIsOffset:\r
4afd3d04 1498 MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))\r
52302d4d 1499 else:\r
4afd3d04 1500 MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))\r
f3decdc3
LG
1501 #\r
1502 # Add debug image full path.\r
1503 #\r
1504 MapBuffer.write('(IMAGE=%s)\n\n' % (ModuleDebugImage))\r
52302d4d
LG
1505 #\r
1506 # Add funtion address\r
1507 #\r
1508 for Function in FunctionList:\r
1509 if AddrIsOffset:\r
1510 MapBuffer.write(' -0x%010X %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))\r
1511 else:\r
1512 MapBuffer.write(' 0x%010X %s\n' % (BaseAddress + Function[1], Function[0]))\r
1513 ImageMap.close()\r
1514\r
1515 #\r
1516 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1517 #\r
1518 if ModeIsSmm:\r
1519 BaseAddress = BaseAddress + ModuleInfo.Image.Size\r
1520\r
1521 ## Collect MAP information of all FVs\r
1522 #\r
636f2be6 1523 def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):\r
0d2711a6 1524 if self.Fdf:\r
52302d4d 1525 # First get the XIP base address for FV map file.\r
636f2be6 1526 GuidPattern = re.compile("[-a-fA-F0-9]+")\r
f3decdc3 1527 GuidName = re.compile("\(GUID=[-a-fA-F0-9]+")\r
9eb87141 1528 for FvName in Wa.FdfProfile.FvDict:\r
52302d4d
LG
1529 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')\r
1530 if not os.path.exists(FvMapBuffer):\r
1531 continue\r
1be2ed90 1532 FvMap = open(FvMapBuffer, 'r')\r
52302d4d
LG
1533 #skip FV size information\r
1534 FvMap.readline()\r
1535 FvMap.readline()\r
1536 FvMap.readline()\r
1537 FvMap.readline()\r
636f2be6
LG
1538 for Line in FvMap:\r
1539 MatchGuid = GuidPattern.match(Line)\r
4231a819 1540 if MatchGuid is not None:\r
636f2be6
LG
1541 #\r
1542 # Replace GUID with module name\r
1543 #\r
1544 GuidString = MatchGuid.group()\r
1545 if GuidString.upper() in ModuleList:\r
1546 Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)\r
caf74495 1547 MapBuffer.write(Line)\r
f3decdc3
LG
1548 #\r
1549 # Add the debug image full path.\r
1550 #\r
1551 MatchGuid = GuidName.match(Line)\r
4231a819 1552 if MatchGuid is not None:\r
f3decdc3
LG
1553 GuidString = MatchGuid.group().split("=")[1]\r
1554 if GuidString.upper() in ModuleList:\r
1555 MapBuffer.write('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))\r
1556\r
52302d4d
LG
1557 FvMap.close()\r
1558\r
1559 ## Collect MAP information of all modules\r
1560 #\r
1561 def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):\r
da92f276
LG
1562 sys.stdout.write ("Generate Load Module At Fix Address Map")\r
1563 sys.stdout.flush()\r
52302d4d
LG
1564 PatchEfiImageList = []\r
1565 PeiModuleList = {}\r
1566 BtModuleList = {}\r
1567 RtModuleList = {}\r
1568 SmmModuleList = {}\r
1569 PeiSize = 0\r
1570 BtSize = 0\r
1571 RtSize = 0\r
1572 # reserve 4K size in SMRAM to make SMM module address not from 0.\r
1573 SmmSize = 0x1000\r
1574 IsIpfPlatform = False\r
1575 if 'IPF' in self.ArchList:\r
1576 IsIpfPlatform = True\r
636f2be6
LG
1577 for ModuleGuid in ModuleList:\r
1578 Module = ModuleList[ModuleGuid]\r
52302d4d 1579 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)\r
4afd3d04 1580\r
52302d4d
LG
1581 OutputImageFile = ''\r
1582 for ResultFile in Module.CodaTargetList:\r
1583 if str(ResultFile.Target).endswith('.efi'):\r
1584 #\r
1585 # module list for PEI, DXE, RUNTIME and SMM\r
1586 #\r
1587 OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')\r
1588 ImageClass = PeImageClass (OutputImageFile)\r
1589 if not ImageClass.IsValid:\r
1590 EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)\r
f3decdc3 1591 ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)\r
0c60e60b 1592 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
1593 PeiModuleList[Module.MetaFile] = ImageInfo\r
1594 PeiSize += ImageInfo.Image.Size\r
0c60e60b 1595 elif Module.ModuleType in [EDK_COMPONENT_TYPE_BS_DRIVER, SUP_MODULE_DXE_DRIVER, SUP_MODULE_UEFI_DRIVER]:\r
52302d4d
LG
1596 BtModuleList[Module.MetaFile] = ImageInfo\r
1597 BtSize += ImageInfo.Image.Size\r
0c60e60b 1598 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
1599 RtModuleList[Module.MetaFile] = ImageInfo\r
1600 #IPF runtime driver needs to be at 2 page alignment.\r
1601 if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0:\r
1602 ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000\r
1603 RtSize += ImageInfo.Image.Size\r
8bb63e37 1604 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
1605 SmmModuleList[Module.MetaFile] = ImageInfo\r
1606 SmmSize += ImageInfo.Image.Size\r
8bb63e37 1607 if Module.ModuleType == SUP_MODULE_DXE_SMM_DRIVER:\r
888d7f19 1608 PiSpecVersion = Module.Module.Specification.get('PI_SPECIFICATION_VERSION', '0x00000000')\r
52302d4d 1609 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.\r
da92f276 1610 if int(PiSpecVersion, 16) < 0x0001000A:\r
52302d4d
LG
1611 BtModuleList[Module.MetaFile] = ImageInfo\r
1612 BtSize += ImageInfo.Image.Size\r
1613 break\r
1614 #\r
1615 # EFI image is final target.\r
1616 # Check EFI image contains patchable FixAddress related PCDs.\r
1617 #\r
1618 if OutputImageFile != '':\r
1619 ModuleIsPatch = False\r
1620 for Pcd in Module.ModulePcdList:\r
eece4292 1621 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:\r
52302d4d
LG
1622 ModuleIsPatch = True\r
1623 break\r
1624 if not ModuleIsPatch:\r
1625 for Pcd in Module.LibraryPcdList:\r
eece4292 1626 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:\r
52302d4d
LG
1627 ModuleIsPatch = True\r
1628 break\r
4afd3d04 1629\r
52302d4d
LG
1630 if not ModuleIsPatch:\r
1631 continue\r
1632 #\r
1633 # Module includes the patchable load fix address PCDs.\r
4afd3d04 1634 # It will be fixed up later.\r
52302d4d
LG
1635 #\r
1636 PatchEfiImageList.append (OutputImageFile)\r
4afd3d04 1637\r
52302d4d
LG
1638 #\r
1639 # Get Top Memory address\r
1640 #\r
1641 ReservedRuntimeMemorySize = 0\r
1642 TopMemoryAddress = 0\r
1643 if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:\r
1644 TopMemoryAddress = 0\r
1645 else:\r
1646 TopMemoryAddress = self.LoadFixAddress\r
1647 if TopMemoryAddress < RtSize + BtSize + PeiSize:\r
1648 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")\r
1649 # Make IPF runtime driver at 2 page alignment.\r
1650 if IsIpfPlatform:\r
1651 ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000\r
1652 RtSize = RtSize + ReservedRuntimeMemorySize\r
1653\r
1654 #\r
1655 # Patch FixAddress related PCDs into EFI image\r
1656 #\r
4afd3d04 1657 for EfiImage in PatchEfiImageList:\r
52302d4d
LG
1658 EfiImageMap = EfiImage.replace('.efi', '.map')\r
1659 if not os.path.exists(EfiImageMap):\r
1660 continue\r
1661 #\r
1662 # Get PCD offset in EFI image by GenPatchPcdTable function\r
1663 #\r
4afd3d04 1664 PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)\r
52302d4d
LG
1665 #\r
1666 # Patch real PCD value by PatchPcdValue tool\r
1667 #\r
1668 for PcdInfo in PcdTable:\r
1669 ReturnValue = 0\r
1670 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:\r
47fea6af 1671 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize / 0x1000))\r
52302d4d 1672 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:\r
47fea6af 1673 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize / 0x1000))\r
52302d4d 1674 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:\r
47fea6af 1675 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize / 0x1000))\r
52302d4d 1676 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:\r
47fea6af 1677 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize / 0x1000))\r
52302d4d
LG
1678 if ReturnValue != 0:\r
1679 EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)\r
4afd3d04 1680\r
47fea6af
YZ
1681 MapBuffer.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize / 0x1000))\r
1682 MapBuffer.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize / 0x1000))\r
1683 MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize / 0x1000))\r
52302d4d 1684 if len (SmmModuleList) > 0:\r
47fea6af 1685 MapBuffer.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize / 0x1000))\r
4afd3d04
LG
1686\r
1687 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize\r
52302d4d 1688 BtBaseAddr = TopMemoryAddress - RtSize\r
4afd3d04 1689 RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize\r
52302d4d
LG
1690\r
1691 self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)\r
1692 self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)\r
1693 self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)\r
47fea6af 1694 self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset=False, ModeIsSmm=True)\r
52302d4d 1695 MapBuffer.write('\n\n')\r
da92f276
LG
1696 sys.stdout.write ("\n")\r
1697 sys.stdout.flush()\r
4afd3d04 1698\r
52302d4d
LG
1699 ## Save platform Map file\r
1700 #\r
1701 def _SaveMapFile (self, MapBuffer, Wa):\r
1702 #\r
1703 # Map file path is got.\r
1704 #\r
1705 MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')\r
1706 #\r
1707 # Save address map into MAP file.\r
1708 #\r
40d841f6 1709 SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)\r
da92f276
LG
1710 MapBuffer.close()\r
1711 if self.LoadFixAddress != 0:\r
47fea6af 1712 sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath))\r
da92f276 1713 sys.stdout.flush()\r
52302d4d
LG
1714\r
1715 ## Build active platform for different build targets and different tool chains\r
1716 #\r
1717 def _BuildPlatform(self):\r
f0dc69e6 1718 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)\r
52302d4d 1719 for BuildTarget in self.BuildTargetList:\r
0d2711a6 1720 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
40b4e21d 1721 index = 0\r
52302d4d 1722 for ToolChain in self.ToolChainList:\r
0d2711a6
LG
1723 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
1724 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
40b4e21d
YZ
1725 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1726 index += 1\r
52302d4d
LG
1727 Wa = WorkspaceAutoGen(\r
1728 self.WorkspaceDir,\r
0d2711a6 1729 self.PlatformFile,\r
52302d4d
LG
1730 BuildTarget,\r
1731 ToolChain,\r
1732 self.ArchList,\r
1733 self.BuildDatabase,\r
1734 self.TargetTxt,\r
1735 self.ToolDef,\r
1736 self.Fdf,\r
1737 self.FdList,\r
1738 self.FvList,\r
4234283c 1739 self.CapList,\r
f3decdc3 1740 self.SkuId,\r
9508d0fa
LG
1741 self.UniFlag,\r
1742 self.Progress\r
52302d4d 1743 )\r
0d2711a6
LG
1744 self.Fdf = Wa.FdfFile\r
1745 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
52302d4d
LG
1746 self.BuildReport.AddPlatformReport(Wa)\r
1747 self.Progress.Stop("done!")\r
37de70b7
YZ
1748\r
1749 # Add ffs build to makefile\r
1750 CmdListDict = {}\r
1751 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
1752 CmdListDict = self._GenFfsCmd()\r
1753\r
03af2753
HC
1754 for Arch in Wa.ArchList:\r
1755 GlobalData.gGlobalDefines['ARCH'] = Arch\r
1756 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
a0a2cd1e
FB
1757 for Module in Pa.Platform.Modules:\r
1758 # Get ModuleAutoGen object to generate C code file and makefile\r
1759 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
4231a819 1760 if Ma is None:\r
a0a2cd1e
FB
1761 continue\r
1762 self.BuildModules.append(Ma)\r
37de70b7 1763 self._BuildPa(self.Target, Pa, FfsCommand=CmdListDict)\r
4afd3d04 1764\r
52302d4d 1765 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1766 if self.Target in ["", "all", "fds"]:\r
0d2711a6
LG
1767 for Arch in Wa.ArchList:\r
1768 GlobalData.gGlobalDefines['ARCH'] = Arch\r
52302d4d
LG
1769 #\r
1770 # Check whether the set fix address is above 4G for 32bit image.\r
1771 #\r
1772 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
0d2711a6 1773 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
1774 #\r
1775 # Get Module List\r
1776 #\r
636f2be6 1777 ModuleList = {}\r
52302d4d
LG
1778 for Pa in Wa.AutoGenObjectList:\r
1779 for Ma in Pa.ModuleAutoGenList:\r
4231a819 1780 if Ma is None:\r
52302d4d
LG
1781 continue\r
1782 if not Ma.IsLibrary:\r
636f2be6 1783 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d 1784\r
86379ac4 1785 MapBuffer = BytesIO('')\r
636f2be6
LG
1786 if self.LoadFixAddress != 0:\r
1787 #\r
1788 # Rebase module to the preferred memory address before GenFds\r
1789 #\r
1790 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
0d2711a6 1791 if self.Fdf:\r
b0e23cf3
YL
1792 #\r
1793 # create FDS again for the updated EFI image\r
1794 #\r
1795 self._Build("fds", Wa)\r
52302d4d
LG
1796 #\r
1797 # Create MAP file for all platform FVs after GenFds.\r
1798 #\r
636f2be6 1799 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1800 #\r
1801 # Save MAP buffer into MAP file.\r
1802 #\r
1803 self._SaveMapFile (MapBuffer, Wa)\r
1804\r
1805 ## Build active module for different build targets, different tool chains and different archs\r
1806 #\r
1807 def _BuildModule(self):\r
1808 for BuildTarget in self.BuildTargetList:\r
0d2711a6 1809 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
40b4e21d 1810 index = 0\r
52302d4d 1811 for ToolChain in self.ToolChainList:\r
1b8eca8b 1812 WorkspaceAutoGenTime = time.time()\r
0d2711a6 1813 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
4afd3d04 1814 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
40b4e21d
YZ
1815 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1816 index += 1\r
52302d4d
LG
1817 #\r
1818 # module build needs platform build information, so get platform\r
1819 # AutoGen first\r
1820 #\r
1821 Wa = WorkspaceAutoGen(\r
1822 self.WorkspaceDir,\r
0d2711a6 1823 self.PlatformFile,\r
52302d4d
LG
1824 BuildTarget,\r
1825 ToolChain,\r
1826 self.ArchList,\r
1827 self.BuildDatabase,\r
1828 self.TargetTxt,\r
1829 self.ToolDef,\r
1830 self.Fdf,\r
1831 self.FdList,\r
1832 self.FvList,\r
4234283c 1833 self.CapList,\r
f3decdc3 1834 self.SkuId,\r
9508d0fa
LG
1835 self.UniFlag,\r
1836 self.Progress,\r
1837 self.ModuleFile\r
52302d4d 1838 )\r
0d2711a6
LG
1839 self.Fdf = Wa.FdfFile\r
1840 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
52302d4d 1841 Wa.CreateMakeFile(False)\r
37de70b7
YZ
1842 # Add ffs build to makefile\r
1843 CmdListDict = None\r
1844 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
1845 CmdListDict = self._GenFfsCmd()\r
52302d4d
LG
1846 self.Progress.Stop("done!")\r
1847 MaList = []\r
1b8eca8b
YZ
1848 ExitFlag = threading.Event()\r
1849 ExitFlag.clear()\r
1850 self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))\r
0d2711a6 1851 for Arch in Wa.ArchList:\r
1b8eca8b 1852 AutoGenStart = time.time()\r
0d2711a6 1853 GlobalData.gGlobalDefines['ARCH'] = Arch\r
16bad1fb
YZ
1854 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
1855 for Module in Pa.Platform.Modules:\r
fbe53845 1856 if self.ModuleFile.Dir == Module.Dir and self.ModuleFile.Name == Module.Name:\r
16bad1fb 1857 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
4231a819 1858 if Ma is None: continue\r
19bf8314
YZ
1859 MaList.append(Ma)\r
1860 if Ma.CanSkipbyHash():\r
1861 self.HashSkipModules.append(Ma)\r
1862 continue\r
119d8c42
YZ
1863 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'\r
1864 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1865 # for target which must generate AutoGen code and makefile\r
1866 if not self.SkipAutoGen or self.Target == 'genc':\r
cd498216 1867 self.Progress.Start("Generating code")\r
119d8c42 1868 Ma.CreateCodeFile(True)\r
cd498216
YZ
1869 self.Progress.Stop("done!")\r
1870 if self.Target == "genc":\r
1871 return True\r
119d8c42 1872 if not self.SkipAutoGen or self.Target == 'genmake':\r
cd498216 1873 self.Progress.Start("Generating makefile")\r
37de70b7
YZ
1874 if CmdListDict and self.Fdf and (Module.File, Arch) in CmdListDict:\r
1875 Ma.CreateMakeFile(True, CmdListDict[Module.File, Arch])\r
1876 del CmdListDict[Module.File, Arch]\r
1877 else:\r
1878 Ma.CreateMakeFile(True)\r
cd498216
YZ
1879 self.Progress.Stop("done!")\r
1880 if self.Target == "genmake":\r
1881 return True\r
16bad1fb 1882 self.BuildModules.append(Ma)\r
1b8eca8b
YZ
1883 self.AutoGenTime += int(round((time.time() - AutoGenStart)))\r
1884 MakeStart = time.time()\r
1885 for Ma in self.BuildModules:\r
1886 if not Ma.IsBinaryModule:\r
1887 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))\r
1888 # Break build if any build thread has error\r
1889 if BuildTask.HasError():\r
1890 # we need a full version of makefile for platform\r
1891 ExitFlag.set()\r
1892 BuildTask.WaitForComplete()\r
1893 Pa.CreateMakeFile(False)\r
1894 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1895 # Start task scheduler\r
1896 if not BuildTask.IsOnGoing():\r
1897 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
1898\r
1899 # in case there's an interruption. we need a full version of makefile for platform\r
1900 Pa.CreateMakeFile(False)\r
1901 if BuildTask.HasError():\r
1902 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1903 self.MakeTime += int(round((time.time() - MakeStart)))\r
1904\r
1905 MakeContiue = time.time()\r
1906 ExitFlag.set()\r
1907 BuildTask.WaitForComplete()\r
1908 self.CreateAsBuiltInf()\r
1909 self.MakeTime += int(round((time.time() - MakeContiue)))\r
1910 if BuildTask.HasError():\r
1911 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
d5d56f1b
LG
1912\r
1913 self.BuildReport.AddPlatformReport(Wa, MaList)\r
52302d4d
LG
1914 if MaList == []:\r
1915 EdkLogger.error(\r
1916 'build',\r
1917 BUILD_ERROR,\r
1918 "Module for [%s] is not a component of active platform."\\r
1919 " Please make sure that the ARCH and inf file path are"\\r
47fea6af 1920 " given in the same as in [%s]" % \\r
0d2711a6 1921 (', '.join(Wa.ArchList), self.PlatformFile),\r
52302d4d
LG
1922 ExtraData=self.ModuleFile\r
1923 )\r
1924 # Create MAP file when Load Fix Address is enabled.\r
0d2711a6
LG
1925 if self.Target == "fds" and self.Fdf:\r
1926 for Arch in Wa.ArchList:\r
52302d4d
LG
1927 #\r
1928 # Check whether the set fix address is above 4G for 32bit image.\r
1929 #\r
1930 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1931 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
1932 #\r
1933 # Get Module List\r
1934 #\r
636f2be6 1935 ModuleList = {}\r
52302d4d
LG
1936 for Pa in Wa.AutoGenObjectList:\r
1937 for Ma in Pa.ModuleAutoGenList:\r
4231a819 1938 if Ma is None:\r
52302d4d
LG
1939 continue\r
1940 if not Ma.IsLibrary:\r
636f2be6 1941 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d 1942\r
86379ac4 1943 MapBuffer = BytesIO('')\r
636f2be6
LG
1944 if self.LoadFixAddress != 0:\r
1945 #\r
1946 # Rebase module to the preferred memory address before GenFds\r
1947 #\r
1948 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
b0e23cf3
YL
1949 #\r
1950 # create FDS again for the updated EFI image\r
1951 #\r
1b8eca8b 1952 GenFdsStart = time.time()\r
b0e23cf3 1953 self._Build("fds", Wa)\r
1b8eca8b 1954 self.GenFdsTime += int(round((time.time() - GenFdsStart)))\r
52302d4d
LG
1955 #\r
1956 # Create MAP file for all platform FVs after GenFds.\r
1957 #\r
636f2be6 1958 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1959 #\r
1960 # Save MAP buffer into MAP file.\r
1961 #\r
1962 self._SaveMapFile (MapBuffer, Wa)\r
1963\r
37de70b7 1964 def _GenFfsCmd(self):\r
f7496d71 1965 # convert dictionary of Cmd:(Inf,Arch)\r
9eb87141
CJ
1966 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...\r
1967 CmdSetDict = defaultdict(set)\r
37de70b7
YZ
1968 GenFfsDict = GenFds.GenFfsMakefile('', GlobalData.gFdfParser, self, self.ArchList, GlobalData)\r
1969 for Cmd in GenFfsDict:\r
1970 tmpInf, tmpArch = GenFfsDict[Cmd]\r
9eb87141
CJ
1971 CmdSetDict[tmpInf, tmpArch].add(Cmd)\r
1972 return CmdSetDict\r
37de70b7 1973\r
52302d4d
LG
1974 ## Build a platform in multi-thread mode\r
1975 #\r
1976 def _MultiThreadBuildPlatform(self):\r
f0dc69e6 1977 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)\r
52302d4d 1978 for BuildTarget in self.BuildTargetList:\r
0d2711a6 1979 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
40b4e21d 1980 index = 0\r
52302d4d 1981 for ToolChain in self.ToolChainList:\r
1b8eca8b 1982 WorkspaceAutoGenTime = time.time()\r
0d2711a6 1983 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
4afd3d04 1984 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
40b4e21d
YZ
1985 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1986 index += 1\r
52302d4d
LG
1987 Wa = WorkspaceAutoGen(\r
1988 self.WorkspaceDir,\r
0d2711a6 1989 self.PlatformFile,\r
52302d4d
LG
1990 BuildTarget,\r
1991 ToolChain,\r
1992 self.ArchList,\r
1993 self.BuildDatabase,\r
1994 self.TargetTxt,\r
1995 self.ToolDef,\r
1996 self.Fdf,\r
1997 self.FdList,\r
1998 self.FvList,\r
4234283c 1999 self.CapList,\r
f3decdc3 2000 self.SkuId,\r
9508d0fa
LG
2001 self.UniFlag,\r
2002 self.Progress\r
52302d4d 2003 )\r
0d2711a6
LG
2004 self.Fdf = Wa.FdfFile\r
2005 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
52302d4d
LG
2006 self.BuildReport.AddPlatformReport(Wa)\r
2007 Wa.CreateMakeFile(False)\r
2008\r
37de70b7
YZ
2009 # Add ffs build to makefile\r
2010 CmdListDict = None\r
2011 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
2012 CmdListDict = self._GenFfsCmd()\r
2013\r
52302d4d
LG
2014 # multi-thread exit flag\r
2015 ExitFlag = threading.Event()\r
2016 ExitFlag.clear()\r
1b8eca8b 2017 self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))\r
0d2711a6 2018 for Arch in Wa.ArchList:\r
1b8eca8b 2019 AutoGenStart = time.time()\r
0d2711a6 2020 GlobalData.gGlobalDefines['ARCH'] = Arch\r
52302d4d 2021 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
4231a819 2022 if Pa is None:\r
52302d4d 2023 continue\r
a0a2cd1e
FB
2024 ModuleList = []\r
2025 for Inf in Pa.Platform.Modules:\r
2026 ModuleList.append(Inf)\r
2027 # Add the INF only list in FDF\r
4231a819 2028 if GlobalData.gFdfParser is not None:\r
a0a2cd1e
FB
2029 for InfName in GlobalData.gFdfParser.Profile.InfList:\r
2030 Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)\r
2031 if Inf in Pa.Platform.Modules:\r
2032 continue\r
2033 ModuleList.append(Inf)\r
2034 for Module in ModuleList:\r
52302d4d
LG
2035 # Get ModuleAutoGen object to generate C code file and makefile\r
2036 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
f7496d71 2037\r
4231a819 2038 if Ma is None:\r
52302d4d 2039 continue\r
36d083ef 2040 if Ma.CanSkipbyHash():\r
83397f95 2041 self.HashSkipModules.append(Ma)\r
36d083ef
YZ
2042 continue\r
2043\r
52302d4d
LG
2044 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'\r
2045 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
2046 # for target which must generate AutoGen code and makefile\r
2047 if not self.SkipAutoGen or self.Target == 'genc':\r
2048 Ma.CreateCodeFile(True)\r
2049 if self.Target == "genc":\r
2050 continue\r
2051\r
2052 if not self.SkipAutoGen or self.Target == 'genmake':\r
37de70b7
YZ
2053 if CmdListDict and self.Fdf and (Module.File, Arch) in CmdListDict:\r
2054 Ma.CreateMakeFile(True, CmdListDict[Module.File, Arch])\r
2055 del CmdListDict[Module.File, Arch]\r
2056 else:\r
2057 Ma.CreateMakeFile(True)\r
52302d4d
LG
2058 if self.Target == "genmake":\r
2059 continue\r
a0a2cd1e 2060 self.BuildModules.append(Ma)\r
e8a47801 2061 self.Progress.Stop("done!")\r
1b8eca8b
YZ
2062 self.AutoGenTime += int(round((time.time() - AutoGenStart)))\r
2063 MakeStart = time.time()\r
a0a2cd1e 2064 for Ma in self.BuildModules:\r
52302d4d 2065 # Generate build task for the module\r
a0a2cd1e
FB
2066 if not Ma.IsBinaryModule:\r
2067 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))\r
52302d4d
LG
2068 # Break build if any build thread has error\r
2069 if BuildTask.HasError():\r
2070 # we need a full version of makefile for platform\r
2071 ExitFlag.set()\r
2072 BuildTask.WaitForComplete()\r
2073 Pa.CreateMakeFile(False)\r
2074 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
2075 # Start task scheduler\r
2076 if not BuildTask.IsOnGoing():\r
2077 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
2078\r
2079 # in case there's an interruption. we need a full version of makefile for platform\r
2080 Pa.CreateMakeFile(False)\r
2081 if BuildTask.HasError():\r
2082 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1b8eca8b 2083 self.MakeTime += int(round((time.time() - MakeStart)))\r
52302d4d 2084\r
1b8eca8b 2085 MakeContiue = time.time()\r
64b2609f
LG
2086 #\r
2087 # Save temp tables to a TmpTableDict.\r
2088 #\r
2089 for Key in Wa.BuildDatabase._CACHE_:\r
2090 if Wa.BuildDatabase._CACHE_[Key]._RawData and Wa.BuildDatabase._CACHE_[Key]._RawData._Table and Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table:\r
2091 if TemporaryTablePattern.match(Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table):\r
2092 TmpTableDict[Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table] = Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Cur\r
2093 #\r
52302d4d
LG
2094 #\r
2095 # All modules have been put in build tasks queue. Tell task scheduler\r
2096 # to exit if all tasks are completed\r
2097 #\r
2098 ExitFlag.set()\r
2099 BuildTask.WaitForComplete()\r
a0a2cd1e 2100 self.CreateAsBuiltInf()\r
1b8eca8b 2101 self.MakeTime += int(round((time.time() - MakeContiue)))\r
52302d4d
LG
2102 #\r
2103 # Check for build error, and raise exception if one\r
2104 # has been signaled.\r
2105 #\r
2106 if BuildTask.HasError():\r
2107 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
2108\r
2109 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 2110 if self.Target in ["", "all", "fds"]:\r
0d2711a6 2111 for Arch in Wa.ArchList:\r
52302d4d
LG
2112 #\r
2113 # Check whether the set fix address is above 4G for 32bit image.\r
2114 #\r
2115 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
2116 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
2117 #\r
2118 # Get Module List\r
2119 #\r
636f2be6 2120 ModuleList = {}\r
52302d4d
LG
2121 for Pa in Wa.AutoGenObjectList:\r
2122 for Ma in Pa.ModuleAutoGenList:\r
4231a819 2123 if Ma is None:\r
52302d4d
LG
2124 continue\r
2125 if not Ma.IsLibrary:\r
636f2be6 2126 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
2127 #\r
2128 # Rebase module to the preferred memory address before GenFds\r
2129 #\r
86379ac4 2130 MapBuffer = BytesIO('')\r
636f2be6
LG
2131 if self.LoadFixAddress != 0:\r
2132 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
52302d4d 2133\r
0d2711a6 2134 if self.Fdf:\r
f3decdc3
LG
2135 #\r
2136 # Generate FD image if there's a FDF file found\r
2137 #\r
1b8eca8b 2138 GenFdsStart = time.time()\r
03af2753
HC
2139 LaunchCommand(Wa.GenFdsCommand, os.getcwd())\r
2140\r
52302d4d
LG
2141 #\r
2142 # Create MAP file for all platform FVs after GenFds.\r
2143 #\r
636f2be6 2144 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
1b8eca8b 2145 self.GenFdsTime += int(round((time.time() - GenFdsStart)))\r
52302d4d
LG
2146 #\r
2147 # Save MAP buffer into MAP file.\r
2148 #\r
2149 self._SaveMapFile(MapBuffer, Wa)\r
2150\r
2151 ## Generate GuidedSectionTools.txt in the FV directories.\r
2152 #\r
2153 def CreateGuidedSectionToolsFile(self):\r
0d2711a6
LG
2154 for BuildTarget in self.BuildTargetList:\r
2155 for ToolChain in self.ToolChainList:\r
2156 Wa = WorkspaceAutoGen(\r
2157 self.WorkspaceDir,\r
2158 self.PlatformFile,\r
2159 BuildTarget,\r
2160 ToolChain,\r
2161 self.ArchList,\r
2162 self.BuildDatabase,\r
2163 self.TargetTxt,\r
2164 self.ToolDef,\r
2165 self.Fdf,\r
2166 self.FdList,\r
2167 self.FvList,\r
2168 self.CapList,\r
2169 self.SkuId,\r
2170 self.UniFlag\r
2171 )\r
2172 FvDir = Wa.FvDir\r
2173 if not os.path.exists(FvDir):\r
2174 continue\r
2175\r
4afd3d04 2176 for Arch in self.ArchList:\r
52302d4d
LG
2177 # Build up the list of supported architectures for this build\r
2178 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)\r
4afd3d04 2179\r
52302d4d
LG
2180 # Look through the tool definitions for GUIDed tools\r
2181 guidAttribs = []\r
2182 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():\r
2183 if attrib.upper().endswith('_GUID'):\r
2184 split = attrib.split('_')\r
2185 thisPrefix = '_'.join(split[0:3]) + '_'\r
2186 if thisPrefix == prefix:\r
2187 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]\r
2188 guid = guid.lower()\r
2189 toolName = split[3]\r
2190 path = '_'.join(split[0:4]) + '_PATH'\r
2191 path = self.ToolDef.ToolsDefTxtDictionary[path]\r
2192 path = self.GetFullPathOfTool(path)\r
2193 guidAttribs.append((guid, toolName, path))\r
4afd3d04 2194\r
52302d4d
LG
2195 # Write out GuidedSecTools.txt\r
2196 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')\r
2197 toolsFile = open(toolsFile, 'wt')\r
2198 for guidedSectionTool in guidAttribs:\r
72443dd2 2199 print(' '.join(guidedSectionTool), file=toolsFile)\r
52302d4d
LG
2200 toolsFile.close()\r
2201\r
2202 ## Returns the full path of the tool.\r
2203 #\r
2204 def GetFullPathOfTool (self, tool):\r
2205 if os.path.exists(tool):\r
2206 return os.path.realpath(tool)\r
2207 else:\r
2208 # We need to search for the tool using the\r
2209 # PATH environment variable.\r
2210 for dirInPath in os.environ['PATH'].split(os.pathsep):\r
2211 foundPath = os.path.join(dirInPath, tool)\r
2212 if os.path.exists(foundPath):\r
2213 return os.path.realpath(foundPath)\r
2214\r
2215 # If the tool was not found in the path then we just return\r
2216 # the input tool.\r
2217 return tool\r
2218\r
2219 ## Launch the module or platform build\r
2220 #\r
2221 def Launch(self):\r
0d2711a6 2222 if not self.ModuleFile:\r
52302d4d
LG
2223 if not self.SpawnMode or self.Target not in ["", "all"]:\r
2224 self.SpawnMode = False\r
2225 self._BuildPlatform()\r
2226 else:\r
2227 self._MultiThreadBuildPlatform()\r
2228 self.CreateGuidedSectionToolsFile()\r
2229 else:\r
2230 self.SpawnMode = False\r
2231 self._BuildModule()\r
2232\r
bcbdc755
YL
2233 if self.Target == 'cleanall':\r
2234 self.Db.Close()\r
2235 RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)\r
2236\r
a0a2cd1e
FB
2237 def CreateAsBuiltInf(self):\r
2238 for Module in self.BuildModules:\r
2239 Module.CreateAsBuiltInf()\r
83397f95
YZ
2240 for Module in self.HashSkipModules:\r
2241 Module.CreateAsBuiltInf(True)\r
a0a2cd1e 2242 self.BuildModules = []\r
83397f95 2243 self.HashSkipModules = []\r
52302d4d
LG
2244 ## Do some clean-up works when error occurred\r
2245 def Relinquish(self):\r
2246 OldLogLevel = EdkLogger.GetLevel()\r
2247 EdkLogger.SetLevel(EdkLogger.ERROR)\r
2248 #self.DumpBuildData()\r
2249 Utils.Progressor.Abort()\r
2250 if self.SpawnMode == True:\r
2251 BuildTask.Abort()\r
2252 EdkLogger.SetLevel(OldLogLevel)\r
2253\r
2254 def DumpBuildData(self):\r
97fa0ee9 2255 CacheDirectory = os.path.dirname(GlobalData.gDatabasePath)\r
52302d4d
LG
2256 Utils.CreateDirectory(CacheDirectory)\r
2257 Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))\r
2258 Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))\r
2259\r
2260 def RestoreBuildData(self):\r
97fa0ee9 2261 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gFileTimeStampCache")\r
52302d4d
LG
2262 if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):\r
2263 Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)\r
4231a819 2264 if Utils.gFileTimeStampCache is None:\r
52302d4d
LG
2265 Utils.gFileTimeStampCache = {}\r
2266\r
97fa0ee9 2267 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gDependencyDatabase")\r
52302d4d
LG
2268 if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):\r
2269 Utils.gDependencyDatabase = Utils.DataRestore(FilePath)\r
4231a819 2270 if Utils.gDependencyDatabase is None:\r
52302d4d
LG
2271 Utils.gDependencyDatabase = {}\r
2272\r
2273def ParseDefines(DefineList=[]):\r
2274 DefineDict = {}\r
4231a819 2275 if DefineList is not None:\r
52302d4d
LG
2276 for Define in DefineList:\r
2277 DefineTokenList = Define.split("=", 1)\r
0d2711a6
LG
2278 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):\r
2279 EdkLogger.error('build', FORMAT_INVALID,\r
2280 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",\r
2281 ExtraData=DefineTokenList[0])\r
4afd3d04 2282\r
52302d4d 2283 if len(DefineTokenList) == 1:\r
0d2711a6 2284 DefineDict[DefineTokenList[0]] = "TRUE"\r
52302d4d
LG
2285 else:\r
2286 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()\r
2287 return DefineDict\r
2288\r
2289gParamCheck = []\r
2290def SingleCheckCallback(option, opt_str, value, parser):\r
2291 if option not in gParamCheck:\r
2292 setattr(parser.values, option.dest, value)\r
2293 gParamCheck.append(option)\r
2294 else:\r
2295 parser.error("Option %s only allows one instance in command line!" % option)\r
2296\r
1b8eca8b
YZ
2297def LogBuildTime(Time):\r
2298 if Time:\r
2299 TimeDurStr = ''\r
2300 TimeDur = time.gmtime(Time)\r
2301 if TimeDur.tm_yday > 1:\r
2302 TimeDurStr = time.strftime("%H:%M:%S", TimeDur) + ", %d day(s)" % (TimeDur.tm_yday - 1)\r
2303 else:\r
2304 TimeDurStr = time.strftime("%H:%M:%S", TimeDur)\r
2305 return TimeDurStr\r
2306 else:\r
2307 return None\r
2308\r
52302d4d
LG
2309## Parse command line options\r
2310#\r
2311# Using standard Python module optparse to parse command line option of this tool.\r
2312#\r
2313# @retval Opt A optparse.Values object containing the parsed options\r
2314# @retval Args Target of build command\r
2315#\r
2316def MyOptionParser():\r
47fea6af
YZ
2317 Parser = OptionParser(description=__copyright__, version=__version__, prog="build.exe", usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")\r
2318 Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32', 'X64', 'IPF', 'EBC', 'ARM', 'AARCH64'], dest="TargetArch",\r
4afd3d04 2319 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
2320 Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,\r
2321 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")\r
2322 Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,\r
2323 help="Build the module specified by the INF file name argument.")\r
64b2609f
LG
2324 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",\r
2325 action="append")\r
52302d4d
LG
2326 Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",\r
2327 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")\r
2328 Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,\r
2329 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")\r
2330\r
2331 Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,\r
2052cb67
YZ
2332 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
2333 "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
2334\r
2335 Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,\r
2336 help="The name of the FDF file to use, which overrides the setting in the DSC file.")\r
2337 Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],\r
2338 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")\r
2339 Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],\r
2340 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")\r
4234283c
LG
2341 Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],\r
2342 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")\r
52302d4d
LG
2343 Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")\r
2344 Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")\r
2345\r
0d2711a6 2346 Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.")\r
52302d4d
LG
2347\r
2348 Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")\r
2349 Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")\r
2350\r
2351 Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",\r
2352 help="Make use of silent mode of (n)make.")\r
2353 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
2354 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\\r
2355 "including library instances selected, final dependency expression, "\\r
2356 "and warning messages, etc.")\r
2357 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
2358 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
2359\r
2360 Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")\r
ccaa7754 2361 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 2362 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 2363 "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
2364 Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",\r
2365 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
2366 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\\r
2367 "will override the setting in [BuildOptions] section of platform DSC.")\r
0d2711a6 2368 Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism")\r
97fa0ee9
YL
2369 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")\r
2370 Parser.add_option("--check-usage", action="store_true", dest="CheckUsage", default=False, help="Check usage content of entries listed in INF file.")\r
fae62ff2 2371 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 2372 Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")\r
725cdb8f 2373 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
2374 Parser.add_option("--hash", action="store_true", dest="UseHashCache", default=False, help="Enable hash-based caching during build process.")\r
2375 Parser.add_option("--binary-destination", action="store", type="string", dest="BinCacheDest", help="Generate a cache of binary files in the specified directory.")\r
2376 Parser.add_option("--binary-source", action="store", type="string", dest="BinCacheSource", help="Consume a cache of binary files from the specified directory.")\r
37de70b7 2377 Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=False, help="Enable GenFds multi thread to generate ffs file.")\r
47fea6af 2378 (Opt, Args) = Parser.parse_args()\r
52302d4d
LG
2379 return (Opt, Args)\r
2380\r
2381## Tool entrance method\r
2382#\r
2383# This method mainly dispatch specific methods per the command line options.\r
2384# If no error found, return zero value so the caller of this tool can know\r
2385# if it's executed successfully or not.\r
2386#\r
2387# @retval 0 Tool was successful\r
2388# @retval 1 Tool failed\r
2389#\r
2390def Main():\r
2391 StartTime = time.time()\r
2392\r
2393 # Initialize log system\r
2394 EdkLogger.Initialize()\r
f0dc69e6 2395 GlobalData.gCommand = sys.argv[1:]\r
52302d4d
LG
2396 #\r
2397 # Parse the options and args\r
2398 #\r
2399 (Option, Target) = MyOptionParser()\r
2400 GlobalData.gOptions = Option\r
2401 GlobalData.gCaseInsensitive = Option.CaseInsensitive\r
2402\r
2403 # Set log level\r
4231a819 2404 if Option.verbose is not None:\r
52302d4d 2405 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
4231a819 2406 elif Option.quiet is not None:\r
52302d4d 2407 EdkLogger.SetLevel(EdkLogger.QUIET)\r
4231a819 2408 elif Option.debug is not None:\r
52302d4d
LG
2409 EdkLogger.SetLevel(Option.debug + 1)\r
2410 else:\r
2411 EdkLogger.SetLevel(EdkLogger.INFO)\r
2412\r
4231a819 2413 if Option.LogFile is not None:\r
52302d4d
LG
2414 EdkLogger.SetLogFile(Option.LogFile)\r
2415\r
2416 if Option.WarningAsError == True:\r
2417 EdkLogger.SetWarningAsError()\r
2418\r
2419 if platform.platform().find("Windows") >= 0:\r
2420 GlobalData.gIsWindows = True\r
2421 else:\r
2422 GlobalData.gIsWindows = False\r
2423\r
6780eef1
LG
2424 EdkLogger.quiet("Build environment: %s" % platform.platform())\r
2425 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));\r
52302d4d
LG
2426 ReturnCode = 0\r
2427 MyBuild = None\r
09ae0f11 2428 BuildError = True\r
52302d4d
LG
2429 try:\r
2430 if len(Target) == 0:\r
2431 Target = "all"\r
2432 elif len(Target) >= 2:\r
2433 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",\r
47fea6af 2434 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))\r
52302d4d
LG
2435 else:\r
2436 Target = Target[0].lower()\r
2437\r
2438 if Target not in gSupportedTarget:\r
2439 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,\r
47fea6af 2440 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))\r
52302d4d 2441\r
52302d4d
LG
2442 #\r
2443 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH\r
2444 #\r
2445 CheckEnvVariable()\r
0d2711a6
LG
2446 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))\r
2447\r
52302d4d
LG
2448 Workspace = os.getenv("WORKSPACE")\r
2449 #\r
2450 # Get files real name in workspace dir\r
2451 #\r
2452 GlobalData.gAllFiles = Utils.DirCache(Workspace)\r
2453\r
2454 WorkingDirectory = os.getcwd()\r
2455 if not Option.ModuleFile:\r
2456 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))\r
2457 FileNum = len(FileList)\r
2458 if FileNum >= 2:\r
2459 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),\r
2460 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")\r
2461 elif FileNum == 1:\r
2462 Option.ModuleFile = NormFile(FileList[0], Workspace)\r
2463\r
2464 if Option.ModuleFile:\r
2465 if os.path.isabs (Option.ModuleFile):\r
2466 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:\r
2467 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)\r
2468 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)\r
2469 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)\r
2470 if ErrorCode != 0:\r
2471 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2472\r
4231a819 2473 if Option.PlatformFile is not None:\r
52302d4d
LG
2474 if os.path.isabs (Option.PlatformFile):\r
2475 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:\r
2476 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)\r
2477 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)\r
52302d4d 2478\r
4231a819 2479 if Option.FdfFile is not None:\r
52302d4d
LG
2480 if os.path.isabs (Option.FdfFile):\r
2481 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:\r
2482 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)\r
2483 Option.FdfFile = PathClass(Option.FdfFile, Workspace)\r
2484 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)\r
2485 if ErrorCode != 0:\r
2486 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2487\r
4231a819 2488 if Option.Flag is not None and Option.Flag not in ['-c', '-s']:\r
f3decdc3
LG
2489 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")\r
2490\r
0d2711a6 2491 MyBuild = Build(Target, Workspace, Option)\r
64b2609f 2492 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)\r
f0dc69e6
YZ
2493 if not (MyBuild.LaunchPrebuildFlag and os.path.exists(MyBuild.PlatformBuildPath)):\r
2494 MyBuild.Launch()\r
64b2609f
LG
2495 # Drop temp tables to avoid database locked.\r
2496 for TmpTableName in TmpTableDict:\r
2497 SqlCommand = """drop table IF EXISTS %s""" % TmpTableName\r
2498 TmpTableDict[TmpTableName].execute(SqlCommand)\r
52302d4d 2499 #MyBuild.DumpBuildData()\r
09ae0f11
YL
2500 #\r
2501 # All job done, no error found and no exception raised\r
2502 #\r
2503 BuildError = False\r
5b0671c1 2504 except FatalError as X:\r
4231a819 2505 if MyBuild is not None:\r
52302d4d
LG
2506 # for multi-thread build exits safely\r
2507 MyBuild.Relinquish()\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 ReturnCode = X.args[0]\r
5b0671c1 2511 except Warning as X:\r
52302d4d 2512 # error from Fdf parser\r
4231a819 2513 if MyBuild is not None:\r
52302d4d
LG
2514 # for multi-thread build exits safely\r
2515 MyBuild.Relinquish()\r
4231a819 2516 if Option is not None and Option.debug is not None:\r
52302d4d
LG
2517 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2518 else:\r
47fea6af 2519 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)\r
52302d4d
LG
2520 ReturnCode = FORMAT_INVALID\r
2521 except KeyboardInterrupt:\r
2522 ReturnCode = ABORT_ERROR\r
4231a819 2523 if Option is not None and Option.debug is not None:\r
52302d4d
LG
2524 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2525 except:\r
4231a819 2526 if MyBuild is not None:\r
52302d4d
LG
2527 # for multi-thread build exits safely\r
2528 MyBuild.Relinquish()\r
2529\r
2530 # try to get the meta-file from the object causing exception\r
2531 Tb = sys.exc_info()[-1]\r
2532 MetaFile = GlobalData.gProcessingFile\r
4231a819 2533 while Tb is not None:\r
52302d4d
LG
2534 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):\r
2535 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile\r
2536 Tb = Tb.tb_next\r
2537 EdkLogger.error(\r
2538 "\nbuild",\r
2539 CODE_ERROR,\r
2540 "Unknown fatal error when processing [%s]" % MetaFile,\r
3a0f8bde 2541 ExtraData="\n(Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!)\n",\r
52302d4d
LG
2542 RaiseError=False\r
2543 )\r
d0acc87a 2544 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
52302d4d
LG
2545 ReturnCode = CODE_ERROR\r
2546 finally:\r
2547 Utils.Progressor.Abort()\r
97fa0ee9 2548 Utils.ClearDuplicatedInf()\r
52302d4d
LG
2549\r
2550 if ReturnCode == 0:\r
f0dc69e6 2551 try:\r
91048b0d 2552 MyBuild.LaunchPostbuild()\r
f0dc69e6
YZ
2553 Conclusion = "Done"\r
2554 except:\r
2555 Conclusion = "Failed"\r
52302d4d
LG
2556 elif ReturnCode == ABORT_ERROR:\r
2557 Conclusion = "Aborted"\r
2558 else:\r
2559 Conclusion = "Failed"\r
2560 FinishTime = time.time()\r
4234283c
LG
2561 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))\r
2562 BuildDurationStr = ""\r
2563 if BuildDuration.tm_yday > 1:\r
47fea6af 2564 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)" % (BuildDuration.tm_yday - 1)\r
4234283c
LG
2565 else:\r
2566 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)\r
4231a819 2567 if MyBuild is not None:\r
09ae0f11 2568 if not BuildError:\r
1b8eca8b 2569 MyBuild.BuildReport.GenerateReport(BuildDurationStr, LogBuildTime(MyBuild.AutoGenTime), LogBuildTime(MyBuild.MakeTime), LogBuildTime(MyBuild.GenFdsTime))\r
52302d4d
LG
2570 MyBuild.Db.Close()\r
2571 EdkLogger.SetLevel(EdkLogger.QUIET)\r
6780eef1
LG
2572 EdkLogger.quiet("\n- %s -" % Conclusion)\r
2573 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))\r
4234283c 2574 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)\r
52302d4d
LG
2575 return ReturnCode\r
2576\r
2577if __name__ == '__main__':\r
2578 r = Main()\r
2579 ## 0-127 is a safe return range, and 1 is a standard default error\r
2580 if r < 0 or r > 127: r = 1\r
2581 sys.exit(r)\r
2582\r