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