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