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 from __future__
import absolute_import
16 import os
.path
as path
24 import multiprocessing
25 from threading
import Thread
,Event
,BoundedSemaphore
27 from subprocess
import Popen
,PIPE
28 from collections
import OrderedDict
, defaultdict
29 from optparse
import OptionParser
30 from AutoGen
.PlatformAutoGen
import PlatformAutoGen
31 from AutoGen
.ModuleAutoGen
import ModuleAutoGen
32 from AutoGen
.WorkspaceAutoGen
import WorkspaceAutoGen
33 from AutoGen
import GenMake
34 from Common
import Misc
as Utils
36 from Common
.TargetTxtClassObject
import TargetTxt
37 from Common
.ToolDefClassObject
import ToolDef
38 from Common
.Misc
import PathClass
,SaveFileOnChange
,RemoveDirectory
39 from Common
.StringUtils
import NormPath
40 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
41 from Common
.BuildToolError
import *
42 from Common
.DataType
import *
43 import Common
.EdkLogger
as EdkLogger
44 from Common
.BuildVersion
import gBUILD_VERSION
45 from Workspace
.WorkspaceDatabase
import BuildDB
47 from BuildReport
import BuildReport
48 from GenPatchPcdTable
.GenPatchPcdTable
import PeImageClass
,parsePcdInfoFromMapFile
49 from PatchPcdValue
.PatchPcdValue
import PatchBinaryFile
51 import Common
.GlobalData
as GlobalData
52 from GenFds
.GenFds
import GenFds
, GenFdsApi
55 # Version and Copyright
56 VersionNumber
= "0.60" + ' ' + gBUILD_VERSION
57 __version__
= "%prog Version " + VersionNumber
58 __copyright__
= "Copyright (c) 2007 - 2018, Intel Corporation All rights reserved."
60 ## standard targets of build command
61 gSupportedTarget
= ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
63 ## build configuration file
64 gBuildConfiguration
= "target.txt"
65 gToolsDefinition
= "tools_def.txt"
67 TemporaryTablePattern
= re
.compile(r
'^_\d+_\d+_[a-fA-F0-9]+$')
70 ## Check environment PATH variable to make sure the specified tool is found
72 # If the tool is found in the PATH, then True is returned
73 # Otherwise, False is returned
75 def IsToolInPath(tool
):
76 if 'PATHEXT' in os
.environ
:
77 extns
= os
.environ
['PATHEXT'].split(os
.path
.pathsep
)
80 for pathDir
in os
.environ
['PATH'].split(os
.path
.pathsep
):
82 if os
.path
.exists(os
.path
.join(pathDir
, tool
+ ext
)):
86 ## Check environment variables
88 # Check environment variables that must be set for build. Currently they are
90 # WORKSPACE The directory all packages/platforms start from
91 # EDK_TOOLS_PATH The directory contains all tools needed by the build
92 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
94 # If any of above environment variable is not set or has error, the build
97 def CheckEnvVariable():
99 if "WORKSPACE" not in os
.environ
:
100 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
101 ExtraData
="WORKSPACE")
103 WorkspaceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["WORKSPACE"]))
104 if not os
.path
.exists(WorkspaceDir
):
105 EdkLogger
.error("build", FILE_NOT_FOUND
, "WORKSPACE doesn't exist", ExtraData
=WorkspaceDir
)
106 elif ' ' in WorkspaceDir
:
107 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in WORKSPACE path",
108 ExtraData
=WorkspaceDir
)
109 os
.environ
["WORKSPACE"] = WorkspaceDir
111 # set multiple workspace
112 PackagesPath
= os
.getenv("PACKAGES_PATH")
113 mws
.setWs(WorkspaceDir
, PackagesPath
)
114 if mws
.PACKAGES_PATH
:
115 for Path
in mws
.PACKAGES_PATH
:
116 if not os
.path
.exists(Path
):
117 EdkLogger
.error("build", FILE_NOT_FOUND
, "One Path in PACKAGES_PATH doesn't exist", ExtraData
=Path
)
119 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in PACKAGES_PATH", ExtraData
=Path
)
122 os
.environ
["EDK_TOOLS_PATH"] = os
.path
.normcase(os
.environ
["EDK_TOOLS_PATH"])
124 # check EDK_TOOLS_PATH
125 if "EDK_TOOLS_PATH" not in os
.environ
:
126 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
127 ExtraData
="EDK_TOOLS_PATH")
130 if "PATH" not in os
.environ
:
131 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
134 GlobalData
.gWorkspace
= WorkspaceDir
136 GlobalData
.gGlobalDefines
["WORKSPACE"] = WorkspaceDir
137 GlobalData
.gGlobalDefines
["EDK_TOOLS_PATH"] = os
.environ
["EDK_TOOLS_PATH"]
139 ## Get normalized file path
141 # Convert the path to be local format, and remove the WORKSPACE path at the
142 # beginning if the file path is given in full path.
144 # @param FilePath File path to be normalized
145 # @param Workspace Workspace path which the FilePath will be checked against
147 # @retval string The normalized file path
149 def NormFile(FilePath
, Workspace
):
150 # check if the path is absolute or relative
151 if os
.path
.isabs(FilePath
):
152 FileFullPath
= os
.path
.normpath(FilePath
)
154 FileFullPath
= os
.path
.normpath(mws
.join(Workspace
, FilePath
))
155 Workspace
= mws
.getWs(Workspace
, FilePath
)
157 # check if the file path exists or not
158 if not os
.path
.isfile(FileFullPath
):
159 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath
)
161 # remove workspace directory from the beginning part of the file path
162 if Workspace
[-1] in ["\\", "/"]:
163 return FileFullPath
[len(Workspace
):]
165 return FileFullPath
[(len(Workspace
) + 1):]
167 ## Get the output of an external program
169 # This is the entrance method of thread reading output of an external program and
170 # putting them in STDOUT/STDERR of current program.
172 # @param From The stream message read from
173 # @param To The stream message put on
174 # @param ExitFlag The flag used to indicate stopping reading
176 def ReadMessage(From
, To
, ExitFlag
):
178 # read one line a time
179 Line
= From
.readline()
180 # empty string means "end"
181 if Line
is not None and Line
!= b
"":
182 To(Line
.rstrip().decode(encoding
='utf-8', errors
='ignore'))
188 ## Launch an external program
190 # This method will call subprocess.Popen to execute an external program with
191 # given options in specified directory. Because of the dead-lock issue during
192 # redirecting output of the external program, threads are used to to do the
195 # @param Command A list or string containing the call of the program
196 # @param WorkingDir The directory in which the program will be running
198 def LaunchCommand(Command
, WorkingDir
):
199 BeginTime
= time
.time()
200 # if working directory doesn't exist, Popen() will raise an exception
201 if not os
.path
.isdir(WorkingDir
):
202 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=WorkingDir
)
204 # Command is used as the first Argument in following Popen().
205 # It could be a string or sequence. We find that if command is a string in following Popen(),
206 # ubuntu may fail with an error message that the command is not found.
207 # So here we may need convert command from string to list instance.
208 if platform
.system() != 'Windows':
209 if not isinstance(Command
, list):
210 Command
= Command
.split()
211 Command
= ' '.join(Command
)
214 EndOfProcedure
= None
217 Proc
= Popen(Command
, stdout
=PIPE
, stderr
=PIPE
, env
=os
.environ
, cwd
=WorkingDir
, bufsize
=-1, shell
=True)
219 # launch two threads to read the STDOUT and STDERR
220 EndOfProcedure
= Event()
221 EndOfProcedure
.clear()
223 StdOutThread
= Thread(target
=ReadMessage
, args
=(Proc
.stdout
, EdkLogger
.info
, EndOfProcedure
))
224 StdOutThread
.setName("STDOUT-Redirector")
225 StdOutThread
.setDaemon(False)
229 StdErrThread
= Thread(target
=ReadMessage
, args
=(Proc
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
230 StdErrThread
.setName("STDERR-Redirector")
231 StdErrThread
.setDaemon(False)
234 # waiting for program exit
236 except: # in case of aborting
237 # terminate the threads redirecting the program output
238 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
239 if EndOfProcedure
is not None:
242 if not isinstance(Command
, type("")):
243 Command
= " ".join(Command
)
244 EdkLogger
.error("build", COMMAND_FAILURE
, "Failed to start command", ExtraData
="%s [%s]" % (Command
, WorkingDir
))
251 # check the return code of the program
252 if Proc
.returncode
!= 0:
253 if not isinstance(Command
, type("")):
254 Command
= " ".join(Command
)
255 # print out the Response file and its content when make failure
256 RespFile
= os
.path
.join(WorkingDir
, 'OUTPUT', 'respfilelist.txt')
257 if os
.path
.isfile(RespFile
):
259 RespContent
= f
.read()
261 EdkLogger
.info(RespContent
)
263 EdkLogger
.error("build", COMMAND_FAILURE
, ExtraData
="%s [%s]" % (Command
, WorkingDir
))
264 return "%dms" % (int(round((time
.time() - BeginTime
) * 1000)))
266 ## The smallest unit that can be built in multi-thread build mode
268 # This is the base class of build unit. The "Obj" parameter must provide
269 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
272 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
277 # @param self The object pointer
278 # @param Obj The object the build is working on
279 # @param Target The build target name, one of gSupportedTarget
280 # @param Dependency The BuildUnit(s) which must be completed in advance
281 # @param WorkingDir The directory build command starts in
283 def __init__(self
, Obj
, BuildCommand
, Target
, Dependency
, WorkingDir
="."):
284 self
.BuildObject
= Obj
285 self
.Dependency
= Dependency
286 self
.WorkingDir
= WorkingDir
288 self
.BuildCommand
= BuildCommand
290 EdkLogger
.error("build", OPTION_MISSING
,
291 "No build command found for this module. "
292 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
293 (Obj
.BuildTarget
, Obj
.ToolChain
, Obj
.Arch
),
299 # It just returns the string representation of self.BuildObject
301 # @param self The object pointer
304 return str(self
.BuildObject
)
306 ## "==" operator method
308 # It just compares self.BuildObject with "Other". So self.BuildObject must
309 # provide its own __eq__() method.
311 # @param self The object pointer
312 # @param Other The other BuildUnit object compared to
314 def __eq__(self
, Other
):
315 return Other
and self
.BuildObject
== Other
.BuildObject \
316 and Other
.BuildObject \
317 and self
.BuildObject
.Arch
== Other
.BuildObject
.Arch
321 # It just returns the hash value of self.BuildObject which must be hashable.
323 # @param self The object pointer
326 return hash(self
.BuildObject
) + hash(self
.BuildObject
.Arch
)
329 return repr(self
.BuildObject
)
331 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
333 # This class is for module build by nmake/make build system. The "Obj" parameter
334 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
335 # be make units missing build.
337 # Currently the "Obj" should be only ModuleAutoGen object.
339 class ModuleMakeUnit(BuildUnit
):
342 # @param self The object pointer
343 # @param Obj The ModuleAutoGen object the build is working on
344 # @param Target The build target name, one of gSupportedTarget
346 def __init__(self
, Obj
, Target
):
347 Dependency
= [ModuleMakeUnit(La
, Target
) for La
in Obj
.LibraryAutoGenList
]
348 BuildUnit
.__init
__(self
, Obj
, Obj
.BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
349 if Target
in [None, "", "all"]:
350 self
.Target
= "tbuild"
352 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
354 # This class is for platform build by nmake/make build system. The "Obj" parameter
355 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
356 # be make units missing build.
358 # Currently the "Obj" should be only PlatformAutoGen object.
360 class PlatformMakeUnit(BuildUnit
):
363 # @param self The object pointer
364 # @param Obj The PlatformAutoGen object the build is working on
365 # @param Target The build target name, one of gSupportedTarget
367 def __init__(self
, Obj
, Target
):
368 Dependency
= [ModuleMakeUnit(Lib
, Target
) for Lib
in self
.BuildObject
.LibraryAutoGenList
]
369 Dependency
.extend([ModuleMakeUnit(Mod
, Target
) for Mod
in self
.BuildObject
.ModuleAutoGenList
])
370 BuildUnit
.__init
__(self
, Obj
, Obj
.BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
372 ## The class representing the task of a module build or platform build
374 # This class manages the build tasks in multi-thread build mode. Its jobs include
375 # scheduling thread running, catching thread error, monitor the thread status, etc.
378 # queue for tasks waiting for schedule
379 _PendingQueue
= OrderedDict()
380 _PendingQueueLock
= threading
.Lock()
382 # queue for tasks ready for running
383 _ReadyQueue
= OrderedDict()
384 _ReadyQueueLock
= threading
.Lock()
386 # queue for run tasks
387 _RunningQueue
= OrderedDict()
388 _RunningQueueLock
= threading
.Lock()
390 # queue containing all build tasks, in case duplicate build
391 _TaskQueue
= OrderedDict()
393 # flag indicating error occurs in a running thread
394 _ErrorFlag
= threading
.Event()
398 # BoundedSemaphore object used to control the number of running threads
401 # flag indicating if the scheduler is started or not
402 _SchedulerStopped
= threading
.Event()
403 _SchedulerStopped
.set()
405 ## Start the task scheduler thread
407 # @param MaxThreadNumber The maximum thread number
408 # @param ExitFlag Flag used to end the scheduler
411 def StartScheduler(MaxThreadNumber
, ExitFlag
):
412 SchedulerThread
= Thread(target
=BuildTask
.Scheduler
, args
=(MaxThreadNumber
, ExitFlag
))
413 SchedulerThread
.setName("Build-Task-Scheduler")
414 SchedulerThread
.setDaemon(False)
415 SchedulerThread
.start()
416 # wait for the scheduler to be started, especially useful in Linux
417 while not BuildTask
.IsOnGoing():
422 # @param MaxThreadNumber The maximum thread number
423 # @param ExitFlag Flag used to end the scheduler
426 def Scheduler(MaxThreadNumber
, ExitFlag
):
427 BuildTask
._SchedulerStopped
.clear()
429 # use BoundedSemaphore to control the maximum running threads
430 BuildTask
._Thread
= BoundedSemaphore(MaxThreadNumber
)
432 # scheduling loop, which will exits when no pending/ready task and
433 # indicated to do so, or there's error in running thread
435 while (len(BuildTask
._PendingQueue
) > 0 or len(BuildTask
._ReadyQueue
) > 0 \
436 or not ExitFlag
.isSet()) and not BuildTask
._ErrorFlag
.isSet():
437 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Pending Queue (%d), Ready Queue (%d)"
438 % (len(BuildTask
._PendingQueue
), len(BuildTask
._ReadyQueue
)))
440 # get all pending tasks
441 BuildTask
._PendingQueueLock
.acquire()
442 BuildObjectList
= list(BuildTask
._PendingQueue
.keys())
444 # check if their dependency is resolved, and if true, move them
447 for BuildObject
in BuildObjectList
:
448 Bt
= BuildTask
._PendingQueue
[BuildObject
]
450 BuildTask
._ReadyQueue
[BuildObject
] = BuildTask
._PendingQueue
.pop(BuildObject
)
451 BuildTask
._PendingQueueLock
.release()
453 # launch build thread until the maximum number of threads is reached
454 while not BuildTask
._ErrorFlag
.isSet():
455 # empty ready queue, do nothing further
456 if len(BuildTask
._ReadyQueue
) == 0:
459 # wait for active thread(s) exit
460 BuildTask
._Thread
.acquire(True)
462 # start a new build thread
463 Bo
, Bt
= BuildTask
._ReadyQueue
.popitem()
465 # move into running queue
466 BuildTask
._RunningQueueLock
.acquire()
467 BuildTask
._RunningQueue
[Bo
] = Bt
468 BuildTask
._RunningQueueLock
.release()
477 # wait for all running threads exit
478 if BuildTask
._ErrorFlag
.isSet():
479 EdkLogger
.quiet("\nWaiting for all build threads exit...")
480 # while not BuildTask._ErrorFlag.isSet() and \
481 while len(BuildTask
._RunningQueue
) > 0:
482 EdkLogger
.verbose("Waiting for thread ending...(%d)" % len(BuildTask
._RunningQueue
))
483 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Threads [%s]" % ", ".join(Th
.getName() for Th
in threading
.enumerate()))
486 except BaseException
as X
:
488 # TRICK: hide the output of threads left running, so that the user can
489 # catch the error message easily
491 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
492 BuildTask
._ErrorFlag
.set()
493 BuildTask
._ErrorMessage
= "build thread scheduler error\n\t%s" % str(X
)
495 BuildTask
._PendingQueue
.clear()
496 BuildTask
._ReadyQueue
.clear()
497 BuildTask
._RunningQueue
.clear()
498 BuildTask
._TaskQueue
.clear()
499 BuildTask
._SchedulerStopped
.set()
501 ## Wait for all running method exit
504 def WaitForComplete():
505 BuildTask
._SchedulerStopped
.wait()
507 ## Check if the scheduler is running or not
511 return not BuildTask
._SchedulerStopped
.isSet()
516 if BuildTask
.IsOnGoing():
517 BuildTask
._ErrorFlag
.set()
518 BuildTask
.WaitForComplete()
520 ## Check if there's error in running thread
522 # Since the main thread cannot catch exceptions in other thread, we have to
523 # use threading.Event to communicate this formation to main thread.
527 return BuildTask
._ErrorFlag
.isSet()
529 ## Get error message in running thread
531 # Since the main thread cannot catch exceptions in other thread, we have to
532 # use a static variable to communicate this message to main thread.
535 def GetErrorMessage():
536 return BuildTask
._ErrorMessage
538 ## Factory method to create a BuildTask object
540 # This method will check if a module is building or has been built. And if
541 # true, just return the associated BuildTask object in the _TaskQueue. If
542 # not, create and return a new BuildTask object. The new BuildTask object
543 # will be appended to the _PendingQueue for scheduling later.
545 # @param BuildItem A BuildUnit object representing a build object
546 # @param Dependency The dependent build object of BuildItem
549 def New(BuildItem
, Dependency
=None):
550 if BuildItem
in BuildTask
._TaskQueue
:
551 Bt
= BuildTask
._TaskQueue
[BuildItem
]
555 Bt
._Init
(BuildItem
, Dependency
)
556 BuildTask
._TaskQueue
[BuildItem
] = Bt
558 BuildTask
._PendingQueueLock
.acquire()
559 BuildTask
._PendingQueue
[BuildItem
] = Bt
560 BuildTask
._PendingQueueLock
.release()
564 ## The real constructor of BuildTask
566 # @param BuildItem A BuildUnit object representing a build object
567 # @param Dependency The dependent build object of BuildItem
569 def _Init(self
, BuildItem
, Dependency
=None):
570 self
.BuildItem
= BuildItem
572 self
.DependencyList
= []
573 if Dependency
is None:
574 Dependency
= BuildItem
.Dependency
576 Dependency
.extend(BuildItem
.Dependency
)
577 self
.AddDependency(Dependency
)
578 # flag indicating build completes, used to avoid unnecessary re-build
579 self
.CompleteFlag
= False
581 ## Check if all dependent build tasks are completed or not
585 for Dep
in self
.DependencyList
:
586 if Dep
.CompleteFlag
== True:
593 ## Add dependent build task
595 # @param Dependency The list of dependent build objects
597 def AddDependency(self
, Dependency
):
598 for Dep
in Dependency
:
599 if not Dep
.BuildObject
.IsBinaryModule
and not Dep
.BuildObject
.CanSkipbyHash():
600 self
.DependencyList
.append(BuildTask
.New(Dep
)) # BuildTask list
602 ## The thread wrapper of LaunchCommand function
604 # @param Command A list or string contains the call of the command
605 # @param WorkingDir The directory in which the program will be running
607 def _CommandThread(self
, Command
, WorkingDir
):
609 self
.BuildItem
.BuildObject
.BuildTime
= LaunchCommand(Command
, WorkingDir
)
610 self
.CompleteFlag
= True
612 # Run hash operation post dependency, to account for libs
613 if GlobalData
.gUseHashCache
and self
.BuildItem
.BuildObject
.IsLibrary
:
614 HashFile
= path
.join(self
.BuildItem
.BuildObject
.BuildDir
, self
.BuildItem
.BuildObject
.Name
+ ".hash")
615 SaveFileOnChange(HashFile
, self
.BuildItem
.BuildObject
.GenModuleHash(), True)
618 # TRICK: hide the output of threads left running, so that the user can
619 # catch the error message easily
621 if not BuildTask
._ErrorFlag
.isSet():
622 GlobalData
.gBuildingModule
= "%s [%s, %s, %s]" % (str(self
.BuildItem
.BuildObject
),
623 self
.BuildItem
.BuildObject
.Arch
,
624 self
.BuildItem
.BuildObject
.ToolChain
,
625 self
.BuildItem
.BuildObject
.BuildTarget
627 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
628 BuildTask
._ErrorFlag
.set()
629 BuildTask
._ErrorMessage
= "%s broken\n %s [%s]" % \
630 (threading
.currentThread().getName(), Command
, WorkingDir
)
632 # Set the value used by hash invalidation flow in GlobalData.gModuleBuildTracking to 'SUCCESS'
633 # If Module or Lib is being tracked, it did not fail header check test, and built successfully
634 if (self
.BuildItem
.BuildObject
.Arch
in GlobalData
.gModuleBuildTracking
and
635 self
.BuildItem
.BuildObject
in GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
.Arch
] and
636 GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
.Arch
][self
.BuildItem
.BuildObject
] != 'FAIL_METAFILE' and
637 not BuildTask
._ErrorFlag
.isSet()
639 GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
.Arch
][self
.BuildItem
.BuildObject
] = 'SUCCESS'
641 # indicate there's a thread is available for another build task
642 BuildTask
._RunningQueueLock
.acquire()
643 BuildTask
._RunningQueue
.pop(self
.BuildItem
)
644 BuildTask
._RunningQueueLock
.release()
645 BuildTask
._Thread
.release()
647 ## Start build task thread
650 EdkLogger
.quiet("Building ... %s" % repr(self
.BuildItem
))
651 Command
= self
.BuildItem
.BuildCommand
+ [self
.BuildItem
.Target
]
652 self
.BuildTread
= Thread(target
=self
._CommandThread
, args
=(Command
, self
.BuildItem
.WorkingDir
))
653 self
.BuildTread
.setName("build thread")
654 self
.BuildTread
.setDaemon(False)
655 self
.BuildTread
.start()
657 ## The class contains the information related to EFI image
662 # Constructor will load all required image information.
664 # @param BaseName The full file path of image.
665 # @param Guid The GUID for image.
666 # @param Arch Arch of this image.
667 # @param OutputDir The output directory for image.
668 # @param DebugDir The debug directory for image.
669 # @param ImageClass PeImage Information
671 def __init__(self
, BaseName
, Guid
, Arch
, OutputDir
, DebugDir
, ImageClass
):
672 self
.BaseName
= BaseName
675 self
.OutputDir
= OutputDir
676 self
.DebugDir
= DebugDir
677 self
.Image
= ImageClass
678 self
.Image
.Size
= (self
.Image
.Size
// 0x1000 + 1) * 0x1000
680 ## The class implementing the EDK2 build process
682 # The build process includes:
683 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
684 # 2. Parse DSC file of active platform
685 # 3. Parse FDF file if any
686 # 4. Establish build database, including parse all other files (module, package)
687 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
688 # 6. Call build command
693 # Constructor will load all necessary configurations, parse platform, modules
694 # and packages and the establish a database for AutoGen.
696 # @param Target The build command target, one of gSupportedTarget
697 # @param WorkspaceDir The directory of workspace
698 # @param BuildOptions Build options passed from command line
700 def __init__(self
, Target
, WorkspaceDir
, BuildOptions
):
701 self
.WorkspaceDir
= WorkspaceDir
703 self
.PlatformFile
= BuildOptions
.PlatformFile
704 self
.ModuleFile
= BuildOptions
.ModuleFile
705 self
.ArchList
= BuildOptions
.TargetArch
706 self
.ToolChainList
= BuildOptions
.ToolChain
707 self
.BuildTargetList
= BuildOptions
.BuildTarget
708 self
.Fdf
= BuildOptions
.FdfFile
709 self
.FdList
= BuildOptions
.RomImage
710 self
.FvList
= BuildOptions
.FvImage
711 self
.CapList
= BuildOptions
.CapName
712 self
.SilentMode
= BuildOptions
.SilentMode
713 self
.ThreadNumber
= BuildOptions
.ThreadNumber
714 self
.SkipAutoGen
= BuildOptions
.SkipAutoGen
715 self
.Reparse
= BuildOptions
.Reparse
716 self
.SkuId
= BuildOptions
.SkuId
718 GlobalData
.gSKUID_CMD
= self
.SkuId
719 self
.ConfDirectory
= BuildOptions
.ConfDirectory
720 self
.SpawnMode
= True
721 self
.BuildReport
= BuildReport(BuildOptions
.ReportFile
, BuildOptions
.ReportType
)
722 self
.TargetTxt
= TargetTxt
723 self
.ToolDef
= ToolDef
727 GlobalData
.BuildOptionPcd
= BuildOptions
.OptionPcd
if BuildOptions
.OptionPcd
else []
728 #Set global flag for build mode
729 GlobalData
.gIgnoreSource
= BuildOptions
.IgnoreSources
730 GlobalData
.gUseHashCache
= BuildOptions
.UseHashCache
731 GlobalData
.gBinCacheDest
= BuildOptions
.BinCacheDest
732 GlobalData
.gBinCacheSource
= BuildOptions
.BinCacheSource
733 GlobalData
.gEnableGenfdsMultiThread
= BuildOptions
.GenfdsMultiThread
734 GlobalData
.gDisableIncludePathCheck
= BuildOptions
.DisableIncludePathCheck
736 if GlobalData
.gBinCacheDest
and not GlobalData
.gUseHashCache
:
737 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination must be used together with --hash.")
739 if GlobalData
.gBinCacheSource
and not GlobalData
.gUseHashCache
:
740 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-source must be used together with --hash.")
742 if GlobalData
.gBinCacheDest
and GlobalData
.gBinCacheSource
:
743 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination can not be used together with --binary-source.")
745 if GlobalData
.gBinCacheSource
:
746 BinCacheSource
= os
.path
.normpath(GlobalData
.gBinCacheSource
)
747 if not os
.path
.isabs(BinCacheSource
):
748 BinCacheSource
= mws
.join(self
.WorkspaceDir
, BinCacheSource
)
749 GlobalData
.gBinCacheSource
= BinCacheSource
751 if GlobalData
.gBinCacheSource
is not None:
752 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-source.")
754 if GlobalData
.gBinCacheDest
:
755 BinCacheDest
= os
.path
.normpath(GlobalData
.gBinCacheDest
)
756 if not os
.path
.isabs(BinCacheDest
):
757 BinCacheDest
= mws
.join(self
.WorkspaceDir
, BinCacheDest
)
758 GlobalData
.gBinCacheDest
= BinCacheDest
760 if GlobalData
.gBinCacheDest
is not None:
761 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-destination.")
763 if self
.ConfDirectory
:
764 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
765 ConfDirectoryPath
= os
.path
.normpath(self
.ConfDirectory
)
767 if not os
.path
.isabs(ConfDirectoryPath
):
768 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
769 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
770 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, ConfDirectoryPath
)
772 if "CONF_PATH" in os
.environ
:
773 ConfDirectoryPath
= os
.path
.normcase(os
.path
.normpath(os
.environ
["CONF_PATH"]))
775 # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf
776 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, 'Conf')
777 GlobalData
.gConfDirectory
= ConfDirectoryPath
778 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
779 if not os
.path
.exists(os
.path
.join(GlobalData
.gConfDirectory
, '.cache')):
780 os
.makedirs(os
.path
.join(GlobalData
.gConfDirectory
, '.cache'))
782 self
.BuildDatabase
= self
.Db
.BuildObject
784 self
.ToolChainFamily
= None
785 self
.LoadFixAddress
= 0
786 self
.UniFlag
= BuildOptions
.Flag
787 self
.BuildModules
= []
788 self
.HashSkipModules
= []
790 self
.LaunchPrebuildFlag
= False
791 self
.PlatformBuildPath
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PlatformBuild')
792 if BuildOptions
.CommandLength
:
793 GlobalData
.gCommandMaxLength
= BuildOptions
.CommandLength
795 # print dot character during doing some time-consuming work
796 self
.Progress
= Utils
.Progressor()
797 # print current build environment and configuration
798 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
799 if "PACKAGES_PATH" in os
.environ
:
800 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
801 EdkLogger
.quiet("%-16s = %s" % ("PACKAGES_PATH", os
.path
.normcase(os
.path
.normpath(os
.environ
["PACKAGES_PATH"]))))
802 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
803 if "EDK_TOOLS_BIN" in os
.environ
:
804 # Print the same path style with WORKSPACE env.
805 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_TOOLS_BIN"]))))
806 EdkLogger
.quiet("%-16s = %s" % ("CONF_PATH", GlobalData
.gConfDirectory
))
807 if "PYTHON3_ENABLE" in os
.environ
:
808 PYTHON3_ENABLE
= os
.environ
["PYTHON3_ENABLE"]
809 if PYTHON3_ENABLE
!= "TRUE":
810 PYTHON3_ENABLE
= "FALSE"
811 EdkLogger
.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE
))
812 if "PYTHON_COMMAND" in os
.environ
:
813 EdkLogger
.quiet("%-16s = %s" % ("PYTHON_COMMAND", os
.environ
["PYTHON_COMMAND"]))
817 EdkLogger
.quiet("%-16s = %s" % ("PREBUILD", self
.Prebuild
))
819 EdkLogger
.quiet("%-16s = %s" % ("POSTBUILD", self
.Postbuild
))
821 self
.LaunchPrebuild()
822 self
.TargetTxt
= TargetTxt
823 self
.ToolDef
= ToolDef
824 if not (self
.LaunchPrebuildFlag
and os
.path
.exists(self
.PlatformBuildPath
)):
828 os
.chdir(self
.WorkspaceDir
)
830 ## Load configuration
832 # This method will parse target.txt and get the build configurations.
834 def LoadConfiguration(self
):
836 # if no ARCH given in command line, get it from target.txt
837 if not self
.ArchList
:
838 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET_ARCH
]
839 self
.ArchList
= tuple(self
.ArchList
)
841 # if no build target given in command line, get it from target.txt
842 if not self
.BuildTargetList
:
843 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
845 # if no tool chain given in command line, get it from target.txt
846 if not self
.ToolChainList
:
847 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
848 if self
.ToolChainList
is None or len(self
.ToolChainList
) == 0:
849 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
851 # check if the tool chains are defined or not
852 NewToolChainList
= []
853 for ToolChain
in self
.ToolChainList
:
854 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
855 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
857 NewToolChainList
.append(ToolChain
)
858 # if no tool chain available, break the build
859 if len(NewToolChainList
) == 0:
860 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
861 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
863 self
.ToolChainList
= NewToolChainList
866 ToolDefinition
= self
.ToolDef
.ToolsDefTxtDatabase
867 for Tool
in self
.ToolChainList
:
868 if TAB_TOD_DEFINES_FAMILY
not in ToolDefinition
or Tool
not in ToolDefinition
[TAB_TOD_DEFINES_FAMILY
] \
869 or not ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
]:
870 EdkLogger
.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool
)
871 ToolChainFamily
.append(TAB_COMPILER_MSFT
)
873 ToolChainFamily
.append(ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
])
874 self
.ToolChainFamily
= ToolChainFamily
876 if self
.ThreadNumber
is None:
877 self
.ThreadNumber
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
878 if self
.ThreadNumber
== '':
879 self
.ThreadNumber
= 0
881 self
.ThreadNumber
= int(self
.ThreadNumber
, 0)
883 if self
.ThreadNumber
== 0:
885 self
.ThreadNumber
= multiprocessing
.cpu_count()
886 except (ImportError, NotImplementedError):
887 self
.ThreadNumber
= 1
889 if not self
.PlatformFile
:
890 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
892 # Try to find one in current directory
893 WorkingDirectory
= os
.getcwd()
894 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
895 FileNum
= len(FileList
)
897 EdkLogger
.error("build", OPTION_MISSING
,
898 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
900 PlatformFile
= FileList
[0]
902 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
903 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
905 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
907 ## Initialize build configuration
909 # This method will parse DSC file and merge the configurations from
910 # command line and target.txt, then get the final build configurations.
913 # parse target.txt, tools_def.txt, and platform file
914 self
.LoadConfiguration()
916 # Allow case-insensitive for those from command line or configuration file
917 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
919 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
922 def InitPreBuild(self
):
923 self
.LoadConfiguration()
924 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
926 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
927 if self
.BuildTargetList
:
928 GlobalData
.gGlobalDefines
['TARGET'] = self
.BuildTargetList
[0]
930 GlobalData
.gGlobalDefines
['ARCH'] = self
.ArchList
[0]
931 if self
.ToolChainList
:
932 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = self
.ToolChainList
[0]
933 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = self
.ToolChainList
[0]
934 if self
.ToolChainFamily
:
935 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[0]
936 if 'PREBUILD' in GlobalData
.gCommandLineDefines
:
937 self
.Prebuild
= GlobalData
.gCommandLineDefines
.get('PREBUILD')
940 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
941 self
.Prebuild
= str(Platform
.Prebuild
)
945 # Evaluate all arguments and convert arguments that are WORKSPACE
946 # relative paths to absolute paths. Filter arguments that look like
947 # flags or do not follow the file/dir naming rules to avoid false
948 # positives on this conversion.
950 for Arg
in self
.Prebuild
.split():
952 # Do not modify Arg if it looks like a flag or an absolute file path
954 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
955 PrebuildList
.append(Arg
)
958 # Do not modify Arg if it does not look like a Workspace relative
959 # path that starts with a valid package directory name
961 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
962 PrebuildList
.append(Arg
)
965 # If Arg looks like a WORKSPACE relative path, then convert to an
966 # absolute path and check to see if the file exists.
968 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
969 if os
.path
.isfile(Temp
):
971 PrebuildList
.append(Arg
)
972 self
.Prebuild
= ' '.join(PrebuildList
)
973 self
.Prebuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
975 def InitPostBuild(self
):
976 if 'POSTBUILD' in GlobalData
.gCommandLineDefines
:
977 self
.Postbuild
= GlobalData
.gCommandLineDefines
.get('POSTBUILD')
979 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
980 self
.Postbuild
= str(Platform
.Postbuild
)
984 # Evaluate all arguments and convert arguments that are WORKSPACE
985 # relative paths to absolute paths. Filter arguments that look like
986 # flags or do not follow the file/dir naming rules to avoid false
987 # positives on this conversion.
989 for Arg
in self
.Postbuild
.split():
991 # Do not modify Arg if it looks like a flag or an absolute file path
993 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
994 PostbuildList
.append(Arg
)
997 # Do not modify Arg if it does not look like a Workspace relative
998 # path that starts with a valid package directory name
1000 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1001 PostbuildList
.append(Arg
)
1004 # If Arg looks like a WORKSPACE relative path, then convert to an
1005 # absolute path and check to see if the file exists.
1007 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1008 if os
.path
.isfile(Temp
):
1010 PostbuildList
.append(Arg
)
1011 self
.Postbuild
= ' '.join(PostbuildList
)
1012 self
.Postbuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1014 def PassCommandOption(self
, BuildTarget
, TargetArch
, ToolChain
, PlatformFile
, Target
):
1016 if GlobalData
.gCommand
and isinstance(GlobalData
.gCommand
, list):
1017 BuildStr
+= ' ' + ' '.join(GlobalData
.gCommand
)
1020 ToolChainFlag
= False
1021 PlatformFileFlag
= False
1023 if GlobalData
.gOptions
and not GlobalData
.gOptions
.BuildTarget
:
1025 if GlobalData
.gOptions
and not GlobalData
.gOptions
.TargetArch
:
1027 if GlobalData
.gOptions
and not GlobalData
.gOptions
.ToolChain
:
1028 ToolChainFlag
= True
1029 if GlobalData
.gOptions
and not GlobalData
.gOptions
.PlatformFile
:
1030 PlatformFileFlag
= True
1032 if TargetFlag
and BuildTarget
:
1033 if isinstance(BuildTarget
, list) or isinstance(BuildTarget
, tuple):
1034 BuildStr
+= ' -b ' + ' -b '.join(BuildTarget
)
1035 elif isinstance(BuildTarget
, str):
1036 BuildStr
+= ' -b ' + BuildTarget
1037 if ArchFlag
and TargetArch
:
1038 if isinstance(TargetArch
, list) or isinstance(TargetArch
, tuple):
1039 BuildStr
+= ' -a ' + ' -a '.join(TargetArch
)
1040 elif isinstance(TargetArch
, str):
1041 BuildStr
+= ' -a ' + TargetArch
1042 if ToolChainFlag
and ToolChain
:
1043 if isinstance(ToolChain
, list) or isinstance(ToolChain
, tuple):
1044 BuildStr
+= ' -t ' + ' -t '.join(ToolChain
)
1045 elif isinstance(ToolChain
, str):
1046 BuildStr
+= ' -t ' + ToolChain
1047 if PlatformFileFlag
and PlatformFile
:
1048 if isinstance(PlatformFile
, list) or isinstance(PlatformFile
, tuple):
1049 BuildStr
+= ' -p ' + ' -p '.join(PlatformFile
)
1050 elif isinstance(PlatformFile
, str):
1051 BuildStr
+= ' -p' + PlatformFile
1052 BuildStr
+= ' --conf=' + GlobalData
.gConfDirectory
1054 BuildStr
+= ' ' + Target
1058 def LaunchPrebuild(self
):
1060 EdkLogger
.info("\n- Prebuild Start -\n")
1061 self
.LaunchPrebuildFlag
= True
1063 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1064 # and preserve them for the rest of the main build step, because the child process environment will
1065 # evaporate as soon as it exits, we cannot get it in build step.
1067 PrebuildEnvFile
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PrebuildEnv')
1068 if os
.path
.isfile(PrebuildEnvFile
):
1069 os
.remove(PrebuildEnvFile
)
1070 if os
.path
.isfile(self
.PlatformBuildPath
):
1071 os
.remove(self
.PlatformBuildPath
)
1072 if sys
.platform
== "win32":
1073 args
= ' && '.join((self
.Prebuild
, 'set > ' + PrebuildEnvFile
))
1074 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1076 args
= ' && '.join((self
.Prebuild
, 'env > ' + PrebuildEnvFile
))
1077 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1079 # launch two threads to read the STDOUT and STDERR
1080 EndOfProcedure
= Event()
1081 EndOfProcedure
.clear()
1083 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1084 StdOutThread
.setName("STDOUT-Redirector")
1085 StdOutThread
.setDaemon(False)
1086 StdOutThread
.start()
1089 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1090 StdErrThread
.setName("STDERR-Redirector")
1091 StdErrThread
.setDaemon(False)
1092 StdErrThread
.start()
1093 # waiting for program exit
1100 if Process
.returncode
!= 0 :
1101 EdkLogger
.error("Prebuild", PREBUILD_ERROR
, 'Prebuild process is not success!')
1103 if os
.path
.exists(PrebuildEnvFile
):
1104 f
= open(PrebuildEnvFile
)
1105 envs
= f
.readlines()
1107 envs
= [l
.split("=", 1) for l
in envs
]
1108 envs
= [[I
.strip() for I
in item
] for item
in envs
if len(item
) == 2]
1109 os
.environ
.update(dict(envs
))
1110 EdkLogger
.info("\n- Prebuild Done -\n")
1112 def LaunchPostbuild(self
):
1114 EdkLogger
.info("\n- Postbuild Start -\n")
1115 if sys
.platform
== "win32":
1116 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1118 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1119 # launch two threads to read the STDOUT and STDERR
1120 EndOfProcedure
= Event()
1121 EndOfProcedure
.clear()
1123 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1124 StdOutThread
.setName("STDOUT-Redirector")
1125 StdOutThread
.setDaemon(False)
1126 StdOutThread
.start()
1129 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1130 StdErrThread
.setName("STDERR-Redirector")
1131 StdErrThread
.setDaemon(False)
1132 StdErrThread
.start()
1133 # waiting for program exit
1140 if Process
.returncode
!= 0 :
1141 EdkLogger
.error("Postbuild", POSTBUILD_ERROR
, 'Postbuild process is not success!')
1142 EdkLogger
.info("\n- Postbuild Done -\n")
1144 ## Error handling for hash feature
1146 # On BuildTask error, iterate through the Module Build tracking
1147 # dictionary to determine wheather a module failed to build. Invalidate
1148 # the hash associated with that module by removing it from storage.
1151 def invalidateHash(self
):
1152 # Only for hashing feature
1153 if not GlobalData
.gUseHashCache
:
1156 # GlobalData.gModuleBuildTracking contains only modules or libs that cannot be skipped by hash
1157 for moduleAutoGenObjArch
in GlobalData
.gModuleBuildTracking
.keys():
1158 for moduleAutoGenObj
in GlobalData
.gModuleBuildTracking
[moduleAutoGenObjArch
].keys():
1159 # Skip invalidating for Successful Module/Lib builds
1160 if GlobalData
.gModuleBuildTracking
[moduleAutoGenObjArch
][moduleAutoGenObj
] == 'SUCCESS':
1163 # The module failed to build, failed to start building, or failed the header check test from this point on
1165 # Remove .hash from build
1166 ModuleHashFile
= os
.path
.join(moduleAutoGenObj
.BuildDir
, moduleAutoGenObj
.Name
+ ".hash")
1167 if os
.path
.exists(ModuleHashFile
):
1168 os
.remove(ModuleHashFile
)
1170 # Remove .hash file from cache
1171 if GlobalData
.gBinCacheDest
:
1172 FileDir
= os
.path
.join(GlobalData
.gBinCacheDest
, moduleAutoGenObj
.Arch
, moduleAutoGenObj
.SourceDir
, moduleAutoGenObj
.MetaFile
.BaseName
)
1173 HashFile
= os
.path
.join(FileDir
, moduleAutoGenObj
.Name
+ '.hash')
1174 if os
.path
.exists(HashFile
):
1177 ## Build a module or platform
1179 # Create autogen code and makefile for a module or platform, and the launch
1180 # "make" command to build it
1182 # @param Target The target of build command
1183 # @param Platform The platform file
1184 # @param Module The module file
1185 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1186 # @param ToolChain The name of toolchain to build
1187 # @param Arch The arch of the module/platform
1188 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1189 # for dependent modules/Libraries
1190 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1191 # for dependent modules/Libraries
1193 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False, FfsCommand
={}):
1194 if AutoGenObject
is None:
1197 # skip file generation for cleanxxx targets, run and fds target
1198 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1199 # for target which must generate AutoGen code and makefile
1200 if not self
.SkipAutoGen
or Target
== 'genc':
1201 self
.Progress
.Start("Generating code")
1202 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1203 self
.Progress
.Stop("done!")
1204 if Target
== "genc":
1207 if not self
.SkipAutoGen
or Target
== 'genmake':
1208 self
.Progress
.Start("Generating makefile")
1209 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
, FfsCommand
)
1210 self
.Progress
.Stop("done!")
1211 if Target
== "genmake":
1214 # always recreate top/platform makefile when clean, just in case of inconsistency
1215 AutoGenObject
.CreateCodeFile(False)
1216 AutoGenObject
.CreateMakeFile(False)
1218 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1219 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1221 BuildCommand
= AutoGenObject
.BuildCommand
1222 if BuildCommand
is None or len(BuildCommand
) == 0:
1223 EdkLogger
.error("build", OPTION_MISSING
,
1224 "No build command found for this module. "
1225 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1226 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1227 ExtraData
=str(AutoGenObject
))
1229 makefile
= GenMake
.BuildFile(AutoGenObject
)._FILE
_NAME
_[GenMake
.gMakeType
]
1237 BuildCommand
= BuildCommand
+ [Target
]
1238 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1239 self
.CreateAsBuiltInf()
1240 if GlobalData
.gBinCacheDest
:
1241 self
.UpdateBuildCache()
1242 self
.BuildModules
= []
1246 if Target
== 'libraries':
1247 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1248 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1249 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1253 if Target
== 'modules':
1254 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1255 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1256 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1257 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1258 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, makefile
)), 'pbuild']
1259 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1260 self
.CreateAsBuiltInf()
1261 if GlobalData
.gBinCacheDest
:
1262 self
.UpdateBuildCache()
1263 self
.BuildModules
= []
1267 if Target
== 'cleanlib':
1268 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1269 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1270 if os
.path
.exists(LibMakefile
):
1271 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1272 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1276 if Target
== 'clean':
1277 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1278 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, makefile
))
1279 if os
.path
.exists(ModMakefile
):
1280 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
1281 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
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
== 'cleanall':
1292 #os.rmdir(AutoGenObject.BuildDir)
1293 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1294 except WindowsError as X
:
1295 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1298 ## Build a module or platform
1300 # Create autogen code and makefile for a module or platform, and the launch
1301 # "make" command to build it
1303 # @param Target The target of build command
1304 # @param Platform The platform file
1305 # @param Module The module file
1306 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1307 # @param ToolChain The name of toolchain to build
1308 # @param Arch The arch of the module/platform
1309 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1310 # for dependent modules/Libraries
1311 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1312 # for dependent modules/Libraries
1314 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1315 if AutoGenObject
is None:
1318 # skip file generation for cleanxxx targets, run and fds target
1319 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1320 # for target which must generate AutoGen code and makefile
1321 if not self
.SkipAutoGen
or Target
== 'genc':
1322 self
.Progress
.Start("Generating code")
1323 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1324 self
.Progress
.Stop("done!")
1325 if Target
== "genc":
1328 if not self
.SkipAutoGen
or Target
== 'genmake':
1329 self
.Progress
.Start("Generating makefile")
1330 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1331 #AutoGenObject.CreateAsBuiltInf()
1332 self
.Progress
.Stop("done!")
1333 if Target
== "genmake":
1336 # always recreate top/platform makefile when clean, just in case of inconsistency
1337 AutoGenObject
.CreateCodeFile(False)
1338 AutoGenObject
.CreateMakeFile(False)
1340 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1341 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1343 BuildCommand
= AutoGenObject
.BuildCommand
1344 if BuildCommand
is None or len(BuildCommand
) == 0:
1345 EdkLogger
.error("build", OPTION_MISSING
,
1346 "No build command found for this module. "
1347 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1348 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1349 ExtraData
=str(AutoGenObject
))
1354 BuildCommand
= BuildCommand
+ [Target
]
1355 AutoGenObject
.BuildTime
= LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1356 self
.CreateAsBuiltInf()
1357 if GlobalData
.gBinCacheDest
:
1358 self
.UpdateBuildCache()
1359 self
.BuildModules
= []
1364 if GenFdsApi(AutoGenObject
.GenFdsCommandDict
, self
.Db
):
1365 EdkLogger
.error("build", COMMAND_FAILURE
)
1373 if Target
== 'libraries':
1380 if Target
== 'cleanall':
1382 #os.rmdir(AutoGenObject.BuildDir)
1383 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1384 except WindowsError as X
:
1385 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1388 ## Rebase module image and Get function address for the input module list.
1390 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1392 AddrIsOffset
= False
1393 for InfFile
in ModuleList
:
1394 sys
.stdout
.write (".")
1396 ModuleInfo
= ModuleList
[InfFile
]
1397 ModuleName
= ModuleInfo
.BaseName
1398 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1399 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1400 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1402 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1404 # Update Image to new BaseAddress by GenFw tool
1406 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1407 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1410 # Set new address to the section header only for SMM driver.
1412 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1413 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1415 # Collect function address from Map file
1417 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1419 if os
.path
.exists(ImageMapTable
):
1420 OrigImageBaseAddress
= 0
1421 ImageMap
= open(ImageMapTable
, 'r')
1422 for LinStr
in ImageMap
:
1423 if len (LinStr
.strip()) == 0:
1426 # Get the preferred address set on link time.
1428 if LinStr
.find ('Preferred load address is') != -1:
1429 StrList
= LinStr
.split()
1430 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1432 StrList
= LinStr
.split()
1433 if len (StrList
) > 4:
1434 if StrList
[3] == 'f' or StrList
[3] == 'F':
1436 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1437 FunctionList
.append ((Name
, RelativeAddress
))
1441 # Add general information.
1444 MapBuffer
.append('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1446 MapBuffer
.append('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1448 MapBuffer
.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1450 # Add guid and general seciton section.
1452 TextSectionAddress
= 0
1453 DataSectionAddress
= 0
1454 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1455 if SectionHeader
[0] == '.text':
1456 TextSectionAddress
= SectionHeader
[1]
1457 elif SectionHeader
[0] in ['.data', '.sdata']:
1458 DataSectionAddress
= SectionHeader
[1]
1460 MapBuffer
.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1462 MapBuffer
.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1464 # Add debug image full path.
1466 MapBuffer
.append('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1468 # Add function address
1470 for Function
in FunctionList
:
1472 MapBuffer
.append(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1474 MapBuffer
.append(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1478 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1481 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1483 ## Collect MAP information of all FVs
1485 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1487 # First get the XIP base address for FV map file.
1488 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1489 GuidName
= re
.compile(r
"\(GUID=[-a-fA-F0-9]+")
1490 for FvName
in Wa
.FdfProfile
.FvDict
:
1491 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1492 if not os
.path
.exists(FvMapBuffer
):
1494 FvMap
= open(FvMapBuffer
, 'r')
1495 #skip FV size information
1501 MatchGuid
= GuidPattern
.match(Line
)
1502 if MatchGuid
is not None:
1504 # Replace GUID with module name
1506 GuidString
= MatchGuid
.group()
1507 if GuidString
.upper() in ModuleList
:
1508 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1509 MapBuffer
.append(Line
)
1511 # Add the debug image full path.
1513 MatchGuid
= GuidName
.match(Line
)
1514 if MatchGuid
is not None:
1515 GuidString
= MatchGuid
.group().split("=")[1]
1516 if GuidString
.upper() in ModuleList
:
1517 MapBuffer
.append('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1521 ## Collect MAP information of all modules
1523 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1524 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1526 PatchEfiImageList
= []
1534 # reserve 4K size in SMRAM to make SMM module address not from 0.
1536 for ModuleGuid
in ModuleList
:
1537 Module
= ModuleList
[ModuleGuid
]
1538 GlobalData
.gProcessingFile
= "%s [%s, %s, %s]" % (Module
.MetaFile
, Module
.Arch
, Module
.ToolChain
, Module
.BuildTarget
)
1540 OutputImageFile
= ''
1541 for ResultFile
in Module
.CodaTargetList
:
1542 if str(ResultFile
.Target
).endswith('.efi'):
1544 # module list for PEI, DXE, RUNTIME and SMM
1546 OutputImageFile
= os
.path
.join(Module
.OutputDir
, Module
.Name
+ '.efi')
1547 ImageClass
= PeImageClass (OutputImageFile
)
1548 if not ImageClass
.IsValid
:
1549 EdkLogger
.error("build", FILE_PARSE_FAILURE
, ExtraData
=ImageClass
.ErrorInfo
)
1550 ImageInfo
= PeImageInfo(Module
.Name
, Module
.Guid
, Module
.Arch
, Module
.OutputDir
, Module
.DebugDir
, ImageClass
)
1551 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
]:
1552 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1553 PeiSize
+= ImageInfo
.Image
.Size
1554 elif Module
.ModuleType
in [EDK_COMPONENT_TYPE_BS_DRIVER
, SUP_MODULE_DXE_DRIVER
, SUP_MODULE_UEFI_DRIVER
]:
1555 BtModuleList
[Module
.MetaFile
] = ImageInfo
1556 BtSize
+= ImageInfo
.Image
.Size
1557 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
]:
1558 RtModuleList
[Module
.MetaFile
] = ImageInfo
1559 RtSize
+= ImageInfo
.Image
.Size
1560 elif Module
.ModuleType
in [SUP_MODULE_SMM_CORE
, SUP_MODULE_DXE_SMM_DRIVER
, SUP_MODULE_MM_STANDALONE
, SUP_MODULE_MM_CORE_STANDALONE
]:
1561 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1562 SmmSize
+= ImageInfo
.Image
.Size
1563 if Module
.ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
1564 PiSpecVersion
= Module
.Module
.Specification
.get('PI_SPECIFICATION_VERSION', '0x00000000')
1565 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1566 if int(PiSpecVersion
, 16) < 0x0001000A:
1567 BtModuleList
[Module
.MetaFile
] = ImageInfo
1568 BtSize
+= ImageInfo
.Image
.Size
1571 # EFI image is final target.
1572 # Check EFI image contains patchable FixAddress related PCDs.
1574 if OutputImageFile
!= '':
1575 ModuleIsPatch
= False
1576 for Pcd
in Module
.ModulePcdList
:
1577 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1578 ModuleIsPatch
= True
1580 if not ModuleIsPatch
:
1581 for Pcd
in Module
.LibraryPcdList
:
1582 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1583 ModuleIsPatch
= True
1586 if not ModuleIsPatch
:
1589 # Module includes the patchable load fix address PCDs.
1590 # It will be fixed up later.
1592 PatchEfiImageList
.append (OutputImageFile
)
1595 # Get Top Memory address
1597 ReservedRuntimeMemorySize
= 0
1598 TopMemoryAddress
= 0
1599 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1600 TopMemoryAddress
= 0
1602 TopMemoryAddress
= self
.LoadFixAddress
1603 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1604 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1607 # Patch FixAddress related PCDs into EFI image
1609 for EfiImage
in PatchEfiImageList
:
1610 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1611 if not os
.path
.exists(EfiImageMap
):
1614 # Get PCD offset in EFI image by GenPatchPcdTable function
1616 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1618 # Patch real PCD value by PatchPcdValue tool
1620 for PcdInfo
in PcdTable
:
1622 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1623 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
// 0x1000))
1624 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1625 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
// 0x1000))
1626 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1627 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
// 0x1000))
1628 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1629 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
// 0x1000))
1630 if ReturnValue
!= 0:
1631 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1633 MapBuffer
.append('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
// 0x1000))
1634 MapBuffer
.append('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
// 0x1000))
1635 MapBuffer
.append('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
// 0x1000))
1636 if len (SmmModuleList
) > 0:
1637 MapBuffer
.append('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
// 0x1000))
1639 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1640 BtBaseAddr
= TopMemoryAddress
- RtSize
1641 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1643 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1644 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1645 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1646 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
=False, ModeIsSmm
=True)
1647 MapBuffer
.append('\n\n')
1648 sys
.stdout
.write ("\n")
1651 ## Save platform Map file
1653 def _SaveMapFile (self
, MapBuffer
, Wa
):
1655 # Map file path is got.
1657 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1659 # Save address map into MAP file.
1661 SaveFileOnChange(MapFilePath
, ''.join(MapBuffer
), False)
1662 if self
.LoadFixAddress
!= 0:
1663 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath
))
1666 ## Build active platform for different build targets and different tool chains
1668 def _BuildPlatform(self
):
1669 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1670 for BuildTarget
in self
.BuildTargetList
:
1671 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1673 for ToolChain
in self
.ToolChainList
:
1674 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1675 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1676 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1678 Wa
= WorkspaceAutoGen(
1695 self
.Fdf
= Wa
.FdfFile
1696 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1697 self
.BuildReport
.AddPlatformReport(Wa
)
1698 self
.Progress
.Stop("done!")
1700 # Add ffs build to makefile
1702 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1703 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1705 for Arch
in Wa
.ArchList
:
1707 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1708 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1709 for Module
in Pa
.Platform
.Modules
:
1710 # Get ModuleAutoGen object to generate C code file and makefile
1711 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1715 Ma
.PlatformInfo
= Pa
1716 PcdMaList
.append(Ma
)
1717 self
.BuildModules
.append(Ma
)
1718 self
._BuildPa
(self
.Target
, Pa
, FfsCommand
=CmdListDict
)
1720 # Create MAP file when Load Fix Address is enabled.
1721 if self
.Target
in ["", "all", "fds"]:
1722 for Arch
in Wa
.ArchList
:
1723 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1725 # Check whether the set fix address is above 4G for 32bit image.
1727 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1728 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS can't be set to larger than or equal to 4G for the platform with IA32 or ARM arch modules")
1733 for Pa
in Wa
.AutoGenObjectList
:
1734 for Ma
in Pa
.ModuleAutoGenList
:
1737 if not Ma
.IsLibrary
:
1738 ModuleList
[Ma
.Guid
.upper()] = Ma
1741 if self
.LoadFixAddress
!= 0:
1743 # Rebase module to the preferred memory address before GenFds
1745 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1748 # create FDS again for the updated EFI image
1750 self
._Build
("fds", Wa
)
1752 # Create MAP file for all platform FVs after GenFds.
1754 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1756 # Save MAP buffer into MAP file.
1758 self
._SaveMapFile
(MapBuffer
, Wa
)
1760 ## Build active module for different build targets, different tool chains and different archs
1762 def _BuildModule(self
):
1763 for BuildTarget
in self
.BuildTargetList
:
1764 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1766 for ToolChain
in self
.ToolChainList
:
1767 WorkspaceAutoGenTime
= time
.time()
1768 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1769 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1770 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1773 # module build needs platform build information, so get platform
1776 Wa
= WorkspaceAutoGen(
1794 self
.Fdf
= Wa
.FdfFile
1795 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1796 Wa
.CreateMakeFile(False)
1797 # Add ffs build to makefile
1799 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1800 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1801 self
.Progress
.Stop("done!")
1803 ExitFlag
= threading
.Event()
1805 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1806 for Arch
in Wa
.ArchList
:
1807 AutoGenStart
= time
.time()
1808 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1809 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1810 for Module
in Pa
.Platform
.Modules
:
1811 if self
.ModuleFile
.Dir
== Module
.Dir
and self
.ModuleFile
.Name
== Module
.Name
:
1812 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1816 if Ma
.CanSkipbyHash():
1817 self
.HashSkipModules
.append(Ma
)
1818 if GlobalData
.gBinCacheSource
:
1819 EdkLogger
.quiet("cache hit: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1822 if GlobalData
.gBinCacheSource
:
1823 EdkLogger
.quiet("cache miss: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1824 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1825 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1826 # for target which must generate AutoGen code and makefile
1827 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1828 self
.Progress
.Start("Generating code")
1829 Ma
.CreateCodeFile(True)
1830 self
.Progress
.Stop("done!")
1831 if self
.Target
== "genc":
1833 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1834 self
.Progress
.Start("Generating makefile")
1835 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
1836 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
1837 del CmdListDict
[Module
.File
, Arch
]
1839 Ma
.CreateMakeFile(True)
1840 self
.Progress
.Stop("done!")
1841 if self
.Target
== "genmake":
1843 self
.BuildModules
.append(Ma
)
1844 # Initialize all modules in tracking to 'FAIL'
1845 if Ma
.Arch
not in GlobalData
.gModuleBuildTracking
:
1846 GlobalData
.gModuleBuildTracking
[Ma
.Arch
] = dict()
1847 if Ma
not in GlobalData
.gModuleBuildTracking
[Ma
.Arch
]:
1848 GlobalData
.gModuleBuildTracking
[Ma
.Arch
][Ma
] = 'FAIL'
1849 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1850 MakeStart
= time
.time()
1851 for Ma
in self
.BuildModules
:
1852 if not Ma
.IsBinaryModule
:
1853 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
1854 # Break build if any build thread has error
1855 if BuildTask
.HasError():
1856 # we need a full version of makefile for platform
1858 BuildTask
.WaitForComplete()
1859 self
.invalidateHash()
1860 Pa
.CreateMakeFile(False)
1861 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1862 # Start task scheduler
1863 if not BuildTask
.IsOnGoing():
1864 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1866 # in case there's an interruption. we need a full version of makefile for platform
1867 Pa
.CreateMakeFile(False)
1868 if BuildTask
.HasError():
1869 self
.invalidateHash()
1870 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1871 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1873 MakeContiue
= time
.time()
1875 BuildTask
.WaitForComplete()
1876 self
.CreateAsBuiltInf()
1877 if GlobalData
.gBinCacheDest
:
1878 self
.UpdateBuildCache()
1879 self
.BuildModules
= []
1880 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1881 if BuildTask
.HasError():
1882 self
.invalidateHash()
1883 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1885 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1890 "Module for [%s] is not a component of active platform."\
1891 " Please make sure that the ARCH and inf file path are"\
1892 " given in the same as in [%s]" % \
1893 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1894 ExtraData
=self
.ModuleFile
1896 # Create MAP file when Load Fix Address is enabled.
1897 if self
.Target
== "fds" and self
.Fdf
:
1898 for Arch
in Wa
.ArchList
:
1900 # Check whether the set fix address is above 4G for 32bit image.
1902 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1903 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")
1908 for Pa
in Wa
.AutoGenObjectList
:
1909 for Ma
in Pa
.ModuleAutoGenList
:
1912 if not Ma
.IsLibrary
:
1913 ModuleList
[Ma
.Guid
.upper()] = Ma
1916 if self
.LoadFixAddress
!= 0:
1918 # Rebase module to the preferred memory address before GenFds
1920 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1922 # create FDS again for the updated EFI image
1924 GenFdsStart
= time
.time()
1925 self
._Build
("fds", Wa
)
1926 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
1928 # Create MAP file for all platform FVs after GenFds.
1930 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1932 # Save MAP buffer into MAP file.
1934 self
._SaveMapFile
(MapBuffer
, Wa
)
1935 self
.invalidateHash()
1937 def _GenFfsCmd(self
,ArchList
):
1938 # convert dictionary of Cmd:(Inf,Arch)
1939 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
1940 CmdSetDict
= defaultdict(set)
1941 GenFfsDict
= GenFds
.GenFfsMakefile('', GlobalData
.gFdfParser
, self
, ArchList
, GlobalData
)
1942 for Cmd
in GenFfsDict
:
1943 tmpInf
, tmpArch
= GenFfsDict
[Cmd
]
1944 CmdSetDict
[tmpInf
, tmpArch
].add(Cmd
)
1947 ## Build a platform in multi-thread mode
1949 def _MultiThreadBuildPlatform(self
):
1950 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1951 for BuildTarget
in self
.BuildTargetList
:
1952 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1954 for ToolChain
in self
.ToolChainList
:
1955 WorkspaceAutoGenTime
= time
.time()
1956 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1957 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1958 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1960 Wa
= WorkspaceAutoGen(
1977 self
.Fdf
= Wa
.FdfFile
1978 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1979 self
.BuildReport
.AddPlatformReport(Wa
)
1980 Wa
.CreateMakeFile(False)
1982 # Add ffs build to makefile
1984 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1985 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1987 # multi-thread exit flag
1988 ExitFlag
= threading
.Event()
1990 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1991 for Arch
in Wa
.ArchList
:
1993 AutoGenStart
= time
.time()
1994 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1995 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1999 for Inf
in Pa
.Platform
.Modules
:
2000 ModuleList
.append(Inf
)
2001 # Add the INF only list in FDF
2002 if GlobalData
.gFdfParser
is not None:
2003 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
2004 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
2005 if Inf
in Pa
.Platform
.Modules
:
2007 ModuleList
.append(Inf
)
2008 for Module
in ModuleList
:
2009 # Get ModuleAutoGen object to generate C code file and makefile
2010 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2015 Ma
.PlatformInfo
= Pa
2016 PcdMaList
.append(Ma
)
2017 if Ma
.CanSkipbyHash():
2018 self
.HashSkipModules
.append(Ma
)
2019 if GlobalData
.gBinCacheSource
:
2020 EdkLogger
.quiet("cache hit: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
2023 if GlobalData
.gBinCacheSource
:
2024 EdkLogger
.quiet("cache miss: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
2026 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
2027 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
2028 # for target which must generate AutoGen code and makefile
2029 if not self
.SkipAutoGen
or self
.Target
== 'genc':
2030 Ma
.CreateCodeFile(True)
2031 if self
.Target
== "genc":
2034 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
2035 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
2036 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
2037 del CmdListDict
[Module
.File
, Arch
]
2039 Ma
.CreateMakeFile(True)
2040 if self
.Target
== "genmake":
2042 self
.BuildModules
.append(Ma
)
2043 # Initialize all modules in tracking to 'FAIL'
2044 if Ma
.Arch
not in GlobalData
.gModuleBuildTracking
:
2045 GlobalData
.gModuleBuildTracking
[Ma
.Arch
] = dict()
2046 if Ma
not in GlobalData
.gModuleBuildTracking
[Ma
.Arch
]:
2047 GlobalData
.gModuleBuildTracking
[Ma
.Arch
][Ma
] = 'FAIL'
2048 self
.Progress
.Stop("done!")
2049 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
2050 MakeStart
= time
.time()
2051 for Ma
in self
.BuildModules
:
2052 # Generate build task for the module
2053 if not Ma
.IsBinaryModule
:
2054 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
2055 # Break build if any build thread has error
2056 if BuildTask
.HasError():
2057 # we need a full version of makefile for platform
2059 BuildTask
.WaitForComplete()
2060 self
.invalidateHash()
2061 Pa
.CreateMakeFile(False)
2062 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2063 # Start task scheduler
2064 if not BuildTask
.IsOnGoing():
2065 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
2067 # in case there's an interruption. we need a full version of makefile for platform
2068 Pa
.CreateMakeFile(False)
2069 if BuildTask
.HasError():
2070 self
.invalidateHash()
2071 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2072 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
2074 MakeContiue
= time
.time()
2078 # All modules have been put in build tasks queue. Tell task scheduler
2079 # to exit if all tasks are completed
2082 BuildTask
.WaitForComplete()
2083 self
.CreateAsBuiltInf()
2084 if GlobalData
.gBinCacheDest
:
2085 self
.UpdateBuildCache()
2086 self
.BuildModules
= []
2087 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2089 # Check for build error, and raise exception if one
2090 # has been signaled.
2092 if BuildTask
.HasError():
2093 self
.invalidateHash()
2094 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2096 # Create MAP file when Load Fix Address is enabled.
2097 if self
.Target
in ["", "all", "fds"]:
2098 for Arch
in Wa
.ArchList
:
2100 # Check whether the set fix address is above 4G for 32bit image.
2102 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2103 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")
2108 for Pa
in Wa
.AutoGenObjectList
:
2109 for Ma
in Pa
.ModuleAutoGenList
:
2112 if not Ma
.IsLibrary
:
2113 ModuleList
[Ma
.Guid
.upper()] = Ma
2115 # Rebase module to the preferred memory address before GenFds
2118 if self
.LoadFixAddress
!= 0:
2119 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2123 # Generate FD image if there's a FDF file found
2125 GenFdsStart
= time
.time()
2126 if GenFdsApi(Wa
.GenFdsCommandDict
, self
.Db
):
2127 EdkLogger
.error("build", COMMAND_FAILURE
)
2130 # Create MAP file for all platform FVs after GenFds.
2132 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2133 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2135 # Save MAP buffer into MAP file.
2137 self
._SaveMapFile
(MapBuffer
, Wa
)
2138 self
.invalidateHash()
2140 ## Generate GuidedSectionTools.txt in the FV directories.
2142 def CreateGuidedSectionToolsFile(self
):
2143 for BuildTarget
in self
.BuildTargetList
:
2144 for ToolChain
in self
.ToolChainList
:
2145 Wa
= WorkspaceAutoGen(
2162 if not os
.path
.exists(FvDir
):
2165 for Arch
in self
.ArchList
:
2166 # Build up the list of supported architectures for this build
2167 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
2169 # Look through the tool definitions for GUIDed tools
2171 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.items():
2172 if attrib
.upper().endswith('_GUID'):
2173 split
= attrib
.split('_')
2174 thisPrefix
= '_'.join(split
[0:3]) + '_'
2175 if thisPrefix
== prefix
:
2176 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
2179 path
= '_'.join(split
[0:4]) + '_PATH'
2180 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2181 path
= self
.GetFullPathOfTool(path
)
2182 guidAttribs
.append((guid
, toolName
, path
))
2184 # Write out GuidedSecTools.txt
2185 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2186 toolsFile
= open(toolsFile
, 'wt')
2187 for guidedSectionTool
in guidAttribs
:
2188 print(' '.join(guidedSectionTool
), file=toolsFile
)
2191 ## Returns the full path of the tool.
2193 def GetFullPathOfTool (self
, tool
):
2194 if os
.path
.exists(tool
):
2195 return os
.path
.realpath(tool
)
2197 # We need to search for the tool using the
2198 # PATH environment variable.
2199 for dirInPath
in os
.environ
['PATH'].split(os
.pathsep
):
2200 foundPath
= os
.path
.join(dirInPath
, tool
)
2201 if os
.path
.exists(foundPath
):
2202 return os
.path
.realpath(foundPath
)
2204 # If the tool was not found in the path then we just return
2208 ## Launch the module or platform build
2211 if not self
.ModuleFile
:
2212 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2213 self
.SpawnMode
= False
2214 self
._BuildPlatform
()
2216 self
._MultiThreadBuildPlatform
()
2217 self
.CreateGuidedSectionToolsFile()
2219 self
.SpawnMode
= False
2222 if self
.Target
== 'cleanall':
2223 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2225 def CreateAsBuiltInf(self
):
2226 for Module
in self
.BuildModules
:
2227 Module
.CreateAsBuiltInf()
2229 def UpdateBuildCache(self
):
2232 for Module
in self
.BuildModules
:
2233 Module
.CopyModuleToCache()
2234 all_mod_set
.add(Module
)
2235 for Module
in self
.HashSkipModules
:
2236 Module
.CopyModuleToCache()
2237 all_mod_set
.add(Module
)
2238 for Module
in all_mod_set
:
2239 for lib
in Module
.LibraryAutoGenList
:
2240 all_lib_set
.add(lib
)
2241 for lib
in all_lib_set
:
2242 lib
.CopyModuleToCache()
2245 self
.HashSkipModules
= []
2246 ## Do some clean-up works when error occurred
2247 def Relinquish(self
):
2248 OldLogLevel
= EdkLogger
.GetLevel()
2249 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2250 Utils
.Progressor
.Abort()
2251 if self
.SpawnMode
== True:
2253 EdkLogger
.SetLevel(OldLogLevel
)
2255 def ParseDefines(DefineList
=[]):
2257 if DefineList
is not None:
2258 for Define
in DefineList
:
2259 DefineTokenList
= Define
.split("=", 1)
2260 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2261 EdkLogger
.error('build', FORMAT_INVALID
,
2262 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2263 ExtraData
=DefineTokenList
[0])
2265 if len(DefineTokenList
) == 1:
2266 DefineDict
[DefineTokenList
[0]] = "TRUE"
2268 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2272 def SingleCheckCallback(option
, opt_str
, value
, parser
):
2273 if option
not in gParamCheck
:
2274 setattr(parser
.values
, option
.dest
, value
)
2275 gParamCheck
.append(option
)
2277 parser
.error("Option %s only allows one instance in command line!" % option
)
2279 def LogBuildTime(Time
):
2282 TimeDur
= time
.gmtime(Time
)
2283 if TimeDur
.tm_yday
> 1:
2284 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2286 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2291 ## Parse command line options
2293 # Using standard Python module optparse to parse command line option of this tool.
2295 # @retval Opt A optparse.Values object containing the parsed options
2296 # @retval Args Target of build command
2298 def MyOptionParser():
2299 Parser
= OptionParser(description
=__copyright__
, version
=__version__
, prog
="build.exe", usage
="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
2300 Parser
.add_option("-a", "--arch", action
="append", type="choice", choices
=['IA32', 'X64', 'EBC', 'ARM', 'AARCH64'], dest
="TargetArch",
2301 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.")
2302 Parser
.add_option("-p", "--platform", action
="callback", type="string", dest
="PlatformFile", callback
=SingleCheckCallback
,
2303 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
2304 Parser
.add_option("-m", "--module", action
="callback", type="string", dest
="ModuleFile", callback
=SingleCheckCallback
,
2305 help="Build the module specified by the INF file name argument.")
2306 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
2308 Parser
.add_option("-t", "--tagname", action
="append", type="string", dest
="ToolChain",
2309 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
2310 Parser
.add_option("-x", "--sku-id", action
="callback", type="string", dest
="SkuId", callback
=SingleCheckCallback
,
2311 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
2313 Parser
.add_option("-n", action
="callback", type="int", dest
="ThreadNumber", callback
=SingleCheckCallback
,
2314 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 "\
2315 "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.")
2317 Parser
.add_option("-f", "--fdf", action
="callback", type="string", dest
="FdfFile", callback
=SingleCheckCallback
,
2318 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
2319 Parser
.add_option("-r", "--rom-image", action
="append", type="string", dest
="RomImage", default
=[],
2320 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
2321 Parser
.add_option("-i", "--fv-image", action
="append", type="string", dest
="FvImage", default
=[],
2322 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
2323 Parser
.add_option("-C", "--capsule-image", action
="append", type="string", dest
="CapName", default
=[],
2324 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
2325 Parser
.add_option("-u", "--skip-autogen", action
="store_true", dest
="SkipAutoGen", help="Skip AutoGen step.")
2326 Parser
.add_option("-e", "--re-parse", action
="store_true", dest
="Reparse", help="Re-parse all meta-data files.")
2328 Parser
.add_option("-c", "--case-insensitive", action
="store_true", dest
="CaseInsensitive", default
=False, help="Don't check case of file name.")
2330 Parser
.add_option("-w", "--warning-as-error", action
="store_true", dest
="WarningAsError", help="Treat warning in tools as error.")
2331 Parser
.add_option("-j", "--log", action
="store", dest
="LogFile", help="Put log in specified file as well as on console.")
2333 Parser
.add_option("-s", "--silent", action
="store_true", type=None, dest
="SilentMode",
2334 help="Make use of silent mode of (n)make.")
2335 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
2336 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
2337 "including library instances selected, final dependency expression, "\
2338 "and warning messages, etc.")
2339 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
2340 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
2342 Parser
.add_option("-y", "--report-file", action
="store", dest
="ReportFile", help="Create/overwrite the report to the specified filename.")
2343 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
=[],
2344 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]. "\
2345 "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]")
2346 Parser
.add_option("-F", "--flag", action
="store", type="string", dest
="Flag",
2347 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. "\
2348 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
2349 "will override the setting in [BuildOptions] section of platform DSC.")
2350 Parser
.add_option("-N", "--no-cache", action
="store_true", dest
="DisableCache", default
=False, help="Disable build cache mechanism")
2351 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
2352 Parser
.add_option("--check-usage", action
="store_true", dest
="CheckUsage", default
=False, help="Check usage content of entries listed in INF file.")
2353 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
2354 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
2355 Parser
.add_option("-l", "--cmd-len", action
="store", type="int", dest
="CommandLength", help="Specify the maximum line length of build command. Default is 4096.")
2356 Parser
.add_option("--hash", action
="store_true", dest
="UseHashCache", default
=False, help="Enable hash-based caching during build process.")
2357 Parser
.add_option("--binary-destination", action
="store", type="string", dest
="BinCacheDest", help="Generate a cache of binary files in the specified directory.")
2358 Parser
.add_option("--binary-source", action
="store", type="string", dest
="BinCacheSource", help="Consume a cache of binary files from the specified directory.")
2359 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
2360 Parser
.add_option("--disable-include-path-check", action
="store_true", dest
="DisableIncludePathCheck", default
=False, help="Disable the include path check for outside of package.")
2361 (Opt
, Args
) = Parser
.parse_args()
2364 ## Tool entrance method
2366 # This method mainly dispatch specific methods per the command line options.
2367 # If no error found, return zero value so the caller of this tool can know
2368 # if it's executed successfully or not.
2370 # @retval 0 Tool was successful
2371 # @retval 1 Tool failed
2374 StartTime
= time
.time()
2376 # Initialize log system
2377 EdkLogger
.Initialize()
2378 GlobalData
.gCommand
= sys
.argv
[1:]
2380 # Parse the options and args
2382 (Option
, Target
) = MyOptionParser()
2383 GlobalData
.gOptions
= Option
2384 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2387 if Option
.verbose
is not None:
2388 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2389 elif Option
.quiet
is not None:
2390 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2391 elif Option
.debug
is not None:
2392 EdkLogger
.SetLevel(Option
.debug
+ 1)
2394 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2396 if Option
.LogFile
is not None:
2397 EdkLogger
.SetLogFile(Option
.LogFile
)
2399 if Option
.WarningAsError
== True:
2400 EdkLogger
.SetWarningAsError()
2402 if platform
.platform().find("Windows") >= 0:
2403 GlobalData
.gIsWindows
= True
2405 GlobalData
.gIsWindows
= False
2407 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2408 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2413 if len(Target
) == 0:
2415 elif len(Target
) >= 2:
2416 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2417 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2419 Target
= Target
[0].lower()
2421 if Target
not in gSupportedTarget
:
2422 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2423 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2426 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2429 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2431 Workspace
= os
.getenv("WORKSPACE")
2433 # Get files real name in workspace dir
2435 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2437 WorkingDirectory
= os
.getcwd()
2438 if not Option
.ModuleFile
:
2439 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2440 FileNum
= len(FileList
)
2442 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2443 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2445 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2447 if Option
.ModuleFile
:
2448 if os
.path
.isabs (Option
.ModuleFile
):
2449 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2450 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2451 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2452 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2454 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2456 if Option
.PlatformFile
is not None:
2457 if os
.path
.isabs (Option
.PlatformFile
):
2458 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2459 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2460 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2462 if Option
.FdfFile
is not None:
2463 if os
.path
.isabs (Option
.FdfFile
):
2464 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2465 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2466 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2467 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2469 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2471 if Option
.Flag
is not None and Option
.Flag
not in ['-c', '-s']:
2472 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2474 MyBuild
= Build(Target
, Workspace
, Option
)
2475 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2476 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2480 # All job done, no error found and no exception raised
2483 except FatalError
as X
:
2484 if MyBuild
is not None:
2485 # for multi-thread build exits safely
2486 MyBuild
.Relinquish()
2487 if Option
is not None and Option
.debug
is not None:
2488 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2489 ReturnCode
= X
.args
[0]
2490 except Warning as X
:
2491 # error from Fdf parser
2492 if MyBuild
is not None:
2493 # for multi-thread build exits safely
2494 MyBuild
.Relinquish()
2495 if Option
is not None and Option
.debug
is not None:
2496 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2498 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2499 ReturnCode
= FORMAT_INVALID
2500 except KeyboardInterrupt:
2501 ReturnCode
= ABORT_ERROR
2502 if Option
is not None and Option
.debug
is not None:
2503 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2505 if MyBuild
is not None:
2506 # for multi-thread build exits safely
2507 MyBuild
.Relinquish()
2509 # try to get the meta-file from the object causing exception
2510 Tb
= sys
.exc_info()[-1]
2511 MetaFile
= GlobalData
.gProcessingFile
2512 while Tb
is not None:
2513 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2514 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2519 "Unknown fatal error when processing [%s]" % MetaFile
,
2520 ExtraData
="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR
,
2523 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2524 ReturnCode
= CODE_ERROR
2526 Utils
.Progressor
.Abort()
2527 Utils
.ClearDuplicatedInf()
2531 MyBuild
.LaunchPostbuild()
2534 Conclusion
= "Failed"
2535 elif ReturnCode
== ABORT_ERROR
:
2536 Conclusion
= "Aborted"
2538 Conclusion
= "Failed"
2539 FinishTime
= time
.time()
2540 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2541 BuildDurationStr
= ""
2542 if BuildDuration
.tm_yday
> 1:
2543 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2545 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2546 if MyBuild
is not None:
2548 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2550 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2551 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2552 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2553 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2556 if __name__
== '__main__':
2558 ## 0-127 is a safe return range, and 1 is a standard default error
2559 if r
< 0 or r
> 127: r
= 1