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