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