2 # build a platform or a module
4 # Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
5 # Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.<BR>
6 # Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
7 # Copyright (c) 2020, ARM Limited. All rights reserved.<BR>
9 # SPDX-License-Identifier: BSD-2-Clause-Patent
15 from __future__
import print_function
16 from __future__
import absolute_import
17 import os
.path
as path
25 import multiprocessing
26 from threading
import Thread
,Event
,BoundedSemaphore
28 from linecache
import getlines
29 from subprocess
import Popen
,PIPE
, STDOUT
30 from collections
import OrderedDict
, defaultdict
32 from AutoGen
.PlatformAutoGen
import PlatformAutoGen
33 from AutoGen
.ModuleAutoGen
import ModuleAutoGen
34 from AutoGen
.WorkspaceAutoGen
import WorkspaceAutoGen
35 from AutoGen
.AutoGenWorker
import AutoGenWorkerInProcess
,AutoGenManager
,\
37 from AutoGen
import GenMake
38 from Common
import Misc
as Utils
40 from Common
.TargetTxtClassObject
import TargetTxtDict
41 from Common
.ToolDefClassObject
import ToolDefDict
42 from buildoptions
import MyOptionParser
43 from Common
.Misc
import PathClass
,SaveFileOnChange
,RemoveDirectory
44 from Common
.StringUtils
import NormPath
45 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
46 from Common
.BuildToolError
import *
47 from Common
.DataType
import *
48 import Common
.EdkLogger
as EdkLogger
50 from Workspace
.WorkspaceDatabase
import BuildDB
52 from BuildReport
import BuildReport
53 from GenPatchPcdTable
.GenPatchPcdTable
import PeImageClass
,parsePcdInfoFromMapFile
54 from PatchPcdValue
.PatchPcdValue
import PatchBinaryFile
56 import Common
.GlobalData
as GlobalData
57 from GenFds
.GenFds
import GenFds
, GenFdsApi
58 import multiprocessing
as mp
59 from multiprocessing
import Manager
60 from AutoGen
.DataPipe
import MemoryDataPipe
61 from AutoGen
.ModuleAutoGenHelper
import WorkSpaceInfo
, PlatformInfo
62 from GenFds
.FdfParser
import FdfParser
63 from AutoGen
.IncludesAutoGen
import IncludesAutoGen
64 from GenFds
.GenFds
import resetFdsGlobalVariable
66 ## standard targets of build command
67 gSupportedTarget
= ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
69 ## build configuration file
70 gBuildConfiguration
= "target.txt"
71 gToolsDefinition
= "tools_def.txt"
73 TemporaryTablePattern
= re
.compile(r
'^_\d+_\d+_[a-fA-F0-9]+$')
76 ## Check environment PATH variable to make sure the specified tool is found
78 # If the tool is found in the PATH, then True is returned
79 # Otherwise, False is returned
81 def IsToolInPath(tool
):
82 if 'PATHEXT' in os
.environ
:
83 extns
= os
.environ
['PATHEXT'].split(os
.path
.pathsep
)
86 for pathDir
in os
.environ
['PATH'].split(os
.path
.pathsep
):
88 if os
.path
.exists(os
.path
.join(pathDir
, tool
+ ext
)):
92 ## Check environment variables
94 # Check environment variables that must be set for build. Currently they are
96 # WORKSPACE The directory all packages/platforms start from
97 # EDK_TOOLS_PATH The directory contains all tools needed by the build
98 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
100 # If any of above environment variable is not set or has error, the build
103 def CheckEnvVariable():
105 if "WORKSPACE" not in os
.environ
:
106 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
107 ExtraData
="WORKSPACE")
109 WorkspaceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["WORKSPACE"]))
110 if not os
.path
.exists(WorkspaceDir
):
111 EdkLogger
.error("build", FILE_NOT_FOUND
, "WORKSPACE doesn't exist", ExtraData
=WorkspaceDir
)
112 elif ' ' in WorkspaceDir
:
113 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in WORKSPACE path",
114 ExtraData
=WorkspaceDir
)
115 os
.environ
["WORKSPACE"] = WorkspaceDir
117 # set multiple workspace
118 PackagesPath
= os
.getenv("PACKAGES_PATH")
119 mws
.setWs(WorkspaceDir
, PackagesPath
)
120 if mws
.PACKAGES_PATH
:
121 for Path
in mws
.PACKAGES_PATH
:
122 if not os
.path
.exists(Path
):
123 EdkLogger
.error("build", FILE_NOT_FOUND
, "One Path in PACKAGES_PATH doesn't exist", ExtraData
=Path
)
125 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in PACKAGES_PATH", ExtraData
=Path
)
128 os
.environ
["EDK_TOOLS_PATH"] = os
.path
.normcase(os
.environ
["EDK_TOOLS_PATH"])
130 # check EDK_TOOLS_PATH
131 if "EDK_TOOLS_PATH" not in os
.environ
:
132 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
133 ExtraData
="EDK_TOOLS_PATH")
136 if "PATH" not in os
.environ
:
137 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
140 GlobalData
.gWorkspace
= WorkspaceDir
142 GlobalData
.gGlobalDefines
["WORKSPACE"] = WorkspaceDir
143 GlobalData
.gGlobalDefines
["EDK_TOOLS_PATH"] = os
.environ
["EDK_TOOLS_PATH"]
145 ## Get normalized file path
147 # Convert the path to be local format, and remove the WORKSPACE path at the
148 # beginning if the file path is given in full path.
150 # @param FilePath File path to be normalized
151 # @param Workspace Workspace path which the FilePath will be checked against
153 # @retval string The normalized file path
155 def NormFile(FilePath
, Workspace
):
156 # check if the path is absolute or relative
157 if os
.path
.isabs(FilePath
):
158 FileFullPath
= os
.path
.normpath(FilePath
)
160 FileFullPath
= os
.path
.normpath(mws
.join(Workspace
, FilePath
))
161 Workspace
= mws
.getWs(Workspace
, FilePath
)
163 # check if the file path exists or not
164 if not os
.path
.isfile(FileFullPath
):
165 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath
)
167 # remove workspace directory from the beginning part of the file path
168 if Workspace
[-1] in ["\\", "/"]:
169 return FileFullPath
[len(Workspace
):]
171 return FileFullPath
[(len(Workspace
) + 1):]
173 ## Get the output of an external program
175 # This is the entrance method of thread reading output of an external program and
176 # putting them in STDOUT/STDERR of current program.
178 # @param From The stream message read from
179 # @param To The stream message put on
180 # @param ExitFlag The flag used to indicate stopping reading
182 def ReadMessage(From
, To
, ExitFlag
,MemTo
=None):
184 # read one line a time
185 Line
= From
.readline()
186 # empty string means "end"
187 if Line
is not None and Line
!= b
"":
188 LineStr
= Line
.rstrip().decode(encoding
='utf-8', errors
='ignore')
189 if MemTo
is not None:
190 if "Note: including file:" == LineStr
.lstrip()[:21]:
191 MemTo
.append(LineStr
)
194 MemTo
.append(LineStr
)
202 class MakeSubProc(Popen
):
203 def __init__(self
,*args
, **argv
):
204 super(MakeSubProc
,self
).__init
__(*args
, **argv
)
207 ## Launch an external program
209 # This method will call subprocess.Popen to execute an external program with
210 # given options in specified directory. Because of the dead-lock issue during
211 # redirecting output of the external program, threads are used to to do the
214 # @param Command A list or string containing the call of the program
215 # @param WorkingDir The directory in which the program will be running
217 def LaunchCommand(Command
, WorkingDir
,ModuleAuto
= None):
218 BeginTime
= time
.time()
219 # if working directory doesn't exist, Popen() will raise an exception
220 if not os
.path
.isdir(WorkingDir
):
221 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=WorkingDir
)
223 # Command is used as the first Argument in following Popen().
224 # It could be a string or sequence. We find that if command is a string in following Popen(),
225 # ubuntu may fail with an error message that the command is not found.
226 # So here we may need convert command from string to list instance.
227 if platform
.system() != 'Windows':
228 if not isinstance(Command
, list):
229 Command
= Command
.split()
230 Command
= ' '.join(Command
)
233 EndOfProcedure
= None
236 Proc
= MakeSubProc(Command
, stdout
=PIPE
, stderr
=STDOUT
, env
=os
.environ
, cwd
=WorkingDir
, bufsize
=-1, shell
=True)
238 # launch two threads to read the STDOUT and STDERR
239 EndOfProcedure
= Event()
240 EndOfProcedure
.clear()
242 StdOutThread
= Thread(target
=ReadMessage
, args
=(Proc
.stdout
, EdkLogger
.info
, EndOfProcedure
,Proc
.ProcOut
))
243 StdOutThread
.setName("STDOUT-Redirector")
244 StdOutThread
.setDaemon(False)
248 # waiting for program exit
250 except: # in case of aborting
251 # terminate the threads redirecting the program output
252 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
253 if EndOfProcedure
is not None:
256 if not isinstance(Command
, type("")):
257 Command
= " ".join(Command
)
258 EdkLogger
.error("build", COMMAND_FAILURE
, "Failed to start command", ExtraData
="%s [%s]" % (Command
, WorkingDir
))
263 # check the return code of the program
264 if Proc
.returncode
!= 0:
265 if not isinstance(Command
, type("")):
266 Command
= " ".join(Command
)
267 # print out the Response file and its content when make failure
268 RespFile
= os
.path
.join(WorkingDir
, 'OUTPUT', 'respfilelist.txt')
269 if os
.path
.isfile(RespFile
):
271 RespContent
= f
.read()
273 EdkLogger
.info(RespContent
)
275 EdkLogger
.error("build", COMMAND_FAILURE
, ExtraData
="%s [%s]" % (Command
, WorkingDir
))
277 iau
= IncludesAutoGen(WorkingDir
,ModuleAuto
)
278 if ModuleAuto
.ToolChainFamily
== TAB_COMPILER_MSFT
:
279 iau
.CreateDepsFileForMsvc(Proc
.ProcOut
)
281 iau
.UpdateDepsFileforNonMsvc()
282 iau
.UpdateDepsFileforTrim()
283 iau
.CreateModuleDeps()
284 iau
.CreateDepsInclude()
285 iau
.CreateDepsTarget()
286 return "%dms" % (int(round((time
.time() - BeginTime
) * 1000)))
288 ## The smallest unit that can be built in multi-thread build mode
290 # This is the base class of build unit. The "Obj" parameter must provide
291 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
294 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
299 # @param self The object pointer
300 # @param Obj The object the build is working on
301 # @param Target The build target name, one of gSupportedTarget
302 # @param Dependency The BuildUnit(s) which must be completed in advance
303 # @param WorkingDir The directory build command starts in
305 def __init__(self
, Obj
, BuildCommand
, Target
, Dependency
, WorkingDir
="."):
306 self
.BuildObject
= Obj
307 self
.Dependency
= Dependency
308 self
.WorkingDir
= WorkingDir
310 self
.BuildCommand
= BuildCommand
312 EdkLogger
.error("build", OPTION_MISSING
,
313 "No build command found for this module. "
314 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
315 (Obj
.BuildTarget
, Obj
.ToolChain
, Obj
.Arch
),
321 # It just returns the string representation of self.BuildObject
323 # @param self The object pointer
326 return str(self
.BuildObject
)
328 ## "==" operator method
330 # It just compares self.BuildObject with "Other". So self.BuildObject must
331 # provide its own __eq__() method.
333 # @param self The object pointer
334 # @param Other The other BuildUnit object compared to
336 def __eq__(self
, Other
):
337 return Other
and self
.BuildObject
== Other
.BuildObject \
338 and Other
.BuildObject \
339 and self
.BuildObject
.Arch
== Other
.BuildObject
.Arch
343 # It just returns the hash value of self.BuildObject which must be hashable.
345 # @param self The object pointer
348 return hash(self
.BuildObject
) + hash(self
.BuildObject
.Arch
)
351 return repr(self
.BuildObject
)
353 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
355 # This class is for module build by nmake/make build system. The "Obj" parameter
356 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
357 # be make units missing build.
359 # Currently the "Obj" should be only ModuleAutoGen object.
361 class ModuleMakeUnit(BuildUnit
):
364 # @param self The object pointer
365 # @param Obj The ModuleAutoGen object the build is working on
366 # @param Target The build target name, one of gSupportedTarget
368 def __init__(self
, Obj
, BuildCommand
,Target
):
369 Dependency
= [ModuleMakeUnit(La
, BuildCommand
,Target
) for La
in Obj
.LibraryAutoGenList
]
370 BuildUnit
.__init
__(self
, Obj
, BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
371 if Target
in [None, "", "all"]:
372 self
.Target
= "tbuild"
374 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
376 # This class is for platform build by nmake/make build system. The "Obj" parameter
377 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
378 # be make units missing build.
380 # Currently the "Obj" should be only PlatformAutoGen object.
382 class PlatformMakeUnit(BuildUnit
):
385 # @param self The object pointer
386 # @param Obj The PlatformAutoGen object the build is working on
387 # @param Target The build target name, one of gSupportedTarget
389 def __init__(self
, Obj
, BuildCommand
, Target
):
390 Dependency
= [ModuleMakeUnit(Lib
, BuildCommand
, Target
) for Lib
in self
.BuildObject
.LibraryAutoGenList
]
391 Dependency
.extend([ModuleMakeUnit(Mod
, BuildCommand
,Target
) for Mod
in self
.BuildObject
.ModuleAutoGenList
])
392 BuildUnit
.__init
__(self
, Obj
, BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
394 ## The class representing the task of a module build or platform build
396 # This class manages the build tasks in multi-thread build mode. Its jobs include
397 # scheduling thread running, catching thread error, monitor the thread status, etc.
400 # queue for tasks waiting for schedule
401 _PendingQueue
= OrderedDict()
402 _PendingQueueLock
= threading
.Lock()
404 # queue for tasks ready for running
405 _ReadyQueue
= OrderedDict()
406 _ReadyQueueLock
= threading
.Lock()
408 # queue for run tasks
409 _RunningQueue
= OrderedDict()
410 _RunningQueueLock
= threading
.Lock()
412 # queue containing all build tasks, in case duplicate build
413 _TaskQueue
= OrderedDict()
415 # flag indicating error occurs in a running thread
416 _ErrorFlag
= threading
.Event()
420 # BoundedSemaphore object used to control the number of running threads
423 # flag indicating if the scheduler is started or not
424 _SchedulerStopped
= threading
.Event()
425 _SchedulerStopped
.set()
427 ## Start the task scheduler thread
429 # @param MaxThreadNumber The maximum thread number
430 # @param ExitFlag Flag used to end the scheduler
433 def StartScheduler(MaxThreadNumber
, ExitFlag
):
434 SchedulerThread
= Thread(target
=BuildTask
.Scheduler
, args
=(MaxThreadNumber
, ExitFlag
))
435 SchedulerThread
.setName("Build-Task-Scheduler")
436 SchedulerThread
.setDaemon(False)
437 SchedulerThread
.start()
438 # wait for the scheduler to be started, especially useful in Linux
439 while not BuildTask
.IsOnGoing():
444 # @param MaxThreadNumber The maximum thread number
445 # @param ExitFlag Flag used to end the scheduler
448 def Scheduler(MaxThreadNumber
, ExitFlag
):
449 BuildTask
._SchedulerStopped
.clear()
451 # use BoundedSemaphore to control the maximum running threads
452 BuildTask
._Thread
= BoundedSemaphore(MaxThreadNumber
)
454 # scheduling loop, which will exits when no pending/ready task and
455 # indicated to do so, or there's error in running thread
457 while (len(BuildTask
._PendingQueue
) > 0 or len(BuildTask
._ReadyQueue
) > 0 \
458 or not ExitFlag
.isSet()) and not BuildTask
._ErrorFlag
.isSet():
459 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Pending Queue (%d), Ready Queue (%d)"
460 % (len(BuildTask
._PendingQueue
), len(BuildTask
._ReadyQueue
)))
462 # get all pending tasks
463 BuildTask
._PendingQueueLock
.acquire()
464 BuildObjectList
= list(BuildTask
._PendingQueue
.keys())
466 # check if their dependency is resolved, and if true, move them
469 for BuildObject
in BuildObjectList
:
470 Bt
= BuildTask
._PendingQueue
[BuildObject
]
472 BuildTask
._ReadyQueue
[BuildObject
] = BuildTask
._PendingQueue
.pop(BuildObject
)
473 BuildTask
._PendingQueueLock
.release()
475 # launch build thread until the maximum number of threads is reached
476 while not BuildTask
._ErrorFlag
.isSet():
477 # empty ready queue, do nothing further
478 if len(BuildTask
._ReadyQueue
) == 0:
481 # wait for active thread(s) exit
482 BuildTask
._Thread
.acquire(True)
484 # start a new build thread
485 Bo
, Bt
= BuildTask
._ReadyQueue
.popitem()
487 # move into running queue
488 BuildTask
._RunningQueueLock
.acquire()
489 BuildTask
._RunningQueue
[Bo
] = Bt
490 BuildTask
._RunningQueueLock
.release()
499 # wait for all running threads exit
500 if BuildTask
._ErrorFlag
.isSet():
501 EdkLogger
.quiet("\nWaiting for all build threads exit...")
502 # while not BuildTask._ErrorFlag.isSet() and \
503 while len(BuildTask
._RunningQueue
) > 0:
504 EdkLogger
.verbose("Waiting for thread ending...(%d)" % len(BuildTask
._RunningQueue
))
505 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Threads [%s]" % ", ".join(Th
.getName() for Th
in threading
.enumerate()))
508 except BaseException
as X
:
510 # TRICK: hide the output of threads left running, so that the user can
511 # catch the error message easily
513 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
514 BuildTask
._ErrorFlag
.set()
515 BuildTask
._ErrorMessage
= "build thread scheduler error\n\t%s" % str(X
)
517 BuildTask
._PendingQueue
.clear()
518 BuildTask
._ReadyQueue
.clear()
519 BuildTask
._RunningQueue
.clear()
520 BuildTask
._TaskQueue
.clear()
521 BuildTask
._SchedulerStopped
.set()
523 ## Wait for all running method exit
526 def WaitForComplete():
527 BuildTask
._SchedulerStopped
.wait()
529 ## Check if the scheduler is running or not
533 return not BuildTask
._SchedulerStopped
.isSet()
538 if BuildTask
.IsOnGoing():
539 BuildTask
._ErrorFlag
.set()
540 BuildTask
.WaitForComplete()
542 ## Check if there's error in running thread
544 # Since the main thread cannot catch exceptions in other thread, we have to
545 # use threading.Event to communicate this formation to main thread.
549 return BuildTask
._ErrorFlag
.isSet()
551 ## Get error message in running thread
553 # Since the main thread cannot catch exceptions in other thread, we have to
554 # use a static variable to communicate this message to main thread.
557 def GetErrorMessage():
558 return BuildTask
._ErrorMessage
560 ## Factory method to create a BuildTask object
562 # This method will check if a module is building or has been built. And if
563 # true, just return the associated BuildTask object in the _TaskQueue. If
564 # not, create and return a new BuildTask object. The new BuildTask object
565 # will be appended to the _PendingQueue for scheduling later.
567 # @param BuildItem A BuildUnit object representing a build object
568 # @param Dependency The dependent build object of BuildItem
571 def New(BuildItem
, Dependency
=None):
572 if BuildItem
in BuildTask
._TaskQueue
:
573 Bt
= BuildTask
._TaskQueue
[BuildItem
]
577 Bt
._Init
(BuildItem
, Dependency
)
578 BuildTask
._TaskQueue
[BuildItem
] = Bt
580 BuildTask
._PendingQueueLock
.acquire()
581 BuildTask
._PendingQueue
[BuildItem
] = Bt
582 BuildTask
._PendingQueueLock
.release()
586 ## The real constructor of BuildTask
588 # @param BuildItem A BuildUnit object representing a build object
589 # @param Dependency The dependent build object of BuildItem
591 def _Init(self
, BuildItem
, Dependency
=None):
592 self
.BuildItem
= BuildItem
594 self
.DependencyList
= []
595 if Dependency
is None:
596 Dependency
= BuildItem
.Dependency
598 Dependency
.extend(BuildItem
.Dependency
)
599 self
.AddDependency(Dependency
)
600 # flag indicating build completes, used to avoid unnecessary re-build
601 self
.CompleteFlag
= False
603 ## Check if all dependent build tasks are completed or not
607 for Dep
in self
.DependencyList
:
608 if Dep
.CompleteFlag
== True:
615 ## Add dependent build task
617 # @param Dependency The list of dependent build objects
619 def AddDependency(self
, Dependency
):
620 for Dep
in Dependency
:
621 if not Dep
.BuildObject
.IsBinaryModule
and not Dep
.BuildObject
.CanSkipbyCache(GlobalData
.gModuleCacheHit
):
622 self
.DependencyList
.append(BuildTask
.New(Dep
)) # BuildTask list
624 ## The thread wrapper of LaunchCommand function
626 # @param Command A list or string contains the call of the command
627 # @param WorkingDir The directory in which the program will be running
629 def _CommandThread(self
, Command
, WorkingDir
):
631 self
.BuildItem
.BuildObject
.BuildTime
= LaunchCommand(Command
, WorkingDir
,self
.BuildItem
.BuildObject
)
632 self
.CompleteFlag
= True
634 # Run hash operation post dependency to account for libs
635 # Run if --hash or --binary-destination
636 if GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
637 self
.BuildItem
.BuildObject
.GenModuleHash()
638 if GlobalData
.gBinCacheDest
:
639 self
.BuildItem
.BuildObject
.GenCMakeHash()
643 # TRICK: hide the output of threads left running, so that the user can
644 # catch the error message easily
646 if not BuildTask
._ErrorFlag
.isSet():
647 GlobalData
.gBuildingModule
= "%s [%s, %s, %s]" % (str(self
.BuildItem
.BuildObject
),
648 self
.BuildItem
.BuildObject
.Arch
,
649 self
.BuildItem
.BuildObject
.ToolChain
,
650 self
.BuildItem
.BuildObject
.BuildTarget
652 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
653 BuildTask
._ErrorFlag
.set()
654 BuildTask
._ErrorMessage
= "%s broken\n %s [%s]" % \
655 (threading
.currentThread().getName(), Command
, WorkingDir
)
657 # indicate there's a thread is available for another build task
658 BuildTask
._RunningQueueLock
.acquire()
659 BuildTask
._RunningQueue
.pop(self
.BuildItem
)
660 BuildTask
._RunningQueueLock
.release()
661 BuildTask
._Thread
.release()
663 ## Start build task thread
666 EdkLogger
.quiet("Building ... %s" % repr(self
.BuildItem
))
667 Command
= self
.BuildItem
.BuildCommand
+ [self
.BuildItem
.Target
]
668 self
.BuildTread
= Thread(target
=self
._CommandThread
, args
=(Command
, self
.BuildItem
.WorkingDir
))
669 self
.BuildTread
.setName("build thread")
670 self
.BuildTread
.setDaemon(False)
671 self
.BuildTread
.start()
673 ## The class contains the information related to EFI image
678 # Constructor will load all required image information.
680 # @param BaseName The full file path of image.
681 # @param Guid The GUID for image.
682 # @param Arch Arch of this image.
683 # @param OutputDir The output directory for image.
684 # @param DebugDir The debug directory for image.
685 # @param ImageClass PeImage Information
687 def __init__(self
, BaseName
, Guid
, Arch
, OutputDir
, DebugDir
, ImageClass
):
688 self
.BaseName
= BaseName
691 self
.OutputDir
= OutputDir
692 self
.DebugDir
= DebugDir
693 self
.Image
= ImageClass
694 self
.Image
.Size
= (self
.Image
.Size
// 0x1000 + 1) * 0x1000
696 ## The class implementing the EDK2 build process
698 # The build process includes:
699 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
700 # 2. Parse DSC file of active platform
701 # 3. Parse FDF file if any
702 # 4. Establish build database, including parse all other files (module, package)
703 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
704 # 6. Call build command
709 # Constructor will load all necessary configurations, parse platform, modules
710 # and packages and the establish a database for AutoGen.
712 # @param Target The build command target, one of gSupportedTarget
713 # @param WorkspaceDir The directory of workspace
714 # @param BuildOptions Build options passed from command line
716 def __init__(self
, Target
, WorkspaceDir
, BuildOptions
,log_q
):
717 self
.WorkspaceDir
= WorkspaceDir
719 self
.PlatformFile
= BuildOptions
.PlatformFile
720 self
.ModuleFile
= BuildOptions
.ModuleFile
721 self
.ArchList
= BuildOptions
.TargetArch
722 self
.ToolChainList
= BuildOptions
.ToolChain
723 self
.BuildTargetList
= BuildOptions
.BuildTarget
724 self
.Fdf
= BuildOptions
.FdfFile
725 self
.FdList
= BuildOptions
.RomImage
726 self
.FvList
= BuildOptions
.FvImage
727 self
.CapList
= BuildOptions
.CapName
728 self
.SilentMode
= BuildOptions
.SilentMode
729 self
.ThreadNumber
= 1
730 self
.SkipAutoGen
= BuildOptions
.SkipAutoGen
731 self
.Reparse
= BuildOptions
.Reparse
732 self
.SkuId
= BuildOptions
.SkuId
734 GlobalData
.gSKUID_CMD
= self
.SkuId
735 self
.ConfDirectory
= BuildOptions
.ConfDirectory
736 self
.SpawnMode
= True
737 self
.BuildReport
= BuildReport(BuildOptions
.ReportFile
, BuildOptions
.ReportType
)
741 self
.MakeFileName
= ""
742 TargetObj
= TargetTxtDict()
743 ToolDefObj
= ToolDefDict((os
.path
.join(os
.getenv("WORKSPACE"),"Conf")))
744 self
.TargetTxt
= TargetObj
.Target
745 self
.ToolDef
= ToolDefObj
.ToolDef
746 GlobalData
.BuildOptionPcd
= BuildOptions
.OptionPcd
if BuildOptions
.OptionPcd
else []
747 #Set global flag for build mode
748 GlobalData
.gIgnoreSource
= BuildOptions
.IgnoreSources
749 GlobalData
.gUseHashCache
= BuildOptions
.UseHashCache
750 GlobalData
.gBinCacheDest
= BuildOptions
.BinCacheDest
751 GlobalData
.gBinCacheSource
= BuildOptions
.BinCacheSource
752 GlobalData
.gEnableGenfdsMultiThread
= not BuildOptions
.NoGenfdsMultiThread
753 GlobalData
.gDisableIncludePathCheck
= BuildOptions
.DisableIncludePathCheck
755 if GlobalData
.gBinCacheDest
and not GlobalData
.gUseHashCache
:
756 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination must be used together with --hash.")
758 if GlobalData
.gBinCacheSource
and not GlobalData
.gUseHashCache
:
759 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-source must be used together with --hash.")
761 if GlobalData
.gBinCacheDest
and GlobalData
.gBinCacheSource
:
762 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination can not be used together with --binary-source.")
764 if GlobalData
.gBinCacheSource
:
765 BinCacheSource
= os
.path
.normpath(GlobalData
.gBinCacheSource
)
766 if not os
.path
.isabs(BinCacheSource
):
767 BinCacheSource
= mws
.join(self
.WorkspaceDir
, BinCacheSource
)
768 GlobalData
.gBinCacheSource
= BinCacheSource
770 if GlobalData
.gBinCacheSource
is not None:
771 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-source.")
773 if GlobalData
.gBinCacheDest
:
774 BinCacheDest
= os
.path
.normpath(GlobalData
.gBinCacheDest
)
775 if not os
.path
.isabs(BinCacheDest
):
776 BinCacheDest
= mws
.join(self
.WorkspaceDir
, BinCacheDest
)
777 GlobalData
.gBinCacheDest
= BinCacheDest
779 if GlobalData
.gBinCacheDest
is not None:
780 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-destination.")
782 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(GlobalData
.gConfDirectory
, GlobalData
.gDatabasePath
))
783 if not os
.path
.exists(os
.path
.join(GlobalData
.gConfDirectory
, '.cache')):
784 os
.makedirs(os
.path
.join(GlobalData
.gConfDirectory
, '.cache'))
786 self
.BuildDatabase
= self
.Db
.BuildObject
788 self
.ToolChainFamily
= None
789 self
.LoadFixAddress
= 0
790 self
.UniFlag
= BuildOptions
.Flag
791 self
.BuildModules
= []
792 self
.HashSkipModules
= []
794 self
.LaunchPrebuildFlag
= False
795 self
.PlatformBuildPath
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PlatformBuild')
796 if BuildOptions
.CommandLength
:
797 GlobalData
.gCommandMaxLength
= BuildOptions
.CommandLength
799 # print dot character during doing some time-consuming work
800 self
.Progress
= Utils
.Progressor()
801 # print current build environment and configuration
802 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
803 if "PACKAGES_PATH" in os
.environ
:
804 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
805 EdkLogger
.quiet("%-16s = %s" % ("PACKAGES_PATH", os
.path
.normcase(os
.path
.normpath(os
.environ
["PACKAGES_PATH"]))))
806 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
807 if "EDK_TOOLS_BIN" in os
.environ
:
808 # Print the same path style with WORKSPACE env.
809 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_TOOLS_BIN"]))))
810 EdkLogger
.quiet("%-16s = %s" % ("CONF_PATH", GlobalData
.gConfDirectory
))
811 if "PYTHON3_ENABLE" in os
.environ
:
812 PYTHON3_ENABLE
= os
.environ
["PYTHON3_ENABLE"]
813 if PYTHON3_ENABLE
!= "TRUE":
814 PYTHON3_ENABLE
= "FALSE"
815 EdkLogger
.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE
))
816 if "PYTHON_COMMAND" in os
.environ
:
817 EdkLogger
.quiet("%-16s = %s" % ("PYTHON_COMMAND", os
.environ
["PYTHON_COMMAND"]))
821 EdkLogger
.quiet("%-16s = %s" % ("PREBUILD", self
.Prebuild
))
823 EdkLogger
.quiet("%-16s = %s" % ("POSTBUILD", self
.Postbuild
))
825 self
.LaunchPrebuild()
826 TargetObj
= TargetTxtDict()
827 ToolDefObj
= ToolDefDict((os
.path
.join(os
.getenv("WORKSPACE"), "Conf")))
828 self
.TargetTxt
= TargetObj
.Target
829 self
.ToolDef
= ToolDefObj
.ToolDef
830 if not (self
.LaunchPrebuildFlag
and os
.path
.exists(self
.PlatformBuildPath
)):
833 self
.AutoGenMgr
= None
835 os
.chdir(self
.WorkspaceDir
)
837 GlobalData
.file_lock
= mp
.Lock()
838 # Init cache data for local only
839 GlobalData
.gPackageHashFile
= dict()
840 GlobalData
.gModulePreMakeCacheStatus
= dict()
841 GlobalData
.gModuleMakeCacheStatus
= dict()
842 GlobalData
.gHashChainStatus
= dict()
843 GlobalData
.gCMakeHashFile
= dict()
844 GlobalData
.gModuleHashFile
= dict()
845 GlobalData
.gFileHashDict
= dict()
846 GlobalData
.gModuleAllCacheStatus
= set()
847 GlobalData
.gModuleCacheHit
= set()
849 def StartAutoGen(self
,mqueue
, DataPipe
,SkipAutoGen
,PcdMaList
,cqueue
):
853 feedback_q
= mp
.Queue()
854 error_event
= mp
.Event()
855 FfsCmd
= DataPipe
.Get("FfsCommand")
858 GlobalData
.FfsCmd
= FfsCmd
859 auto_workers
= [AutoGenWorkerInProcess(mqueue
,DataPipe
.dump_file
,feedback_q
,GlobalData
.file_lock
,cqueue
,self
.log_q
,error_event
) for _
in range(self
.ThreadNumber
)]
860 self
.AutoGenMgr
= AutoGenManager(auto_workers
,feedback_q
,error_event
)
861 self
.AutoGenMgr
.start()
862 for w
in auto_workers
:
864 if PcdMaList
is not None:
865 for PcdMa
in PcdMaList
:
866 # SourceFileList calling sequence impact the makefile string sequence.
867 # Create cached SourceFileList here to unify its calling sequence for both
868 # CanSkipbyPreMakeCache and CreateCodeFile/CreateMakeFile.
869 RetVal
= PcdMa
.SourceFileList
870 # Force cache miss for PCD driver
871 if GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheDest
and self
.Target
in [None, "", "all"]:
872 cqueue
.put((PcdMa
.MetaFile
.Path
, PcdMa
.Arch
, "PreMakeCache", False))
874 PcdMa
.CreateCodeFile(False)
875 PcdMa
.CreateMakeFile(False,GenFfsList
= DataPipe
.Get("FfsCommand").get((PcdMa
.MetaFile
.Path
, PcdMa
.Arch
),[]))
877 # Force cache miss for PCD driver
878 if GlobalData
.gBinCacheSource
and self
.Target
in [None, "", "all"]:
879 cqueue
.put((PcdMa
.MetaFile
.Path
, PcdMa
.Arch
, "MakeCache", False))
881 self
.AutoGenMgr
.join()
882 rt
= self
.AutoGenMgr
.Status
887 except FatalError
as e
:
888 return False, e
.args
[0]
890 return False, UNKNOWN_ERROR
892 ## Load configuration
894 # This method will parse target.txt and get the build configurations.
896 def LoadConfiguration(self
):
898 # if no ARCH given in command line, get it from target.txt
899 if not self
.ArchList
:
900 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET_ARCH
]
901 self
.ArchList
= tuple(self
.ArchList
)
903 # if no build target given in command line, get it from target.txt
904 if not self
.BuildTargetList
:
905 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
907 # if no tool chain given in command line, get it from target.txt
908 if not self
.ToolChainList
:
909 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
910 if self
.ToolChainList
is None or len(self
.ToolChainList
) == 0:
911 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
913 # check if the tool chains are defined or not
914 NewToolChainList
= []
915 for ToolChain
in self
.ToolChainList
:
916 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
917 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
919 NewToolChainList
.append(ToolChain
)
920 # if no tool chain available, break the build
921 if len(NewToolChainList
) == 0:
922 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
923 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
925 self
.ToolChainList
= NewToolChainList
928 ToolDefinition
= self
.ToolDef
.ToolsDefTxtDatabase
929 for Tool
in self
.ToolChainList
:
930 if TAB_TOD_DEFINES_FAMILY
not in ToolDefinition
or Tool
not in ToolDefinition
[TAB_TOD_DEFINES_FAMILY
] \
931 or not ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
]:
932 EdkLogger
.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool
)
933 ToolChainFamily
.append(TAB_COMPILER_MSFT
)
935 ToolChainFamily
.append(ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
])
936 self
.ToolChainFamily
= ToolChainFamily
938 if not self
.PlatformFile
:
939 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
941 # Try to find one in current directory
942 WorkingDirectory
= os
.getcwd()
943 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
944 FileNum
= len(FileList
)
946 EdkLogger
.error("build", OPTION_MISSING
,
947 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
949 PlatformFile
= FileList
[0]
951 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
952 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
954 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
955 self
.ThreadNumber
= ThreadNum()
956 ## Initialize build configuration
958 # This method will parse DSC file and merge the configurations from
959 # command line and target.txt, then get the final build configurations.
962 # parse target.txt, tools_def.txt, and platform file
963 self
.LoadConfiguration()
965 # Allow case-insensitive for those from command line or configuration file
966 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
968 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
971 def InitPreBuild(self
):
972 self
.LoadConfiguration()
973 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
975 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
976 if self
.BuildTargetList
:
977 GlobalData
.gGlobalDefines
['TARGET'] = self
.BuildTargetList
[0]
979 GlobalData
.gGlobalDefines
['ARCH'] = self
.ArchList
[0]
980 if self
.ToolChainList
:
981 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = self
.ToolChainList
[0]
982 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = self
.ToolChainList
[0]
983 if self
.ToolChainFamily
:
984 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[0]
985 if 'PREBUILD' in GlobalData
.gCommandLineDefines
:
986 self
.Prebuild
= GlobalData
.gCommandLineDefines
.get('PREBUILD')
989 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
990 self
.Prebuild
= str(Platform
.Prebuild
)
994 # Evaluate all arguments and convert arguments that are WORKSPACE
995 # relative paths to absolute paths. Filter arguments that look like
996 # flags or do not follow the file/dir naming rules to avoid false
997 # positives on this conversion.
999 for Arg
in self
.Prebuild
.split():
1001 # Do not modify Arg if it looks like a flag or an absolute file path
1003 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1004 PrebuildList
.append(Arg
)
1007 # Do not modify Arg if it does not look like a Workspace relative
1008 # path that starts with a valid package directory name
1010 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1011 PrebuildList
.append(Arg
)
1014 # If Arg looks like a WORKSPACE relative path, then convert to an
1015 # absolute path and check to see if the file exists.
1017 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1018 if os
.path
.isfile(Temp
):
1020 PrebuildList
.append(Arg
)
1021 self
.Prebuild
= ' '.join(PrebuildList
)
1022 self
.Prebuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1024 def InitPostBuild(self
):
1025 if 'POSTBUILD' in GlobalData
.gCommandLineDefines
:
1026 self
.Postbuild
= GlobalData
.gCommandLineDefines
.get('POSTBUILD')
1028 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
1029 self
.Postbuild
= str(Platform
.Postbuild
)
1033 # Evaluate all arguments and convert arguments that are WORKSPACE
1034 # relative paths to absolute paths. Filter arguments that look like
1035 # flags or do not follow the file/dir naming rules to avoid false
1036 # positives on this conversion.
1038 for Arg
in self
.Postbuild
.split():
1040 # Do not modify Arg if it looks like a flag or an absolute file path
1042 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1043 PostbuildList
.append(Arg
)
1046 # Do not modify Arg if it does not look like a Workspace relative
1047 # path that starts with a valid package directory name
1049 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1050 PostbuildList
.append(Arg
)
1053 # If Arg looks like a WORKSPACE relative path, then convert to an
1054 # absolute path and check to see if the file exists.
1056 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1057 if os
.path
.isfile(Temp
):
1059 PostbuildList
.append(Arg
)
1060 self
.Postbuild
= ' '.join(PostbuildList
)
1061 self
.Postbuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1063 def PassCommandOption(self
, BuildTarget
, TargetArch
, ToolChain
, PlatformFile
, Target
):
1065 if GlobalData
.gCommand
and isinstance(GlobalData
.gCommand
, list):
1066 BuildStr
+= ' ' + ' '.join(GlobalData
.gCommand
)
1069 ToolChainFlag
= False
1070 PlatformFileFlag
= False
1072 if GlobalData
.gOptions
and not GlobalData
.gOptions
.BuildTarget
:
1074 if GlobalData
.gOptions
and not GlobalData
.gOptions
.TargetArch
:
1076 if GlobalData
.gOptions
and not GlobalData
.gOptions
.ToolChain
:
1077 ToolChainFlag
= True
1078 if GlobalData
.gOptions
and not GlobalData
.gOptions
.PlatformFile
:
1079 PlatformFileFlag
= True
1081 if TargetFlag
and BuildTarget
:
1082 if isinstance(BuildTarget
, list) or isinstance(BuildTarget
, tuple):
1083 BuildStr
+= ' -b ' + ' -b '.join(BuildTarget
)
1084 elif isinstance(BuildTarget
, str):
1085 BuildStr
+= ' -b ' + BuildTarget
1086 if ArchFlag
and TargetArch
:
1087 if isinstance(TargetArch
, list) or isinstance(TargetArch
, tuple):
1088 BuildStr
+= ' -a ' + ' -a '.join(TargetArch
)
1089 elif isinstance(TargetArch
, str):
1090 BuildStr
+= ' -a ' + TargetArch
1091 if ToolChainFlag
and ToolChain
:
1092 if isinstance(ToolChain
, list) or isinstance(ToolChain
, tuple):
1093 BuildStr
+= ' -t ' + ' -t '.join(ToolChain
)
1094 elif isinstance(ToolChain
, str):
1095 BuildStr
+= ' -t ' + ToolChain
1096 if PlatformFileFlag
and PlatformFile
:
1097 if isinstance(PlatformFile
, list) or isinstance(PlatformFile
, tuple):
1098 BuildStr
+= ' -p ' + ' -p '.join(PlatformFile
)
1099 elif isinstance(PlatformFile
, str):
1100 BuildStr
+= ' -p' + PlatformFile
1101 BuildStr
+= ' --conf=' + GlobalData
.gConfDirectory
1103 BuildStr
+= ' ' + Target
1107 def LaunchPrebuild(self
):
1109 EdkLogger
.info("\n- Prebuild Start -\n")
1110 self
.LaunchPrebuildFlag
= True
1112 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1113 # and preserve them for the rest of the main build step, because the child process environment will
1114 # evaporate as soon as it exits, we cannot get it in build step.
1116 PrebuildEnvFile
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PrebuildEnv')
1117 if os
.path
.isfile(PrebuildEnvFile
):
1118 os
.remove(PrebuildEnvFile
)
1119 if os
.path
.isfile(self
.PlatformBuildPath
):
1120 os
.remove(self
.PlatformBuildPath
)
1121 if sys
.platform
== "win32":
1122 args
= ' && '.join((self
.Prebuild
, 'set > ' + PrebuildEnvFile
))
1123 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1125 args
= ' && '.join((self
.Prebuild
, 'env > ' + PrebuildEnvFile
))
1126 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1128 # launch two threads to read the STDOUT and STDERR
1129 EndOfProcedure
= Event()
1130 EndOfProcedure
.clear()
1132 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1133 StdOutThread
.setName("STDOUT-Redirector")
1134 StdOutThread
.setDaemon(False)
1135 StdOutThread
.start()
1138 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1139 StdErrThread
.setName("STDERR-Redirector")
1140 StdErrThread
.setDaemon(False)
1141 StdErrThread
.start()
1142 # waiting for program exit
1149 if Process
.returncode
!= 0 :
1150 EdkLogger
.error("Prebuild", PREBUILD_ERROR
, 'Prebuild process is not success!')
1152 if os
.path
.exists(PrebuildEnvFile
):
1153 f
= open(PrebuildEnvFile
)
1154 envs
= f
.readlines()
1156 envs
= [l
.split("=", 1) for l
in envs
]
1157 envs
= [[I
.strip() for I
in item
] for item
in envs
if len(item
) == 2]
1158 os
.environ
.update(dict(envs
))
1159 EdkLogger
.info("\n- Prebuild Done -\n")
1161 def LaunchPostbuild(self
):
1163 EdkLogger
.info("\n- Postbuild Start -\n")
1164 if sys
.platform
== "win32":
1165 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1167 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1168 # launch two threads to read the STDOUT and STDERR
1169 EndOfProcedure
= Event()
1170 EndOfProcedure
.clear()
1172 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1173 StdOutThread
.setName("STDOUT-Redirector")
1174 StdOutThread
.setDaemon(False)
1175 StdOutThread
.start()
1178 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1179 StdErrThread
.setName("STDERR-Redirector")
1180 StdErrThread
.setDaemon(False)
1181 StdErrThread
.start()
1182 # waiting for program exit
1189 if Process
.returncode
!= 0 :
1190 EdkLogger
.error("Postbuild", POSTBUILD_ERROR
, 'Postbuild process is not success!')
1191 EdkLogger
.info("\n- Postbuild Done -\n")
1193 ## Build a module or platform
1195 # Create autogen code and makefile for a module or platform, and the launch
1196 # "make" command to build it
1198 # @param Target The target of build command
1199 # @param Platform The platform file
1200 # @param Module The module file
1201 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1202 # @param ToolChain The name of toolchain to build
1203 # @param Arch The arch of the module/platform
1204 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1205 # for dependent modules/Libraries
1206 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1207 # for dependent modules/Libraries
1209 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False, FfsCommand
=None, PcdMaList
=None):
1210 if AutoGenObject
is None:
1212 if FfsCommand
is None:
1214 # skip file generation for cleanxxx targets, run and fds target
1215 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1216 # for target which must generate AutoGen code and makefile
1218 for m
in AutoGenObject
.GetAllModuleInfo
:
1220 mqueue
.put((None,None,None,None,None,None,None))
1221 AutoGenObject
.DataPipe
.DataContainer
= {"CommandTarget": self
.Target
}
1222 AutoGenObject
.DataPipe
.DataContainer
= {"Workspace_timestamp": AutoGenObject
.Workspace
._SrcTimeStamp
}
1223 AutoGenObject
.CreateLibModuelDirs()
1224 AutoGenObject
.DataPipe
.DataContainer
= {"LibraryBuildDirectoryList":AutoGenObject
.LibraryBuildDirectoryList
}
1225 AutoGenObject
.DataPipe
.DataContainer
= {"ModuleBuildDirectoryList":AutoGenObject
.ModuleBuildDirectoryList
}
1226 AutoGenObject
.DataPipe
.DataContainer
= {"FdsCommandDict": AutoGenObject
.Workspace
.GenFdsCommandDict
}
1227 self
.Progress
.Start("Generating makefile and code")
1228 data_pipe_file
= os
.path
.join(AutoGenObject
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(AutoGenObject
.Guid
),AutoGenObject
.Arch
))
1229 AutoGenObject
.DataPipe
.dump(data_pipe_file
)
1231 autogen_rt
,errorcode
= self
.StartAutoGen(mqueue
, AutoGenObject
.DataPipe
, self
.SkipAutoGen
, PcdMaList
, cqueue
)
1232 AutoGenIdFile
= os
.path
.join(GlobalData
.gConfDirectory
,".AutoGenIdFile.txt")
1233 with
open(AutoGenIdFile
,"w") as fw
:
1234 fw
.write("Arch=%s\n" % "|".join((AutoGenObject
.Workspace
.ArchList
)))
1235 fw
.write("BuildDir=%s\n" % AutoGenObject
.Workspace
.BuildDir
)
1236 fw
.write("PlatformGuid=%s\n" % str(AutoGenObject
.Guid
))
1237 self
.Progress
.Stop("done!")
1239 self
.AutoGenMgr
.TerminateWorkers()
1240 self
.AutoGenMgr
.join(1)
1241 raise FatalError(errorcode
)
1242 AutoGenObject
.CreateCodeFile(False)
1243 AutoGenObject
.CreateMakeFile(False)
1245 # always recreate top/platform makefile when clean, just in case of inconsistency
1246 AutoGenObject
.CreateCodeFile(True)
1247 AutoGenObject
.CreateMakeFile(True)
1249 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1250 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1252 BuildCommand
= AutoGenObject
.BuildCommand
1253 if BuildCommand
is None or len(BuildCommand
) == 0:
1254 EdkLogger
.error("build", OPTION_MISSING
,
1255 "No build command found for this module. "
1256 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1257 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1258 ExtraData
=str(AutoGenObject
))
1266 BuildCommand
= BuildCommand
+ [Target
]
1267 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1268 self
.CreateAsBuiltInf()
1269 if GlobalData
.gBinCacheDest
:
1271 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
1273 # Update PreMakeCacheChain files
1274 self
.GenLocalPreMakeCache()
1275 self
.BuildModules
= []
1279 if Target
== 'libraries':
1281 for Lib
in AutoGenObject
.LibraryAutoGenList
:
1282 if not Lib
.IsBinaryModule
:
1283 DirList
.append((os
.path
.join(AutoGenObject
.BuildDir
, Lib
.BuildDir
),Lib
))
1284 for Lib
, LibAutoGen
in DirList
:
1285 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, self
.MakeFileName
)), 'pbuild']
1286 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
,LibAutoGen
)
1290 if Target
== 'modules':
1292 for Lib
in AutoGenObject
.LibraryAutoGenList
:
1293 if not Lib
.IsBinaryModule
:
1294 DirList
.append((os
.path
.join(AutoGenObject
.BuildDir
, Lib
.BuildDir
),Lib
))
1295 for Lib
, LibAutoGen
in DirList
:
1296 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, self
.MakeFileName
)), 'pbuild']
1297 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
,LibAutoGen
)
1300 for ModuleAutoGen
in AutoGenObject
.ModuleAutoGenList
:
1301 if not ModuleAutoGen
.IsBinaryModule
:
1302 DirList
.append((os
.path
.join(AutoGenObject
.BuildDir
, ModuleAutoGen
.BuildDir
),ModuleAutoGen
))
1303 for Mod
,ModAutoGen
in DirList
:
1304 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, self
.MakeFileName
)), 'pbuild']
1305 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
,ModAutoGen
)
1306 self
.CreateAsBuiltInf()
1307 if GlobalData
.gBinCacheDest
:
1309 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
1311 # Update PreMakeCacheChain files
1312 self
.GenLocalPreMakeCache()
1313 self
.BuildModules
= []
1317 if Target
== 'cleanlib':
1318 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1319 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, self
.MakeFileName
))
1320 if os
.path
.exists(LibMakefile
):
1321 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1322 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1326 if Target
== 'clean':
1327 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1328 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, self
.MakeFileName
))
1329 if os
.path
.exists(ModMakefile
):
1330 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
1331 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1332 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1333 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, self
.MakeFileName
))
1334 if os
.path
.exists(LibMakefile
):
1335 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1336 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1340 if Target
== 'cleanall':
1342 #os.rmdir(AutoGenObject.BuildDir)
1343 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1344 except WindowsError as X
:
1345 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1348 ## Build a module or platform
1350 # Create autogen code and makefile for a module or platform, and the launch
1351 # "make" command to build it
1353 # @param Target The target of build command
1354 # @param Platform The platform file
1355 # @param Module The module file
1356 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1357 # @param ToolChain The name of toolchain to build
1358 # @param Arch The arch of the module/platform
1359 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1360 # for dependent modules/Libraries
1361 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1362 # for dependent modules/Libraries
1364 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1365 if AutoGenObject
is None:
1368 # skip file generation for cleanxxx targets, run and fds target
1369 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1370 # for target which must generate AutoGen code and makefile
1371 if not self
.SkipAutoGen
or Target
== 'genc':
1372 self
.Progress
.Start("Generating code")
1373 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1374 self
.Progress
.Stop("done!")
1375 if Target
== "genc":
1378 if not self
.SkipAutoGen
or Target
== 'genmake':
1379 self
.Progress
.Start("Generating makefile")
1380 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1381 #AutoGenObject.CreateAsBuiltInf()
1382 self
.Progress
.Stop("done!")
1383 if Target
== "genmake":
1386 # always recreate top/platform makefile when clean, just in case of inconsistency
1387 AutoGenObject
.CreateCodeFile(True)
1388 AutoGenObject
.CreateMakeFile(True)
1390 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1391 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1393 BuildCommand
= AutoGenObject
.BuildCommand
1394 if BuildCommand
is None or len(BuildCommand
) == 0:
1395 EdkLogger
.error("build", OPTION_MISSING
,
1396 "No build command found for this module. "
1397 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1398 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1399 ExtraData
=str(AutoGenObject
))
1404 BuildCommand
= BuildCommand
+ [Target
]
1405 AutoGenObject
.BuildTime
= LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1406 self
.CreateAsBuiltInf()
1407 if GlobalData
.gBinCacheDest
:
1409 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
1411 # Update PreMakeCacheChain files
1412 self
.GenLocalPreMakeCache()
1413 self
.BuildModules
= []
1418 if GenFdsApi(AutoGenObject
.GenFdsCommandDict
, self
.Db
):
1419 EdkLogger
.error("build", COMMAND_FAILURE
)
1420 Threshold
= self
.GetFreeSizeThreshold()
1422 self
.CheckFreeSizeThreshold(Threshold
, AutoGenObject
.FvDir
)
1430 if Target
== 'libraries':
1437 if Target
== 'cleanall':
1439 #os.rmdir(AutoGenObject.BuildDir)
1440 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1441 except WindowsError as X
:
1442 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1445 ## Rebase module image and Get function address for the input module list.
1447 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1449 AddrIsOffset
= False
1450 for InfFile
in ModuleList
:
1451 sys
.stdout
.write (".")
1453 ModuleInfo
= ModuleList
[InfFile
]
1454 ModuleName
= ModuleInfo
.BaseName
1455 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1456 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1457 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1459 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1461 # Update Image to new BaseAddress by GenFw tool
1463 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1464 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1467 # Set new address to the section header only for SMM driver.
1469 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1470 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1472 # Collect function address from Map file
1474 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1476 if os
.path
.exists(ImageMapTable
):
1477 OrigImageBaseAddress
= 0
1478 ImageMap
= open(ImageMapTable
, 'r')
1479 for LinStr
in ImageMap
:
1480 if len (LinStr
.strip()) == 0:
1483 # Get the preferred address set on link time.
1485 if LinStr
.find ('Preferred load address is') != -1:
1486 StrList
= LinStr
.split()
1487 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1489 StrList
= LinStr
.split()
1490 if len (StrList
) > 4:
1491 if StrList
[3] == 'f' or StrList
[3] == 'F':
1493 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1494 FunctionList
.append ((Name
, RelativeAddress
))
1498 # Add general information.
1501 MapBuffer
.append('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1503 MapBuffer
.append('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1505 MapBuffer
.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1507 # Add guid and general seciton section.
1509 TextSectionAddress
= 0
1510 DataSectionAddress
= 0
1511 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1512 if SectionHeader
[0] == '.text':
1513 TextSectionAddress
= SectionHeader
[1]
1514 elif SectionHeader
[0] in ['.data', '.sdata']:
1515 DataSectionAddress
= SectionHeader
[1]
1517 MapBuffer
.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1519 MapBuffer
.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1521 # Add debug image full path.
1523 MapBuffer
.append('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1525 # Add function address
1527 for Function
in FunctionList
:
1529 MapBuffer
.append(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1531 MapBuffer
.append(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1535 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1538 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1540 ## Collect MAP information of all FVs
1542 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1544 # First get the XIP base address for FV map file.
1545 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1546 GuidName
= re
.compile(r
"\(GUID=[-a-fA-F0-9]+")
1547 for FvName
in Wa
.FdfProfile
.FvDict
:
1548 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1549 if not os
.path
.exists(FvMapBuffer
):
1551 FvMap
= open(FvMapBuffer
, 'r')
1552 #skip FV size information
1558 MatchGuid
= GuidPattern
.match(Line
)
1559 if MatchGuid
is not None:
1561 # Replace GUID with module name
1563 GuidString
= MatchGuid
.group()
1564 if GuidString
.upper() in ModuleList
:
1565 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1566 MapBuffer
.append(Line
)
1568 # Add the debug image full path.
1570 MatchGuid
= GuidName
.match(Line
)
1571 if MatchGuid
is not None:
1572 GuidString
= MatchGuid
.group().split("=")[1]
1573 if GuidString
.upper() in ModuleList
:
1574 MapBuffer
.append('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1578 ## Collect MAP information of all modules
1580 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1581 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1583 PatchEfiImageList
= []
1591 # reserve 4K size in SMRAM to make SMM module address not from 0.
1593 for ModuleGuid
in ModuleList
:
1594 Module
= ModuleList
[ModuleGuid
]
1595 GlobalData
.gProcessingFile
= "%s [%s, %s, %s]" % (Module
.MetaFile
, Module
.Arch
, Module
.ToolChain
, Module
.BuildTarget
)
1597 OutputImageFile
= ''
1598 for ResultFile
in Module
.CodaTargetList
:
1599 if str(ResultFile
.Target
).endswith('.efi'):
1601 # module list for PEI, DXE, RUNTIME and SMM
1603 OutputImageFile
= os
.path
.join(Module
.OutputDir
, Module
.Name
+ '.efi')
1604 ImageClass
= PeImageClass (OutputImageFile
)
1605 if not ImageClass
.IsValid
:
1606 EdkLogger
.error("build", FILE_PARSE_FAILURE
, ExtraData
=ImageClass
.ErrorInfo
)
1607 ImageInfo
= PeImageInfo(Module
.Name
, Module
.Guid
, Module
.Arch
, Module
.OutputDir
, Module
.DebugDir
, ImageClass
)
1608 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
]:
1609 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1610 PeiSize
+= ImageInfo
.Image
.Size
1611 elif Module
.ModuleType
in [EDK_COMPONENT_TYPE_BS_DRIVER
, SUP_MODULE_DXE_DRIVER
, SUP_MODULE_UEFI_DRIVER
]:
1612 BtModuleList
[Module
.MetaFile
] = ImageInfo
1613 BtSize
+= ImageInfo
.Image
.Size
1614 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
]:
1615 RtModuleList
[Module
.MetaFile
] = ImageInfo
1616 RtSize
+= ImageInfo
.Image
.Size
1617 elif Module
.ModuleType
in [SUP_MODULE_SMM_CORE
, SUP_MODULE_DXE_SMM_DRIVER
, SUP_MODULE_MM_STANDALONE
, SUP_MODULE_MM_CORE_STANDALONE
]:
1618 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1619 SmmSize
+= ImageInfo
.Image
.Size
1620 if Module
.ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
1621 PiSpecVersion
= Module
.Module
.Specification
.get('PI_SPECIFICATION_VERSION', '0x00000000')
1622 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1623 if int(PiSpecVersion
, 16) < 0x0001000A:
1624 BtModuleList
[Module
.MetaFile
] = ImageInfo
1625 BtSize
+= ImageInfo
.Image
.Size
1628 # EFI image is final target.
1629 # Check EFI image contains patchable FixAddress related PCDs.
1631 if OutputImageFile
!= '':
1632 ModuleIsPatch
= False
1633 for Pcd
in Module
.ModulePcdList
:
1634 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1635 ModuleIsPatch
= True
1637 if not ModuleIsPatch
:
1638 for Pcd
in Module
.LibraryPcdList
:
1639 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1640 ModuleIsPatch
= True
1643 if not ModuleIsPatch
:
1646 # Module includes the patchable load fix address PCDs.
1647 # It will be fixed up later.
1649 PatchEfiImageList
.append (OutputImageFile
)
1652 # Get Top Memory address
1654 ReservedRuntimeMemorySize
= 0
1655 TopMemoryAddress
= 0
1656 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1657 TopMemoryAddress
= 0
1659 TopMemoryAddress
= self
.LoadFixAddress
1660 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1661 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1664 # Patch FixAddress related PCDs into EFI image
1666 for EfiImage
in PatchEfiImageList
:
1667 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1668 if not os
.path
.exists(EfiImageMap
):
1671 # Get PCD offset in EFI image by GenPatchPcdTable function
1673 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1675 # Patch real PCD value by PatchPcdValue tool
1677 for PcdInfo
in PcdTable
:
1679 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1680 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
// 0x1000))
1681 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1682 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
// 0x1000))
1683 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1684 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
// 0x1000))
1685 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1686 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
// 0x1000))
1687 if ReturnValue
!= 0:
1688 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1690 MapBuffer
.append('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
// 0x1000))
1691 MapBuffer
.append('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
// 0x1000))
1692 MapBuffer
.append('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
// 0x1000))
1693 if len (SmmModuleList
) > 0:
1694 MapBuffer
.append('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
// 0x1000))
1696 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1697 BtBaseAddr
= TopMemoryAddress
- RtSize
1698 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1700 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1701 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1702 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1703 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
=False, ModeIsSmm
=True)
1704 MapBuffer
.append('\n\n')
1705 sys
.stdout
.write ("\n")
1708 ## Save platform Map file
1710 def _SaveMapFile (self
, MapBuffer
, Wa
):
1712 # Map file path is got.
1714 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1716 # Save address map into MAP file.
1718 SaveFileOnChange(MapFilePath
, ''.join(MapBuffer
), False)
1719 if self
.LoadFixAddress
!= 0:
1720 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath
))
1723 ## Build active platform for different build targets and different tool chains
1725 def _BuildPlatform(self
):
1726 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1727 for BuildTarget
in self
.BuildTargetList
:
1728 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1730 for ToolChain
in self
.ToolChainList
:
1731 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1732 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1733 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1735 Wa
= WorkspaceAutoGen(
1752 self
.Fdf
= Wa
.FdfFile
1753 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1754 self
.BuildReport
.AddPlatformReport(Wa
)
1755 self
.Progress
.Stop("done!")
1757 # Add ffs build to makefile
1759 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1760 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1762 for Arch
in Wa
.ArchList
:
1764 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1765 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1766 for Module
in Pa
.Platform
.Modules
:
1767 # Get ModuleAutoGen object to generate C code file and makefile
1768 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1772 Ma
.PlatformInfo
= Pa
1774 PcdMaList
.append(Ma
)
1775 self
.BuildModules
.append(Ma
)
1776 Pa
.DataPipe
.DataContainer
= {"FfsCommand":CmdListDict
}
1777 Pa
.DataPipe
.DataContainer
= {"Workspace_timestamp": Wa
._SrcTimeStamp
}
1778 self
._BuildPa
(self
.Target
, Pa
, FfsCommand
=CmdListDict
,PcdMaList
=PcdMaList
)
1780 # Create MAP file when Load Fix Address is enabled.
1781 if self
.Target
in ["", "all", "fds"]:
1782 for Arch
in Wa
.ArchList
:
1783 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1785 # Check whether the set fix address is above 4G for 32bit image.
1787 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1788 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")
1793 for Pa
in Wa
.AutoGenObjectList
:
1794 for Ma
in Pa
.ModuleAutoGenList
:
1797 if not Ma
.IsLibrary
:
1798 ModuleList
[Ma
.Guid
.upper()] = Ma
1801 if self
.LoadFixAddress
!= 0:
1803 # Rebase module to the preferred memory address before GenFds
1805 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1808 # create FDS again for the updated EFI image
1810 self
._Build
("fds", Wa
)
1812 # Create MAP file for all platform FVs after GenFds.
1814 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1816 # Save MAP buffer into MAP file.
1818 self
._SaveMapFile
(MapBuffer
, Wa
)
1819 self
.CreateGuidedSectionToolsFile(Wa
)
1821 ## Build active module for different build targets, different tool chains and different archs
1823 def _BuildModule(self
):
1824 for BuildTarget
in self
.BuildTargetList
:
1825 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1827 for ToolChain
in self
.ToolChainList
:
1828 WorkspaceAutoGenTime
= time
.time()
1829 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1830 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1831 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1834 # module build needs platform build information, so get platform
1837 Wa
= WorkspaceAutoGen(
1855 self
.Fdf
= Wa
.FdfFile
1856 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1857 Wa
.CreateMakeFile(False)
1858 # Add ffs build to makefile
1860 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1861 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1863 GlobalData
.file_lock
= mp
.Lock()
1864 GlobalData
.FfsCmd
= CmdListDict
1866 self
.Progress
.Stop("done!")
1868 ExitFlag
= threading
.Event()
1870 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1871 for Arch
in Wa
.ArchList
:
1872 AutoGenStart
= time
.time()
1873 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1874 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1875 for Module
in Pa
.Platform
.Modules
:
1876 if self
.ModuleFile
.Dir
== Module
.Dir
and self
.ModuleFile
.Name
== Module
.Name
:
1877 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1881 Ma
.PlatformInfo
= Pa
1885 if GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheDest
and self
.Target
in [None, "", "all"]:
1886 if Ma
.CanSkipbyPreMakeCache():
1889 self
.PreMakeCacheMiss
.add(Ma
)
1891 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1892 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1893 # for target which must generate AutoGen code and makefile
1894 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1895 self
.Progress
.Start("Generating code")
1896 Ma
.CreateCodeFile(True)
1897 self
.Progress
.Stop("done!")
1898 if self
.Target
== "genc":
1900 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1901 self
.Progress
.Start("Generating makefile")
1902 if CmdListDict
and self
.Fdf
and (Module
.Path
, Arch
) in CmdListDict
:
1903 Ma
.CreateMakeFile(True, CmdListDict
[Module
.Path
, Arch
])
1904 del CmdListDict
[Module
.Path
, Arch
]
1906 Ma
.CreateMakeFile(True)
1907 self
.Progress
.Stop("done!")
1908 if self
.Target
== "genmake":
1911 if GlobalData
.gBinCacheSource
and self
.Target
in [None, "", "all"]:
1912 if Ma
.CanSkipbyMakeCache():
1915 self
.MakeCacheMiss
.add(Ma
)
1917 self
.BuildModules
.append(Ma
)
1918 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1919 MakeStart
= time
.time()
1920 for Ma
in self
.BuildModules
:
1921 if not Ma
.IsBinaryModule
:
1922 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
1923 # Break build if any build thread has error
1924 if BuildTask
.HasError():
1925 # we need a full version of makefile for platform
1927 BuildTask
.WaitForComplete()
1928 Pa
.CreateMakeFile(False)
1929 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1930 # Start task scheduler
1931 if not BuildTask
.IsOnGoing():
1932 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1934 # in case there's an interruption. we need a full version of makefile for platform
1935 Pa
.CreateMakeFile(False)
1936 if BuildTask
.HasError():
1937 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1938 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1940 MakeContiue
= time
.time()
1942 BuildTask
.WaitForComplete()
1943 self
.CreateAsBuiltInf()
1944 if GlobalData
.gBinCacheDest
:
1946 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
1948 # Update PreMakeCacheChain files
1949 self
.GenLocalPreMakeCache()
1950 self
.BuildModules
= []
1951 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1952 if BuildTask
.HasError():
1953 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1955 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1960 "Module for [%s] is not a component of active platform."\
1961 " Please make sure that the ARCH and inf file path are"\
1962 " given in the same as in [%s]" % \
1963 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1964 ExtraData
=self
.ModuleFile
1966 # Create MAP file when Load Fix Address is enabled.
1967 if self
.Target
== "fds" and self
.Fdf
:
1968 for Arch
in Wa
.ArchList
:
1970 # Check whether the set fix address is above 4G for 32bit image.
1972 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1973 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")
1978 for Pa
in Wa
.AutoGenObjectList
:
1979 for Ma
in Pa
.ModuleAutoGenList
:
1982 if not Ma
.IsLibrary
:
1983 ModuleList
[Ma
.Guid
.upper()] = Ma
1986 if self
.LoadFixAddress
!= 0:
1988 # Rebase module to the preferred memory address before GenFds
1990 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1992 # create FDS again for the updated EFI image
1994 GenFdsStart
= time
.time()
1995 self
._Build
("fds", Wa
)
1996 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
1998 # Create MAP file for all platform FVs after GenFds.
2000 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2002 # Save MAP buffer into MAP file.
2004 self
._SaveMapFile
(MapBuffer
, Wa
)
2006 def _GenFfsCmd(self
,ArchList
):
2007 # convert dictionary of Cmd:(Inf,Arch)
2008 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
2009 CmdSetDict
= defaultdict(set)
2010 GenFfsDict
= GenFds
.GenFfsMakefile('', GlobalData
.gFdfParser
, self
, ArchList
, GlobalData
)
2011 for Cmd
in GenFfsDict
:
2012 tmpInf
, tmpArch
= GenFfsDict
[Cmd
]
2013 CmdSetDict
[tmpInf
, tmpArch
].add(Cmd
)
2015 def VerifyAutoGenFiles(self
):
2016 AutoGenIdFile
= os
.path
.join(GlobalData
.gConfDirectory
,".AutoGenIdFile.txt")
2018 with
open(AutoGenIdFile
) as fd
:
2019 lines
= fd
.readlines()
2024 ArchList
= line
.strip().split("=")[1].split("|")
2025 if "BuildDir" in line
:
2026 BuildDir
= line
.split("=")[1].strip()
2027 if "PlatformGuid" in line
:
2028 PlatformGuid
= line
.split("=")[1].strip()
2030 for arch
in ArchList
:
2031 global_var
= os
.path
.join(BuildDir
, "GlobalVar_%s_%s.bin" % (str(PlatformGuid
),arch
))
2032 if not os
.path
.exists(global_var
):
2034 GlobalVarList
.append(global_var
)
2035 for global_var
in GlobalVarList
:
2036 data_pipe
= MemoryDataPipe()
2037 data_pipe
.load(global_var
)
2038 target
= data_pipe
.Get("P_Info").get("Target")
2039 toolchain
= data_pipe
.Get("P_Info").get("ToolChain")
2040 archlist
= data_pipe
.Get("P_Info").get("ArchList")
2041 Arch
= data_pipe
.Get("P_Info").get("Arch")
2042 active_p
= data_pipe
.Get("P_Info").get("ActivePlatform")
2043 workspacedir
= data_pipe
.Get("P_Info").get("WorkspaceDir")
2044 PackagesPath
= os
.getenv("PACKAGES_PATH")
2045 mws
.setWs(workspacedir
, PackagesPath
)
2046 LibraryBuildDirectoryList
= data_pipe
.Get("LibraryBuildDirectoryList")
2047 ModuleBuildDirectoryList
= data_pipe
.Get("ModuleBuildDirectoryList")
2049 for m_build_dir
in LibraryBuildDirectoryList
:
2050 if not os
.path
.exists(os
.path
.join(m_build_dir
,self
.MakeFileName
)):
2052 for m_build_dir
in ModuleBuildDirectoryList
:
2053 if not os
.path
.exists(os
.path
.join(m_build_dir
,self
.MakeFileName
)):
2056 workspacedir
,active_p
,target
,toolchain
,archlist
2058 Pa
= PlatformInfo(Wa
, active_p
, target
, toolchain
, Arch
,data_pipe
)
2059 Wa
.AutoGenObjectList
.append(Pa
)
2061 def SetupMakeSetting(self
,Wa
):
2063 for Pa
in Wa
.AutoGenObjectList
:
2064 for m
in Pa
._MbList
:
2065 ma
= ModuleAutoGen(Wa
,m
.MetaFile
, Pa
.BuildTarget
, Wa
.ToolChain
, Pa
.Arch
, Pa
.MetaFile
,Pa
.DataPipe
)
2066 BuildModules
.append(ma
)
2067 fdf_file
= Wa
.FlashDefinition
2069 Fdf
= FdfParser(fdf_file
.Path
)
2071 GlobalData
.gFdfParser
= Fdf
2072 if Fdf
.CurrentFdName
and Fdf
.CurrentFdName
in Fdf
.Profile
.FdDict
:
2073 FdDict
= Fdf
.Profile
.FdDict
[Fdf
.CurrentFdName
]
2074 for FdRegion
in FdDict
.RegionList
:
2075 if str(FdRegion
.RegionType
) == 'FILE' and self
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
2076 if int(FdRegion
.Offset
) % 8 != 0:
2077 EdkLogger
.error("build", FORMAT_INVALID
, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion
.Offset
))
2078 Wa
.FdfProfile
= Fdf
.Profile
2084 ## Build a platform in multi-thread mode
2086 def PerformAutoGen(self
,BuildTarget
,ToolChain
):
2087 WorkspaceAutoGenTime
= time
.time()
2088 Wa
= WorkspaceAutoGen(
2105 self
.Fdf
= Wa
.FdfFile
2106 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
2107 self
.BuildReport
.AddPlatformReport(Wa
)
2108 Wa
.CreateMakeFile(False)
2110 # Add ffs build to makefile
2112 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
2113 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
2115 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
2117 for Arch
in Wa
.ArchList
:
2119 AutoGenStart
= time
.time()
2120 GlobalData
.gGlobalDefines
['ARCH'] = Arch
2121 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
2125 for Inf
in Pa
.Platform
.Modules
:
2126 ModuleList
.append(Inf
)
2127 # Add the INF only list in FDF
2128 if GlobalData
.gFdfParser
is not None:
2129 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
2130 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
2131 if Inf
in Pa
.Platform
.Modules
:
2133 ModuleList
.append(Inf
)
2134 Pa
.DataPipe
.DataContainer
= {"FfsCommand":CmdListDict
}
2135 Pa
.DataPipe
.DataContainer
= {"Workspace_timestamp": Wa
._SrcTimeStamp
}
2136 Pa
.DataPipe
.DataContainer
= {"CommandTarget": self
.Target
}
2137 Pa
.CreateLibModuelDirs()
2138 # Fetch the MakeFileName.
2139 self
.MakeFileName
= Pa
.MakeFileName
2140 if not self
.MakeFileName
:
2141 self
.MakeFileName
= Pa
.MakeFile
2143 Pa
.DataPipe
.DataContainer
= {"LibraryBuildDirectoryList":Pa
.LibraryBuildDirectoryList
}
2144 Pa
.DataPipe
.DataContainer
= {"ModuleBuildDirectoryList":Pa
.ModuleBuildDirectoryList
}
2145 Pa
.DataPipe
.DataContainer
= {"FdsCommandDict": Wa
.GenFdsCommandDict
}
2146 # Prepare the cache share data for multiprocessing
2147 Pa
.DataPipe
.DataContainer
= {"gPlatformHashFile":GlobalData
.gPlatformHashFile
}
2149 for ma
in Pa
.ModuleAutoGenList
:
2150 ModuleCodaFile
[(ma
.MetaFile
.File
,ma
.MetaFile
.Root
,ma
.Arch
,ma
.MetaFile
.Path
)] = [item
.Target
for item
in ma
.CodaTargetList
]
2151 Pa
.DataPipe
.DataContainer
= {"ModuleCodaFile":ModuleCodaFile
}
2152 # ModuleList contains all driver modules only
2153 for Module
in ModuleList
:
2154 # Get ModuleAutoGen object to generate C code file and makefile
2155 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2159 Ma
.PlatformInfo
= Pa
2161 PcdMaList
.append(Ma
)
2162 self
.AllDrivers
.add(Ma
)
2163 self
.AllModules
.add(Ma
)
2167 for m
in Pa
.GetAllModuleInfo
:
2169 module_file
,module_root
,module_path
,module_basename
,\
2170 module_originalpath
,module_arch
,IsLib
= m
2171 Ma
= ModuleAutoGen(Wa
, PathClass(module_path
, Wa
), BuildTarget
,\
2172 ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2173 self
.AllModules
.add(Ma
)
2174 data_pipe_file
= os
.path
.join(Pa
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(Pa
.Guid
),Pa
.Arch
))
2175 Pa
.DataPipe
.dump(data_pipe_file
)
2177 mqueue
.put((None,None,None,None,None,None,None))
2178 autogen_rt
, errorcode
= self
.StartAutoGen(mqueue
, Pa
.DataPipe
, self
.SkipAutoGen
, PcdMaList
, cqueue
)
2181 self
.AutoGenMgr
.TerminateWorkers()
2182 self
.AutoGenMgr
.join(1)
2183 raise FatalError(errorcode
)
2185 if GlobalData
.gUseHashCache
:
2186 for item
in GlobalData
.gModuleAllCacheStatus
:
2187 (MetaFilePath
, Arch
, CacheStr
, Status
) = item
2188 Ma
= ModuleAutoGen(Wa
, PathClass(MetaFilePath
, Wa
), BuildTarget
,\
2189 ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2190 if CacheStr
== "PreMakeCache" and Status
== False:
2191 self
.PreMakeCacheMiss
.add(Ma
)
2192 if CacheStr
== "PreMakeCache" and Status
== True:
2193 self
.PreMakeCacheHit
.add(Ma
)
2194 GlobalData
.gModuleCacheHit
.add(Ma
)
2195 if CacheStr
== "MakeCache" and Status
== False:
2196 self
.MakeCacheMiss
.add(Ma
)
2197 if CacheStr
== "MakeCache" and Status
== True:
2198 self
.MakeCacheHit
.add(Ma
)
2199 GlobalData
.gModuleCacheHit
.add(Ma
)
2200 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
2201 AutoGenIdFile
= os
.path
.join(GlobalData
.gConfDirectory
,".AutoGenIdFile.txt")
2202 with
open(AutoGenIdFile
,"w") as fw
:
2203 fw
.write("Arch=%s\n" % "|".join((Wa
.ArchList
)))
2204 fw
.write("BuildDir=%s\n" % Wa
.BuildDir
)
2205 fw
.write("PlatformGuid=%s\n" % str(Wa
.AutoGenObjectList
[0].Guid
))
2207 if GlobalData
.gBinCacheSource
:
2208 BuildModules
.extend(self
.MakeCacheMiss
)
2209 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheDest
:
2210 BuildModules
.extend(self
.PreMakeCacheMiss
)
2212 BuildModules
.extend(self
.AllDrivers
)
2214 self
.Progress
.Stop("done!")
2215 return Wa
, BuildModules
2217 def _MultiThreadBuildPlatform(self
):
2218 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
2219 for BuildTarget
in self
.BuildTargetList
:
2220 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
2222 for ToolChain
in self
.ToolChainList
:
2223 resetFdsGlobalVariable()
2224 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
2225 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
2226 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
2228 ExitFlag
= threading
.Event()
2230 if self
.SkipAutoGen
:
2231 Wa
= self
.VerifyAutoGenFiles()
2233 self
.SkipAutoGen
= False
2234 Wa
, self
.BuildModules
= self
.PerformAutoGen(BuildTarget
,ToolChain
)
2236 GlobalData
.gAutoGenPhase
= True
2237 self
.BuildModules
= self
.SetupMakeSetting(Wa
)
2239 Wa
, self
.BuildModules
= self
.PerformAutoGen(BuildTarget
,ToolChain
)
2240 Pa
= Wa
.AutoGenObjectList
[0]
2241 GlobalData
.gAutoGenPhase
= False
2243 if GlobalData
.gBinCacheSource
:
2244 EdkLogger
.quiet("[cache Summary]: Total module num: %s" % len(self
.AllModules
))
2245 EdkLogger
.quiet("[cache Summary]: PreMakecache miss num: %s " % len(self
.PreMakeCacheMiss
))
2246 EdkLogger
.quiet("[cache Summary]: Makecache miss num: %s " % len(self
.MakeCacheMiss
))
2248 for Arch
in Wa
.ArchList
:
2249 MakeStart
= time
.time()
2250 for Ma
in set(self
.BuildModules
):
2251 # Generate build task for the module
2252 if not Ma
.IsBinaryModule
:
2253 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
2254 # Break build if any build thread has error
2255 if BuildTask
.HasError():
2256 # we need a full version of makefile for platform
2258 BuildTask
.WaitForComplete()
2259 Pa
.CreateMakeFile(False)
2260 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2261 # Start task scheduler
2262 if not BuildTask
.IsOnGoing():
2263 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
2265 # in case there's an interruption. we need a full version of makefile for platform
2267 if BuildTask
.HasError():
2268 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2269 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
2271 MakeContiue
= time
.time()
2274 # All modules have been put in build tasks queue. Tell task scheduler
2275 # to exit if all tasks are completed
2278 BuildTask
.WaitForComplete()
2279 self
.CreateAsBuiltInf()
2280 if GlobalData
.gBinCacheDest
:
2282 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
2284 # Update PreMakeCacheChain files
2285 self
.GenLocalPreMakeCache()
2289 ModuleList
= {ma
.Guid
.upper(): ma
for ma
in self
.BuildModules
}
2290 self
.BuildModules
= []
2291 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2293 # Check for build error, and raise exception if one
2294 # has been signaled.
2296 if BuildTask
.HasError():
2297 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2299 # Create MAP file when Load Fix Address is enabled.
2300 if self
.Target
in ["", "all", "fds"]:
2301 for Arch
in Wa
.ArchList
:
2303 # Check whether the set fix address is above 4G for 32bit image.
2305 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2306 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")
2309 # Rebase module to the preferred memory address before GenFds
2312 if self
.LoadFixAddress
!= 0:
2313 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2317 # Generate FD image if there's a FDF file found
2319 GenFdsStart
= time
.time()
2320 if GenFdsApi(Wa
.GenFdsCommandDict
, self
.Db
):
2321 EdkLogger
.error("build", COMMAND_FAILURE
)
2322 Threshold
= self
.GetFreeSizeThreshold()
2324 self
.CheckFreeSizeThreshold(Threshold
, Wa
.FvDir
)
2327 # Create MAP file for all platform FVs after GenFds.
2329 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2330 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2332 # Save MAP buffer into MAP file.
2334 self
._SaveMapFile
(MapBuffer
, Wa
)
2335 self
.CreateGuidedSectionToolsFile(Wa
)
2337 ## GetFreeSizeThreshold()
2339 # @retval int Threshold value
2341 def GetFreeSizeThreshold(self
):
2343 Threshold_Str
= GlobalData
.gCommandLineDefines
.get('FV_SPARE_SPACE_THRESHOLD')
2346 if Threshold_Str
.lower().startswith('0x'):
2347 Threshold
= int(Threshold_Str
, 16)
2349 Threshold
= int(Threshold_Str
)
2351 EdkLogger
.warn("build", 'incorrect value for FV_SPARE_SPACE_THRESHOLD %s.Only decimal or hex format is allowed.' % Threshold_Str
)
2354 def CheckFreeSizeThreshold(self
, Threshold
=None, FvDir
=None):
2355 if not isinstance(Threshold
, int):
2357 if not isinstance(FvDir
, str) or not FvDir
:
2359 FdfParserObject
= GlobalData
.gFdfParser
2360 FvRegionNameList
= [FvName
for FvName
in FdfParserObject
.Profile
.FvDict
if FdfParserObject
.Profile
.FvDict
[FvName
].FvRegionInFD
]
2361 for FvName
in FdfParserObject
.Profile
.FvDict
:
2362 if FvName
in FvRegionNameList
:
2363 FvSpaceInfoFileName
= os
.path
.join(FvDir
, FvName
.upper() + '.Fv.map')
2364 if os
.path
.exists(FvSpaceInfoFileName
):
2365 FileLinesList
= getlines(FvSpaceInfoFileName
)
2366 for Line
in FileLinesList
:
2367 NameValue
= Line
.split('=')
2368 if len(NameValue
) == 2 and NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
2369 FreeSizeValue
= int(NameValue
[1].strip(), 0)
2370 if FreeSizeValue
< Threshold
:
2371 EdkLogger
.error("build", FV_FREESIZE_ERROR
,
2372 '%s FV free space %d is not enough to meet with the required spare space %d set by -D FV_SPARE_SPACE_THRESHOLD option.' % (
2373 FvName
, FreeSizeValue
, Threshold
))
2376 ## Generate GuidedSectionTools.txt in the FV directories.
2378 def CreateGuidedSectionToolsFile(self
,Wa
):
2379 for BuildTarget
in self
.BuildTargetList
:
2380 for ToolChain
in self
.ToolChainList
:
2382 if not os
.path
.exists(FvDir
):
2385 for Arch
in self
.ArchList
:
2386 # Build up the list of supported architectures for this build
2387 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
2389 # Look through the tool definitions for GUIDed tools
2391 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.items():
2392 if attrib
.upper().endswith('_GUID'):
2393 split
= attrib
.split('_')
2394 thisPrefix
= '_'.join(split
[0:3]) + '_'
2395 if thisPrefix
== prefix
:
2396 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
2399 path
= '_'.join(split
[0:4]) + '_PATH'
2400 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2401 path
= self
.GetRealPathOfTool(path
)
2402 guidAttribs
.append((guid
, toolName
, path
))
2404 # Write out GuidedSecTools.txt
2405 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2406 toolsFile
= open(toolsFile
, 'wt')
2407 for guidedSectionTool
in guidAttribs
:
2408 print(' '.join(guidedSectionTool
), file=toolsFile
)
2411 ## Returns the real path of the tool.
2413 def GetRealPathOfTool (self
, tool
):
2414 if os
.path
.exists(tool
):
2415 return os
.path
.realpath(tool
)
2418 ## Launch the module or platform build
2421 self
.AllDrivers
= set()
2422 self
.AllModules
= set()
2423 self
.PreMakeCacheMiss
= set()
2424 self
.PreMakeCacheHit
= set()
2425 self
.MakeCacheMiss
= set()
2426 self
.MakeCacheHit
= set()
2427 if not self
.ModuleFile
:
2428 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2429 self
.SpawnMode
= False
2430 self
._BuildPlatform
()
2432 self
._MultiThreadBuildPlatform
()
2434 self
.SpawnMode
= False
2437 if self
.Target
== 'cleanall':
2438 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2440 def CreateAsBuiltInf(self
):
2441 for Module
in self
.BuildModules
:
2442 Module
.CreateAsBuiltInf()
2444 def GenDestCache(self
):
2445 for Module
in self
.AllModules
:
2446 Module
.GenPreMakefileHashList()
2447 Module
.GenMakefileHashList()
2448 Module
.CopyModuleToCache()
2450 def GenLocalPreMakeCache(self
):
2451 for Module
in self
.PreMakeCacheMiss
:
2452 Module
.GenPreMakefileHashList()
2454 ## Do some clean-up works when error occurred
2455 def Relinquish(self
):
2456 OldLogLevel
= EdkLogger
.GetLevel()
2457 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2458 Utils
.Progressor
.Abort()
2459 if self
.SpawnMode
== True:
2461 EdkLogger
.SetLevel(OldLogLevel
)
2463 def ParseDefines(DefineList
=[]):
2465 if DefineList
is not None:
2466 for Define
in DefineList
:
2467 DefineTokenList
= Define
.split("=", 1)
2468 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2469 EdkLogger
.error('build', FORMAT_INVALID
,
2470 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2471 ExtraData
=DefineTokenList
[0])
2473 if len(DefineTokenList
) == 1:
2474 DefineDict
[DefineTokenList
[0]] = "TRUE"
2476 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2481 def LogBuildTime(Time
):
2484 TimeDur
= time
.gmtime(Time
)
2485 if TimeDur
.tm_yday
> 1:
2486 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2488 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2493 OptionParser
= MyOptionParser()
2494 if not OptionParser
.BuildOption
and not OptionParser
.BuildTarget
:
2495 OptionParser
.GetOption()
2496 BuildOption
, BuildTarget
= OptionParser
.BuildOption
, OptionParser
.BuildTarget
2497 ThreadNumber
= BuildOption
.ThreadNumber
2498 GlobalData
.gCmdConfDir
= BuildOption
.ConfDirectory
2499 if ThreadNumber
is None:
2500 TargetObj
= TargetTxtDict()
2501 ThreadNumber
= TargetObj
.Target
.TargetTxtDictionary
[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
2502 if ThreadNumber
== '':
2505 ThreadNumber
= int(ThreadNumber
, 0)
2507 if ThreadNumber
== 0:
2509 ThreadNumber
= multiprocessing
.cpu_count()
2510 except (ImportError, NotImplementedError):
2513 ## Tool entrance method
2515 # This method mainly dispatch specific methods per the command line options.
2516 # If no error found, return zero value so the caller of this tool can know
2517 # if it's executed successfully or not.
2519 # @retval 0 Tool was successful
2520 # @retval 1 Tool failed
2522 LogQMaxSize
= ThreadNum() * 10
2524 StartTime
= time
.time()
2527 # Create a log Queue
2529 LogQ
= mp
.Queue(LogQMaxSize
)
2530 # Initialize log system
2531 EdkLogger
.LogClientInitialize(LogQ
)
2532 GlobalData
.gCommand
= sys
.argv
[1:]
2534 # Parse the options and args
2536 OptionParser
= MyOptionParser()
2537 if not OptionParser
.BuildOption
and not OptionParser
.BuildTarget
:
2538 OptionParser
.GetOption()
2539 Option
, Target
= OptionParser
.BuildOption
, OptionParser
.BuildTarget
2540 GlobalData
.gOptions
= Option
2541 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2544 LogLevel
= EdkLogger
.INFO
2545 if Option
.verbose
is not None:
2546 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2547 LogLevel
= EdkLogger
.VERBOSE
2548 elif Option
.quiet
is not None:
2549 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2550 LogLevel
= EdkLogger
.QUIET
2551 elif Option
.debug
is not None:
2552 EdkLogger
.SetLevel(Option
.debug
+ 1)
2553 LogLevel
= Option
.debug
+ 1
2555 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2557 if Option
.WarningAsError
== True:
2558 EdkLogger
.SetWarningAsError()
2559 Log_Agent
= LogAgent(LogQ
,LogLevel
,Option
.LogFile
)
2562 if platform
.platform().find("Windows") >= 0:
2563 GlobalData
.gIsWindows
= True
2565 GlobalData
.gIsWindows
= False
2567 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2568 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2573 if len(Target
) == 0:
2575 elif len(Target
) >= 2:
2576 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2577 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2579 Target
= Target
[0].lower()
2581 if Target
not in gSupportedTarget
:
2582 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2583 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2586 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2589 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2591 Workspace
= os
.getenv("WORKSPACE")
2593 # Get files real name in workspace dir
2595 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2597 WorkingDirectory
= os
.getcwd()
2598 if not Option
.ModuleFile
:
2599 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2600 FileNum
= len(FileList
)
2602 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2603 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2605 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2607 if Option
.ModuleFile
:
2608 if os
.path
.isabs (Option
.ModuleFile
):
2609 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2610 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2611 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2612 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2614 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2616 if Option
.PlatformFile
is not None:
2617 if os
.path
.isabs (Option
.PlatformFile
):
2618 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2619 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2620 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2622 if Option
.FdfFile
is not None:
2623 if os
.path
.isabs (Option
.FdfFile
):
2624 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2625 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2626 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2627 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2629 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2631 if Option
.Flag
is not None and Option
.Flag
not in ['-c', '-s']:
2632 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2634 MyBuild
= Build(Target
, Workspace
, Option
,LogQ
)
2635 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2636 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2640 # All job done, no error found and no exception raised
2643 except FatalError
as X
:
2644 if MyBuild
is not None:
2645 # for multi-thread build exits safely
2646 MyBuild
.Relinquish()
2647 if Option
is not None and Option
.debug
is not None:
2648 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2649 ReturnCode
= X
.args
[0]
2650 except Warning as X
:
2651 # error from Fdf parser
2652 if MyBuild
is not None:
2653 # for multi-thread build exits safely
2654 MyBuild
.Relinquish()
2655 if Option
is not None and Option
.debug
is not None:
2656 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2658 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2659 ReturnCode
= FORMAT_INVALID
2660 except KeyboardInterrupt:
2661 if MyBuild
is not None:
2663 # for multi-thread build exits safely
2664 MyBuild
.Relinquish()
2665 ReturnCode
= ABORT_ERROR
2666 if Option
is not None and Option
.debug
is not None:
2667 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2669 if MyBuild
is not None:
2670 # for multi-thread build exits safely
2671 MyBuild
.Relinquish()
2673 # try to get the meta-file from the object causing exception
2674 Tb
= sys
.exc_info()[-1]
2675 MetaFile
= GlobalData
.gProcessingFile
2676 while Tb
is not None:
2677 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2678 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2683 "Unknown fatal error when processing [%s]" % MetaFile
,
2684 ExtraData
="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR
,
2687 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2688 ReturnCode
= CODE_ERROR
2690 Utils
.Progressor
.Abort()
2691 Utils
.ClearDuplicatedInf()
2695 MyBuild
.LaunchPostbuild()
2698 Conclusion
= "Failed"
2699 elif ReturnCode
== ABORT_ERROR
:
2700 Conclusion
= "Aborted"
2702 Conclusion
= "Failed"
2703 FinishTime
= time
.time()
2704 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2705 BuildDurationStr
= ""
2706 if BuildDuration
.tm_yday
> 1:
2707 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2709 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2710 if MyBuild
is not None:
2712 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2714 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2715 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2716 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2717 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2722 if __name__
== '__main__':
2724 mp
.set_start_method('spawn')
2728 ## 0-127 is a safe return range, and 1 is a standard default error
2729 if r
< 0 or r
> 127: r
= 1