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
)
1819 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1820 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1821 # for target which must generate AutoGen code and makefile
1822 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1823 self
.Progress
.Start("Generating code")
1824 Ma
.CreateCodeFile(True)
1825 self
.Progress
.Stop("done!")
1826 if self
.Target
== "genc":
1828 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1829 self
.Progress
.Start("Generating makefile")
1830 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
1831 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
1832 del CmdListDict
[Module
.File
, Arch
]
1834 Ma
.CreateMakeFile(True)
1835 self
.Progress
.Stop("done!")
1836 if self
.Target
== "genmake":
1838 self
.BuildModules
.append(Ma
)
1839 # Initialize all modules in tracking to 'FAIL'
1840 if Ma
.Arch
not in GlobalData
.gModuleBuildTracking
:
1841 GlobalData
.gModuleBuildTracking
[Ma
.Arch
] = dict()
1842 if Ma
not in GlobalData
.gModuleBuildTracking
[Ma
.Arch
]:
1843 GlobalData
.gModuleBuildTracking
[Ma
.Arch
][Ma
] = 'FAIL'
1844 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1845 MakeStart
= time
.time()
1846 for Ma
in self
.BuildModules
:
1847 if not Ma
.IsBinaryModule
:
1848 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
1849 # Break build if any build thread has error
1850 if BuildTask
.HasError():
1851 # we need a full version of makefile for platform
1853 BuildTask
.WaitForComplete()
1854 self
.invalidateHash()
1855 Pa
.CreateMakeFile(False)
1856 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1857 # Start task scheduler
1858 if not BuildTask
.IsOnGoing():
1859 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1861 # in case there's an interruption. we need a full version of makefile for platform
1862 Pa
.CreateMakeFile(False)
1863 if BuildTask
.HasError():
1864 self
.invalidateHash()
1865 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1866 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1868 MakeContiue
= time
.time()
1870 BuildTask
.WaitForComplete()
1871 self
.CreateAsBuiltInf()
1872 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1873 if BuildTask
.HasError():
1874 self
.invalidateHash()
1875 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1877 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1882 "Module for [%s] is not a component of active platform."\
1883 " Please make sure that the ARCH and inf file path are"\
1884 " given in the same as in [%s]" % \
1885 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1886 ExtraData
=self
.ModuleFile
1888 # Create MAP file when Load Fix Address is enabled.
1889 if self
.Target
== "fds" and self
.Fdf
:
1890 for Arch
in Wa
.ArchList
:
1892 # Check whether the set fix address is above 4G for 32bit image.
1894 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1895 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")
1900 for Pa
in Wa
.AutoGenObjectList
:
1901 for Ma
in Pa
.ModuleAutoGenList
:
1904 if not Ma
.IsLibrary
:
1905 ModuleList
[Ma
.Guid
.upper()] = Ma
1908 if self
.LoadFixAddress
!= 0:
1910 # Rebase module to the preferred memory address before GenFds
1912 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1914 # create FDS again for the updated EFI image
1916 GenFdsStart
= time
.time()
1917 self
._Build
("fds", Wa
)
1918 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
1920 # Create MAP file for all platform FVs after GenFds.
1922 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1924 # Save MAP buffer into MAP file.
1926 self
._SaveMapFile
(MapBuffer
, Wa
)
1927 self
.invalidateHash()
1929 def _GenFfsCmd(self
,ArchList
):
1930 # convert dictionary of Cmd:(Inf,Arch)
1931 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
1932 CmdSetDict
= defaultdict(set)
1933 GenFfsDict
= GenFds
.GenFfsMakefile('', GlobalData
.gFdfParser
, self
, ArchList
, GlobalData
)
1934 for Cmd
in GenFfsDict
:
1935 tmpInf
, tmpArch
= GenFfsDict
[Cmd
]
1936 CmdSetDict
[tmpInf
, tmpArch
].add(Cmd
)
1939 ## Build a platform in multi-thread mode
1941 def _MultiThreadBuildPlatform(self
):
1942 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1943 for BuildTarget
in self
.BuildTargetList
:
1944 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1946 for ToolChain
in self
.ToolChainList
:
1947 WorkspaceAutoGenTime
= time
.time()
1948 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1949 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1950 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1952 Wa
= WorkspaceAutoGen(
1969 self
.Fdf
= Wa
.FdfFile
1970 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1971 self
.BuildReport
.AddPlatformReport(Wa
)
1972 Wa
.CreateMakeFile(False)
1974 # Add ffs build to makefile
1976 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1977 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1979 # multi-thread exit flag
1980 ExitFlag
= threading
.Event()
1982 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1983 for Arch
in Wa
.ArchList
:
1984 AutoGenStart
= time
.time()
1985 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1986 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1990 for Inf
in Pa
.Platform
.Modules
:
1991 ModuleList
.append(Inf
)
1992 # Add the INF only list in FDF
1993 if GlobalData
.gFdfParser
is not None:
1994 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
1995 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
1996 if Inf
in Pa
.Platform
.Modules
:
1998 ModuleList
.append(Inf
)
1999 for Module
in ModuleList
:
2000 # Get ModuleAutoGen object to generate C code file and makefile
2001 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
2005 if Ma
.CanSkipbyHash():
2006 self
.HashSkipModules
.append(Ma
)
2009 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
2010 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
2011 # for target which must generate AutoGen code and makefile
2012 if not self
.SkipAutoGen
or self
.Target
== 'genc':
2013 Ma
.CreateCodeFile(True)
2014 if self
.Target
== "genc":
2017 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
2018 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
2019 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
2020 del CmdListDict
[Module
.File
, Arch
]
2022 Ma
.CreateMakeFile(True)
2023 if self
.Target
== "genmake":
2025 self
.BuildModules
.append(Ma
)
2026 # Initialize all modules in tracking to 'FAIL'
2027 if Ma
.Arch
not in GlobalData
.gModuleBuildTracking
:
2028 GlobalData
.gModuleBuildTracking
[Ma
.Arch
] = dict()
2029 if Ma
not in GlobalData
.gModuleBuildTracking
[Ma
.Arch
]:
2030 GlobalData
.gModuleBuildTracking
[Ma
.Arch
][Ma
] = 'FAIL'
2031 self
.Progress
.Stop("done!")
2032 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
2033 MakeStart
= time
.time()
2034 for Ma
in self
.BuildModules
:
2035 # Generate build task for the module
2036 if not Ma
.IsBinaryModule
:
2037 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
2038 # Break build if any build thread has error
2039 if BuildTask
.HasError():
2040 # we need a full version of makefile for platform
2042 BuildTask
.WaitForComplete()
2043 self
.invalidateHash()
2044 Pa
.CreateMakeFile(False)
2045 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2046 # Start task scheduler
2047 if not BuildTask
.IsOnGoing():
2048 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
2050 # in case there's an interruption. we need a full version of makefile for platform
2051 Pa
.CreateMakeFile(False)
2052 if BuildTask
.HasError():
2053 self
.invalidateHash()
2054 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2055 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
2057 MakeContiue
= time
.time()
2061 # All modules have been put in build tasks queue. Tell task scheduler
2062 # to exit if all tasks are completed
2065 BuildTask
.WaitForComplete()
2066 self
.CreateAsBuiltInf()
2067 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2069 # Check for build error, and raise exception if one
2070 # has been signaled.
2072 if BuildTask
.HasError():
2073 self
.invalidateHash()
2074 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2076 # Create MAP file when Load Fix Address is enabled.
2077 if self
.Target
in ["", "all", "fds"]:
2078 for Arch
in Wa
.ArchList
:
2080 # Check whether the set fix address is above 4G for 32bit image.
2082 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2083 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")
2088 for Pa
in Wa
.AutoGenObjectList
:
2089 for Ma
in Pa
.ModuleAutoGenList
:
2092 if not Ma
.IsLibrary
:
2093 ModuleList
[Ma
.Guid
.upper()] = Ma
2095 # Rebase module to the preferred memory address before GenFds
2098 if self
.LoadFixAddress
!= 0:
2099 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2103 # Generate FD image if there's a FDF file found
2105 GenFdsStart
= time
.time()
2106 if GenFdsApi(Wa
.GenFdsCommandDict
, self
.Db
):
2107 EdkLogger
.error("build", COMMAND_FAILURE
)
2110 # Create MAP file for all platform FVs after GenFds.
2112 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2113 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2115 # Save MAP buffer into MAP file.
2117 self
._SaveMapFile
(MapBuffer
, Wa
)
2118 self
.invalidateHash()
2120 ## Generate GuidedSectionTools.txt in the FV directories.
2122 def CreateGuidedSectionToolsFile(self
):
2123 for BuildTarget
in self
.BuildTargetList
:
2124 for ToolChain
in self
.ToolChainList
:
2125 Wa
= WorkspaceAutoGen(
2142 if not os
.path
.exists(FvDir
):
2145 for Arch
in self
.ArchList
:
2146 # Build up the list of supported architectures for this build
2147 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
2149 # Look through the tool definitions for GUIDed tools
2151 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.items():
2152 if attrib
.upper().endswith('_GUID'):
2153 split
= attrib
.split('_')
2154 thisPrefix
= '_'.join(split
[0:3]) + '_'
2155 if thisPrefix
== prefix
:
2156 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
2159 path
= '_'.join(split
[0:4]) + '_PATH'
2160 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2161 path
= self
.GetFullPathOfTool(path
)
2162 guidAttribs
.append((guid
, toolName
, path
))
2164 # Write out GuidedSecTools.txt
2165 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2166 toolsFile
= open(toolsFile
, 'wt')
2167 for guidedSectionTool
in guidAttribs
:
2168 print(' '.join(guidedSectionTool
), file=toolsFile
)
2171 ## Returns the full path of the tool.
2173 def GetFullPathOfTool (self
, tool
):
2174 if os
.path
.exists(tool
):
2175 return os
.path
.realpath(tool
)
2177 # We need to search for the tool using the
2178 # PATH environment variable.
2179 for dirInPath
in os
.environ
['PATH'].split(os
.pathsep
):
2180 foundPath
= os
.path
.join(dirInPath
, tool
)
2181 if os
.path
.exists(foundPath
):
2182 return os
.path
.realpath(foundPath
)
2184 # If the tool was not found in the path then we just return
2188 ## Launch the module or platform build
2191 if not self
.ModuleFile
:
2192 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2193 self
.SpawnMode
= False
2194 self
._BuildPlatform
()
2196 self
._MultiThreadBuildPlatform
()
2197 self
.CreateGuidedSectionToolsFile()
2199 self
.SpawnMode
= False
2202 if self
.Target
== 'cleanall':
2203 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2205 def CreateAsBuiltInf(self
):
2208 for Module
in self
.BuildModules
:
2209 Module
.CreateAsBuiltInf()
2210 all_mod_set
.add(Module
)
2211 for Module
in self
.HashSkipModules
:
2212 Module
.CreateAsBuiltInf(True)
2213 all_mod_set
.add(Module
)
2214 for Module
in all_mod_set
:
2215 for lib
in Module
.LibraryAutoGenList
:
2216 all_lib_set
.add(lib
)
2217 for lib
in all_lib_set
:
2218 lib
.CreateAsBuiltInf(True)
2221 self
.BuildModules
= []
2222 self
.HashSkipModules
= []
2223 ## Do some clean-up works when error occurred
2224 def Relinquish(self
):
2225 OldLogLevel
= EdkLogger
.GetLevel()
2226 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2227 Utils
.Progressor
.Abort()
2228 if self
.SpawnMode
== True:
2230 EdkLogger
.SetLevel(OldLogLevel
)
2232 def ParseDefines(DefineList
=[]):
2234 if DefineList
is not None:
2235 for Define
in DefineList
:
2236 DefineTokenList
= Define
.split("=", 1)
2237 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2238 EdkLogger
.error('build', FORMAT_INVALID
,
2239 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2240 ExtraData
=DefineTokenList
[0])
2242 if len(DefineTokenList
) == 1:
2243 DefineDict
[DefineTokenList
[0]] = "TRUE"
2245 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2249 def SingleCheckCallback(option
, opt_str
, value
, parser
):
2250 if option
not in gParamCheck
:
2251 setattr(parser
.values
, option
.dest
, value
)
2252 gParamCheck
.append(option
)
2254 parser
.error("Option %s only allows one instance in command line!" % option
)
2256 def LogBuildTime(Time
):
2259 TimeDur
= time
.gmtime(Time
)
2260 if TimeDur
.tm_yday
> 1:
2261 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2263 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2268 ## Parse command line options
2270 # Using standard Python module optparse to parse command line option of this tool.
2272 # @retval Opt A optparse.Values object containing the parsed options
2273 # @retval Args Target of build command
2275 def MyOptionParser():
2276 Parser
= OptionParser(description
=__copyright__
, version
=__version__
, prog
="build.exe", usage
="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
2277 Parser
.add_option("-a", "--arch", action
="append", type="choice", choices
=['IA32', 'X64', 'EBC', 'ARM', 'AARCH64'], dest
="TargetArch",
2278 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.")
2279 Parser
.add_option("-p", "--platform", action
="callback", type="string", dest
="PlatformFile", callback
=SingleCheckCallback
,
2280 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
2281 Parser
.add_option("-m", "--module", action
="callback", type="string", dest
="ModuleFile", callback
=SingleCheckCallback
,
2282 help="Build the module specified by the INF file name argument.")
2283 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
2285 Parser
.add_option("-t", "--tagname", action
="append", type="string", dest
="ToolChain",
2286 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
2287 Parser
.add_option("-x", "--sku-id", action
="callback", type="string", dest
="SkuId", callback
=SingleCheckCallback
,
2288 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
2290 Parser
.add_option("-n", action
="callback", type="int", dest
="ThreadNumber", callback
=SingleCheckCallback
,
2291 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 "\
2292 "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.")
2294 Parser
.add_option("-f", "--fdf", action
="callback", type="string", dest
="FdfFile", callback
=SingleCheckCallback
,
2295 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
2296 Parser
.add_option("-r", "--rom-image", action
="append", type="string", dest
="RomImage", default
=[],
2297 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
2298 Parser
.add_option("-i", "--fv-image", action
="append", type="string", dest
="FvImage", default
=[],
2299 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
2300 Parser
.add_option("-C", "--capsule-image", action
="append", type="string", dest
="CapName", default
=[],
2301 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
2302 Parser
.add_option("-u", "--skip-autogen", action
="store_true", dest
="SkipAutoGen", help="Skip AutoGen step.")
2303 Parser
.add_option("-e", "--re-parse", action
="store_true", dest
="Reparse", help="Re-parse all meta-data files.")
2305 Parser
.add_option("-c", "--case-insensitive", action
="store_true", dest
="CaseInsensitive", default
=False, help="Don't check case of file name.")
2307 Parser
.add_option("-w", "--warning-as-error", action
="store_true", dest
="WarningAsError", help="Treat warning in tools as error.")
2308 Parser
.add_option("-j", "--log", action
="store", dest
="LogFile", help="Put log in specified file as well as on console.")
2310 Parser
.add_option("-s", "--silent", action
="store_true", type=None, dest
="SilentMode",
2311 help="Make use of silent mode of (n)make.")
2312 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
2313 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
2314 "including library instances selected, final dependency expression, "\
2315 "and warning messages, etc.")
2316 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
2317 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
2319 Parser
.add_option("-y", "--report-file", action
="store", dest
="ReportFile", help="Create/overwrite the report to the specified filename.")
2320 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
=[],
2321 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]. "\
2322 "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]")
2323 Parser
.add_option("-F", "--flag", action
="store", type="string", dest
="Flag",
2324 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. "\
2325 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
2326 "will override the setting in [BuildOptions] section of platform DSC.")
2327 Parser
.add_option("-N", "--no-cache", action
="store_true", dest
="DisableCache", default
=False, help="Disable build cache mechanism")
2328 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
2329 Parser
.add_option("--check-usage", action
="store_true", dest
="CheckUsage", default
=False, help="Check usage content of entries listed in INF file.")
2330 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
2331 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
2332 Parser
.add_option("-l", "--cmd-len", action
="store", type="int", dest
="CommandLength", help="Specify the maximum line length of build command. Default is 4096.")
2333 Parser
.add_option("--hash", action
="store_true", dest
="UseHashCache", default
=False, help="Enable hash-based caching during build process.")
2334 Parser
.add_option("--binary-destination", action
="store", type="string", dest
="BinCacheDest", help="Generate a cache of binary files in the specified directory.")
2335 Parser
.add_option("--binary-source", action
="store", type="string", dest
="BinCacheSource", help="Consume a cache of binary files from the specified directory.")
2336 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
2337 Parser
.add_option("--disable-include-path-check", action
="store_true", dest
="DisableIncludePathCheck", default
=False, help="Disable the include path check for outside of package.")
2338 (Opt
, Args
) = Parser
.parse_args()
2341 ## Tool entrance method
2343 # This method mainly dispatch specific methods per the command line options.
2344 # If no error found, return zero value so the caller of this tool can know
2345 # if it's executed successfully or not.
2347 # @retval 0 Tool was successful
2348 # @retval 1 Tool failed
2351 StartTime
= time
.time()
2353 # Initialize log system
2354 EdkLogger
.Initialize()
2355 GlobalData
.gCommand
= sys
.argv
[1:]
2357 # Parse the options and args
2359 (Option
, Target
) = MyOptionParser()
2360 GlobalData
.gOptions
= Option
2361 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2364 if Option
.verbose
is not None:
2365 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2366 elif Option
.quiet
is not None:
2367 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2368 elif Option
.debug
is not None:
2369 EdkLogger
.SetLevel(Option
.debug
+ 1)
2371 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2373 if Option
.LogFile
is not None:
2374 EdkLogger
.SetLogFile(Option
.LogFile
)
2376 if Option
.WarningAsError
== True:
2377 EdkLogger
.SetWarningAsError()
2379 if platform
.platform().find("Windows") >= 0:
2380 GlobalData
.gIsWindows
= True
2382 GlobalData
.gIsWindows
= False
2384 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2385 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2390 if len(Target
) == 0:
2392 elif len(Target
) >= 2:
2393 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2394 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2396 Target
= Target
[0].lower()
2398 if Target
not in gSupportedTarget
:
2399 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2400 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2403 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2406 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2408 Workspace
= os
.getenv("WORKSPACE")
2410 # Get files real name in workspace dir
2412 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2414 WorkingDirectory
= os
.getcwd()
2415 if not Option
.ModuleFile
:
2416 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2417 FileNum
= len(FileList
)
2419 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2420 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2422 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2424 if Option
.ModuleFile
:
2425 if os
.path
.isabs (Option
.ModuleFile
):
2426 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2427 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2428 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2429 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2431 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2433 if Option
.PlatformFile
is not None:
2434 if os
.path
.isabs (Option
.PlatformFile
):
2435 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2436 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2437 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2439 if Option
.FdfFile
is not None:
2440 if os
.path
.isabs (Option
.FdfFile
):
2441 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2442 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2443 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2444 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2446 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2448 if Option
.Flag
is not None and Option
.Flag
not in ['-c', '-s']:
2449 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2451 MyBuild
= Build(Target
, Workspace
, Option
)
2452 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2453 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2457 # All job done, no error found and no exception raised
2460 except FatalError
as X
:
2461 if MyBuild
is not None:
2462 # for multi-thread build exits safely
2463 MyBuild
.Relinquish()
2464 if Option
is not None and Option
.debug
is not None:
2465 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2466 ReturnCode
= X
.args
[0]
2467 except Warning as X
:
2468 # error from Fdf parser
2469 if MyBuild
is not None:
2470 # for multi-thread build exits safely
2471 MyBuild
.Relinquish()
2472 if Option
is not None and Option
.debug
is not None:
2473 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2475 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2476 ReturnCode
= FORMAT_INVALID
2477 except KeyboardInterrupt:
2478 ReturnCode
= ABORT_ERROR
2479 if Option
is not None and Option
.debug
is not None:
2480 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2482 if MyBuild
is not None:
2483 # for multi-thread build exits safely
2484 MyBuild
.Relinquish()
2486 # try to get the meta-file from the object causing exception
2487 Tb
= sys
.exc_info()[-1]
2488 MetaFile
= GlobalData
.gProcessingFile
2489 while Tb
is not None:
2490 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2491 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2496 "Unknown fatal error when processing [%s]" % MetaFile
,
2497 ExtraData
="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR
,
2500 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2501 ReturnCode
= CODE_ERROR
2503 Utils
.Progressor
.Abort()
2504 Utils
.ClearDuplicatedInf()
2508 MyBuild
.LaunchPostbuild()
2511 Conclusion
= "Failed"
2512 elif ReturnCode
== ABORT_ERROR
:
2513 Conclusion
= "Aborted"
2515 Conclusion
= "Failed"
2516 FinishTime
= time
.time()
2517 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2518 BuildDurationStr
= ""
2519 if BuildDuration
.tm_yday
> 1:
2520 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2522 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2523 if MyBuild
is not None:
2525 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2527 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2528 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2529 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2530 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2533 if __name__
== '__main__':
2535 ## 0-127 is a safe return range, and 1 is a standard default error
2536 if r
< 0 or r
> 127: r
= 1