2 # build a platform or a module
4 # Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
5 # Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
7 # This program and the accompanying materials
8 # are licensed and made available under the terms and conditions of the BSD License
9 # which accompanies this distribution. The full text of the license may be found at
10 # http://opensource.org/licenses/bsd-license.php
12 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 import Common
.LongFilePathOs
as os
27 import encodings
.ascii
30 from threading
import *
31 from optparse
import OptionParser
32 from subprocess
import *
33 from Common
import Misc
as Utils
35 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
36 from Common
.LongFilePathSupport
import LongFilePath
37 from Common
.TargetTxtClassObject
import *
38 from Common
.ToolDefClassObject
import *
39 from Common
.DataType
import *
40 from Common
.BuildVersion
import gBUILD_VERSION
41 from AutoGen
.AutoGen
import *
42 from Common
.BuildToolError
import *
43 from Workspace
.WorkspaceDatabase
import *
45 from BuildReport
import BuildReport
46 from GenPatchPcdTable
.GenPatchPcdTable
import *
47 from PatchPcdValue
.PatchPcdValue
import *
49 import Common
.EdkLogger
50 import Common
.GlobalData
as GlobalData
52 # Version and Copyright
53 VersionNumber
= "0.60" + ' ' + gBUILD_VERSION
54 __version__
= "%prog Version " + VersionNumber
55 __copyright__
= "Copyright (c) 2007 - 2014, Intel Corporation All rights reserved."
57 ## standard targets of build command
58 gSupportedTarget
= ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
60 ## build configuration file
61 gBuildConfiguration
= "target.txt"
62 gToolsDefinition
= "tools_def.txt"
64 TemporaryTablePattern
= re
.compile(r
'^_\d+_\d+_[a-fA-F0-9]+$')
67 ## Check environment PATH variable to make sure the specified tool is found
69 # If the tool is found in the PATH, then True is returned
70 # Otherwise, False is returned
72 def IsToolInPath(tool
):
73 if os
.environ
.has_key('PATHEXT'):
74 extns
= os
.environ
['PATHEXT'].split(os
.path
.pathsep
)
77 for pathDir
in os
.environ
['PATH'].split(os
.path
.pathsep
):
79 if os
.path
.exists(os
.path
.join(pathDir
, tool
+ ext
)):
83 ## Check environment variables
85 # Check environment variables that must be set for build. Currently they are
87 # WORKSPACE The directory all packages/platforms start from
88 # EDK_TOOLS_PATH The directory contains all tools needed by the build
89 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
91 # If any of above environment variable is not set or has error, the build
94 def CheckEnvVariable():
96 if "WORKSPACE" not in os
.environ
:
97 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
98 ExtraData
="WORKSPACE")
100 WorkspaceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["WORKSPACE"]))
101 if not os
.path
.exists(WorkspaceDir
):
102 EdkLogger
.error("build", FILE_NOT_FOUND
, "WORKSPACE doesn't exist", ExtraData
="%s" % WorkspaceDir
)
103 elif ' ' in WorkspaceDir
:
104 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in WORKSPACE path",
105 ExtraData
=WorkspaceDir
)
106 os
.environ
["WORKSPACE"] = WorkspaceDir
109 # Check EFI_SOURCE (Edk build convention). EDK_SOURCE will always point to ECP
111 if "ECP_SOURCE" not in os
.environ
:
112 os
.environ
["ECP_SOURCE"] = os
.path
.join(WorkspaceDir
, GlobalData
.gEdkCompatibilityPkg
)
113 if "EFI_SOURCE" not in os
.environ
:
114 os
.environ
["EFI_SOURCE"] = os
.environ
["ECP_SOURCE"]
115 if "EDK_SOURCE" not in os
.environ
:
116 os
.environ
["EDK_SOURCE"] = os
.environ
["ECP_SOURCE"]
119 # Unify case of characters on case-insensitive systems
121 EfiSourceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["EFI_SOURCE"]))
122 EdkSourceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_SOURCE"]))
123 EcpSourceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["ECP_SOURCE"]))
125 os
.environ
["EFI_SOURCE"] = EfiSourceDir
126 os
.environ
["EDK_SOURCE"] = EdkSourceDir
127 os
.environ
["ECP_SOURCE"] = EcpSourceDir
128 os
.environ
["EDK_TOOLS_PATH"] = os
.path
.normcase(os
.environ
["EDK_TOOLS_PATH"])
130 if not os
.path
.exists(EcpSourceDir
):
131 EdkLogger
.verbose("ECP_SOURCE = %s doesn't exist. Edk modules could not be built." % EcpSourceDir
)
132 elif ' ' in EcpSourceDir
:
133 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in ECP_SOURCE path",
134 ExtraData
=EcpSourceDir
)
135 if not os
.path
.exists(EdkSourceDir
):
136 if EdkSourceDir
== EcpSourceDir
:
137 EdkLogger
.verbose("EDK_SOURCE = %s doesn't exist. Edk modules could not be built." % EdkSourceDir
)
139 EdkLogger
.error("build", PARAMETER_INVALID
, "EDK_SOURCE does not exist",
140 ExtraData
=EdkSourceDir
)
141 elif ' ' in EdkSourceDir
:
142 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in EDK_SOURCE path",
143 ExtraData
=EdkSourceDir
)
144 if not os
.path
.exists(EfiSourceDir
):
145 if EfiSourceDir
== EcpSourceDir
:
146 EdkLogger
.verbose("EFI_SOURCE = %s doesn't exist. Edk modules could not be built." % EfiSourceDir
)
148 EdkLogger
.error("build", PARAMETER_INVALID
, "EFI_SOURCE does not exist",
149 ExtraData
=EfiSourceDir
)
150 elif ' ' in EfiSourceDir
:
151 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in EFI_SOURCE path",
152 ExtraData
=EfiSourceDir
)
154 # change absolute path to relative path to WORKSPACE
155 if EfiSourceDir
.upper().find(WorkspaceDir
.upper()) != 0:
156 EdkLogger
.error("build", PARAMETER_INVALID
, "EFI_SOURCE is not under WORKSPACE",
157 ExtraData
="WORKSPACE = %s\n EFI_SOURCE = %s" % (WorkspaceDir
, EfiSourceDir
))
158 if EdkSourceDir
.upper().find(WorkspaceDir
.upper()) != 0:
159 EdkLogger
.error("build", PARAMETER_INVALID
, "EDK_SOURCE is not under WORKSPACE",
160 ExtraData
="WORKSPACE = %s\n EDK_SOURCE = %s" % (WorkspaceDir
, EdkSourceDir
))
161 if EcpSourceDir
.upper().find(WorkspaceDir
.upper()) != 0:
162 EdkLogger
.error("build", PARAMETER_INVALID
, "ECP_SOURCE is not under WORKSPACE",
163 ExtraData
="WORKSPACE = %s\n ECP_SOURCE = %s" % (WorkspaceDir
, EcpSourceDir
))
165 # check EDK_TOOLS_PATH
166 if "EDK_TOOLS_PATH" not in os
.environ
:
167 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
168 ExtraData
="EDK_TOOLS_PATH")
171 if "PATH" not in os
.environ
:
172 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
175 GlobalData
.gWorkspace
= WorkspaceDir
176 GlobalData
.gEfiSource
= EfiSourceDir
177 GlobalData
.gEdkSource
= EdkSourceDir
178 GlobalData
.gEcpSource
= EcpSourceDir
180 GlobalData
.gGlobalDefines
["WORKSPACE"] = WorkspaceDir
181 GlobalData
.gGlobalDefines
["EFI_SOURCE"] = EfiSourceDir
182 GlobalData
.gGlobalDefines
["EDK_SOURCE"] = EdkSourceDir
183 GlobalData
.gGlobalDefines
["ECP_SOURCE"] = EcpSourceDir
184 GlobalData
.gGlobalDefines
["EDK_TOOLS_PATH"] = os
.environ
["EDK_TOOLS_PATH"]
186 ## Get normalized file path
188 # Convert the path to be local format, and remove the WORKSPACE path at the
189 # beginning if the file path is given in full path.
191 # @param FilePath File path to be normalized
192 # @param Workspace Workspace path which the FilePath will be checked against
194 # @retval string The normalized file path
196 def NormFile(FilePath
, Workspace
):
197 # check if the path is absolute or relative
198 if os
.path
.isabs(FilePath
):
199 FileFullPath
= os
.path
.normpath(FilePath
)
201 FileFullPath
= os
.path
.normpath(os
.path
.join(Workspace
, FilePath
))
203 # check if the file path exists or not
204 if not os
.path
.isfile(FileFullPath
):
205 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath
)
207 # remove workspace directory from the beginning part of the file path
208 if Workspace
[-1] in ["\\", "/"]:
209 return FileFullPath
[len(Workspace
):]
211 return FileFullPath
[(len(Workspace
) + 1):]
213 ## Get the output of an external program
215 # This is the entrance method of thread reading output of an external program and
216 # putting them in STDOUT/STDERR of current program.
218 # @param From The stream message read from
219 # @param To The stream message put on
220 # @param ExitFlag The flag used to indicate stopping reading
222 def ReadMessage(From
, To
, ExitFlag
):
224 # read one line a time
225 Line
= From
.readline()
226 # empty string means "end"
227 if Line
!= None and Line
!= "":
234 ## Launch an external program
236 # This method will call subprocess.Popen to execute an external program with
237 # given options in specified directory. Because of the dead-lock issue during
238 # redirecting output of the external program, threads are used to to do the
241 # @param Command A list or string containing the call of the program
242 # @param WorkingDir The directory in which the program will be running
244 def LaunchCommand(Command
, WorkingDir
):
245 # if working directory doesn't exist, Popen() will raise an exception
246 if not os
.path
.isdir(WorkingDir
):
247 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=WorkingDir
)
249 # Command is used as the first Argument in following Popen().
250 # It could be a string or sequence. We find that if command is a string in following Popen(),
251 # ubuntu may fail with an error message that the command is not found.
252 # So here we may need convert command from string to list instance.
253 if not isinstance(Command
, list):
254 if platform
.system() != 'Windows':
255 Command
= Command
.split()
258 EndOfProcedure
= None
261 Proc
= Popen(Command
, stdout
=PIPE
, stderr
=PIPE
, env
=os
.environ
, cwd
=WorkingDir
, bufsize
=-1)
263 # launch two threads to read the STDOUT and STDERR
264 EndOfProcedure
= Event()
265 EndOfProcedure
.clear()
267 StdOutThread
= Thread(target
=ReadMessage
, args
=(Proc
.stdout
, EdkLogger
.info
, EndOfProcedure
))
268 StdOutThread
.setName("STDOUT-Redirector")
269 StdOutThread
.setDaemon(False)
273 StdErrThread
= Thread(target
=ReadMessage
, args
=(Proc
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
274 StdErrThread
.setName("STDERR-Redirector")
275 StdErrThread
.setDaemon(False)
278 # waiting for program exit
280 except: # in case of aborting
281 # terminate the threads redirecting the program output
282 if EndOfProcedure
!= None:
285 if type(Command
) != type(""):
286 Command
= " ".join(Command
)
287 EdkLogger
.error("build", COMMAND_FAILURE
, "Failed to start command", ExtraData
="%s [%s]" % (Command
, WorkingDir
))
294 # check the return code of the program
295 if Proc
.returncode
!= 0:
296 if type(Command
) != type(""):
297 Command
= " ".join(Command
)
298 EdkLogger
.error("build", COMMAND_FAILURE
, ExtraData
="%s [%s]" % (Command
, WorkingDir
))
300 ## The smallest unit that can be built in multi-thread build mode
302 # This is the base class of build unit. The "Obj" parameter must provide
303 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
306 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
311 # @param self The object pointer
312 # @param Obj The object the build is working on
313 # @param Target The build target name, one of gSupportedTarget
314 # @param Dependency The BuildUnit(s) which must be completed in advance
315 # @param WorkingDir The directory build command starts in
317 def __init__(self
, Obj
, BuildCommand
, Target
, Dependency
, WorkingDir
="."):
318 self
.BuildObject
= Obj
319 self
.Dependency
= Dependency
320 self
.WorkingDir
= WorkingDir
322 self
.BuildCommand
= BuildCommand
324 EdkLogger
.error("build", OPTION_MISSING
,
325 "No build command found for this module. "
326 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
327 (Obj
.BuildTarget
, Obj
.ToolChain
, Obj
.Arch
),
333 # It just returns the string representation of self.BuildObject
335 # @param self The object pointer
338 return str(self
.BuildObject
)
340 ## "==" operator method
342 # It just compares self.BuildObject with "Other". So self.BuildObject must
343 # provide its own __eq__() method.
345 # @param self The object pointer
346 # @param Other The other BuildUnit object compared to
348 def __eq__(self
, Other
):
349 return Other
!= None and self
.BuildObject
== Other
.BuildObject \
350 and self
.BuildObject
.Arch
== Other
.BuildObject
.Arch
354 # It just returns the hash value of self.BuildObject which must be hashable.
356 # @param self The object pointer
359 return hash(self
.BuildObject
) + hash(self
.BuildObject
.Arch
)
362 return repr(self
.BuildObject
)
364 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
366 # This class is for module build by nmake/make build system. The "Obj" parameter
367 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
368 # be make units missing build.
370 # Currently the "Obj" should be only ModuleAutoGen object.
372 class ModuleMakeUnit(BuildUnit
):
375 # @param self The object pointer
376 # @param Obj The ModuleAutoGen object the build is working on
377 # @param Target The build target name, one of gSupportedTarget
379 def __init__(self
, Obj
, Target
):
380 Dependency
= [ModuleMakeUnit(La
, Target
) for La
in Obj
.LibraryAutoGenList
]
381 BuildUnit
.__init
__(self
, Obj
, Obj
.BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
382 if Target
in [None, "", "all"]:
383 self
.Target
= "tbuild"
385 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
387 # This class is for platform build by nmake/make build system. The "Obj" parameter
388 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
389 # be make units missing build.
391 # Currently the "Obj" should be only PlatformAutoGen object.
393 class PlatformMakeUnit(BuildUnit
):
396 # @param self The object pointer
397 # @param Obj The PlatformAutoGen object the build is working on
398 # @param Target The build target name, one of gSupportedTarget
400 def __init__(self
, Obj
, Target
):
401 Dependency
= [ModuleMakeUnit(Lib
, Target
) for Lib
in self
.BuildObject
.LibraryAutoGenList
]
402 Dependency
.extend([ModuleMakeUnit(Mod
, Target
) for Mod
in self
.BuildObject
.ModuleAutoGenList
])
403 BuildUnit
.__init
__(self
, Obj
, Obj
.BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
405 ## The class representing the task of a module build or platform build
407 # This class manages the build tasks in multi-thread build mode. Its jobs include
408 # scheduling thread running, catching thread error, monitor the thread status, etc.
411 # queue for tasks waiting for schedule
412 _PendingQueue
= sdict()
413 _PendingQueueLock
= threading
.Lock()
415 # queue for tasks ready for running
416 _ReadyQueue
= sdict()
417 _ReadyQueueLock
= threading
.Lock()
419 # queue for run tasks
420 _RunningQueue
= sdict()
421 _RunningQueueLock
= threading
.Lock()
423 # queue containing all build tasks, in case duplicate build
426 # flag indicating error occurs in a running thread
427 _ErrorFlag
= threading
.Event()
431 # BoundedSemaphore object used to control the number of running threads
434 # flag indicating if the scheduler is started or not
435 _SchedulerStopped
= threading
.Event()
436 _SchedulerStopped
.set()
438 ## Start the task scheduler thread
440 # @param MaxThreadNumber The maximum thread number
441 # @param ExitFlag Flag used to end the scheduler
444 def StartScheduler(MaxThreadNumber
, ExitFlag
):
445 SchedulerThread
= Thread(target
=BuildTask
.Scheduler
, args
=(MaxThreadNumber
, ExitFlag
))
446 SchedulerThread
.setName("Build-Task-Scheduler")
447 SchedulerThread
.setDaemon(False)
448 SchedulerThread
.start()
449 # wait for the scheduler to be started, especially useful in Linux
450 while not BuildTask
.IsOnGoing():
455 # @param MaxThreadNumber The maximum thread number
456 # @param ExitFlag Flag used to end the scheduler
459 def Scheduler(MaxThreadNumber
, ExitFlag
):
460 BuildTask
._SchedulerStopped
.clear()
462 # use BoundedSemaphore to control the maximum running threads
463 BuildTask
._Thread
= BoundedSemaphore(MaxThreadNumber
)
465 # scheduling loop, which will exits when no pending/ready task and
466 # indicated to do so, or there's error in running thread
468 while (len(BuildTask
._PendingQueue
) > 0 or len(BuildTask
._ReadyQueue
) > 0 \
469 or not ExitFlag
.isSet()) and not BuildTask
._ErrorFlag
.isSet():
470 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Pending Queue (%d), Ready Queue (%d)"
471 % (len(BuildTask
._PendingQueue
), len(BuildTask
._ReadyQueue
)))
473 # get all pending tasks
474 BuildTask
._PendingQueueLock
.acquire()
475 BuildObjectList
= BuildTask
._PendingQueue
.keys()
477 # check if their dependency is resolved, and if true, move them
480 for BuildObject
in BuildObjectList
:
481 Bt
= BuildTask
._PendingQueue
[BuildObject
]
483 BuildTask
._ReadyQueue
[BuildObject
] = BuildTask
._PendingQueue
.pop(BuildObject
)
484 BuildTask
._PendingQueueLock
.release()
486 # launch build thread until the maximum number of threads is reached
487 while not BuildTask
._ErrorFlag
.isSet():
488 # empty ready queue, do nothing further
489 if len(BuildTask
._ReadyQueue
) == 0:
492 # wait for active thread(s) exit
493 BuildTask
._Thread
.acquire(True)
495 # start a new build thread
496 Bo
= BuildTask
._ReadyQueue
.keys()[0]
497 Bt
= BuildTask
._ReadyQueue
.pop(Bo
)
499 # move into running queue
500 BuildTask
._RunningQueueLock
.acquire()
501 BuildTask
._RunningQueue
[Bo
] = Bt
502 BuildTask
._RunningQueueLock
.release()
511 # wait for all running threads exit
512 if BuildTask
._ErrorFlag
.isSet():
513 EdkLogger
.quiet("\nWaiting for all build threads exit...")
514 # while not BuildTask._ErrorFlag.isSet() and \
515 while len(BuildTask
._RunningQueue
) > 0:
516 EdkLogger
.verbose("Waiting for thread ending...(%d)" % len(BuildTask
._RunningQueue
))
517 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Threads [%s]" % ", ".join([Th
.getName() for Th
in threading
.enumerate()]))
520 except BaseException
, X
:
522 # TRICK: hide the output of threads left runing, so that the user can
523 # catch the error message easily
525 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
526 BuildTask
._ErrorFlag
.set()
527 BuildTask
._ErrorMessage
= "build thread scheduler error\n\t%s" % str(X
)
529 BuildTask
._PendingQueue
.clear()
530 BuildTask
._ReadyQueue
.clear()
531 BuildTask
._RunningQueue
.clear()
532 BuildTask
._TaskQueue
.clear()
533 BuildTask
._SchedulerStopped
.set()
535 ## Wait for all running method exit
538 def WaitForComplete():
539 BuildTask
._SchedulerStopped
.wait()
541 ## Check if the scheduler is running or not
545 return not BuildTask
._SchedulerStopped
.isSet()
550 if BuildTask
.IsOnGoing():
551 BuildTask
._ErrorFlag
.set()
552 BuildTask
.WaitForComplete()
554 ## Check if there's error in running thread
556 # Since the main thread cannot catch exceptions in other thread, we have to
557 # use threading.Event to communicate this formation to main thread.
561 return BuildTask
._ErrorFlag
.isSet()
563 ## Get error message in running thread
565 # Since the main thread cannot catch exceptions in other thread, we have to
566 # use a static variable to communicate this message to main thread.
569 def GetErrorMessage():
570 return BuildTask
._ErrorMessage
572 ## Factory method to create a BuildTask object
574 # This method will check if a module is building or has been built. And if
575 # true, just return the associated BuildTask object in the _TaskQueue. If
576 # not, create and return a new BuildTask object. The new BuildTask object
577 # will be appended to the _PendingQueue for scheduling later.
579 # @param BuildItem A BuildUnit object representing a build object
580 # @param Dependency The dependent build object of BuildItem
583 def New(BuildItem
, Dependency
=None):
584 if BuildItem
in BuildTask
._TaskQueue
:
585 Bt
= BuildTask
._TaskQueue
[BuildItem
]
589 Bt
._Init
(BuildItem
, Dependency
)
590 BuildTask
._TaskQueue
[BuildItem
] = Bt
592 BuildTask
._PendingQueueLock
.acquire()
593 BuildTask
._PendingQueue
[BuildItem
] = Bt
594 BuildTask
._PendingQueueLock
.release()
598 ## The real constructor of BuildTask
600 # @param BuildItem A BuildUnit object representing a build object
601 # @param Dependency The dependent build object of BuildItem
603 def _Init(self
, BuildItem
, Dependency
=None):
604 self
.BuildItem
= BuildItem
606 self
.DependencyList
= []
607 if Dependency
== None:
608 Dependency
= BuildItem
.Dependency
610 Dependency
.extend(BuildItem
.Dependency
)
611 self
.AddDependency(Dependency
)
612 # flag indicating build completes, used to avoid unnecessary re-build
613 self
.CompleteFlag
= False
615 ## Check if all dependent build tasks are completed or not
619 for Dep
in self
.DependencyList
:
620 if Dep
.CompleteFlag
== True:
627 ## Add dependent build task
629 # @param Dependency The list of dependent build objects
631 def AddDependency(self
, Dependency
):
632 for Dep
in Dependency
:
633 if not Dep
.BuildObject
.IsBinaryModule
:
634 self
.DependencyList
.append(BuildTask
.New(Dep
)) # BuildTask list
636 ## The thread wrapper of LaunchCommand function
638 # @param Command A list or string contains the call of the command
639 # @param WorkingDir The directory in which the program will be running
641 def _CommandThread(self
, Command
, WorkingDir
):
643 LaunchCommand(Command
, WorkingDir
)
644 self
.CompleteFlag
= True
647 # TRICK: hide the output of threads left runing, so that the user can
648 # catch the error message easily
650 if not BuildTask
._ErrorFlag
.isSet():
651 GlobalData
.gBuildingModule
= "%s [%s, %s, %s]" % (str(self
.BuildItem
.BuildObject
),
652 self
.BuildItem
.BuildObject
.Arch
,
653 self
.BuildItem
.BuildObject
.ToolChain
,
654 self
.BuildItem
.BuildObject
.BuildTarget
656 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
657 BuildTask
._ErrorFlag
.set()
658 BuildTask
._ErrorMessage
= "%s broken\n %s [%s]" % \
659 (threading
.currentThread().getName(), Command
, WorkingDir
)
660 # indicate there's a thread is available for another build task
661 BuildTask
._RunningQueueLock
.acquire()
662 BuildTask
._RunningQueue
.pop(self
.BuildItem
)
663 BuildTask
._RunningQueueLock
.release()
664 BuildTask
._Thread
.release()
666 ## Start build task thread
669 EdkLogger
.quiet("Building ... %s" % repr(self
.BuildItem
))
670 Command
= self
.BuildItem
.BuildCommand
+ [self
.BuildItem
.Target
]
671 self
.BuildTread
= Thread(target
=self
._CommandThread
, args
=(Command
, self
.BuildItem
.WorkingDir
))
672 self
.BuildTread
.setName("build thread")
673 self
.BuildTread
.setDaemon(False)
674 self
.BuildTread
.start()
676 ## The class contains the information related to EFI image
681 # Constructor will load all required image information.
683 # @param BaseName The full file path of image.
684 # @param Guid The GUID for image.
685 # @param Arch Arch of this image.
686 # @param OutputDir The output directory for image.
687 # @param DebugDir The debug directory for image.
688 # @param ImageClass PeImage Information
690 def __init__(self
, BaseName
, Guid
, Arch
, OutputDir
, DebugDir
, ImageClass
):
691 self
.BaseName
= BaseName
694 self
.OutputDir
= OutputDir
695 self
.DebugDir
= DebugDir
696 self
.Image
= ImageClass
697 self
.Image
.Size
= (self
.Image
.Size
/ 0x1000 + 1) * 0x1000
699 ## The class implementing the EDK2 build process
701 # The build process includes:
702 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
703 # 2. Parse DSC file of active platform
704 # 3. Parse FDF file if any
705 # 4. Establish build database, including parse all other files (module, package)
706 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
707 # 6. Call build command
712 # Constructor will load all necessary configurations, parse platform, modules
713 # and packages and the establish a database for AutoGen.
715 # @param Target The build command target, one of gSupportedTarget
716 # @param WorkspaceDir The directory of workspace
717 # @param BuildOptions Build options passed from command line
719 def __init__(self
, Target
, WorkspaceDir
, BuildOptions
):
720 self
.WorkspaceDir
= WorkspaceDir
722 self
.PlatformFile
= BuildOptions
.PlatformFile
723 self
.ModuleFile
= BuildOptions
.ModuleFile
724 self
.ArchList
= BuildOptions
.TargetArch
725 self
.ToolChainList
= BuildOptions
.ToolChain
726 self
.BuildTargetList
= BuildOptions
.BuildTarget
727 self
.Fdf
= BuildOptions
.FdfFile
728 self
.FdList
= BuildOptions
.RomImage
729 self
.FvList
= BuildOptions
.FvImage
730 self
.CapList
= BuildOptions
.CapName
731 self
.SilentMode
= BuildOptions
.SilentMode
732 self
.ThreadNumber
= BuildOptions
.ThreadNumber
733 self
.SkipAutoGen
= BuildOptions
.SkipAutoGen
734 self
.Reparse
= BuildOptions
.Reparse
735 self
.SkuId
= BuildOptions
.SkuId
736 self
.ConfDirectory
= BuildOptions
.ConfDirectory
737 self
.SpawnMode
= True
738 self
.BuildReport
= BuildReport(BuildOptions
.ReportFile
, BuildOptions
.ReportType
)
739 self
.TargetTxt
= TargetTxtClassObject()
740 self
.ToolDef
= ToolDefClassObject()
741 #Set global flag for build mode
742 GlobalData
.gIgnoreSource
= BuildOptions
.IgnoreSources
744 if self
.ConfDirectory
:
745 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
746 ConfDirectoryPath
= os
.path
.normpath(self
.ConfDirectory
)
748 if not os
.path
.isabs(ConfDirectoryPath
):
749 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
750 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
751 ConfDirectoryPath
= os
.path
.join(self
.WorkspaceDir
, ConfDirectoryPath
)
753 # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf
754 ConfDirectoryPath
= os
.path
.join(self
.WorkspaceDir
, 'Conf')
755 GlobalData
.gConfDirectory
= ConfDirectoryPath
756 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
758 if BuildOptions
.DisableCache
:
759 self
.Db
= WorkspaceDatabase(":memory:")
761 self
.Db
= WorkspaceDatabase(GlobalData
.gDatabasePath
, self
.Reparse
)
762 self
.BuildDatabase
= self
.Db
.BuildObject
764 self
.LoadFixAddress
= 0
765 self
.UniFlag
= BuildOptions
.Flag
766 self
.BuildModules
= []
768 # print dot character during doing some time-consuming work
769 self
.Progress
= Utils
.Progressor()
773 # print current build environment and configuration
774 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
775 EdkLogger
.quiet("%-16s = %s" % ("ECP_SOURCE", os
.environ
["ECP_SOURCE"]))
776 EdkLogger
.quiet("%-16s = %s" % ("EDK_SOURCE", os
.environ
["EDK_SOURCE"]))
777 EdkLogger
.quiet("%-16s = %s" % ("EFI_SOURCE", os
.environ
["EFI_SOURCE"]))
778 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
782 os
.chdir(self
.WorkspaceDir
)
784 ## Load configuration
786 # This method will parse target.txt and get the build configurations.
788 def LoadConfiguration(self
):
790 # Check target.txt and tools_def.txt and Init them
792 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(GlobalData
.gConfDirectory
, gBuildConfiguration
))
793 if os
.path
.isfile(BuildConfigurationFile
) == True:
794 StatusCode
= self
.TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
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
, 'Conf', ToolDefinitionFile
))
800 if os
.path
.isfile(ToolDefinitionFile
) == True:
801 StatusCode
= self
.ToolDef
.LoadToolDefFile(ToolDefinitionFile
)
803 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=ToolDefinitionFile
)
805 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
807 # if no ARCH given in command line, get it from target.txt
808 if not self
.ArchList
:
809 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TARGET_ARCH
]
810 self
.ArchList
= tuple(self
.ArchList
)
812 # if no build target given in command line, get it from target.txt
813 if not self
.BuildTargetList
:
814 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TARGET
]
816 # if no tool chain given in command line, get it from target.txt
817 if not self
.ToolChainList
:
818 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
819 if self
.ToolChainList
== None or len(self
.ToolChainList
) == 0:
820 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
822 # check if the tool chains are defined or not
823 NewToolChainList
= []
824 for ToolChain
in self
.ToolChainList
:
825 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
826 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
828 NewToolChainList
.append(ToolChain
)
829 # if no tool chain available, break the build
830 if len(NewToolChainList
) == 0:
831 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
832 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
834 self
.ToolChainList
= NewToolChainList
836 if self
.ThreadNumber
== None:
837 self
.ThreadNumber
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
838 if self
.ThreadNumber
== '':
839 self
.ThreadNumber
= 0
841 self
.ThreadNumber
= int(self
.ThreadNumber
, 0)
843 if self
.ThreadNumber
== 0:
844 self
.ThreadNumber
= 1
846 if not self
.PlatformFile
:
847 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
849 # Try to find one in current directory
850 WorkingDirectory
= os
.getcwd()
851 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
852 FileNum
= len(FileList
)
854 EdkLogger
.error("build", OPTION_MISSING
,
855 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
857 PlatformFile
= FileList
[0]
859 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
860 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
862 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
864 ## Initialize build configuration
866 # This method will parse DSC file and merge the configurations from
867 # command line and target.txt, then get the final build configurations.
870 # parse target.txt, tools_def.txt, and platform file
871 self
.LoadConfiguration()
873 # Allow case-insensitive for those from command line or configuration file
874 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
876 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
878 # create metafile database
879 self
.Db
.InitDatabase()
881 ## Build a module or platform
883 # Create autogen code and makefile for a module or platform, and the launch
884 # "make" command to build it
886 # @param Target The target of build command
887 # @param Platform The platform file
888 # @param Module The module file
889 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
890 # @param ToolChain The name of toolchain to build
891 # @param Arch The arch of the module/platform
892 # @param CreateDepModuleCodeFile Flag used to indicate creating code
893 # for dependent modules/Libraries
894 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
895 # for dependent modules/Libraries
897 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
898 if AutoGenObject
== None:
901 # skip file generation for cleanxxx targets, run and fds target
902 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
903 # for target which must generate AutoGen code and makefile
904 if not self
.SkipAutoGen
or Target
== 'genc':
905 self
.Progress
.Start("Generating code")
906 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
907 self
.Progress
.Stop("done!")
911 if not self
.SkipAutoGen
or Target
== 'genmake':
912 self
.Progress
.Start("Generating makefile")
913 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
914 self
.Progress
.Stop("done!")
915 if Target
== "genmake":
918 # always recreate top/platform makefile when clean, just in case of inconsistency
919 AutoGenObject
.CreateCodeFile(False)
920 AutoGenObject
.CreateMakeFile(False)
922 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
923 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
925 BuildCommand
= AutoGenObject
.BuildCommand
926 if BuildCommand
== None or len(BuildCommand
) == 0:
927 EdkLogger
.error("build", OPTION_MISSING
,
928 "No build command found for this module. "
929 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
930 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
931 ExtraData
=str(AutoGenObject
))
933 makefile
= GenMake
.BuildFile(AutoGenObject
)._FILE
_NAME
_[GenMake
.gMakeType
]
937 LaunchCommand(AutoGenObject
.GenFdsCommand
, AutoGenObject
.MakeFileDir
)
942 RunDir
= os
.path
.normpath(os
.path
.join(AutoGenObject
.BuildDir
, GlobalData
.gGlobalDefines
['ARCH']))
943 Command
= '.\SecMain'
945 LaunchCommand(Command
, RunDir
)
950 BuildCommand
= BuildCommand
+ [Target
]
951 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
952 self
.CreateAsBuiltInf()
956 if Target
== 'libraries':
957 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
958 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
959 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
963 if Target
== 'modules':
964 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
965 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
966 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
967 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
968 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, makefile
)), 'pbuild']
969 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
970 self
.CreateAsBuiltInf()
974 if Target
== 'cleanlib':
975 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
976 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
977 if os
.path
.exists(LibMakefile
):
978 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
979 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
983 if Target
== 'clean':
984 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
985 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, makefile
))
986 if os
.path
.exists(ModMakefile
):
987 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
988 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
989 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
990 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
991 if os
.path
.exists(LibMakefile
):
992 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
993 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
997 if Target
== 'cleanall':
999 #os.rmdir(AutoGenObject.BuildDir)
1000 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1001 except WindowsError, X
:
1002 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1005 ## Build a module or platform
1007 # Create autogen code and makefile for a module or platform, and the launch
1008 # "make" command to build it
1010 # @param Target The target of build command
1011 # @param Platform The platform file
1012 # @param Module The module file
1013 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1014 # @param ToolChain The name of toolchain to build
1015 # @param Arch The arch of the module/platform
1016 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1017 # for dependent modules/Libraries
1018 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1019 # for dependent modules/Libraries
1021 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1022 if AutoGenObject
== None:
1025 # skip file generation for cleanxxx targets, run and fds target
1026 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1027 # for target which must generate AutoGen code and makefile
1028 if not self
.SkipAutoGen
or Target
== 'genc':
1029 self
.Progress
.Start("Generating code")
1030 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1031 self
.Progress
.Stop("done!")
1032 if Target
== "genc":
1035 if not self
.SkipAutoGen
or Target
== 'genmake':
1036 self
.Progress
.Start("Generating makefile")
1037 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1038 #AutoGenObject.CreateAsBuiltInf()
1039 self
.Progress
.Stop("done!")
1040 if Target
== "genmake":
1043 # always recreate top/platform makefile when clean, just in case of inconsistency
1044 AutoGenObject
.CreateCodeFile(False)
1045 AutoGenObject
.CreateMakeFile(False)
1047 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1048 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1050 BuildCommand
= AutoGenObject
.BuildCommand
1051 if BuildCommand
== None or len(BuildCommand
) == 0:
1052 EdkLogger
.error("build", OPTION_MISSING
,
1053 "No build command found for this module. "
1054 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1055 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1056 ExtraData
=str(AutoGenObject
))
1060 LaunchCommand(AutoGenObject
.GenFdsCommand
, AutoGenObject
.MakeFileDir
)
1065 RunDir
= os
.path
.normpath(os
.path
.join(AutoGenObject
.BuildDir
, GlobalData
.gGlobalDefines
['ARCH']))
1066 Command
= '.\SecMain'
1068 LaunchCommand(Command
, RunDir
)
1072 BuildCommand
= BuildCommand
+ [Target
]
1074 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1075 self
.CreateAsBuiltInf()
1079 if Target
== 'libraries':
1086 if Target
== 'cleanall':
1088 #os.rmdir(AutoGenObject.BuildDir)
1089 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1090 except WindowsError, X
:
1091 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1094 ## Rebase module image and Get function address for the input module list.
1096 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1098 AddrIsOffset
= False
1099 InfFileNameList
= ModuleList
.keys()
1100 #InfFileNameList.sort()
1101 for InfFile
in InfFileNameList
:
1102 sys
.stdout
.write (".")
1104 ModuleInfo
= ModuleList
[InfFile
]
1105 ModuleName
= ModuleInfo
.BaseName
1106 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1107 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1108 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1110 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1112 # Update Image to new BaseAddress by GenFw tool
1114 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1115 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1118 # Set new address to the section header only for SMM driver.
1120 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1121 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1123 # Collect funtion address from Map file
1125 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1127 if os
.path
.exists(ImageMapTable
):
1128 OrigImageBaseAddress
= 0
1129 ImageMap
= open (ImageMapTable
, 'r')
1130 for LinStr
in ImageMap
:
1131 if len (LinStr
.strip()) == 0:
1134 # Get the preferred address set on link time.
1136 if LinStr
.find ('Preferred load address is') != -1:
1137 StrList
= LinStr
.split()
1138 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1140 StrList
= LinStr
.split()
1141 if len (StrList
) > 4:
1142 if StrList
[3] == 'f' or StrList
[3] =='F':
1144 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1145 FunctionList
.append ((Name
, RelativeAddress
))
1146 if ModuleInfo
.Arch
== 'IPF' and Name
.endswith('_ModuleEntryPoint'):
1148 # Get the real entry point address for IPF image.
1150 ModuleInfo
.Image
.EntryPoint
= RelativeAddress
1153 # Add general information.
1156 MapBuffer
.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1158 MapBuffer
.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1160 MapBuffer
.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1162 # Add guid and general seciton section.
1164 TextSectionAddress
= 0
1165 DataSectionAddress
= 0
1166 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1167 if SectionHeader
[0] == '.text':
1168 TextSectionAddress
= SectionHeader
[1]
1169 elif SectionHeader
[0] in ['.data', '.sdata']:
1170 DataSectionAddress
= SectionHeader
[1]
1172 MapBuffer
.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1174 MapBuffer
.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1176 # Add debug image full path.
1178 MapBuffer
.write('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1180 # Add funtion address
1182 for Function
in FunctionList
:
1184 MapBuffer
.write(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1186 MapBuffer
.write(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1190 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1193 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1195 ## Collect MAP information of all FVs
1197 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1199 # First get the XIP base address for FV map file.
1200 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1201 GuidName
= re
.compile("\(GUID=[-a-fA-F0-9]+")
1202 for FvName
in Wa
.FdfProfile
.FvDict
.keys():
1203 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1204 if not os
.path
.exists(FvMapBuffer
):
1206 FvMap
= open(FvMapBuffer
, 'r')
1207 #skip FV size information
1213 MatchGuid
= GuidPattern
.match(Line
)
1214 if MatchGuid
!= None:
1216 # Replace GUID with module name
1218 GuidString
= MatchGuid
.group()
1219 if GuidString
.upper() in ModuleList
:
1220 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1221 MapBuffer
.write('%s' % (Line
))
1223 # Add the debug image full path.
1225 MatchGuid
= GuidName
.match(Line
)
1226 if MatchGuid
!= None:
1227 GuidString
= MatchGuid
.group().split("=")[1]
1228 if GuidString
.upper() in ModuleList
:
1229 MapBuffer
.write('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1233 ## Collect MAP information of all modules
1235 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1236 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1238 PatchEfiImageList
= []
1246 # reserve 4K size in SMRAM to make SMM module address not from 0.
1248 IsIpfPlatform
= False
1249 if 'IPF' in self
.ArchList
:
1250 IsIpfPlatform
= True
1251 for ModuleGuid
in ModuleList
:
1252 Module
= ModuleList
[ModuleGuid
]
1253 GlobalData
.gProcessingFile
= "%s [%s, %s, %s]" % (Module
.MetaFile
, Module
.Arch
, Module
.ToolChain
, Module
.BuildTarget
)
1255 OutputImageFile
= ''
1256 for ResultFile
in Module
.CodaTargetList
:
1257 if str(ResultFile
.Target
).endswith('.efi'):
1259 # module list for PEI, DXE, RUNTIME and SMM
1261 OutputImageFile
= os
.path
.join(Module
.OutputDir
, Module
.Name
+ '.efi')
1262 ImageClass
= PeImageClass (OutputImageFile
)
1263 if not ImageClass
.IsValid
:
1264 EdkLogger
.error("build", FILE_PARSE_FAILURE
, ExtraData
=ImageClass
.ErrorInfo
)
1265 ImageInfo
= PeImageInfo(Module
.Name
, Module
.Guid
, Module
.Arch
, Module
.OutputDir
, Module
.DebugDir
, ImageClass
)
1266 if Module
.ModuleType
in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER','PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']:
1267 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1268 PeiSize
+= ImageInfo
.Image
.Size
1269 elif Module
.ModuleType
in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']:
1270 BtModuleList
[Module
.MetaFile
] = ImageInfo
1271 BtSize
+= ImageInfo
.Image
.Size
1272 elif Module
.ModuleType
in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']:
1273 RtModuleList
[Module
.MetaFile
] = ImageInfo
1274 #IPF runtime driver needs to be at 2 page alignment.
1275 if IsIpfPlatform
and ImageInfo
.Image
.Size
% 0x2000 != 0:
1276 ImageInfo
.Image
.Size
= (ImageInfo
.Image
.Size
/ 0x2000 + 1) * 0x2000
1277 RtSize
+= ImageInfo
.Image
.Size
1278 elif Module
.ModuleType
in ['SMM_CORE', 'DXE_SMM_DRIVER']:
1279 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1280 SmmSize
+= ImageInfo
.Image
.Size
1281 if Module
.ModuleType
== 'DXE_SMM_DRIVER':
1282 PiSpecVersion
= '0x00000000'
1283 if 'PI_SPECIFICATION_VERSION' in Module
.Module
.Specification
:
1284 PiSpecVersion
= Module
.Module
.Specification
['PI_SPECIFICATION_VERSION']
1285 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1286 if int(PiSpecVersion
, 16) < 0x0001000A:
1287 BtModuleList
[Module
.MetaFile
] = ImageInfo
1288 BtSize
+= ImageInfo
.Image
.Size
1291 # EFI image is final target.
1292 # Check EFI image contains patchable FixAddress related PCDs.
1294 if OutputImageFile
!= '':
1295 ModuleIsPatch
= False
1296 for Pcd
in Module
.ModulePcdList
:
1297 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST
:
1298 ModuleIsPatch
= True
1300 if not ModuleIsPatch
:
1301 for Pcd
in Module
.LibraryPcdList
:
1302 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST
:
1303 ModuleIsPatch
= True
1306 if not ModuleIsPatch
:
1309 # Module includes the patchable load fix address PCDs.
1310 # It will be fixed up later.
1312 PatchEfiImageList
.append (OutputImageFile
)
1315 # Get Top Memory address
1317 ReservedRuntimeMemorySize
= 0
1318 TopMemoryAddress
= 0
1319 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1320 TopMemoryAddress
= 0
1322 TopMemoryAddress
= self
.LoadFixAddress
1323 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1324 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1325 # Make IPF runtime driver at 2 page alignment.
1327 ReservedRuntimeMemorySize
= TopMemoryAddress
% 0x2000
1328 RtSize
= RtSize
+ ReservedRuntimeMemorySize
1331 # Patch FixAddress related PCDs into EFI image
1333 for EfiImage
in PatchEfiImageList
:
1334 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1335 if not os
.path
.exists(EfiImageMap
):
1338 # Get PCD offset in EFI image by GenPatchPcdTable function
1340 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1342 # Patch real PCD value by PatchPcdValue tool
1344 for PcdInfo
in PcdTable
:
1346 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1347 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
/0x1000))
1348 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1349 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
/0x1000))
1350 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1351 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
/0x1000))
1352 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1353 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
/0x1000))
1354 if ReturnValue
!= 0:
1355 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1357 MapBuffer
.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
/0x1000))
1358 MapBuffer
.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
/0x1000))
1359 MapBuffer
.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
/0x1000))
1360 if len (SmmModuleList
) > 0:
1361 MapBuffer
.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
/0x1000))
1363 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1364 BtBaseAddr
= TopMemoryAddress
- RtSize
1365 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1367 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1368 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1369 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1370 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
= False, ModeIsSmm
= True)
1371 MapBuffer
.write('\n\n')
1372 sys
.stdout
.write ("\n")
1375 ## Save platform Map file
1377 def _SaveMapFile (self
, MapBuffer
, Wa
):
1379 # Map file path is got.
1381 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1383 # Save address map into MAP file.
1385 SaveFileOnChange(MapFilePath
, MapBuffer
.getvalue(), False)
1387 if self
.LoadFixAddress
!= 0:
1388 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" %(MapFilePath))
1391 ## Build active platform for different build targets and different tool chains
1393 def _BuildPlatform(self
):
1394 for BuildTarget
in self
.BuildTargetList
:
1395 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1396 for ToolChain
in self
.ToolChainList
:
1397 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1398 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1399 Wa
= WorkspaceAutoGen(
1416 self
.Fdf
= Wa
.FdfFile
1417 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1418 self
.BuildReport
.AddPlatformReport(Wa
)
1419 self
.Progress
.Stop("done!")
1420 for Arch
in Wa
.ArchList
:
1421 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1422 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1423 for Module
in Pa
.Platform
.Modules
:
1424 # Get ModuleAutoGen object to generate C code file and makefile
1425 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1428 self
.BuildModules
.append(Ma
)
1429 self
._BuildPa
(self
.Target
, Pa
)
1431 # Create MAP file when Load Fix Address is enabled.
1432 if self
.Target
in ["", "all", "fds"]:
1433 for Arch
in Wa
.ArchList
:
1434 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1436 # Check whether the set fix address is above 4G for 32bit image.
1438 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1439 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS can't be set to larger than or equal to 4G for the platform with IA32 or ARM arch modules")
1444 for Pa
in Wa
.AutoGenObjectList
:
1445 for Ma
in Pa
.ModuleAutoGenList
:
1448 if not Ma
.IsLibrary
:
1449 ModuleList
[Ma
.Guid
.upper()] = Ma
1451 MapBuffer
= StringIO('')
1452 if self
.LoadFixAddress
!= 0:
1454 # Rebase module to the preferred memory address before GenFds
1456 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1459 # create FDS again for the updated EFI image
1461 self
._Build
("fds", Wa
)
1464 # Create MAP file for all platform FVs after GenFds.
1466 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1468 # Save MAP buffer into MAP file.
1470 self
._SaveMapFile
(MapBuffer
, Wa
)
1472 ## Build active module for different build targets, different tool chains and different archs
1474 def _BuildModule(self
):
1475 for BuildTarget
in self
.BuildTargetList
:
1476 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1477 for ToolChain
in self
.ToolChainList
:
1478 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1479 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1481 # module build needs platform build information, so get platform
1484 Wa
= WorkspaceAutoGen(
1502 self
.Fdf
= Wa
.FdfFile
1503 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1504 Wa
.CreateMakeFile(False)
1505 self
.Progress
.Stop("done!")
1507 for Arch
in Wa
.ArchList
:
1508 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1509 Ma
= ModuleAutoGen(Wa
, self
.ModuleFile
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1510 if Ma
== None: continue
1512 self
.BuildModules
.append(Ma
)
1513 if not Ma
.IsBinaryModule
:
1514 self
._Build
(self
.Target
, Ma
, BuildModule
=True)
1516 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1521 "Module for [%s] is not a component of active platform."\
1522 " Please make sure that the ARCH and inf file path are"\
1523 " given in the same as in [%s]" %\
1524 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1525 ExtraData
=self
.ModuleFile
1527 # Create MAP file when Load Fix Address is enabled.
1528 if self
.Target
== "fds" and self
.Fdf
:
1529 for Arch
in Wa
.ArchList
:
1531 # Check whether the set fix address is above 4G for 32bit image.
1533 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1534 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")
1539 for Pa
in Wa
.AutoGenObjectList
:
1540 for Ma
in Pa
.ModuleAutoGenList
:
1543 if not Ma
.IsLibrary
:
1544 ModuleList
[Ma
.Guid
.upper()] = Ma
1546 MapBuffer
= StringIO('')
1547 if self
.LoadFixAddress
!= 0:
1549 # Rebase module to the preferred memory address before GenFds
1551 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1553 # create FDS again for the updated EFI image
1555 self
._Build
("fds", Wa
)
1557 # Create MAP file for all platform FVs after GenFds.
1559 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1561 # Save MAP buffer into MAP file.
1563 self
._SaveMapFile
(MapBuffer
, Wa
)
1565 ## Build a platform in multi-thread mode
1567 def _MultiThreadBuildPlatform(self
):
1568 for BuildTarget
in self
.BuildTargetList
:
1569 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1570 for ToolChain
in self
.ToolChainList
:
1571 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1572 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1573 Wa
= WorkspaceAutoGen(
1590 self
.Fdf
= Wa
.FdfFile
1591 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1592 self
.BuildReport
.AddPlatformReport(Wa
)
1593 Wa
.CreateMakeFile(False)
1595 # multi-thread exit flag
1596 ExitFlag
= threading
.Event()
1598 for Arch
in Wa
.ArchList
:
1599 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1600 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1604 for Inf
in Pa
.Platform
.Modules
:
1605 ModuleList
.append(Inf
)
1606 # Add the INF only list in FDF
1607 if GlobalData
.gFdfParser
!= None:
1608 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
1609 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
1610 if Inf
in Pa
.Platform
.Modules
:
1612 ModuleList
.append(Inf
)
1613 for Module
in ModuleList
:
1614 # Get ModuleAutoGen object to generate C code file and makefile
1615 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1619 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1620 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1621 # for target which must generate AutoGen code and makefile
1622 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1623 Ma
.CreateCodeFile(True)
1624 if self
.Target
== "genc":
1627 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1628 Ma
.CreateMakeFile(True)
1629 if self
.Target
== "genmake":
1631 self
.BuildModules
.append(Ma
)
1632 self
.Progress
.Stop("done!")
1634 for Ma
in self
.BuildModules
:
1635 # Generate build task for the module
1636 if not Ma
.IsBinaryModule
:
1637 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
1638 # Break build if any build thread has error
1639 if BuildTask
.HasError():
1640 # we need a full version of makefile for platform
1642 BuildTask
.WaitForComplete()
1643 Pa
.CreateMakeFile(False)
1644 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1645 # Start task scheduler
1646 if not BuildTask
.IsOnGoing():
1647 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1649 # in case there's an interruption. we need a full version of makefile for platform
1650 Pa
.CreateMakeFile(False)
1651 if BuildTask
.HasError():
1652 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1655 # Save temp tables to a TmpTableDict.
1657 for Key
in Wa
.BuildDatabase
._CACHE
_:
1658 if Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
and Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
._Table
and Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
._Table
.Table
:
1659 if TemporaryTablePattern
.match(Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
._Table
.Table
):
1660 TmpTableDict
[Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
._Table
.Table
] = Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
._Table
.Cur
1663 # All modules have been put in build tasks queue. Tell task scheduler
1664 # to exit if all tasks are completed
1667 BuildTask
.WaitForComplete()
1668 self
.CreateAsBuiltInf()
1671 # Check for build error, and raise exception if one
1672 # has been signaled.
1674 if BuildTask
.HasError():
1675 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1677 # Create MAP file when Load Fix Address is enabled.
1678 if self
.Target
in ["", "all", "fds"]:
1679 for Arch
in Wa
.ArchList
:
1681 # Check whether the set fix address is above 4G for 32bit image.
1683 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1684 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")
1689 for Pa
in Wa
.AutoGenObjectList
:
1690 for Ma
in Pa
.ModuleAutoGenList
:
1693 if not Ma
.IsLibrary
:
1694 ModuleList
[Ma
.Guid
.upper()] = Ma
1696 # Rebase module to the preferred memory address before GenFds
1698 MapBuffer
= StringIO('')
1699 if self
.LoadFixAddress
!= 0:
1700 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1704 # Generate FD image if there's a FDF file found
1706 LaunchCommand(Wa
.GenFdsCommand
, os
.getcwd())
1709 # Create MAP file for all platform FVs after GenFds.
1711 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1713 # Save MAP buffer into MAP file.
1715 self
._SaveMapFile
(MapBuffer
, Wa
)
1717 ## Generate GuidedSectionTools.txt in the FV directories.
1719 def CreateGuidedSectionToolsFile(self
):
1720 for BuildTarget
in self
.BuildTargetList
:
1721 for ToolChain
in self
.ToolChainList
:
1722 Wa
= WorkspaceAutoGen(
1739 if not os
.path
.exists(FvDir
):
1742 for Arch
in self
.ArchList
:
1743 # Build up the list of supported architectures for this build
1744 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
1746 # Look through the tool definitions for GUIDed tools
1748 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.iteritems():
1749 if attrib
.upper().endswith('_GUID'):
1750 split
= attrib
.split('_')
1751 thisPrefix
= '_'.join(split
[0:3]) + '_'
1752 if thisPrefix
== prefix
:
1753 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
1756 path
= '_'.join(split
[0:4]) + '_PATH'
1757 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
1758 path
= self
.GetFullPathOfTool(path
)
1759 guidAttribs
.append((guid
, toolName
, path
))
1761 # Write out GuidedSecTools.txt
1762 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
1763 toolsFile
= open(toolsFile
, 'wt')
1764 for guidedSectionTool
in guidAttribs
:
1765 print >> toolsFile
, ' '.join(guidedSectionTool
)
1768 ## Returns the full path of the tool.
1770 def GetFullPathOfTool (self
, tool
):
1771 if os
.path
.exists(tool
):
1772 return os
.path
.realpath(tool
)
1774 # We need to search for the tool using the
1775 # PATH environment variable.
1776 for dirInPath
in os
.environ
['PATH'].split(os
.pathsep
):
1777 foundPath
= os
.path
.join(dirInPath
, tool
)
1778 if os
.path
.exists(foundPath
):
1779 return os
.path
.realpath(foundPath
)
1781 # If the tool was not found in the path then we just return
1785 ## Launch the module or platform build
1788 if not self
.ModuleFile
:
1789 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
1790 self
.SpawnMode
= False
1791 self
._BuildPlatform
()
1793 self
._MultiThreadBuildPlatform
()
1794 self
.CreateGuidedSectionToolsFile()
1796 self
.SpawnMode
= False
1799 if self
.Target
== 'cleanall':
1801 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
1803 def CreateAsBuiltInf(self
):
1804 for Module
in self
.BuildModules
:
1805 Module
.CreateAsBuiltInf()
1806 self
.BuildModules
= []
1807 ## Do some clean-up works when error occurred
1808 def Relinquish(self
):
1809 OldLogLevel
= EdkLogger
.GetLevel()
1810 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
1811 #self.DumpBuildData()
1812 Utils
.Progressor
.Abort()
1813 if self
.SpawnMode
== True:
1815 EdkLogger
.SetLevel(OldLogLevel
)
1817 def DumpBuildData(self
):
1818 CacheDirectory
= os
.path
.dirname(GlobalData
.gDatabasePath
)
1819 Utils
.CreateDirectory(CacheDirectory
)
1820 Utils
.DataDump(Utils
.gFileTimeStampCache
, os
.path
.join(CacheDirectory
, "gFileTimeStampCache"))
1821 Utils
.DataDump(Utils
.gDependencyDatabase
, os
.path
.join(CacheDirectory
, "gDependencyDatabase"))
1823 def RestoreBuildData(self
):
1824 FilePath
= os
.path
.join(os
.path
.dirname(GlobalData
.gDatabasePath
), "gFileTimeStampCache")
1825 if Utils
.gFileTimeStampCache
== {} and os
.path
.isfile(FilePath
):
1826 Utils
.gFileTimeStampCache
= Utils
.DataRestore(FilePath
)
1827 if Utils
.gFileTimeStampCache
== None:
1828 Utils
.gFileTimeStampCache
= {}
1830 FilePath
= os
.path
.join(os
.path
.dirname(GlobalData
.gDatabasePath
), "gDependencyDatabase")
1831 if Utils
.gDependencyDatabase
== {} and os
.path
.isfile(FilePath
):
1832 Utils
.gDependencyDatabase
= Utils
.DataRestore(FilePath
)
1833 if Utils
.gDependencyDatabase
== None:
1834 Utils
.gDependencyDatabase
= {}
1836 def ParseDefines(DefineList
=[]):
1838 if DefineList
!= None:
1839 for Define
in DefineList
:
1840 DefineTokenList
= Define
.split("=", 1)
1841 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
1842 EdkLogger
.error('build', FORMAT_INVALID
,
1843 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
1844 ExtraData
=DefineTokenList
[0])
1846 if len(DefineTokenList
) == 1:
1847 DefineDict
[DefineTokenList
[0]] = "TRUE"
1849 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
1853 def SingleCheckCallback(option
, opt_str
, value
, parser
):
1854 if option
not in gParamCheck
:
1855 setattr(parser
.values
, option
.dest
, value
)
1856 gParamCheck
.append(option
)
1858 parser
.error("Option %s only allows one instance in command line!" % option
)
1860 ## Parse command line options
1862 # Using standard Python module optparse to parse command line option of this tool.
1864 # @retval Opt A optparse.Values object containing the parsed options
1865 # @retval Args Target of build command
1867 def MyOptionParser():
1868 Parser
= OptionParser(description
=__copyright__
,version
=__version__
,prog
="build.exe",usage
="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
1869 Parser
.add_option("-a", "--arch", action
="append", type="choice", choices
=['IA32','X64','IPF','EBC','ARM', 'AARCH64'], dest
="TargetArch",
1870 help="ARCHS is one of list: IA32, X64, IPF, ARM, AARCH64 or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.")
1871 Parser
.add_option("-p", "--platform", action
="callback", type="string", dest
="PlatformFile", callback
=SingleCheckCallback
,
1872 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
1873 Parser
.add_option("-m", "--module", action
="callback", type="string", dest
="ModuleFile", callback
=SingleCheckCallback
,
1874 help="Build the module specified by the INF file name argument.")
1875 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
1877 Parser
.add_option("-t", "--tagname", action
="append", type="string", dest
="ToolChain",
1878 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
1879 Parser
.add_option("-x", "--sku-id", action
="callback", type="string", dest
="SkuId", callback
=SingleCheckCallback
,
1880 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
1882 Parser
.add_option("-n", action
="callback", type="int", dest
="ThreadNumber", callback
=SingleCheckCallback
,
1883 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.")
1885 Parser
.add_option("-f", "--fdf", action
="callback", type="string", dest
="FdfFile", callback
=SingleCheckCallback
,
1886 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
1887 Parser
.add_option("-r", "--rom-image", action
="append", type="string", dest
="RomImage", default
=[],
1888 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
1889 Parser
.add_option("-i", "--fv-image", action
="append", type="string", dest
="FvImage", default
=[],
1890 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
1891 Parser
.add_option("-C", "--capsule-image", action
="append", type="string", dest
="CapName", default
=[],
1892 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
1893 Parser
.add_option("-u", "--skip-autogen", action
="store_true", dest
="SkipAutoGen", help="Skip AutoGen step.")
1894 Parser
.add_option("-e", "--re-parse", action
="store_true", dest
="Reparse", help="Re-parse all meta-data files.")
1896 Parser
.add_option("-c", "--case-insensitive", action
="store_true", dest
="CaseInsensitive", default
=False, help="Don't check case of file name.")
1898 Parser
.add_option("-w", "--warning-as-error", action
="store_true", dest
="WarningAsError", help="Treat warning in tools as error.")
1899 Parser
.add_option("-j", "--log", action
="store", dest
="LogFile", help="Put log in specified file as well as on console.")
1901 Parser
.add_option("-s", "--silent", action
="store_true", type=None, dest
="SilentMode",
1902 help="Make use of silent mode of (n)make.")
1903 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
1904 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
1905 "including library instances selected, final dependency expression, "\
1906 "and warning messages, etc.")
1907 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
1908 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
1910 Parser
.add_option("-y", "--report-file", action
="store", dest
="ReportFile", help="Create/overwrite the report to the specified filename.")
1911 Parser
.add_option("-Y", "--report-type", action
="append", type="choice", choices
=['PCD','LIBRARY','FLASH','DEPEX','BUILD_FLAGS','FIXED_ADDRESS', 'EXECUTION_ORDER'], dest
="ReportType", default
=[],
1912 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]. "\
1913 "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]")
1914 Parser
.add_option("-F", "--flag", action
="store", type="string", dest
="Flag",
1915 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. "\
1916 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
1917 "will override the setting in [BuildOptions] section of platform DSC.")
1918 Parser
.add_option("-N", "--no-cache", action
="store_true", dest
="DisableCache", default
=False, help="Disable build cache mechanism")
1919 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
1920 Parser
.add_option("--check-usage", action
="store_true", dest
="CheckUsage", default
=False, help="Check usage content of entries listed in INF file.")
1921 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
1923 (Opt
, Args
)=Parser
.parse_args()
1926 ## Tool entrance method
1928 # This method mainly dispatch specific methods per the command line options.
1929 # If no error found, return zero value so the caller of this tool can know
1930 # if it's executed successfully or not.
1932 # @retval 0 Tool was successful
1933 # @retval 1 Tool failed
1936 StartTime
= time
.time()
1938 # Initialize log system
1939 EdkLogger
.Initialize()
1942 # Parse the options and args
1944 (Option
, Target
) = MyOptionParser()
1945 GlobalData
.gOptions
= Option
1946 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
1949 if Option
.verbose
!= None:
1950 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
1951 elif Option
.quiet
!= None:
1952 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
1953 elif Option
.debug
!= None:
1954 EdkLogger
.SetLevel(Option
.debug
+ 1)
1956 EdkLogger
.SetLevel(EdkLogger
.INFO
)
1958 if Option
.LogFile
!= None:
1959 EdkLogger
.SetLogFile(Option
.LogFile
)
1961 if Option
.WarningAsError
== True:
1962 EdkLogger
.SetWarningAsError()
1964 if platform
.platform().find("Windows") >= 0:
1965 GlobalData
.gIsWindows
= True
1967 GlobalData
.gIsWindows
= False
1969 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
1970 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
1974 if len(Target
) == 0:
1976 elif len(Target
) >= 2:
1977 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
1978 ExtraData
="Please select one of: %s" %(' '.join(gSupportedTarget
)))
1980 Target
= Target
[0].lower()
1982 if Target
not in gSupportedTarget
:
1983 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
1984 ExtraData
="Please select one of: %s" %(' '.join(gSupportedTarget
)))
1987 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
1990 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
1992 Workspace
= os
.getenv("WORKSPACE")
1994 # Get files real name in workspace dir
1996 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
1998 WorkingDirectory
= os
.getcwd()
1999 if not Option
.ModuleFile
:
2000 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2001 FileNum
= len(FileList
)
2003 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2004 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2006 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2008 if Option
.ModuleFile
:
2009 if os
.path
.isabs (Option
.ModuleFile
):
2010 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2011 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2012 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2013 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2015 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2017 if Option
.PlatformFile
!= None:
2018 if os
.path
.isabs (Option
.PlatformFile
):
2019 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2020 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2021 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2023 if Option
.FdfFile
!= None:
2024 if os
.path
.isabs (Option
.FdfFile
):
2025 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2026 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2027 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2028 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2030 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2032 if Option
.Flag
!= None and Option
.Flag
not in ['-c', '-s']:
2033 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2035 MyBuild
= Build(Target
, Workspace
, Option
)
2036 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2038 # Drop temp tables to avoid database locked.
2039 for TmpTableName
in TmpTableDict
:
2040 SqlCommand
= """drop table IF EXISTS %s""" % TmpTableName
2041 TmpTableDict
[TmpTableName
].execute(SqlCommand
)
2042 #MyBuild.DumpBuildData()
2043 except FatalError
, X
:
2045 # for multi-thread build exits safely
2046 MyBuild
.Relinquish()
2047 if Option
!= None and Option
.debug
!= None:
2048 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2049 ReturnCode
= X
.args
[0]
2051 # error from Fdf parser
2053 # for multi-thread build exits safely
2054 MyBuild
.Relinquish()
2055 if Option
!= None and Option
.debug
!= None:
2056 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2058 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
= False)
2059 ReturnCode
= FORMAT_INVALID
2060 except KeyboardInterrupt:
2061 ReturnCode
= ABORT_ERROR
2062 if Option
!= None and Option
.debug
!= None:
2063 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2066 # for multi-thread build exits safely
2067 MyBuild
.Relinquish()
2069 # try to get the meta-file from the object causing exception
2070 Tb
= sys
.exc_info()[-1]
2071 MetaFile
= GlobalData
.gProcessingFile
2073 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2074 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2079 "Unknown fatal error when processing [%s]" % MetaFile
,
2080 ExtraData
="\n(Please send email to edk2-devel@lists.sourceforge.net for help, attaching following call stack trace!)\n",
2083 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2084 ReturnCode
= CODE_ERROR
2086 Utils
.Progressor
.Abort()
2087 Utils
.ClearDuplicatedInf()
2091 elif ReturnCode
== ABORT_ERROR
:
2092 Conclusion
= "Aborted"
2094 Conclusion
= "Failed"
2095 FinishTime
= time
.time()
2096 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2097 BuildDurationStr
= ""
2098 if BuildDuration
.tm_yday
> 1:
2099 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)"%(BuildDuration
.tm_yday
- 1)
2101 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2103 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
)
2105 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2106 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2107 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2108 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2111 if __name__
== '__main__':
2113 ## 0-127 is a safe return range, and 1 is a standard default error
2114 if r
< 0 or r
> 127: r
= 1