2 # build a platform or a module
4 # Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
5 # Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
6 # Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
8 # SPDX-License-Identifier: BSD-2-Clause-Patent
14 from __future__
import print_function
15 import Common
.LongFilePathOs
as os
22 import encodings
.ascii
23 import multiprocessing
26 from threading
import *
28 from optparse
import OptionParser
29 from subprocess
import *
30 from Common
import Misc
as Utils
32 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
33 from Common
.TargetTxtClassObject
import TargetTxtClassObject
34 from Common
.ToolDefClassObject
import ToolDefClassObject
35 from Common
.DataType
import *
36 from Common
.BuildVersion
import gBUILD_VERSION
37 from AutoGen
.AutoGen
import *
38 from Common
.BuildToolError
import *
39 from Workspace
.WorkspaceDatabase
import WorkspaceDatabase
40 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
42 from BuildReport
import BuildReport
43 from GenPatchPcdTable
.GenPatchPcdTable
import *
44 from PatchPcdValue
.PatchPcdValue
import *
46 import Common
.EdkLogger
47 import Common
.GlobalData
as GlobalData
48 from GenFds
.GenFds
import GenFds
, GenFdsApi
50 from collections
import OrderedDict
, defaultdict
52 # Version and Copyright
53 VersionNumber
= "0.60" + ' ' + gBUILD_VERSION
54 __version__
= "%prog Version " + VersionNumber
55 __copyright__
= "Copyright (c) 2007 - 2018, 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 'PATHEXT' in os
.environ
:
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
=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
108 # set multiple workspace
109 PackagesPath
= os
.getenv("PACKAGES_PATH")
110 mws
.setWs(WorkspaceDir
, PackagesPath
)
111 if mws
.PACKAGES_PATH
:
112 for Path
in mws
.PACKAGES_PATH
:
113 if not os
.path
.exists(Path
):
114 EdkLogger
.error("build", FILE_NOT_FOUND
, "One Path in PACKAGES_PATH doesn't exist", ExtraData
=Path
)
116 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in PACKAGES_PATH", ExtraData
=Path
)
119 os
.environ
["EDK_TOOLS_PATH"] = os
.path
.normcase(os
.environ
["EDK_TOOLS_PATH"])
121 # check EDK_TOOLS_PATH
122 if "EDK_TOOLS_PATH" not in os
.environ
:
123 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
124 ExtraData
="EDK_TOOLS_PATH")
127 if "PATH" not in os
.environ
:
128 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
131 GlobalData
.gWorkspace
= WorkspaceDir
133 GlobalData
.gGlobalDefines
["WORKSPACE"] = WorkspaceDir
134 GlobalData
.gGlobalDefines
["EDK_TOOLS_PATH"] = os
.environ
["EDK_TOOLS_PATH"]
136 ## Get normalized file path
138 # Convert the path to be local format, and remove the WORKSPACE path at the
139 # beginning if the file path is given in full path.
141 # @param FilePath File path to be normalized
142 # @param Workspace Workspace path which the FilePath will be checked against
144 # @retval string The normalized file path
146 def NormFile(FilePath
, Workspace
):
147 # check if the path is absolute or relative
148 if os
.path
.isabs(FilePath
):
149 FileFullPath
= os
.path
.normpath(FilePath
)
151 FileFullPath
= os
.path
.normpath(mws
.join(Workspace
, FilePath
))
152 Workspace
= mws
.getWs(Workspace
, FilePath
)
154 # check if the file path exists or not
155 if not os
.path
.isfile(FileFullPath
):
156 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath
)
158 # remove workspace directory from the beginning part of the file path
159 if Workspace
[-1] in ["\\", "/"]:
160 return FileFullPath
[len(Workspace
):]
162 return FileFullPath
[(len(Workspace
) + 1):]
164 ## Get the output of an external program
166 # This is the entrance method of thread reading output of an external program and
167 # putting them in STDOUT/STDERR of current program.
169 # @param From The stream message read from
170 # @param To The stream message put on
171 # @param ExitFlag The flag used to indicate stopping reading
173 def ReadMessage(From
, To
, ExitFlag
):
175 # read one line a time
176 Line
= From
.readline()
177 # empty string means "end"
178 if Line
is not None and Line
!= b
"":
179 To(Line
.rstrip().decode(encoding
='utf-8', errors
='ignore'))
185 ## Launch an external program
187 # This method will call subprocess.Popen to execute an external program with
188 # given options in specified directory. Because of the dead-lock issue during
189 # redirecting output of the external program, threads are used to to do the
192 # @param Command A list or string containing the call of the program
193 # @param WorkingDir The directory in which the program will be running
195 def LaunchCommand(Command
, WorkingDir
):
196 BeginTime
= time
.time()
197 # if working directory doesn't exist, Popen() will raise an exception
198 if not os
.path
.isdir(WorkingDir
):
199 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=WorkingDir
)
201 # Command is used as the first Argument in following Popen().
202 # It could be a string or sequence. We find that if command is a string in following Popen(),
203 # ubuntu may fail with an error message that the command is not found.
204 # So here we may need convert command from string to list instance.
205 if platform
.system() != 'Windows':
206 if not isinstance(Command
, list):
207 Command
= Command
.split()
208 Command
= ' '.join(Command
)
211 EndOfProcedure
= None
214 Proc
= Popen(Command
, stdout
=PIPE
, stderr
=PIPE
, env
=os
.environ
, cwd
=WorkingDir
, bufsize
=-1, shell
=True)
216 # launch two threads to read the STDOUT and STDERR
217 EndOfProcedure
= Event()
218 EndOfProcedure
.clear()
220 StdOutThread
= Thread(target
=ReadMessage
, args
=(Proc
.stdout
, EdkLogger
.info
, EndOfProcedure
))
221 StdOutThread
.setName("STDOUT-Redirector")
222 StdOutThread
.setDaemon(False)
226 StdErrThread
= Thread(target
=ReadMessage
, args
=(Proc
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
227 StdErrThread
.setName("STDERR-Redirector")
228 StdErrThread
.setDaemon(False)
231 # waiting for program exit
233 except: # in case of aborting
234 # terminate the threads redirecting the program output
235 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
236 if EndOfProcedure
is not None:
239 if not isinstance(Command
, type("")):
240 Command
= " ".join(Command
)
241 EdkLogger
.error("build", COMMAND_FAILURE
, "Failed to start command", ExtraData
="%s [%s]" % (Command
, WorkingDir
))
248 # check the return code of the program
249 if Proc
.returncode
!= 0:
250 if not isinstance(Command
, type("")):
251 Command
= " ".join(Command
)
252 # print out the Response file and its content when make failure
253 RespFile
= os
.path
.join(WorkingDir
, 'OUTPUT', 'respfilelist.txt')
254 if os
.path
.isfile(RespFile
):
256 RespContent
= f
.read()
258 EdkLogger
.info(RespContent
)
260 EdkLogger
.error("build", COMMAND_FAILURE
, ExtraData
="%s [%s]" % (Command
, WorkingDir
))
261 return "%dms" % (int(round((time
.time() - BeginTime
) * 1000)))
263 ## The smallest unit that can be built in multi-thread build mode
265 # This is the base class of build unit. The "Obj" parameter must provide
266 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
269 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
274 # @param self The object pointer
275 # @param Obj The object the build is working on
276 # @param Target The build target name, one of gSupportedTarget
277 # @param Dependency The BuildUnit(s) which must be completed in advance
278 # @param WorkingDir The directory build command starts in
280 def __init__(self
, Obj
, BuildCommand
, Target
, Dependency
, WorkingDir
="."):
281 self
.BuildObject
= Obj
282 self
.Dependency
= Dependency
283 self
.WorkingDir
= WorkingDir
285 self
.BuildCommand
= BuildCommand
287 EdkLogger
.error("build", OPTION_MISSING
,
288 "No build command found for this module. "
289 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
290 (Obj
.BuildTarget
, Obj
.ToolChain
, Obj
.Arch
),
296 # It just returns the string representation of self.BuildObject
298 # @param self The object pointer
301 return str(self
.BuildObject
)
303 ## "==" operator method
305 # It just compares self.BuildObject with "Other". So self.BuildObject must
306 # provide its own __eq__() method.
308 # @param self The object pointer
309 # @param Other The other BuildUnit object compared to
311 def __eq__(self
, Other
):
312 return Other
and self
.BuildObject
== Other
.BuildObject \
313 and Other
.BuildObject \
314 and self
.BuildObject
.Arch
== Other
.BuildObject
.Arch
318 # It just returns the hash value of self.BuildObject which must be hashable.
320 # @param self The object pointer
323 return hash(self
.BuildObject
) + hash(self
.BuildObject
.Arch
)
326 return repr(self
.BuildObject
)
328 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
330 # This class is for module build by nmake/make build system. The "Obj" parameter
331 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
332 # be make units missing build.
334 # Currently the "Obj" should be only ModuleAutoGen object.
336 class ModuleMakeUnit(BuildUnit
):
339 # @param self The object pointer
340 # @param Obj The ModuleAutoGen object the build is working on
341 # @param Target The build target name, one of gSupportedTarget
343 def __init__(self
, Obj
, Target
):
344 Dependency
= [ModuleMakeUnit(La
, Target
) for La
in Obj
.LibraryAutoGenList
]
345 BuildUnit
.__init
__(self
, Obj
, Obj
.BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
346 if Target
in [None, "", "all"]:
347 self
.Target
= "tbuild"
349 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
351 # This class is for platform build by nmake/make build system. The "Obj" parameter
352 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
353 # be make units missing build.
355 # Currently the "Obj" should be only PlatformAutoGen object.
357 class PlatformMakeUnit(BuildUnit
):
360 # @param self The object pointer
361 # @param Obj The PlatformAutoGen object the build is working on
362 # @param Target The build target name, one of gSupportedTarget
364 def __init__(self
, Obj
, Target
):
365 Dependency
= [ModuleMakeUnit(Lib
, Target
) for Lib
in self
.BuildObject
.LibraryAutoGenList
]
366 Dependency
.extend([ModuleMakeUnit(Mod
, Target
) for Mod
in self
.BuildObject
.ModuleAutoGenList
])
367 BuildUnit
.__init
__(self
, Obj
, Obj
.BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
369 ## The class representing the task of a module build or platform build
371 # This class manages the build tasks in multi-thread build mode. Its jobs include
372 # scheduling thread running, catching thread error, monitor the thread status, etc.
375 # queue for tasks waiting for schedule
376 _PendingQueue
= OrderedDict()
377 _PendingQueueLock
= threading
.Lock()
379 # queue for tasks ready for running
380 _ReadyQueue
= OrderedDict()
381 _ReadyQueueLock
= threading
.Lock()
383 # queue for run tasks
384 _RunningQueue
= OrderedDict()
385 _RunningQueueLock
= threading
.Lock()
387 # queue containing all build tasks, in case duplicate build
388 _TaskQueue
= OrderedDict()
390 # flag indicating error occurs in a running thread
391 _ErrorFlag
= threading
.Event()
395 # BoundedSemaphore object used to control the number of running threads
398 # flag indicating if the scheduler is started or not
399 _SchedulerStopped
= threading
.Event()
400 _SchedulerStopped
.set()
402 ## Start the task scheduler thread
404 # @param MaxThreadNumber The maximum thread number
405 # @param ExitFlag Flag used to end the scheduler
408 def StartScheduler(MaxThreadNumber
, ExitFlag
):
409 SchedulerThread
= Thread(target
=BuildTask
.Scheduler
, args
=(MaxThreadNumber
, ExitFlag
))
410 SchedulerThread
.setName("Build-Task-Scheduler")
411 SchedulerThread
.setDaemon(False)
412 SchedulerThread
.start()
413 # wait for the scheduler to be started, especially useful in Linux
414 while not BuildTask
.IsOnGoing():
419 # @param MaxThreadNumber The maximum thread number
420 # @param ExitFlag Flag used to end the scheduler
423 def Scheduler(MaxThreadNumber
, ExitFlag
):
424 BuildTask
._SchedulerStopped
.clear()
426 # use BoundedSemaphore to control the maximum running threads
427 BuildTask
._Thread
= BoundedSemaphore(MaxThreadNumber
)
429 # scheduling loop, which will exits when no pending/ready task and
430 # indicated to do so, or there's error in running thread
432 while (len(BuildTask
._PendingQueue
) > 0 or len(BuildTask
._ReadyQueue
) > 0 \
433 or not ExitFlag
.isSet()) and not BuildTask
._ErrorFlag
.isSet():
434 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Pending Queue (%d), Ready Queue (%d)"
435 % (len(BuildTask
._PendingQueue
), len(BuildTask
._ReadyQueue
)))
437 # get all pending tasks
438 BuildTask
._PendingQueueLock
.acquire()
439 BuildObjectList
= list(BuildTask
._PendingQueue
.keys())
441 # check if their dependency is resolved, and if true, move them
444 for BuildObject
in BuildObjectList
:
445 Bt
= BuildTask
._PendingQueue
[BuildObject
]
447 BuildTask
._ReadyQueue
[BuildObject
] = BuildTask
._PendingQueue
.pop(BuildObject
)
448 BuildTask
._PendingQueueLock
.release()
450 # launch build thread until the maximum number of threads is reached
451 while not BuildTask
._ErrorFlag
.isSet():
452 # empty ready queue, do nothing further
453 if len(BuildTask
._ReadyQueue
) == 0:
456 # wait for active thread(s) exit
457 BuildTask
._Thread
.acquire(True)
459 # start a new build thread
460 Bo
, Bt
= BuildTask
._ReadyQueue
.popitem()
462 # move into running queue
463 BuildTask
._RunningQueueLock
.acquire()
464 BuildTask
._RunningQueue
[Bo
] = Bt
465 BuildTask
._RunningQueueLock
.release()
474 # wait for all running threads exit
475 if BuildTask
._ErrorFlag
.isSet():
476 EdkLogger
.quiet("\nWaiting for all build threads exit...")
477 # while not BuildTask._ErrorFlag.isSet() and \
478 while len(BuildTask
._RunningQueue
) > 0:
479 EdkLogger
.verbose("Waiting for thread ending...(%d)" % len(BuildTask
._RunningQueue
))
480 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Threads [%s]" % ", ".join(Th
.getName() for Th
in threading
.enumerate()))
483 except BaseException
as X
:
485 # TRICK: hide the output of threads left running, so that the user can
486 # catch the error message easily
488 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
489 BuildTask
._ErrorFlag
.set()
490 BuildTask
._ErrorMessage
= "build thread scheduler error\n\t%s" % str(X
)
492 BuildTask
._PendingQueue
.clear()
493 BuildTask
._ReadyQueue
.clear()
494 BuildTask
._RunningQueue
.clear()
495 BuildTask
._TaskQueue
.clear()
496 BuildTask
._SchedulerStopped
.set()
498 ## Wait for all running method exit
501 def WaitForComplete():
502 BuildTask
._SchedulerStopped
.wait()
504 ## Check if the scheduler is running or not
508 return not BuildTask
._SchedulerStopped
.isSet()
513 if BuildTask
.IsOnGoing():
514 BuildTask
._ErrorFlag
.set()
515 BuildTask
.WaitForComplete()
517 ## Check if there's error in running thread
519 # Since the main thread cannot catch exceptions in other thread, we have to
520 # use threading.Event to communicate this formation to main thread.
524 return BuildTask
._ErrorFlag
.isSet()
526 ## Get error message in running thread
528 # Since the main thread cannot catch exceptions in other thread, we have to
529 # use a static variable to communicate this message to main thread.
532 def GetErrorMessage():
533 return BuildTask
._ErrorMessage
535 ## Factory method to create a BuildTask object
537 # This method will check if a module is building or has been built. And if
538 # true, just return the associated BuildTask object in the _TaskQueue. If
539 # not, create and return a new BuildTask object. The new BuildTask object
540 # will be appended to the _PendingQueue for scheduling later.
542 # @param BuildItem A BuildUnit object representing a build object
543 # @param Dependency The dependent build object of BuildItem
546 def New(BuildItem
, Dependency
=None):
547 if BuildItem
in BuildTask
._TaskQueue
:
548 Bt
= BuildTask
._TaskQueue
[BuildItem
]
552 Bt
._Init
(BuildItem
, Dependency
)
553 BuildTask
._TaskQueue
[BuildItem
] = Bt
555 BuildTask
._PendingQueueLock
.acquire()
556 BuildTask
._PendingQueue
[BuildItem
] = Bt
557 BuildTask
._PendingQueueLock
.release()
561 ## The real constructor of BuildTask
563 # @param BuildItem A BuildUnit object representing a build object
564 # @param Dependency The dependent build object of BuildItem
566 def _Init(self
, BuildItem
, Dependency
=None):
567 self
.BuildItem
= BuildItem
569 self
.DependencyList
= []
570 if Dependency
is None:
571 Dependency
= BuildItem
.Dependency
573 Dependency
.extend(BuildItem
.Dependency
)
574 self
.AddDependency(Dependency
)
575 # flag indicating build completes, used to avoid unnecessary re-build
576 self
.CompleteFlag
= False
578 ## Check if all dependent build tasks are completed or not
582 for Dep
in self
.DependencyList
:
583 if Dep
.CompleteFlag
== True:
590 ## Add dependent build task
592 # @param Dependency The list of dependent build objects
594 def AddDependency(self
, Dependency
):
595 for Dep
in Dependency
:
596 if not Dep
.BuildObject
.IsBinaryModule
and not Dep
.BuildObject
.CanSkipbyHash():
597 self
.DependencyList
.append(BuildTask
.New(Dep
)) # BuildTask list
599 ## The thread wrapper of LaunchCommand function
601 # @param Command A list or string contains the call of the command
602 # @param WorkingDir The directory in which the program will be running
604 def _CommandThread(self
, Command
, WorkingDir
):
606 self
.BuildItem
.BuildObject
.BuildTime
= LaunchCommand(Command
, WorkingDir
)
607 self
.CompleteFlag
= True
609 # Run hash operation post dependency, to account for libs
610 if GlobalData
.gUseHashCache
and self
.BuildItem
.BuildObject
.IsLibrary
:
611 HashFile
= path
.join(self
.BuildItem
.BuildObject
.BuildDir
, self
.BuildItem
.BuildObject
.Name
+ ".hash")
612 SaveFileOnChange(HashFile
, self
.BuildItem
.BuildObject
.GenModuleHash(), True)
615 # TRICK: hide the output of threads left running, so that the user can
616 # catch the error message easily
618 if not BuildTask
._ErrorFlag
.isSet():
619 GlobalData
.gBuildingModule
= "%s [%s, %s, %s]" % (str(self
.BuildItem
.BuildObject
),
620 self
.BuildItem
.BuildObject
.Arch
,
621 self
.BuildItem
.BuildObject
.ToolChain
,
622 self
.BuildItem
.BuildObject
.BuildTarget
624 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
625 BuildTask
._ErrorFlag
.set()
626 BuildTask
._ErrorMessage
= "%s broken\n %s [%s]" % \
627 (threading
.currentThread().getName(), Command
, WorkingDir
)
629 # Set the value used by hash invalidation flow in GlobalData.gModuleBuildTracking to 'SUCCESS'
630 # If Module or Lib is being tracked, it did not fail header check test, and built successfully
631 if (self
.BuildItem
.BuildObject
.Arch
in GlobalData
.gModuleBuildTracking
and
632 self
.BuildItem
.BuildObject
in GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
.Arch
] and
633 GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
.Arch
][self
.BuildItem
.BuildObject
] != 'FAIL_METAFILE' and
634 not BuildTask
._ErrorFlag
.isSet()
636 GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
.Arch
][self
.BuildItem
.BuildObject
] = 'SUCCESS'
638 # indicate there's a thread is available for another build task
639 BuildTask
._RunningQueueLock
.acquire()
640 BuildTask
._RunningQueue
.pop(self
.BuildItem
)
641 BuildTask
._RunningQueueLock
.release()
642 BuildTask
._Thread
.release()
644 ## Start build task thread
647 EdkLogger
.quiet("Building ... %s" % repr(self
.BuildItem
))
648 Command
= self
.BuildItem
.BuildCommand
+ [self
.BuildItem
.Target
]
649 self
.BuildTread
= Thread(target
=self
._CommandThread
, args
=(Command
, self
.BuildItem
.WorkingDir
))
650 self
.BuildTread
.setName("build thread")
651 self
.BuildTread
.setDaemon(False)
652 self
.BuildTread
.start()
654 ## The class contains the information related to EFI image
659 # Constructor will load all required image information.
661 # @param BaseName The full file path of image.
662 # @param Guid The GUID for image.
663 # @param Arch Arch of this image.
664 # @param OutputDir The output directory for image.
665 # @param DebugDir The debug directory for image.
666 # @param ImageClass PeImage Information
668 def __init__(self
, BaseName
, Guid
, Arch
, OutputDir
, DebugDir
, ImageClass
):
669 self
.BaseName
= BaseName
672 self
.OutputDir
= OutputDir
673 self
.DebugDir
= DebugDir
674 self
.Image
= ImageClass
675 self
.Image
.Size
= (self
.Image
.Size
// 0x1000 + 1) * 0x1000
677 ## The class implementing the EDK2 build process
679 # The build process includes:
680 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
681 # 2. Parse DSC file of active platform
682 # 3. Parse FDF file if any
683 # 4. Establish build database, including parse all other files (module, package)
684 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
685 # 6. Call build command
690 # Constructor will load all necessary configurations, parse platform, modules
691 # and packages and the establish a database for AutoGen.
693 # @param Target The build command target, one of gSupportedTarget
694 # @param WorkspaceDir The directory of workspace
695 # @param BuildOptions Build options passed from command line
697 def __init__(self
, Target
, WorkspaceDir
, BuildOptions
):
698 self
.WorkspaceDir
= WorkspaceDir
700 self
.PlatformFile
= BuildOptions
.PlatformFile
701 self
.ModuleFile
= BuildOptions
.ModuleFile
702 self
.ArchList
= BuildOptions
.TargetArch
703 self
.ToolChainList
= BuildOptions
.ToolChain
704 self
.BuildTargetList
= BuildOptions
.BuildTarget
705 self
.Fdf
= BuildOptions
.FdfFile
706 self
.FdList
= BuildOptions
.RomImage
707 self
.FvList
= BuildOptions
.FvImage
708 self
.CapList
= BuildOptions
.CapName
709 self
.SilentMode
= BuildOptions
.SilentMode
710 self
.ThreadNumber
= BuildOptions
.ThreadNumber
711 self
.SkipAutoGen
= BuildOptions
.SkipAutoGen
712 self
.Reparse
= BuildOptions
.Reparse
713 self
.SkuId
= BuildOptions
.SkuId
715 GlobalData
.gSKUID_CMD
= self
.SkuId
716 self
.ConfDirectory
= BuildOptions
.ConfDirectory
717 self
.SpawnMode
= True
718 self
.BuildReport
= BuildReport(BuildOptions
.ReportFile
, BuildOptions
.ReportType
)
719 self
.TargetTxt
= TargetTxtClassObject()
720 self
.ToolDef
= ToolDefClassObject()
724 GlobalData
.BuildOptionPcd
= BuildOptions
.OptionPcd
if BuildOptions
.OptionPcd
else []
725 #Set global flag for build mode
726 GlobalData
.gIgnoreSource
= BuildOptions
.IgnoreSources
727 GlobalData
.gUseHashCache
= BuildOptions
.UseHashCache
728 GlobalData
.gBinCacheDest
= BuildOptions
.BinCacheDest
729 GlobalData
.gBinCacheSource
= BuildOptions
.BinCacheSource
730 GlobalData
.gEnableGenfdsMultiThread
= BuildOptions
.GenfdsMultiThread
731 GlobalData
.gDisableIncludePathCheck
= BuildOptions
.DisableIncludePathCheck
733 if GlobalData
.gBinCacheDest
and not GlobalData
.gUseHashCache
:
734 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination must be used together with --hash.")
736 if GlobalData
.gBinCacheSource
and not GlobalData
.gUseHashCache
:
737 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-source must be used together with --hash.")
739 if GlobalData
.gBinCacheDest
and GlobalData
.gBinCacheSource
:
740 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination can not be used together with --binary-source.")
742 if GlobalData
.gBinCacheSource
:
743 BinCacheSource
= os
.path
.normpath(GlobalData
.gBinCacheSource
)
744 if not os
.path
.isabs(BinCacheSource
):
745 BinCacheSource
= mws
.join(self
.WorkspaceDir
, BinCacheSource
)
746 GlobalData
.gBinCacheSource
= BinCacheSource
748 if GlobalData
.gBinCacheSource
is not None:
749 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-source.")
751 if GlobalData
.gBinCacheDest
:
752 BinCacheDest
= os
.path
.normpath(GlobalData
.gBinCacheDest
)
753 if not os
.path
.isabs(BinCacheDest
):
754 BinCacheDest
= mws
.join(self
.WorkspaceDir
, BinCacheDest
)
755 GlobalData
.gBinCacheDest
= BinCacheDest
757 if GlobalData
.gBinCacheDest
is not None:
758 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-destination.")
760 if self
.ConfDirectory
:
761 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
762 ConfDirectoryPath
= os
.path
.normpath(self
.ConfDirectory
)
764 if not os
.path
.isabs(ConfDirectoryPath
):
765 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
766 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
767 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, ConfDirectoryPath
)
769 if "CONF_PATH" in os
.environ
:
770 ConfDirectoryPath
= os
.path
.normcase(os
.path
.normpath(os
.environ
["CONF_PATH"]))
772 # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf
773 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, 'Conf')
774 GlobalData
.gConfDirectory
= ConfDirectoryPath
775 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
777 self
.Db
= WorkspaceDatabase()
778 self
.BuildDatabase
= self
.Db
.BuildObject
780 self
.ToolChainFamily
= None
781 self
.LoadFixAddress
= 0
782 self
.UniFlag
= BuildOptions
.Flag
783 self
.BuildModules
= []
784 self
.HashSkipModules
= []
786 self
.LaunchPrebuildFlag
= False
787 self
.PlatformBuildPath
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PlatformBuild')
788 if BuildOptions
.CommandLength
:
789 GlobalData
.gCommandMaxLength
= BuildOptions
.CommandLength
791 # print dot character during doing some time-consuming work
792 self
.Progress
= Utils
.Progressor()
793 # print current build environment and configuration
794 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
795 if "PACKAGES_PATH" in os
.environ
:
796 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
797 EdkLogger
.quiet("%-16s = %s" % ("PACKAGES_PATH", os
.path
.normcase(os
.path
.normpath(os
.environ
["PACKAGES_PATH"]))))
798 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
799 if "EDK_TOOLS_BIN" in os
.environ
:
800 # Print the same path style with WORKSPACE env.
801 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_TOOLS_BIN"]))))
802 EdkLogger
.quiet("%-16s = %s" % ("CONF_PATH", GlobalData
.gConfDirectory
))
803 if "PYTHON3_ENABLE" in os
.environ
:
804 PYTHON3_ENABLE
= os
.environ
["PYTHON3_ENABLE"]
805 if PYTHON3_ENABLE
!= "TRUE":
806 PYTHON3_ENABLE
= "FALSE"
807 EdkLogger
.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE
))
808 if "PYTHON_COMMAND" in os
.environ
:
809 EdkLogger
.quiet("%-16s = %s" % ("PYTHON_COMMAND", os
.environ
["PYTHON_COMMAND"]))
813 EdkLogger
.quiet("%-16s = %s" % ("PREBUILD", self
.Prebuild
))
815 EdkLogger
.quiet("%-16s = %s" % ("POSTBUILD", self
.Postbuild
))
817 self
.LaunchPrebuild()
818 self
.TargetTxt
= TargetTxtClassObject()
819 self
.ToolDef
= ToolDefClassObject()
820 if not (self
.LaunchPrebuildFlag
and os
.path
.exists(self
.PlatformBuildPath
)):
824 os
.chdir(self
.WorkspaceDir
)
826 ## Load configuration
828 # This method will parse target.txt and get the build configurations.
830 def LoadConfiguration(self
):
832 # Check target.txt and tools_def.txt and Init them
834 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(GlobalData
.gConfDirectory
, gBuildConfiguration
))
835 if os
.path
.isfile(BuildConfigurationFile
) == True:
836 StatusCode
= self
.TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
838 ToolDefinitionFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_CONF
]
839 if ToolDefinitionFile
== '':
840 ToolDefinitionFile
= gToolsDefinition
841 ToolDefinitionFile
= os
.path
.normpath(mws
.join(self
.WorkspaceDir
, 'Conf', ToolDefinitionFile
))
842 if os
.path
.isfile(ToolDefinitionFile
) == True:
843 StatusCode
= self
.ToolDef
.LoadToolDefFile(ToolDefinitionFile
)
845 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=ToolDefinitionFile
)
847 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
849 # if no ARCH given in command line, get it from target.txt
850 if not self
.ArchList
:
851 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET_ARCH
]
852 self
.ArchList
= tuple(self
.ArchList
)
854 # if no build target given in command line, get it from target.txt
855 if not self
.BuildTargetList
:
856 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
858 # if no tool chain given in command line, get it from target.txt
859 if not self
.ToolChainList
:
860 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
861 if self
.ToolChainList
is None or len(self
.ToolChainList
) == 0:
862 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
864 # check if the tool chains are defined or not
865 NewToolChainList
= []
866 for ToolChain
in self
.ToolChainList
:
867 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
868 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
870 NewToolChainList
.append(ToolChain
)
871 # if no tool chain available, break the build
872 if len(NewToolChainList
) == 0:
873 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
874 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
876 self
.ToolChainList
= NewToolChainList
879 ToolDefinition
= self
.ToolDef
.ToolsDefTxtDatabase
880 for Tool
in self
.ToolChainList
:
881 if TAB_TOD_DEFINES_FAMILY
not in ToolDefinition
or Tool
not in ToolDefinition
[TAB_TOD_DEFINES_FAMILY
] \
882 or not ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
]:
883 EdkLogger
.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool
)
884 ToolChainFamily
.append(TAB_COMPILER_MSFT
)
886 ToolChainFamily
.append(ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
])
887 self
.ToolChainFamily
= ToolChainFamily
889 if self
.ThreadNumber
is None:
890 self
.ThreadNumber
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
891 if self
.ThreadNumber
== '':
892 self
.ThreadNumber
= 0
894 self
.ThreadNumber
= int(self
.ThreadNumber
, 0)
896 if self
.ThreadNumber
== 0:
898 self
.ThreadNumber
= multiprocessing
.cpu_count()
899 except (ImportError, NotImplementedError):
900 self
.ThreadNumber
= 1
902 if not self
.PlatformFile
:
903 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
905 # Try to find one in current directory
906 WorkingDirectory
= os
.getcwd()
907 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
908 FileNum
= len(FileList
)
910 EdkLogger
.error("build", OPTION_MISSING
,
911 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
913 PlatformFile
= FileList
[0]
915 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
916 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
918 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
920 ## Initialize build configuration
922 # This method will parse DSC file and merge the configurations from
923 # command line and target.txt, then get the final build configurations.
926 # parse target.txt, tools_def.txt, and platform file
927 self
.LoadConfiguration()
929 # Allow case-insensitive for those from command line or configuration file
930 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
932 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
935 def InitPreBuild(self
):
936 self
.LoadConfiguration()
937 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
939 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
940 if self
.BuildTargetList
:
941 GlobalData
.gGlobalDefines
['TARGET'] = self
.BuildTargetList
[0]
943 GlobalData
.gGlobalDefines
['ARCH'] = self
.ArchList
[0]
944 if self
.ToolChainList
:
945 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = self
.ToolChainList
[0]
946 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = self
.ToolChainList
[0]
947 if self
.ToolChainFamily
:
948 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[0]
949 if 'PREBUILD' in GlobalData
.gCommandLineDefines
:
950 self
.Prebuild
= GlobalData
.gCommandLineDefines
.get('PREBUILD')
953 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
954 self
.Prebuild
= str(Platform
.Prebuild
)
958 # Evaluate all arguments and convert arguments that are WORKSPACE
959 # relative paths to absolute paths. Filter arguments that look like
960 # flags or do not follow the file/dir naming rules to avoid false
961 # positives on this conversion.
963 for Arg
in self
.Prebuild
.split():
965 # Do not modify Arg if it looks like a flag or an absolute file path
967 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
968 PrebuildList
.append(Arg
)
971 # Do not modify Arg if it does not look like a Workspace relative
972 # path that starts with a valid package directory name
974 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
975 PrebuildList
.append(Arg
)
978 # If Arg looks like a WORKSPACE relative path, then convert to an
979 # absolute path and check to see if the file exists.
981 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
982 if os
.path
.isfile(Temp
):
984 PrebuildList
.append(Arg
)
985 self
.Prebuild
= ' '.join(PrebuildList
)
986 self
.Prebuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
988 def InitPostBuild(self
):
989 if 'POSTBUILD' in GlobalData
.gCommandLineDefines
:
990 self
.Postbuild
= GlobalData
.gCommandLineDefines
.get('POSTBUILD')
992 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
993 self
.Postbuild
= str(Platform
.Postbuild
)
997 # Evaluate all arguments and convert arguments that are WORKSPACE
998 # relative paths to absolute paths. Filter arguments that look like
999 # flags or do not follow the file/dir naming rules to avoid false
1000 # positives on this conversion.
1002 for Arg
in self
.Postbuild
.split():
1004 # Do not modify Arg if it looks like a flag or an absolute file path
1006 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1007 PostbuildList
.append(Arg
)
1010 # Do not modify Arg if it does not look like a Workspace relative
1011 # path that starts with a valid package directory name
1013 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1014 PostbuildList
.append(Arg
)
1017 # If Arg looks like a WORKSPACE relative path, then convert to an
1018 # absolute path and check to see if the file exists.
1020 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1021 if os
.path
.isfile(Temp
):
1023 PostbuildList
.append(Arg
)
1024 self
.Postbuild
= ' '.join(PostbuildList
)
1025 self
.Postbuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1027 def PassCommandOption(self
, BuildTarget
, TargetArch
, ToolChain
, PlatformFile
, Target
):
1029 if GlobalData
.gCommand
and isinstance(GlobalData
.gCommand
, list):
1030 BuildStr
+= ' ' + ' '.join(GlobalData
.gCommand
)
1033 ToolChainFlag
= False
1034 PlatformFileFlag
= False
1036 if GlobalData
.gOptions
and not GlobalData
.gOptions
.BuildTarget
:
1038 if GlobalData
.gOptions
and not GlobalData
.gOptions
.TargetArch
:
1040 if GlobalData
.gOptions
and not GlobalData
.gOptions
.ToolChain
:
1041 ToolChainFlag
= True
1042 if GlobalData
.gOptions
and not GlobalData
.gOptions
.PlatformFile
:
1043 PlatformFileFlag
= True
1045 if TargetFlag
and BuildTarget
:
1046 if isinstance(BuildTarget
, list) or isinstance(BuildTarget
, tuple):
1047 BuildStr
+= ' -b ' + ' -b '.join(BuildTarget
)
1048 elif isinstance(BuildTarget
, str):
1049 BuildStr
+= ' -b ' + BuildTarget
1050 if ArchFlag
and TargetArch
:
1051 if isinstance(TargetArch
, list) or isinstance(TargetArch
, tuple):
1052 BuildStr
+= ' -a ' + ' -a '.join(TargetArch
)
1053 elif isinstance(TargetArch
, str):
1054 BuildStr
+= ' -a ' + TargetArch
1055 if ToolChainFlag
and ToolChain
:
1056 if isinstance(ToolChain
, list) or isinstance(ToolChain
, tuple):
1057 BuildStr
+= ' -t ' + ' -t '.join(ToolChain
)
1058 elif isinstance(ToolChain
, str):
1059 BuildStr
+= ' -t ' + ToolChain
1060 if PlatformFileFlag
and PlatformFile
:
1061 if isinstance(PlatformFile
, list) or isinstance(PlatformFile
, tuple):
1062 BuildStr
+= ' -p ' + ' -p '.join(PlatformFile
)
1063 elif isinstance(PlatformFile
, str):
1064 BuildStr
+= ' -p' + PlatformFile
1065 BuildStr
+= ' --conf=' + GlobalData
.gConfDirectory
1067 BuildStr
+= ' ' + Target
1071 def LaunchPrebuild(self
):
1073 EdkLogger
.info("\n- Prebuild Start -\n")
1074 self
.LaunchPrebuildFlag
= True
1076 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1077 # and preserve them for the rest of the main build step, because the child process environment will
1078 # evaporate as soon as it exits, we cannot get it in build step.
1080 PrebuildEnvFile
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PrebuildEnv')
1081 if os
.path
.isfile(PrebuildEnvFile
):
1082 os
.remove(PrebuildEnvFile
)
1083 if os
.path
.isfile(self
.PlatformBuildPath
):
1084 os
.remove(self
.PlatformBuildPath
)
1085 if sys
.platform
== "win32":
1086 args
= ' && '.join((self
.Prebuild
, 'set > ' + PrebuildEnvFile
))
1087 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1089 args
= ' && '.join((self
.Prebuild
, 'env > ' + PrebuildEnvFile
))
1090 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1092 # launch two threads to read the STDOUT and STDERR
1093 EndOfProcedure
= Event()
1094 EndOfProcedure
.clear()
1096 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1097 StdOutThread
.setName("STDOUT-Redirector")
1098 StdOutThread
.setDaemon(False)
1099 StdOutThread
.start()
1102 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1103 StdErrThread
.setName("STDERR-Redirector")
1104 StdErrThread
.setDaemon(False)
1105 StdErrThread
.start()
1106 # waiting for program exit
1113 if Process
.returncode
!= 0 :
1114 EdkLogger
.error("Prebuild", PREBUILD_ERROR
, 'Prebuild process is not success!')
1116 if os
.path
.exists(PrebuildEnvFile
):
1117 f
= open(PrebuildEnvFile
)
1118 envs
= f
.readlines()
1120 envs
= [l
.split("=", 1) for l
in envs
]
1121 envs
= [[I
.strip() for I
in item
] for item
in envs
if len(item
) == 2]
1122 os
.environ
.update(dict(envs
))
1123 EdkLogger
.info("\n- Prebuild Done -\n")
1125 def LaunchPostbuild(self
):
1127 EdkLogger
.info("\n- Postbuild Start -\n")
1128 if sys
.platform
== "win32":
1129 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1131 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1132 # launch two threads to read the STDOUT and STDERR
1133 EndOfProcedure
= Event()
1134 EndOfProcedure
.clear()
1136 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1137 StdOutThread
.setName("STDOUT-Redirector")
1138 StdOutThread
.setDaemon(False)
1139 StdOutThread
.start()
1142 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1143 StdErrThread
.setName("STDERR-Redirector")
1144 StdErrThread
.setDaemon(False)
1145 StdErrThread
.start()
1146 # waiting for program exit
1153 if Process
.returncode
!= 0 :
1154 EdkLogger
.error("Postbuild", POSTBUILD_ERROR
, 'Postbuild process is not success!')
1155 EdkLogger
.info("\n- Postbuild Done -\n")
1157 ## Error handling for hash feature
1159 # On BuildTask error, iterate through the Module Build tracking
1160 # dictionary to determine wheather a module failed to build. Invalidate
1161 # the hash associated with that module by removing it from storage.
1164 def invalidateHash(self
):
1165 # Only for hashing feature
1166 if not GlobalData
.gUseHashCache
:
1169 # GlobalData.gModuleBuildTracking contains only modules or libs that cannot be skipped by hash
1170 for moduleAutoGenObjArch
in GlobalData
.gModuleBuildTracking
.keys():
1171 for moduleAutoGenObj
in GlobalData
.gModuleBuildTracking
[moduleAutoGenObjArch
].keys():
1172 # Skip invalidating for Successful Module/Lib builds
1173 if GlobalData
.gModuleBuildTracking
[moduleAutoGenObjArch
][moduleAutoGenObj
] == 'SUCCESS':
1176 # The module failed to build, failed to start building, or failed the header check test from this point on
1178 # Remove .hash from build
1179 ModuleHashFile
= os
.path
.join(moduleAutoGenObj
.BuildDir
, moduleAutoGenObj
.Name
+ ".hash")
1180 if os
.path
.exists(ModuleHashFile
):
1181 os
.remove(ModuleHashFile
)
1183 # Remove .hash file from cache
1184 if GlobalData
.gBinCacheDest
:
1185 FileDir
= os
.path
.join(GlobalData
.gBinCacheDest
, moduleAutoGenObj
.Arch
, moduleAutoGenObj
.SourceDir
, moduleAutoGenObj
.MetaFile
.BaseName
)
1186 HashFile
= os
.path
.join(FileDir
, moduleAutoGenObj
.Name
+ '.hash')
1187 if os
.path
.exists(HashFile
):
1190 ## Build a module or platform
1192 # Create autogen code and makefile for a module or platform, and the launch
1193 # "make" command to build it
1195 # @param Target The target of build command
1196 # @param Platform The platform file
1197 # @param Module The module file
1198 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1199 # @param ToolChain The name of toolchain to build
1200 # @param Arch The arch of the module/platform
1201 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1202 # for dependent modules/Libraries
1203 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1204 # for dependent modules/Libraries
1206 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False, FfsCommand
={}):
1207 if AutoGenObject
is None:
1210 # skip file generation for cleanxxx targets, run and fds target
1211 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1212 # for target which must generate AutoGen code and makefile
1213 if not self
.SkipAutoGen
or Target
== 'genc':
1214 self
.Progress
.Start("Generating code")
1215 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1216 self
.Progress
.Stop("done!")
1217 if Target
== "genc":
1220 if not self
.SkipAutoGen
or Target
== 'genmake':
1221 self
.Progress
.Start("Generating makefile")
1222 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
, FfsCommand
)
1223 self
.Progress
.Stop("done!")
1224 if Target
== "genmake":
1227 # always recreate top/platform makefile when clean, just in case of inconsistency
1228 AutoGenObject
.CreateCodeFile(False)
1229 AutoGenObject
.CreateMakeFile(False)
1231 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1232 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1234 BuildCommand
= AutoGenObject
.BuildCommand
1235 if BuildCommand
is None or len(BuildCommand
) == 0:
1236 EdkLogger
.error("build", OPTION_MISSING
,
1237 "No build command found for this module. "
1238 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1239 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1240 ExtraData
=str(AutoGenObject
))
1242 makefile
= GenMake
.BuildFile(AutoGenObject
)._FILE
_NAME
_[GenMake
.gMakeType
]
1250 BuildCommand
= BuildCommand
+ [Target
]
1251 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1252 self
.CreateAsBuiltInf()
1256 if Target
== 'libraries':
1257 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1258 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1259 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1263 if Target
== 'modules':
1264 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1265 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1266 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1267 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1268 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, makefile
)), 'pbuild']
1269 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1270 self
.CreateAsBuiltInf()
1274 if Target
== 'cleanlib':
1275 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1276 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1277 if os
.path
.exists(LibMakefile
):
1278 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1279 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1283 if Target
== 'clean':
1284 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1285 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, makefile
))
1286 if os
.path
.exists(ModMakefile
):
1287 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
1288 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1289 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1290 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1291 if os
.path
.exists(LibMakefile
):
1292 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1293 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1297 if Target
== 'cleanall':
1299 #os.rmdir(AutoGenObject.BuildDir)
1300 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1301 except WindowsError as X
:
1302 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1305 ## Build a module or platform
1307 # Create autogen code and makefile for a module or platform, and the launch
1308 # "make" command to build it
1310 # @param Target The target of build command
1311 # @param Platform The platform file
1312 # @param Module The module file
1313 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1314 # @param ToolChain The name of toolchain to build
1315 # @param Arch The arch of the module/platform
1316 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1317 # for dependent modules/Libraries
1318 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1319 # for dependent modules/Libraries
1321 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1322 if AutoGenObject
is None:
1325 # skip file generation for cleanxxx targets, run and fds target
1326 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1327 # for target which must generate AutoGen code and makefile
1328 if not self
.SkipAutoGen
or Target
== 'genc':
1329 self
.Progress
.Start("Generating code")
1330 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1331 self
.Progress
.Stop("done!")
1332 if Target
== "genc":
1335 if not self
.SkipAutoGen
or Target
== 'genmake':
1336 self
.Progress
.Start("Generating makefile")
1337 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1338 #AutoGenObject.CreateAsBuiltInf()
1339 self
.Progress
.Stop("done!")
1340 if Target
== "genmake":
1343 # always recreate top/platform makefile when clean, just in case of inconsistency
1344 AutoGenObject
.CreateCodeFile(False)
1345 AutoGenObject
.CreateMakeFile(False)
1347 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1348 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1350 BuildCommand
= AutoGenObject
.BuildCommand
1351 if BuildCommand
is None or len(BuildCommand
) == 0:
1352 EdkLogger
.error("build", OPTION_MISSING
,
1353 "No build command found for this module. "
1354 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1355 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1356 ExtraData
=str(AutoGenObject
))
1361 BuildCommand
= BuildCommand
+ [Target
]
1362 AutoGenObject
.BuildTime
= LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1363 self
.CreateAsBuiltInf()
1368 if GenFdsApi(AutoGenObject
.GenFdsCommandDict
, self
.Db
):
1369 EdkLogger
.error("build", COMMAND_FAILURE
)
1377 if Target
== 'libraries':
1384 if Target
== 'cleanall':
1386 #os.rmdir(AutoGenObject.BuildDir)
1387 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1388 except WindowsError as X
:
1389 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1392 ## Rebase module image and Get function address for the input module list.
1394 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1396 AddrIsOffset
= False
1397 for InfFile
in ModuleList
:
1398 sys
.stdout
.write (".")
1400 ModuleInfo
= ModuleList
[InfFile
]
1401 ModuleName
= ModuleInfo
.BaseName
1402 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1403 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1404 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1406 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1408 # Update Image to new BaseAddress by GenFw tool
1410 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1411 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1414 # Set new address to the section header only for SMM driver.
1416 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1417 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1419 # Collect function address from Map file
1421 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1423 if os
.path
.exists(ImageMapTable
):
1424 OrigImageBaseAddress
= 0
1425 ImageMap
= open(ImageMapTable
, 'r')
1426 for LinStr
in ImageMap
:
1427 if len (LinStr
.strip()) == 0:
1430 # Get the preferred address set on link time.
1432 if LinStr
.find ('Preferred load address is') != -1:
1433 StrList
= LinStr
.split()
1434 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1436 StrList
= LinStr
.split()
1437 if len (StrList
) > 4:
1438 if StrList
[3] == 'f' or StrList
[3] == 'F':
1440 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1441 FunctionList
.append ((Name
, RelativeAddress
))
1445 # Add general information.
1448 MapBuffer
.append('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1450 MapBuffer
.append('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1452 MapBuffer
.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1454 # Add guid and general seciton section.
1456 TextSectionAddress
= 0
1457 DataSectionAddress
= 0
1458 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1459 if SectionHeader
[0] == '.text':
1460 TextSectionAddress
= SectionHeader
[1]
1461 elif SectionHeader
[0] in ['.data', '.sdata']:
1462 DataSectionAddress
= SectionHeader
[1]
1464 MapBuffer
.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1466 MapBuffer
.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1468 # Add debug image full path.
1470 MapBuffer
.append('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1472 # Add function address
1474 for Function
in FunctionList
:
1476 MapBuffer
.append(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1478 MapBuffer
.append(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1482 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1485 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1487 ## Collect MAP information of all FVs
1489 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1491 # First get the XIP base address for FV map file.
1492 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1493 GuidName
= re
.compile("\(GUID=[-a-fA-F0-9]+")
1494 for FvName
in Wa
.FdfProfile
.FvDict
:
1495 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1496 if not os
.path
.exists(FvMapBuffer
):
1498 FvMap
= open(FvMapBuffer
, 'r')
1499 #skip FV size information
1505 MatchGuid
= GuidPattern
.match(Line
)
1506 if MatchGuid
is not None:
1508 # Replace GUID with module name
1510 GuidString
= MatchGuid
.group()
1511 if GuidString
.upper() in ModuleList
:
1512 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1513 MapBuffer
.append(Line
)
1515 # Add the debug image full path.
1517 MatchGuid
= GuidName
.match(Line
)
1518 if MatchGuid
is not None:
1519 GuidString
= MatchGuid
.group().split("=")[1]
1520 if GuidString
.upper() in ModuleList
:
1521 MapBuffer
.append('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1525 ## Collect MAP information of all modules
1527 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1528 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1530 PatchEfiImageList
= []
1538 # reserve 4K size in SMRAM to make SMM module address not from 0.
1540 for ModuleGuid
in ModuleList
:
1541 Module
= ModuleList
[ModuleGuid
]
1542 GlobalData
.gProcessingFile
= "%s [%s, %s, %s]" % (Module
.MetaFile
, Module
.Arch
, Module
.ToolChain
, Module
.BuildTarget
)
1544 OutputImageFile
= ''
1545 for ResultFile
in Module
.CodaTargetList
:
1546 if str(ResultFile
.Target
).endswith('.efi'):
1548 # module list for PEI, DXE, RUNTIME and SMM
1550 OutputImageFile
= os
.path
.join(Module
.OutputDir
, Module
.Name
+ '.efi')
1551 ImageClass
= PeImageClass (OutputImageFile
)
1552 if not ImageClass
.IsValid
:
1553 EdkLogger
.error("build", FILE_PARSE_FAILURE
, ExtraData
=ImageClass
.ErrorInfo
)
1554 ImageInfo
= PeImageInfo(Module
.Name
, Module
.Guid
, Module
.Arch
, Module
.OutputDir
, Module
.DebugDir
, ImageClass
)
1555 if Module
.ModuleType
in [SUP_MODULE_PEI_CORE
, SUP_MODULE_PEIM
, EDK_COMPONENT_TYPE_COMBINED_PEIM_DRIVER
, EDK_COMPONENT_TYPE_PIC_PEIM
, EDK_COMPONENT_TYPE_RELOCATABLE_PEIM
, SUP_MODULE_DXE_CORE
]:
1556 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1557 PeiSize
+= ImageInfo
.Image
.Size
1558 elif Module
.ModuleType
in [EDK_COMPONENT_TYPE_BS_DRIVER
, SUP_MODULE_DXE_DRIVER
, SUP_MODULE_UEFI_DRIVER
]:
1559 BtModuleList
[Module
.MetaFile
] = ImageInfo
1560 BtSize
+= ImageInfo
.Image
.Size
1561 elif Module
.ModuleType
in [SUP_MODULE_DXE_RUNTIME_DRIVER
, EDK_COMPONENT_TYPE_RT_DRIVER
, SUP_MODULE_DXE_SAL_DRIVER
, EDK_COMPONENT_TYPE_SAL_RT_DRIVER
]:
1562 RtModuleList
[Module
.MetaFile
] = ImageInfo
1563 RtSize
+= ImageInfo
.Image
.Size
1564 elif Module
.ModuleType
in [SUP_MODULE_SMM_CORE
, SUP_MODULE_DXE_SMM_DRIVER
, SUP_MODULE_MM_STANDALONE
, SUP_MODULE_MM_CORE_STANDALONE
]:
1565 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1566 SmmSize
+= ImageInfo
.Image
.Size
1567 if Module
.ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
1568 PiSpecVersion
= Module
.Module
.Specification
.get('PI_SPECIFICATION_VERSION', '0x00000000')
1569 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1570 if int(PiSpecVersion
, 16) < 0x0001000A:
1571 BtModuleList
[Module
.MetaFile
] = ImageInfo
1572 BtSize
+= ImageInfo
.Image
.Size
1575 # EFI image is final target.
1576 # Check EFI image contains patchable FixAddress related PCDs.
1578 if OutputImageFile
!= '':
1579 ModuleIsPatch
= False
1580 for Pcd
in Module
.ModulePcdList
:
1581 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1582 ModuleIsPatch
= True
1584 if not ModuleIsPatch
:
1585 for Pcd
in Module
.LibraryPcdList
:
1586 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1587 ModuleIsPatch
= True
1590 if not ModuleIsPatch
:
1593 # Module includes the patchable load fix address PCDs.
1594 # It will be fixed up later.
1596 PatchEfiImageList
.append (OutputImageFile
)
1599 # Get Top Memory address
1601 ReservedRuntimeMemorySize
= 0
1602 TopMemoryAddress
= 0
1603 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1604 TopMemoryAddress
= 0
1606 TopMemoryAddress
= self
.LoadFixAddress
1607 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1608 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1611 # Patch FixAddress related PCDs into EFI image
1613 for EfiImage
in PatchEfiImageList
:
1614 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1615 if not os
.path
.exists(EfiImageMap
):
1618 # Get PCD offset in EFI image by GenPatchPcdTable function
1620 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1622 # Patch real PCD value by PatchPcdValue tool
1624 for PcdInfo
in PcdTable
:
1626 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1627 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
// 0x1000))
1628 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1629 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
// 0x1000))
1630 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1631 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
// 0x1000))
1632 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1633 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
// 0x1000))
1634 if ReturnValue
!= 0:
1635 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1637 MapBuffer
.append('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
// 0x1000))
1638 MapBuffer
.append('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
// 0x1000))
1639 MapBuffer
.append('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
// 0x1000))
1640 if len (SmmModuleList
) > 0:
1641 MapBuffer
.append('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
// 0x1000))
1643 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1644 BtBaseAddr
= TopMemoryAddress
- RtSize
1645 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1647 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1648 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1649 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1650 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
=False, ModeIsSmm
=True)
1651 MapBuffer
.append('\n\n')
1652 sys
.stdout
.write ("\n")
1655 ## Save platform Map file
1657 def _SaveMapFile (self
, MapBuffer
, Wa
):
1659 # Map file path is got.
1661 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1663 # Save address map into MAP file.
1665 SaveFileOnChange(MapFilePath
, ''.join(MapBuffer
), False)
1666 if self
.LoadFixAddress
!= 0:
1667 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath
))
1670 ## Build active platform for different build targets and different tool chains
1672 def _BuildPlatform(self
):
1673 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1674 for BuildTarget
in self
.BuildTargetList
:
1675 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1677 for ToolChain
in self
.ToolChainList
:
1678 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1679 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1680 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1682 Wa
= WorkspaceAutoGen(
1699 self
.Fdf
= Wa
.FdfFile
1700 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1701 self
.BuildReport
.AddPlatformReport(Wa
)
1702 self
.Progress
.Stop("done!")
1704 # Add ffs build to makefile
1706 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1707 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1709 for Arch
in Wa
.ArchList
:
1710 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1711 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1712 for Module
in Pa
.Platform
.Modules
:
1713 # Get ModuleAutoGen object to generate C code file and makefile
1714 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1717 self
.BuildModules
.append(Ma
)
1718 self
._BuildPa
(self
.Target
, Pa
, FfsCommand
=CmdListDict
)
1720 # Create MAP file when Load Fix Address is enabled.
1721 if self
.Target
in ["", "all", "fds"]:
1722 for Arch
in Wa
.ArchList
:
1723 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1725 # Check whether the set fix address is above 4G for 32bit image.
1727 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1728 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")
1733 for Pa
in Wa
.AutoGenObjectList
:
1734 for Ma
in Pa
.ModuleAutoGenList
:
1737 if not Ma
.IsLibrary
:
1738 ModuleList
[Ma
.Guid
.upper()] = Ma
1741 if self
.LoadFixAddress
!= 0:
1743 # Rebase module to the preferred memory address before GenFds
1745 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1748 # create FDS again for the updated EFI image
1750 self
._Build
("fds", Wa
)
1752 # Create MAP file for all platform FVs after GenFds.
1754 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1756 # Save MAP buffer into MAP file.
1758 self
._SaveMapFile
(MapBuffer
, Wa
)
1760 ## Build active module for different build targets, different tool chains and different archs
1762 def _BuildModule(self
):
1763 for BuildTarget
in self
.BuildTargetList
:
1764 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1766 for ToolChain
in self
.ToolChainList
:
1767 WorkspaceAutoGenTime
= time
.time()
1768 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1769 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1770 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1773 # module build needs platform build information, so get platform
1776 Wa
= WorkspaceAutoGen(
1794 self
.Fdf
= Wa
.FdfFile
1795 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1796 Wa
.CreateMakeFile(False)
1797 # Add ffs build to makefile
1799 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1800 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1801 self
.Progress
.Stop("done!")
1803 ExitFlag
= threading
.Event()
1805 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1806 for Arch
in Wa
.ArchList
:
1807 AutoGenStart
= time
.time()
1808 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1809 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1810 for Module
in Pa
.Platform
.Modules
:
1811 if self
.ModuleFile
.Dir
== Module
.Dir
and self
.ModuleFile
.Name
== Module
.Name
:
1812 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1816 if Ma
.CanSkipbyHash():
1817 self
.HashSkipModules
.append(Ma
)
1818 if GlobalData
.gBinCacheSource
:
1819 EdkLogger
.quiet("cache hit: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1822 if GlobalData
.gBinCacheSource
:
1823 EdkLogger
.quiet("cache miss: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1824 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1825 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1826 # for target which must generate AutoGen code and makefile
1827 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1828 self
.Progress
.Start("Generating code")
1829 Ma
.CreateCodeFile(True)
1830 self
.Progress
.Stop("done!")
1831 if self
.Target
== "genc":
1833 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1834 self
.Progress
.Start("Generating makefile")
1835 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
1836 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
1837 del CmdListDict
[Module
.File
, Arch
]
1839 Ma
.CreateMakeFile(True)
1840 self
.Progress
.Stop("done!")
1841 if self
.Target
== "genmake":
1843 self
.BuildModules
.append(Ma
)
1844 # Initialize all modules in tracking to 'FAIL'
1845 if Ma
.Arch
not in GlobalData
.gModuleBuildTracking
:
1846 GlobalData
.gModuleBuildTracking
[Ma
.Arch
] = dict()
1847 if Ma
not in GlobalData
.gModuleBuildTracking
[Ma
.Arch
]:
1848 GlobalData
.gModuleBuildTracking
[Ma
.Arch
][Ma
] = 'FAIL'
1849 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1850 MakeStart
= time
.time()
1851 for Ma
in self
.BuildModules
:
1852 if not Ma
.IsBinaryModule
:
1853 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
1854 # Break build if any build thread has error
1855 if BuildTask
.HasError():
1856 # we need a full version of makefile for platform
1858 BuildTask
.WaitForComplete()
1859 self
.invalidateHash()
1860 Pa
.CreateMakeFile(False)
1861 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1862 # Start task scheduler
1863 if not BuildTask
.IsOnGoing():
1864 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1866 # in case there's an interruption. we need a full version of makefile for platform
1867 Pa
.CreateMakeFile(False)
1868 if BuildTask
.HasError():
1869 self
.invalidateHash()
1870 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1871 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1873 MakeContiue
= time
.time()
1875 BuildTask
.WaitForComplete()
1876 self
.CreateAsBuiltInf()
1877 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1878 if BuildTask
.HasError():
1879 self
.invalidateHash()
1880 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1882 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1887 "Module for [%s] is not a component of active platform."\
1888 " Please make sure that the ARCH and inf file path are"\
1889 " given in the same as in [%s]" % \
1890 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1891 ExtraData
=self
.ModuleFile
1893 # Create MAP file when Load Fix Address is enabled.
1894 if self
.Target
== "fds" and self
.Fdf
:
1895 for Arch
in Wa
.ArchList
:
1897 # Check whether the set fix address is above 4G for 32bit image.
1899 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1900 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")
1905 for Pa
in Wa
.AutoGenObjectList
:
1906 for Ma
in Pa
.ModuleAutoGenList
:
1909 if not Ma
.IsLibrary
:
1910 ModuleList
[Ma
.Guid
.upper()] = Ma
1913 if self
.LoadFixAddress
!= 0:
1915 # Rebase module to the preferred memory address before GenFds
1917 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1919 # create FDS again for the updated EFI image
1921 GenFdsStart
= time
.time()
1922 self
._Build
("fds", Wa
)
1923 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
1925 # Create MAP file for all platform FVs after GenFds.
1927 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1929 # Save MAP buffer into MAP file.
1931 self
._SaveMapFile
(MapBuffer
, Wa
)
1932 self
.invalidateHash()
1934 def _GenFfsCmd(self
,ArchList
):
1935 # convert dictionary of Cmd:(Inf,Arch)
1936 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
1937 CmdSetDict
= defaultdict(set)
1938 GenFfsDict
= GenFds
.GenFfsMakefile('', GlobalData
.gFdfParser
, self
, ArchList
, GlobalData
)
1939 for Cmd
in GenFfsDict
:
1940 tmpInf
, tmpArch
= GenFfsDict
[Cmd
]
1941 CmdSetDict
[tmpInf
, tmpArch
].add(Cmd
)
1944 ## Build a platform in multi-thread mode
1946 def _MultiThreadBuildPlatform(self
):
1947 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1948 for BuildTarget
in self
.BuildTargetList
:
1949 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1951 for ToolChain
in self
.ToolChainList
:
1952 WorkspaceAutoGenTime
= time
.time()
1953 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1954 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1955 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1957 Wa
= WorkspaceAutoGen(
1974 self
.Fdf
= Wa
.FdfFile
1975 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1976 self
.BuildReport
.AddPlatformReport(Wa
)
1977 Wa
.CreateMakeFile(False)
1979 # Add ffs build to makefile
1981 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1982 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1984 # multi-thread exit flag
1985 ExitFlag
= threading
.Event()
1987 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1988 for Arch
in Wa
.ArchList
:
1989 AutoGenStart
= time
.time()
1990 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1991 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1995 for Inf
in Pa
.Platform
.Modules
:
1996 ModuleList
.append(Inf
)
1997 # Add the INF only list in FDF
1998 if GlobalData
.gFdfParser
is not None:
1999 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
2000 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
2001 if Inf
in Pa
.Platform
.Modules
:
2003 ModuleList
.append(Inf
)
2004 for Module
in ModuleList
:
2005 # Get ModuleAutoGen object to generate C code file and makefile
2006 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
2010 if Ma
.CanSkipbyHash():
2011 self
.HashSkipModules
.append(Ma
)
2012 if GlobalData
.gBinCacheSource
:
2013 EdkLogger
.quiet("cache hit: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
2016 if GlobalData
.gBinCacheSource
:
2017 EdkLogger
.quiet("cache miss: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
2019 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
2020 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
2021 # for target which must generate AutoGen code and makefile
2022 if not self
.SkipAutoGen
or self
.Target
== 'genc':
2023 Ma
.CreateCodeFile(True)
2024 if self
.Target
== "genc":
2027 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
2028 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
2029 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
2030 del CmdListDict
[Module
.File
, Arch
]
2032 Ma
.CreateMakeFile(True)
2033 if self
.Target
== "genmake":
2035 self
.BuildModules
.append(Ma
)
2036 # Initialize all modules in tracking to 'FAIL'
2037 if Ma
.Arch
not in GlobalData
.gModuleBuildTracking
:
2038 GlobalData
.gModuleBuildTracking
[Ma
.Arch
] = dict()
2039 if Ma
not in GlobalData
.gModuleBuildTracking
[Ma
.Arch
]:
2040 GlobalData
.gModuleBuildTracking
[Ma
.Arch
][Ma
] = 'FAIL'
2041 self
.Progress
.Stop("done!")
2042 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
2043 MakeStart
= time
.time()
2044 for Ma
in self
.BuildModules
:
2045 # Generate build task for the module
2046 if not Ma
.IsBinaryModule
:
2047 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
2048 # Break build if any build thread has error
2049 if BuildTask
.HasError():
2050 # we need a full version of makefile for platform
2052 BuildTask
.WaitForComplete()
2053 self
.invalidateHash()
2054 Pa
.CreateMakeFile(False)
2055 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2056 # Start task scheduler
2057 if not BuildTask
.IsOnGoing():
2058 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
2060 # in case there's an interruption. we need a full version of makefile for platform
2061 Pa
.CreateMakeFile(False)
2062 if BuildTask
.HasError():
2063 self
.invalidateHash()
2064 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2065 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
2067 MakeContiue
= time
.time()
2071 # All modules have been put in build tasks queue. Tell task scheduler
2072 # to exit if all tasks are completed
2075 BuildTask
.WaitForComplete()
2076 self
.CreateAsBuiltInf()
2077 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2079 # Check for build error, and raise exception if one
2080 # has been signaled.
2082 if BuildTask
.HasError():
2083 self
.invalidateHash()
2084 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2086 # Create MAP file when Load Fix Address is enabled.
2087 if self
.Target
in ["", "all", "fds"]:
2088 for Arch
in Wa
.ArchList
:
2090 # Check whether the set fix address is above 4G for 32bit image.
2092 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2093 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")
2098 for Pa
in Wa
.AutoGenObjectList
:
2099 for Ma
in Pa
.ModuleAutoGenList
:
2102 if not Ma
.IsLibrary
:
2103 ModuleList
[Ma
.Guid
.upper()] = Ma
2105 # Rebase module to the preferred memory address before GenFds
2108 if self
.LoadFixAddress
!= 0:
2109 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2113 # Generate FD image if there's a FDF file found
2115 GenFdsStart
= time
.time()
2116 if GenFdsApi(Wa
.GenFdsCommandDict
, self
.Db
):
2117 EdkLogger
.error("build", COMMAND_FAILURE
)
2120 # Create MAP file for all platform FVs after GenFds.
2122 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2123 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2125 # Save MAP buffer into MAP file.
2127 self
._SaveMapFile
(MapBuffer
, Wa
)
2128 self
.invalidateHash()
2130 ## Generate GuidedSectionTools.txt in the FV directories.
2132 def CreateGuidedSectionToolsFile(self
):
2133 for BuildTarget
in self
.BuildTargetList
:
2134 for ToolChain
in self
.ToolChainList
:
2135 Wa
= WorkspaceAutoGen(
2152 if not os
.path
.exists(FvDir
):
2155 for Arch
in self
.ArchList
:
2156 # Build up the list of supported architectures for this build
2157 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
2159 # Look through the tool definitions for GUIDed tools
2161 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.items():
2162 if attrib
.upper().endswith('_GUID'):
2163 split
= attrib
.split('_')
2164 thisPrefix
= '_'.join(split
[0:3]) + '_'
2165 if thisPrefix
== prefix
:
2166 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
2169 path
= '_'.join(split
[0:4]) + '_PATH'
2170 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2171 path
= self
.GetFullPathOfTool(path
)
2172 guidAttribs
.append((guid
, toolName
, path
))
2174 # Write out GuidedSecTools.txt
2175 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2176 toolsFile
= open(toolsFile
, 'wt')
2177 for guidedSectionTool
in guidAttribs
:
2178 print(' '.join(guidedSectionTool
), file=toolsFile
)
2181 ## Returns the full path of the tool.
2183 def GetFullPathOfTool (self
, tool
):
2184 if os
.path
.exists(tool
):
2185 return os
.path
.realpath(tool
)
2187 # We need to search for the tool using the
2188 # PATH environment variable.
2189 for dirInPath
in os
.environ
['PATH'].split(os
.pathsep
):
2190 foundPath
= os
.path
.join(dirInPath
, tool
)
2191 if os
.path
.exists(foundPath
):
2192 return os
.path
.realpath(foundPath
)
2194 # If the tool was not found in the path then we just return
2198 ## Launch the module or platform build
2201 if not self
.ModuleFile
:
2202 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2203 self
.SpawnMode
= False
2204 self
._BuildPlatform
()
2206 self
._MultiThreadBuildPlatform
()
2207 self
.CreateGuidedSectionToolsFile()
2209 self
.SpawnMode
= False
2212 if self
.Target
== 'cleanall':
2213 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2215 def CreateAsBuiltInf(self
):
2218 for Module
in self
.BuildModules
:
2219 Module
.CreateAsBuiltInf()
2220 all_mod_set
.add(Module
)
2221 for Module
in self
.HashSkipModules
:
2222 if GlobalData
.gBinCacheDest
:
2223 Module
.CopyModuleToCache()
2224 all_mod_set
.add(Module
)
2225 for Module
in all_mod_set
:
2226 for lib
in Module
.LibraryAutoGenList
:
2227 all_lib_set
.add(lib
)
2228 for lib
in all_lib_set
:
2229 if GlobalData
.gBinCacheDest
:
2230 lib
.CopyModuleToCache()
2233 self
.BuildModules
= []
2234 self
.HashSkipModules
= []
2235 ## Do some clean-up works when error occurred
2236 def Relinquish(self
):
2237 OldLogLevel
= EdkLogger
.GetLevel()
2238 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2239 Utils
.Progressor
.Abort()
2240 if self
.SpawnMode
== True:
2242 EdkLogger
.SetLevel(OldLogLevel
)
2244 def ParseDefines(DefineList
=[]):
2246 if DefineList
is not None:
2247 for Define
in DefineList
:
2248 DefineTokenList
= Define
.split("=", 1)
2249 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2250 EdkLogger
.error('build', FORMAT_INVALID
,
2251 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2252 ExtraData
=DefineTokenList
[0])
2254 if len(DefineTokenList
) == 1:
2255 DefineDict
[DefineTokenList
[0]] = "TRUE"
2257 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2261 def SingleCheckCallback(option
, opt_str
, value
, parser
):
2262 if option
not in gParamCheck
:
2263 setattr(parser
.values
, option
.dest
, value
)
2264 gParamCheck
.append(option
)
2266 parser
.error("Option %s only allows one instance in command line!" % option
)
2268 def LogBuildTime(Time
):
2271 TimeDur
= time
.gmtime(Time
)
2272 if TimeDur
.tm_yday
> 1:
2273 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2275 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2280 ## Parse command line options
2282 # Using standard Python module optparse to parse command line option of this tool.
2284 # @retval Opt A optparse.Values object containing the parsed options
2285 # @retval Args Target of build command
2287 def MyOptionParser():
2288 Parser
= OptionParser(description
=__copyright__
, version
=__version__
, prog
="build.exe", usage
="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
2289 Parser
.add_option("-a", "--arch", action
="append", type="choice", choices
=['IA32', 'X64', 'EBC', 'ARM', 'AARCH64'], dest
="TargetArch",
2290 help="ARCHS is one of list: IA32, X64, ARM, AARCH64 or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.")
2291 Parser
.add_option("-p", "--platform", action
="callback", type="string", dest
="PlatformFile", callback
=SingleCheckCallback
,
2292 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
2293 Parser
.add_option("-m", "--module", action
="callback", type="string", dest
="ModuleFile", callback
=SingleCheckCallback
,
2294 help="Build the module specified by the INF file name argument.")
2295 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
2297 Parser
.add_option("-t", "--tagname", action
="append", type="string", dest
="ToolChain",
2298 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
2299 Parser
.add_option("-x", "--sku-id", action
="callback", type="string", dest
="SkuId", callback
=SingleCheckCallback
,
2300 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
2302 Parser
.add_option("-n", action
="callback", type="int", dest
="ThreadNumber", callback
=SingleCheckCallback
,
2303 help="Build the platform using multi-threaded compiler. The value overrides target.txt's MAX_CONCURRENT_THREAD_NUMBER. When value is set to 0, tool automatically detect number of "\
2304 "processor threads, set value to 1 means disable multi-thread build, and set value to more than 1 means user specify the threads number to build.")
2306 Parser
.add_option("-f", "--fdf", action
="callback", type="string", dest
="FdfFile", callback
=SingleCheckCallback
,
2307 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
2308 Parser
.add_option("-r", "--rom-image", action
="append", type="string", dest
="RomImage", default
=[],
2309 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
2310 Parser
.add_option("-i", "--fv-image", action
="append", type="string", dest
="FvImage", default
=[],
2311 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
2312 Parser
.add_option("-C", "--capsule-image", action
="append", type="string", dest
="CapName", default
=[],
2313 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
2314 Parser
.add_option("-u", "--skip-autogen", action
="store_true", dest
="SkipAutoGen", help="Skip AutoGen step.")
2315 Parser
.add_option("-e", "--re-parse", action
="store_true", dest
="Reparse", help="Re-parse all meta-data files.")
2317 Parser
.add_option("-c", "--case-insensitive", action
="store_true", dest
="CaseInsensitive", default
=False, help="Don't check case of file name.")
2319 Parser
.add_option("-w", "--warning-as-error", action
="store_true", dest
="WarningAsError", help="Treat warning in tools as error.")
2320 Parser
.add_option("-j", "--log", action
="store", dest
="LogFile", help="Put log in specified file as well as on console.")
2322 Parser
.add_option("-s", "--silent", action
="store_true", type=None, dest
="SilentMode",
2323 help="Make use of silent mode of (n)make.")
2324 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
2325 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
2326 "including library instances selected, final dependency expression, "\
2327 "and warning messages, etc.")
2328 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
2329 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
2331 Parser
.add_option("-y", "--report-file", action
="store", dest
="ReportFile", help="Create/overwrite the report to the specified filename.")
2332 Parser
.add_option("-Y", "--report-type", action
="append", type="choice", choices
=['PCD', 'LIBRARY', 'FLASH', 'DEPEX', 'BUILD_FLAGS', 'FIXED_ADDRESS', 'HASH', 'EXECUTION_ORDER'], dest
="ReportType", default
=[],
2333 help="Flags that control the type of build report to generate. Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, HASH, EXECUTION_ORDER]. "\
2334 "To specify more than one flag, repeat this option on the command line and the default flag set is [PCD, LIBRARY, FLASH, DEPEX, HASH, BUILD_FLAGS, FIXED_ADDRESS]")
2335 Parser
.add_option("-F", "--flag", action
="store", type="string", dest
="Flag",
2336 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. "\
2337 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
2338 "will override the setting in [BuildOptions] section of platform DSC.")
2339 Parser
.add_option("-N", "--no-cache", action
="store_true", dest
="DisableCache", default
=False, help="Disable build cache mechanism")
2340 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
2341 Parser
.add_option("--check-usage", action
="store_true", dest
="CheckUsage", default
=False, help="Check usage content of entries listed in INF file.")
2342 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
2343 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
2344 Parser
.add_option("-l", "--cmd-len", action
="store", type="int", dest
="CommandLength", help="Specify the maximum line length of build command. Default is 4096.")
2345 Parser
.add_option("--hash", action
="store_true", dest
="UseHashCache", default
=False, help="Enable hash-based caching during build process.")
2346 Parser
.add_option("--binary-destination", action
="store", type="string", dest
="BinCacheDest", help="Generate a cache of binary files in the specified directory.")
2347 Parser
.add_option("--binary-source", action
="store", type="string", dest
="BinCacheSource", help="Consume a cache of binary files from the specified directory.")
2348 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
2349 Parser
.add_option("--disable-include-path-check", action
="store_true", dest
="DisableIncludePathCheck", default
=False, help="Disable the include path check for outside of package.")
2350 (Opt
, Args
) = Parser
.parse_args()
2353 ## Tool entrance method
2355 # This method mainly dispatch specific methods per the command line options.
2356 # If no error found, return zero value so the caller of this tool can know
2357 # if it's executed successfully or not.
2359 # @retval 0 Tool was successful
2360 # @retval 1 Tool failed
2363 StartTime
= time
.time()
2365 # Initialize log system
2366 EdkLogger
.Initialize()
2367 GlobalData
.gCommand
= sys
.argv
[1:]
2369 # Parse the options and args
2371 (Option
, Target
) = MyOptionParser()
2372 GlobalData
.gOptions
= Option
2373 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2376 if Option
.verbose
is not None:
2377 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2378 elif Option
.quiet
is not None:
2379 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2380 elif Option
.debug
is not None:
2381 EdkLogger
.SetLevel(Option
.debug
+ 1)
2383 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2385 if Option
.LogFile
is not None:
2386 EdkLogger
.SetLogFile(Option
.LogFile
)
2388 if Option
.WarningAsError
== True:
2389 EdkLogger
.SetWarningAsError()
2391 if platform
.platform().find("Windows") >= 0:
2392 GlobalData
.gIsWindows
= True
2394 GlobalData
.gIsWindows
= False
2396 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2397 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2402 if len(Target
) == 0:
2404 elif len(Target
) >= 2:
2405 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2406 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2408 Target
= Target
[0].lower()
2410 if Target
not in gSupportedTarget
:
2411 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2412 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2415 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2418 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2420 Workspace
= os
.getenv("WORKSPACE")
2422 # Get files real name in workspace dir
2424 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2426 WorkingDirectory
= os
.getcwd()
2427 if not Option
.ModuleFile
:
2428 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2429 FileNum
= len(FileList
)
2431 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2432 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2434 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2436 if Option
.ModuleFile
:
2437 if os
.path
.isabs (Option
.ModuleFile
):
2438 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2439 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2440 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2441 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2443 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2445 if Option
.PlatformFile
is not None:
2446 if os
.path
.isabs (Option
.PlatformFile
):
2447 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2448 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2449 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2451 if Option
.FdfFile
is not None:
2452 if os
.path
.isabs (Option
.FdfFile
):
2453 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2454 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2455 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2456 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2458 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2460 if Option
.Flag
is not None and Option
.Flag
not in ['-c', '-s']:
2461 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2463 MyBuild
= Build(Target
, Workspace
, Option
)
2464 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2465 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2469 # All job done, no error found and no exception raised
2472 except FatalError
as X
:
2473 if MyBuild
is not None:
2474 # for multi-thread build exits safely
2475 MyBuild
.Relinquish()
2476 if Option
is not None and Option
.debug
is not None:
2477 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2478 ReturnCode
= X
.args
[0]
2479 except Warning as X
:
2480 # error from Fdf parser
2481 if MyBuild
is not None:
2482 # for multi-thread build exits safely
2483 MyBuild
.Relinquish()
2484 if Option
is not None and Option
.debug
is not None:
2485 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2487 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2488 ReturnCode
= FORMAT_INVALID
2489 except KeyboardInterrupt:
2490 ReturnCode
= ABORT_ERROR
2491 if Option
is not None and Option
.debug
is not None:
2492 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2494 if MyBuild
is not None:
2495 # for multi-thread build exits safely
2496 MyBuild
.Relinquish()
2498 # try to get the meta-file from the object causing exception
2499 Tb
= sys
.exc_info()[-1]
2500 MetaFile
= GlobalData
.gProcessingFile
2501 while Tb
is not None:
2502 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2503 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2508 "Unknown fatal error when processing [%s]" % MetaFile
,
2509 ExtraData
="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR
,
2512 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2513 ReturnCode
= CODE_ERROR
2515 Utils
.Progressor
.Abort()
2516 Utils
.ClearDuplicatedInf()
2520 MyBuild
.LaunchPostbuild()
2523 Conclusion
= "Failed"
2524 elif ReturnCode
== ABORT_ERROR
:
2525 Conclusion
= "Aborted"
2527 Conclusion
= "Failed"
2528 FinishTime
= time
.time()
2529 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2530 BuildDurationStr
= ""
2531 if BuildDuration
.tm_yday
> 1:
2532 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2534 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2535 if MyBuild
is not None:
2537 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2539 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2540 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2541 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2542 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2545 if __name__
== '__main__':
2547 ## 0-127 is a safe return range, and 1 is a standard default error
2548 if r
< 0 or r
> 127: r
= 1