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