2 # build a platform or a module
4 # Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
5 # Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
6 # Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
8 # SPDX-License-Identifier: BSD-2-Clause-Patent
14 from __future__
import print_function
15 from __future__
import absolute_import
16 import os
.path
as path
24 import multiprocessing
25 from threading
import Thread
,Event
,BoundedSemaphore
27 from subprocess
import Popen
,PIPE
28 from collections
import OrderedDict
, defaultdict
29 from Common
.buildoptions
import BuildOption
,BuildTarget
30 from AutoGen
.PlatformAutoGen
import PlatformAutoGen
31 from AutoGen
.ModuleAutoGen
import ModuleAutoGen
32 from AutoGen
.WorkspaceAutoGen
import WorkspaceAutoGen
33 from AutoGen
.AutoGenWorker
import AutoGenWorkerInProcess
,AutoGenManager
,\
35 from AutoGen
import GenMake
36 from Common
import Misc
as Utils
38 from Common
.TargetTxtClassObject
import TargetTxt
39 from Common
.ToolDefClassObject
import ToolDef
40 from Common
.Misc
import PathClass
,SaveFileOnChange
,RemoveDirectory
41 from Common
.StringUtils
import NormPath
42 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
43 from Common
.BuildToolError
import *
44 from Common
.DataType
import *
45 import Common
.EdkLogger
as EdkLogger
47 from Workspace
.WorkspaceDatabase
import BuildDB
49 from BuildReport
import BuildReport
50 from GenPatchPcdTable
.GenPatchPcdTable
import PeImageClass
,parsePcdInfoFromMapFile
51 from PatchPcdValue
.PatchPcdValue
import PatchBinaryFile
53 import Common
.GlobalData
as GlobalData
54 from GenFds
.GenFds
import GenFds
, GenFdsApi
55 import multiprocessing
as mp
56 from multiprocessing
import Manager
57 from AutoGen
.DataPipe
import MemoryDataPipe
58 from AutoGen
.ModuleAutoGenHelper
import WorkSpaceInfo
, PlatformInfo
59 from GenFds
.FdfParser
import FdfParser
60 from AutoGen
.IncludesAutoGen
import IncludesAutoGen
62 ## standard targets of build command
63 gSupportedTarget
= ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
65 ## build configuration file
66 gBuildConfiguration
= "target.txt"
67 gToolsDefinition
= "tools_def.txt"
69 TemporaryTablePattern
= re
.compile(r
'^_\d+_\d+_[a-fA-F0-9]+$')
72 ## Check environment PATH variable to make sure the specified tool is found
74 # If the tool is found in the PATH, then True is returned
75 # Otherwise, False is returned
77 def IsToolInPath(tool
):
78 if 'PATHEXT' in os
.environ
:
79 extns
= os
.environ
['PATHEXT'].split(os
.path
.pathsep
)
82 for pathDir
in os
.environ
['PATH'].split(os
.path
.pathsep
):
84 if os
.path
.exists(os
.path
.join(pathDir
, tool
+ ext
)):
88 ## Check environment variables
90 # Check environment variables that must be set for build. Currently they are
92 # WORKSPACE The directory all packages/platforms start from
93 # EDK_TOOLS_PATH The directory contains all tools needed by the build
94 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
96 # If any of above environment variable is not set or has error, the build
99 def CheckEnvVariable():
101 if "WORKSPACE" not in os
.environ
:
102 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
103 ExtraData
="WORKSPACE")
105 WorkspaceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["WORKSPACE"]))
106 if not os
.path
.exists(WorkspaceDir
):
107 EdkLogger
.error("build", FILE_NOT_FOUND
, "WORKSPACE doesn't exist", ExtraData
=WorkspaceDir
)
108 elif ' ' in WorkspaceDir
:
109 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in WORKSPACE path",
110 ExtraData
=WorkspaceDir
)
111 os
.environ
["WORKSPACE"] = WorkspaceDir
113 # set multiple workspace
114 PackagesPath
= os
.getenv("PACKAGES_PATH")
115 mws
.setWs(WorkspaceDir
, PackagesPath
)
116 if mws
.PACKAGES_PATH
:
117 for Path
in mws
.PACKAGES_PATH
:
118 if not os
.path
.exists(Path
):
119 EdkLogger
.error("build", FILE_NOT_FOUND
, "One Path in PACKAGES_PATH doesn't exist", ExtraData
=Path
)
121 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in PACKAGES_PATH", ExtraData
=Path
)
124 os
.environ
["EDK_TOOLS_PATH"] = os
.path
.normcase(os
.environ
["EDK_TOOLS_PATH"])
126 # check EDK_TOOLS_PATH
127 if "EDK_TOOLS_PATH" not in os
.environ
:
128 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
129 ExtraData
="EDK_TOOLS_PATH")
132 if "PATH" not in os
.environ
:
133 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
136 GlobalData
.gWorkspace
= WorkspaceDir
138 GlobalData
.gGlobalDefines
["WORKSPACE"] = WorkspaceDir
139 GlobalData
.gGlobalDefines
["EDK_TOOLS_PATH"] = os
.environ
["EDK_TOOLS_PATH"]
141 ## Get normalized file path
143 # Convert the path to be local format, and remove the WORKSPACE path at the
144 # beginning if the file path is given in full path.
146 # @param FilePath File path to be normalized
147 # @param Workspace Workspace path which the FilePath will be checked against
149 # @retval string The normalized file path
151 def NormFile(FilePath
, Workspace
):
152 # check if the path is absolute or relative
153 if os
.path
.isabs(FilePath
):
154 FileFullPath
= os
.path
.normpath(FilePath
)
156 FileFullPath
= os
.path
.normpath(mws
.join(Workspace
, FilePath
))
157 Workspace
= mws
.getWs(Workspace
, FilePath
)
159 # check if the file path exists or not
160 if not os
.path
.isfile(FileFullPath
):
161 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath
)
163 # remove workspace directory from the beginning part of the file path
164 if Workspace
[-1] in ["\\", "/"]:
165 return FileFullPath
[len(Workspace
):]
167 return FileFullPath
[(len(Workspace
) + 1):]
169 ## Get the output of an external program
171 # This is the entrance method of thread reading output of an external program and
172 # putting them in STDOUT/STDERR of current program.
174 # @param From The stream message read from
175 # @param To The stream message put on
176 # @param ExitFlag The flag used to indicate stopping reading
178 def ReadMessage(From
, To
, ExitFlag
,MemTo
=None):
180 # read one line a time
181 Line
= From
.readline()
182 # empty string means "end"
183 if Line
is not None and Line
!= b
"":
184 LineStr
= Line
.rstrip().decode(encoding
='utf-8', errors
='ignore')
185 if MemTo
is not None:
186 if "Note: including file:" == LineStr
.lstrip()[:21]:
187 MemTo
.append(LineStr
)
190 MemTo
.append(LineStr
)
198 class MakeSubProc(Popen
):
199 def __init__(self
,*args
, **argv
):
200 super(MakeSubProc
,self
).__init
__(*args
, **argv
)
203 ## Launch an external program
205 # This method will call subprocess.Popen to execute an external program with
206 # given options in specified directory. Because of the dead-lock issue during
207 # redirecting output of the external program, threads are used to to do the
210 # @param Command A list or string containing the call of the program
211 # @param WorkingDir The directory in which the program will be running
213 def LaunchCommand(Command
, WorkingDir
,ModuleAuto
= None):
214 BeginTime
= time
.time()
215 # if working directory doesn't exist, Popen() will raise an exception
216 if not os
.path
.isdir(WorkingDir
):
217 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=WorkingDir
)
219 # Command is used as the first Argument in following Popen().
220 # It could be a string or sequence. We find that if command is a string in following Popen(),
221 # ubuntu may fail with an error message that the command is not found.
222 # So here we may need convert command from string to list instance.
223 if platform
.system() != 'Windows':
224 if not isinstance(Command
, list):
225 Command
= Command
.split()
226 Command
= ' '.join(Command
)
229 EndOfProcedure
= None
232 Proc
= MakeSubProc(Command
, stdout
=PIPE
, stderr
=PIPE
, env
=os
.environ
, cwd
=WorkingDir
, bufsize
=-1, shell
=True)
234 # launch two threads to read the STDOUT and STDERR
235 EndOfProcedure
= Event()
236 EndOfProcedure
.clear()
238 StdOutThread
= Thread(target
=ReadMessage
, args
=(Proc
.stdout
, EdkLogger
.info
, EndOfProcedure
,Proc
.ProcOut
))
239 StdOutThread
.setName("STDOUT-Redirector")
240 StdOutThread
.setDaemon(False)
244 StdErrThread
= Thread(target
=ReadMessage
, args
=(Proc
.stderr
, EdkLogger
.quiet
, EndOfProcedure
,Proc
.ProcOut
))
245 StdErrThread
.setName("STDERR-Redirector")
246 StdErrThread
.setDaemon(False)
249 # waiting for program exit
251 except: # in case of aborting
252 # terminate the threads redirecting the program output
253 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
254 if EndOfProcedure
is not None:
257 if not isinstance(Command
, type("")):
258 Command
= " ".join(Command
)
259 EdkLogger
.error("build", COMMAND_FAILURE
, "Failed to start command", ExtraData
="%s [%s]" % (Command
, WorkingDir
))
266 # check the return code of the program
267 if Proc
.returncode
!= 0:
268 if not isinstance(Command
, type("")):
269 Command
= " ".join(Command
)
270 # print out the Response file and its content when make failure
271 RespFile
= os
.path
.join(WorkingDir
, 'OUTPUT', 'respfilelist.txt')
272 if os
.path
.isfile(RespFile
):
274 RespContent
= f
.read()
276 EdkLogger
.info(RespContent
)
278 EdkLogger
.error("build", COMMAND_FAILURE
, ExtraData
="%s [%s]" % (Command
, WorkingDir
))
280 iau
= IncludesAutoGen(WorkingDir
,ModuleAuto
)
281 if ModuleAuto
.ToolChainFamily
== TAB_COMPILER_MSFT
:
282 iau
.CreateDepsFileForMsvc(Proc
.ProcOut
)
284 iau
.UpdateDepsFileforNonMsvc()
285 iau
.UpdateDepsFileforTrim()
286 iau
.CreateModuleDeps()
287 iau
.CreateDepsInclude()
288 return "%dms" % (int(round((time
.time() - BeginTime
) * 1000)))
290 ## The smallest unit that can be built in multi-thread build mode
292 # This is the base class of build unit. The "Obj" parameter must provide
293 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
296 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
301 # @param self The object pointer
302 # @param Obj The object the build is working on
303 # @param Target The build target name, one of gSupportedTarget
304 # @param Dependency The BuildUnit(s) which must be completed in advance
305 # @param WorkingDir The directory build command starts in
307 def __init__(self
, Obj
, BuildCommand
, Target
, Dependency
, WorkingDir
="."):
308 self
.BuildObject
= Obj
309 self
.Dependency
= Dependency
310 self
.WorkingDir
= WorkingDir
312 self
.BuildCommand
= BuildCommand
314 EdkLogger
.error("build", OPTION_MISSING
,
315 "No build command found for this module. "
316 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
317 (Obj
.BuildTarget
, Obj
.ToolChain
, Obj
.Arch
),
323 # It just returns the string representation of self.BuildObject
325 # @param self The object pointer
328 return str(self
.BuildObject
)
330 ## "==" operator method
332 # It just compares self.BuildObject with "Other". So self.BuildObject must
333 # provide its own __eq__() method.
335 # @param self The object pointer
336 # @param Other The other BuildUnit object compared to
338 def __eq__(self
, Other
):
339 return Other
and self
.BuildObject
== Other
.BuildObject \
340 and Other
.BuildObject \
341 and self
.BuildObject
.Arch
== Other
.BuildObject
.Arch
345 # It just returns the hash value of self.BuildObject which must be hashable.
347 # @param self The object pointer
350 return hash(self
.BuildObject
) + hash(self
.BuildObject
.Arch
)
353 return repr(self
.BuildObject
)
355 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
357 # This class is for module build by nmake/make build system. The "Obj" parameter
358 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
359 # be make units missing build.
361 # Currently the "Obj" should be only ModuleAutoGen object.
363 class ModuleMakeUnit(BuildUnit
):
366 # @param self The object pointer
367 # @param Obj The ModuleAutoGen object the build is working on
368 # @param Target The build target name, one of gSupportedTarget
370 def __init__(self
, Obj
, BuildCommand
,Target
):
371 Dependency
= [ModuleMakeUnit(La
, BuildCommand
,Target
) for La
in Obj
.LibraryAutoGenList
]
372 BuildUnit
.__init
__(self
, Obj
, BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
373 if Target
in [None, "", "all"]:
374 self
.Target
= "tbuild"
376 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
378 # This class is for platform build by nmake/make build system. The "Obj" parameter
379 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
380 # be make units missing build.
382 # Currently the "Obj" should be only PlatformAutoGen object.
384 class PlatformMakeUnit(BuildUnit
):
387 # @param self The object pointer
388 # @param Obj The PlatformAutoGen object the build is working on
389 # @param Target The build target name, one of gSupportedTarget
391 def __init__(self
, Obj
, BuildCommand
, Target
):
392 Dependency
= [ModuleMakeUnit(Lib
, BuildCommand
, Target
) for Lib
in self
.BuildObject
.LibraryAutoGenList
]
393 Dependency
.extend([ModuleMakeUnit(Mod
, BuildCommand
,Target
) for Mod
in self
.BuildObject
.ModuleAutoGenList
])
394 BuildUnit
.__init
__(self
, Obj
, BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
396 ## The class representing the task of a module build or platform build
398 # This class manages the build tasks in multi-thread build mode. Its jobs include
399 # scheduling thread running, catching thread error, monitor the thread status, etc.
402 # queue for tasks waiting for schedule
403 _PendingQueue
= OrderedDict()
404 _PendingQueueLock
= threading
.Lock()
406 # queue for tasks ready for running
407 _ReadyQueue
= OrderedDict()
408 _ReadyQueueLock
= threading
.Lock()
410 # queue for run tasks
411 _RunningQueue
= OrderedDict()
412 _RunningQueueLock
= threading
.Lock()
414 # queue containing all build tasks, in case duplicate build
415 _TaskQueue
= OrderedDict()
417 # flag indicating error occurs in a running thread
418 _ErrorFlag
= threading
.Event()
422 # BoundedSemaphore object used to control the number of running threads
425 # flag indicating if the scheduler is started or not
426 _SchedulerStopped
= threading
.Event()
427 _SchedulerStopped
.set()
429 ## Start the task scheduler thread
431 # @param MaxThreadNumber The maximum thread number
432 # @param ExitFlag Flag used to end the scheduler
435 def StartScheduler(MaxThreadNumber
, ExitFlag
):
436 SchedulerThread
= Thread(target
=BuildTask
.Scheduler
, args
=(MaxThreadNumber
, ExitFlag
))
437 SchedulerThread
.setName("Build-Task-Scheduler")
438 SchedulerThread
.setDaemon(False)
439 SchedulerThread
.start()
440 # wait for the scheduler to be started, especially useful in Linux
441 while not BuildTask
.IsOnGoing():
446 # @param MaxThreadNumber The maximum thread number
447 # @param ExitFlag Flag used to end the scheduler
450 def Scheduler(MaxThreadNumber
, ExitFlag
):
451 BuildTask
._SchedulerStopped
.clear()
453 # use BoundedSemaphore to control the maximum running threads
454 BuildTask
._Thread
= BoundedSemaphore(MaxThreadNumber
)
456 # scheduling loop, which will exits when no pending/ready task and
457 # indicated to do so, or there's error in running thread
459 while (len(BuildTask
._PendingQueue
) > 0 or len(BuildTask
._ReadyQueue
) > 0 \
460 or not ExitFlag
.isSet()) and not BuildTask
._ErrorFlag
.isSet():
461 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Pending Queue (%d), Ready Queue (%d)"
462 % (len(BuildTask
._PendingQueue
), len(BuildTask
._ReadyQueue
)))
464 # get all pending tasks
465 BuildTask
._PendingQueueLock
.acquire()
466 BuildObjectList
= list(BuildTask
._PendingQueue
.keys())
468 # check if their dependency is resolved, and if true, move them
471 for BuildObject
in BuildObjectList
:
472 Bt
= BuildTask
._PendingQueue
[BuildObject
]
474 BuildTask
._ReadyQueue
[BuildObject
] = BuildTask
._PendingQueue
.pop(BuildObject
)
475 BuildTask
._PendingQueueLock
.release()
477 # launch build thread until the maximum number of threads is reached
478 while not BuildTask
._ErrorFlag
.isSet():
479 # empty ready queue, do nothing further
480 if len(BuildTask
._ReadyQueue
) == 0:
483 # wait for active thread(s) exit
484 BuildTask
._Thread
.acquire(True)
486 # start a new build thread
487 Bo
, Bt
= BuildTask
._ReadyQueue
.popitem()
489 # move into running queue
490 BuildTask
._RunningQueueLock
.acquire()
491 BuildTask
._RunningQueue
[Bo
] = Bt
492 BuildTask
._RunningQueueLock
.release()
501 # wait for all running threads exit
502 if BuildTask
._ErrorFlag
.isSet():
503 EdkLogger
.quiet("\nWaiting for all build threads exit...")
504 # while not BuildTask._ErrorFlag.isSet() and \
505 while len(BuildTask
._RunningQueue
) > 0:
506 EdkLogger
.verbose("Waiting for thread ending...(%d)" % len(BuildTask
._RunningQueue
))
507 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Threads [%s]" % ", ".join(Th
.getName() for Th
in threading
.enumerate()))
510 except BaseException
as X
:
512 # TRICK: hide the output of threads left running, so that the user can
513 # catch the error message easily
515 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
516 BuildTask
._ErrorFlag
.set()
517 BuildTask
._ErrorMessage
= "build thread scheduler error\n\t%s" % str(X
)
519 BuildTask
._PendingQueue
.clear()
520 BuildTask
._ReadyQueue
.clear()
521 BuildTask
._RunningQueue
.clear()
522 BuildTask
._TaskQueue
.clear()
523 BuildTask
._SchedulerStopped
.set()
525 ## Wait for all running method exit
528 def WaitForComplete():
529 BuildTask
._SchedulerStopped
.wait()
531 ## Check if the scheduler is running or not
535 return not BuildTask
._SchedulerStopped
.isSet()
540 if BuildTask
.IsOnGoing():
541 BuildTask
._ErrorFlag
.set()
542 BuildTask
.WaitForComplete()
544 ## Check if there's error in running thread
546 # Since the main thread cannot catch exceptions in other thread, we have to
547 # use threading.Event to communicate this formation to main thread.
551 return BuildTask
._ErrorFlag
.isSet()
553 ## Get error message in running thread
555 # Since the main thread cannot catch exceptions in other thread, we have to
556 # use a static variable to communicate this message to main thread.
559 def GetErrorMessage():
560 return BuildTask
._ErrorMessage
562 ## Factory method to create a BuildTask object
564 # This method will check if a module is building or has been built. And if
565 # true, just return the associated BuildTask object in the _TaskQueue. If
566 # not, create and return a new BuildTask object. The new BuildTask object
567 # will be appended to the _PendingQueue for scheduling later.
569 # @param BuildItem A BuildUnit object representing a build object
570 # @param Dependency The dependent build object of BuildItem
573 def New(BuildItem
, Dependency
=None):
574 if BuildItem
in BuildTask
._TaskQueue
:
575 Bt
= BuildTask
._TaskQueue
[BuildItem
]
579 Bt
._Init
(BuildItem
, Dependency
)
580 BuildTask
._TaskQueue
[BuildItem
] = Bt
582 BuildTask
._PendingQueueLock
.acquire()
583 BuildTask
._PendingQueue
[BuildItem
] = Bt
584 BuildTask
._PendingQueueLock
.release()
588 ## The real constructor of BuildTask
590 # @param BuildItem A BuildUnit object representing a build object
591 # @param Dependency The dependent build object of BuildItem
593 def _Init(self
, BuildItem
, Dependency
=None):
594 self
.BuildItem
= BuildItem
596 self
.DependencyList
= []
597 if Dependency
is None:
598 Dependency
= BuildItem
.Dependency
600 Dependency
.extend(BuildItem
.Dependency
)
601 self
.AddDependency(Dependency
)
602 # flag indicating build completes, used to avoid unnecessary re-build
603 self
.CompleteFlag
= False
605 ## Check if all dependent build tasks are completed or not
609 for Dep
in self
.DependencyList
:
610 if Dep
.CompleteFlag
== True:
617 ## Add dependent build task
619 # @param Dependency The list of dependent build objects
621 def AddDependency(self
, Dependency
):
622 for Dep
in Dependency
:
623 if not Dep
.BuildObject
.IsBinaryModule
and not Dep
.BuildObject
.CanSkipbyCache(GlobalData
.gCacheIR
):
624 self
.DependencyList
.append(BuildTask
.New(Dep
)) # BuildTask list
626 ## The thread wrapper of LaunchCommand function
628 # @param Command A list or string contains the call of the command
629 # @param WorkingDir The directory in which the program will be running
631 def _CommandThread(self
, Command
, WorkingDir
):
633 self
.BuildItem
.BuildObject
.BuildTime
= LaunchCommand(Command
, WorkingDir
,self
.BuildItem
.BuildObject
)
634 self
.CompleteFlag
= True
636 # Run hash operation post dependency, to account for libs
637 if GlobalData
.gUseHashCache
and self
.BuildItem
.BuildObject
.IsLibrary
:
638 HashFile
= path
.join(self
.BuildItem
.BuildObject
.BuildDir
, self
.BuildItem
.BuildObject
.Name
+ ".hash")
639 SaveFileOnChange(HashFile
, self
.BuildItem
.BuildObject
.GenModuleHash(), True)
642 # TRICK: hide the output of threads left running, so that the user can
643 # catch the error message easily
645 if not BuildTask
._ErrorFlag
.isSet():
646 GlobalData
.gBuildingModule
= "%s [%s, %s, %s]" % (str(self
.BuildItem
.BuildObject
),
647 self
.BuildItem
.BuildObject
.Arch
,
648 self
.BuildItem
.BuildObject
.ToolChain
,
649 self
.BuildItem
.BuildObject
.BuildTarget
651 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
652 BuildTask
._ErrorFlag
.set()
653 BuildTask
._ErrorMessage
= "%s broken\n %s [%s]" % \
654 (threading
.currentThread().getName(), Command
, WorkingDir
)
656 # Set the value used by hash invalidation flow in GlobalData.gModuleBuildTracking to 'SUCCESS'
657 # If Module or Lib is being tracked, it did not fail header check test, and built successfully
658 if (self
.BuildItem
.BuildObject
in GlobalData
.gModuleBuildTracking
and
659 GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
] != 'FAIL_METAFILE' and
660 not BuildTask
._ErrorFlag
.isSet()
662 GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
] = 'SUCCESS'
664 # indicate there's a thread is available for another build task
665 BuildTask
._RunningQueueLock
.acquire()
666 BuildTask
._RunningQueue
.pop(self
.BuildItem
)
667 BuildTask
._RunningQueueLock
.release()
668 BuildTask
._Thread
.release()
670 ## Start build task thread
673 EdkLogger
.quiet("Building ... %s" % repr(self
.BuildItem
))
674 Command
= self
.BuildItem
.BuildCommand
+ [self
.BuildItem
.Target
]
675 self
.BuildTread
= Thread(target
=self
._CommandThread
, args
=(Command
, self
.BuildItem
.WorkingDir
))
676 self
.BuildTread
.setName("build thread")
677 self
.BuildTread
.setDaemon(False)
678 self
.BuildTread
.start()
680 ## The class contains the information related to EFI image
685 # Constructor will load all required image information.
687 # @param BaseName The full file path of image.
688 # @param Guid The GUID for image.
689 # @param Arch Arch of this image.
690 # @param OutputDir The output directory for image.
691 # @param DebugDir The debug directory for image.
692 # @param ImageClass PeImage Information
694 def __init__(self
, BaseName
, Guid
, Arch
, OutputDir
, DebugDir
, ImageClass
):
695 self
.BaseName
= BaseName
698 self
.OutputDir
= OutputDir
699 self
.DebugDir
= DebugDir
700 self
.Image
= ImageClass
701 self
.Image
.Size
= (self
.Image
.Size
// 0x1000 + 1) * 0x1000
703 ## The class implementing the EDK2 build process
705 # The build process includes:
706 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
707 # 2. Parse DSC file of active platform
708 # 3. Parse FDF file if any
709 # 4. Establish build database, including parse all other files (module, package)
710 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
711 # 6. Call build command
716 # Constructor will load all necessary configurations, parse platform, modules
717 # and packages and the establish a database for AutoGen.
719 # @param Target The build command target, one of gSupportedTarget
720 # @param WorkspaceDir The directory of workspace
721 # @param BuildOptions Build options passed from command line
723 def __init__(self
, Target
, WorkspaceDir
, BuildOptions
,log_q
):
724 self
.WorkspaceDir
= WorkspaceDir
726 self
.PlatformFile
= BuildOptions
.PlatformFile
727 self
.ModuleFile
= BuildOptions
.ModuleFile
728 self
.ArchList
= BuildOptions
.TargetArch
729 self
.ToolChainList
= BuildOptions
.ToolChain
730 self
.BuildTargetList
= BuildOptions
.BuildTarget
731 self
.Fdf
= BuildOptions
.FdfFile
732 self
.FdList
= BuildOptions
.RomImage
733 self
.FvList
= BuildOptions
.FvImage
734 self
.CapList
= BuildOptions
.CapName
735 self
.SilentMode
= BuildOptions
.SilentMode
736 self
.ThreadNumber
= 1
737 self
.SkipAutoGen
= BuildOptions
.SkipAutoGen
738 self
.Reparse
= BuildOptions
.Reparse
739 self
.SkuId
= BuildOptions
.SkuId
741 GlobalData
.gSKUID_CMD
= self
.SkuId
742 self
.ConfDirectory
= BuildOptions
.ConfDirectory
743 self
.SpawnMode
= True
744 self
.BuildReport
= BuildReport(BuildOptions
.ReportFile
, BuildOptions
.ReportType
)
745 self
.TargetTxt
= TargetTxt
746 self
.ToolDef
= ToolDef
750 GlobalData
.BuildOptionPcd
= BuildOptions
.OptionPcd
if BuildOptions
.OptionPcd
else []
751 #Set global flag for build mode
752 GlobalData
.gIgnoreSource
= BuildOptions
.IgnoreSources
753 GlobalData
.gUseHashCache
= BuildOptions
.UseHashCache
754 GlobalData
.gBinCacheDest
= BuildOptions
.BinCacheDest
755 GlobalData
.gBinCacheSource
= BuildOptions
.BinCacheSource
756 GlobalData
.gEnableGenfdsMultiThread
= not BuildOptions
.NoGenfdsMultiThread
757 GlobalData
.gDisableIncludePathCheck
= BuildOptions
.DisableIncludePathCheck
759 if GlobalData
.gBinCacheDest
and not GlobalData
.gUseHashCache
:
760 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination must be used together with --hash.")
762 if GlobalData
.gBinCacheSource
and not GlobalData
.gUseHashCache
:
763 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-source must be used together with --hash.")
765 if GlobalData
.gBinCacheDest
and GlobalData
.gBinCacheSource
:
766 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination can not be used together with --binary-source.")
768 if GlobalData
.gBinCacheSource
:
769 BinCacheSource
= os
.path
.normpath(GlobalData
.gBinCacheSource
)
770 if not os
.path
.isabs(BinCacheSource
):
771 BinCacheSource
= mws
.join(self
.WorkspaceDir
, BinCacheSource
)
772 GlobalData
.gBinCacheSource
= BinCacheSource
774 if GlobalData
.gBinCacheSource
is not None:
775 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-source.")
777 if GlobalData
.gBinCacheDest
:
778 BinCacheDest
= os
.path
.normpath(GlobalData
.gBinCacheDest
)
779 if not os
.path
.isabs(BinCacheDest
):
780 BinCacheDest
= mws
.join(self
.WorkspaceDir
, BinCacheDest
)
781 GlobalData
.gBinCacheDest
= BinCacheDest
783 if GlobalData
.gBinCacheDest
is not None:
784 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-destination.")
786 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(GlobalData
.gConfDirectory
, GlobalData
.gDatabasePath
))
787 if not os
.path
.exists(os
.path
.join(GlobalData
.gConfDirectory
, '.cache')):
788 os
.makedirs(os
.path
.join(GlobalData
.gConfDirectory
, '.cache'))
790 self
.BuildDatabase
= self
.Db
.BuildObject
792 self
.ToolChainFamily
= None
793 self
.LoadFixAddress
= 0
794 self
.UniFlag
= BuildOptions
.Flag
795 self
.BuildModules
= []
796 self
.HashSkipModules
= []
798 self
.LaunchPrebuildFlag
= False
799 self
.PlatformBuildPath
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PlatformBuild')
800 if BuildOptions
.CommandLength
:
801 GlobalData
.gCommandMaxLength
= BuildOptions
.CommandLength
803 # print dot character during doing some time-consuming work
804 self
.Progress
= Utils
.Progressor()
805 # print current build environment and configuration
806 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
807 if "PACKAGES_PATH" in os
.environ
:
808 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
809 EdkLogger
.quiet("%-16s = %s" % ("PACKAGES_PATH", os
.path
.normcase(os
.path
.normpath(os
.environ
["PACKAGES_PATH"]))))
810 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
811 if "EDK_TOOLS_BIN" in os
.environ
:
812 # Print the same path style with WORKSPACE env.
813 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_TOOLS_BIN"]))))
814 EdkLogger
.quiet("%-16s = %s" % ("CONF_PATH", GlobalData
.gConfDirectory
))
815 if "PYTHON3_ENABLE" in os
.environ
:
816 PYTHON3_ENABLE
= os
.environ
["PYTHON3_ENABLE"]
817 if PYTHON3_ENABLE
!= "TRUE":
818 PYTHON3_ENABLE
= "FALSE"
819 EdkLogger
.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE
))
820 if "PYTHON_COMMAND" in os
.environ
:
821 EdkLogger
.quiet("%-16s = %s" % ("PYTHON_COMMAND", os
.environ
["PYTHON_COMMAND"]))
825 EdkLogger
.quiet("%-16s = %s" % ("PREBUILD", self
.Prebuild
))
827 EdkLogger
.quiet("%-16s = %s" % ("POSTBUILD", self
.Postbuild
))
829 self
.LaunchPrebuild()
830 self
.TargetTxt
= TargetTxt
831 self
.ToolDef
= ToolDef
832 if not (self
.LaunchPrebuildFlag
and os
.path
.exists(self
.PlatformBuildPath
)):
835 self
.AutoGenMgr
= None
837 os
.chdir(self
.WorkspaceDir
)
838 GlobalData
.gCacheIR
= Manager().dict()
840 GlobalData
.file_lock
= mp
.Lock()
841 GlobalData
.cache_lock
= mp
.Lock()
842 def StartAutoGen(self
,mqueue
, DataPipe
,SkipAutoGen
,PcdMaList
,share_data
):
846 feedback_q
= mp
.Queue()
847 error_event
= mp
.Event()
848 FfsCmd
= DataPipe
.Get("FfsCommand")
851 GlobalData
.FfsCmd
= FfsCmd
852 GlobalData
.libConstPcd
= DataPipe
.Get("LibConstPcd")
853 GlobalData
.Refes
= DataPipe
.Get("REFS")
854 auto_workers
= [AutoGenWorkerInProcess(mqueue
,DataPipe
.dump_file
,feedback_q
,GlobalData
.file_lock
,GlobalData
.cache_lock
,share_data
,self
.log_q
,error_event
) for _
in range(self
.ThreadNumber
)]
855 self
.AutoGenMgr
= AutoGenManager(auto_workers
,feedback_q
,error_event
)
856 self
.AutoGenMgr
.start()
857 for w
in auto_workers
:
859 if PcdMaList
is not None:
860 for PcdMa
in PcdMaList
:
861 if GlobalData
.gBinCacheSource
and self
.Target
in [None, "", "all"]:
862 PcdMa
.GenModuleFilesHash(share_data
)
863 PcdMa
.GenPreMakefileHash(share_data
)
864 if PcdMa
.CanSkipbyPreMakefileCache(share_data
):
867 PcdMa
.CreateCodeFile(False)
868 PcdMa
.CreateMakeFile(False,GenFfsList
= DataPipe
.Get("FfsCommand").get((PcdMa
.MetaFile
.Path
, PcdMa
.Arch
),[]))
870 if GlobalData
.gBinCacheSource
and self
.Target
in [None, "", "all"]:
871 PcdMa
.GenMakeHeaderFilesHash(share_data
)
872 PcdMa
.GenMakeHash(share_data
)
873 if PcdMa
.CanSkipbyMakeCache(share_data
):
876 self
.AutoGenMgr
.join()
877 rt
= self
.AutoGenMgr
.Status
879 except FatalError
as e
:
880 return False, e
.args
[0]
882 return False, UNKNOWN_ERROR
884 ## Load configuration
886 # This method will parse target.txt and get the build configurations.
888 def LoadConfiguration(self
):
890 # if no ARCH given in command line, get it from target.txt
891 if not self
.ArchList
:
892 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET_ARCH
]
893 self
.ArchList
= tuple(self
.ArchList
)
895 # if no build target given in command line, get it from target.txt
896 if not self
.BuildTargetList
:
897 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
899 # if no tool chain given in command line, get it from target.txt
900 if not self
.ToolChainList
:
901 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
902 if self
.ToolChainList
is None or len(self
.ToolChainList
) == 0:
903 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
905 # check if the tool chains are defined or not
906 NewToolChainList
= []
907 for ToolChain
in self
.ToolChainList
:
908 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
909 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
911 NewToolChainList
.append(ToolChain
)
912 # if no tool chain available, break the build
913 if len(NewToolChainList
) == 0:
914 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
915 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
917 self
.ToolChainList
= NewToolChainList
920 ToolDefinition
= self
.ToolDef
.ToolsDefTxtDatabase
921 for Tool
in self
.ToolChainList
:
922 if TAB_TOD_DEFINES_FAMILY
not in ToolDefinition
or Tool
not in ToolDefinition
[TAB_TOD_DEFINES_FAMILY
] \
923 or not ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
]:
924 EdkLogger
.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool
)
925 ToolChainFamily
.append(TAB_COMPILER_MSFT
)
927 ToolChainFamily
.append(ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
])
928 self
.ToolChainFamily
= ToolChainFamily
930 if not self
.PlatformFile
:
931 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
933 # Try to find one in current directory
934 WorkingDirectory
= os
.getcwd()
935 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
936 FileNum
= len(FileList
)
938 EdkLogger
.error("build", OPTION_MISSING
,
939 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
941 PlatformFile
= FileList
[0]
943 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
944 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
946 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
947 self
.ThreadNumber
= ThreadNum()
948 ## Initialize build configuration
950 # This method will parse DSC file and merge the configurations from
951 # command line and target.txt, then get the final build configurations.
954 # parse target.txt, tools_def.txt, and platform file
955 self
.LoadConfiguration()
957 # Allow case-insensitive for those from command line or configuration file
958 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
960 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
963 def InitPreBuild(self
):
964 self
.LoadConfiguration()
965 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
967 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
968 if self
.BuildTargetList
:
969 GlobalData
.gGlobalDefines
['TARGET'] = self
.BuildTargetList
[0]
971 GlobalData
.gGlobalDefines
['ARCH'] = self
.ArchList
[0]
972 if self
.ToolChainList
:
973 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = self
.ToolChainList
[0]
974 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = self
.ToolChainList
[0]
975 if self
.ToolChainFamily
:
976 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[0]
977 if 'PREBUILD' in GlobalData
.gCommandLineDefines
:
978 self
.Prebuild
= GlobalData
.gCommandLineDefines
.get('PREBUILD')
981 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
982 self
.Prebuild
= str(Platform
.Prebuild
)
986 # Evaluate all arguments and convert arguments that are WORKSPACE
987 # relative paths to absolute paths. Filter arguments that look like
988 # flags or do not follow the file/dir naming rules to avoid false
989 # positives on this conversion.
991 for Arg
in self
.Prebuild
.split():
993 # Do not modify Arg if it looks like a flag or an absolute file path
995 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
996 PrebuildList
.append(Arg
)
999 # Do not modify Arg if it does not look like a Workspace relative
1000 # path that starts with a valid package directory name
1002 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1003 PrebuildList
.append(Arg
)
1006 # If Arg looks like a WORKSPACE relative path, then convert to an
1007 # absolute path and check to see if the file exists.
1009 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1010 if os
.path
.isfile(Temp
):
1012 PrebuildList
.append(Arg
)
1013 self
.Prebuild
= ' '.join(PrebuildList
)
1014 self
.Prebuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1016 def InitPostBuild(self
):
1017 if 'POSTBUILD' in GlobalData
.gCommandLineDefines
:
1018 self
.Postbuild
= GlobalData
.gCommandLineDefines
.get('POSTBUILD')
1020 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
1021 self
.Postbuild
= str(Platform
.Postbuild
)
1025 # Evaluate all arguments and convert arguments that are WORKSPACE
1026 # relative paths to absolute paths. Filter arguments that look like
1027 # flags or do not follow the file/dir naming rules to avoid false
1028 # positives on this conversion.
1030 for Arg
in self
.Postbuild
.split():
1032 # Do not modify Arg if it looks like a flag or an absolute file path
1034 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1035 PostbuildList
.append(Arg
)
1038 # Do not modify Arg if it does not look like a Workspace relative
1039 # path that starts with a valid package directory name
1041 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1042 PostbuildList
.append(Arg
)
1045 # If Arg looks like a WORKSPACE relative path, then convert to an
1046 # absolute path and check to see if the file exists.
1048 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1049 if os
.path
.isfile(Temp
):
1051 PostbuildList
.append(Arg
)
1052 self
.Postbuild
= ' '.join(PostbuildList
)
1053 self
.Postbuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1055 def PassCommandOption(self
, BuildTarget
, TargetArch
, ToolChain
, PlatformFile
, Target
):
1057 if GlobalData
.gCommand
and isinstance(GlobalData
.gCommand
, list):
1058 BuildStr
+= ' ' + ' '.join(GlobalData
.gCommand
)
1061 ToolChainFlag
= False
1062 PlatformFileFlag
= False
1064 if GlobalData
.gOptions
and not GlobalData
.gOptions
.BuildTarget
:
1066 if GlobalData
.gOptions
and not GlobalData
.gOptions
.TargetArch
:
1068 if GlobalData
.gOptions
and not GlobalData
.gOptions
.ToolChain
:
1069 ToolChainFlag
= True
1070 if GlobalData
.gOptions
and not GlobalData
.gOptions
.PlatformFile
:
1071 PlatformFileFlag
= True
1073 if TargetFlag
and BuildTarget
:
1074 if isinstance(BuildTarget
, list) or isinstance(BuildTarget
, tuple):
1075 BuildStr
+= ' -b ' + ' -b '.join(BuildTarget
)
1076 elif isinstance(BuildTarget
, str):
1077 BuildStr
+= ' -b ' + BuildTarget
1078 if ArchFlag
and TargetArch
:
1079 if isinstance(TargetArch
, list) or isinstance(TargetArch
, tuple):
1080 BuildStr
+= ' -a ' + ' -a '.join(TargetArch
)
1081 elif isinstance(TargetArch
, str):
1082 BuildStr
+= ' -a ' + TargetArch
1083 if ToolChainFlag
and ToolChain
:
1084 if isinstance(ToolChain
, list) or isinstance(ToolChain
, tuple):
1085 BuildStr
+= ' -t ' + ' -t '.join(ToolChain
)
1086 elif isinstance(ToolChain
, str):
1087 BuildStr
+= ' -t ' + ToolChain
1088 if PlatformFileFlag
and PlatformFile
:
1089 if isinstance(PlatformFile
, list) or isinstance(PlatformFile
, tuple):
1090 BuildStr
+= ' -p ' + ' -p '.join(PlatformFile
)
1091 elif isinstance(PlatformFile
, str):
1092 BuildStr
+= ' -p' + PlatformFile
1093 BuildStr
+= ' --conf=' + GlobalData
.gConfDirectory
1095 BuildStr
+= ' ' + Target
1099 def LaunchPrebuild(self
):
1101 EdkLogger
.info("\n- Prebuild Start -\n")
1102 self
.LaunchPrebuildFlag
= True
1104 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1105 # and preserve them for the rest of the main build step, because the child process environment will
1106 # evaporate as soon as it exits, we cannot get it in build step.
1108 PrebuildEnvFile
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PrebuildEnv')
1109 if os
.path
.isfile(PrebuildEnvFile
):
1110 os
.remove(PrebuildEnvFile
)
1111 if os
.path
.isfile(self
.PlatformBuildPath
):
1112 os
.remove(self
.PlatformBuildPath
)
1113 if sys
.platform
== "win32":
1114 args
= ' && '.join((self
.Prebuild
, 'set > ' + PrebuildEnvFile
))
1115 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1117 args
= ' && '.join((self
.Prebuild
, 'env > ' + PrebuildEnvFile
))
1118 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1120 # launch two threads to read the STDOUT and STDERR
1121 EndOfProcedure
= Event()
1122 EndOfProcedure
.clear()
1124 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1125 StdOutThread
.setName("STDOUT-Redirector")
1126 StdOutThread
.setDaemon(False)
1127 StdOutThread
.start()
1130 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1131 StdErrThread
.setName("STDERR-Redirector")
1132 StdErrThread
.setDaemon(False)
1133 StdErrThread
.start()
1134 # waiting for program exit
1141 if Process
.returncode
!= 0 :
1142 EdkLogger
.error("Prebuild", PREBUILD_ERROR
, 'Prebuild process is not success!')
1144 if os
.path
.exists(PrebuildEnvFile
):
1145 f
= open(PrebuildEnvFile
)
1146 envs
= f
.readlines()
1148 envs
= [l
.split("=", 1) for l
in envs
]
1149 envs
= [[I
.strip() for I
in item
] for item
in envs
if len(item
) == 2]
1150 os
.environ
.update(dict(envs
))
1151 EdkLogger
.info("\n- Prebuild Done -\n")
1153 def LaunchPostbuild(self
):
1155 EdkLogger
.info("\n- Postbuild Start -\n")
1156 if sys
.platform
== "win32":
1157 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1159 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1160 # launch two threads to read the STDOUT and STDERR
1161 EndOfProcedure
= Event()
1162 EndOfProcedure
.clear()
1164 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1165 StdOutThread
.setName("STDOUT-Redirector")
1166 StdOutThread
.setDaemon(False)
1167 StdOutThread
.start()
1170 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1171 StdErrThread
.setName("STDERR-Redirector")
1172 StdErrThread
.setDaemon(False)
1173 StdErrThread
.start()
1174 # waiting for program exit
1181 if Process
.returncode
!= 0 :
1182 EdkLogger
.error("Postbuild", POSTBUILD_ERROR
, 'Postbuild process is not success!')
1183 EdkLogger
.info("\n- Postbuild Done -\n")
1185 ## Error handling for hash feature
1187 # On BuildTask error, iterate through the Module Build tracking
1188 # dictionary to determine wheather a module failed to build. Invalidate
1189 # the hash associated with that module by removing it from storage.
1192 def invalidateHash(self
):
1193 # Only for hashing feature
1194 if not GlobalData
.gUseHashCache
:
1197 # GlobalData.gModuleBuildTracking contains only modules or libs that cannot be skipped by hash
1198 for Ma
in GlobalData
.gModuleBuildTracking
:
1199 # Skip invalidating for Successful Module/Lib builds
1200 if GlobalData
.gModuleBuildTracking
[Ma
] == 'SUCCESS':
1203 # The module failed to build, failed to start building, or failed the header check test from this point on
1205 # Remove .hash from build
1206 ModuleHashFile
= os
.path
.join(Ma
.BuildDir
, Ma
.Name
+ ".hash")
1207 if os
.path
.exists(ModuleHashFile
):
1208 os
.remove(ModuleHashFile
)
1210 # Remove .hash file from cache
1211 if GlobalData
.gBinCacheDest
:
1212 FileDir
= os
.path
.join(GlobalData
.gBinCacheDest
, Ma
.PlatformInfo
.OutputDir
, Ma
.BuildTarget
+ "_" + Ma
.ToolChain
, Ma
.Arch
, Ma
.SourceDir
, Ma
.MetaFile
.BaseName
)
1213 HashFile
= os
.path
.join(FileDir
, Ma
.Name
+ '.hash')
1214 if os
.path
.exists(HashFile
):
1217 ## Build a module or platform
1219 # Create autogen code and makefile for a module or platform, and the launch
1220 # "make" command to build it
1222 # @param Target The target of build command
1223 # @param Platform The platform file
1224 # @param Module The module file
1225 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1226 # @param ToolChain The name of toolchain to build
1227 # @param Arch The arch of the module/platform
1228 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1229 # for dependent modules/Libraries
1230 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1231 # for dependent modules/Libraries
1233 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False, FfsCommand
=None, PcdMaList
=None):
1234 if AutoGenObject
is None:
1236 if FfsCommand
is None:
1238 # skip file generation for cleanxxx targets, run and fds target
1239 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1240 # for target which must generate AutoGen code and makefile
1242 for m
in AutoGenObject
.GetAllModuleInfo
:
1245 AutoGenObject
.DataPipe
.DataContainer
= {"CommandTarget": self
.Target
}
1246 AutoGenObject
.DataPipe
.DataContainer
= {"Workspace_timestamp": AutoGenObject
.Workspace
._SrcTimeStamp
}
1247 AutoGenObject
.CreateLibModuelDirs()
1248 AutoGenObject
.DataPipe
.DataContainer
= {"LibraryBuildDirectoryList":AutoGenObject
.LibraryBuildDirectoryList
}
1249 AutoGenObject
.DataPipe
.DataContainer
= {"ModuleBuildDirectoryList":AutoGenObject
.ModuleBuildDirectoryList
}
1250 AutoGenObject
.DataPipe
.DataContainer
= {"FdsCommandDict": AutoGenObject
.Workspace
.GenFdsCommandDict
}
1251 self
.Progress
.Start("Generating makefile and code")
1252 data_pipe_file
= os
.path
.join(AutoGenObject
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(AutoGenObject
.Guid
),AutoGenObject
.Arch
))
1253 AutoGenObject
.DataPipe
.dump(data_pipe_file
)
1254 autogen_rt
,errorcode
= self
.StartAutoGen(mqueue
, AutoGenObject
.DataPipe
, self
.SkipAutoGen
, PcdMaList
, GlobalData
.gCacheIR
)
1255 AutoGenIdFile
= os
.path
.join(GlobalData
.gConfDirectory
,".AutoGenIdFile.txt")
1256 with
open(AutoGenIdFile
,"w") as fw
:
1257 fw
.write("Arch=%s\n" % "|".join((AutoGenObject
.Workspace
.ArchList
)))
1258 fw
.write("BuildDir=%s\n" % AutoGenObject
.Workspace
.BuildDir
)
1259 fw
.write("PlatformGuid=%s\n" % str(AutoGenObject
.Guid
))
1260 self
.Progress
.Stop("done!")
1262 self
.AutoGenMgr
.TerminateWorkers()
1263 self
.AutoGenMgr
.join(1)
1264 raise FatalError(errorcode
)
1265 AutoGenObject
.CreateCodeFile(False)
1266 AutoGenObject
.CreateMakeFile(False)
1268 # always recreate top/platform makefile when clean, just in case of inconsistency
1269 AutoGenObject
.CreateCodeFile(True)
1270 AutoGenObject
.CreateMakeFile(True)
1272 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1273 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1275 BuildCommand
= AutoGenObject
.BuildCommand
1276 if BuildCommand
is None or len(BuildCommand
) == 0:
1277 EdkLogger
.error("build", OPTION_MISSING
,
1278 "No build command found for this module. "
1279 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1280 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1281 ExtraData
=str(AutoGenObject
))
1283 makefile
= GenMake
.BuildFile(AutoGenObject
)._FILE
_NAME
_[GenMake
.gMakeType
]
1291 BuildCommand
= BuildCommand
+ [Target
]
1292 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1293 self
.CreateAsBuiltInf()
1294 if GlobalData
.gBinCacheDest
:
1295 self
.UpdateBuildCache()
1296 self
.BuildModules
= []
1300 if Target
== 'libraries':
1302 for Lib
in AutoGenObject
.LibraryAutoGenList
:
1303 if not Lib
.IsBinaryModule
:
1304 DirList
.append((os
.path
.join(AutoGenObject
.BuildDir
, Lib
.BuildDir
),Lib
))
1305 for Lib
, LibAutoGen
in DirList
:
1306 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1307 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
,LibAutoGen
)
1311 if Target
== 'modules':
1313 for Lib
in AutoGenObject
.LibraryAutoGenList
:
1314 if not Lib
.IsBinaryModule
:
1315 DirList
.append((os
.path
.join(AutoGenObject
.BuildDir
, Lib
.BuildDir
),Lib
))
1316 for Lib
, LibAutoGen
in DirList
:
1317 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1318 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
,LibAutoGen
)
1321 for ModuleAutoGen
in AutoGenObject
.ModuleAutoGenList
:
1322 if not ModuleAutoGen
.IsBinaryModule
:
1323 DirList
.append((os
.path
.join(AutoGenObject
.BuildDir
, ModuleAutoGen
.BuildDir
),ModuleAutoGen
))
1324 for Mod
,ModAutoGen
in DirList
:
1325 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, makefile
)), 'pbuild']
1326 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
,ModAutoGen
)
1327 self
.CreateAsBuiltInf()
1328 if GlobalData
.gBinCacheDest
:
1329 self
.UpdateBuildCache()
1330 self
.BuildModules
= []
1334 if Target
== 'cleanlib':
1335 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1336 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1337 if os
.path
.exists(LibMakefile
):
1338 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1339 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1343 if Target
== 'clean':
1344 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1345 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, makefile
))
1346 if os
.path
.exists(ModMakefile
):
1347 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
1348 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1349 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1350 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1351 if os
.path
.exists(LibMakefile
):
1352 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1353 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1357 if Target
== 'cleanall':
1359 #os.rmdir(AutoGenObject.BuildDir)
1360 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1361 except WindowsError as X
:
1362 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1365 ## Build a module or platform
1367 # Create autogen code and makefile for a module or platform, and the launch
1368 # "make" command to build it
1370 # @param Target The target of build command
1371 # @param Platform The platform file
1372 # @param Module The module file
1373 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1374 # @param ToolChain The name of toolchain to build
1375 # @param Arch The arch of the module/platform
1376 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1377 # for dependent modules/Libraries
1378 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1379 # for dependent modules/Libraries
1381 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1382 if AutoGenObject
is None:
1385 # skip file generation for cleanxxx targets, run and fds target
1386 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1387 # for target which must generate AutoGen code and makefile
1388 if not self
.SkipAutoGen
or Target
== 'genc':
1389 self
.Progress
.Start("Generating code")
1390 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1391 self
.Progress
.Stop("done!")
1392 if Target
== "genc":
1395 if not self
.SkipAutoGen
or Target
== 'genmake':
1396 self
.Progress
.Start("Generating makefile")
1397 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1398 #AutoGenObject.CreateAsBuiltInf()
1399 self
.Progress
.Stop("done!")
1400 if Target
== "genmake":
1403 # always recreate top/platform makefile when clean, just in case of inconsistency
1404 AutoGenObject
.CreateCodeFile(True)
1405 AutoGenObject
.CreateMakeFile(True)
1407 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1408 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1410 BuildCommand
= AutoGenObject
.BuildCommand
1411 if BuildCommand
is None or len(BuildCommand
) == 0:
1412 EdkLogger
.error("build", OPTION_MISSING
,
1413 "No build command found for this module. "
1414 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1415 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1416 ExtraData
=str(AutoGenObject
))
1421 BuildCommand
= BuildCommand
+ [Target
]
1422 AutoGenObject
.BuildTime
= LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1423 self
.CreateAsBuiltInf()
1424 if GlobalData
.gBinCacheDest
:
1425 self
.UpdateBuildCache()
1426 self
.BuildModules
= []
1431 if GenFdsApi(AutoGenObject
.GenFdsCommandDict
, self
.Db
):
1432 EdkLogger
.error("build", COMMAND_FAILURE
)
1440 if Target
== 'libraries':
1447 if Target
== 'cleanall':
1449 #os.rmdir(AutoGenObject.BuildDir)
1450 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1451 except WindowsError as X
:
1452 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1455 ## Rebase module image and Get function address for the input module list.
1457 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1459 AddrIsOffset
= False
1460 for InfFile
in ModuleList
:
1461 sys
.stdout
.write (".")
1463 ModuleInfo
= ModuleList
[InfFile
]
1464 ModuleName
= ModuleInfo
.BaseName
1465 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1466 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1467 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1469 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1471 # Update Image to new BaseAddress by GenFw tool
1473 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1474 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1477 # Set new address to the section header only for SMM driver.
1479 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1480 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1482 # Collect function address from Map file
1484 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1486 if os
.path
.exists(ImageMapTable
):
1487 OrigImageBaseAddress
= 0
1488 ImageMap
= open(ImageMapTable
, 'r')
1489 for LinStr
in ImageMap
:
1490 if len (LinStr
.strip()) == 0:
1493 # Get the preferred address set on link time.
1495 if LinStr
.find ('Preferred load address is') != -1:
1496 StrList
= LinStr
.split()
1497 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1499 StrList
= LinStr
.split()
1500 if len (StrList
) > 4:
1501 if StrList
[3] == 'f' or StrList
[3] == 'F':
1503 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1504 FunctionList
.append ((Name
, RelativeAddress
))
1508 # Add general information.
1511 MapBuffer
.append('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1513 MapBuffer
.append('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1515 MapBuffer
.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1517 # Add guid and general seciton section.
1519 TextSectionAddress
= 0
1520 DataSectionAddress
= 0
1521 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1522 if SectionHeader
[0] == '.text':
1523 TextSectionAddress
= SectionHeader
[1]
1524 elif SectionHeader
[0] in ['.data', '.sdata']:
1525 DataSectionAddress
= SectionHeader
[1]
1527 MapBuffer
.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1529 MapBuffer
.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1531 # Add debug image full path.
1533 MapBuffer
.append('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1535 # Add function address
1537 for Function
in FunctionList
:
1539 MapBuffer
.append(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1541 MapBuffer
.append(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1545 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1548 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1550 ## Collect MAP information of all FVs
1552 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1554 # First get the XIP base address for FV map file.
1555 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1556 GuidName
= re
.compile(r
"\(GUID=[-a-fA-F0-9]+")
1557 for FvName
in Wa
.FdfProfile
.FvDict
:
1558 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1559 if not os
.path
.exists(FvMapBuffer
):
1561 FvMap
= open(FvMapBuffer
, 'r')
1562 #skip FV size information
1568 MatchGuid
= GuidPattern
.match(Line
)
1569 if MatchGuid
is not None:
1571 # Replace GUID with module name
1573 GuidString
= MatchGuid
.group()
1574 if GuidString
.upper() in ModuleList
:
1575 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1576 MapBuffer
.append(Line
)
1578 # Add the debug image full path.
1580 MatchGuid
= GuidName
.match(Line
)
1581 if MatchGuid
is not None:
1582 GuidString
= MatchGuid
.group().split("=")[1]
1583 if GuidString
.upper() in ModuleList
:
1584 MapBuffer
.append('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1588 ## Collect MAP information of all modules
1590 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1591 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1593 PatchEfiImageList
= []
1601 # reserve 4K size in SMRAM to make SMM module address not from 0.
1603 for ModuleGuid
in ModuleList
:
1604 Module
= ModuleList
[ModuleGuid
]
1605 GlobalData
.gProcessingFile
= "%s [%s, %s, %s]" % (Module
.MetaFile
, Module
.Arch
, Module
.ToolChain
, Module
.BuildTarget
)
1607 OutputImageFile
= ''
1608 for ResultFile
in Module
.CodaTargetList
:
1609 if str(ResultFile
.Target
).endswith('.efi'):
1611 # module list for PEI, DXE, RUNTIME and SMM
1613 OutputImageFile
= os
.path
.join(Module
.OutputDir
, Module
.Name
+ '.efi')
1614 ImageClass
= PeImageClass (OutputImageFile
)
1615 if not ImageClass
.IsValid
:
1616 EdkLogger
.error("build", FILE_PARSE_FAILURE
, ExtraData
=ImageClass
.ErrorInfo
)
1617 ImageInfo
= PeImageInfo(Module
.Name
, Module
.Guid
, Module
.Arch
, Module
.OutputDir
, Module
.DebugDir
, ImageClass
)
1618 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
]:
1619 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1620 PeiSize
+= ImageInfo
.Image
.Size
1621 elif Module
.ModuleType
in [EDK_COMPONENT_TYPE_BS_DRIVER
, SUP_MODULE_DXE_DRIVER
, SUP_MODULE_UEFI_DRIVER
]:
1622 BtModuleList
[Module
.MetaFile
] = ImageInfo
1623 BtSize
+= ImageInfo
.Image
.Size
1624 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
]:
1625 RtModuleList
[Module
.MetaFile
] = ImageInfo
1626 RtSize
+= ImageInfo
.Image
.Size
1627 elif Module
.ModuleType
in [SUP_MODULE_SMM_CORE
, SUP_MODULE_DXE_SMM_DRIVER
, SUP_MODULE_MM_STANDALONE
, SUP_MODULE_MM_CORE_STANDALONE
]:
1628 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1629 SmmSize
+= ImageInfo
.Image
.Size
1630 if Module
.ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
1631 PiSpecVersion
= Module
.Module
.Specification
.get('PI_SPECIFICATION_VERSION', '0x00000000')
1632 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1633 if int(PiSpecVersion
, 16) < 0x0001000A:
1634 BtModuleList
[Module
.MetaFile
] = ImageInfo
1635 BtSize
+= ImageInfo
.Image
.Size
1638 # EFI image is final target.
1639 # Check EFI image contains patchable FixAddress related PCDs.
1641 if OutputImageFile
!= '':
1642 ModuleIsPatch
= False
1643 for Pcd
in Module
.ModulePcdList
:
1644 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1645 ModuleIsPatch
= True
1647 if not ModuleIsPatch
:
1648 for Pcd
in Module
.LibraryPcdList
:
1649 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1650 ModuleIsPatch
= True
1653 if not ModuleIsPatch
:
1656 # Module includes the patchable load fix address PCDs.
1657 # It will be fixed up later.
1659 PatchEfiImageList
.append (OutputImageFile
)
1662 # Get Top Memory address
1664 ReservedRuntimeMemorySize
= 0
1665 TopMemoryAddress
= 0
1666 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1667 TopMemoryAddress
= 0
1669 TopMemoryAddress
= self
.LoadFixAddress
1670 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1671 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1674 # Patch FixAddress related PCDs into EFI image
1676 for EfiImage
in PatchEfiImageList
:
1677 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1678 if not os
.path
.exists(EfiImageMap
):
1681 # Get PCD offset in EFI image by GenPatchPcdTable function
1683 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1685 # Patch real PCD value by PatchPcdValue tool
1687 for PcdInfo
in PcdTable
:
1689 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1690 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
// 0x1000))
1691 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1692 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
// 0x1000))
1693 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1694 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
// 0x1000))
1695 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1696 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
// 0x1000))
1697 if ReturnValue
!= 0:
1698 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1700 MapBuffer
.append('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
// 0x1000))
1701 MapBuffer
.append('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
// 0x1000))
1702 MapBuffer
.append('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
// 0x1000))
1703 if len (SmmModuleList
) > 0:
1704 MapBuffer
.append('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
// 0x1000))
1706 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1707 BtBaseAddr
= TopMemoryAddress
- RtSize
1708 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1710 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1711 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1712 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1713 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
=False, ModeIsSmm
=True)
1714 MapBuffer
.append('\n\n')
1715 sys
.stdout
.write ("\n")
1718 ## Save platform Map file
1720 def _SaveMapFile (self
, MapBuffer
, Wa
):
1722 # Map file path is got.
1724 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1726 # Save address map into MAP file.
1728 SaveFileOnChange(MapFilePath
, ''.join(MapBuffer
), False)
1729 if self
.LoadFixAddress
!= 0:
1730 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath
))
1733 ## Build active platform for different build targets and different tool chains
1735 def _BuildPlatform(self
):
1736 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1737 for BuildTarget
in self
.BuildTargetList
:
1738 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1740 for ToolChain
in self
.ToolChainList
:
1741 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1742 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1743 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1745 Wa
= WorkspaceAutoGen(
1762 self
.Fdf
= Wa
.FdfFile
1763 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1764 self
.BuildReport
.AddPlatformReport(Wa
)
1765 self
.Progress
.Stop("done!")
1767 # Add ffs build to makefile
1769 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1770 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1772 for Arch
in Wa
.ArchList
:
1774 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1775 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1776 for Module
in Pa
.Platform
.Modules
:
1777 # Get ModuleAutoGen object to generate C code file and makefile
1778 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1782 Ma
.PlatformInfo
= Pa
1784 PcdMaList
.append(Ma
)
1785 self
.BuildModules
.append(Ma
)
1786 Pa
.DataPipe
.DataContainer
= {"FfsCommand":CmdListDict
}
1787 Pa
.DataPipe
.DataContainer
= {"Workspace_timestamp": Wa
._SrcTimeStamp
}
1788 self
._BuildPa
(self
.Target
, Pa
, FfsCommand
=CmdListDict
,PcdMaList
=PcdMaList
)
1790 # Create MAP file when Load Fix Address is enabled.
1791 if self
.Target
in ["", "all", "fds"]:
1792 for Arch
in Wa
.ArchList
:
1793 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1795 # Check whether the set fix address is above 4G for 32bit image.
1797 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1798 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")
1803 for Pa
in Wa
.AutoGenObjectList
:
1804 for Ma
in Pa
.ModuleAutoGenList
:
1807 if not Ma
.IsLibrary
:
1808 ModuleList
[Ma
.Guid
.upper()] = Ma
1811 if self
.LoadFixAddress
!= 0:
1813 # Rebase module to the preferred memory address before GenFds
1815 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1818 # create FDS again for the updated EFI image
1820 self
._Build
("fds", Wa
)
1822 # Create MAP file for all platform FVs after GenFds.
1824 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1826 # Save MAP buffer into MAP file.
1828 self
._SaveMapFile
(MapBuffer
, Wa
)
1829 self
.CreateGuidedSectionToolsFile(Wa
)
1831 ## Build active module for different build targets, different tool chains and different archs
1833 def _BuildModule(self
):
1834 for BuildTarget
in self
.BuildTargetList
:
1835 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1837 for ToolChain
in self
.ToolChainList
:
1838 WorkspaceAutoGenTime
= time
.time()
1839 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1840 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1841 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1844 # module build needs platform build information, so get platform
1847 Wa
= WorkspaceAutoGen(
1865 self
.Fdf
= Wa
.FdfFile
1866 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1867 Wa
.CreateMakeFile(False)
1868 # Add ffs build to makefile
1870 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1871 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1873 # Add Platform and Package level hash in share_data for module hash calculation later
1874 if GlobalData
.gBinCacheSource
or GlobalData
.gBinCacheDest
:
1875 GlobalData
.gCacheIR
[('PlatformHash')] = GlobalData
.gPlatformHash
1876 for PkgName
in GlobalData
.gPackageHash
.keys():
1877 GlobalData
.gCacheIR
[(PkgName
, 'PackageHash')] = GlobalData
.gPackageHash
[PkgName
]
1878 GlobalData
.file_lock
= mp
.Lock()
1879 GlobalData
.cache_lock
= mp
.Lock()
1880 GlobalData
.FfsCmd
= CmdListDict
1882 self
.Progress
.Stop("done!")
1884 ExitFlag
= threading
.Event()
1886 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1887 for Arch
in Wa
.ArchList
:
1888 AutoGenStart
= time
.time()
1889 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1890 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1891 GlobalData
.libConstPcd
= Pa
.DataPipe
.Get("LibConstPcd")
1892 GlobalData
.Refes
= Pa
.DataPipe
.Get("REFS")
1893 for Module
in Pa
.Platform
.Modules
:
1894 if self
.ModuleFile
.Dir
== Module
.Dir
and self
.ModuleFile
.Name
== Module
.Name
:
1895 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1899 Ma
.PlatformInfo
= Pa
1903 if GlobalData
.gBinCacheSource
and self
.Target
in [None, "", "all"]:
1904 Ma
.GenModuleFilesHash(GlobalData
.gCacheIR
)
1905 Ma
.GenPreMakefileHash(GlobalData
.gCacheIR
)
1906 if Ma
.CanSkipbyPreMakefileCache(GlobalData
.gCacheIR
):
1907 self
.HashSkipModules
.append(Ma
)
1908 EdkLogger
.quiet("cache hit: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1911 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1912 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1913 # for target which must generate AutoGen code and makefile
1914 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1915 self
.Progress
.Start("Generating code")
1916 Ma
.CreateCodeFile(True)
1917 self
.Progress
.Stop("done!")
1918 if self
.Target
== "genc":
1920 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1921 self
.Progress
.Start("Generating makefile")
1922 if CmdListDict
and self
.Fdf
and (Module
.Path
, Arch
) in CmdListDict
:
1923 Ma
.CreateMakeFile(True, CmdListDict
[Module
.Path
, Arch
])
1924 del CmdListDict
[Module
.Path
, Arch
]
1926 Ma
.CreateMakeFile(True)
1927 self
.Progress
.Stop("done!")
1928 if self
.Target
== "genmake":
1931 if GlobalData
.gBinCacheSource
and self
.Target
in [None, "", "all"]:
1932 Ma
.GenMakeHeaderFilesHash(GlobalData
.gCacheIR
)
1933 Ma
.GenMakeHash(GlobalData
.gCacheIR
)
1934 if Ma
.CanSkipbyMakeCache(GlobalData
.gCacheIR
):
1935 self
.HashSkipModules
.append(Ma
)
1936 EdkLogger
.quiet("cache hit: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1939 EdkLogger
.quiet("cache miss: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1940 Ma
.PrintFirstMakeCacheMissFile(GlobalData
.gCacheIR
)
1942 self
.BuildModules
.append(Ma
)
1943 # Initialize all modules in tracking to 'FAIL'
1944 GlobalData
.gModuleBuildTracking
[Ma
] = 'FAIL'
1945 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1946 MakeStart
= time
.time()
1947 for Ma
in self
.BuildModules
:
1948 if not Ma
.IsBinaryModule
:
1949 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
1950 # Break build if any build thread has error
1951 if BuildTask
.HasError():
1952 # we need a full version of makefile for platform
1954 BuildTask
.WaitForComplete()
1955 self
.invalidateHash()
1956 Pa
.CreateMakeFile(False)
1957 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1958 # Start task scheduler
1959 if not BuildTask
.IsOnGoing():
1960 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1962 # in case there's an interruption. we need a full version of makefile for platform
1963 Pa
.CreateMakeFile(False)
1964 if BuildTask
.HasError():
1965 self
.invalidateHash()
1966 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1967 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1969 MakeContiue
= time
.time()
1971 BuildTask
.WaitForComplete()
1972 self
.CreateAsBuiltInf()
1973 if GlobalData
.gBinCacheDest
:
1974 self
.UpdateBuildCache()
1975 self
.BuildModules
= []
1976 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1977 if BuildTask
.HasError():
1978 self
.invalidateHash()
1979 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1981 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1986 "Module for [%s] is not a component of active platform."\
1987 " Please make sure that the ARCH and inf file path are"\
1988 " given in the same as in [%s]" % \
1989 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1990 ExtraData
=self
.ModuleFile
1992 # Create MAP file when Load Fix Address is enabled.
1993 if self
.Target
== "fds" and self
.Fdf
:
1994 for Arch
in Wa
.ArchList
:
1996 # Check whether the set fix address is above 4G for 32bit image.
1998 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1999 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")
2004 for Pa
in Wa
.AutoGenObjectList
:
2005 for Ma
in Pa
.ModuleAutoGenList
:
2008 if not Ma
.IsLibrary
:
2009 ModuleList
[Ma
.Guid
.upper()] = Ma
2012 if self
.LoadFixAddress
!= 0:
2014 # Rebase module to the preferred memory address before GenFds
2016 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2018 # create FDS again for the updated EFI image
2020 GenFdsStart
= time
.time()
2021 self
._Build
("fds", Wa
)
2022 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2024 # Create MAP file for all platform FVs after GenFds.
2026 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2028 # Save MAP buffer into MAP file.
2030 self
._SaveMapFile
(MapBuffer
, Wa
)
2031 self
.invalidateHash()
2033 def _GenFfsCmd(self
,ArchList
):
2034 # convert dictionary of Cmd:(Inf,Arch)
2035 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
2036 CmdSetDict
= defaultdict(set)
2037 GenFfsDict
= GenFds
.GenFfsMakefile('', GlobalData
.gFdfParser
, self
, ArchList
, GlobalData
)
2038 for Cmd
in GenFfsDict
:
2039 tmpInf
, tmpArch
= GenFfsDict
[Cmd
]
2040 CmdSetDict
[tmpInf
, tmpArch
].add(Cmd
)
2042 def VerifyAutoGenFiles(self
):
2043 AutoGenIdFile
= os
.path
.join(GlobalData
.gConfDirectory
,".AutoGenIdFile.txt")
2045 with
open(AutoGenIdFile
) as fd
:
2046 lines
= fd
.readlines()
2051 ArchList
= line
.strip().split("=")[1].split("|")
2052 if "BuildDir" in line
:
2053 BuildDir
= line
.split("=")[1].strip()
2054 if "PlatformGuid" in line
:
2055 PlatformGuid
= line
.split("=")[1].strip()
2057 for arch
in ArchList
:
2058 global_var
= os
.path
.join(BuildDir
, "GlobalVar_%s_%s.bin" % (str(PlatformGuid
),arch
))
2059 if not os
.path
.exists(global_var
):
2061 GlobalVarList
.append(global_var
)
2062 for global_var
in GlobalVarList
:
2063 data_pipe
= MemoryDataPipe()
2064 data_pipe
.load(global_var
)
2065 target
= data_pipe
.Get("P_Info").get("Target")
2066 toolchain
= data_pipe
.Get("P_Info").get("ToolChain")
2067 archlist
= data_pipe
.Get("P_Info").get("ArchList")
2068 Arch
= data_pipe
.Get("P_Info").get("Arch")
2069 active_p
= data_pipe
.Get("P_Info").get("ActivePlatform")
2070 workspacedir
= data_pipe
.Get("P_Info").get("WorkspaceDir")
2071 PackagesPath
= os
.getenv("PACKAGES_PATH")
2072 mws
.setWs(workspacedir
, PackagesPath
)
2073 LibraryBuildDirectoryList
= data_pipe
.Get("LibraryBuildDirectoryList")
2074 ModuleBuildDirectoryList
= data_pipe
.Get("ModuleBuildDirectoryList")
2076 for m_build_dir
in LibraryBuildDirectoryList
:
2077 if not os
.path
.exists(os
.path
.join(m_build_dir
,GenMake
.BuildFile
._FILE
_NAME
_[GenMake
.gMakeType
])):
2079 for m_build_dir
in ModuleBuildDirectoryList
:
2080 if not os
.path
.exists(os
.path
.join(m_build_dir
,GenMake
.BuildFile
._FILE
_NAME
_[GenMake
.gMakeType
])):
2083 workspacedir
,active_p
,target
,toolchain
,archlist
2085 Pa
= PlatformInfo(Wa
, active_p
, target
, toolchain
, Arch
,data_pipe
)
2086 Wa
.AutoGenObjectList
.append(Pa
)
2088 def SetupMakeSetting(self
,Wa
):
2090 for Pa
in Wa
.AutoGenObjectList
:
2091 for m
in Pa
._MbList
:
2092 ma
= ModuleAutoGen(Wa
,m
.MetaFile
, Pa
.BuildTarget
, Wa
.ToolChain
, Pa
.Arch
, Pa
.MetaFile
,Pa
.DataPipe
)
2093 BuildModules
.append(ma
)
2094 fdf_file
= Wa
.FlashDefinition
2096 Fdf
= FdfParser(fdf_file
.Path
)
2098 GlobalData
.gFdfParser
= Fdf
2099 if Fdf
.CurrentFdName
and Fdf
.CurrentFdName
in Fdf
.Profile
.FdDict
:
2100 FdDict
= Fdf
.Profile
.FdDict
[Fdf
.CurrentFdName
]
2101 for FdRegion
in FdDict
.RegionList
:
2102 if str(FdRegion
.RegionType
) == 'FILE' and self
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
2103 if int(FdRegion
.Offset
) % 8 != 0:
2104 EdkLogger
.error("build", FORMAT_INVALID
, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion
.Offset
))
2105 Wa
.FdfProfile
= Fdf
.Profile
2111 ## Build a platform in multi-thread mode
2113 def PerformAutoGen(self
,BuildTarget
,ToolChain
):
2114 WorkspaceAutoGenTime
= time
.time()
2115 Wa
= WorkspaceAutoGen(
2132 self
.Fdf
= Wa
.FdfFile
2133 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
2134 self
.BuildReport
.AddPlatformReport(Wa
)
2135 Wa
.CreateMakeFile(False)
2137 # Add ffs build to makefile
2139 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
2140 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
2142 # Add Platform and Package level hash in share_data for module hash calculation later
2143 if GlobalData
.gBinCacheSource
or GlobalData
.gBinCacheDest
:
2144 GlobalData
.gCacheIR
[('PlatformHash')] = GlobalData
.gPlatformHash
2145 for PkgName
in GlobalData
.gPackageHash
.keys():
2146 GlobalData
.gCacheIR
[(PkgName
, 'PackageHash')] = GlobalData
.gPackageHash
[PkgName
]
2148 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
2151 for Arch
in Wa
.ArchList
:
2153 AutoGenStart
= time
.time()
2154 GlobalData
.gGlobalDefines
['ARCH'] = Arch
2155 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
2159 for Inf
in Pa
.Platform
.Modules
:
2160 ModuleList
.append(Inf
)
2161 # Add the INF only list in FDF
2162 if GlobalData
.gFdfParser
is not None:
2163 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
2164 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
2165 if Inf
in Pa
.Platform
.Modules
:
2167 ModuleList
.append(Inf
)
2168 Pa
.DataPipe
.DataContainer
= {"FfsCommand":CmdListDict
}
2169 Pa
.DataPipe
.DataContainer
= {"Workspace_timestamp": Wa
._SrcTimeStamp
}
2170 Pa
.DataPipe
.DataContainer
= {"CommandTarget": self
.Target
}
2171 Pa
.CreateLibModuelDirs()
2172 Pa
.DataPipe
.DataContainer
= {"LibraryBuildDirectoryList":Pa
.LibraryBuildDirectoryList
}
2173 Pa
.DataPipe
.DataContainer
= {"ModuleBuildDirectoryList":Pa
.ModuleBuildDirectoryList
}
2174 Pa
.DataPipe
.DataContainer
= {"FdsCommandDict": Wa
.GenFdsCommandDict
}
2176 for ma
in Pa
.ModuleAutoGenList
:
2177 ModuleCodaFile
[(ma
.MetaFile
.File
,ma
.MetaFile
.Root
,ma
.Arch
,ma
.MetaFile
.Path
)] = [item
.Target
for item
in ma
.CodaTargetList
]
2178 Pa
.DataPipe
.DataContainer
= {"ModuleCodaFile":ModuleCodaFile
}
2179 for Module
in ModuleList
:
2180 # Get ModuleAutoGen object to generate C code file and makefile
2181 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2186 Ma
.PlatformInfo
= Pa
2188 PcdMaList
.append(Ma
)
2189 TotalModules
.append(Ma
)
2190 # Initialize all modules in tracking to 'FAIL'
2191 GlobalData
.gModuleBuildTracking
[Ma
] = 'FAIL'
2195 for m
in Pa
.GetAllModuleInfo
:
2197 data_pipe_file
= os
.path
.join(Pa
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(Pa
.Guid
),Pa
.Arch
))
2198 Pa
.DataPipe
.dump(data_pipe_file
)
2200 autogen_rt
, errorcode
= self
.StartAutoGen(mqueue
, Pa
.DataPipe
, self
.SkipAutoGen
, PcdMaList
,GlobalData
.gCacheIR
)
2202 # Skip cache hit modules
2203 if GlobalData
.gBinCacheSource
:
2204 for Ma
in TotalModules
:
2205 if (Ma
.MetaFile
.Path
, Ma
.Arch
) in GlobalData
.gCacheIR
and \
2206 GlobalData
.gCacheIR
[(Ma
.MetaFile
.Path
, Ma
.Arch
)].PreMakeCacheHit
:
2207 self
.HashSkipModules
.append(Ma
)
2209 if (Ma
.MetaFile
.Path
, Ma
.Arch
) in GlobalData
.gCacheIR
and \
2210 GlobalData
.gCacheIR
[(Ma
.MetaFile
.Path
, Ma
.Arch
)].MakeCacheHit
:
2211 self
.HashSkipModules
.append(Ma
)
2213 BuildModules
.append(Ma
)
2215 BuildModules
.extend(TotalModules
)
2218 self
.AutoGenMgr
.TerminateWorkers()
2219 self
.AutoGenMgr
.join(1)
2220 raise FatalError(errorcode
)
2221 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
2222 AutoGenIdFile
= os
.path
.join(GlobalData
.gConfDirectory
,".AutoGenIdFile.txt")
2223 with
open(AutoGenIdFile
,"w") as fw
:
2224 fw
.write("Arch=%s\n" % "|".join((Wa
.ArchList
)))
2225 fw
.write("BuildDir=%s\n" % Wa
.BuildDir
)
2226 fw
.write("PlatformGuid=%s\n" % str(Wa
.AutoGenObjectList
[0].Guid
))
2227 self
.Progress
.Stop("done!")
2228 return Wa
, BuildModules
2230 def _MultiThreadBuildPlatform(self
):
2231 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
2232 for BuildTarget
in self
.BuildTargetList
:
2233 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
2235 for ToolChain
in self
.ToolChainList
:
2236 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
2237 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
2238 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
2240 ExitFlag
= threading
.Event()
2242 if self
.SkipAutoGen
:
2243 Wa
= self
.VerifyAutoGenFiles()
2245 self
.SkipAutoGen
= False
2246 Wa
, self
.BuildModules
= self
.PerformAutoGen(BuildTarget
,ToolChain
)
2248 GlobalData
.gAutoGenPhase
= True
2249 self
.BuildModules
= self
.SetupMakeSetting(Wa
)
2251 Wa
, self
.BuildModules
= self
.PerformAutoGen(BuildTarget
,ToolChain
)
2252 Pa
= Wa
.AutoGenObjectList
[0]
2253 GlobalData
.gAutoGenPhase
= False
2255 if GlobalData
.gBinCacheSource
:
2256 EdkLogger
.quiet("Total cache hit driver num: %s, cache miss driver num: %s" % (len(set(self
.HashSkipModules
)), len(set(self
.BuildModules
))))
2258 CacheNotHitMa
= set()
2259 for IR
in GlobalData
.gCacheIR
.keys():
2260 if 'PlatformHash' in IR
or 'PackageHash' in IR
:
2262 if GlobalData
.gCacheIR
[IR
].PreMakeCacheHit
or GlobalData
.gCacheIR
[IR
].MakeCacheHit
:
2265 # There might be binary module or module which has .inc files, not count for cache miss
2266 CacheNotHitMa
.add(IR
)
2267 EdkLogger
.quiet("Total module num: %s, cache hit module num: %s" % (len(CacheHitMa
)+len(CacheNotHitMa
), len(CacheHitMa
)))
2269 for Arch
in Wa
.ArchList
:
2270 MakeStart
= time
.time()
2271 for Ma
in set(self
.BuildModules
):
2272 # Generate build task for the module
2273 if not Ma
.IsBinaryModule
:
2274 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
2275 # Break build if any build thread has error
2276 if BuildTask
.HasError():
2277 # we need a full version of makefile for platform
2279 BuildTask
.WaitForComplete()
2280 self
.invalidateHash()
2281 Pa
.CreateMakeFile(False)
2282 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2283 # Start task scheduler
2284 if not BuildTask
.IsOnGoing():
2285 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
2287 # in case there's an interruption. we need a full version of makefile for platform
2289 if BuildTask
.HasError():
2290 self
.invalidateHash()
2291 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2292 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
2294 MakeContiue
= time
.time()
2297 # All modules have been put in build tasks queue. Tell task scheduler
2298 # to exit if all tasks are completed
2301 BuildTask
.WaitForComplete()
2302 self
.CreateAsBuiltInf()
2303 if GlobalData
.gBinCacheDest
:
2304 self
.UpdateBuildCache()
2308 ModuleList
= {ma
.Guid
.upper(): ma
for ma
in self
.BuildModules
}
2309 self
.BuildModules
= []
2310 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2312 # Check for build error, and raise exception if one
2313 # has been signaled.
2315 if BuildTask
.HasError():
2316 self
.invalidateHash()
2317 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2319 # Create MAP file when Load Fix Address is enabled.
2320 if self
.Target
in ["", "all", "fds"]:
2321 for Arch
in Wa
.ArchList
:
2323 # Check whether the set fix address is above 4G for 32bit image.
2325 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2326 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")
2329 # Rebase module to the preferred memory address before GenFds
2332 if self
.LoadFixAddress
!= 0:
2333 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2337 # Generate FD image if there's a FDF file found
2339 GenFdsStart
= time
.time()
2340 if GenFdsApi(Wa
.GenFdsCommandDict
, self
.Db
):
2341 EdkLogger
.error("build", COMMAND_FAILURE
)
2344 # Create MAP file for all platform FVs after GenFds.
2346 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2347 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2349 # Save MAP buffer into MAP file.
2351 self
._SaveMapFile
(MapBuffer
, Wa
)
2352 self
.CreateGuidedSectionToolsFile(Wa
)
2353 self
.invalidateHash()
2354 ## Generate GuidedSectionTools.txt in the FV directories.
2356 def CreateGuidedSectionToolsFile(self
,Wa
):
2357 for BuildTarget
in self
.BuildTargetList
:
2358 for ToolChain
in self
.ToolChainList
:
2360 if not os
.path
.exists(FvDir
):
2363 for Arch
in self
.ArchList
:
2364 # Build up the list of supported architectures for this build
2365 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
2367 # Look through the tool definitions for GUIDed tools
2369 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.items():
2370 if attrib
.upper().endswith('_GUID'):
2371 split
= attrib
.split('_')
2372 thisPrefix
= '_'.join(split
[0:3]) + '_'
2373 if thisPrefix
== prefix
:
2374 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
2377 path
= '_'.join(split
[0:4]) + '_PATH'
2378 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2379 path
= self
.GetFullPathOfTool(path
)
2380 guidAttribs
.append((guid
, toolName
, path
))
2382 # Write out GuidedSecTools.txt
2383 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2384 toolsFile
= open(toolsFile
, 'wt')
2385 for guidedSectionTool
in guidAttribs
:
2386 print(' '.join(guidedSectionTool
), file=toolsFile
)
2389 ## Returns the full path of the tool.
2391 def GetFullPathOfTool (self
, tool
):
2392 if os
.path
.exists(tool
):
2393 return os
.path
.realpath(tool
)
2395 # We need to search for the tool using the
2396 # PATH environment variable.
2397 for dirInPath
in os
.environ
['PATH'].split(os
.pathsep
):
2398 foundPath
= os
.path
.join(dirInPath
, tool
)
2399 if os
.path
.exists(foundPath
):
2400 return os
.path
.realpath(foundPath
)
2402 # If the tool was not found in the path then we just return
2406 ## Launch the module or platform build
2409 if not self
.ModuleFile
:
2410 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2411 self
.SpawnMode
= False
2412 self
._BuildPlatform
()
2414 self
._MultiThreadBuildPlatform
()
2416 self
.SpawnMode
= False
2419 if self
.Target
== 'cleanall':
2420 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2422 def CreateAsBuiltInf(self
):
2423 for Module
in self
.BuildModules
:
2424 Module
.CreateAsBuiltInf()
2426 def UpdateBuildCache(self
):
2429 for Module
in self
.BuildModules
:
2430 Module
.CopyModuleToCache()
2431 all_mod_set
.add(Module
)
2432 for Module
in self
.HashSkipModules
:
2433 Module
.CopyModuleToCache()
2434 all_mod_set
.add(Module
)
2435 for Module
in all_mod_set
:
2436 for lib
in Module
.LibraryAutoGenList
:
2437 all_lib_set
.add(lib
)
2438 for lib
in all_lib_set
:
2439 lib
.CopyModuleToCache()
2442 self
.HashSkipModules
= []
2443 ## Do some clean-up works when error occurred
2444 def Relinquish(self
):
2445 OldLogLevel
= EdkLogger
.GetLevel()
2446 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2447 Utils
.Progressor
.Abort()
2448 if self
.SpawnMode
== True:
2450 EdkLogger
.SetLevel(OldLogLevel
)
2452 def ParseDefines(DefineList
=[]):
2454 if DefineList
is not None:
2455 for Define
in DefineList
:
2456 DefineTokenList
= Define
.split("=", 1)
2457 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2458 EdkLogger
.error('build', FORMAT_INVALID
,
2459 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2460 ExtraData
=DefineTokenList
[0])
2462 if len(DefineTokenList
) == 1:
2463 DefineDict
[DefineTokenList
[0]] = "TRUE"
2465 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2470 def LogBuildTime(Time
):
2473 TimeDur
= time
.gmtime(Time
)
2474 if TimeDur
.tm_yday
> 1:
2475 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2477 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2482 ThreadNumber
= BuildOption
.ThreadNumber
2483 if ThreadNumber
is None:
2484 ThreadNumber
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
2485 if ThreadNumber
== '':
2488 ThreadNumber
= int(ThreadNumber
, 0)
2490 if ThreadNumber
== 0:
2492 ThreadNumber
= multiprocessing
.cpu_count()
2493 except (ImportError, NotImplementedError):
2496 ## Tool entrance method
2498 # This method mainly dispatch specific methods per the command line options.
2499 # If no error found, return zero value so the caller of this tool can know
2500 # if it's executed successfully or not.
2502 # @retval 0 Tool was successful
2503 # @retval 1 Tool failed
2505 LogQMaxSize
= ThreadNum() * 10
2507 StartTime
= time
.time()
2510 # Create a log Queue
2512 LogQ
= mp
.Queue(LogQMaxSize
)
2513 # Initialize log system
2514 EdkLogger
.LogClientInitialize(LogQ
)
2515 GlobalData
.gCommand
= sys
.argv
[1:]
2517 # Parse the options and args
2519 Option
, Target
= BuildOption
, BuildTarget
2520 GlobalData
.gOptions
= Option
2521 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2524 LogLevel
= EdkLogger
.INFO
2525 if Option
.verbose
is not None:
2526 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2527 LogLevel
= EdkLogger
.VERBOSE
2528 elif Option
.quiet
is not None:
2529 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2530 LogLevel
= EdkLogger
.QUIET
2531 elif Option
.debug
is not None:
2532 EdkLogger
.SetLevel(Option
.debug
+ 1)
2533 LogLevel
= Option
.debug
+ 1
2535 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2537 if Option
.WarningAsError
== True:
2538 EdkLogger
.SetWarningAsError()
2539 Log_Agent
= LogAgent(LogQ
,LogLevel
,Option
.LogFile
)
2542 if platform
.platform().find("Windows") >= 0:
2543 GlobalData
.gIsWindows
= True
2545 GlobalData
.gIsWindows
= False
2547 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2548 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2553 if len(Target
) == 0:
2555 elif len(Target
) >= 2:
2556 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2557 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2559 Target
= Target
[0].lower()
2561 if Target
not in gSupportedTarget
:
2562 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2563 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2566 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2569 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2571 Workspace
= os
.getenv("WORKSPACE")
2573 # Get files real name in workspace dir
2575 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2577 WorkingDirectory
= os
.getcwd()
2578 if not Option
.ModuleFile
:
2579 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2580 FileNum
= len(FileList
)
2582 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2583 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2585 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2587 if Option
.ModuleFile
:
2588 if os
.path
.isabs (Option
.ModuleFile
):
2589 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2590 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2591 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2592 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2594 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2596 if Option
.PlatformFile
is not None:
2597 if os
.path
.isabs (Option
.PlatformFile
):
2598 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2599 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2600 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2602 if Option
.FdfFile
is not None:
2603 if os
.path
.isabs (Option
.FdfFile
):
2604 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2605 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2606 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2607 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2609 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2611 if Option
.Flag
is not None and Option
.Flag
not in ['-c', '-s']:
2612 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2614 MyBuild
= Build(Target
, Workspace
, Option
,LogQ
)
2615 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2616 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2620 # All job done, no error found and no exception raised
2623 except FatalError
as X
:
2624 if MyBuild
is not None:
2625 # for multi-thread build exits safely
2626 MyBuild
.Relinquish()
2627 if Option
is not None and Option
.debug
is not None:
2628 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2629 ReturnCode
= X
.args
[0]
2630 except Warning as X
:
2631 # error from Fdf parser
2632 if MyBuild
is not None:
2633 # for multi-thread build exits safely
2634 MyBuild
.Relinquish()
2635 if Option
is not None and Option
.debug
is not None:
2636 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2638 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2639 ReturnCode
= FORMAT_INVALID
2640 except KeyboardInterrupt:
2641 if MyBuild
is not None:
2643 # for multi-thread build exits safely
2644 MyBuild
.Relinquish()
2645 ReturnCode
= ABORT_ERROR
2646 if Option
is not None and Option
.debug
is not None:
2647 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2649 if MyBuild
is not None:
2650 # for multi-thread build exits safely
2651 MyBuild
.Relinquish()
2653 # try to get the meta-file from the object causing exception
2654 Tb
= sys
.exc_info()[-1]
2655 MetaFile
= GlobalData
.gProcessingFile
2656 while Tb
is not None:
2657 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2658 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2663 "Unknown fatal error when processing [%s]" % MetaFile
,
2664 ExtraData
="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR
,
2667 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2668 ReturnCode
= CODE_ERROR
2670 Utils
.Progressor
.Abort()
2671 Utils
.ClearDuplicatedInf()
2675 MyBuild
.LaunchPostbuild()
2678 Conclusion
= "Failed"
2679 elif ReturnCode
== ABORT_ERROR
:
2680 Conclusion
= "Aborted"
2682 Conclusion
= "Failed"
2683 FinishTime
= time
.time()
2684 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2685 BuildDurationStr
= ""
2686 if BuildDuration
.tm_yday
> 1:
2687 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2689 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2690 if MyBuild
is not None:
2692 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2694 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2695 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2696 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2697 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2702 if __name__
== '__main__':
2704 mp
.set_start_method('spawn')
2708 ## 0-127 is a safe return range, and 1 is a standard default error
2709 if r
< 0 or r
> 127: r
= 1