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