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