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