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