2 # build a platform or a module
4 # Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
5 # Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR>
6 # Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
7 # Copyright (c) 2020, ARM Limited. All rights reserved.<BR>
9 # SPDX-License-Identifier: BSD-2-Clause-Patent
15 from __future__
import print_function
16 from __future__
import absolute_import
17 import os
.path
as path
25 import multiprocessing
26 from threading
import Thread
,Event
,BoundedSemaphore
28 from linecache
import getlines
29 from subprocess
import Popen
,PIPE
, STDOUT
30 from collections
import OrderedDict
, defaultdict
32 from AutoGen
.PlatformAutoGen
import PlatformAutoGen
33 from AutoGen
.ModuleAutoGen
import ModuleAutoGen
34 from AutoGen
.WorkspaceAutoGen
import WorkspaceAutoGen
35 from AutoGen
.AutoGenWorker
import AutoGenWorkerInProcess
,AutoGenManager
,\
37 from AutoGen
import GenMake
38 from Common
import Misc
as Utils
40 from Common
.TargetTxtClassObject
import TargetTxtDict
41 from Common
.ToolDefClassObject
import ToolDefDict
42 from buildoptions
import MyOptionParser
43 from Common
.Misc
import PathClass
,SaveFileOnChange
,RemoveDirectory
44 from Common
.StringUtils
import NormPath
45 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
46 from Common
.BuildToolError
import *
47 from Common
.DataType
import *
48 import Common
.EdkLogger
as EdkLogger
50 from Workspace
.WorkspaceDatabase
import BuildDB
52 from BuildReport
import BuildReport
53 from GenPatchPcdTable
.GenPatchPcdTable
import PeImageClass
,parsePcdInfoFromMapFile
54 from PatchPcdValue
.PatchPcdValue
import PatchBinaryFile
56 import Common
.GlobalData
as GlobalData
57 from GenFds
.GenFds
import GenFds
, GenFdsApi
58 import multiprocessing
as mp
59 from multiprocessing
import Manager
60 from AutoGen
.DataPipe
import MemoryDataPipe
61 from AutoGen
.ModuleAutoGenHelper
import WorkSpaceInfo
, PlatformInfo
62 from GenFds
.FdfParser
import FdfParser
63 from AutoGen
.IncludesAutoGen
import IncludesAutoGen
64 from GenFds
.GenFds
import resetFdsGlobalVariable
66 ## standard targets of build command
67 gSupportedTarget
= ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
69 ## build configuration file
70 gBuildConfiguration
= "target.txt"
71 gToolsDefinition
= "tools_def.txt"
73 TemporaryTablePattern
= re
.compile(r
'^_\d+_\d+_[a-fA-F0-9]+$')
76 ## Check environment PATH variable to make sure the specified tool is found
78 # If the tool is found in the PATH, then True is returned
79 # Otherwise, False is returned
81 def IsToolInPath(tool
):
82 if 'PATHEXT' in os
.environ
:
83 extns
= os
.environ
['PATHEXT'].split(os
.path
.pathsep
)
86 for pathDir
in os
.environ
['PATH'].split(os
.path
.pathsep
):
88 if os
.path
.exists(os
.path
.join(pathDir
, tool
+ ext
)):
92 ## Check environment variables
94 # Check environment variables that must be set for build. Currently they are
96 # WORKSPACE The directory all packages/platforms start from
97 # EDK_TOOLS_PATH The directory contains all tools needed by the build
98 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
100 # If any of above environment variable is not set or has error, the build
103 def CheckEnvVariable():
105 if "WORKSPACE" not in os
.environ
:
106 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
107 ExtraData
="WORKSPACE")
109 WorkspaceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["WORKSPACE"]))
110 if not os
.path
.exists(WorkspaceDir
):
111 EdkLogger
.error("build", FILE_NOT_FOUND
, "WORKSPACE doesn't exist", ExtraData
=WorkspaceDir
)
112 elif ' ' in WorkspaceDir
:
113 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in WORKSPACE path",
114 ExtraData
=WorkspaceDir
)
115 os
.environ
["WORKSPACE"] = WorkspaceDir
117 # set multiple workspace
118 PackagesPath
= os
.getenv("PACKAGES_PATH")
119 mws
.setWs(WorkspaceDir
, PackagesPath
)
120 if mws
.PACKAGES_PATH
:
121 for Path
in mws
.PACKAGES_PATH
:
122 if not os
.path
.exists(Path
):
123 EdkLogger
.error("build", FILE_NOT_FOUND
, "One Path in PACKAGES_PATH doesn't exist", ExtraData
=Path
)
125 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in PACKAGES_PATH", ExtraData
=Path
)
128 os
.environ
["EDK_TOOLS_PATH"] = os
.path
.normcase(os
.environ
["EDK_TOOLS_PATH"])
130 # check EDK_TOOLS_PATH
131 if "EDK_TOOLS_PATH" not in os
.environ
:
132 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
133 ExtraData
="EDK_TOOLS_PATH")
136 if "PATH" not in os
.environ
:
137 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
140 GlobalData
.gWorkspace
= WorkspaceDir
142 GlobalData
.gGlobalDefines
["WORKSPACE"] = WorkspaceDir
143 GlobalData
.gGlobalDefines
["EDK_TOOLS_PATH"] = os
.environ
["EDK_TOOLS_PATH"]
145 ## Get normalized file path
147 # Convert the path to be local format, and remove the WORKSPACE path at the
148 # beginning if the file path is given in full path.
150 # @param FilePath File path to be normalized
151 # @param Workspace Workspace path which the FilePath will be checked against
153 # @retval string The normalized file path
155 def NormFile(FilePath
, Workspace
):
156 # check if the path is absolute or relative
157 if os
.path
.isabs(FilePath
):
158 FileFullPath
= os
.path
.normpath(FilePath
)
160 FileFullPath
= os
.path
.normpath(mws
.join(Workspace
, FilePath
))
161 Workspace
= mws
.getWs(Workspace
, FilePath
)
163 # check if the file path exists or not
164 if not os
.path
.isfile(FileFullPath
):
165 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath
)
167 # remove workspace directory from the beginning part of the file path
168 if Workspace
[-1] in ["\\", "/"]:
169 return FileFullPath
[len(Workspace
):]
171 return FileFullPath
[(len(Workspace
) + 1):]
173 ## Get the output of an external program
175 # This is the entrance method of thread reading output of an external program and
176 # putting them in STDOUT/STDERR of current program.
178 # @param From The stream message read from
179 # @param To The stream message put on
180 # @param ExitFlag The flag used to indicate stopping reading
182 def ReadMessage(From
, To
, ExitFlag
,MemTo
=None):
184 # read one line a time
185 Line
= From
.readline()
186 # empty string means "end"
187 if Line
is not None and Line
!= b
"":
188 LineStr
= Line
.rstrip().decode(encoding
='utf-8', errors
='ignore')
189 if MemTo
is not None:
190 if "Note: including file:" == LineStr
.lstrip()[:21]:
191 MemTo
.append(LineStr
)
194 MemTo
.append(LineStr
)
202 class MakeSubProc(Popen
):
203 def __init__(self
,*args
, **argv
):
204 super(MakeSubProc
,self
).__init
__(*args
, **argv
)
207 ## Launch an external program
209 # This method will call subprocess.Popen to execute an external program with
210 # given options in specified directory. Because of the dead-lock issue during
211 # redirecting output of the external program, threads are used to to do the
214 # @param Command A list or string containing the call of the program
215 # @param WorkingDir The directory in which the program will be running
217 def LaunchCommand(Command
, WorkingDir
,ModuleAuto
= None):
218 BeginTime
= time
.time()
219 # if working directory doesn't exist, Popen() will raise an exception
220 if not os
.path
.isdir(WorkingDir
):
221 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=WorkingDir
)
223 # Command is used as the first Argument in following Popen().
224 # It could be a string or sequence. We find that if command is a string in following Popen(),
225 # ubuntu may fail with an error message that the command is not found.
226 # So here we may need convert command from string to list instance.
227 if platform
.system() != 'Windows':
228 if not isinstance(Command
, list):
229 Command
= Command
.split()
230 Command
= ' '.join(Command
)
233 EndOfProcedure
= None
236 Proc
= MakeSubProc(Command
, stdout
=PIPE
, stderr
=STDOUT
, env
=os
.environ
, cwd
=WorkingDir
, bufsize
=-1, shell
=True)
238 # launch two threads to read the STDOUT and STDERR
239 EndOfProcedure
= Event()
240 EndOfProcedure
.clear()
242 StdOutThread
= Thread(target
=ReadMessage
, args
=(Proc
.stdout
, EdkLogger
.info
, EndOfProcedure
,Proc
.ProcOut
))
243 StdOutThread
.setName("STDOUT-Redirector")
244 StdOutThread
.setDaemon(False)
248 # waiting for program exit
250 except: # in case of aborting
251 # terminate the threads redirecting the program output
252 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
253 if EndOfProcedure
is not None:
256 if not isinstance(Command
, type("")):
257 Command
= " ".join(Command
)
258 EdkLogger
.error("build", COMMAND_FAILURE
, "Failed to start command", ExtraData
="%s [%s]" % (Command
, WorkingDir
))
263 # check the return code of the program
264 if Proc
.returncode
!= 0:
265 if not isinstance(Command
, type("")):
266 Command
= " ".join(Command
)
267 # print out the Response file and its content when make failure
268 RespFile
= os
.path
.join(WorkingDir
, 'OUTPUT', 'respfilelist.txt')
269 if os
.path
.isfile(RespFile
):
271 RespContent
= f
.read()
273 EdkLogger
.info(RespContent
)
275 EdkLogger
.error("build", COMMAND_FAILURE
, ExtraData
="%s [%s]" % (Command
, WorkingDir
))
277 iau
= IncludesAutoGen(WorkingDir
,ModuleAuto
)
278 if ModuleAuto
.ToolChainFamily
== TAB_COMPILER_MSFT
:
279 iau
.CreateDepsFileForMsvc(Proc
.ProcOut
)
281 iau
.UpdateDepsFileforNonMsvc()
282 iau
.UpdateDepsFileforTrim()
283 iau
.CreateModuleDeps()
284 iau
.CreateDepsInclude()
285 iau
.CreateDepsTarget()
286 return "%dms" % (int(round((time
.time() - BeginTime
) * 1000)))
288 ## The smallest unit that can be built in multi-thread build mode
290 # This is the base class of build unit. The "Obj" parameter must provide
291 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
294 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
299 # @param self The object pointer
300 # @param Obj The object the build is working on
301 # @param Target The build target name, one of gSupportedTarget
302 # @param Dependency The BuildUnit(s) which must be completed in advance
303 # @param WorkingDir The directory build command starts in
305 def __init__(self
, Obj
, BuildCommand
, Target
, Dependency
, WorkingDir
="."):
306 self
.BuildObject
= Obj
307 self
.Dependency
= Dependency
308 self
.WorkingDir
= WorkingDir
310 self
.BuildCommand
= BuildCommand
312 EdkLogger
.error("build", OPTION_MISSING
,
313 "No build command found for this module. "
314 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
315 (Obj
.BuildTarget
, Obj
.ToolChain
, Obj
.Arch
),
321 # It just returns the string representation of self.BuildObject
323 # @param self The object pointer
326 return str(self
.BuildObject
)
328 ## "==" operator method
330 # It just compares self.BuildObject with "Other". So self.BuildObject must
331 # provide its own __eq__() method.
333 # @param self The object pointer
334 # @param Other The other BuildUnit object compared to
336 def __eq__(self
, Other
):
337 return Other
and self
.BuildObject
== Other
.BuildObject \
338 and Other
.BuildObject \
339 and self
.BuildObject
.Arch
== Other
.BuildObject
.Arch
343 # It just returns the hash value of self.BuildObject which must be hashable.
345 # @param self The object pointer
348 return hash(self
.BuildObject
) + hash(self
.BuildObject
.Arch
)
351 return repr(self
.BuildObject
)
353 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
355 # This class is for module build by nmake/make build system. The "Obj" parameter
356 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
357 # be make units missing build.
359 # Currently the "Obj" should be only ModuleAutoGen object.
361 class ModuleMakeUnit(BuildUnit
):
364 # @param self The object pointer
365 # @param Obj The ModuleAutoGen object the build is working on
366 # @param Target The build target name, one of gSupportedTarget
368 def __init__(self
, Obj
, BuildCommand
,Target
):
369 Dependency
= [ModuleMakeUnit(La
, BuildCommand
,Target
) for La
in Obj
.LibraryAutoGenList
]
370 BuildUnit
.__init
__(self
, Obj
, BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
371 if Target
in [None, "", "all"]:
372 self
.Target
= "tbuild"
374 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
376 # This class is for platform build by nmake/make build system. The "Obj" parameter
377 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
378 # be make units missing build.
380 # Currently the "Obj" should be only PlatformAutoGen object.
382 class PlatformMakeUnit(BuildUnit
):
385 # @param self The object pointer
386 # @param Obj The PlatformAutoGen object the build is working on
387 # @param Target The build target name, one of gSupportedTarget
389 def __init__(self
, Obj
, BuildCommand
, Target
):
390 Dependency
= [ModuleMakeUnit(Lib
, BuildCommand
, Target
) for Lib
in self
.BuildObject
.LibraryAutoGenList
]
391 Dependency
.extend([ModuleMakeUnit(Mod
, BuildCommand
,Target
) for Mod
in self
.BuildObject
.ModuleAutoGenList
])
392 BuildUnit
.__init
__(self
, Obj
, BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
394 ## The class representing the task of a module build or platform build
396 # This class manages the build tasks in multi-thread build mode. Its jobs include
397 # scheduling thread running, catching thread error, monitor the thread status, etc.
400 # queue for tasks waiting for schedule
401 _PendingQueue
= OrderedDict()
402 _PendingQueueLock
= threading
.Lock()
404 # queue for tasks ready for running
405 _ReadyQueue
= OrderedDict()
406 _ReadyQueueLock
= threading
.Lock()
408 # queue for run tasks
409 _RunningQueue
= OrderedDict()
410 _RunningQueueLock
= threading
.Lock()
412 # queue containing all build tasks, in case duplicate build
413 _TaskQueue
= OrderedDict()
415 # flag indicating error occurs in a running thread
416 _ErrorFlag
= threading
.Event()
420 # BoundedSemaphore object used to control the number of running threads
423 # flag indicating if the scheduler is started or not
424 _SchedulerStopped
= threading
.Event()
425 _SchedulerStopped
.set()
427 ## Start the task scheduler thread
429 # @param MaxThreadNumber The maximum thread number
430 # @param ExitFlag Flag used to end the scheduler
433 def StartScheduler(MaxThreadNumber
, ExitFlag
):
434 SchedulerThread
= Thread(target
=BuildTask
.Scheduler
, args
=(MaxThreadNumber
, ExitFlag
))
435 SchedulerThread
.setName("Build-Task-Scheduler")
436 SchedulerThread
.setDaemon(False)
437 SchedulerThread
.start()
438 # wait for the scheduler to be started, especially useful in Linux
439 while not BuildTask
.IsOnGoing():
444 # @param MaxThreadNumber The maximum thread number
445 # @param ExitFlag Flag used to end the scheduler
448 def Scheduler(MaxThreadNumber
, ExitFlag
):
449 BuildTask
._SchedulerStopped
.clear()
451 # use BoundedSemaphore to control the maximum running threads
452 BuildTask
._Thread
= BoundedSemaphore(MaxThreadNumber
)
454 # scheduling loop, which will exits when no pending/ready task and
455 # indicated to do so, or there's error in running thread
457 while (len(BuildTask
._PendingQueue
) > 0 or len(BuildTask
._ReadyQueue
) > 0 \
458 or not ExitFlag
.isSet()) and not BuildTask
._ErrorFlag
.isSet():
459 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Pending Queue (%d), Ready Queue (%d)"
460 % (len(BuildTask
._PendingQueue
), len(BuildTask
._ReadyQueue
)))
462 # get all pending tasks
463 BuildTask
._PendingQueueLock
.acquire()
464 BuildObjectList
= list(BuildTask
._PendingQueue
.keys())
466 # check if their dependency is resolved, and if true, move them
469 for BuildObject
in BuildObjectList
:
470 Bt
= BuildTask
._PendingQueue
[BuildObject
]
472 BuildTask
._ReadyQueue
[BuildObject
] = BuildTask
._PendingQueue
.pop(BuildObject
)
473 BuildTask
._PendingQueueLock
.release()
475 # launch build thread until the maximum number of threads is reached
476 while not BuildTask
._ErrorFlag
.isSet():
477 # empty ready queue, do nothing further
478 if len(BuildTask
._ReadyQueue
) == 0:
481 # wait for active thread(s) exit
482 BuildTask
._Thread
.acquire(True)
484 # start a new build thread
485 Bo
, Bt
= BuildTask
._ReadyQueue
.popitem()
487 # move into running queue
488 BuildTask
._RunningQueueLock
.acquire()
489 BuildTask
._RunningQueue
[Bo
] = Bt
490 BuildTask
._RunningQueueLock
.release()
499 # wait for all running threads exit
500 if BuildTask
._ErrorFlag
.isSet():
501 EdkLogger
.quiet("\nWaiting for all build threads exit...")
502 # while not BuildTask._ErrorFlag.isSet() and \
503 while len(BuildTask
._RunningQueue
) > 0:
504 EdkLogger
.verbose("Waiting for thread ending...(%d)" % len(BuildTask
._RunningQueue
))
505 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Threads [%s]" % ", ".join(Th
.getName() for Th
in threading
.enumerate()))
508 except BaseException
as X
:
510 # TRICK: hide the output of threads left running, so that the user can
511 # catch the error message easily
513 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
514 BuildTask
._ErrorFlag
.set()
515 BuildTask
._ErrorMessage
= "build thread scheduler error\n\t%s" % str(X
)
517 BuildTask
._PendingQueue
.clear()
518 BuildTask
._ReadyQueue
.clear()
519 BuildTask
._RunningQueue
.clear()
520 BuildTask
._TaskQueue
.clear()
521 BuildTask
._SchedulerStopped
.set()
523 ## Wait for all running method exit
526 def WaitForComplete():
527 BuildTask
._SchedulerStopped
.wait()
529 ## Check if the scheduler is running or not
533 return not BuildTask
._SchedulerStopped
.isSet()
538 if BuildTask
.IsOnGoing():
539 BuildTask
._ErrorFlag
.set()
540 BuildTask
.WaitForComplete()
542 ## Check if there's error in running thread
544 # Since the main thread cannot catch exceptions in other thread, we have to
545 # use threading.Event to communicate this formation to main thread.
549 return BuildTask
._ErrorFlag
.isSet()
551 ## Get error message in running thread
553 # Since the main thread cannot catch exceptions in other thread, we have to
554 # use a static variable to communicate this message to main thread.
557 def GetErrorMessage():
558 return BuildTask
._ErrorMessage
560 ## Factory method to create a BuildTask object
562 # This method will check if a module is building or has been built. And if
563 # true, just return the associated BuildTask object in the _TaskQueue. If
564 # not, create and return a new BuildTask object. The new BuildTask object
565 # will be appended to the _PendingQueue for scheduling later.
567 # @param BuildItem A BuildUnit object representing a build object
568 # @param Dependency The dependent build object of BuildItem
571 def New(BuildItem
, Dependency
=None):
572 if BuildItem
in BuildTask
._TaskQueue
:
573 Bt
= BuildTask
._TaskQueue
[BuildItem
]
577 Bt
._Init
(BuildItem
, Dependency
)
578 BuildTask
._TaskQueue
[BuildItem
] = Bt
580 BuildTask
._PendingQueueLock
.acquire()
581 BuildTask
._PendingQueue
[BuildItem
] = Bt
582 BuildTask
._PendingQueueLock
.release()
586 ## The real constructor of BuildTask
588 # @param BuildItem A BuildUnit object representing a build object
589 # @param Dependency The dependent build object of BuildItem
591 def _Init(self
, BuildItem
, Dependency
=None):
592 self
.BuildItem
= BuildItem
594 self
.DependencyList
= []
595 if Dependency
is None:
596 Dependency
= BuildItem
.Dependency
598 Dependency
.extend(BuildItem
.Dependency
)
599 self
.AddDependency(Dependency
)
600 # flag indicating build completes, used to avoid unnecessary re-build
601 self
.CompleteFlag
= False
603 ## Check if all dependent build tasks are completed or not
607 for Dep
in self
.DependencyList
:
608 if Dep
.CompleteFlag
== True:
615 ## Add dependent build task
617 # @param Dependency The list of dependent build objects
619 def AddDependency(self
, Dependency
):
620 for Dep
in Dependency
:
621 if not Dep
.BuildObject
.IsBinaryModule
and not Dep
.BuildObject
.CanSkipbyCache(GlobalData
.gModuleCacheHit
):
622 self
.DependencyList
.append(BuildTask
.New(Dep
)) # BuildTask list
624 ## The thread wrapper of LaunchCommand function
626 # @param Command A list or string contains the call of the command
627 # @param WorkingDir The directory in which the program will be running
629 def _CommandThread(self
, Command
, WorkingDir
):
631 self
.BuildItem
.BuildObject
.BuildTime
= LaunchCommand(Command
, WorkingDir
,self
.BuildItem
.BuildObject
)
632 self
.CompleteFlag
= True
634 # Run hash operation post dependency to account for libs
635 # Run if --hash or --binary-destination
636 if GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
637 self
.BuildItem
.BuildObject
.GenModuleHash()
638 if GlobalData
.gBinCacheDest
:
639 self
.BuildItem
.BuildObject
.GenCMakeHash()
643 # TRICK: hide the output of threads left running, so that the user can
644 # catch the error message easily
646 if not BuildTask
._ErrorFlag
.isSet():
647 GlobalData
.gBuildingModule
= "%s [%s, %s, %s]" % (str(self
.BuildItem
.BuildObject
),
648 self
.BuildItem
.BuildObject
.Arch
,
649 self
.BuildItem
.BuildObject
.ToolChain
,
650 self
.BuildItem
.BuildObject
.BuildTarget
652 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
653 BuildTask
._ErrorFlag
.set()
654 BuildTask
._ErrorMessage
= "%s broken\n %s [%s]" % \
655 (threading
.currentThread().getName(), Command
, WorkingDir
)
657 # indicate there's a thread is available for another build task
658 BuildTask
._RunningQueueLock
.acquire()
659 BuildTask
._RunningQueue
.pop(self
.BuildItem
)
660 BuildTask
._RunningQueueLock
.release()
661 BuildTask
._Thread
.release()
663 ## Start build task thread
666 EdkLogger
.quiet("Building ... %s" % repr(self
.BuildItem
))
667 Command
= self
.BuildItem
.BuildCommand
+ [self
.BuildItem
.Target
]
668 self
.BuildTread
= Thread(target
=self
._CommandThread
, args
=(Command
, self
.BuildItem
.WorkingDir
))
669 self
.BuildTread
.setName("build thread")
670 self
.BuildTread
.setDaemon(False)
671 self
.BuildTread
.start()
673 ## The class contains the information related to EFI image
678 # Constructor will load all required image information.
680 # @param BaseName The full file path of image.
681 # @param Guid The GUID for image.
682 # @param Arch Arch of this image.
683 # @param OutputDir The output directory for image.
684 # @param DebugDir The debug directory for image.
685 # @param ImageClass PeImage Information
687 def __init__(self
, BaseName
, Guid
, Arch
, OutputDir
, DebugDir
, ImageClass
):
688 self
.BaseName
= BaseName
691 self
.OutputDir
= OutputDir
692 self
.DebugDir
= DebugDir
693 self
.Image
= ImageClass
694 self
.Image
.Size
= (self
.Image
.Size
// 0x1000 + 1) * 0x1000
696 ## The class implementing the EDK2 build process
698 # The build process includes:
699 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
700 # 2. Parse DSC file of active platform
701 # 3. Parse FDF file if any
702 # 4. Establish build database, including parse all other files (module, package)
703 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
704 # 6. Call build command
709 # Constructor will load all necessary configurations, parse platform, modules
710 # and packages and the establish a database for AutoGen.
712 # @param Target The build command target, one of gSupportedTarget
713 # @param WorkspaceDir The directory of workspace
714 # @param BuildOptions Build options passed from command line
716 def __init__(self
, Target
, WorkspaceDir
, BuildOptions
,log_q
):
717 self
.WorkspaceDir
= WorkspaceDir
719 self
.PlatformFile
= BuildOptions
.PlatformFile
720 self
.ModuleFile
= BuildOptions
.ModuleFile
721 self
.ArchList
= BuildOptions
.TargetArch
722 self
.ToolChainList
= BuildOptions
.ToolChain
723 self
.BuildTargetList
= BuildOptions
.BuildTarget
724 self
.Fdf
= BuildOptions
.FdfFile
725 self
.FdList
= BuildOptions
.RomImage
726 self
.FvList
= BuildOptions
.FvImage
727 self
.CapList
= BuildOptions
.CapName
728 self
.SilentMode
= BuildOptions
.SilentMode
729 self
.ThreadNumber
= 1
730 self
.SkipAutoGen
= BuildOptions
.SkipAutoGen
731 self
.Reparse
= BuildOptions
.Reparse
732 self
.SkuId
= BuildOptions
.SkuId
734 GlobalData
.gSKUID_CMD
= self
.SkuId
735 self
.ConfDirectory
= BuildOptions
.ConfDirectory
736 self
.SpawnMode
= True
737 self
.BuildReport
= BuildReport(BuildOptions
.ReportFile
, BuildOptions
.ReportType
)
741 self
.MakeFileName
= ""
742 TargetObj
= TargetTxtDict()
743 ToolDefObj
= ToolDefDict((os
.path
.join(os
.getenv("WORKSPACE"),"Conf")))
744 self
.TargetTxt
= TargetObj
.Target
745 self
.ToolDef
= ToolDefObj
.ToolDef
746 GlobalData
.BuildOptionPcd
= BuildOptions
.OptionPcd
if BuildOptions
.OptionPcd
else []
747 #Set global flag for build mode
748 GlobalData
.gIgnoreSource
= BuildOptions
.IgnoreSources
749 GlobalData
.gUseHashCache
= BuildOptions
.UseHashCache
750 GlobalData
.gBinCacheDest
= BuildOptions
.BinCacheDest
751 GlobalData
.gBinCacheSource
= BuildOptions
.BinCacheSource
752 GlobalData
.gEnableGenfdsMultiThread
= not BuildOptions
.NoGenfdsMultiThread
753 GlobalData
.gDisableIncludePathCheck
= BuildOptions
.DisableIncludePathCheck
755 if GlobalData
.gBinCacheDest
and not GlobalData
.gUseHashCache
:
756 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination must be used together with --hash.")
758 if GlobalData
.gBinCacheSource
and not GlobalData
.gUseHashCache
:
759 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-source must be used together with --hash.")
761 if GlobalData
.gBinCacheDest
and GlobalData
.gBinCacheSource
:
762 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination can not be used together with --binary-source.")
764 if GlobalData
.gBinCacheSource
:
765 BinCacheSource
= os
.path
.normpath(GlobalData
.gBinCacheSource
)
766 if not os
.path
.isabs(BinCacheSource
):
767 BinCacheSource
= mws
.join(self
.WorkspaceDir
, BinCacheSource
)
768 GlobalData
.gBinCacheSource
= BinCacheSource
770 if GlobalData
.gBinCacheSource
is not None:
771 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-source.")
773 if GlobalData
.gBinCacheDest
:
774 BinCacheDest
= os
.path
.normpath(GlobalData
.gBinCacheDest
)
775 if not os
.path
.isabs(BinCacheDest
):
776 BinCacheDest
= mws
.join(self
.WorkspaceDir
, BinCacheDest
)
777 GlobalData
.gBinCacheDest
= BinCacheDest
779 if GlobalData
.gBinCacheDest
is not None:
780 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-destination.")
782 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(GlobalData
.gConfDirectory
, GlobalData
.gDatabasePath
))
783 if not os
.path
.exists(os
.path
.join(GlobalData
.gConfDirectory
, '.cache')):
784 os
.makedirs(os
.path
.join(GlobalData
.gConfDirectory
, '.cache'))
786 self
.BuildDatabase
= self
.Db
.BuildObject
788 self
.ToolChainFamily
= None
789 self
.LoadFixAddress
= 0
790 self
.UniFlag
= BuildOptions
.Flag
791 self
.BuildModules
= []
792 self
.HashSkipModules
= []
794 self
.LaunchPrebuildFlag
= False
795 self
.PlatformBuildPath
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PlatformBuild')
796 if BuildOptions
.CommandLength
:
797 GlobalData
.gCommandMaxLength
= BuildOptions
.CommandLength
799 # print dot character during doing some time-consuming work
800 self
.Progress
= Utils
.Progressor()
801 # print current build environment and configuration
802 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
803 if "PACKAGES_PATH" in os
.environ
:
804 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
805 EdkLogger
.quiet("%-16s = %s" % ("PACKAGES_PATH", os
.path
.normcase(os
.path
.normpath(os
.environ
["PACKAGES_PATH"]))))
806 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
807 if "EDK_TOOLS_BIN" in os
.environ
:
808 # Print the same path style with WORKSPACE env.
809 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_TOOLS_BIN"]))))
810 EdkLogger
.quiet("%-16s = %s" % ("CONF_PATH", GlobalData
.gConfDirectory
))
811 if "PYTHON3_ENABLE" in os
.environ
:
812 PYTHON3_ENABLE
= os
.environ
["PYTHON3_ENABLE"]
813 if PYTHON3_ENABLE
!= "TRUE":
814 PYTHON3_ENABLE
= "FALSE"
815 EdkLogger
.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE
))
816 if "PYTHON_COMMAND" in os
.environ
:
817 EdkLogger
.quiet("%-16s = %s" % ("PYTHON_COMMAND", os
.environ
["PYTHON_COMMAND"]))
821 EdkLogger
.quiet("%-16s = %s" % ("PREBUILD", self
.Prebuild
))
823 EdkLogger
.quiet("%-16s = %s" % ("POSTBUILD", self
.Postbuild
))
825 self
.LaunchPrebuild()
826 TargetObj
= TargetTxtDict()
827 ToolDefObj
= ToolDefDict((os
.path
.join(os
.getenv("WORKSPACE"), "Conf")))
828 self
.TargetTxt
= TargetObj
.Target
829 self
.ToolDef
= ToolDefObj
.ToolDef
830 if not (self
.LaunchPrebuildFlag
and os
.path
.exists(self
.PlatformBuildPath
)):
833 self
.AutoGenMgr
= None
835 os
.chdir(self
.WorkspaceDir
)
837 GlobalData
.file_lock
= mp
.Lock()
838 # Init cache data for local only
839 GlobalData
.gPackageHashFile
= dict()
840 GlobalData
.gModulePreMakeCacheStatus
= dict()
841 GlobalData
.gModuleMakeCacheStatus
= dict()
842 GlobalData
.gHashChainStatus
= dict()
843 GlobalData
.gCMakeHashFile
= dict()
844 GlobalData
.gModuleHashFile
= dict()
845 GlobalData
.gFileHashDict
= dict()
846 GlobalData
.gModuleAllCacheStatus
= set()
847 GlobalData
.gModuleCacheHit
= set()
849 def StartAutoGen(self
,mqueue
, DataPipe
,SkipAutoGen
,PcdMaList
,cqueue
):
853 feedback_q
= mp
.Queue()
854 error_event
= mp
.Event()
855 FfsCmd
= DataPipe
.Get("FfsCommand")
858 GlobalData
.FfsCmd
= FfsCmd
859 auto_workers
= [AutoGenWorkerInProcess(mqueue
,DataPipe
.dump_file
,feedback_q
,GlobalData
.file_lock
,cqueue
,self
.log_q
,error_event
) for _
in range(self
.ThreadNumber
)]
860 self
.AutoGenMgr
= AutoGenManager(auto_workers
,feedback_q
,error_event
)
861 self
.AutoGenMgr
.start()
862 for w
in auto_workers
:
864 if PcdMaList
is not None:
865 for PcdMa
in PcdMaList
:
866 # SourceFileList calling sequence impact the makefile string sequence.
867 # Create cached SourceFileList here to unify its calling sequence for both
868 # CanSkipbyPreMakeCache and CreateCodeFile/CreateMakeFile.
869 RetVal
= PcdMa
.SourceFileList
870 # Force cache miss for PCD driver
871 if GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheDest
and self
.Target
in [None, "", "all"]:
872 cqueue
.put((PcdMa
.MetaFile
.Path
, PcdMa
.Arch
, "PreMakeCache", False))
874 PcdMa
.CreateCodeFile(False)
875 PcdMa
.CreateMakeFile(False,GenFfsList
= DataPipe
.Get("FfsCommand").get((PcdMa
.MetaFile
.Path
, PcdMa
.Arch
),[]))
876 PcdMa
.CreateAsBuiltInf()
877 # Force cache miss for PCD driver
878 if GlobalData
.gBinCacheSource
and self
.Target
in [None, "", "all"]:
879 cqueue
.put((PcdMa
.MetaFile
.Path
, PcdMa
.Arch
, "MakeCache", False))
881 self
.AutoGenMgr
.join()
882 rt
= self
.AutoGenMgr
.Status
887 except FatalError
as e
:
888 return False, e
.args
[0]
890 return False, UNKNOWN_ERROR
892 ## Add TOOLCHAIN and FAMILY declared in DSC [BuildOptions] to ToolsDefTxtDatabase.
894 # Loop through the set of build targets, tool chains, and archs provided on either
895 # the command line or in target.txt to discover FAMILY and TOOLCHAIN delclarations
896 # in [BuildOptions] sections that may be within !if expressions that may use
897 # $(TARGET), $(TOOLCHAIN), $(TOOLCHAIN_TAG), or $(ARCH) operands.
899 def GetToolChainAndFamilyFromDsc (self
, File
):
900 for BuildTarget
in self
.BuildTargetList
:
901 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
902 for BuildToolChain
in self
.ToolChainList
:
903 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = BuildToolChain
904 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = BuildToolChain
905 for BuildArch
in self
.ArchList
:
906 GlobalData
.gGlobalDefines
['ARCH'] = BuildArch
907 dscobj
= self
.BuildDatabase
[File
, BuildArch
]
908 for KeyFamily
, Key
, KeyCodeBase
in dscobj
.BuildOptions
:
910 Target
, ToolChain
, Arch
, Tool
, Attr
= Key
.split('_')
913 if ToolChain
== TAB_STAR
or Attr
!= TAB_TOD_DEFINES_FAMILY
:
916 Family
= dscobj
.BuildOptions
[(KeyFamily
, Key
, KeyCodeBase
)]
917 Family
= Family
.strip().strip('=').strip()
920 if TAB_TOD_DEFINES_FAMILY
not in self
.ToolDef
.ToolsDefTxtDatabase
:
921 self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
] = {}
922 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
]:
923 self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
][ToolChain
] = Family
924 if TAB_TOD_DEFINES_BUILDRULEFAMILY
not in self
.ToolDef
.ToolsDefTxtDatabase
:
925 self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
] = {}
926 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
]:
927 self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
][ToolChain
] = Family
928 if TAB_TOD_DEFINES_TOOL_CHAIN_TAG
not in self
.ToolDef
.ToolsDefTxtDatabase
:
929 self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
] = []
930 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
931 self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
].append(ToolChain
)
933 ## Load configuration
935 # This method will parse target.txt and get the build configurations.
937 def LoadConfiguration(self
):
939 # if no ARCH given in command line, get it from target.txt
940 if not self
.ArchList
:
941 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET_ARCH
]
942 self
.ArchList
= tuple(self
.ArchList
)
944 # if no build target given in command line, get it from target.txt
945 if not self
.BuildTargetList
:
946 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
948 # if no tool chain given in command line, get it from target.txt
949 if not self
.ToolChainList
:
950 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
951 if self
.ToolChainList
is None or len(self
.ToolChainList
) == 0:
952 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
954 if not self
.PlatformFile
:
955 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
957 # Try to find one in current directory
958 WorkingDirectory
= os
.getcwd()
959 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
960 FileNum
= len(FileList
)
962 EdkLogger
.error("build", OPTION_MISSING
,
963 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
965 PlatformFile
= FileList
[0]
967 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
968 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
970 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
972 self
.GetToolChainAndFamilyFromDsc (self
.PlatformFile
)
974 # check if the tool chains are defined or not
975 NewToolChainList
= []
976 for ToolChain
in self
.ToolChainList
:
977 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
978 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
980 NewToolChainList
.append(ToolChain
)
981 # if no tool chain available, break the build
982 if len(NewToolChainList
) == 0:
983 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
984 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
986 self
.ToolChainList
= NewToolChainList
989 ToolDefinition
= self
.ToolDef
.ToolsDefTxtDatabase
990 for Tool
in self
.ToolChainList
:
991 if TAB_TOD_DEFINES_FAMILY
not in ToolDefinition
or Tool
not in ToolDefinition
[TAB_TOD_DEFINES_FAMILY
] \
992 or not ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
]:
993 EdkLogger
.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool
)
994 ToolChainFamily
.append(TAB_COMPILER_MSFT
)
996 ToolChainFamily
.append(ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
])
997 self
.ToolChainFamily
= ToolChainFamily
999 self
.ThreadNumber
= ThreadNum()
1000 ## Initialize build configuration
1002 # This method will parse DSC file and merge the configurations from
1003 # command line and target.txt, then get the final build configurations.
1005 def InitBuild(self
):
1006 # parse target.txt, tools_def.txt, and platform file
1007 self
.LoadConfiguration()
1009 # Allow case-insensitive for those from command line or configuration file
1010 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
1012 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
1015 def InitPreBuild(self
):
1016 self
.LoadConfiguration()
1017 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
1019 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
1020 if self
.BuildTargetList
:
1021 GlobalData
.gGlobalDefines
['TARGET'] = self
.BuildTargetList
[0]
1023 GlobalData
.gGlobalDefines
['ARCH'] = self
.ArchList
[0]
1024 if self
.ToolChainList
:
1025 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = self
.ToolChainList
[0]
1026 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = self
.ToolChainList
[0]
1027 if self
.ToolChainFamily
:
1028 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[0]
1029 if 'PREBUILD' in GlobalData
.gCommandLineDefines
:
1030 self
.Prebuild
= GlobalData
.gCommandLineDefines
.get('PREBUILD')
1033 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
1034 self
.Prebuild
= str(Platform
.Prebuild
)
1038 # Evaluate all arguments and convert arguments that are WORKSPACE
1039 # relative paths to absolute paths. Filter arguments that look like
1040 # flags or do not follow the file/dir naming rules to avoid false
1041 # positives on this conversion.
1043 for Arg
in self
.Prebuild
.split():
1045 # Do not modify Arg if it looks like a flag or an absolute file path
1047 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1048 PrebuildList
.append(Arg
)
1051 # Do not modify Arg if it does not look like a Workspace relative
1052 # path that starts with a valid package directory name
1054 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1055 PrebuildList
.append(Arg
)
1058 # If Arg looks like a WORKSPACE relative path, then convert to an
1059 # absolute path and check to see if the file exists.
1061 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1062 if os
.path
.isfile(Temp
):
1064 PrebuildList
.append(Arg
)
1065 self
.Prebuild
= ' '.join(PrebuildList
)
1066 self
.Prebuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1068 def InitPostBuild(self
):
1069 if 'POSTBUILD' in GlobalData
.gCommandLineDefines
:
1070 self
.Postbuild
= GlobalData
.gCommandLineDefines
.get('POSTBUILD')
1072 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
1073 self
.Postbuild
= str(Platform
.Postbuild
)
1077 # Evaluate all arguments and convert arguments that are WORKSPACE
1078 # relative paths to absolute paths. Filter arguments that look like
1079 # flags or do not follow the file/dir naming rules to avoid false
1080 # positives on this conversion.
1082 for Arg
in self
.Postbuild
.split():
1084 # Do not modify Arg if it looks like a flag or an absolute file path
1086 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1087 PostbuildList
.append(Arg
)
1090 # Do not modify Arg if it does not look like a Workspace relative
1091 # path that starts with a valid package directory name
1093 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1094 PostbuildList
.append(Arg
)
1097 # If Arg looks like a WORKSPACE relative path, then convert to an
1098 # absolute path and check to see if the file exists.
1100 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1101 if os
.path
.isfile(Temp
):
1103 PostbuildList
.append(Arg
)
1104 self
.Postbuild
= ' '.join(PostbuildList
)
1105 self
.Postbuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1107 def PassCommandOption(self
, BuildTarget
, TargetArch
, ToolChain
, PlatformFile
, Target
):
1109 if GlobalData
.gCommand
and isinstance(GlobalData
.gCommand
, list):
1110 BuildStr
+= ' ' + ' '.join(GlobalData
.gCommand
)
1113 ToolChainFlag
= False
1114 PlatformFileFlag
= False
1116 if GlobalData
.gOptions
and not GlobalData
.gOptions
.BuildTarget
:
1118 if GlobalData
.gOptions
and not GlobalData
.gOptions
.TargetArch
:
1120 if GlobalData
.gOptions
and not GlobalData
.gOptions
.ToolChain
:
1121 ToolChainFlag
= True
1122 if GlobalData
.gOptions
and not GlobalData
.gOptions
.PlatformFile
:
1123 PlatformFileFlag
= True
1125 if TargetFlag
and BuildTarget
:
1126 if isinstance(BuildTarget
, list) or isinstance(BuildTarget
, tuple):
1127 BuildStr
+= ' -b ' + ' -b '.join(BuildTarget
)
1128 elif isinstance(BuildTarget
, str):
1129 BuildStr
+= ' -b ' + BuildTarget
1130 if ArchFlag
and TargetArch
:
1131 if isinstance(TargetArch
, list) or isinstance(TargetArch
, tuple):
1132 BuildStr
+= ' -a ' + ' -a '.join(TargetArch
)
1133 elif isinstance(TargetArch
, str):
1134 BuildStr
+= ' -a ' + TargetArch
1135 if ToolChainFlag
and ToolChain
:
1136 if isinstance(ToolChain
, list) or isinstance(ToolChain
, tuple):
1137 BuildStr
+= ' -t ' + ' -t '.join(ToolChain
)
1138 elif isinstance(ToolChain
, str):
1139 BuildStr
+= ' -t ' + ToolChain
1140 if PlatformFileFlag
and PlatformFile
:
1141 if isinstance(PlatformFile
, list) or isinstance(PlatformFile
, tuple):
1142 BuildStr
+= ' -p ' + ' -p '.join(PlatformFile
)
1143 elif isinstance(PlatformFile
, str):
1144 BuildStr
+= ' -p' + PlatformFile
1145 BuildStr
+= ' --conf=' + GlobalData
.gConfDirectory
1147 BuildStr
+= ' ' + Target
1151 def LaunchPrebuild(self
):
1153 EdkLogger
.info("\n- Prebuild Start -\n")
1154 self
.LaunchPrebuildFlag
= True
1156 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1157 # and preserve them for the rest of the main build step, because the child process environment will
1158 # evaporate as soon as it exits, we cannot get it in build step.
1160 PrebuildEnvFile
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PrebuildEnv')
1161 if os
.path
.isfile(PrebuildEnvFile
):
1162 os
.remove(PrebuildEnvFile
)
1163 if os
.path
.isfile(self
.PlatformBuildPath
):
1164 os
.remove(self
.PlatformBuildPath
)
1165 if sys
.platform
== "win32":
1166 args
= ' && '.join((self
.Prebuild
, 'set > ' + PrebuildEnvFile
))
1167 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1169 args
= ' && '.join((self
.Prebuild
, 'env > ' + PrebuildEnvFile
))
1170 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1172 # launch two threads to read the STDOUT and STDERR
1173 EndOfProcedure
= Event()
1174 EndOfProcedure
.clear()
1176 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1177 StdOutThread
.setName("STDOUT-Redirector")
1178 StdOutThread
.setDaemon(False)
1179 StdOutThread
.start()
1182 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1183 StdErrThread
.setName("STDERR-Redirector")
1184 StdErrThread
.setDaemon(False)
1185 StdErrThread
.start()
1186 # waiting for program exit
1193 if Process
.returncode
!= 0 :
1194 EdkLogger
.error("Prebuild", PREBUILD_ERROR
, 'Prebuild process is not success!')
1196 if os
.path
.exists(PrebuildEnvFile
):
1197 f
= open(PrebuildEnvFile
)
1198 envs
= f
.readlines()
1200 envs
= [l
.split("=", 1) for l
in envs
]
1201 envs
= [[I
.strip() for I
in item
] for item
in envs
if len(item
) == 2]
1202 os
.environ
.update(dict(envs
))
1203 EdkLogger
.info("\n- Prebuild Done -\n")
1205 def LaunchPostbuild(self
):
1207 EdkLogger
.info("\n- Postbuild Start -\n")
1208 if sys
.platform
== "win32":
1209 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1211 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1212 # launch two threads to read the STDOUT and STDERR
1213 EndOfProcedure
= Event()
1214 EndOfProcedure
.clear()
1216 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1217 StdOutThread
.setName("STDOUT-Redirector")
1218 StdOutThread
.setDaemon(False)
1219 StdOutThread
.start()
1222 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1223 StdErrThread
.setName("STDERR-Redirector")
1224 StdErrThread
.setDaemon(False)
1225 StdErrThread
.start()
1226 # waiting for program exit
1233 if Process
.returncode
!= 0 :
1234 EdkLogger
.error("Postbuild", POSTBUILD_ERROR
, 'Postbuild process is not success!')
1235 EdkLogger
.info("\n- Postbuild Done -\n")
1237 ## Build a module or platform
1239 # Create autogen code and makefile for a module or platform, and the launch
1240 # "make" command to build it
1242 # @param Target The target of build command
1243 # @param Platform The platform file
1244 # @param Module The module file
1245 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1246 # @param ToolChain The name of toolchain to build
1247 # @param Arch The arch of the module/platform
1248 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1249 # for dependent modules/Libraries
1250 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1251 # for dependent modules/Libraries
1253 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False, FfsCommand
=None, PcdMaList
=None):
1254 if AutoGenObject
is None:
1256 if FfsCommand
is None:
1258 # skip file generation for cleanxxx targets, run and fds target
1259 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1260 # for target which must generate AutoGen code and makefile
1262 for m
in AutoGenObject
.GetAllModuleInfo
:
1264 mqueue
.put((None,None,None,None,None,None,None))
1265 AutoGenObject
.DataPipe
.DataContainer
= {"CommandTarget": self
.Target
}
1266 AutoGenObject
.DataPipe
.DataContainer
= {"Workspace_timestamp": AutoGenObject
.Workspace
._SrcTimeStamp
}
1267 AutoGenObject
.CreateLibModuelDirs()
1268 AutoGenObject
.DataPipe
.DataContainer
= {"LibraryBuildDirectoryList":AutoGenObject
.LibraryBuildDirectoryList
}
1269 AutoGenObject
.DataPipe
.DataContainer
= {"ModuleBuildDirectoryList":AutoGenObject
.ModuleBuildDirectoryList
}
1270 AutoGenObject
.DataPipe
.DataContainer
= {"FdsCommandDict": AutoGenObject
.Workspace
.GenFdsCommandDict
}
1271 self
.Progress
.Start("Generating makefile and code")
1272 data_pipe_file
= os
.path
.join(AutoGenObject
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(AutoGenObject
.Guid
),AutoGenObject
.Arch
))
1273 AutoGenObject
.DataPipe
.dump(data_pipe_file
)
1275 autogen_rt
,errorcode
= self
.StartAutoGen(mqueue
, AutoGenObject
.DataPipe
, self
.SkipAutoGen
, PcdMaList
, cqueue
)
1276 AutoGenIdFile
= os
.path
.join(GlobalData
.gConfDirectory
,".AutoGenIdFile.txt")
1277 with
open(AutoGenIdFile
,"w") as fw
:
1278 fw
.write("Arch=%s\n" % "|".join((AutoGenObject
.Workspace
.ArchList
)))
1279 fw
.write("BuildDir=%s\n" % AutoGenObject
.Workspace
.BuildDir
)
1280 fw
.write("PlatformGuid=%s\n" % str(AutoGenObject
.Guid
))
1281 self
.Progress
.Stop("done!")
1283 self
.AutoGenMgr
.TerminateWorkers()
1284 self
.AutoGenMgr
.join(1)
1285 raise FatalError(errorcode
)
1286 AutoGenObject
.CreateCodeFile(False)
1287 AutoGenObject
.CreateMakeFile(False)
1289 # always recreate top/platform makefile when clean, just in case of inconsistency
1290 AutoGenObject
.CreateCodeFile(True)
1291 AutoGenObject
.CreateMakeFile(True)
1293 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1294 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1296 BuildCommand
= AutoGenObject
.BuildCommand
1297 if BuildCommand
is None or len(BuildCommand
) == 0:
1298 EdkLogger
.error("build", OPTION_MISSING
,
1299 "No build command found for this module. "
1300 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1301 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1302 ExtraData
=str(AutoGenObject
))
1310 BuildCommand
= BuildCommand
+ [Target
]
1311 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1312 if GlobalData
.gBinCacheDest
:
1314 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
1316 # Update PreMakeCacheChain files
1317 self
.GenLocalPreMakeCache()
1318 self
.BuildModules
= []
1322 if Target
== 'libraries':
1324 for Lib
in AutoGenObject
.LibraryAutoGenList
:
1325 if not Lib
.IsBinaryModule
:
1326 DirList
.append((os
.path
.join(AutoGenObject
.BuildDir
, Lib
.BuildDir
),Lib
))
1327 for Lib
, LibAutoGen
in DirList
:
1328 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, self
.MakeFileName
)), 'pbuild']
1329 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
,LibAutoGen
)
1333 if Target
== 'modules':
1335 for Lib
in AutoGenObject
.LibraryAutoGenList
:
1336 if not Lib
.IsBinaryModule
:
1337 DirList
.append((os
.path
.join(AutoGenObject
.BuildDir
, Lib
.BuildDir
),Lib
))
1338 for Lib
, LibAutoGen
in DirList
:
1339 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, self
.MakeFileName
)), 'pbuild']
1340 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
,LibAutoGen
)
1343 for ModuleAutoGen
in AutoGenObject
.ModuleAutoGenList
:
1344 if not ModuleAutoGen
.IsBinaryModule
:
1345 DirList
.append((os
.path
.join(AutoGenObject
.BuildDir
, ModuleAutoGen
.BuildDir
),ModuleAutoGen
))
1346 for Mod
,ModAutoGen
in DirList
:
1347 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, self
.MakeFileName
)), 'pbuild']
1348 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
,ModAutoGen
)
1349 self
.CreateAsBuiltInf()
1350 if GlobalData
.gBinCacheDest
:
1352 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
1354 # Update PreMakeCacheChain files
1355 self
.GenLocalPreMakeCache()
1356 self
.BuildModules
= []
1360 if Target
== 'cleanlib':
1361 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1362 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, self
.MakeFileName
))
1363 if os
.path
.exists(LibMakefile
):
1364 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1365 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1369 if Target
== 'clean':
1370 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1371 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, self
.MakeFileName
))
1372 if os
.path
.exists(ModMakefile
):
1373 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
1374 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1375 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1376 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, self
.MakeFileName
))
1377 if os
.path
.exists(LibMakefile
):
1378 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1379 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1383 if Target
== 'cleanall':
1385 #os.rmdir(AutoGenObject.BuildDir)
1386 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1387 except WindowsError as X
:
1388 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1391 ## Build a module or platform
1393 # Create autogen code and makefile for a module or platform, and the launch
1394 # "make" command to build it
1396 # @param Target The target of build command
1397 # @param Platform The platform file
1398 # @param Module The module file
1399 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1400 # @param ToolChain The name of toolchain to build
1401 # @param Arch The arch of the module/platform
1402 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1403 # for dependent modules/Libraries
1404 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1405 # for dependent modules/Libraries
1407 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1408 if AutoGenObject
is None:
1411 # skip file generation for cleanxxx targets, run and fds target
1412 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1413 # for target which must generate AutoGen code and makefile
1414 if not self
.SkipAutoGen
or Target
== 'genc':
1415 self
.Progress
.Start("Generating code")
1416 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1417 self
.Progress
.Stop("done!")
1418 if Target
== "genc":
1421 if not self
.SkipAutoGen
or Target
== 'genmake':
1422 self
.Progress
.Start("Generating makefile")
1423 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1424 #AutoGenObject.CreateAsBuiltInf()
1425 self
.Progress
.Stop("done!")
1426 if Target
== "genmake":
1429 # always recreate top/platform makefile when clean, just in case of inconsistency
1430 AutoGenObject
.CreateCodeFile(True)
1431 AutoGenObject
.CreateMakeFile(True)
1433 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1434 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1436 BuildCommand
= AutoGenObject
.BuildCommand
1437 if BuildCommand
is None or len(BuildCommand
) == 0:
1438 EdkLogger
.error("build", OPTION_MISSING
,
1439 "No build command found for this module. "
1440 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1441 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1442 ExtraData
=str(AutoGenObject
))
1447 BuildCommand
= BuildCommand
+ [Target
]
1448 AutoGenObject
.BuildTime
= LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1449 self
.CreateAsBuiltInf()
1450 if GlobalData
.gBinCacheDest
:
1452 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
1454 # Update PreMakeCacheChain files
1455 self
.GenLocalPreMakeCache()
1456 self
.BuildModules
= []
1461 if GenFdsApi(AutoGenObject
.GenFdsCommandDict
, self
.Db
):
1462 EdkLogger
.error("build", COMMAND_FAILURE
)
1463 Threshold
= self
.GetFreeSizeThreshold()
1465 self
.CheckFreeSizeThreshold(Threshold
, AutoGenObject
.FvDir
)
1473 if Target
== 'libraries':
1480 if Target
== 'cleanall':
1482 #os.rmdir(AutoGenObject.BuildDir)
1483 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1484 except WindowsError as X
:
1485 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1488 ## Rebase module image and Get function address for the input module list.
1490 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1492 AddrIsOffset
= False
1493 for InfFile
in ModuleList
:
1494 sys
.stdout
.write (".")
1496 ModuleInfo
= ModuleList
[InfFile
]
1497 ModuleName
= ModuleInfo
.BaseName
1498 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1499 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1500 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1502 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1504 # Update Image to new BaseAddress by GenFw tool
1506 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1507 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1510 # Set new address to the section header only for SMM driver.
1512 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1513 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1515 # Collect function address from Map file
1517 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1519 if os
.path
.exists(ImageMapTable
):
1520 OrigImageBaseAddress
= 0
1521 ImageMap
= open(ImageMapTable
, 'r')
1522 for LinStr
in ImageMap
:
1523 if len (LinStr
.strip()) == 0:
1526 # Get the preferred address set on link time.
1528 if LinStr
.find ('Preferred load address is') != -1:
1529 StrList
= LinStr
.split()
1530 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1532 StrList
= LinStr
.split()
1533 if len (StrList
) > 4:
1534 if StrList
[3] == 'f' or StrList
[3] == 'F':
1536 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1537 FunctionList
.append ((Name
, RelativeAddress
))
1541 # Add general information.
1544 MapBuffer
.append('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1546 MapBuffer
.append('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1548 MapBuffer
.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1550 # Add guid and general seciton section.
1552 TextSectionAddress
= 0
1553 DataSectionAddress
= 0
1554 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1555 if SectionHeader
[0] == '.text':
1556 TextSectionAddress
= SectionHeader
[1]
1557 elif SectionHeader
[0] in ['.data', '.sdata']:
1558 DataSectionAddress
= SectionHeader
[1]
1560 MapBuffer
.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1562 MapBuffer
.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1564 # Add debug image full path.
1566 MapBuffer
.append('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1568 # Add function address
1570 for Function
in FunctionList
:
1572 MapBuffer
.append(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1574 MapBuffer
.append(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1578 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1581 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1583 ## Collect MAP information of all FVs
1585 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1587 # First get the XIP base address for FV map file.
1588 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1589 GuidName
= re
.compile(r
"\(GUID=[-a-fA-F0-9]+")
1590 for FvName
in Wa
.FdfProfile
.FvDict
:
1591 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1592 if not os
.path
.exists(FvMapBuffer
):
1594 FvMap
= open(FvMapBuffer
, 'r')
1595 #skip FV size information
1601 MatchGuid
= GuidPattern
.match(Line
)
1602 if MatchGuid
is not None:
1604 # Replace GUID with module name
1606 GuidString
= MatchGuid
.group()
1607 if GuidString
.upper() in ModuleList
:
1608 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1609 MapBuffer
.append(Line
)
1611 # Add the debug image full path.
1613 MatchGuid
= GuidName
.match(Line
)
1614 if MatchGuid
is not None:
1615 GuidString
= MatchGuid
.group().split("=")[1]
1616 if GuidString
.upper() in ModuleList
:
1617 MapBuffer
.append('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1621 ## Collect MAP information of all modules
1623 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1624 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1626 PatchEfiImageList
= []
1634 # reserve 4K size in SMRAM to make SMM module address not from 0.
1636 for ModuleGuid
in ModuleList
:
1637 Module
= ModuleList
[ModuleGuid
]
1638 GlobalData
.gProcessingFile
= "%s [%s, %s, %s]" % (Module
.MetaFile
, Module
.Arch
, Module
.ToolChain
, Module
.BuildTarget
)
1640 OutputImageFile
= ''
1641 for ResultFile
in Module
.CodaTargetList
:
1642 if str(ResultFile
.Target
).endswith('.efi'):
1644 # module list for PEI, DXE, RUNTIME and SMM
1646 OutputImageFile
= os
.path
.join(Module
.OutputDir
, Module
.Name
+ '.efi')
1647 ImageClass
= PeImageClass (OutputImageFile
)
1648 if not ImageClass
.IsValid
:
1649 EdkLogger
.error("build", FILE_PARSE_FAILURE
, ExtraData
=ImageClass
.ErrorInfo
)
1650 ImageInfo
= PeImageInfo(Module
.Name
, Module
.Guid
, Module
.Arch
, Module
.OutputDir
, Module
.DebugDir
, ImageClass
)
1651 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
]:
1652 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1653 PeiSize
+= ImageInfo
.Image
.Size
1654 elif Module
.ModuleType
in [EDK_COMPONENT_TYPE_BS_DRIVER
, SUP_MODULE_DXE_DRIVER
, SUP_MODULE_UEFI_DRIVER
]:
1655 BtModuleList
[Module
.MetaFile
] = ImageInfo
1656 BtSize
+= ImageInfo
.Image
.Size
1657 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
]:
1658 RtModuleList
[Module
.MetaFile
] = ImageInfo
1659 RtSize
+= ImageInfo
.Image
.Size
1660 elif Module
.ModuleType
in [SUP_MODULE_SMM_CORE
, SUP_MODULE_DXE_SMM_DRIVER
, SUP_MODULE_MM_STANDALONE
, SUP_MODULE_MM_CORE_STANDALONE
]:
1661 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1662 SmmSize
+= ImageInfo
.Image
.Size
1663 if Module
.ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
1664 PiSpecVersion
= Module
.Module
.Specification
.get('PI_SPECIFICATION_VERSION', '0x00000000')
1665 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1666 if int(PiSpecVersion
, 16) < 0x0001000A:
1667 BtModuleList
[Module
.MetaFile
] = ImageInfo
1668 BtSize
+= ImageInfo
.Image
.Size
1671 # EFI image is final target.
1672 # Check EFI image contains patchable FixAddress related PCDs.
1674 if OutputImageFile
!= '':
1675 ModuleIsPatch
= False
1676 for Pcd
in Module
.ModulePcdList
:
1677 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1678 ModuleIsPatch
= True
1680 if not ModuleIsPatch
:
1681 for Pcd
in Module
.LibraryPcdList
:
1682 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1683 ModuleIsPatch
= True
1686 if not ModuleIsPatch
:
1689 # Module includes the patchable load fix address PCDs.
1690 # It will be fixed up later.
1692 PatchEfiImageList
.append (OutputImageFile
)
1695 # Get Top Memory address
1697 ReservedRuntimeMemorySize
= 0
1698 TopMemoryAddress
= 0
1699 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1700 TopMemoryAddress
= 0
1702 TopMemoryAddress
= self
.LoadFixAddress
1703 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1704 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1707 # Patch FixAddress related PCDs into EFI image
1709 for EfiImage
in PatchEfiImageList
:
1710 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1711 if not os
.path
.exists(EfiImageMap
):
1714 # Get PCD offset in EFI image by GenPatchPcdTable function
1716 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1718 # Patch real PCD value by PatchPcdValue tool
1720 for PcdInfo
in PcdTable
:
1722 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1723 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
// 0x1000))
1724 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1725 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
// 0x1000))
1726 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1727 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
// 0x1000))
1728 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1729 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
// 0x1000))
1730 if ReturnValue
!= 0:
1731 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1733 MapBuffer
.append('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
// 0x1000))
1734 MapBuffer
.append('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
// 0x1000))
1735 MapBuffer
.append('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
// 0x1000))
1736 if len (SmmModuleList
) > 0:
1737 MapBuffer
.append('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
// 0x1000))
1739 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1740 BtBaseAddr
= TopMemoryAddress
- RtSize
1741 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1743 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1744 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1745 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1746 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
=False, ModeIsSmm
=True)
1747 MapBuffer
.append('\n\n')
1748 sys
.stdout
.write ("\n")
1751 ## Save platform Map file
1753 def _SaveMapFile (self
, MapBuffer
, Wa
):
1755 # Map file path is got.
1757 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1759 # Save address map into MAP file.
1761 SaveFileOnChange(MapFilePath
, ''.join(MapBuffer
), False)
1762 if self
.LoadFixAddress
!= 0:
1763 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath
))
1766 ## Build active platform for different build targets and different tool chains
1768 def _BuildPlatform(self
):
1769 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1770 for BuildTarget
in self
.BuildTargetList
:
1771 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1773 for ToolChain
in self
.ToolChainList
:
1774 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1775 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1776 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1778 Wa
= WorkspaceAutoGen(
1795 self
.Fdf
= Wa
.FdfFile
1796 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1797 self
.BuildReport
.AddPlatformReport(Wa
)
1798 self
.Progress
.Stop("done!")
1800 # Add ffs build to makefile
1802 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1803 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1805 for Arch
in Wa
.ArchList
:
1807 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1808 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1809 for Module
in Pa
.Platform
.Modules
:
1810 # Get ModuleAutoGen object to generate C code file and makefile
1811 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1815 Ma
.PlatformInfo
= Pa
1817 PcdMaList
.append(Ma
)
1818 self
.BuildModules
.append(Ma
)
1819 Pa
.DataPipe
.DataContainer
= {"FfsCommand":CmdListDict
}
1820 Pa
.DataPipe
.DataContainer
= {"Workspace_timestamp": Wa
._SrcTimeStamp
}
1821 self
._BuildPa
(self
.Target
, Pa
, FfsCommand
=CmdListDict
,PcdMaList
=PcdMaList
)
1823 # Create MAP file when Load Fix Address is enabled.
1824 if self
.Target
in ["", "all", "fds"]:
1825 for Arch
in Wa
.ArchList
:
1826 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1828 # Check whether the set fix address is above 4G for 32bit image.
1830 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1831 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")
1836 for Pa
in Wa
.AutoGenObjectList
:
1837 for Ma
in Pa
.ModuleAutoGenList
:
1840 if not Ma
.IsLibrary
:
1841 ModuleList
[Ma
.Guid
.upper()] = Ma
1844 if self
.LoadFixAddress
!= 0:
1846 # Rebase module to the preferred memory address before GenFds
1848 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1851 # create FDS again for the updated EFI image
1853 self
._Build
("fds", Wa
)
1855 # Create MAP file for all platform FVs after GenFds.
1857 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1859 # Save MAP buffer into MAP file.
1861 self
._SaveMapFile
(MapBuffer
, Wa
)
1862 self
.CreateGuidedSectionToolsFile(Wa
)
1864 ## Build active module for different build targets, different tool chains and different archs
1866 def _BuildModule(self
):
1867 for BuildTarget
in self
.BuildTargetList
:
1868 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1870 for ToolChain
in self
.ToolChainList
:
1871 WorkspaceAutoGenTime
= time
.time()
1872 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1873 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1874 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1877 # module build needs platform build information, so get platform
1880 Wa
= WorkspaceAutoGen(
1898 self
.Fdf
= Wa
.FdfFile
1899 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1900 Wa
.CreateMakeFile(False)
1901 # Add ffs build to makefile
1903 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1904 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1906 GlobalData
.file_lock
= mp
.Lock()
1907 GlobalData
.FfsCmd
= CmdListDict
1909 self
.Progress
.Stop("done!")
1911 ExitFlag
= threading
.Event()
1913 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1914 for Arch
in Wa
.ArchList
:
1915 AutoGenStart
= time
.time()
1916 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1917 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1918 for Module
in Pa
.Platform
.Modules
:
1919 if self
.ModuleFile
.Dir
== Module
.Dir
and self
.ModuleFile
.Name
== Module
.Name
:
1920 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1924 Ma
.PlatformInfo
= Pa
1928 if GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheDest
and self
.Target
in [None, "", "all"]:
1929 if Ma
.CanSkipbyPreMakeCache():
1932 self
.PreMakeCacheMiss
.add(Ma
)
1934 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1935 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1936 # for target which must generate AutoGen code and makefile
1937 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1938 self
.Progress
.Start("Generating code")
1939 Ma
.CreateCodeFile(True)
1940 self
.Progress
.Stop("done!")
1941 if self
.Target
== "genc":
1943 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1944 self
.Progress
.Start("Generating makefile")
1945 if CmdListDict
and self
.Fdf
and (Module
.Path
, Arch
) in CmdListDict
:
1946 Ma
.CreateMakeFile(True, CmdListDict
[Module
.Path
, Arch
])
1947 del CmdListDict
[Module
.Path
, Arch
]
1949 Ma
.CreateMakeFile(True)
1950 self
.Progress
.Stop("done!")
1951 if self
.Target
== "genmake":
1954 if GlobalData
.gBinCacheSource
and self
.Target
in [None, "", "all"]:
1955 if Ma
.CanSkipbyMakeCache():
1958 self
.MakeCacheMiss
.add(Ma
)
1960 self
.BuildModules
.append(Ma
)
1961 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1962 MakeStart
= time
.time()
1963 for Ma
in self
.BuildModules
:
1964 if not Ma
.IsBinaryModule
:
1965 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
1966 # Break build if any build thread has error
1967 if BuildTask
.HasError():
1968 # we need a full version of makefile for platform
1970 BuildTask
.WaitForComplete()
1971 Pa
.CreateMakeFile(False)
1972 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1973 # Start task scheduler
1974 if not BuildTask
.IsOnGoing():
1975 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1977 # in case there's an interruption. we need a full version of makefile for platform
1978 Pa
.CreateMakeFile(False)
1979 if BuildTask
.HasError():
1980 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1981 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1983 MakeContiue
= time
.time()
1985 BuildTask
.WaitForComplete()
1986 self
.CreateAsBuiltInf()
1987 if GlobalData
.gBinCacheDest
:
1989 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
1991 # Update PreMakeCacheChain files
1992 self
.GenLocalPreMakeCache()
1993 self
.BuildModules
= []
1994 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1995 if BuildTask
.HasError():
1996 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1998 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
2003 "Module for [%s] is not a component of active platform."\
2004 " Please make sure that the ARCH and inf file path are"\
2005 " given in the same as in [%s]" % \
2006 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
2007 ExtraData
=self
.ModuleFile
2009 # Create MAP file when Load Fix Address is enabled.
2010 if self
.Target
== "fds" and self
.Fdf
:
2011 for Arch
in Wa
.ArchList
:
2013 # Check whether the set fix address is above 4G for 32bit image.
2015 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2016 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")
2021 for Pa
in Wa
.AutoGenObjectList
:
2022 for Ma
in Pa
.ModuleAutoGenList
:
2025 if not Ma
.IsLibrary
:
2026 ModuleList
[Ma
.Guid
.upper()] = Ma
2029 if self
.LoadFixAddress
!= 0:
2031 # Rebase module to the preferred memory address before GenFds
2033 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2035 # create FDS again for the updated EFI image
2037 GenFdsStart
= time
.time()
2038 self
._Build
("fds", Wa
)
2039 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2041 # Create MAP file for all platform FVs after GenFds.
2043 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2045 # Save MAP buffer into MAP file.
2047 self
._SaveMapFile
(MapBuffer
, Wa
)
2049 def _GenFfsCmd(self
,ArchList
):
2050 # convert dictionary of Cmd:(Inf,Arch)
2051 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
2052 CmdSetDict
= defaultdict(set)
2053 GenFfsDict
= GenFds
.GenFfsMakefile('', GlobalData
.gFdfParser
, self
, ArchList
, GlobalData
)
2054 for Cmd
in GenFfsDict
:
2055 tmpInf
, tmpArch
= GenFfsDict
[Cmd
]
2056 CmdSetDict
[tmpInf
, tmpArch
].add(Cmd
)
2058 def VerifyAutoGenFiles(self
):
2059 AutoGenIdFile
= os
.path
.join(GlobalData
.gConfDirectory
,".AutoGenIdFile.txt")
2061 with
open(AutoGenIdFile
) as fd
:
2062 lines
= fd
.readlines()
2067 ArchList
= line
.strip().split("=")[1].split("|")
2068 if "BuildDir" in line
:
2069 BuildDir
= line
.split("=")[1].strip()
2070 if "PlatformGuid" in line
:
2071 PlatformGuid
= line
.split("=")[1].strip()
2073 for arch
in ArchList
:
2074 global_var
= os
.path
.join(BuildDir
, "GlobalVar_%s_%s.bin" % (str(PlatformGuid
),arch
))
2075 if not os
.path
.exists(global_var
):
2077 GlobalVarList
.append(global_var
)
2078 for global_var
in GlobalVarList
:
2079 data_pipe
= MemoryDataPipe()
2080 data_pipe
.load(global_var
)
2081 target
= data_pipe
.Get("P_Info").get("Target")
2082 toolchain
= data_pipe
.Get("P_Info").get("ToolChain")
2083 archlist
= data_pipe
.Get("P_Info").get("ArchList")
2084 Arch
= data_pipe
.Get("P_Info").get("Arch")
2085 active_p
= data_pipe
.Get("P_Info").get("ActivePlatform")
2086 workspacedir
= data_pipe
.Get("P_Info").get("WorkspaceDir")
2087 PackagesPath
= os
.getenv("PACKAGES_PATH")
2088 mws
.setWs(workspacedir
, PackagesPath
)
2089 LibraryBuildDirectoryList
= data_pipe
.Get("LibraryBuildDirectoryList")
2090 ModuleBuildDirectoryList
= data_pipe
.Get("ModuleBuildDirectoryList")
2092 for m_build_dir
in LibraryBuildDirectoryList
:
2093 if not os
.path
.exists(os
.path
.join(m_build_dir
,self
.MakeFileName
)):
2095 for m_build_dir
in ModuleBuildDirectoryList
:
2096 if not os
.path
.exists(os
.path
.join(m_build_dir
,self
.MakeFileName
)):
2099 workspacedir
,active_p
,target
,toolchain
,archlist
2101 Pa
= PlatformInfo(Wa
, active_p
, target
, toolchain
, Arch
,data_pipe
)
2102 Wa
.AutoGenObjectList
.append(Pa
)
2104 def SetupMakeSetting(self
,Wa
):
2106 for Pa
in Wa
.AutoGenObjectList
:
2107 for m
in Pa
._MbList
:
2108 ma
= ModuleAutoGen(Wa
,m
.MetaFile
, Pa
.BuildTarget
, Wa
.ToolChain
, Pa
.Arch
, Pa
.MetaFile
,Pa
.DataPipe
)
2109 BuildModules
.append(ma
)
2110 fdf_file
= Wa
.FlashDefinition
2112 Fdf
= FdfParser(fdf_file
.Path
)
2114 GlobalData
.gFdfParser
= Fdf
2115 if Fdf
.CurrentFdName
and Fdf
.CurrentFdName
in Fdf
.Profile
.FdDict
:
2116 FdDict
= Fdf
.Profile
.FdDict
[Fdf
.CurrentFdName
]
2117 for FdRegion
in FdDict
.RegionList
:
2118 if str(FdRegion
.RegionType
) == 'FILE' and self
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
2119 if int(FdRegion
.Offset
) % 8 != 0:
2120 EdkLogger
.error("build", FORMAT_INVALID
, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion
.Offset
))
2121 Wa
.FdfProfile
= Fdf
.Profile
2127 ## Build a platform in multi-thread mode
2129 def PerformAutoGen(self
,BuildTarget
,ToolChain
):
2130 WorkspaceAutoGenTime
= time
.time()
2131 Wa
= WorkspaceAutoGen(
2148 self
.Fdf
= Wa
.FdfFile
2149 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
2150 self
.BuildReport
.AddPlatformReport(Wa
)
2151 Wa
.CreateMakeFile(False)
2153 # Add ffs build to makefile
2155 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
2156 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
2158 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
2160 for Arch
in Wa
.ArchList
:
2162 AutoGenStart
= time
.time()
2163 GlobalData
.gGlobalDefines
['ARCH'] = Arch
2164 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
2168 for Inf
in Pa
.Platform
.Modules
:
2169 ModuleList
.append(Inf
)
2170 # Add the INF only list in FDF
2171 if GlobalData
.gFdfParser
is not None:
2172 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
2173 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
2174 if Inf
in Pa
.Platform
.Modules
:
2176 ModuleList
.append(Inf
)
2177 Pa
.DataPipe
.DataContainer
= {"FfsCommand":CmdListDict
}
2178 Pa
.DataPipe
.DataContainer
= {"Workspace_timestamp": Wa
._SrcTimeStamp
}
2179 Pa
.DataPipe
.DataContainer
= {"CommandTarget": self
.Target
}
2180 Pa
.CreateLibModuelDirs()
2181 # Fetch the MakeFileName.
2182 self
.MakeFileName
= Pa
.MakeFileName
2183 if not self
.MakeFileName
:
2184 self
.MakeFileName
= Pa
.MakeFile
2186 Pa
.DataPipe
.DataContainer
= {"LibraryBuildDirectoryList":Pa
.LibraryBuildDirectoryList
}
2187 Pa
.DataPipe
.DataContainer
= {"ModuleBuildDirectoryList":Pa
.ModuleBuildDirectoryList
}
2188 Pa
.DataPipe
.DataContainer
= {"FdsCommandDict": Wa
.GenFdsCommandDict
}
2189 # Prepare the cache share data for multiprocessing
2190 Pa
.DataPipe
.DataContainer
= {"gPlatformHashFile":GlobalData
.gPlatformHashFile
}
2192 for ma
in Pa
.ModuleAutoGenList
:
2193 ModuleCodaFile
[(ma
.MetaFile
.File
,ma
.MetaFile
.Root
,ma
.Arch
,ma
.MetaFile
.Path
)] = [item
.Target
for item
in ma
.CodaTargetList
]
2194 Pa
.DataPipe
.DataContainer
= {"ModuleCodaFile":ModuleCodaFile
}
2195 # ModuleList contains all driver modules only
2196 for Module
in ModuleList
:
2197 # Get ModuleAutoGen object to generate C code file and makefile
2198 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2202 Ma
.PlatformInfo
= Pa
2204 PcdMaList
.append(Ma
)
2205 self
.AllDrivers
.add(Ma
)
2206 self
.AllModules
.add(Ma
)
2210 for m
in Pa
.GetAllModuleInfo
:
2212 module_file
,module_root
,module_path
,module_basename
,\
2213 module_originalpath
,module_arch
,IsLib
= m
2214 Ma
= ModuleAutoGen(Wa
, PathClass(module_path
, Wa
), BuildTarget
,\
2215 ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2216 self
.AllModules
.add(Ma
)
2217 data_pipe_file
= os
.path
.join(Pa
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(Pa
.Guid
),Pa
.Arch
))
2218 Pa
.DataPipe
.dump(data_pipe_file
)
2220 mqueue
.put((None,None,None,None,None,None,None))
2221 autogen_rt
, errorcode
= self
.StartAutoGen(mqueue
, Pa
.DataPipe
, self
.SkipAutoGen
, PcdMaList
, cqueue
)
2224 self
.AutoGenMgr
.TerminateWorkers()
2225 self
.AutoGenMgr
.join(1)
2226 raise FatalError(errorcode
)
2228 if GlobalData
.gUseHashCache
:
2229 for item
in GlobalData
.gModuleAllCacheStatus
:
2230 (MetaFilePath
, Arch
, CacheStr
, Status
) = item
2231 Ma
= ModuleAutoGen(Wa
, PathClass(MetaFilePath
, Wa
), BuildTarget
,\
2232 ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2233 if CacheStr
== "PreMakeCache" and Status
== False:
2234 self
.PreMakeCacheMiss
.add(Ma
)
2235 if CacheStr
== "PreMakeCache" and Status
== True:
2236 self
.PreMakeCacheHit
.add(Ma
)
2237 GlobalData
.gModuleCacheHit
.add(Ma
)
2238 if CacheStr
== "MakeCache" and Status
== False:
2239 self
.MakeCacheMiss
.add(Ma
)
2240 if CacheStr
== "MakeCache" and Status
== True:
2241 self
.MakeCacheHit
.add(Ma
)
2242 GlobalData
.gModuleCacheHit
.add(Ma
)
2243 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
2244 AutoGenIdFile
= os
.path
.join(GlobalData
.gConfDirectory
,".AutoGenIdFile.txt")
2245 with
open(AutoGenIdFile
,"w") as fw
:
2246 fw
.write("Arch=%s\n" % "|".join((Wa
.ArchList
)))
2247 fw
.write("BuildDir=%s\n" % Wa
.BuildDir
)
2248 fw
.write("PlatformGuid=%s\n" % str(Wa
.AutoGenObjectList
[0].Guid
))
2250 if GlobalData
.gBinCacheSource
:
2251 BuildModules
.extend(self
.MakeCacheMiss
)
2252 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheDest
:
2253 BuildModules
.extend(self
.PreMakeCacheMiss
)
2255 BuildModules
.extend(self
.AllDrivers
)
2257 self
.Progress
.Stop("done!")
2258 return Wa
, BuildModules
2260 def _MultiThreadBuildPlatform(self
):
2261 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
2262 for BuildTarget
in self
.BuildTargetList
:
2263 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
2265 for ToolChain
in self
.ToolChainList
:
2266 resetFdsGlobalVariable()
2267 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
2268 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
2269 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
2271 ExitFlag
= threading
.Event()
2273 if self
.SkipAutoGen
:
2274 Wa
= self
.VerifyAutoGenFiles()
2276 self
.SkipAutoGen
= False
2277 Wa
, self
.BuildModules
= self
.PerformAutoGen(BuildTarget
,ToolChain
)
2279 GlobalData
.gAutoGenPhase
= True
2280 self
.BuildModules
= self
.SetupMakeSetting(Wa
)
2282 Wa
, self
.BuildModules
= self
.PerformAutoGen(BuildTarget
,ToolChain
)
2283 Pa
= Wa
.AutoGenObjectList
[0]
2284 GlobalData
.gAutoGenPhase
= False
2286 if GlobalData
.gBinCacheSource
:
2287 EdkLogger
.quiet("[cache Summary]: Total module num: %s" % len(self
.AllModules
))
2288 EdkLogger
.quiet("[cache Summary]: PreMakecache miss num: %s " % len(self
.PreMakeCacheMiss
))
2289 EdkLogger
.quiet("[cache Summary]: Makecache miss num: %s " % len(self
.MakeCacheMiss
))
2291 for Arch
in Wa
.ArchList
:
2292 MakeStart
= time
.time()
2293 for Ma
in set(self
.BuildModules
):
2294 # Generate build task for the module
2295 if not Ma
.IsBinaryModule
:
2296 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
2297 # Break build if any build thread has error
2298 if BuildTask
.HasError():
2299 # we need a full version of makefile for platform
2301 BuildTask
.WaitForComplete()
2302 Pa
.CreateMakeFile(False)
2303 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2304 # Start task scheduler
2305 if not BuildTask
.IsOnGoing():
2306 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
2308 # in case there's an interruption. we need a full version of makefile for platform
2310 if BuildTask
.HasError():
2311 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2312 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
2314 MakeContiue
= time
.time()
2317 # All modules have been put in build tasks queue. Tell task scheduler
2318 # to exit if all tasks are completed
2321 BuildTask
.WaitForComplete()
2322 if GlobalData
.gBinCacheDest
:
2324 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
2326 # Update PreMakeCacheChain files
2327 self
.GenLocalPreMakeCache()
2331 ModuleList
= {ma
.Guid
.upper(): ma
for ma
in self
.BuildModules
}
2332 self
.BuildModules
= []
2333 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2335 # Check for build error, and raise exception if one
2336 # has been signaled.
2338 if BuildTask
.HasError():
2339 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2341 # Create MAP file when Load Fix Address is enabled.
2342 if self
.Target
in ["", "all", "fds"]:
2343 for Arch
in Wa
.ArchList
:
2345 # Check whether the set fix address is above 4G for 32bit image.
2347 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2348 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")
2351 # Rebase module to the preferred memory address before GenFds
2354 if self
.LoadFixAddress
!= 0:
2355 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2359 # Generate FD image if there's a FDF file found
2361 GenFdsStart
= time
.time()
2362 if GenFdsApi(Wa
.GenFdsCommandDict
, self
.Db
):
2363 EdkLogger
.error("build", COMMAND_FAILURE
)
2364 Threshold
= self
.GetFreeSizeThreshold()
2366 self
.CheckFreeSizeThreshold(Threshold
, Wa
.FvDir
)
2369 # Create MAP file for all platform FVs after GenFds.
2371 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2372 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2374 # Save MAP buffer into MAP file.
2376 self
._SaveMapFile
(MapBuffer
, Wa
)
2377 self
.CreateGuidedSectionToolsFile(Wa
)
2379 ## GetFreeSizeThreshold()
2381 # @retval int Threshold value
2383 def GetFreeSizeThreshold(self
):
2385 Threshold_Str
= GlobalData
.gCommandLineDefines
.get('FV_SPARE_SPACE_THRESHOLD')
2388 if Threshold_Str
.lower().startswith('0x'):
2389 Threshold
= int(Threshold_Str
, 16)
2391 Threshold
= int(Threshold_Str
)
2393 EdkLogger
.warn("build", 'incorrect value for FV_SPARE_SPACE_THRESHOLD %s.Only decimal or hex format is allowed.' % Threshold_Str
)
2396 def CheckFreeSizeThreshold(self
, Threshold
=None, FvDir
=None):
2397 if not isinstance(Threshold
, int):
2399 if not isinstance(FvDir
, str) or not FvDir
:
2401 FdfParserObject
= GlobalData
.gFdfParser
2402 FvRegionNameList
= [FvName
for FvName
in FdfParserObject
.Profile
.FvDict
if FdfParserObject
.Profile
.FvDict
[FvName
].FvRegionInFD
]
2403 for FvName
in FdfParserObject
.Profile
.FvDict
:
2404 if FvName
in FvRegionNameList
:
2405 FvSpaceInfoFileName
= os
.path
.join(FvDir
, FvName
.upper() + '.Fv.map')
2406 if os
.path
.exists(FvSpaceInfoFileName
):
2407 FileLinesList
= getlines(FvSpaceInfoFileName
)
2408 for Line
in FileLinesList
:
2409 NameValue
= Line
.split('=')
2410 if len(NameValue
) == 2 and NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
2411 FreeSizeValue
= int(NameValue
[1].strip(), 0)
2412 if FreeSizeValue
< Threshold
:
2413 EdkLogger
.error("build", FV_FREESIZE_ERROR
,
2414 '%s FV free space %d is not enough to meet with the required spare space %d set by -D FV_SPARE_SPACE_THRESHOLD option.' % (
2415 FvName
, FreeSizeValue
, Threshold
))
2418 ## Generate GuidedSectionTools.txt in the FV directories.
2420 def CreateGuidedSectionToolsFile(self
,Wa
):
2421 for BuildTarget
in self
.BuildTargetList
:
2422 for ToolChain
in self
.ToolChainList
:
2424 if not os
.path
.exists(FvDir
):
2427 for Arch
in self
.ArchList
:
2428 # Look through the tool definitions for GUIDed tools
2430 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.items():
2431 GuidBuildTarget
, GuidToolChain
, GuidArch
, GuidTool
, GuidAttr
= attrib
.split('_')
2432 if GuidAttr
.upper() == 'GUID':
2433 if GuidBuildTarget
== TAB_STAR
:
2434 GuidBuildTarget
= BuildTarget
2435 if GuidToolChain
== TAB_STAR
:
2436 GuidToolChain
= ToolChain
2437 if GuidArch
== TAB_STAR
:
2439 if GuidBuildTarget
== BuildTarget
and GuidToolChain
== ToolChain
and GuidArch
== Arch
:
2440 path
= '_'.join(attrib
.split('_')[:-1]) + '_PATH'
2441 if path
in self
.ToolDef
.ToolsDefTxtDictionary
:
2442 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2443 path
= self
.GetRealPathOfTool(path
)
2444 guidAttribs
.append((value
.lower(), GuidTool
, path
))
2445 # Sort by GuidTool name
2446 sorted (guidAttribs
, key
=lambda x
: x
[1])
2447 # Write out GuidedSecTools.txt
2448 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2449 toolsFile
= open(toolsFile
, 'wt')
2450 for guidedSectionTool
in guidAttribs
:
2451 print(' '.join(guidedSectionTool
), file=toolsFile
)
2454 ## Returns the real path of the tool.
2456 def GetRealPathOfTool (self
, tool
):
2457 if os
.path
.exists(tool
):
2458 return os
.path
.realpath(tool
)
2461 ## Launch the module or platform build
2464 self
.AllDrivers
= set()
2465 self
.AllModules
= set()
2466 self
.PreMakeCacheMiss
= set()
2467 self
.PreMakeCacheHit
= set()
2468 self
.MakeCacheMiss
= set()
2469 self
.MakeCacheHit
= set()
2470 if not self
.ModuleFile
:
2471 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2472 self
.SpawnMode
= False
2473 self
._BuildPlatform
()
2475 self
._MultiThreadBuildPlatform
()
2477 self
.SpawnMode
= False
2480 if self
.Target
== 'cleanall':
2481 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2483 def CreateAsBuiltInf(self
):
2484 for Module
in self
.BuildModules
:
2485 Module
.CreateAsBuiltInf()
2487 def GenDestCache(self
):
2488 for Module
in self
.AllModules
:
2489 Module
.GenPreMakefileHashList()
2490 Module
.GenMakefileHashList()
2491 Module
.CopyModuleToCache()
2493 def GenLocalPreMakeCache(self
):
2494 for Module
in self
.PreMakeCacheMiss
:
2495 Module
.GenPreMakefileHashList()
2497 ## Do some clean-up works when error occurred
2498 def Relinquish(self
):
2499 OldLogLevel
= EdkLogger
.GetLevel()
2500 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2501 Utils
.Progressor
.Abort()
2502 if self
.SpawnMode
== True:
2504 EdkLogger
.SetLevel(OldLogLevel
)
2506 def ParseDefines(DefineList
=[]):
2508 if DefineList
is not None:
2509 for Define
in DefineList
:
2510 DefineTokenList
= Define
.split("=", 1)
2511 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2512 EdkLogger
.error('build', FORMAT_INVALID
,
2513 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2514 ExtraData
=DefineTokenList
[0])
2516 if len(DefineTokenList
) == 1:
2517 DefineDict
[DefineTokenList
[0]] = "TRUE"
2519 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2524 def LogBuildTime(Time
):
2527 TimeDur
= time
.gmtime(Time
)
2528 if TimeDur
.tm_yday
> 1:
2529 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2531 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2536 OptionParser
= MyOptionParser()
2537 if not OptionParser
.BuildOption
and not OptionParser
.BuildTarget
:
2538 OptionParser
.GetOption()
2539 BuildOption
, BuildTarget
= OptionParser
.BuildOption
, OptionParser
.BuildTarget
2540 ThreadNumber
= BuildOption
.ThreadNumber
2541 GlobalData
.gCmdConfDir
= BuildOption
.ConfDirectory
2542 if ThreadNumber
is None:
2543 TargetObj
= TargetTxtDict()
2544 ThreadNumber
= TargetObj
.Target
.TargetTxtDictionary
[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
2545 if ThreadNumber
== '':
2548 ThreadNumber
= int(ThreadNumber
, 0)
2550 if ThreadNumber
== 0:
2552 ThreadNumber
= multiprocessing
.cpu_count()
2553 except (ImportError, NotImplementedError):
2556 ## Tool entrance method
2558 # This method mainly dispatch specific methods per the command line options.
2559 # If no error found, return zero value so the caller of this tool can know
2560 # if it's executed successfully or not.
2562 # @retval 0 Tool was successful
2563 # @retval 1 Tool failed
2565 LogQMaxSize
= ThreadNum() * 10
2567 StartTime
= time
.time()
2570 # Create a log Queue
2572 LogQ
= mp
.Queue(LogQMaxSize
)
2573 # Initialize log system
2574 EdkLogger
.LogClientInitialize(LogQ
)
2575 GlobalData
.gCommand
= sys
.argv
[1:]
2577 # Parse the options and args
2579 OptionParser
= MyOptionParser()
2580 if not OptionParser
.BuildOption
and not OptionParser
.BuildTarget
:
2581 OptionParser
.GetOption()
2582 Option
, Target
= OptionParser
.BuildOption
, OptionParser
.BuildTarget
2583 GlobalData
.gOptions
= Option
2584 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2587 LogLevel
= EdkLogger
.INFO
2588 if Option
.verbose
is not None:
2589 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2590 LogLevel
= EdkLogger
.VERBOSE
2591 elif Option
.quiet
is not None:
2592 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2593 LogLevel
= EdkLogger
.QUIET
2594 elif Option
.debug
is not None:
2595 EdkLogger
.SetLevel(Option
.debug
+ 1)
2596 LogLevel
= Option
.debug
+ 1
2598 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2600 if Option
.WarningAsError
== True:
2601 EdkLogger
.SetWarningAsError()
2602 Log_Agent
= LogAgent(LogQ
,LogLevel
,Option
.LogFile
)
2605 if platform
.platform().find("Windows") >= 0:
2606 GlobalData
.gIsWindows
= True
2608 GlobalData
.gIsWindows
= False
2610 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2611 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2616 if len(Target
) == 0:
2618 elif len(Target
) >= 2:
2619 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2620 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2622 Target
= Target
[0].lower()
2624 if Target
not in gSupportedTarget
:
2625 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2626 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2629 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2632 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2634 Workspace
= os
.getenv("WORKSPACE")
2636 # Get files real name in workspace dir
2638 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2640 WorkingDirectory
= os
.getcwd()
2641 if not Option
.ModuleFile
:
2642 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2643 FileNum
= len(FileList
)
2645 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2646 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2648 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2650 if Option
.ModuleFile
:
2651 if os
.path
.isabs (Option
.ModuleFile
):
2652 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2653 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2654 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2655 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2657 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2659 if Option
.PlatformFile
is not None:
2660 if os
.path
.isabs (Option
.PlatformFile
):
2661 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2662 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2663 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2665 if Option
.FdfFile
is not None:
2666 if os
.path
.isabs (Option
.FdfFile
):
2667 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2668 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2669 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2670 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2672 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2674 if Option
.Flag
is not None and Option
.Flag
not in ['-c', '-s']:
2675 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2677 MyBuild
= Build(Target
, Workspace
, Option
,LogQ
)
2678 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2679 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2683 # All job done, no error found and no exception raised
2686 except FatalError
as X
:
2687 if MyBuild
is not None:
2688 # for multi-thread build exits safely
2689 MyBuild
.Relinquish()
2690 if Option
is not None and Option
.debug
is not None:
2691 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2692 ReturnCode
= X
.args
[0]
2693 except Warning as X
:
2694 # error from Fdf parser
2695 if MyBuild
is not None:
2696 # for multi-thread build exits safely
2697 MyBuild
.Relinquish()
2698 if Option
is not None and Option
.debug
is not None:
2699 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2701 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2702 ReturnCode
= FORMAT_INVALID
2703 except KeyboardInterrupt:
2704 if MyBuild
is not None:
2706 # for multi-thread build exits safely
2707 MyBuild
.Relinquish()
2708 ReturnCode
= ABORT_ERROR
2709 if Option
is not None and Option
.debug
is not None:
2710 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2712 if MyBuild
is not None:
2713 # for multi-thread build exits safely
2714 MyBuild
.Relinquish()
2716 # try to get the meta-file from the object causing exception
2717 Tb
= sys
.exc_info()[-1]
2718 MetaFile
= GlobalData
.gProcessingFile
2719 while Tb
is not None:
2720 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2721 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2726 "Unknown fatal error when processing [%s]" % MetaFile
,
2727 ExtraData
="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR
,
2730 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2731 ReturnCode
= CODE_ERROR
2733 Utils
.Progressor
.Abort()
2734 Utils
.ClearDuplicatedInf()
2738 MyBuild
.LaunchPostbuild()
2741 Conclusion
= "Failed"
2742 elif ReturnCode
== ABORT_ERROR
:
2743 Conclusion
= "Aborted"
2745 Conclusion
= "Failed"
2746 FinishTime
= time
.time()
2747 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2748 BuildDurationStr
= ""
2749 if BuildDuration
.tm_yday
> 1:
2750 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2752 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2753 if MyBuild
is not None:
2755 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2757 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2758 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2759 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2760 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2765 if __name__
== '__main__':
2767 mp
.set_start_method('spawn')
2771 ## 0-127 is a safe return range, and 1 is a standard default error
2772 if r
< 0 or r
> 127: r
= 1