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