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
))
776 if not os
.path
.exists(os
.path
.join(GlobalData
.gConfDirectory
, '.cache')):
777 os
.makedirs(os
.path
.join(GlobalData
.gConfDirectory
, '.cache'))
778 self
.Db
= WorkspaceDatabase()
779 self
.BuildDatabase
= self
.Db
.BuildObject
781 self
.ToolChainFamily
= None
782 self
.LoadFixAddress
= 0
783 self
.UniFlag
= BuildOptions
.Flag
784 self
.BuildModules
= []
785 self
.HashSkipModules
= []
787 self
.LaunchPrebuildFlag
= False
788 self
.PlatformBuildPath
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PlatformBuild')
789 if BuildOptions
.CommandLength
:
790 GlobalData
.gCommandMaxLength
= BuildOptions
.CommandLength
792 # print dot character during doing some time-consuming work
793 self
.Progress
= Utils
.Progressor()
794 # print current build environment and configuration
795 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
796 if "PACKAGES_PATH" in os
.environ
:
797 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
798 EdkLogger
.quiet("%-16s = %s" % ("PACKAGES_PATH", os
.path
.normcase(os
.path
.normpath(os
.environ
["PACKAGES_PATH"]))))
799 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
800 if "EDK_TOOLS_BIN" in os
.environ
:
801 # Print the same path style with WORKSPACE env.
802 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_TOOLS_BIN"]))))
803 EdkLogger
.quiet("%-16s = %s" % ("CONF_PATH", GlobalData
.gConfDirectory
))
804 if "PYTHON3_ENABLE" in os
.environ
:
805 PYTHON3_ENABLE
= os
.environ
["PYTHON3_ENABLE"]
806 if PYTHON3_ENABLE
!= "TRUE":
807 PYTHON3_ENABLE
= "FALSE"
808 EdkLogger
.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE
))
809 if "PYTHON_COMMAND" in os
.environ
:
810 EdkLogger
.quiet("%-16s = %s" % ("PYTHON_COMMAND", os
.environ
["PYTHON_COMMAND"]))
814 EdkLogger
.quiet("%-16s = %s" % ("PREBUILD", self
.Prebuild
))
816 EdkLogger
.quiet("%-16s = %s" % ("POSTBUILD", self
.Postbuild
))
818 self
.LaunchPrebuild()
819 self
.TargetTxt
= TargetTxtClassObject()
820 self
.ToolDef
= ToolDefClassObject()
821 if not (self
.LaunchPrebuildFlag
and os
.path
.exists(self
.PlatformBuildPath
)):
825 os
.chdir(self
.WorkspaceDir
)
827 ## Load configuration
829 # This method will parse target.txt and get the build configurations.
831 def LoadConfiguration(self
):
833 # Check target.txt and tools_def.txt and Init them
835 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(GlobalData
.gConfDirectory
, gBuildConfiguration
))
836 if os
.path
.isfile(BuildConfigurationFile
) == True:
837 StatusCode
= self
.TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
839 ToolDefinitionFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_CONF
]
840 if ToolDefinitionFile
== '':
841 ToolDefinitionFile
= gToolsDefinition
842 ToolDefinitionFile
= os
.path
.normpath(mws
.join(self
.WorkspaceDir
, 'Conf', ToolDefinitionFile
))
843 if os
.path
.isfile(ToolDefinitionFile
) == True:
844 StatusCode
= self
.ToolDef
.LoadToolDefFile(ToolDefinitionFile
)
846 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=ToolDefinitionFile
)
848 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
850 # if no ARCH given in command line, get it from target.txt
851 if not self
.ArchList
:
852 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET_ARCH
]
853 self
.ArchList
= tuple(self
.ArchList
)
855 # if no build target given in command line, get it from target.txt
856 if not self
.BuildTargetList
:
857 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
859 # if no tool chain given in command line, get it from target.txt
860 if not self
.ToolChainList
:
861 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
862 if self
.ToolChainList
is None or len(self
.ToolChainList
) == 0:
863 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
865 # check if the tool chains are defined or not
866 NewToolChainList
= []
867 for ToolChain
in self
.ToolChainList
:
868 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
869 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
871 NewToolChainList
.append(ToolChain
)
872 # if no tool chain available, break the build
873 if len(NewToolChainList
) == 0:
874 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
875 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
877 self
.ToolChainList
= NewToolChainList
880 ToolDefinition
= self
.ToolDef
.ToolsDefTxtDatabase
881 for Tool
in self
.ToolChainList
:
882 if TAB_TOD_DEFINES_FAMILY
not in ToolDefinition
or Tool
not in ToolDefinition
[TAB_TOD_DEFINES_FAMILY
] \
883 or not ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
]:
884 EdkLogger
.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool
)
885 ToolChainFamily
.append(TAB_COMPILER_MSFT
)
887 ToolChainFamily
.append(ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
])
888 self
.ToolChainFamily
= ToolChainFamily
890 if self
.ThreadNumber
is None:
891 self
.ThreadNumber
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
892 if self
.ThreadNumber
== '':
893 self
.ThreadNumber
= 0
895 self
.ThreadNumber
= int(self
.ThreadNumber
, 0)
897 if self
.ThreadNumber
== 0:
899 self
.ThreadNumber
= multiprocessing
.cpu_count()
900 except (ImportError, NotImplementedError):
901 self
.ThreadNumber
= 1
903 if not self
.PlatformFile
:
904 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
906 # Try to find one in current directory
907 WorkingDirectory
= os
.getcwd()
908 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
909 FileNum
= len(FileList
)
911 EdkLogger
.error("build", OPTION_MISSING
,
912 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
914 PlatformFile
= FileList
[0]
916 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
917 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
919 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
921 ## Initialize build configuration
923 # This method will parse DSC file and merge the configurations from
924 # command line and target.txt, then get the final build configurations.
927 # parse target.txt, tools_def.txt, and platform file
928 self
.LoadConfiguration()
930 # Allow case-insensitive for those from command line or configuration file
931 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
933 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
936 def InitPreBuild(self
):
937 self
.LoadConfiguration()
938 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
940 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
941 if self
.BuildTargetList
:
942 GlobalData
.gGlobalDefines
['TARGET'] = self
.BuildTargetList
[0]
944 GlobalData
.gGlobalDefines
['ARCH'] = self
.ArchList
[0]
945 if self
.ToolChainList
:
946 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = self
.ToolChainList
[0]
947 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = self
.ToolChainList
[0]
948 if self
.ToolChainFamily
:
949 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[0]
950 if 'PREBUILD' in GlobalData
.gCommandLineDefines
:
951 self
.Prebuild
= GlobalData
.gCommandLineDefines
.get('PREBUILD')
954 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
955 self
.Prebuild
= str(Platform
.Prebuild
)
959 # Evaluate all arguments and convert arguments that are WORKSPACE
960 # relative paths to absolute paths. Filter arguments that look like
961 # flags or do not follow the file/dir naming rules to avoid false
962 # positives on this conversion.
964 for Arg
in self
.Prebuild
.split():
966 # Do not modify Arg if it looks like a flag or an absolute file path
968 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
969 PrebuildList
.append(Arg
)
972 # Do not modify Arg if it does not look like a Workspace relative
973 # path that starts with a valid package directory name
975 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
976 PrebuildList
.append(Arg
)
979 # If Arg looks like a WORKSPACE relative path, then convert to an
980 # absolute path and check to see if the file exists.
982 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
983 if os
.path
.isfile(Temp
):
985 PrebuildList
.append(Arg
)
986 self
.Prebuild
= ' '.join(PrebuildList
)
987 self
.Prebuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
989 def InitPostBuild(self
):
990 if 'POSTBUILD' in GlobalData
.gCommandLineDefines
:
991 self
.Postbuild
= GlobalData
.gCommandLineDefines
.get('POSTBUILD')
993 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
994 self
.Postbuild
= str(Platform
.Postbuild
)
998 # Evaluate all arguments and convert arguments that are WORKSPACE
999 # relative paths to absolute paths. Filter arguments that look like
1000 # flags or do not follow the file/dir naming rules to avoid false
1001 # positives on this conversion.
1003 for Arg
in self
.Postbuild
.split():
1005 # Do not modify Arg if it looks like a flag or an absolute file path
1007 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1008 PostbuildList
.append(Arg
)
1011 # Do not modify Arg if it does not look like a Workspace relative
1012 # path that starts with a valid package directory name
1014 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1015 PostbuildList
.append(Arg
)
1018 # If Arg looks like a WORKSPACE relative path, then convert to an
1019 # absolute path and check to see if the file exists.
1021 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1022 if os
.path
.isfile(Temp
):
1024 PostbuildList
.append(Arg
)
1025 self
.Postbuild
= ' '.join(PostbuildList
)
1026 self
.Postbuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1028 def PassCommandOption(self
, BuildTarget
, TargetArch
, ToolChain
, PlatformFile
, Target
):
1030 if GlobalData
.gCommand
and isinstance(GlobalData
.gCommand
, list):
1031 BuildStr
+= ' ' + ' '.join(GlobalData
.gCommand
)
1034 ToolChainFlag
= False
1035 PlatformFileFlag
= False
1037 if GlobalData
.gOptions
and not GlobalData
.gOptions
.BuildTarget
:
1039 if GlobalData
.gOptions
and not GlobalData
.gOptions
.TargetArch
:
1041 if GlobalData
.gOptions
and not GlobalData
.gOptions
.ToolChain
:
1042 ToolChainFlag
= True
1043 if GlobalData
.gOptions
and not GlobalData
.gOptions
.PlatformFile
:
1044 PlatformFileFlag
= True
1046 if TargetFlag
and BuildTarget
:
1047 if isinstance(BuildTarget
, list) or isinstance(BuildTarget
, tuple):
1048 BuildStr
+= ' -b ' + ' -b '.join(BuildTarget
)
1049 elif isinstance(BuildTarget
, str):
1050 BuildStr
+= ' -b ' + BuildTarget
1051 if ArchFlag
and TargetArch
:
1052 if isinstance(TargetArch
, list) or isinstance(TargetArch
, tuple):
1053 BuildStr
+= ' -a ' + ' -a '.join(TargetArch
)
1054 elif isinstance(TargetArch
, str):
1055 BuildStr
+= ' -a ' + TargetArch
1056 if ToolChainFlag
and ToolChain
:
1057 if isinstance(ToolChain
, list) or isinstance(ToolChain
, tuple):
1058 BuildStr
+= ' -t ' + ' -t '.join(ToolChain
)
1059 elif isinstance(ToolChain
, str):
1060 BuildStr
+= ' -t ' + ToolChain
1061 if PlatformFileFlag
and PlatformFile
:
1062 if isinstance(PlatformFile
, list) or isinstance(PlatformFile
, tuple):
1063 BuildStr
+= ' -p ' + ' -p '.join(PlatformFile
)
1064 elif isinstance(PlatformFile
, str):
1065 BuildStr
+= ' -p' + PlatformFile
1066 BuildStr
+= ' --conf=' + GlobalData
.gConfDirectory
1068 BuildStr
+= ' ' + Target
1072 def LaunchPrebuild(self
):
1074 EdkLogger
.info("\n- Prebuild Start -\n")
1075 self
.LaunchPrebuildFlag
= True
1077 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1078 # and preserve them for the rest of the main build step, because the child process environment will
1079 # evaporate as soon as it exits, we cannot get it in build step.
1081 PrebuildEnvFile
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PrebuildEnv')
1082 if os
.path
.isfile(PrebuildEnvFile
):
1083 os
.remove(PrebuildEnvFile
)
1084 if os
.path
.isfile(self
.PlatformBuildPath
):
1085 os
.remove(self
.PlatformBuildPath
)
1086 if sys
.platform
== "win32":
1087 args
= ' && '.join((self
.Prebuild
, 'set > ' + PrebuildEnvFile
))
1088 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1090 args
= ' && '.join((self
.Prebuild
, 'env > ' + PrebuildEnvFile
))
1091 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1093 # launch two threads to read the STDOUT and STDERR
1094 EndOfProcedure
= Event()
1095 EndOfProcedure
.clear()
1097 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1098 StdOutThread
.setName("STDOUT-Redirector")
1099 StdOutThread
.setDaemon(False)
1100 StdOutThread
.start()
1103 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1104 StdErrThread
.setName("STDERR-Redirector")
1105 StdErrThread
.setDaemon(False)
1106 StdErrThread
.start()
1107 # waiting for program exit
1114 if Process
.returncode
!= 0 :
1115 EdkLogger
.error("Prebuild", PREBUILD_ERROR
, 'Prebuild process is not success!')
1117 if os
.path
.exists(PrebuildEnvFile
):
1118 f
= open(PrebuildEnvFile
)
1119 envs
= f
.readlines()
1121 envs
= [l
.split("=", 1) for l
in envs
]
1122 envs
= [[I
.strip() for I
in item
] for item
in envs
if len(item
) == 2]
1123 os
.environ
.update(dict(envs
))
1124 EdkLogger
.info("\n- Prebuild Done -\n")
1126 def LaunchPostbuild(self
):
1128 EdkLogger
.info("\n- Postbuild Start -\n")
1129 if sys
.platform
== "win32":
1130 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1132 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1133 # launch two threads to read the STDOUT and STDERR
1134 EndOfProcedure
= Event()
1135 EndOfProcedure
.clear()
1137 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1138 StdOutThread
.setName("STDOUT-Redirector")
1139 StdOutThread
.setDaemon(False)
1140 StdOutThread
.start()
1143 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1144 StdErrThread
.setName("STDERR-Redirector")
1145 StdErrThread
.setDaemon(False)
1146 StdErrThread
.start()
1147 # waiting for program exit
1154 if Process
.returncode
!= 0 :
1155 EdkLogger
.error("Postbuild", POSTBUILD_ERROR
, 'Postbuild process is not success!')
1156 EdkLogger
.info("\n- Postbuild Done -\n")
1158 ## Error handling for hash feature
1160 # On BuildTask error, iterate through the Module Build tracking
1161 # dictionary to determine wheather a module failed to build. Invalidate
1162 # the hash associated with that module by removing it from storage.
1165 def invalidateHash(self
):
1166 # Only for hashing feature
1167 if not GlobalData
.gUseHashCache
:
1170 # GlobalData.gModuleBuildTracking contains only modules or libs that cannot be skipped by hash
1171 for moduleAutoGenObjArch
in GlobalData
.gModuleBuildTracking
.keys():
1172 for moduleAutoGenObj
in GlobalData
.gModuleBuildTracking
[moduleAutoGenObjArch
].keys():
1173 # Skip invalidating for Successful Module/Lib builds
1174 if GlobalData
.gModuleBuildTracking
[moduleAutoGenObjArch
][moduleAutoGenObj
] == 'SUCCESS':
1177 # The module failed to build, failed to start building, or failed the header check test from this point on
1179 # Remove .hash from build
1180 ModuleHashFile
= os
.path
.join(moduleAutoGenObj
.BuildDir
, moduleAutoGenObj
.Name
+ ".hash")
1181 if os
.path
.exists(ModuleHashFile
):
1182 os
.remove(ModuleHashFile
)
1184 # Remove .hash file from cache
1185 if GlobalData
.gBinCacheDest
:
1186 FileDir
= os
.path
.join(GlobalData
.gBinCacheDest
, moduleAutoGenObj
.Arch
, moduleAutoGenObj
.SourceDir
, moduleAutoGenObj
.MetaFile
.BaseName
)
1187 HashFile
= os
.path
.join(FileDir
, moduleAutoGenObj
.Name
+ '.hash')
1188 if os
.path
.exists(HashFile
):
1191 ## Build a module or platform
1193 # Create autogen code and makefile for a module or platform, and the launch
1194 # "make" command to build it
1196 # @param Target The target of build command
1197 # @param Platform The platform file
1198 # @param Module The module file
1199 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1200 # @param ToolChain The name of toolchain to build
1201 # @param Arch The arch of the module/platform
1202 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1203 # for dependent modules/Libraries
1204 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1205 # for dependent modules/Libraries
1207 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False, FfsCommand
={}):
1208 if AutoGenObject
is None:
1211 # skip file generation for cleanxxx targets, run and fds target
1212 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1213 # for target which must generate AutoGen code and makefile
1214 if not self
.SkipAutoGen
or Target
== 'genc':
1215 self
.Progress
.Start("Generating code")
1216 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1217 self
.Progress
.Stop("done!")
1218 if Target
== "genc":
1221 if not self
.SkipAutoGen
or Target
== 'genmake':
1222 self
.Progress
.Start("Generating makefile")
1223 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
, FfsCommand
)
1224 self
.Progress
.Stop("done!")
1225 if Target
== "genmake":
1228 # always recreate top/platform makefile when clean, just in case of inconsistency
1229 AutoGenObject
.CreateCodeFile(False)
1230 AutoGenObject
.CreateMakeFile(False)
1232 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1233 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1235 BuildCommand
= AutoGenObject
.BuildCommand
1236 if BuildCommand
is None or len(BuildCommand
) == 0:
1237 EdkLogger
.error("build", OPTION_MISSING
,
1238 "No build command found for this module. "
1239 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1240 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1241 ExtraData
=str(AutoGenObject
))
1243 makefile
= GenMake
.BuildFile(AutoGenObject
)._FILE
_NAME
_[GenMake
.gMakeType
]
1251 BuildCommand
= BuildCommand
+ [Target
]
1252 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1253 self
.CreateAsBuiltInf()
1254 if GlobalData
.gBinCacheDest
:
1255 self
.UpdateBuildCache()
1256 self
.BuildModules
= []
1260 if Target
== 'libraries':
1261 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1262 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1263 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1267 if Target
== 'modules':
1268 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1269 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1270 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1271 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1272 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, makefile
)), 'pbuild']
1273 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1274 self
.CreateAsBuiltInf()
1275 if GlobalData
.gBinCacheDest
:
1276 self
.UpdateBuildCache()
1277 self
.BuildModules
= []
1281 if Target
== 'cleanlib':
1282 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1283 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1284 if os
.path
.exists(LibMakefile
):
1285 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1286 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1290 if Target
== 'clean':
1291 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1292 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, makefile
))
1293 if os
.path
.exists(ModMakefile
):
1294 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
1295 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1296 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1297 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1298 if os
.path
.exists(LibMakefile
):
1299 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1300 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1304 if Target
== 'cleanall':
1306 #os.rmdir(AutoGenObject.BuildDir)
1307 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1308 except WindowsError as X
:
1309 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1312 ## Build a module or platform
1314 # Create autogen code and makefile for a module or platform, and the launch
1315 # "make" command to build it
1317 # @param Target The target of build command
1318 # @param Platform The platform file
1319 # @param Module The module file
1320 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1321 # @param ToolChain The name of toolchain to build
1322 # @param Arch The arch of the module/platform
1323 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1324 # for dependent modules/Libraries
1325 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1326 # for dependent modules/Libraries
1328 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1329 if AutoGenObject
is None:
1332 # skip file generation for cleanxxx targets, run and fds target
1333 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1334 # for target which must generate AutoGen code and makefile
1335 if not self
.SkipAutoGen
or Target
== 'genc':
1336 self
.Progress
.Start("Generating code")
1337 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1338 self
.Progress
.Stop("done!")
1339 if Target
== "genc":
1342 if not self
.SkipAutoGen
or Target
== 'genmake':
1343 self
.Progress
.Start("Generating makefile")
1344 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1345 #AutoGenObject.CreateAsBuiltInf()
1346 self
.Progress
.Stop("done!")
1347 if Target
== "genmake":
1350 # always recreate top/platform makefile when clean, just in case of inconsistency
1351 AutoGenObject
.CreateCodeFile(False)
1352 AutoGenObject
.CreateMakeFile(False)
1354 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1355 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1357 BuildCommand
= AutoGenObject
.BuildCommand
1358 if BuildCommand
is None or len(BuildCommand
) == 0:
1359 EdkLogger
.error("build", OPTION_MISSING
,
1360 "No build command found for this module. "
1361 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1362 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1363 ExtraData
=str(AutoGenObject
))
1368 BuildCommand
= BuildCommand
+ [Target
]
1369 AutoGenObject
.BuildTime
= LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1370 self
.CreateAsBuiltInf()
1371 if GlobalData
.gBinCacheDest
:
1372 self
.UpdateBuildCache()
1373 self
.BuildModules
= []
1378 if GenFdsApi(AutoGenObject
.GenFdsCommandDict
, self
.Db
):
1379 EdkLogger
.error("build", COMMAND_FAILURE
)
1387 if Target
== 'libraries':
1394 if Target
== 'cleanall':
1396 #os.rmdir(AutoGenObject.BuildDir)
1397 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1398 except WindowsError as X
:
1399 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1402 ## Rebase module image and Get function address for the input module list.
1404 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1406 AddrIsOffset
= False
1407 for InfFile
in ModuleList
:
1408 sys
.stdout
.write (".")
1410 ModuleInfo
= ModuleList
[InfFile
]
1411 ModuleName
= ModuleInfo
.BaseName
1412 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1413 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1414 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1416 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1418 # Update Image to new BaseAddress by GenFw tool
1420 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1421 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1424 # Set new address to the section header only for SMM driver.
1426 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1427 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1429 # Collect function address from Map file
1431 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1433 if os
.path
.exists(ImageMapTable
):
1434 OrigImageBaseAddress
= 0
1435 ImageMap
= open(ImageMapTable
, 'r')
1436 for LinStr
in ImageMap
:
1437 if len (LinStr
.strip()) == 0:
1440 # Get the preferred address set on link time.
1442 if LinStr
.find ('Preferred load address is') != -1:
1443 StrList
= LinStr
.split()
1444 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1446 StrList
= LinStr
.split()
1447 if len (StrList
) > 4:
1448 if StrList
[3] == 'f' or StrList
[3] == 'F':
1450 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1451 FunctionList
.append ((Name
, RelativeAddress
))
1455 # Add general information.
1458 MapBuffer
.append('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1460 MapBuffer
.append('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1462 MapBuffer
.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1464 # Add guid and general seciton section.
1466 TextSectionAddress
= 0
1467 DataSectionAddress
= 0
1468 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1469 if SectionHeader
[0] == '.text':
1470 TextSectionAddress
= SectionHeader
[1]
1471 elif SectionHeader
[0] in ['.data', '.sdata']:
1472 DataSectionAddress
= SectionHeader
[1]
1474 MapBuffer
.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1476 MapBuffer
.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1478 # Add debug image full path.
1480 MapBuffer
.append('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1482 # Add function address
1484 for Function
in FunctionList
:
1486 MapBuffer
.append(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1488 MapBuffer
.append(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1492 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1495 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1497 ## Collect MAP information of all FVs
1499 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1501 # First get the XIP base address for FV map file.
1502 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1503 GuidName
= re
.compile(r
"\(GUID=[-a-fA-F0-9]+")
1504 for FvName
in Wa
.FdfProfile
.FvDict
:
1505 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1506 if not os
.path
.exists(FvMapBuffer
):
1508 FvMap
= open(FvMapBuffer
, 'r')
1509 #skip FV size information
1515 MatchGuid
= GuidPattern
.match(Line
)
1516 if MatchGuid
is not None:
1518 # Replace GUID with module name
1520 GuidString
= MatchGuid
.group()
1521 if GuidString
.upper() in ModuleList
:
1522 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1523 MapBuffer
.append(Line
)
1525 # Add the debug image full path.
1527 MatchGuid
= GuidName
.match(Line
)
1528 if MatchGuid
is not None:
1529 GuidString
= MatchGuid
.group().split("=")[1]
1530 if GuidString
.upper() in ModuleList
:
1531 MapBuffer
.append('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1535 ## Collect MAP information of all modules
1537 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1538 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1540 PatchEfiImageList
= []
1548 # reserve 4K size in SMRAM to make SMM module address not from 0.
1550 for ModuleGuid
in ModuleList
:
1551 Module
= ModuleList
[ModuleGuid
]
1552 GlobalData
.gProcessingFile
= "%s [%s, %s, %s]" % (Module
.MetaFile
, Module
.Arch
, Module
.ToolChain
, Module
.BuildTarget
)
1554 OutputImageFile
= ''
1555 for ResultFile
in Module
.CodaTargetList
:
1556 if str(ResultFile
.Target
).endswith('.efi'):
1558 # module list for PEI, DXE, RUNTIME and SMM
1560 OutputImageFile
= os
.path
.join(Module
.OutputDir
, Module
.Name
+ '.efi')
1561 ImageClass
= PeImageClass (OutputImageFile
)
1562 if not ImageClass
.IsValid
:
1563 EdkLogger
.error("build", FILE_PARSE_FAILURE
, ExtraData
=ImageClass
.ErrorInfo
)
1564 ImageInfo
= PeImageInfo(Module
.Name
, Module
.Guid
, Module
.Arch
, Module
.OutputDir
, Module
.DebugDir
, ImageClass
)
1565 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
]:
1566 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1567 PeiSize
+= ImageInfo
.Image
.Size
1568 elif Module
.ModuleType
in [EDK_COMPONENT_TYPE_BS_DRIVER
, SUP_MODULE_DXE_DRIVER
, SUP_MODULE_UEFI_DRIVER
]:
1569 BtModuleList
[Module
.MetaFile
] = ImageInfo
1570 BtSize
+= ImageInfo
.Image
.Size
1571 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
]:
1572 RtModuleList
[Module
.MetaFile
] = ImageInfo
1573 RtSize
+= ImageInfo
.Image
.Size
1574 elif Module
.ModuleType
in [SUP_MODULE_SMM_CORE
, SUP_MODULE_DXE_SMM_DRIVER
, SUP_MODULE_MM_STANDALONE
, SUP_MODULE_MM_CORE_STANDALONE
]:
1575 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1576 SmmSize
+= ImageInfo
.Image
.Size
1577 if Module
.ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
1578 PiSpecVersion
= Module
.Module
.Specification
.get('PI_SPECIFICATION_VERSION', '0x00000000')
1579 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1580 if int(PiSpecVersion
, 16) < 0x0001000A:
1581 BtModuleList
[Module
.MetaFile
] = ImageInfo
1582 BtSize
+= ImageInfo
.Image
.Size
1585 # EFI image is final target.
1586 # Check EFI image contains patchable FixAddress related PCDs.
1588 if OutputImageFile
!= '':
1589 ModuleIsPatch
= False
1590 for Pcd
in Module
.ModulePcdList
:
1591 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1592 ModuleIsPatch
= True
1594 if not ModuleIsPatch
:
1595 for Pcd
in Module
.LibraryPcdList
:
1596 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1597 ModuleIsPatch
= True
1600 if not ModuleIsPatch
:
1603 # Module includes the patchable load fix address PCDs.
1604 # It will be fixed up later.
1606 PatchEfiImageList
.append (OutputImageFile
)
1609 # Get Top Memory address
1611 ReservedRuntimeMemorySize
= 0
1612 TopMemoryAddress
= 0
1613 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1614 TopMemoryAddress
= 0
1616 TopMemoryAddress
= self
.LoadFixAddress
1617 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1618 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1621 # Patch FixAddress related PCDs into EFI image
1623 for EfiImage
in PatchEfiImageList
:
1624 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1625 if not os
.path
.exists(EfiImageMap
):
1628 # Get PCD offset in EFI image by GenPatchPcdTable function
1630 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1632 # Patch real PCD value by PatchPcdValue tool
1634 for PcdInfo
in PcdTable
:
1636 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1637 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
// 0x1000))
1638 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1639 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
// 0x1000))
1640 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1641 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
// 0x1000))
1642 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1643 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
// 0x1000))
1644 if ReturnValue
!= 0:
1645 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1647 MapBuffer
.append('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
// 0x1000))
1648 MapBuffer
.append('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
// 0x1000))
1649 MapBuffer
.append('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
// 0x1000))
1650 if len (SmmModuleList
) > 0:
1651 MapBuffer
.append('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
// 0x1000))
1653 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1654 BtBaseAddr
= TopMemoryAddress
- RtSize
1655 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1657 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1658 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1659 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1660 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
=False, ModeIsSmm
=True)
1661 MapBuffer
.append('\n\n')
1662 sys
.stdout
.write ("\n")
1665 ## Save platform Map file
1667 def _SaveMapFile (self
, MapBuffer
, Wa
):
1669 # Map file path is got.
1671 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1673 # Save address map into MAP file.
1675 SaveFileOnChange(MapFilePath
, ''.join(MapBuffer
), False)
1676 if self
.LoadFixAddress
!= 0:
1677 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath
))
1680 ## Build active platform for different build targets and different tool chains
1682 def _BuildPlatform(self
):
1683 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1684 for BuildTarget
in self
.BuildTargetList
:
1685 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1687 for ToolChain
in self
.ToolChainList
:
1688 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1689 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1690 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1692 Wa
= WorkspaceAutoGen(
1709 self
.Fdf
= Wa
.FdfFile
1710 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1711 self
.BuildReport
.AddPlatformReport(Wa
)
1712 self
.Progress
.Stop("done!")
1714 # Add ffs build to makefile
1716 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1717 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1719 for Arch
in Wa
.ArchList
:
1720 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1721 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1722 for Module
in Pa
.Platform
.Modules
:
1723 # Get ModuleAutoGen object to generate C code file and makefile
1724 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1727 self
.BuildModules
.append(Ma
)
1728 self
._BuildPa
(self
.Target
, Pa
, FfsCommand
=CmdListDict
)
1730 # Create MAP file when Load Fix Address is enabled.
1731 if self
.Target
in ["", "all", "fds"]:
1732 for Arch
in Wa
.ArchList
:
1733 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1735 # Check whether the set fix address is above 4G for 32bit image.
1737 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1738 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")
1743 for Pa
in Wa
.AutoGenObjectList
:
1744 for Ma
in Pa
.ModuleAutoGenList
:
1747 if not Ma
.IsLibrary
:
1748 ModuleList
[Ma
.Guid
.upper()] = Ma
1751 if self
.LoadFixAddress
!= 0:
1753 # Rebase module to the preferred memory address before GenFds
1755 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1758 # create FDS again for the updated EFI image
1760 self
._Build
("fds", Wa
)
1762 # Create MAP file for all platform FVs after GenFds.
1764 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1766 # Save MAP buffer into MAP file.
1768 self
._SaveMapFile
(MapBuffer
, Wa
)
1770 ## Build active module for different build targets, different tool chains and different archs
1772 def _BuildModule(self
):
1773 for BuildTarget
in self
.BuildTargetList
:
1774 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1776 for ToolChain
in self
.ToolChainList
:
1777 WorkspaceAutoGenTime
= time
.time()
1778 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1779 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1780 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1783 # module build needs platform build information, so get platform
1786 Wa
= WorkspaceAutoGen(
1804 self
.Fdf
= Wa
.FdfFile
1805 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1806 Wa
.CreateMakeFile(False)
1807 # Add ffs build to makefile
1809 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1810 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1811 self
.Progress
.Stop("done!")
1813 ExitFlag
= threading
.Event()
1815 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1816 for Arch
in Wa
.ArchList
:
1817 AutoGenStart
= time
.time()
1818 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1819 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1820 for Module
in Pa
.Platform
.Modules
:
1821 if self
.ModuleFile
.Dir
== Module
.Dir
and self
.ModuleFile
.Name
== Module
.Name
:
1822 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1826 if Ma
.CanSkipbyHash():
1827 self
.HashSkipModules
.append(Ma
)
1828 if GlobalData
.gBinCacheSource
:
1829 EdkLogger
.quiet("cache hit: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1832 if GlobalData
.gBinCacheSource
:
1833 EdkLogger
.quiet("cache miss: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1834 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1835 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1836 # for target which must generate AutoGen code and makefile
1837 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1838 self
.Progress
.Start("Generating code")
1839 Ma
.CreateCodeFile(True)
1840 self
.Progress
.Stop("done!")
1841 if self
.Target
== "genc":
1843 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1844 self
.Progress
.Start("Generating makefile")
1845 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
1846 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
1847 del CmdListDict
[Module
.File
, Arch
]
1849 Ma
.CreateMakeFile(True)
1850 self
.Progress
.Stop("done!")
1851 if self
.Target
== "genmake":
1853 self
.BuildModules
.append(Ma
)
1854 # Initialize all modules in tracking to 'FAIL'
1855 if Ma
.Arch
not in GlobalData
.gModuleBuildTracking
:
1856 GlobalData
.gModuleBuildTracking
[Ma
.Arch
] = dict()
1857 if Ma
not in GlobalData
.gModuleBuildTracking
[Ma
.Arch
]:
1858 GlobalData
.gModuleBuildTracking
[Ma
.Arch
][Ma
] = 'FAIL'
1859 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1860 MakeStart
= time
.time()
1861 for Ma
in self
.BuildModules
:
1862 if not Ma
.IsBinaryModule
:
1863 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
1864 # Break build if any build thread has error
1865 if BuildTask
.HasError():
1866 # we need a full version of makefile for platform
1868 BuildTask
.WaitForComplete()
1869 self
.invalidateHash()
1870 Pa
.CreateMakeFile(False)
1871 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1872 # Start task scheduler
1873 if not BuildTask
.IsOnGoing():
1874 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1876 # in case there's an interruption. we need a full version of makefile for platform
1877 Pa
.CreateMakeFile(False)
1878 if BuildTask
.HasError():
1879 self
.invalidateHash()
1880 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1881 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1883 MakeContiue
= time
.time()
1885 BuildTask
.WaitForComplete()
1886 self
.CreateAsBuiltInf()
1887 if GlobalData
.gBinCacheDest
:
1888 self
.UpdateBuildCache()
1889 self
.BuildModules
= []
1890 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1891 if BuildTask
.HasError():
1892 self
.invalidateHash()
1893 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1895 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1900 "Module for [%s] is not a component of active platform."\
1901 " Please make sure that the ARCH and inf file path are"\
1902 " given in the same as in [%s]" % \
1903 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1904 ExtraData
=self
.ModuleFile
1906 # Create MAP file when Load Fix Address is enabled.
1907 if self
.Target
== "fds" and self
.Fdf
:
1908 for Arch
in Wa
.ArchList
:
1910 # Check whether the set fix address is above 4G for 32bit image.
1912 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1913 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")
1918 for Pa
in Wa
.AutoGenObjectList
:
1919 for Ma
in Pa
.ModuleAutoGenList
:
1922 if not Ma
.IsLibrary
:
1923 ModuleList
[Ma
.Guid
.upper()] = Ma
1926 if self
.LoadFixAddress
!= 0:
1928 # Rebase module to the preferred memory address before GenFds
1930 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1932 # create FDS again for the updated EFI image
1934 GenFdsStart
= time
.time()
1935 self
._Build
("fds", Wa
)
1936 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
1938 # Create MAP file for all platform FVs after GenFds.
1940 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1942 # Save MAP buffer into MAP file.
1944 self
._SaveMapFile
(MapBuffer
, Wa
)
1945 self
.invalidateHash()
1947 def _GenFfsCmd(self
,ArchList
):
1948 # convert dictionary of Cmd:(Inf,Arch)
1949 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
1950 CmdSetDict
= defaultdict(set)
1951 GenFfsDict
= GenFds
.GenFfsMakefile('', GlobalData
.gFdfParser
, self
, ArchList
, GlobalData
)
1952 for Cmd
in GenFfsDict
:
1953 tmpInf
, tmpArch
= GenFfsDict
[Cmd
]
1954 CmdSetDict
[tmpInf
, tmpArch
].add(Cmd
)
1957 ## Build a platform in multi-thread mode
1959 def _MultiThreadBuildPlatform(self
):
1960 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1961 for BuildTarget
in self
.BuildTargetList
:
1962 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1964 for ToolChain
in self
.ToolChainList
:
1965 WorkspaceAutoGenTime
= time
.time()
1966 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1967 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1968 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1970 Wa
= WorkspaceAutoGen(
1987 self
.Fdf
= Wa
.FdfFile
1988 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1989 self
.BuildReport
.AddPlatformReport(Wa
)
1990 Wa
.CreateMakeFile(False)
1992 # Add ffs build to makefile
1994 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1995 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1997 # multi-thread exit flag
1998 ExitFlag
= threading
.Event()
2000 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
2001 for Arch
in Wa
.ArchList
:
2002 AutoGenStart
= time
.time()
2003 GlobalData
.gGlobalDefines
['ARCH'] = Arch
2004 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
2008 for Inf
in Pa
.Platform
.Modules
:
2009 ModuleList
.append(Inf
)
2010 # Add the INF only list in FDF
2011 if GlobalData
.gFdfParser
is not None:
2012 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
2013 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
2014 if Inf
in Pa
.Platform
.Modules
:
2016 ModuleList
.append(Inf
)
2017 for Module
in ModuleList
:
2018 # Get ModuleAutoGen object to generate C code file and makefile
2019 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
2023 if Ma
.CanSkipbyHash():
2024 self
.HashSkipModules
.append(Ma
)
2025 if GlobalData
.gBinCacheSource
:
2026 EdkLogger
.quiet("cache hit: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
2029 if GlobalData
.gBinCacheSource
:
2030 EdkLogger
.quiet("cache miss: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
2032 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
2033 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
2034 # for target which must generate AutoGen code and makefile
2035 if not self
.SkipAutoGen
or self
.Target
== 'genc':
2036 Ma
.CreateCodeFile(True)
2037 if self
.Target
== "genc":
2040 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
2041 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
2042 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
2043 del CmdListDict
[Module
.File
, Arch
]
2045 Ma
.CreateMakeFile(True)
2046 if self
.Target
== "genmake":
2048 self
.BuildModules
.append(Ma
)
2049 # Initialize all modules in tracking to 'FAIL'
2050 if Ma
.Arch
not in GlobalData
.gModuleBuildTracking
:
2051 GlobalData
.gModuleBuildTracking
[Ma
.Arch
] = dict()
2052 if Ma
not in GlobalData
.gModuleBuildTracking
[Ma
.Arch
]:
2053 GlobalData
.gModuleBuildTracking
[Ma
.Arch
][Ma
] = 'FAIL'
2054 self
.Progress
.Stop("done!")
2055 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
2056 MakeStart
= time
.time()
2057 for Ma
in self
.BuildModules
:
2058 # Generate build task for the module
2059 if not Ma
.IsBinaryModule
:
2060 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
2061 # Break build if any build thread has error
2062 if BuildTask
.HasError():
2063 # we need a full version of makefile for platform
2065 BuildTask
.WaitForComplete()
2066 self
.invalidateHash()
2067 Pa
.CreateMakeFile(False)
2068 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2069 # Start task scheduler
2070 if not BuildTask
.IsOnGoing():
2071 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
2073 # in case there's an interruption. we need a full version of makefile for platform
2074 Pa
.CreateMakeFile(False)
2075 if BuildTask
.HasError():
2076 self
.invalidateHash()
2077 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2078 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
2080 MakeContiue
= time
.time()
2084 # All modules have been put in build tasks queue. Tell task scheduler
2085 # to exit if all tasks are completed
2088 BuildTask
.WaitForComplete()
2089 self
.CreateAsBuiltInf()
2090 if GlobalData
.gBinCacheDest
:
2091 self
.UpdateBuildCache()
2092 self
.BuildModules
= []
2093 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2095 # Check for build error, and raise exception if one
2096 # has been signaled.
2098 if BuildTask
.HasError():
2099 self
.invalidateHash()
2100 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2102 # Create MAP file when Load Fix Address is enabled.
2103 if self
.Target
in ["", "all", "fds"]:
2104 for Arch
in Wa
.ArchList
:
2106 # Check whether the set fix address is above 4G for 32bit image.
2108 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2109 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")
2114 for Pa
in Wa
.AutoGenObjectList
:
2115 for Ma
in Pa
.ModuleAutoGenList
:
2118 if not Ma
.IsLibrary
:
2119 ModuleList
[Ma
.Guid
.upper()] = Ma
2121 # Rebase module to the preferred memory address before GenFds
2124 if self
.LoadFixAddress
!= 0:
2125 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2129 # Generate FD image if there's a FDF file found
2131 GenFdsStart
= time
.time()
2132 if GenFdsApi(Wa
.GenFdsCommandDict
, self
.Db
):
2133 EdkLogger
.error("build", COMMAND_FAILURE
)
2136 # Create MAP file for all platform FVs after GenFds.
2138 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2139 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2141 # Save MAP buffer into MAP file.
2143 self
._SaveMapFile
(MapBuffer
, Wa
)
2144 self
.invalidateHash()
2146 ## Generate GuidedSectionTools.txt in the FV directories.
2148 def CreateGuidedSectionToolsFile(self
):
2149 for BuildTarget
in self
.BuildTargetList
:
2150 for ToolChain
in self
.ToolChainList
:
2151 Wa
= WorkspaceAutoGen(
2168 if not os
.path
.exists(FvDir
):
2171 for Arch
in self
.ArchList
:
2172 # Build up the list of supported architectures for this build
2173 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
2175 # Look through the tool definitions for GUIDed tools
2177 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.items():
2178 if attrib
.upper().endswith('_GUID'):
2179 split
= attrib
.split('_')
2180 thisPrefix
= '_'.join(split
[0:3]) + '_'
2181 if thisPrefix
== prefix
:
2182 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
2185 path
= '_'.join(split
[0:4]) + '_PATH'
2186 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2187 path
= self
.GetFullPathOfTool(path
)
2188 guidAttribs
.append((guid
, toolName
, path
))
2190 # Write out GuidedSecTools.txt
2191 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2192 toolsFile
= open(toolsFile
, 'wt')
2193 for guidedSectionTool
in guidAttribs
:
2194 print(' '.join(guidedSectionTool
), file=toolsFile
)
2197 ## Returns the full path of the tool.
2199 def GetFullPathOfTool (self
, tool
):
2200 if os
.path
.exists(tool
):
2201 return os
.path
.realpath(tool
)
2203 # We need to search for the tool using the
2204 # PATH environment variable.
2205 for dirInPath
in os
.environ
['PATH'].split(os
.pathsep
):
2206 foundPath
= os
.path
.join(dirInPath
, tool
)
2207 if os
.path
.exists(foundPath
):
2208 return os
.path
.realpath(foundPath
)
2210 # If the tool was not found in the path then we just return
2214 ## Launch the module or platform build
2217 if not self
.ModuleFile
:
2218 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2219 self
.SpawnMode
= False
2220 self
._BuildPlatform
()
2222 self
._MultiThreadBuildPlatform
()
2223 self
.CreateGuidedSectionToolsFile()
2225 self
.SpawnMode
= False
2228 if self
.Target
== 'cleanall':
2229 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2231 def CreateAsBuiltInf(self
):
2232 for Module
in self
.BuildModules
:
2233 Module
.CreateAsBuiltInf()
2235 def UpdateBuildCache(self
):
2238 for Module
in self
.BuildModules
:
2239 Module
.CopyModuleToCache()
2240 all_mod_set
.add(Module
)
2241 for Module
in self
.HashSkipModules
:
2242 Module
.CopyModuleToCache()
2243 all_mod_set
.add(Module
)
2244 for Module
in all_mod_set
:
2245 for lib
in Module
.LibraryAutoGenList
:
2246 all_lib_set
.add(lib
)
2247 for lib
in all_lib_set
:
2248 lib
.CopyModuleToCache()
2251 self
.HashSkipModules
= []
2252 ## Do some clean-up works when error occurred
2253 def Relinquish(self
):
2254 OldLogLevel
= EdkLogger
.GetLevel()
2255 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2256 Utils
.Progressor
.Abort()
2257 if self
.SpawnMode
== True:
2259 EdkLogger
.SetLevel(OldLogLevel
)
2261 def ParseDefines(DefineList
=[]):
2263 if DefineList
is not None:
2264 for Define
in DefineList
:
2265 DefineTokenList
= Define
.split("=", 1)
2266 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2267 EdkLogger
.error('build', FORMAT_INVALID
,
2268 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2269 ExtraData
=DefineTokenList
[0])
2271 if len(DefineTokenList
) == 1:
2272 DefineDict
[DefineTokenList
[0]] = "TRUE"
2274 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2278 def SingleCheckCallback(option
, opt_str
, value
, parser
):
2279 if option
not in gParamCheck
:
2280 setattr(parser
.values
, option
.dest
, value
)
2281 gParamCheck
.append(option
)
2283 parser
.error("Option %s only allows one instance in command line!" % option
)
2285 def LogBuildTime(Time
):
2288 TimeDur
= time
.gmtime(Time
)
2289 if TimeDur
.tm_yday
> 1:
2290 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2292 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2297 ## Parse command line options
2299 # Using standard Python module optparse to parse command line option of this tool.
2301 # @retval Opt A optparse.Values object containing the parsed options
2302 # @retval Args Target of build command
2304 def MyOptionParser():
2305 Parser
= OptionParser(description
=__copyright__
, version
=__version__
, prog
="build.exe", usage
="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
2306 Parser
.add_option("-a", "--arch", action
="append", type="choice", choices
=['IA32', 'X64', 'EBC', 'ARM', 'AARCH64'], dest
="TargetArch",
2307 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.")
2308 Parser
.add_option("-p", "--platform", action
="callback", type="string", dest
="PlatformFile", callback
=SingleCheckCallback
,
2309 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
2310 Parser
.add_option("-m", "--module", action
="callback", type="string", dest
="ModuleFile", callback
=SingleCheckCallback
,
2311 help="Build the module specified by the INF file name argument.")
2312 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
2314 Parser
.add_option("-t", "--tagname", action
="append", type="string", dest
="ToolChain",
2315 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
2316 Parser
.add_option("-x", "--sku-id", action
="callback", type="string", dest
="SkuId", callback
=SingleCheckCallback
,
2317 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
2319 Parser
.add_option("-n", action
="callback", type="int", dest
="ThreadNumber", callback
=SingleCheckCallback
,
2320 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 "\
2321 "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.")
2323 Parser
.add_option("-f", "--fdf", action
="callback", type="string", dest
="FdfFile", callback
=SingleCheckCallback
,
2324 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
2325 Parser
.add_option("-r", "--rom-image", action
="append", type="string", dest
="RomImage", default
=[],
2326 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
2327 Parser
.add_option("-i", "--fv-image", action
="append", type="string", dest
="FvImage", default
=[],
2328 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
2329 Parser
.add_option("-C", "--capsule-image", action
="append", type="string", dest
="CapName", default
=[],
2330 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
2331 Parser
.add_option("-u", "--skip-autogen", action
="store_true", dest
="SkipAutoGen", help="Skip AutoGen step.")
2332 Parser
.add_option("-e", "--re-parse", action
="store_true", dest
="Reparse", help="Re-parse all meta-data files.")
2334 Parser
.add_option("-c", "--case-insensitive", action
="store_true", dest
="CaseInsensitive", default
=False, help="Don't check case of file name.")
2336 Parser
.add_option("-w", "--warning-as-error", action
="store_true", dest
="WarningAsError", help="Treat warning in tools as error.")
2337 Parser
.add_option("-j", "--log", action
="store", dest
="LogFile", help="Put log in specified file as well as on console.")
2339 Parser
.add_option("-s", "--silent", action
="store_true", type=None, dest
="SilentMode",
2340 help="Make use of silent mode of (n)make.")
2341 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
2342 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
2343 "including library instances selected, final dependency expression, "\
2344 "and warning messages, etc.")
2345 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
2346 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
2348 Parser
.add_option("-y", "--report-file", action
="store", dest
="ReportFile", help="Create/overwrite the report to the specified filename.")
2349 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
=[],
2350 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]. "\
2351 "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]")
2352 Parser
.add_option("-F", "--flag", action
="store", type="string", dest
="Flag",
2353 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. "\
2354 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
2355 "will override the setting in [BuildOptions] section of platform DSC.")
2356 Parser
.add_option("-N", "--no-cache", action
="store_true", dest
="DisableCache", default
=False, help="Disable build cache mechanism")
2357 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
2358 Parser
.add_option("--check-usage", action
="store_true", dest
="CheckUsage", default
=False, help="Check usage content of entries listed in INF file.")
2359 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
2360 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
2361 Parser
.add_option("-l", "--cmd-len", action
="store", type="int", dest
="CommandLength", help="Specify the maximum line length of build command. Default is 4096.")
2362 Parser
.add_option("--hash", action
="store_true", dest
="UseHashCache", default
=False, help="Enable hash-based caching during build process.")
2363 Parser
.add_option("--binary-destination", action
="store", type="string", dest
="BinCacheDest", help="Generate a cache of binary files in the specified directory.")
2364 Parser
.add_option("--binary-source", action
="store", type="string", dest
="BinCacheSource", help="Consume a cache of binary files from the specified directory.")
2365 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
2366 Parser
.add_option("--disable-include-path-check", action
="store_true", dest
="DisableIncludePathCheck", default
=False, help="Disable the include path check for outside of package.")
2367 (Opt
, Args
) = Parser
.parse_args()
2370 ## Tool entrance method
2372 # This method mainly dispatch specific methods per the command line options.
2373 # If no error found, return zero value so the caller of this tool can know
2374 # if it's executed successfully or not.
2376 # @retval 0 Tool was successful
2377 # @retval 1 Tool failed
2380 StartTime
= time
.time()
2382 # Initialize log system
2383 EdkLogger
.Initialize()
2384 GlobalData
.gCommand
= sys
.argv
[1:]
2386 # Parse the options and args
2388 (Option
, Target
) = MyOptionParser()
2389 GlobalData
.gOptions
= Option
2390 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2393 if Option
.verbose
is not None:
2394 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2395 elif Option
.quiet
is not None:
2396 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2397 elif Option
.debug
is not None:
2398 EdkLogger
.SetLevel(Option
.debug
+ 1)
2400 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2402 if Option
.LogFile
is not None:
2403 EdkLogger
.SetLogFile(Option
.LogFile
)
2405 if Option
.WarningAsError
== True:
2406 EdkLogger
.SetWarningAsError()
2408 if platform
.platform().find("Windows") >= 0:
2409 GlobalData
.gIsWindows
= True
2411 GlobalData
.gIsWindows
= False
2413 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2414 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2419 if len(Target
) == 0:
2421 elif len(Target
) >= 2:
2422 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2423 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2425 Target
= Target
[0].lower()
2427 if Target
not in gSupportedTarget
:
2428 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2429 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2432 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2435 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2437 Workspace
= os
.getenv("WORKSPACE")
2439 # Get files real name in workspace dir
2441 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2443 WorkingDirectory
= os
.getcwd()
2444 if not Option
.ModuleFile
:
2445 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2446 FileNum
= len(FileList
)
2448 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2449 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2451 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2453 if Option
.ModuleFile
:
2454 if os
.path
.isabs (Option
.ModuleFile
):
2455 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2456 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2457 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2458 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2460 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2462 if Option
.PlatformFile
is not None:
2463 if os
.path
.isabs (Option
.PlatformFile
):
2464 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2465 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2466 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2468 if Option
.FdfFile
is not None:
2469 if os
.path
.isabs (Option
.FdfFile
):
2470 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2471 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2472 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2473 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2475 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2477 if Option
.Flag
is not None and Option
.Flag
not in ['-c', '-s']:
2478 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2480 MyBuild
= Build(Target
, Workspace
, Option
)
2481 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2482 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2486 # All job done, no error found and no exception raised
2489 except FatalError
as X
:
2490 if MyBuild
is not None:
2491 # for multi-thread build exits safely
2492 MyBuild
.Relinquish()
2493 if Option
is not None and Option
.debug
is not None:
2494 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2495 ReturnCode
= X
.args
[0]
2496 except Warning as X
:
2497 # error from Fdf parser
2498 if MyBuild
is not None:
2499 # for multi-thread build exits safely
2500 MyBuild
.Relinquish()
2501 if Option
is not None and Option
.debug
is not None:
2502 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2504 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2505 ReturnCode
= FORMAT_INVALID
2506 except KeyboardInterrupt:
2507 ReturnCode
= ABORT_ERROR
2508 if Option
is not None and Option
.debug
is not None:
2509 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2511 if MyBuild
is not None:
2512 # for multi-thread build exits safely
2513 MyBuild
.Relinquish()
2515 # try to get the meta-file from the object causing exception
2516 Tb
= sys
.exc_info()[-1]
2517 MetaFile
= GlobalData
.gProcessingFile
2518 while Tb
is not None:
2519 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2520 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2525 "Unknown fatal error when processing [%s]" % MetaFile
,
2526 ExtraData
="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR
,
2529 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2530 ReturnCode
= CODE_ERROR
2532 Utils
.Progressor
.Abort()
2533 Utils
.ClearDuplicatedInf()
2537 MyBuild
.LaunchPostbuild()
2540 Conclusion
= "Failed"
2541 elif ReturnCode
== ABORT_ERROR
:
2542 Conclusion
= "Aborted"
2544 Conclusion
= "Failed"
2545 FinishTime
= time
.time()
2546 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2547 BuildDurationStr
= ""
2548 if BuildDuration
.tm_yday
> 1:
2549 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2551 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2552 if MyBuild
is not None:
2554 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2556 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2557 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2558 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2559 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2562 if __name__
== '__main__':
2564 ## 0-127 is a safe return range, and 1 is a standard default error
2565 if r
< 0 or r
> 127: r
= 1