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