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