]> 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
fae62ff2
HC
739 #Set global flag for build mode\r
740 GlobalData.gIgnoreSource = BuildOptions.IgnoreSources\r
0d2711a6
LG
741 if BuildOptions.DisableCache:\r
742 self.Db = WorkspaceDatabase(":memory:")\r
743 else:\r
744 self.Db = WorkspaceDatabase(None, self.Reparse)\r
52302d4d
LG
745 self.BuildDatabase = self.Db.BuildObject\r
746 self.Platform = None\r
747 self.LoadFixAddress = 0\r
0d2711a6 748 self.UniFlag = BuildOptions.Flag\r
a0a2cd1e 749 self.BuildModules = []\r
52302d4d 750\r
e56468c0 751 # print dot character during doing some time-consuming work\r
52302d4d
LG
752 self.Progress = Utils.Progressor()\r
753\r
52302d4d
LG
754 self.InitBuild()\r
755\r
756 # print current build environment and configuration\r
0d2711a6
LG
757 EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))\r
758 EdkLogger.quiet("%-16s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"]))\r
759 EdkLogger.quiet("%-16s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"]))\r
760 EdkLogger.quiet("%-16s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"]))\r
761 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))\r
762\r
763 EdkLogger.info("")\r
52302d4d
LG
764\r
765 os.chdir(self.WorkspaceDir)\r
52302d4d
LG
766\r
767 ## Load configuration\r
768 #\r
769 # This method will parse target.txt and get the build configurations.\r
770 #\r
771 def LoadConfiguration(self):\r
772 #\r
773 # Check target.txt and tools_def.txt and Init them\r
774 #\r
775 BuildConfigurationFile = os.path.normpath(os.path.join(self.WorkspaceDir, gBuildConfiguration))\r
776 if os.path.isfile(BuildConfigurationFile) == True:\r
777 StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)\r
778\r
779 ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]\r
780 if ToolDefinitionFile == '':\r
781 ToolDefinitionFile = gToolsDefinition\r
782 ToolDefinitionFile = os.path.normpath(os.path.join(self.WorkspaceDir, ToolDefinitionFile))\r
783 if os.path.isfile(ToolDefinitionFile) == True:\r
784 StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)\r
785 else:\r
786 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)\r
787 else:\r
788 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)\r
789\r
790 # if no ARCH given in command line, get it from target.txt\r
0d2711a6 791 if not self.ArchList:\r
52302d4d 792 self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH]\r
0d2711a6 793 self.ArchList = tuple(self.ArchList)\r
52302d4d
LG
794\r
795 # if no build target given in command line, get it from target.txt\r
0d2711a6 796 if not self.BuildTargetList:\r
52302d4d
LG
797 self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]\r
798\r
799 # if no tool chain given in command line, get it from target.txt\r
0d2711a6 800 if not self.ToolChainList:\r
52302d4d
LG
801 self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]\r
802 if self.ToolChainList == None or len(self.ToolChainList) == 0:\r
803 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")\r
804\r
805 # check if the tool chains are defined or not\r
806 NewToolChainList = []\r
807 for ToolChain in self.ToolChainList:\r
808 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:\r
809 EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)\r
810 else:\r
811 NewToolChainList.append(ToolChain)\r
812 # if no tool chain available, break the build\r
813 if len(NewToolChainList) == 0:\r
814 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
815 ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))\r
816 else:\r
817 self.ToolChainList = NewToolChainList\r
818\r
819 if self.ThreadNumber == None:\r
820 self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]\r
821 if self.ThreadNumber == '':\r
822 self.ThreadNumber = 0\r
823 else:\r
824 self.ThreadNumber = int(self.ThreadNumber, 0)\r
825\r
826 if self.ThreadNumber == 0:\r
827 self.ThreadNumber = 1\r
828\r
829 if not self.PlatformFile:\r
830 PlatformFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM]\r
831 if not PlatformFile:\r
832 # Try to find one in current directory\r
833 WorkingDirectory = os.getcwd()\r
834 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))\r
835 FileNum = len(FileList)\r
836 if FileNum >= 2:\r
837 EdkLogger.error("build", OPTION_MISSING,\r
838 ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))\r
839 elif FileNum == 1:\r
840 PlatformFile = FileList[0]\r
841 else:\r
842 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
843 ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")\r
844\r
845 self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)\r
52302d4d
LG
846\r
847 ## Initialize build configuration\r
848 #\r
849 # This method will parse DSC file and merge the configurations from\r
850 # command line and target.txt, then get the final build configurations.\r
851 #\r
852 def InitBuild(self):\r
0d2711a6 853 # parse target.txt, tools_def.txt, and platform file\r
4afd3d04 854 self.LoadConfiguration()\r
0d2711a6
LG
855\r
856 # Allow case-insensitive for those from command line or configuration file\r
857 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)\r
52302d4d
LG
858 if ErrorCode != 0:\r
859 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
860\r
861 # create metafile database\r
862 self.Db.InitDatabase()\r
863\r
52302d4d
LG
864 ## Build a module or platform\r
865 #\r
08dd311f 866 # Create autogen code and makefile for a module or platform, and the launch\r
52302d4d
LG
867 # "make" command to build it\r
868 #\r
869 # @param Target The target of build command\r
870 # @param Platform The platform file\r
871 # @param Module The module file\r
872 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
873 # @param ToolChain The name of toolchain to build\r
874 # @param Arch The arch of the module/platform\r
875 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
876 # for dependent modules/Libraries\r
877 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
878 # for dependent modules/Libraries\r
879 #\r
03af2753 880 def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):\r
52302d4d
LG
881 if AutoGenObject == None:\r
882 return False\r
883\r
884 # skip file generation for cleanxxx targets, run and fds target\r
885 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
886 # for target which must generate AutoGen code and makefile\r
887 if not self.SkipAutoGen or Target == 'genc':\r
888 self.Progress.Start("Generating code")\r
889 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
890 self.Progress.Stop("done!")\r
891 if Target == "genc":\r
892 return True\r
893\r
894 if not self.SkipAutoGen or Target == 'genmake':\r
895 self.Progress.Start("Generating makefile")\r
896 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)\r
897 self.Progress.Stop("done!")\r
898 if Target == "genmake":\r
899 return True\r
900 else:\r
901 # always recreate top/platform makefile when clean, just in case of inconsistency\r
902 AutoGenObject.CreateCodeFile(False)\r
903 AutoGenObject.CreateMakeFile(False)\r
904\r
905 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
906 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
907\r
908 BuildCommand = AutoGenObject.BuildCommand\r
909 if BuildCommand == None or len(BuildCommand) == 0:\r
0d2711a6
LG
910 EdkLogger.error("build", OPTION_MISSING,\r
911 "No build command found for this module. "\r
4afd3d04 912 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
0d2711a6
LG
913 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
914 ExtraData=str(AutoGenObject))\r
52302d4d 915\r
03af2753
HC
916 makefile = GenMake.BuildFile(AutoGenObject)._FILE_NAME_[GenMake.gMakeType]\r
917\r
918 # genfds\r
919 if Target == 'fds':\r
920 LaunchCommand(AutoGenObject.GenFdsCommand, AutoGenObject.MakeFileDir)\r
921 return True\r
922\r
923 # run\r
924 if Target == 'run':\r
925 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, 'IA32'))\r
926 Command = '.\SecMain'\r
927 os.chdir(RunDir)\r
928 LaunchCommand(Command, RunDir)\r
929 return True\r
930\r
931 # build modules\r
932 if BuildModule:\r
933 BuildCommand = BuildCommand + [Target]\r
934 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
a0a2cd1e 935 self.CreateAsBuiltInf()\r
03af2753
HC
936 return True\r
937\r
938 # build library\r
939 if Target == 'libraries':\r
940 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
941 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']\r
942 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
943 return True\r
944\r
945 # build module\r
946 if Target == 'modules':\r
947 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
948 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']\r
949 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
950 for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
951 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']\r
952 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
a0a2cd1e 953 self.CreateAsBuiltInf()\r
03af2753
HC
954 return True\r
955\r
956 # cleanlib\r
957 if Target == 'cleanlib':\r
958 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
959 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))\r
960 if os.path.exists(LibMakefile):\r
961 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
962 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
963 return True\r
964\r
965 # clean\r
966 if Target == 'clean':\r
967 for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
968 ModMakefile = os.path.normpath(os.path.join(Mod, makefile))\r
969 if os.path.exists(ModMakefile):\r
970 NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']\r
971 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
972 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
973 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))\r
974 if os.path.exists(LibMakefile):\r
975 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
976 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
977 return True\r
978\r
979 # cleanall\r
980 if Target == 'cleanall':\r
981 try:\r
982 #os.rmdir(AutoGenObject.BuildDir)\r
983 RemoveDirectory(AutoGenObject.BuildDir, True)\r
984 #\r
985 # First should close DB.\r
986 #\r
987 self.Db.Close()\r
988 RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)\r
989 except WindowsError, X:\r
990 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
991 return True\r
992\r
993 ## Build a module or platform\r
994 #\r
995 # Create autogen code and makefile for a module or platform, and the launch\r
996 # "make" command to build it\r
997 #\r
998 # @param Target The target of build command\r
999 # @param Platform The platform file\r
1000 # @param Module The module file\r
1001 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
1002 # @param ToolChain The name of toolchain to build\r
1003 # @param Arch The arch of the module/platform\r
1004 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
1005 # for dependent modules/Libraries\r
1006 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
1007 # for dependent modules/Libraries\r
1008 #\r
1009 def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):\r
1010 if AutoGenObject == None:\r
1011 return False\r
1012\r
1013 # skip file generation for cleanxxx targets, run and fds target\r
1014 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1015 # for target which must generate AutoGen code and makefile\r
1016 if not self.SkipAutoGen or Target == 'genc':\r
1017 self.Progress.Start("Generating code")\r
1018 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
1019 self.Progress.Stop("done!")\r
1020 if Target == "genc":\r
1021 return True\r
1022\r
1023 if not self.SkipAutoGen or Target == 'genmake':\r
1024 self.Progress.Start("Generating makefile")\r
1025 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)\r
1026 #AutoGenObject.CreateAsBuiltInf()\r
1027 self.Progress.Stop("done!")\r
1028 if Target == "genmake":\r
1029 return True\r
1030 else:\r
1031 # always recreate top/platform makefile when clean, just in case of inconsistency\r
1032 AutoGenObject.CreateCodeFile(False)\r
1033 AutoGenObject.CreateMakeFile(False)\r
1034\r
1035 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
1036 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
1037\r
1038 BuildCommand = AutoGenObject.BuildCommand\r
1039 if BuildCommand == None or len(BuildCommand) == 0:\r
1040 EdkLogger.error("build", OPTION_MISSING,\r
1041 "No build command found for this module. "\r
1042 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
1043 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
1044 ExtraData=str(AutoGenObject))\r
1045\r
1046 # genfds\r
1047 if Target == 'fds':\r
1048 LaunchCommand(AutoGenObject.GenFdsCommand, AutoGenObject.MakeFileDir)\r
1049 return True\r
1050\r
1051 # run\r
1052 if Target == 'run':\r
1053 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, 'IA32'))\r
1054 Command = '.\SecMain'\r
1055 os.chdir(RunDir)\r
1056 LaunchCommand(Command, RunDir)\r
1057 return True\r
1058\r
1059 # build modules\r
52302d4d 1060 BuildCommand = BuildCommand + [Target]\r
03af2753
HC
1061 if BuildModule:\r
1062 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
a0a2cd1e 1063 self.CreateAsBuiltInf()\r
03af2753
HC
1064 return True\r
1065\r
1066 # build library\r
1067 if Target == 'libraries':\r
1068 pass\r
1069\r
1070 # not build modules\r
1071\r
1072\r
1073 # cleanall\r
52302d4d
LG
1074 if Target == 'cleanall':\r
1075 try:\r
1076 #os.rmdir(AutoGenObject.BuildDir)\r
1077 RemoveDirectory(AutoGenObject.BuildDir, True)\r
4234283c
LG
1078 #\r
1079 # First should close DB.\r
1080 #\r
0d2711a6 1081 self.Db.Close()\r
4234283c 1082 RemoveDirectory(gBuildCacheDir, True)\r
52302d4d
LG
1083 except WindowsError, X:\r
1084 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1085 return True\r
1086\r
6780eef1 1087 ## Rebase module image and Get function address for the input module list.\r
52302d4d
LG
1088 #\r
1089 def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):\r
1090 if ModeIsSmm:\r
1091 AddrIsOffset = False\r
1092 InfFileNameList = ModuleList.keys()\r
1093 #InfFileNameList.sort()\r
1094 for InfFile in InfFileNameList:\r
da92f276
LG
1095 sys.stdout.write (".")\r
1096 sys.stdout.flush()\r
52302d4d
LG
1097 ModuleInfo = ModuleList[InfFile]\r
1098 ModuleName = ModuleInfo.BaseName\r
f3decdc3
LG
1099 ModuleOutputImage = ModuleInfo.Image.FileName\r
1100 ModuleDebugImage = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')\r
52302d4d
LG
1101 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1102 if not ModeIsSmm:\r
1103 BaseAddress = BaseAddress - ModuleInfo.Image.Size\r
1104 #\r
1105 # Update Image to new BaseAddress by GenFw tool\r
1106 #\r
f3decdc3
LG
1107 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
1108 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
52302d4d
LG
1109 else:\r
1110 #\r
1111 # Set new address to the section header only for SMM driver.\r
1112 #\r
f3decdc3
LG
1113 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
1114 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
52302d4d
LG
1115 #\r
1116 # Collect funtion address from Map file\r
1117 #\r
f3decdc3 1118 ImageMapTable = ModuleOutputImage.replace('.efi', '.map')\r
52302d4d
LG
1119 FunctionList = []\r
1120 if os.path.exists(ImageMapTable):\r
1121 OrigImageBaseAddress = 0\r
1122 ImageMap = open (ImageMapTable, 'r')\r
1123 for LinStr in ImageMap:\r
1124 if len (LinStr.strip()) == 0:\r
1125 continue\r
1126 #\r
1127 # Get the preferred address set on link time.\r
1128 #\r
1129 if LinStr.find ('Preferred load address is') != -1:\r
1130 StrList = LinStr.split()\r
1131 OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)\r
1132\r
1133 StrList = LinStr.split()\r
1134 if len (StrList) > 4:\r
1135 if StrList[3] == 'f' or StrList[3] =='F':\r
1136 Name = StrList[1]\r
1137 RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress\r
1138 FunctionList.append ((Name, RelativeAddress))\r
1139 if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'):\r
1140 #\r
1141 # Get the real entry point address for IPF image.\r
1142 #\r
1143 ModuleInfo.Image.EntryPoint = RelativeAddress\r
1144 ImageMap.close()\r
1145 #\r
1146 # Add general information.\r
1147 #\r
1148 if ModeIsSmm:\r
1149 MapBuffer.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1150 elif AddrIsOffset:\r
1151 MapBuffer.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))\r
1152 else:\r
1153 MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1154 #\r
1155 # Add guid and general seciton section.\r
1156 #\r
1157 TextSectionAddress = 0\r
1158 DataSectionAddress = 0\r
1159 for SectionHeader in ModuleInfo.Image.SectionHeaderList:\r
1160 if SectionHeader[0] == '.text':\r
1161 TextSectionAddress = SectionHeader[1]\r
1162 elif SectionHeader[0] in ['.data', '.sdata']:\r
1163 DataSectionAddress = SectionHeader[1]\r
1164 if AddrIsOffset:\r
4afd3d04 1165 MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))\r
52302d4d 1166 else:\r
4afd3d04 1167 MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))\r
f3decdc3
LG
1168 #\r
1169 # Add debug image full path.\r
1170 #\r
1171 MapBuffer.write('(IMAGE=%s)\n\n' % (ModuleDebugImage))\r
52302d4d
LG
1172 #\r
1173 # Add funtion address\r
1174 #\r
1175 for Function in FunctionList:\r
1176 if AddrIsOffset:\r
1177 MapBuffer.write(' -0x%010X %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))\r
1178 else:\r
1179 MapBuffer.write(' 0x%010X %s\n' % (BaseAddress + Function[1], Function[0]))\r
1180 ImageMap.close()\r
1181\r
1182 #\r
1183 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1184 #\r
1185 if ModeIsSmm:\r
1186 BaseAddress = BaseAddress + ModuleInfo.Image.Size\r
1187\r
1188 ## Collect MAP information of all FVs\r
1189 #\r
636f2be6 1190 def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):\r
0d2711a6 1191 if self.Fdf:\r
52302d4d 1192 # First get the XIP base address for FV map file.\r
636f2be6 1193 GuidPattern = re.compile("[-a-fA-F0-9]+")\r
f3decdc3 1194 GuidName = re.compile("\(GUID=[-a-fA-F0-9]+")\r
52302d4d
LG
1195 for FvName in Wa.FdfProfile.FvDict.keys():\r
1196 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')\r
1197 if not os.path.exists(FvMapBuffer):\r
1198 continue\r
1be2ed90 1199 FvMap = open(FvMapBuffer, 'r')\r
52302d4d
LG
1200 #skip FV size information\r
1201 FvMap.readline()\r
1202 FvMap.readline()\r
1203 FvMap.readline()\r
1204 FvMap.readline()\r
636f2be6
LG
1205 for Line in FvMap:\r
1206 MatchGuid = GuidPattern.match(Line)\r
1207 if MatchGuid != None:\r
1208 #\r
1209 # Replace GUID with module name\r
1210 #\r
1211 GuidString = MatchGuid.group()\r
1212 if GuidString.upper() in ModuleList:\r
1213 Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)\r
1214 MapBuffer.write('%s' % (Line))\r
f3decdc3
LG
1215 #\r
1216 # Add the debug image full path.\r
1217 #\r
1218 MatchGuid = GuidName.match(Line)\r
1219 if MatchGuid != None:\r
1220 GuidString = MatchGuid.group().split("=")[1]\r
1221 if GuidString.upper() in ModuleList:\r
1222 MapBuffer.write('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))\r
1223\r
52302d4d
LG
1224 FvMap.close()\r
1225\r
1226 ## Collect MAP information of all modules\r
1227 #\r
1228 def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):\r
da92f276
LG
1229 sys.stdout.write ("Generate Load Module At Fix Address Map")\r
1230 sys.stdout.flush()\r
52302d4d
LG
1231 PatchEfiImageList = []\r
1232 PeiModuleList = {}\r
1233 BtModuleList = {}\r
1234 RtModuleList = {}\r
1235 SmmModuleList = {}\r
1236 PeiSize = 0\r
1237 BtSize = 0\r
1238 RtSize = 0\r
1239 # reserve 4K size in SMRAM to make SMM module address not from 0.\r
1240 SmmSize = 0x1000\r
1241 IsIpfPlatform = False\r
1242 if 'IPF' in self.ArchList:\r
1243 IsIpfPlatform = True\r
636f2be6
LG
1244 for ModuleGuid in ModuleList:\r
1245 Module = ModuleList[ModuleGuid]\r
52302d4d 1246 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)\r
4afd3d04 1247\r
52302d4d
LG
1248 OutputImageFile = ''\r
1249 for ResultFile in Module.CodaTargetList:\r
1250 if str(ResultFile.Target).endswith('.efi'):\r
1251 #\r
1252 # module list for PEI, DXE, RUNTIME and SMM\r
1253 #\r
1254 OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')\r
1255 ImageClass = PeImageClass (OutputImageFile)\r
1256 if not ImageClass.IsValid:\r
1257 EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)\r
f3decdc3 1258 ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)\r
52302d4d
LG
1259 if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER','PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']:\r
1260 PeiModuleList[Module.MetaFile] = ImageInfo\r
1261 PeiSize += ImageInfo.Image.Size\r
1262 elif Module.ModuleType in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']:\r
1263 BtModuleList[Module.MetaFile] = ImageInfo\r
1264 BtSize += ImageInfo.Image.Size\r
1265 elif Module.ModuleType in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']:\r
1266 RtModuleList[Module.MetaFile] = ImageInfo\r
1267 #IPF runtime driver needs to be at 2 page alignment.\r
1268 if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0:\r
1269 ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000\r
1270 RtSize += ImageInfo.Image.Size\r
1271 elif Module.ModuleType in ['SMM_CORE', 'DXE_SMM_DRIVER']:\r
1272 SmmModuleList[Module.MetaFile] = ImageInfo\r
1273 SmmSize += ImageInfo.Image.Size\r
1274 if Module.ModuleType == 'DXE_SMM_DRIVER':\r
da92f276
LG
1275 PiSpecVersion = '0x00000000'\r
1276 if 'PI_SPECIFICATION_VERSION' in Module.Module.Specification:\r
1277 PiSpecVersion = Module.Module.Specification['PI_SPECIFICATION_VERSION']\r
52302d4d 1278 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.\r
da92f276 1279 if int(PiSpecVersion, 16) < 0x0001000A:\r
52302d4d
LG
1280 BtModuleList[Module.MetaFile] = ImageInfo\r
1281 BtSize += ImageInfo.Image.Size\r
1282 break\r
1283 #\r
1284 # EFI image is final target.\r
1285 # Check EFI image contains patchable FixAddress related PCDs.\r
1286 #\r
1287 if OutputImageFile != '':\r
1288 ModuleIsPatch = False\r
1289 for Pcd in Module.ModulePcdList:\r
1290 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:\r
1291 ModuleIsPatch = True\r
1292 break\r
1293 if not ModuleIsPatch:\r
1294 for Pcd in Module.LibraryPcdList:\r
1295 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:\r
1296 ModuleIsPatch = True\r
1297 break\r
4afd3d04 1298\r
52302d4d
LG
1299 if not ModuleIsPatch:\r
1300 continue\r
1301 #\r
1302 # Module includes the patchable load fix address PCDs.\r
4afd3d04 1303 # It will be fixed up later.\r
52302d4d
LG
1304 #\r
1305 PatchEfiImageList.append (OutputImageFile)\r
4afd3d04 1306\r
52302d4d
LG
1307 #\r
1308 # Get Top Memory address\r
1309 #\r
1310 ReservedRuntimeMemorySize = 0\r
1311 TopMemoryAddress = 0\r
1312 if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:\r
1313 TopMemoryAddress = 0\r
1314 else:\r
1315 TopMemoryAddress = self.LoadFixAddress\r
1316 if TopMemoryAddress < RtSize + BtSize + PeiSize:\r
1317 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")\r
1318 # Make IPF runtime driver at 2 page alignment.\r
1319 if IsIpfPlatform:\r
1320 ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000\r
1321 RtSize = RtSize + ReservedRuntimeMemorySize\r
1322\r
1323 #\r
1324 # Patch FixAddress related PCDs into EFI image\r
1325 #\r
4afd3d04 1326 for EfiImage in PatchEfiImageList:\r
52302d4d
LG
1327 EfiImageMap = EfiImage.replace('.efi', '.map')\r
1328 if not os.path.exists(EfiImageMap):\r
1329 continue\r
1330 #\r
1331 # Get PCD offset in EFI image by GenPatchPcdTable function\r
1332 #\r
4afd3d04 1333 PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)\r
52302d4d
LG
1334 #\r
1335 # Patch real PCD value by PatchPcdValue tool\r
1336 #\r
1337 for PcdInfo in PcdTable:\r
1338 ReturnValue = 0\r
1339 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:\r
1340 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize/0x1000))\r
1341 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:\r
1342 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize/0x1000))\r
1343 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:\r
1344 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize/0x1000))\r
1345 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:\r
1346 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize/0x1000))\r
1347 if ReturnValue != 0:\r
1348 EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)\r
4afd3d04 1349\r
52302d4d
LG
1350 MapBuffer.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize/0x1000))\r
1351 MapBuffer.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize/0x1000))\r
1352 MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize/0x1000))\r
1353 if len (SmmModuleList) > 0:\r
1354 MapBuffer.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize/0x1000))\r
4afd3d04
LG
1355\r
1356 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize\r
52302d4d 1357 BtBaseAddr = TopMemoryAddress - RtSize\r
4afd3d04 1358 RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize\r
52302d4d
LG
1359\r
1360 self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)\r
1361 self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)\r
1362 self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)\r
1363 self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset = False, ModeIsSmm = True)\r
1364 MapBuffer.write('\n\n')\r
da92f276
LG
1365 sys.stdout.write ("\n")\r
1366 sys.stdout.flush()\r
4afd3d04 1367\r
52302d4d
LG
1368 ## Save platform Map file\r
1369 #\r
1370 def _SaveMapFile (self, MapBuffer, Wa):\r
1371 #\r
1372 # Map file path is got.\r
1373 #\r
1374 MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')\r
1375 #\r
1376 # Save address map into MAP file.\r
1377 #\r
40d841f6 1378 SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)\r
da92f276
LG
1379 MapBuffer.close()\r
1380 if self.LoadFixAddress != 0:\r
1381 sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" %(MapFilePath))\r
1382 sys.stdout.flush()\r
52302d4d
LG
1383\r
1384 ## Build active platform for different build targets and different tool chains\r
1385 #\r
1386 def _BuildPlatform(self):\r
1387 for BuildTarget in self.BuildTargetList:\r
0d2711a6 1388 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
52302d4d 1389 for ToolChain in self.ToolChainList:\r
0d2711a6
LG
1390 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
1391 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
52302d4d
LG
1392 Wa = WorkspaceAutoGen(\r
1393 self.WorkspaceDir,\r
0d2711a6 1394 self.PlatformFile,\r
52302d4d
LG
1395 BuildTarget,\r
1396 ToolChain,\r
1397 self.ArchList,\r
1398 self.BuildDatabase,\r
1399 self.TargetTxt,\r
1400 self.ToolDef,\r
1401 self.Fdf,\r
1402 self.FdList,\r
1403 self.FvList,\r
4234283c 1404 self.CapList,\r
f3decdc3 1405 self.SkuId,\r
9508d0fa
LG
1406 self.UniFlag,\r
1407 self.Progress\r
52302d4d 1408 )\r
0d2711a6
LG
1409 self.Fdf = Wa.FdfFile\r
1410 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
52302d4d
LG
1411 self.BuildReport.AddPlatformReport(Wa)\r
1412 self.Progress.Stop("done!")\r
03af2753
HC
1413 for Arch in Wa.ArchList:\r
1414 GlobalData.gGlobalDefines['ARCH'] = Arch\r
1415 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
a0a2cd1e
FB
1416 for Module in Pa.Platform.Modules:\r
1417 # Get ModuleAutoGen object to generate C code file and makefile\r
1418 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1419 if Ma == None:\r
1420 continue\r
1421 self.BuildModules.append(Ma)\r
03af2753 1422 self._BuildPa(self.Target, Pa)\r
4afd3d04 1423\r
52302d4d 1424 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1425 if self.Target in ["", "all", "fds"]:\r
0d2711a6
LG
1426 for Arch in Wa.ArchList:\r
1427 GlobalData.gGlobalDefines['ARCH'] = Arch\r
52302d4d
LG
1428 #\r
1429 # Check whether the set fix address is above 4G for 32bit image.\r
1430 #\r
1431 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
0d2711a6 1432 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
1433 #\r
1434 # Get Module List\r
1435 #\r
636f2be6 1436 ModuleList = {}\r
52302d4d
LG
1437 for Pa in Wa.AutoGenObjectList:\r
1438 for Ma in Pa.ModuleAutoGenList:\r
1439 if Ma == None:\r
1440 continue\r
1441 if not Ma.IsLibrary:\r
636f2be6 1442 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
1443\r
1444 MapBuffer = StringIO('')\r
636f2be6
LG
1445 if self.LoadFixAddress != 0:\r
1446 #\r
1447 # Rebase module to the preferred memory address before GenFds\r
1448 #\r
1449 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
0d2711a6 1450 if self.Fdf:\r
f3decdc3
LG
1451 #\r
1452 # create FDS again for the updated EFI image\r
1453 #\r
1454 self._Build("fds", Wa)\r
0d2711a6 1455 if self.Fdf:\r
52302d4d
LG
1456 #\r
1457 # Create MAP file for all platform FVs after GenFds.\r
1458 #\r
636f2be6 1459 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1460 #\r
1461 # Save MAP buffer into MAP file.\r
1462 #\r
1463 self._SaveMapFile (MapBuffer, Wa)\r
1464\r
1465 ## Build active module for different build targets, different tool chains and different archs\r
1466 #\r
1467 def _BuildModule(self):\r
1468 for BuildTarget in self.BuildTargetList:\r
0d2711a6 1469 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
52302d4d 1470 for ToolChain in self.ToolChainList:\r
0d2711a6 1471 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
4afd3d04 1472 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
52302d4d
LG
1473 #\r
1474 # module build needs platform build information, so get platform\r
1475 # AutoGen first\r
1476 #\r
1477 Wa = WorkspaceAutoGen(\r
1478 self.WorkspaceDir,\r
0d2711a6 1479 self.PlatformFile,\r
52302d4d
LG
1480 BuildTarget,\r
1481 ToolChain,\r
1482 self.ArchList,\r
1483 self.BuildDatabase,\r
1484 self.TargetTxt,\r
1485 self.ToolDef,\r
1486 self.Fdf,\r
1487 self.FdList,\r
1488 self.FvList,\r
4234283c 1489 self.CapList,\r
f3decdc3 1490 self.SkuId,\r
9508d0fa
LG
1491 self.UniFlag,\r
1492 self.Progress,\r
1493 self.ModuleFile\r
52302d4d 1494 )\r
0d2711a6
LG
1495 self.Fdf = Wa.FdfFile\r
1496 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
52302d4d
LG
1497 Wa.CreateMakeFile(False)\r
1498 self.Progress.Stop("done!")\r
1499 MaList = []\r
0d2711a6
LG
1500 for Arch in Wa.ArchList:\r
1501 GlobalData.gGlobalDefines['ARCH'] = Arch\r
52302d4d
LG
1502 Ma = ModuleAutoGen(Wa, self.ModuleFile, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1503 if Ma == None: continue\r
1504 MaList.append(Ma)\r
a0a2cd1e 1505 self.BuildModules.append(Ma)\r
03af2753
HC
1506 if not Ma.IsBinaryModule:\r
1507 self._Build(self.Target, Ma, BuildModule=True)\r
d5d56f1b
LG
1508\r
1509 self.BuildReport.AddPlatformReport(Wa, MaList)\r
52302d4d
LG
1510 if MaList == []:\r
1511 EdkLogger.error(\r
1512 'build',\r
1513 BUILD_ERROR,\r
1514 "Module for [%s] is not a component of active platform."\\r
1515 " Please make sure that the ARCH and inf file path are"\\r
1516 " given in the same as in [%s]" %\\r
0d2711a6 1517 (', '.join(Wa.ArchList), self.PlatformFile),\r
52302d4d
LG
1518 ExtraData=self.ModuleFile\r
1519 )\r
1520 # Create MAP file when Load Fix Address is enabled.\r
0d2711a6
LG
1521 if self.Target == "fds" and self.Fdf:\r
1522 for Arch in Wa.ArchList:\r
52302d4d
LG
1523 #\r
1524 # Check whether the set fix address is above 4G for 32bit image.\r
1525 #\r
1526 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1527 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
1528 #\r
1529 # Get Module List\r
1530 #\r
636f2be6 1531 ModuleList = {}\r
52302d4d
LG
1532 for Pa in Wa.AutoGenObjectList:\r
1533 for Ma in Pa.ModuleAutoGenList:\r
1534 if Ma == None:\r
1535 continue\r
1536 if not Ma.IsLibrary:\r
636f2be6 1537 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
1538\r
1539 MapBuffer = StringIO('')\r
636f2be6
LG
1540 if self.LoadFixAddress != 0:\r
1541 #\r
1542 # Rebase module to the preferred memory address before GenFds\r
1543 #\r
1544 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
1545 #\r
1546 # create FDS again for the updated EFI image\r
1547 #\r
1548 self._Build("fds", Wa)\r
52302d4d
LG
1549 #\r
1550 # Create MAP file for all platform FVs after GenFds.\r
1551 #\r
636f2be6 1552 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1553 #\r
1554 # Save MAP buffer into MAP file.\r
1555 #\r
1556 self._SaveMapFile (MapBuffer, Wa)\r
1557\r
1558 ## Build a platform in multi-thread mode\r
1559 #\r
1560 def _MultiThreadBuildPlatform(self):\r
1561 for BuildTarget in self.BuildTargetList:\r
0d2711a6 1562 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
52302d4d 1563 for ToolChain in self.ToolChainList:\r
0d2711a6 1564 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
4afd3d04 1565 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
52302d4d
LG
1566 Wa = WorkspaceAutoGen(\r
1567 self.WorkspaceDir,\r
0d2711a6 1568 self.PlatformFile,\r
52302d4d
LG
1569 BuildTarget,\r
1570 ToolChain,\r
1571 self.ArchList,\r
1572 self.BuildDatabase,\r
1573 self.TargetTxt,\r
1574 self.ToolDef,\r
1575 self.Fdf,\r
1576 self.FdList,\r
1577 self.FvList,\r
4234283c 1578 self.CapList,\r
f3decdc3 1579 self.SkuId,\r
9508d0fa
LG
1580 self.UniFlag,\r
1581 self.Progress\r
52302d4d 1582 )\r
0d2711a6
LG
1583 self.Fdf = Wa.FdfFile\r
1584 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
52302d4d
LG
1585 self.BuildReport.AddPlatformReport(Wa)\r
1586 Wa.CreateMakeFile(False)\r
1587\r
1588 # multi-thread exit flag\r
1589 ExitFlag = threading.Event()\r
1590 ExitFlag.clear()\r
0d2711a6
LG
1591 for Arch in Wa.ArchList:\r
1592 GlobalData.gGlobalDefines['ARCH'] = Arch\r
52302d4d
LG
1593 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
1594 if Pa == None:\r
1595 continue\r
a0a2cd1e
FB
1596 ModuleList = []\r
1597 for Inf in Pa.Platform.Modules:\r
1598 ModuleList.append(Inf)\r
1599 # Add the INF only list in FDF\r
1600 if GlobalData.gFdfParser != None:\r
1601 for InfName in GlobalData.gFdfParser.Profile.InfList:\r
1602 Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)\r
1603 if Inf in Pa.Platform.Modules:\r
1604 continue\r
1605 ModuleList.append(Inf)\r
1606 for Module in ModuleList:\r
52302d4d
LG
1607 # Get ModuleAutoGen object to generate C code file and makefile\r
1608 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
a0a2cd1e 1609 \r
52302d4d
LG
1610 if Ma == None:\r
1611 continue\r
1612 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'\r
1613 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1614 # for target which must generate AutoGen code and makefile\r
1615 if not self.SkipAutoGen or self.Target == 'genc':\r
1616 Ma.CreateCodeFile(True)\r
1617 if self.Target == "genc":\r
1618 continue\r
1619\r
1620 if not self.SkipAutoGen or self.Target == 'genmake':\r
1621 Ma.CreateMakeFile(True)\r
1622 if self.Target == "genmake":\r
1623 continue\r
a0a2cd1e 1624 self.BuildModules.append(Ma)\r
e8a47801 1625 self.Progress.Stop("done!")\r
4afd3d04 1626\r
a0a2cd1e 1627 for Ma in self.BuildModules:\r
52302d4d 1628 # Generate build task for the module\r
a0a2cd1e
FB
1629 if not Ma.IsBinaryModule:\r
1630 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))\r
52302d4d
LG
1631 # Break build if any build thread has error\r
1632 if BuildTask.HasError():\r
1633 # we need a full version of makefile for platform\r
1634 ExitFlag.set()\r
1635 BuildTask.WaitForComplete()\r
1636 Pa.CreateMakeFile(False)\r
1637 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1638 # Start task scheduler\r
1639 if not BuildTask.IsOnGoing():\r
1640 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
1641\r
1642 # in case there's an interruption. we need a full version of makefile for platform\r
1643 Pa.CreateMakeFile(False)\r
1644 if BuildTask.HasError():\r
1645 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1646\r
64b2609f
LG
1647 #\r
1648 # Save temp tables to a TmpTableDict.\r
1649 #\r
1650 for Key in Wa.BuildDatabase._CACHE_:\r
1651 if Wa.BuildDatabase._CACHE_[Key]._RawData and Wa.BuildDatabase._CACHE_[Key]._RawData._Table and Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table:\r
1652 if TemporaryTablePattern.match(Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table):\r
1653 TmpTableDict[Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table] = Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Cur\r
1654 #\r
52302d4d
LG
1655 #\r
1656 # All modules have been put in build tasks queue. Tell task scheduler\r
1657 # to exit if all tasks are completed\r
1658 #\r
1659 ExitFlag.set()\r
1660 BuildTask.WaitForComplete()\r
a0a2cd1e 1661 self.CreateAsBuiltInf()\r
52302d4d
LG
1662\r
1663 #\r
1664 # Check for build error, and raise exception if one\r
1665 # has been signaled.\r
1666 #\r
1667 if BuildTask.HasError():\r
1668 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1669\r
1670 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1671 if self.Target in ["", "all", "fds"]:\r
0d2711a6 1672 for Arch in Wa.ArchList:\r
52302d4d
LG
1673 #\r
1674 # Check whether the set fix address is above 4G for 32bit image.\r
1675 #\r
1676 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1677 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
1678 #\r
1679 # Get Module List\r
1680 #\r
636f2be6 1681 ModuleList = {}\r
52302d4d
LG
1682 for Pa in Wa.AutoGenObjectList:\r
1683 for Ma in Pa.ModuleAutoGenList:\r
1684 if Ma == None:\r
1685 continue\r
1686 if not Ma.IsLibrary:\r
636f2be6 1687 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
1688 #\r
1689 # Rebase module to the preferred memory address before GenFds\r
1690 #\r
1691 MapBuffer = StringIO('')\r
636f2be6
LG
1692 if self.LoadFixAddress != 0:\r
1693 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
52302d4d 1694\r
0d2711a6 1695 if self.Fdf:\r
f3decdc3
LG
1696 #\r
1697 # Generate FD image if there's a FDF file found\r
1698 #\r
03af2753
HC
1699 LaunchCommand(Wa.GenFdsCommand, os.getcwd())\r
1700\r
52302d4d
LG
1701 #\r
1702 # Create MAP file for all platform FVs after GenFds.\r
1703 #\r
636f2be6 1704 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1705 #\r
1706 # Save MAP buffer into MAP file.\r
1707 #\r
1708 self._SaveMapFile(MapBuffer, Wa)\r
1709\r
1710 ## Generate GuidedSectionTools.txt in the FV directories.\r
1711 #\r
1712 def CreateGuidedSectionToolsFile(self):\r
0d2711a6
LG
1713 for BuildTarget in self.BuildTargetList:\r
1714 for ToolChain in self.ToolChainList:\r
1715 Wa = WorkspaceAutoGen(\r
1716 self.WorkspaceDir,\r
1717 self.PlatformFile,\r
1718 BuildTarget,\r
1719 ToolChain,\r
1720 self.ArchList,\r
1721 self.BuildDatabase,\r
1722 self.TargetTxt,\r
1723 self.ToolDef,\r
1724 self.Fdf,\r
1725 self.FdList,\r
1726 self.FvList,\r
1727 self.CapList,\r
1728 self.SkuId,\r
1729 self.UniFlag\r
1730 )\r
1731 FvDir = Wa.FvDir\r
1732 if not os.path.exists(FvDir):\r
1733 continue\r
1734\r
4afd3d04 1735 for Arch in self.ArchList:\r
52302d4d
LG
1736 # Build up the list of supported architectures for this build\r
1737 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)\r
4afd3d04 1738\r
52302d4d
LG
1739 # Look through the tool definitions for GUIDed tools\r
1740 guidAttribs = []\r
1741 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():\r
1742 if attrib.upper().endswith('_GUID'):\r
1743 split = attrib.split('_')\r
1744 thisPrefix = '_'.join(split[0:3]) + '_'\r
1745 if thisPrefix == prefix:\r
1746 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]\r
1747 guid = guid.lower()\r
1748 toolName = split[3]\r
1749 path = '_'.join(split[0:4]) + '_PATH'\r
1750 path = self.ToolDef.ToolsDefTxtDictionary[path]\r
1751 path = self.GetFullPathOfTool(path)\r
1752 guidAttribs.append((guid, toolName, path))\r
4afd3d04 1753\r
52302d4d
LG
1754 # Write out GuidedSecTools.txt\r
1755 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')\r
1756 toolsFile = open(toolsFile, 'wt')\r
1757 for guidedSectionTool in guidAttribs:\r
1758 print >> toolsFile, ' '.join(guidedSectionTool)\r
1759 toolsFile.close()\r
1760\r
1761 ## Returns the full path of the tool.\r
1762 #\r
1763 def GetFullPathOfTool (self, tool):\r
1764 if os.path.exists(tool):\r
1765 return os.path.realpath(tool)\r
1766 else:\r
1767 # We need to search for the tool using the\r
1768 # PATH environment variable.\r
1769 for dirInPath in os.environ['PATH'].split(os.pathsep):\r
1770 foundPath = os.path.join(dirInPath, tool)\r
1771 if os.path.exists(foundPath):\r
1772 return os.path.realpath(foundPath)\r
1773\r
1774 # If the tool was not found in the path then we just return\r
1775 # the input tool.\r
1776 return tool\r
1777\r
1778 ## Launch the module or platform build\r
1779 #\r
1780 def Launch(self):\r
0d2711a6 1781 if not self.ModuleFile:\r
52302d4d
LG
1782 if not self.SpawnMode or self.Target not in ["", "all"]:\r
1783 self.SpawnMode = False\r
1784 self._BuildPlatform()\r
1785 else:\r
1786 self._MultiThreadBuildPlatform()\r
1787 self.CreateGuidedSectionToolsFile()\r
1788 else:\r
1789 self.SpawnMode = False\r
1790 self._BuildModule()\r
1791\r
a0a2cd1e
FB
1792 def CreateAsBuiltInf(self):\r
1793 for Module in self.BuildModules:\r
1794 Module.CreateAsBuiltInf()\r
1795 self.BuildModules = []\r
52302d4d
LG
1796 ## Do some clean-up works when error occurred\r
1797 def Relinquish(self):\r
1798 OldLogLevel = EdkLogger.GetLevel()\r
1799 EdkLogger.SetLevel(EdkLogger.ERROR)\r
1800 #self.DumpBuildData()\r
1801 Utils.Progressor.Abort()\r
1802 if self.SpawnMode == True:\r
1803 BuildTask.Abort()\r
1804 EdkLogger.SetLevel(OldLogLevel)\r
1805\r
1806 def DumpBuildData(self):\r
1807 CacheDirectory = os.path.join(self.WorkspaceDir, gBuildCacheDir)\r
1808 Utils.CreateDirectory(CacheDirectory)\r
1809 Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))\r
1810 Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))\r
1811\r
1812 def RestoreBuildData(self):\r
1813 FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gFileTimeStampCache")\r
1814 if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):\r
1815 Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)\r
1816 if Utils.gFileTimeStampCache == None:\r
1817 Utils.gFileTimeStampCache = {}\r
1818\r
1819 FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gDependencyDatabase")\r
1820 if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):\r
1821 Utils.gDependencyDatabase = Utils.DataRestore(FilePath)\r
1822 if Utils.gDependencyDatabase == None:\r
1823 Utils.gDependencyDatabase = {}\r
1824\r
1825def ParseDefines(DefineList=[]):\r
1826 DefineDict = {}\r
1827 if DefineList != None:\r
1828 for Define in DefineList:\r
1829 DefineTokenList = Define.split("=", 1)\r
0d2711a6
LG
1830 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):\r
1831 EdkLogger.error('build', FORMAT_INVALID,\r
1832 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",\r
1833 ExtraData=DefineTokenList[0])\r
4afd3d04 1834\r
52302d4d 1835 if len(DefineTokenList) == 1:\r
0d2711a6 1836 DefineDict[DefineTokenList[0]] = "TRUE"\r
52302d4d
LG
1837 else:\r
1838 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()\r
1839 return DefineDict\r
1840\r
1841gParamCheck = []\r
1842def SingleCheckCallback(option, opt_str, value, parser):\r
1843 if option not in gParamCheck:\r
1844 setattr(parser.values, option.dest, value)\r
1845 gParamCheck.append(option)\r
1846 else:\r
1847 parser.error("Option %s only allows one instance in command line!" % option)\r
1848\r
1849## Parse command line options\r
1850#\r
1851# Using standard Python module optparse to parse command line option of this tool.\r
1852#\r
1853# @retval Opt A optparse.Values object containing the parsed options\r
1854# @retval Args Target of build command\r
1855#\r
1856def MyOptionParser():\r
1857 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
1858 Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32','X64','IPF','EBC','ARM', 'AARCH64'], dest="TargetArch",\r
1859 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
1860 Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,\r
1861 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")\r
1862 Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,\r
1863 help="Build the module specified by the INF file name argument.")\r
64b2609f
LG
1864 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",\r
1865 action="append")\r
52302d4d
LG
1866 Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",\r
1867 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")\r
1868 Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,\r
1869 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")\r
1870\r
1871 Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,\r
1872 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
1873\r
1874 Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,\r
1875 help="The name of the FDF file to use, which overrides the setting in the DSC file.")\r
1876 Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],\r
1877 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")\r
1878 Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],\r
1879 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")\r
4234283c
LG
1880 Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],\r
1881 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")\r
52302d4d
LG
1882 Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")\r
1883 Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")\r
1884\r
0d2711a6 1885 Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.")\r
52302d4d
LG
1886\r
1887 Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")\r
1888 Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")\r
1889\r
1890 Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",\r
1891 help="Make use of silent mode of (n)make.")\r
1892 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
1893 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\\r
1894 "including library instances selected, final dependency expression, "\\r
1895 "and warning messages, etc.")\r
1896 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
1897 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
1898\r
1899 Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")\r
1900 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
1901 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
1902 "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
1903 Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",\r
1904 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
1905 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\\r
1906 "will override the setting in [BuildOptions] section of platform DSC.")\r
0d2711a6 1907 Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism")\r
fae62ff2 1908 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
1909\r
1910 (Opt, Args)=Parser.parse_args()\r
1911 return (Opt, Args)\r
1912\r
1913## Tool entrance method\r
1914#\r
1915# This method mainly dispatch specific methods per the command line options.\r
1916# If no error found, return zero value so the caller of this tool can know\r
1917# if it's executed successfully or not.\r
1918#\r
1919# @retval 0 Tool was successful\r
1920# @retval 1 Tool failed\r
1921#\r
1922def Main():\r
1923 StartTime = time.time()\r
1924\r
1925 # Initialize log system\r
1926 EdkLogger.Initialize()\r
1927\r
1928 #\r
1929 # Parse the options and args\r
1930 #\r
1931 (Option, Target) = MyOptionParser()\r
1932 GlobalData.gOptions = Option\r
1933 GlobalData.gCaseInsensitive = Option.CaseInsensitive\r
1934\r
1935 # Set log level\r
1936 if Option.verbose != None:\r
1937 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
1938 elif Option.quiet != None:\r
1939 EdkLogger.SetLevel(EdkLogger.QUIET)\r
1940 elif Option.debug != None:\r
1941 EdkLogger.SetLevel(Option.debug + 1)\r
1942 else:\r
1943 EdkLogger.SetLevel(EdkLogger.INFO)\r
1944\r
1945 if Option.LogFile != None:\r
1946 EdkLogger.SetLogFile(Option.LogFile)\r
1947\r
1948 if Option.WarningAsError == True:\r
1949 EdkLogger.SetWarningAsError()\r
1950\r
1951 if platform.platform().find("Windows") >= 0:\r
1952 GlobalData.gIsWindows = True\r
1953 else:\r
1954 GlobalData.gIsWindows = False\r
1955\r
6780eef1
LG
1956 EdkLogger.quiet("Build environment: %s" % platform.platform())\r
1957 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));\r
52302d4d
LG
1958 ReturnCode = 0\r
1959 MyBuild = None\r
1960 try:\r
1961 if len(Target) == 0:\r
1962 Target = "all"\r
1963 elif len(Target) >= 2:\r
1964 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",\r
1965 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))\r
1966 else:\r
1967 Target = Target[0].lower()\r
1968\r
1969 if Target not in gSupportedTarget:\r
1970 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,\r
1971 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))\r
1972\r
52302d4d
LG
1973 #\r
1974 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH\r
1975 #\r
1976 CheckEnvVariable()\r
0d2711a6
LG
1977 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))\r
1978\r
52302d4d
LG
1979 Workspace = os.getenv("WORKSPACE")\r
1980 #\r
1981 # Get files real name in workspace dir\r
1982 #\r
1983 GlobalData.gAllFiles = Utils.DirCache(Workspace)\r
1984\r
1985 WorkingDirectory = os.getcwd()\r
1986 if not Option.ModuleFile:\r
1987 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))\r
1988 FileNum = len(FileList)\r
1989 if FileNum >= 2:\r
1990 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),\r
1991 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")\r
1992 elif FileNum == 1:\r
1993 Option.ModuleFile = NormFile(FileList[0], Workspace)\r
1994\r
1995 if Option.ModuleFile:\r
1996 if os.path.isabs (Option.ModuleFile):\r
1997 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:\r
1998 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)\r
1999 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)\r
2000 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)\r
2001 if ErrorCode != 0:\r
2002 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2003\r
2004 if Option.PlatformFile != None:\r
2005 if os.path.isabs (Option.PlatformFile):\r
2006 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:\r
2007 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)\r
2008 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)\r
52302d4d
LG
2009\r
2010 if Option.FdfFile != None:\r
2011 if os.path.isabs (Option.FdfFile):\r
2012 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:\r
2013 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)\r
2014 Option.FdfFile = PathClass(Option.FdfFile, Workspace)\r
2015 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)\r
2016 if ErrorCode != 0:\r
2017 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2018\r
f3decdc3
LG
2019 if Option.Flag != None and Option.Flag not in ['-c', '-s']:\r
2020 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")\r
2021\r
0d2711a6 2022 MyBuild = Build(Target, Workspace, Option)\r
64b2609f 2023 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)\r
52302d4d 2024 MyBuild.Launch()\r
64b2609f
LG
2025 # Drop temp tables to avoid database locked.\r
2026 for TmpTableName in TmpTableDict:\r
2027 SqlCommand = """drop table IF EXISTS %s""" % TmpTableName\r
2028 TmpTableDict[TmpTableName].execute(SqlCommand)\r
52302d4d
LG
2029 #MyBuild.DumpBuildData()\r
2030 except FatalError, X:\r
2031 if MyBuild != None:\r
2032 # for multi-thread build exits safely\r
2033 MyBuild.Relinquish()\r
2034 if Option != None and Option.debug != None:\r
2035 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2036 ReturnCode = X.args[0]\r
2037 except Warning, X:\r
2038 # error from Fdf parser\r
2039 if MyBuild != None:\r
2040 # for multi-thread build exits safely\r
2041 MyBuild.Relinquish()\r
2042 if Option != None and Option.debug != None:\r
2043 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2044 else:\r
2045 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError = False)\r
2046 ReturnCode = FORMAT_INVALID\r
2047 except KeyboardInterrupt:\r
2048 ReturnCode = ABORT_ERROR\r
2049 if Option != None and Option.debug != None:\r
2050 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2051 except:\r
2052 if MyBuild != None:\r
2053 # for multi-thread build exits safely\r
2054 MyBuild.Relinquish()\r
2055\r
2056 # try to get the meta-file from the object causing exception\r
2057 Tb = sys.exc_info()[-1]\r
2058 MetaFile = GlobalData.gProcessingFile\r
2059 while Tb != None:\r
2060 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):\r
2061 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile\r
2062 Tb = Tb.tb_next\r
2063 EdkLogger.error(\r
2064 "\nbuild",\r
2065 CODE_ERROR,\r
2066 "Unknown fatal error when processing [%s]" % MetaFile,\r
2067 ExtraData="\n(Please send email to edk2-buildtools-devel@lists.sourceforge.net for help, attaching following call stack trace!)\n",\r
2068 RaiseError=False\r
2069 )\r
d0acc87a 2070 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
52302d4d
LG
2071 ReturnCode = CODE_ERROR\r
2072 finally:\r
2073 Utils.Progressor.Abort()\r
2074\r
2075 if ReturnCode == 0:\r
2076 Conclusion = "Done"\r
2077 elif ReturnCode == ABORT_ERROR:\r
2078 Conclusion = "Aborted"\r
2079 else:\r
2080 Conclusion = "Failed"\r
2081 FinishTime = time.time()\r
4234283c
LG
2082 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))\r
2083 BuildDurationStr = ""\r
2084 if BuildDuration.tm_yday > 1:\r
2085 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)"%(BuildDuration.tm_yday - 1)\r
2086 else:\r
2087 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)\r
52302d4d 2088 if MyBuild != None:\r
4234283c 2089 MyBuild.BuildReport.GenerateReport(BuildDurationStr)\r
52302d4d
LG
2090 MyBuild.Db.Close()\r
2091 EdkLogger.SetLevel(EdkLogger.QUIET)\r
6780eef1
LG
2092 EdkLogger.quiet("\n- %s -" % Conclusion)\r
2093 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))\r
4234283c 2094 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)\r
52302d4d
LG
2095 return ReturnCode\r
2096\r
2097if __name__ == '__main__':\r
2098 r = Main()\r
2099 ## 0-127 is a safe return range, and 1 is a standard default error\r
2100 if r < 0 or r > 127: r = 1\r
2101 sys.exit(r)\r
2102\r