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