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