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