2 # build a platform or a module
4 # Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
5 # Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
6 # Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
8 # SPDX-License-Identifier: BSD-2-Clause-Patent
14 from __future__
import print_function
15 from __future__
import absolute_import
16 import os
.path
as path
24 import multiprocessing
25 from threading
import Thread
,Event
,BoundedSemaphore
27 from subprocess
import Popen
,PIPE
, STDOUT
28 from collections
import OrderedDict
, defaultdict
29 from Common
.buildoptions
import BuildOption
,BuildTarget
30 from AutoGen
.PlatformAutoGen
import PlatformAutoGen
31 from AutoGen
.ModuleAutoGen
import ModuleAutoGen
32 from AutoGen
.WorkspaceAutoGen
import WorkspaceAutoGen
33 from AutoGen
.AutoGenWorker
import AutoGenWorkerInProcess
,AutoGenManager
,\
35 from AutoGen
import GenMake
36 from Common
import Misc
as Utils
38 from Common
.TargetTxtClassObject
import TargetTxt
39 from Common
.ToolDefClassObject
import ToolDef
40 from Common
.Misc
import PathClass
,SaveFileOnChange
,RemoveDirectory
41 from Common
.StringUtils
import NormPath
42 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
43 from Common
.BuildToolError
import *
44 from Common
.DataType
import *
45 import Common
.EdkLogger
as EdkLogger
47 from Workspace
.WorkspaceDatabase
import BuildDB
49 from BuildReport
import BuildReport
50 from GenPatchPcdTable
.GenPatchPcdTable
import PeImageClass
,parsePcdInfoFromMapFile
51 from PatchPcdValue
.PatchPcdValue
import PatchBinaryFile
53 import Common
.GlobalData
as GlobalData
54 from GenFds
.GenFds
import GenFds
, GenFdsApi
55 import multiprocessing
as mp
56 from multiprocessing
import Manager
57 from AutoGen
.DataPipe
import MemoryDataPipe
58 from AutoGen
.ModuleAutoGenHelper
import WorkSpaceInfo
, PlatformInfo
59 from GenFds
.FdfParser
import FdfParser
60 from AutoGen
.IncludesAutoGen
import IncludesAutoGen
61 from GenFds
.GenFds
import resetFdsGlobalVariable
63 ## standard targets of build command
64 gSupportedTarget
= ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
66 ## build configuration file
67 gBuildConfiguration
= "target.txt"
68 gToolsDefinition
= "tools_def.txt"
70 TemporaryTablePattern
= re
.compile(r
'^_\d+_\d+_[a-fA-F0-9]+$')
73 ## Check environment PATH variable to make sure the specified tool is found
75 # If the tool is found in the PATH, then True is returned
76 # Otherwise, False is returned
78 def IsToolInPath(tool
):
79 if 'PATHEXT' in os
.environ
:
80 extns
= os
.environ
['PATHEXT'].split(os
.path
.pathsep
)
83 for pathDir
in os
.environ
['PATH'].split(os
.path
.pathsep
):
85 if os
.path
.exists(os
.path
.join(pathDir
, tool
+ ext
)):
89 ## Check environment variables
91 # Check environment variables that must be set for build. Currently they are
93 # WORKSPACE The directory all packages/platforms start from
94 # EDK_TOOLS_PATH The directory contains all tools needed by the build
95 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
97 # If any of above environment variable is not set or has error, the build
100 def CheckEnvVariable():
102 if "WORKSPACE" not in os
.environ
:
103 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
104 ExtraData
="WORKSPACE")
106 WorkspaceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["WORKSPACE"]))
107 if not os
.path
.exists(WorkspaceDir
):
108 EdkLogger
.error("build", FILE_NOT_FOUND
, "WORKSPACE doesn't exist", ExtraData
=WorkspaceDir
)
109 elif ' ' in WorkspaceDir
:
110 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in WORKSPACE path",
111 ExtraData
=WorkspaceDir
)
112 os
.environ
["WORKSPACE"] = WorkspaceDir
114 # set multiple workspace
115 PackagesPath
= os
.getenv("PACKAGES_PATH")
116 mws
.setWs(WorkspaceDir
, PackagesPath
)
117 if mws
.PACKAGES_PATH
:
118 for Path
in mws
.PACKAGES_PATH
:
119 if not os
.path
.exists(Path
):
120 EdkLogger
.error("build", FILE_NOT_FOUND
, "One Path in PACKAGES_PATH doesn't exist", ExtraData
=Path
)
122 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in PACKAGES_PATH", ExtraData
=Path
)
125 os
.environ
["EDK_TOOLS_PATH"] = os
.path
.normcase(os
.environ
["EDK_TOOLS_PATH"])
127 # check EDK_TOOLS_PATH
128 if "EDK_TOOLS_PATH" not in os
.environ
:
129 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
130 ExtraData
="EDK_TOOLS_PATH")
133 if "PATH" not in os
.environ
:
134 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
137 GlobalData
.gWorkspace
= WorkspaceDir
139 GlobalData
.gGlobalDefines
["WORKSPACE"] = WorkspaceDir
140 GlobalData
.gGlobalDefines
["EDK_TOOLS_PATH"] = os
.environ
["EDK_TOOLS_PATH"]
142 ## Get normalized file path
144 # Convert the path to be local format, and remove the WORKSPACE path at the
145 # beginning if the file path is given in full path.
147 # @param FilePath File path to be normalized
148 # @param Workspace Workspace path which the FilePath will be checked against
150 # @retval string The normalized file path
152 def NormFile(FilePath
, Workspace
):
153 # check if the path is absolute or relative
154 if os
.path
.isabs(FilePath
):
155 FileFullPath
= os
.path
.normpath(FilePath
)
157 FileFullPath
= os
.path
.normpath(mws
.join(Workspace
, FilePath
))
158 Workspace
= mws
.getWs(Workspace
, FilePath
)
160 # check if the file path exists or not
161 if not os
.path
.isfile(FileFullPath
):
162 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath
)
164 # remove workspace directory from the beginning part of the file path
165 if Workspace
[-1] in ["\\", "/"]:
166 return FileFullPath
[len(Workspace
):]
168 return FileFullPath
[(len(Workspace
) + 1):]
170 ## Get the output of an external program
172 # This is the entrance method of thread reading output of an external program and
173 # putting them in STDOUT/STDERR of current program.
175 # @param From The stream message read from
176 # @param To The stream message put on
177 # @param ExitFlag The flag used to indicate stopping reading
179 def ReadMessage(From
, To
, ExitFlag
,MemTo
=None):
181 # read one line a time
182 Line
= From
.readline()
183 # empty string means "end"
184 if Line
is not None and Line
!= b
"":
185 LineStr
= Line
.rstrip().decode(encoding
='utf-8', errors
='ignore')
186 if MemTo
is not None:
187 if "Note: including file:" == LineStr
.lstrip()[:21]:
188 MemTo
.append(LineStr
)
191 MemTo
.append(LineStr
)
199 class MakeSubProc(Popen
):
200 def __init__(self
,*args
, **argv
):
201 super(MakeSubProc
,self
).__init
__(*args
, **argv
)
204 ## Launch an external program
206 # This method will call subprocess.Popen to execute an external program with
207 # given options in specified directory. Because of the dead-lock issue during
208 # redirecting output of the external program, threads are used to to do the
211 # @param Command A list or string containing the call of the program
212 # @param WorkingDir The directory in which the program will be running
214 def LaunchCommand(Command
, WorkingDir
,ModuleAuto
= None):
215 BeginTime
= time
.time()
216 # if working directory doesn't exist, Popen() will raise an exception
217 if not os
.path
.isdir(WorkingDir
):
218 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=WorkingDir
)
220 # Command is used as the first Argument in following Popen().
221 # It could be a string or sequence. We find that if command is a string in following Popen(),
222 # ubuntu may fail with an error message that the command is not found.
223 # So here we may need convert command from string to list instance.
224 if platform
.system() != 'Windows':
225 if not isinstance(Command
, list):
226 Command
= Command
.split()
227 Command
= ' '.join(Command
)
230 EndOfProcedure
= None
233 Proc
= MakeSubProc(Command
, stdout
=PIPE
, stderr
=STDOUT
, env
=os
.environ
, cwd
=WorkingDir
, bufsize
=-1, shell
=True)
235 # launch two threads to read the STDOUT and STDERR
236 EndOfProcedure
= Event()
237 EndOfProcedure
.clear()
239 StdOutThread
= Thread(target
=ReadMessage
, args
=(Proc
.stdout
, EdkLogger
.info
, EndOfProcedure
,Proc
.ProcOut
))
240 StdOutThread
.setName("STDOUT-Redirector")
241 StdOutThread
.setDaemon(False)
245 # waiting for program exit
247 except: # in case of aborting
248 # terminate the threads redirecting the program output
249 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
250 if EndOfProcedure
is not None:
253 if not isinstance(Command
, type("")):
254 Command
= " ".join(Command
)
255 EdkLogger
.error("build", COMMAND_FAILURE
, "Failed to start command", ExtraData
="%s [%s]" % (Command
, WorkingDir
))
260 # check the return code of the program
261 if Proc
.returncode
!= 0:
262 if not isinstance(Command
, type("")):
263 Command
= " ".join(Command
)
264 # print out the Response file and its content when make failure
265 RespFile
= os
.path
.join(WorkingDir
, 'OUTPUT', 'respfilelist.txt')
266 if os
.path
.isfile(RespFile
):
268 RespContent
= f
.read()
270 EdkLogger
.info(RespContent
)
272 EdkLogger
.error("build", COMMAND_FAILURE
, ExtraData
="%s [%s]" % (Command
, WorkingDir
))
274 iau
= IncludesAutoGen(WorkingDir
,ModuleAuto
)
275 if ModuleAuto
.ToolChainFamily
== TAB_COMPILER_MSFT
:
276 iau
.CreateDepsFileForMsvc(Proc
.ProcOut
)
278 iau
.UpdateDepsFileforNonMsvc()
279 iau
.UpdateDepsFileforTrim()
280 iau
.CreateModuleDeps()
281 iau
.CreateDepsInclude()
282 return "%dms" % (int(round((time
.time() - BeginTime
) * 1000)))
284 ## The smallest unit that can be built in multi-thread build mode
286 # This is the base class of build unit. The "Obj" parameter must provide
287 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
290 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
295 # @param self The object pointer
296 # @param Obj The object the build is working on
297 # @param Target The build target name, one of gSupportedTarget
298 # @param Dependency The BuildUnit(s) which must be completed in advance
299 # @param WorkingDir The directory build command starts in
301 def __init__(self
, Obj
, BuildCommand
, Target
, Dependency
, WorkingDir
="."):
302 self
.BuildObject
= Obj
303 self
.Dependency
= Dependency
304 self
.WorkingDir
= WorkingDir
306 self
.BuildCommand
= BuildCommand
308 EdkLogger
.error("build", OPTION_MISSING
,
309 "No build command found for this module. "
310 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
311 (Obj
.BuildTarget
, Obj
.ToolChain
, Obj
.Arch
),
317 # It just returns the string representation of self.BuildObject
319 # @param self The object pointer
322 return str(self
.BuildObject
)
324 ## "==" operator method
326 # It just compares self.BuildObject with "Other". So self.BuildObject must
327 # provide its own __eq__() method.
329 # @param self The object pointer
330 # @param Other The other BuildUnit object compared to
332 def __eq__(self
, Other
):
333 return Other
and self
.BuildObject
== Other
.BuildObject \
334 and Other
.BuildObject \
335 and self
.BuildObject
.Arch
== Other
.BuildObject
.Arch
339 # It just returns the hash value of self.BuildObject which must be hashable.
341 # @param self The object pointer
344 return hash(self
.BuildObject
) + hash(self
.BuildObject
.Arch
)
347 return repr(self
.BuildObject
)
349 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
351 # This class is for module build by nmake/make build system. The "Obj" parameter
352 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
353 # be make units missing build.
355 # Currently the "Obj" should be only ModuleAutoGen object.
357 class ModuleMakeUnit(BuildUnit
):
360 # @param self The object pointer
361 # @param Obj The ModuleAutoGen object the build is working on
362 # @param Target The build target name, one of gSupportedTarget
364 def __init__(self
, Obj
, BuildCommand
,Target
):
365 Dependency
= [ModuleMakeUnit(La
, BuildCommand
,Target
) for La
in Obj
.LibraryAutoGenList
]
366 BuildUnit
.__init
__(self
, Obj
, BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
367 if Target
in [None, "", "all"]:
368 self
.Target
= "tbuild"
370 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
372 # This class is for platform build by nmake/make build system. The "Obj" parameter
373 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
374 # be make units missing build.
376 # Currently the "Obj" should be only PlatformAutoGen object.
378 class PlatformMakeUnit(BuildUnit
):
381 # @param self The object pointer
382 # @param Obj The PlatformAutoGen object the build is working on
383 # @param Target The build target name, one of gSupportedTarget
385 def __init__(self
, Obj
, BuildCommand
, Target
):
386 Dependency
= [ModuleMakeUnit(Lib
, BuildCommand
, Target
) for Lib
in self
.BuildObject
.LibraryAutoGenList
]
387 Dependency
.extend([ModuleMakeUnit(Mod
, BuildCommand
,Target
) for Mod
in self
.BuildObject
.ModuleAutoGenList
])
388 BuildUnit
.__init
__(self
, Obj
, BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
390 ## The class representing the task of a module build or platform build
392 # This class manages the build tasks in multi-thread build mode. Its jobs include
393 # scheduling thread running, catching thread error, monitor the thread status, etc.
396 # queue for tasks waiting for schedule
397 _PendingQueue
= OrderedDict()
398 _PendingQueueLock
= threading
.Lock()
400 # queue for tasks ready for running
401 _ReadyQueue
= OrderedDict()
402 _ReadyQueueLock
= threading
.Lock()
404 # queue for run tasks
405 _RunningQueue
= OrderedDict()
406 _RunningQueueLock
= threading
.Lock()
408 # queue containing all build tasks, in case duplicate build
409 _TaskQueue
= OrderedDict()
411 # flag indicating error occurs in a running thread
412 _ErrorFlag
= threading
.Event()
416 # BoundedSemaphore object used to control the number of running threads
419 # flag indicating if the scheduler is started or not
420 _SchedulerStopped
= threading
.Event()
421 _SchedulerStopped
.set()
423 ## Start the task scheduler thread
425 # @param MaxThreadNumber The maximum thread number
426 # @param ExitFlag Flag used to end the scheduler
429 def StartScheduler(MaxThreadNumber
, ExitFlag
):
430 SchedulerThread
= Thread(target
=BuildTask
.Scheduler
, args
=(MaxThreadNumber
, ExitFlag
))
431 SchedulerThread
.setName("Build-Task-Scheduler")
432 SchedulerThread
.setDaemon(False)
433 SchedulerThread
.start()
434 # wait for the scheduler to be started, especially useful in Linux
435 while not BuildTask
.IsOnGoing():
440 # @param MaxThreadNumber The maximum thread number
441 # @param ExitFlag Flag used to end the scheduler
444 def Scheduler(MaxThreadNumber
, ExitFlag
):
445 BuildTask
._SchedulerStopped
.clear()
447 # use BoundedSemaphore to control the maximum running threads
448 BuildTask
._Thread
= BoundedSemaphore(MaxThreadNumber
)
450 # scheduling loop, which will exits when no pending/ready task and
451 # indicated to do so, or there's error in running thread
453 while (len(BuildTask
._PendingQueue
) > 0 or len(BuildTask
._ReadyQueue
) > 0 \
454 or not ExitFlag
.isSet()) and not BuildTask
._ErrorFlag
.isSet():
455 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Pending Queue (%d), Ready Queue (%d)"
456 % (len(BuildTask
._PendingQueue
), len(BuildTask
._ReadyQueue
)))
458 # get all pending tasks
459 BuildTask
._PendingQueueLock
.acquire()
460 BuildObjectList
= list(BuildTask
._PendingQueue
.keys())
462 # check if their dependency is resolved, and if true, move them
465 for BuildObject
in BuildObjectList
:
466 Bt
= BuildTask
._PendingQueue
[BuildObject
]
468 BuildTask
._ReadyQueue
[BuildObject
] = BuildTask
._PendingQueue
.pop(BuildObject
)
469 BuildTask
._PendingQueueLock
.release()
471 # launch build thread until the maximum number of threads is reached
472 while not BuildTask
._ErrorFlag
.isSet():
473 # empty ready queue, do nothing further
474 if len(BuildTask
._ReadyQueue
) == 0:
477 # wait for active thread(s) exit
478 BuildTask
._Thread
.acquire(True)
480 # start a new build thread
481 Bo
, Bt
= BuildTask
._ReadyQueue
.popitem()
483 # move into running queue
484 BuildTask
._RunningQueueLock
.acquire()
485 BuildTask
._RunningQueue
[Bo
] = Bt
486 BuildTask
._RunningQueueLock
.release()
495 # wait for all running threads exit
496 if BuildTask
._ErrorFlag
.isSet():
497 EdkLogger
.quiet("\nWaiting for all build threads exit...")
498 # while not BuildTask._ErrorFlag.isSet() and \
499 while len(BuildTask
._RunningQueue
) > 0:
500 EdkLogger
.verbose("Waiting for thread ending...(%d)" % len(BuildTask
._RunningQueue
))
501 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Threads [%s]" % ", ".join(Th
.getName() for Th
in threading
.enumerate()))
504 except BaseException
as X
:
506 # TRICK: hide the output of threads left running, so that the user can
507 # catch the error message easily
509 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
510 BuildTask
._ErrorFlag
.set()
511 BuildTask
._ErrorMessage
= "build thread scheduler error\n\t%s" % str(X
)
513 BuildTask
._PendingQueue
.clear()
514 BuildTask
._ReadyQueue
.clear()
515 BuildTask
._RunningQueue
.clear()
516 BuildTask
._TaskQueue
.clear()
517 BuildTask
._SchedulerStopped
.set()
519 ## Wait for all running method exit
522 def WaitForComplete():
523 BuildTask
._SchedulerStopped
.wait()
525 ## Check if the scheduler is running or not
529 return not BuildTask
._SchedulerStopped
.isSet()
534 if BuildTask
.IsOnGoing():
535 BuildTask
._ErrorFlag
.set()
536 BuildTask
.WaitForComplete()
538 ## Check if there's error in running thread
540 # Since the main thread cannot catch exceptions in other thread, we have to
541 # use threading.Event to communicate this formation to main thread.
545 return BuildTask
._ErrorFlag
.isSet()
547 ## Get error message in running thread
549 # Since the main thread cannot catch exceptions in other thread, we have to
550 # use a static variable to communicate this message to main thread.
553 def GetErrorMessage():
554 return BuildTask
._ErrorMessage
556 ## Factory method to create a BuildTask object
558 # This method will check if a module is building or has been built. And if
559 # true, just return the associated BuildTask object in the _TaskQueue. If
560 # not, create and return a new BuildTask object. The new BuildTask object
561 # will be appended to the _PendingQueue for scheduling later.
563 # @param BuildItem A BuildUnit object representing a build object
564 # @param Dependency The dependent build object of BuildItem
567 def New(BuildItem
, Dependency
=None):
568 if BuildItem
in BuildTask
._TaskQueue
:
569 Bt
= BuildTask
._TaskQueue
[BuildItem
]
573 Bt
._Init
(BuildItem
, Dependency
)
574 BuildTask
._TaskQueue
[BuildItem
] = Bt
576 BuildTask
._PendingQueueLock
.acquire()
577 BuildTask
._PendingQueue
[BuildItem
] = Bt
578 BuildTask
._PendingQueueLock
.release()
582 ## The real constructor of BuildTask
584 # @param BuildItem A BuildUnit object representing a build object
585 # @param Dependency The dependent build object of BuildItem
587 def _Init(self
, BuildItem
, Dependency
=None):
588 self
.BuildItem
= BuildItem
590 self
.DependencyList
= []
591 if Dependency
is None:
592 Dependency
= BuildItem
.Dependency
594 Dependency
.extend(BuildItem
.Dependency
)
595 self
.AddDependency(Dependency
)
596 # flag indicating build completes, used to avoid unnecessary re-build
597 self
.CompleteFlag
= False
599 ## Check if all dependent build tasks are completed or not
603 for Dep
in self
.DependencyList
:
604 if Dep
.CompleteFlag
== True:
611 ## Add dependent build task
613 # @param Dependency The list of dependent build objects
615 def AddDependency(self
, Dependency
):
616 for Dep
in Dependency
:
617 if not Dep
.BuildObject
.IsBinaryModule
and not Dep
.BuildObject
.CanSkipbyCache(GlobalData
.gModuleCacheHit
):
618 self
.DependencyList
.append(BuildTask
.New(Dep
)) # BuildTask list
620 ## The thread wrapper of LaunchCommand function
622 # @param Command A list or string contains the call of the command
623 # @param WorkingDir The directory in which the program will be running
625 def _CommandThread(self
, Command
, WorkingDir
):
627 self
.BuildItem
.BuildObject
.BuildTime
= LaunchCommand(Command
, WorkingDir
,self
.BuildItem
.BuildObject
)
628 self
.CompleteFlag
= True
630 # Run hash operation post dependency to account for libs
631 # Run if --hash or --binary-destination
632 if GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
633 self
.BuildItem
.BuildObject
.GenModuleHash()
634 if GlobalData
.gBinCacheDest
:
635 self
.BuildItem
.BuildObject
.GenCMakeHash()
639 # TRICK: hide the output of threads left running, so that the user can
640 # catch the error message easily
642 if not BuildTask
._ErrorFlag
.isSet():
643 GlobalData
.gBuildingModule
= "%s [%s, %s, %s]" % (str(self
.BuildItem
.BuildObject
),
644 self
.BuildItem
.BuildObject
.Arch
,
645 self
.BuildItem
.BuildObject
.ToolChain
,
646 self
.BuildItem
.BuildObject
.BuildTarget
648 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
649 BuildTask
._ErrorFlag
.set()
650 BuildTask
._ErrorMessage
= "%s broken\n %s [%s]" % \
651 (threading
.currentThread().getName(), Command
, WorkingDir
)
653 # indicate there's a thread is available for another build task
654 BuildTask
._RunningQueueLock
.acquire()
655 BuildTask
._RunningQueue
.pop(self
.BuildItem
)
656 BuildTask
._RunningQueueLock
.release()
657 BuildTask
._Thread
.release()
659 ## Start build task thread
662 EdkLogger
.quiet("Building ... %s" % repr(self
.BuildItem
))
663 Command
= self
.BuildItem
.BuildCommand
+ [self
.BuildItem
.Target
]
664 self
.BuildTread
= Thread(target
=self
._CommandThread
, args
=(Command
, self
.BuildItem
.WorkingDir
))
665 self
.BuildTread
.setName("build thread")
666 self
.BuildTread
.setDaemon(False)
667 self
.BuildTread
.start()
669 ## The class contains the information related to EFI image
674 # Constructor will load all required image information.
676 # @param BaseName The full file path of image.
677 # @param Guid The GUID for image.
678 # @param Arch Arch of this image.
679 # @param OutputDir The output directory for image.
680 # @param DebugDir The debug directory for image.
681 # @param ImageClass PeImage Information
683 def __init__(self
, BaseName
, Guid
, Arch
, OutputDir
, DebugDir
, ImageClass
):
684 self
.BaseName
= BaseName
687 self
.OutputDir
= OutputDir
688 self
.DebugDir
= DebugDir
689 self
.Image
= ImageClass
690 self
.Image
.Size
= (self
.Image
.Size
// 0x1000 + 1) * 0x1000
692 ## The class implementing the EDK2 build process
694 # The build process includes:
695 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
696 # 2. Parse DSC file of active platform
697 # 3. Parse FDF file if any
698 # 4. Establish build database, including parse all other files (module, package)
699 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
700 # 6. Call build command
705 # Constructor will load all necessary configurations, parse platform, modules
706 # and packages and the establish a database for AutoGen.
708 # @param Target The build command target, one of gSupportedTarget
709 # @param WorkspaceDir The directory of workspace
710 # @param BuildOptions Build options passed from command line
712 def __init__(self
, Target
, WorkspaceDir
, BuildOptions
,log_q
):
713 self
.WorkspaceDir
= WorkspaceDir
715 self
.PlatformFile
= BuildOptions
.PlatformFile
716 self
.ModuleFile
= BuildOptions
.ModuleFile
717 self
.ArchList
= BuildOptions
.TargetArch
718 self
.ToolChainList
= BuildOptions
.ToolChain
719 self
.BuildTargetList
= BuildOptions
.BuildTarget
720 self
.Fdf
= BuildOptions
.FdfFile
721 self
.FdList
= BuildOptions
.RomImage
722 self
.FvList
= BuildOptions
.FvImage
723 self
.CapList
= BuildOptions
.CapName
724 self
.SilentMode
= BuildOptions
.SilentMode
725 self
.ThreadNumber
= 1
726 self
.SkipAutoGen
= BuildOptions
.SkipAutoGen
727 self
.Reparse
= BuildOptions
.Reparse
728 self
.SkuId
= BuildOptions
.SkuId
730 GlobalData
.gSKUID_CMD
= self
.SkuId
731 self
.ConfDirectory
= BuildOptions
.ConfDirectory
732 self
.SpawnMode
= True
733 self
.BuildReport
= BuildReport(BuildOptions
.ReportFile
, BuildOptions
.ReportType
)
734 self
.TargetTxt
= TargetTxt
735 self
.ToolDef
= ToolDef
739 GlobalData
.BuildOptionPcd
= BuildOptions
.OptionPcd
if BuildOptions
.OptionPcd
else []
740 #Set global flag for build mode
741 GlobalData
.gIgnoreSource
= BuildOptions
.IgnoreSources
742 GlobalData
.gUseHashCache
= BuildOptions
.UseHashCache
743 GlobalData
.gBinCacheDest
= BuildOptions
.BinCacheDest
744 GlobalData
.gBinCacheSource
= BuildOptions
.BinCacheSource
745 GlobalData
.gEnableGenfdsMultiThread
= not BuildOptions
.NoGenfdsMultiThread
746 GlobalData
.gDisableIncludePathCheck
= BuildOptions
.DisableIncludePathCheck
748 if GlobalData
.gBinCacheDest
and not GlobalData
.gUseHashCache
:
749 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination must be used together with --hash.")
751 if GlobalData
.gBinCacheSource
and not GlobalData
.gUseHashCache
:
752 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-source must be used together with --hash.")
754 if GlobalData
.gBinCacheDest
and GlobalData
.gBinCacheSource
:
755 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination can not be used together with --binary-source.")
757 if GlobalData
.gBinCacheSource
:
758 BinCacheSource
= os
.path
.normpath(GlobalData
.gBinCacheSource
)
759 if not os
.path
.isabs(BinCacheSource
):
760 BinCacheSource
= mws
.join(self
.WorkspaceDir
, BinCacheSource
)
761 GlobalData
.gBinCacheSource
= BinCacheSource
763 if GlobalData
.gBinCacheSource
is not None:
764 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-source.")
766 if GlobalData
.gBinCacheDest
:
767 BinCacheDest
= os
.path
.normpath(GlobalData
.gBinCacheDest
)
768 if not os
.path
.isabs(BinCacheDest
):
769 BinCacheDest
= mws
.join(self
.WorkspaceDir
, BinCacheDest
)
770 GlobalData
.gBinCacheDest
= BinCacheDest
772 if GlobalData
.gBinCacheDest
is not None:
773 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-destination.")
775 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(GlobalData
.gConfDirectory
, GlobalData
.gDatabasePath
))
776 if not os
.path
.exists(os
.path
.join(GlobalData
.gConfDirectory
, '.cache')):
777 os
.makedirs(os
.path
.join(GlobalData
.gConfDirectory
, '.cache'))
779 self
.BuildDatabase
= self
.Db
.BuildObject
781 self
.ToolChainFamily
= None
782 self
.LoadFixAddress
= 0
783 self
.UniFlag
= BuildOptions
.Flag
784 self
.BuildModules
= []
785 self
.HashSkipModules
= []
787 self
.LaunchPrebuildFlag
= False
788 self
.PlatformBuildPath
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PlatformBuild')
789 if BuildOptions
.CommandLength
:
790 GlobalData
.gCommandMaxLength
= BuildOptions
.CommandLength
792 # print dot character during doing some time-consuming work
793 self
.Progress
= Utils
.Progressor()
794 # print current build environment and configuration
795 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
796 if "PACKAGES_PATH" in os
.environ
:
797 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
798 EdkLogger
.quiet("%-16s = %s" % ("PACKAGES_PATH", os
.path
.normcase(os
.path
.normpath(os
.environ
["PACKAGES_PATH"]))))
799 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
800 if "EDK_TOOLS_BIN" in os
.environ
:
801 # Print the same path style with WORKSPACE env.
802 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_TOOLS_BIN"]))))
803 EdkLogger
.quiet("%-16s = %s" % ("CONF_PATH", GlobalData
.gConfDirectory
))
804 if "PYTHON3_ENABLE" in os
.environ
:
805 PYTHON3_ENABLE
= os
.environ
["PYTHON3_ENABLE"]
806 if PYTHON3_ENABLE
!= "TRUE":
807 PYTHON3_ENABLE
= "FALSE"
808 EdkLogger
.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE
))
809 if "PYTHON_COMMAND" in os
.environ
:
810 EdkLogger
.quiet("%-16s = %s" % ("PYTHON_COMMAND", os
.environ
["PYTHON_COMMAND"]))
814 EdkLogger
.quiet("%-16s = %s" % ("PREBUILD", self
.Prebuild
))
816 EdkLogger
.quiet("%-16s = %s" % ("POSTBUILD", self
.Postbuild
))
818 self
.LaunchPrebuild()
819 self
.TargetTxt
= TargetTxt
820 self
.ToolDef
= ToolDef
821 if not (self
.LaunchPrebuildFlag
and os
.path
.exists(self
.PlatformBuildPath
)):
824 self
.AutoGenMgr
= None
826 os
.chdir(self
.WorkspaceDir
)
828 GlobalData
.file_lock
= mp
.Lock()
829 # Init cache data for local only
830 GlobalData
.gPackageHashFile
= dict()
831 GlobalData
.gModulePreMakeCacheStatus
= dict()
832 GlobalData
.gModuleMakeCacheStatus
= dict()
833 GlobalData
.gHashChainStatus
= dict()
834 GlobalData
.gCMakeHashFile
= dict()
835 GlobalData
.gModuleHashFile
= dict()
836 GlobalData
.gFileHashDict
= dict()
837 GlobalData
.gModuleAllCacheStatus
= set()
838 GlobalData
.gModuleCacheHit
= set()
840 def StartAutoGen(self
,mqueue
, DataPipe
,SkipAutoGen
,PcdMaList
,cqueue
):
844 feedback_q
= mp
.Queue()
845 error_event
= mp
.Event()
846 FfsCmd
= DataPipe
.Get("FfsCommand")
849 GlobalData
.FfsCmd
= FfsCmd
850 auto_workers
= [AutoGenWorkerInProcess(mqueue
,DataPipe
.dump_file
,feedback_q
,GlobalData
.file_lock
,cqueue
,self
.log_q
,error_event
) for _
in range(self
.ThreadNumber
)]
851 self
.AutoGenMgr
= AutoGenManager(auto_workers
,feedback_q
,error_event
)
852 self
.AutoGenMgr
.start()
853 for w
in auto_workers
:
855 if PcdMaList
is not None:
856 for PcdMa
in PcdMaList
:
857 # SourceFileList calling sequence impact the makefile string sequence.
858 # Create cached SourceFileList here to unify its calling sequence for both
859 # CanSkipbyPreMakeCache and CreateCodeFile/CreateMakeFile.
860 RetVal
= PcdMa
.SourceFileList
861 # Force cache miss for PCD driver
862 if GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheDest
and self
.Target
in [None, "", "all"]:
863 cqueue
.put((PcdMa
.MetaFile
.Path
, PcdMa
.Arch
, "PreMakeCache", False))
865 PcdMa
.CreateCodeFile(False)
866 PcdMa
.CreateMakeFile(False,GenFfsList
= DataPipe
.Get("FfsCommand").get((PcdMa
.MetaFile
.Path
, PcdMa
.Arch
),[]))
868 # Force cache miss for PCD driver
869 if GlobalData
.gBinCacheSource
and self
.Target
in [None, "", "all"]:
870 cqueue
.put((PcdMa
.MetaFile
.Path
, PcdMa
.Arch
, "MakeCache", False))
872 self
.AutoGenMgr
.join()
873 rt
= self
.AutoGenMgr
.Status
875 except FatalError
as e
:
876 return False, e
.args
[0]
878 return False, UNKNOWN_ERROR
880 ## Load configuration
882 # This method will parse target.txt and get the build configurations.
884 def LoadConfiguration(self
):
886 # if no ARCH given in command line, get it from target.txt
887 if not self
.ArchList
:
888 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET_ARCH
]
889 self
.ArchList
= tuple(self
.ArchList
)
891 # if no build target given in command line, get it from target.txt
892 if not self
.BuildTargetList
:
893 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
895 # if no tool chain given in command line, get it from target.txt
896 if not self
.ToolChainList
:
897 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
898 if self
.ToolChainList
is None or len(self
.ToolChainList
) == 0:
899 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
901 # check if the tool chains are defined or not
902 NewToolChainList
= []
903 for ToolChain
in self
.ToolChainList
:
904 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
905 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
907 NewToolChainList
.append(ToolChain
)
908 # if no tool chain available, break the build
909 if len(NewToolChainList
) == 0:
910 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
911 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
913 self
.ToolChainList
= NewToolChainList
916 ToolDefinition
= self
.ToolDef
.ToolsDefTxtDatabase
917 for Tool
in self
.ToolChainList
:
918 if TAB_TOD_DEFINES_FAMILY
not in ToolDefinition
or Tool
not in ToolDefinition
[TAB_TOD_DEFINES_FAMILY
] \
919 or not ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
]:
920 EdkLogger
.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool
)
921 ToolChainFamily
.append(TAB_COMPILER_MSFT
)
923 ToolChainFamily
.append(ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
])
924 self
.ToolChainFamily
= ToolChainFamily
926 if not self
.PlatformFile
:
927 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
929 # Try to find one in current directory
930 WorkingDirectory
= os
.getcwd()
931 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
932 FileNum
= len(FileList
)
934 EdkLogger
.error("build", OPTION_MISSING
,
935 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
937 PlatformFile
= FileList
[0]
939 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
940 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
942 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
943 self
.ThreadNumber
= ThreadNum()
944 ## Initialize build configuration
946 # This method will parse DSC file and merge the configurations from
947 # command line and target.txt, then get the final build configurations.
950 # parse target.txt, tools_def.txt, and platform file
951 self
.LoadConfiguration()
953 # Allow case-insensitive for those from command line or configuration file
954 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
956 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
959 def InitPreBuild(self
):
960 self
.LoadConfiguration()
961 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
963 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
964 if self
.BuildTargetList
:
965 GlobalData
.gGlobalDefines
['TARGET'] = self
.BuildTargetList
[0]
967 GlobalData
.gGlobalDefines
['ARCH'] = self
.ArchList
[0]
968 if self
.ToolChainList
:
969 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = self
.ToolChainList
[0]
970 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = self
.ToolChainList
[0]
971 if self
.ToolChainFamily
:
972 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[0]
973 if 'PREBUILD' in GlobalData
.gCommandLineDefines
:
974 self
.Prebuild
= GlobalData
.gCommandLineDefines
.get('PREBUILD')
977 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
978 self
.Prebuild
= str(Platform
.Prebuild
)
982 # Evaluate all arguments and convert arguments that are WORKSPACE
983 # relative paths to absolute paths. Filter arguments that look like
984 # flags or do not follow the file/dir naming rules to avoid false
985 # positives on this conversion.
987 for Arg
in self
.Prebuild
.split():
989 # Do not modify Arg if it looks like a flag or an absolute file path
991 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
992 PrebuildList
.append(Arg
)
995 # Do not modify Arg if it does not look like a Workspace relative
996 # path that starts with a valid package directory name
998 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
999 PrebuildList
.append(Arg
)
1002 # If Arg looks like a WORKSPACE relative path, then convert to an
1003 # absolute path and check to see if the file exists.
1005 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1006 if os
.path
.isfile(Temp
):
1008 PrebuildList
.append(Arg
)
1009 self
.Prebuild
= ' '.join(PrebuildList
)
1010 self
.Prebuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1012 def InitPostBuild(self
):
1013 if 'POSTBUILD' in GlobalData
.gCommandLineDefines
:
1014 self
.Postbuild
= GlobalData
.gCommandLineDefines
.get('POSTBUILD')
1016 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
1017 self
.Postbuild
= str(Platform
.Postbuild
)
1021 # Evaluate all arguments and convert arguments that are WORKSPACE
1022 # relative paths to absolute paths. Filter arguments that look like
1023 # flags or do not follow the file/dir naming rules to avoid false
1024 # positives on this conversion.
1026 for Arg
in self
.Postbuild
.split():
1028 # Do not modify Arg if it looks like a flag or an absolute file path
1030 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1031 PostbuildList
.append(Arg
)
1034 # Do not modify Arg if it does not look like a Workspace relative
1035 # path that starts with a valid package directory name
1037 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1038 PostbuildList
.append(Arg
)
1041 # If Arg looks like a WORKSPACE relative path, then convert to an
1042 # absolute path and check to see if the file exists.
1044 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1045 if os
.path
.isfile(Temp
):
1047 PostbuildList
.append(Arg
)
1048 self
.Postbuild
= ' '.join(PostbuildList
)
1049 self
.Postbuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1051 def PassCommandOption(self
, BuildTarget
, TargetArch
, ToolChain
, PlatformFile
, Target
):
1053 if GlobalData
.gCommand
and isinstance(GlobalData
.gCommand
, list):
1054 BuildStr
+= ' ' + ' '.join(GlobalData
.gCommand
)
1057 ToolChainFlag
= False
1058 PlatformFileFlag
= False
1060 if GlobalData
.gOptions
and not GlobalData
.gOptions
.BuildTarget
:
1062 if GlobalData
.gOptions
and not GlobalData
.gOptions
.TargetArch
:
1064 if GlobalData
.gOptions
and not GlobalData
.gOptions
.ToolChain
:
1065 ToolChainFlag
= True
1066 if GlobalData
.gOptions
and not GlobalData
.gOptions
.PlatformFile
:
1067 PlatformFileFlag
= True
1069 if TargetFlag
and BuildTarget
:
1070 if isinstance(BuildTarget
, list) or isinstance(BuildTarget
, tuple):
1071 BuildStr
+= ' -b ' + ' -b '.join(BuildTarget
)
1072 elif isinstance(BuildTarget
, str):
1073 BuildStr
+= ' -b ' + BuildTarget
1074 if ArchFlag
and TargetArch
:
1075 if isinstance(TargetArch
, list) or isinstance(TargetArch
, tuple):
1076 BuildStr
+= ' -a ' + ' -a '.join(TargetArch
)
1077 elif isinstance(TargetArch
, str):
1078 BuildStr
+= ' -a ' + TargetArch
1079 if ToolChainFlag
and ToolChain
:
1080 if isinstance(ToolChain
, list) or isinstance(ToolChain
, tuple):
1081 BuildStr
+= ' -t ' + ' -t '.join(ToolChain
)
1082 elif isinstance(ToolChain
, str):
1083 BuildStr
+= ' -t ' + ToolChain
1084 if PlatformFileFlag
and PlatformFile
:
1085 if isinstance(PlatformFile
, list) or isinstance(PlatformFile
, tuple):
1086 BuildStr
+= ' -p ' + ' -p '.join(PlatformFile
)
1087 elif isinstance(PlatformFile
, str):
1088 BuildStr
+= ' -p' + PlatformFile
1089 BuildStr
+= ' --conf=' + GlobalData
.gConfDirectory
1091 BuildStr
+= ' ' + Target
1095 def LaunchPrebuild(self
):
1097 EdkLogger
.info("\n- Prebuild Start -\n")
1098 self
.LaunchPrebuildFlag
= True
1100 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1101 # and preserve them for the rest of the main build step, because the child process environment will
1102 # evaporate as soon as it exits, we cannot get it in build step.
1104 PrebuildEnvFile
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PrebuildEnv')
1105 if os
.path
.isfile(PrebuildEnvFile
):
1106 os
.remove(PrebuildEnvFile
)
1107 if os
.path
.isfile(self
.PlatformBuildPath
):
1108 os
.remove(self
.PlatformBuildPath
)
1109 if sys
.platform
== "win32":
1110 args
= ' && '.join((self
.Prebuild
, 'set > ' + PrebuildEnvFile
))
1111 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1113 args
= ' && '.join((self
.Prebuild
, 'env > ' + PrebuildEnvFile
))
1114 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1116 # launch two threads to read the STDOUT and STDERR
1117 EndOfProcedure
= Event()
1118 EndOfProcedure
.clear()
1120 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1121 StdOutThread
.setName("STDOUT-Redirector")
1122 StdOutThread
.setDaemon(False)
1123 StdOutThread
.start()
1126 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1127 StdErrThread
.setName("STDERR-Redirector")
1128 StdErrThread
.setDaemon(False)
1129 StdErrThread
.start()
1130 # waiting for program exit
1137 if Process
.returncode
!= 0 :
1138 EdkLogger
.error("Prebuild", PREBUILD_ERROR
, 'Prebuild process is not success!')
1140 if os
.path
.exists(PrebuildEnvFile
):
1141 f
= open(PrebuildEnvFile
)
1142 envs
= f
.readlines()
1144 envs
= [l
.split("=", 1) for l
in envs
]
1145 envs
= [[I
.strip() for I
in item
] for item
in envs
if len(item
) == 2]
1146 os
.environ
.update(dict(envs
))
1147 EdkLogger
.info("\n- Prebuild Done -\n")
1149 def LaunchPostbuild(self
):
1151 EdkLogger
.info("\n- Postbuild Start -\n")
1152 if sys
.platform
== "win32":
1153 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1155 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1156 # launch two threads to read the STDOUT and STDERR
1157 EndOfProcedure
= Event()
1158 EndOfProcedure
.clear()
1160 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1161 StdOutThread
.setName("STDOUT-Redirector")
1162 StdOutThread
.setDaemon(False)
1163 StdOutThread
.start()
1166 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1167 StdErrThread
.setName("STDERR-Redirector")
1168 StdErrThread
.setDaemon(False)
1169 StdErrThread
.start()
1170 # waiting for program exit
1177 if Process
.returncode
!= 0 :
1178 EdkLogger
.error("Postbuild", POSTBUILD_ERROR
, 'Postbuild process is not success!')
1179 EdkLogger
.info("\n- Postbuild Done -\n")
1181 ## Build a module or platform
1183 # Create autogen code and makefile for a module or platform, and the launch
1184 # "make" command to build it
1186 # @param Target The target of build command
1187 # @param Platform The platform file
1188 # @param Module The module file
1189 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1190 # @param ToolChain The name of toolchain to build
1191 # @param Arch The arch of the module/platform
1192 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1193 # for dependent modules/Libraries
1194 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1195 # for dependent modules/Libraries
1197 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False, FfsCommand
=None, PcdMaList
=None):
1198 if AutoGenObject
is None:
1200 if FfsCommand
is None:
1202 # skip file generation for cleanxxx targets, run and fds target
1203 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1204 # for target which must generate AutoGen code and makefile
1206 for m
in AutoGenObject
.GetAllModuleInfo
:
1209 AutoGenObject
.DataPipe
.DataContainer
= {"CommandTarget": self
.Target
}
1210 AutoGenObject
.DataPipe
.DataContainer
= {"Workspace_timestamp": AutoGenObject
.Workspace
._SrcTimeStamp
}
1211 AutoGenObject
.CreateLibModuelDirs()
1212 AutoGenObject
.DataPipe
.DataContainer
= {"LibraryBuildDirectoryList":AutoGenObject
.LibraryBuildDirectoryList
}
1213 AutoGenObject
.DataPipe
.DataContainer
= {"ModuleBuildDirectoryList":AutoGenObject
.ModuleBuildDirectoryList
}
1214 AutoGenObject
.DataPipe
.DataContainer
= {"FdsCommandDict": AutoGenObject
.Workspace
.GenFdsCommandDict
}
1215 self
.Progress
.Start("Generating makefile and code")
1216 data_pipe_file
= os
.path
.join(AutoGenObject
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(AutoGenObject
.Guid
),AutoGenObject
.Arch
))
1217 AutoGenObject
.DataPipe
.dump(data_pipe_file
)
1219 autogen_rt
,errorcode
= self
.StartAutoGen(mqueue
, AutoGenObject
.DataPipe
, self
.SkipAutoGen
, PcdMaList
, cqueue
)
1220 AutoGenIdFile
= os
.path
.join(GlobalData
.gConfDirectory
,".AutoGenIdFile.txt")
1221 with
open(AutoGenIdFile
,"w") as fw
:
1222 fw
.write("Arch=%s\n" % "|".join((AutoGenObject
.Workspace
.ArchList
)))
1223 fw
.write("BuildDir=%s\n" % AutoGenObject
.Workspace
.BuildDir
)
1224 fw
.write("PlatformGuid=%s\n" % str(AutoGenObject
.Guid
))
1225 self
.Progress
.Stop("done!")
1227 self
.AutoGenMgr
.TerminateWorkers()
1228 self
.AutoGenMgr
.join(1)
1229 raise FatalError(errorcode
)
1230 AutoGenObject
.CreateCodeFile(False)
1231 AutoGenObject
.CreateMakeFile(False)
1233 # always recreate top/platform makefile when clean, just in case of inconsistency
1234 AutoGenObject
.CreateCodeFile(True)
1235 AutoGenObject
.CreateMakeFile(True)
1237 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1238 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1240 BuildCommand
= AutoGenObject
.BuildCommand
1241 if BuildCommand
is None or len(BuildCommand
) == 0:
1242 EdkLogger
.error("build", OPTION_MISSING
,
1243 "No build command found for this module. "
1244 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1245 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1246 ExtraData
=str(AutoGenObject
))
1248 makefile
= GenMake
.BuildFile(AutoGenObject
)._FILE
_NAME
_[GenMake
.gMakeType
]
1256 BuildCommand
= BuildCommand
+ [Target
]
1257 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1258 self
.CreateAsBuiltInf()
1259 if GlobalData
.gBinCacheDest
:
1261 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
1263 # Update PreMakeCacheChain files
1264 self
.GenLocalPreMakeCache()
1265 self
.BuildModules
= []
1269 if Target
== 'libraries':
1271 for Lib
in AutoGenObject
.LibraryAutoGenList
:
1272 if not Lib
.IsBinaryModule
:
1273 DirList
.append((os
.path
.join(AutoGenObject
.BuildDir
, Lib
.BuildDir
),Lib
))
1274 for Lib
, LibAutoGen
in DirList
:
1275 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1276 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
,LibAutoGen
)
1280 if Target
== 'modules':
1282 for Lib
in AutoGenObject
.LibraryAutoGenList
:
1283 if not Lib
.IsBinaryModule
:
1284 DirList
.append((os
.path
.join(AutoGenObject
.BuildDir
, Lib
.BuildDir
),Lib
))
1285 for Lib
, LibAutoGen
in DirList
:
1286 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1287 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
,LibAutoGen
)
1290 for ModuleAutoGen
in AutoGenObject
.ModuleAutoGenList
:
1291 if not ModuleAutoGen
.IsBinaryModule
:
1292 DirList
.append((os
.path
.join(AutoGenObject
.BuildDir
, ModuleAutoGen
.BuildDir
),ModuleAutoGen
))
1293 for Mod
,ModAutoGen
in DirList
:
1294 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, makefile
)), 'pbuild']
1295 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
,ModAutoGen
)
1296 self
.CreateAsBuiltInf()
1297 if GlobalData
.gBinCacheDest
:
1299 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
1301 # Update PreMakeCacheChain files
1302 self
.GenLocalPreMakeCache()
1303 self
.BuildModules
= []
1307 if Target
== 'cleanlib':
1308 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1309 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1310 if os
.path
.exists(LibMakefile
):
1311 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1312 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1316 if Target
== 'clean':
1317 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1318 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, makefile
))
1319 if os
.path
.exists(ModMakefile
):
1320 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
1321 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1322 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1323 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1324 if os
.path
.exists(LibMakefile
):
1325 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1326 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1330 if Target
== 'cleanall':
1332 #os.rmdir(AutoGenObject.BuildDir)
1333 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1334 except WindowsError as X
:
1335 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1338 ## Build a module or platform
1340 # Create autogen code and makefile for a module or platform, and the launch
1341 # "make" command to build it
1343 # @param Target The target of build command
1344 # @param Platform The platform file
1345 # @param Module The module file
1346 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1347 # @param ToolChain The name of toolchain to build
1348 # @param Arch The arch of the module/platform
1349 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1350 # for dependent modules/Libraries
1351 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1352 # for dependent modules/Libraries
1354 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1355 if AutoGenObject
is None:
1358 # skip file generation for cleanxxx targets, run and fds target
1359 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1360 # for target which must generate AutoGen code and makefile
1361 if not self
.SkipAutoGen
or Target
== 'genc':
1362 self
.Progress
.Start("Generating code")
1363 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1364 self
.Progress
.Stop("done!")
1365 if Target
== "genc":
1368 if not self
.SkipAutoGen
or Target
== 'genmake':
1369 self
.Progress
.Start("Generating makefile")
1370 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1371 #AutoGenObject.CreateAsBuiltInf()
1372 self
.Progress
.Stop("done!")
1373 if Target
== "genmake":
1376 # always recreate top/platform makefile when clean, just in case of inconsistency
1377 AutoGenObject
.CreateCodeFile(True)
1378 AutoGenObject
.CreateMakeFile(True)
1380 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1381 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1383 BuildCommand
= AutoGenObject
.BuildCommand
1384 if BuildCommand
is None or len(BuildCommand
) == 0:
1385 EdkLogger
.error("build", OPTION_MISSING
,
1386 "No build command found for this module. "
1387 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1388 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1389 ExtraData
=str(AutoGenObject
))
1394 BuildCommand
= BuildCommand
+ [Target
]
1395 AutoGenObject
.BuildTime
= LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1396 self
.CreateAsBuiltInf()
1397 if GlobalData
.gBinCacheDest
:
1399 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
1401 # Update PreMakeCacheChain files
1402 self
.GenLocalPreMakeCache()
1403 self
.BuildModules
= []
1408 if GenFdsApi(AutoGenObject
.GenFdsCommandDict
, self
.Db
):
1409 EdkLogger
.error("build", COMMAND_FAILURE
)
1417 if Target
== 'libraries':
1424 if Target
== 'cleanall':
1426 #os.rmdir(AutoGenObject.BuildDir)
1427 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1428 except WindowsError as X
:
1429 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1432 ## Rebase module image and Get function address for the input module list.
1434 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1436 AddrIsOffset
= False
1437 for InfFile
in ModuleList
:
1438 sys
.stdout
.write (".")
1440 ModuleInfo
= ModuleList
[InfFile
]
1441 ModuleName
= ModuleInfo
.BaseName
1442 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1443 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1444 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1446 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1448 # Update Image to new BaseAddress by GenFw tool
1450 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1451 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1454 # Set new address to the section header only for SMM driver.
1456 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1457 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1459 # Collect function address from Map file
1461 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1463 if os
.path
.exists(ImageMapTable
):
1464 OrigImageBaseAddress
= 0
1465 ImageMap
= open(ImageMapTable
, 'r')
1466 for LinStr
in ImageMap
:
1467 if len (LinStr
.strip()) == 0:
1470 # Get the preferred address set on link time.
1472 if LinStr
.find ('Preferred load address is') != -1:
1473 StrList
= LinStr
.split()
1474 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1476 StrList
= LinStr
.split()
1477 if len (StrList
) > 4:
1478 if StrList
[3] == 'f' or StrList
[3] == 'F':
1480 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1481 FunctionList
.append ((Name
, RelativeAddress
))
1485 # Add general information.
1488 MapBuffer
.append('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1490 MapBuffer
.append('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1492 MapBuffer
.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1494 # Add guid and general seciton section.
1496 TextSectionAddress
= 0
1497 DataSectionAddress
= 0
1498 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1499 if SectionHeader
[0] == '.text':
1500 TextSectionAddress
= SectionHeader
[1]
1501 elif SectionHeader
[0] in ['.data', '.sdata']:
1502 DataSectionAddress
= SectionHeader
[1]
1504 MapBuffer
.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1506 MapBuffer
.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1508 # Add debug image full path.
1510 MapBuffer
.append('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1512 # Add function address
1514 for Function
in FunctionList
:
1516 MapBuffer
.append(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1518 MapBuffer
.append(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1522 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1525 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1527 ## Collect MAP information of all FVs
1529 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1531 # First get the XIP base address for FV map file.
1532 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1533 GuidName
= re
.compile(r
"\(GUID=[-a-fA-F0-9]+")
1534 for FvName
in Wa
.FdfProfile
.FvDict
:
1535 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1536 if not os
.path
.exists(FvMapBuffer
):
1538 FvMap
= open(FvMapBuffer
, 'r')
1539 #skip FV size information
1545 MatchGuid
= GuidPattern
.match(Line
)
1546 if MatchGuid
is not None:
1548 # Replace GUID with module name
1550 GuidString
= MatchGuid
.group()
1551 if GuidString
.upper() in ModuleList
:
1552 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1553 MapBuffer
.append(Line
)
1555 # Add the debug image full path.
1557 MatchGuid
= GuidName
.match(Line
)
1558 if MatchGuid
is not None:
1559 GuidString
= MatchGuid
.group().split("=")[1]
1560 if GuidString
.upper() in ModuleList
:
1561 MapBuffer
.append('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1565 ## Collect MAP information of all modules
1567 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1568 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1570 PatchEfiImageList
= []
1578 # reserve 4K size in SMRAM to make SMM module address not from 0.
1580 for ModuleGuid
in ModuleList
:
1581 Module
= ModuleList
[ModuleGuid
]
1582 GlobalData
.gProcessingFile
= "%s [%s, %s, %s]" % (Module
.MetaFile
, Module
.Arch
, Module
.ToolChain
, Module
.BuildTarget
)
1584 OutputImageFile
= ''
1585 for ResultFile
in Module
.CodaTargetList
:
1586 if str(ResultFile
.Target
).endswith('.efi'):
1588 # module list for PEI, DXE, RUNTIME and SMM
1590 OutputImageFile
= os
.path
.join(Module
.OutputDir
, Module
.Name
+ '.efi')
1591 ImageClass
= PeImageClass (OutputImageFile
)
1592 if not ImageClass
.IsValid
:
1593 EdkLogger
.error("build", FILE_PARSE_FAILURE
, ExtraData
=ImageClass
.ErrorInfo
)
1594 ImageInfo
= PeImageInfo(Module
.Name
, Module
.Guid
, Module
.Arch
, Module
.OutputDir
, Module
.DebugDir
, ImageClass
)
1595 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
]:
1596 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1597 PeiSize
+= ImageInfo
.Image
.Size
1598 elif Module
.ModuleType
in [EDK_COMPONENT_TYPE_BS_DRIVER
, SUP_MODULE_DXE_DRIVER
, SUP_MODULE_UEFI_DRIVER
]:
1599 BtModuleList
[Module
.MetaFile
] = ImageInfo
1600 BtSize
+= ImageInfo
.Image
.Size
1601 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
]:
1602 RtModuleList
[Module
.MetaFile
] = ImageInfo
1603 RtSize
+= ImageInfo
.Image
.Size
1604 elif Module
.ModuleType
in [SUP_MODULE_SMM_CORE
, SUP_MODULE_DXE_SMM_DRIVER
, SUP_MODULE_MM_STANDALONE
, SUP_MODULE_MM_CORE_STANDALONE
]:
1605 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1606 SmmSize
+= ImageInfo
.Image
.Size
1607 if Module
.ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
1608 PiSpecVersion
= Module
.Module
.Specification
.get('PI_SPECIFICATION_VERSION', '0x00000000')
1609 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1610 if int(PiSpecVersion
, 16) < 0x0001000A:
1611 BtModuleList
[Module
.MetaFile
] = ImageInfo
1612 BtSize
+= ImageInfo
.Image
.Size
1615 # EFI image is final target.
1616 # Check EFI image contains patchable FixAddress related PCDs.
1618 if OutputImageFile
!= '':
1619 ModuleIsPatch
= False
1620 for Pcd
in Module
.ModulePcdList
:
1621 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1622 ModuleIsPatch
= True
1624 if not ModuleIsPatch
:
1625 for Pcd
in Module
.LibraryPcdList
:
1626 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1627 ModuleIsPatch
= True
1630 if not ModuleIsPatch
:
1633 # Module includes the patchable load fix address PCDs.
1634 # It will be fixed up later.
1636 PatchEfiImageList
.append (OutputImageFile
)
1639 # Get Top Memory address
1641 ReservedRuntimeMemorySize
= 0
1642 TopMemoryAddress
= 0
1643 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1644 TopMemoryAddress
= 0
1646 TopMemoryAddress
= self
.LoadFixAddress
1647 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1648 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1651 # Patch FixAddress related PCDs into EFI image
1653 for EfiImage
in PatchEfiImageList
:
1654 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1655 if not os
.path
.exists(EfiImageMap
):
1658 # Get PCD offset in EFI image by GenPatchPcdTable function
1660 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1662 # Patch real PCD value by PatchPcdValue tool
1664 for PcdInfo
in PcdTable
:
1666 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1667 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
// 0x1000))
1668 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1669 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
// 0x1000))
1670 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1671 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
// 0x1000))
1672 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1673 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
// 0x1000))
1674 if ReturnValue
!= 0:
1675 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1677 MapBuffer
.append('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
// 0x1000))
1678 MapBuffer
.append('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
// 0x1000))
1679 MapBuffer
.append('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
// 0x1000))
1680 if len (SmmModuleList
) > 0:
1681 MapBuffer
.append('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
// 0x1000))
1683 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1684 BtBaseAddr
= TopMemoryAddress
- RtSize
1685 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1687 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1688 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1689 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1690 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
=False, ModeIsSmm
=True)
1691 MapBuffer
.append('\n\n')
1692 sys
.stdout
.write ("\n")
1695 ## Save platform Map file
1697 def _SaveMapFile (self
, MapBuffer
, Wa
):
1699 # Map file path is got.
1701 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1703 # Save address map into MAP file.
1705 SaveFileOnChange(MapFilePath
, ''.join(MapBuffer
), False)
1706 if self
.LoadFixAddress
!= 0:
1707 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath
))
1710 ## Build active platform for different build targets and different tool chains
1712 def _BuildPlatform(self
):
1713 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1714 for BuildTarget
in self
.BuildTargetList
:
1715 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1717 for ToolChain
in self
.ToolChainList
:
1718 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1719 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1720 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1722 Wa
= WorkspaceAutoGen(
1739 self
.Fdf
= Wa
.FdfFile
1740 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1741 self
.BuildReport
.AddPlatformReport(Wa
)
1742 self
.Progress
.Stop("done!")
1744 # Add ffs build to makefile
1746 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1747 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1749 for Arch
in Wa
.ArchList
:
1751 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1752 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1753 for Module
in Pa
.Platform
.Modules
:
1754 # Get ModuleAutoGen object to generate C code file and makefile
1755 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1759 Ma
.PlatformInfo
= Pa
1761 PcdMaList
.append(Ma
)
1762 self
.BuildModules
.append(Ma
)
1763 Pa
.DataPipe
.DataContainer
= {"FfsCommand":CmdListDict
}
1764 Pa
.DataPipe
.DataContainer
= {"Workspace_timestamp": Wa
._SrcTimeStamp
}
1765 self
._BuildPa
(self
.Target
, Pa
, FfsCommand
=CmdListDict
,PcdMaList
=PcdMaList
)
1767 # Create MAP file when Load Fix Address is enabled.
1768 if self
.Target
in ["", "all", "fds"]:
1769 for Arch
in Wa
.ArchList
:
1770 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1772 # Check whether the set fix address is above 4G for 32bit image.
1774 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1775 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")
1780 for Pa
in Wa
.AutoGenObjectList
:
1781 for Ma
in Pa
.ModuleAutoGenList
:
1784 if not Ma
.IsLibrary
:
1785 ModuleList
[Ma
.Guid
.upper()] = Ma
1788 if self
.LoadFixAddress
!= 0:
1790 # Rebase module to the preferred memory address before GenFds
1792 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1795 # create FDS again for the updated EFI image
1797 self
._Build
("fds", Wa
)
1799 # Create MAP file for all platform FVs after GenFds.
1801 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1803 # Save MAP buffer into MAP file.
1805 self
._SaveMapFile
(MapBuffer
, Wa
)
1806 self
.CreateGuidedSectionToolsFile(Wa
)
1808 ## Build active module for different build targets, different tool chains and different archs
1810 def _BuildModule(self
):
1811 for BuildTarget
in self
.BuildTargetList
:
1812 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1814 for ToolChain
in self
.ToolChainList
:
1815 WorkspaceAutoGenTime
= time
.time()
1816 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1817 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1818 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1821 # module build needs platform build information, so get platform
1824 Wa
= WorkspaceAutoGen(
1842 self
.Fdf
= Wa
.FdfFile
1843 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1844 Wa
.CreateMakeFile(False)
1845 # Add ffs build to makefile
1847 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1848 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1850 GlobalData
.file_lock
= mp
.Lock()
1851 GlobalData
.FfsCmd
= CmdListDict
1853 self
.Progress
.Stop("done!")
1855 ExitFlag
= threading
.Event()
1857 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1858 for Arch
in Wa
.ArchList
:
1859 AutoGenStart
= time
.time()
1860 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1861 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1862 for Module
in Pa
.Platform
.Modules
:
1863 if self
.ModuleFile
.Dir
== Module
.Dir
and self
.ModuleFile
.Name
== Module
.Name
:
1864 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1868 Ma
.PlatformInfo
= Pa
1872 if GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheDest
and self
.Target
in [None, "", "all"]:
1873 if Ma
.CanSkipbyPreMakeCache():
1876 self
.PreMakeCacheMiss
.add(Ma
)
1878 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1879 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1880 # for target which must generate AutoGen code and makefile
1881 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1882 self
.Progress
.Start("Generating code")
1883 Ma
.CreateCodeFile(True)
1884 self
.Progress
.Stop("done!")
1885 if self
.Target
== "genc":
1887 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1888 self
.Progress
.Start("Generating makefile")
1889 if CmdListDict
and self
.Fdf
and (Module
.Path
, Arch
) in CmdListDict
:
1890 Ma
.CreateMakeFile(True, CmdListDict
[Module
.Path
, Arch
])
1891 del CmdListDict
[Module
.Path
, Arch
]
1893 Ma
.CreateMakeFile(True)
1894 self
.Progress
.Stop("done!")
1895 if self
.Target
== "genmake":
1898 if GlobalData
.gBinCacheSource
and self
.Target
in [None, "", "all"]:
1899 if Ma
.CanSkipbyMakeCache():
1902 self
.MakeCacheMiss
.add(Ma
)
1904 self
.BuildModules
.append(Ma
)
1905 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1906 MakeStart
= time
.time()
1907 for Ma
in self
.BuildModules
:
1908 if not Ma
.IsBinaryModule
:
1909 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
1910 # Break build if any build thread has error
1911 if BuildTask
.HasError():
1912 # we need a full version of makefile for platform
1914 BuildTask
.WaitForComplete()
1915 Pa
.CreateMakeFile(False)
1916 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1917 # Start task scheduler
1918 if not BuildTask
.IsOnGoing():
1919 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1921 # in case there's an interruption. we need a full version of makefile for platform
1922 Pa
.CreateMakeFile(False)
1923 if BuildTask
.HasError():
1924 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1925 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1927 MakeContiue
= time
.time()
1929 BuildTask
.WaitForComplete()
1930 self
.CreateAsBuiltInf()
1931 if GlobalData
.gBinCacheDest
:
1933 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
1935 # Update PreMakeCacheChain files
1936 self
.GenLocalPreMakeCache()
1937 self
.BuildModules
= []
1938 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1939 if BuildTask
.HasError():
1940 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1942 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1947 "Module for [%s] is not a component of active platform."\
1948 " Please make sure that the ARCH and inf file path are"\
1949 " given in the same as in [%s]" % \
1950 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1951 ExtraData
=self
.ModuleFile
1953 # Create MAP file when Load Fix Address is enabled.
1954 if self
.Target
== "fds" and self
.Fdf
:
1955 for Arch
in Wa
.ArchList
:
1957 # Check whether the set fix address is above 4G for 32bit image.
1959 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1960 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")
1965 for Pa
in Wa
.AutoGenObjectList
:
1966 for Ma
in Pa
.ModuleAutoGenList
:
1969 if not Ma
.IsLibrary
:
1970 ModuleList
[Ma
.Guid
.upper()] = Ma
1973 if self
.LoadFixAddress
!= 0:
1975 # Rebase module to the preferred memory address before GenFds
1977 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1979 # create FDS again for the updated EFI image
1981 GenFdsStart
= time
.time()
1982 self
._Build
("fds", Wa
)
1983 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
1985 # Create MAP file for all platform FVs after GenFds.
1987 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1989 # Save MAP buffer into MAP file.
1991 self
._SaveMapFile
(MapBuffer
, Wa
)
1993 def _GenFfsCmd(self
,ArchList
):
1994 # convert dictionary of Cmd:(Inf,Arch)
1995 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
1996 CmdSetDict
= defaultdict(set)
1997 GenFfsDict
= GenFds
.GenFfsMakefile('', GlobalData
.gFdfParser
, self
, ArchList
, GlobalData
)
1998 for Cmd
in GenFfsDict
:
1999 tmpInf
, tmpArch
= GenFfsDict
[Cmd
]
2000 CmdSetDict
[tmpInf
, tmpArch
].add(Cmd
)
2002 def VerifyAutoGenFiles(self
):
2003 AutoGenIdFile
= os
.path
.join(GlobalData
.gConfDirectory
,".AutoGenIdFile.txt")
2005 with
open(AutoGenIdFile
) as fd
:
2006 lines
= fd
.readlines()
2011 ArchList
= line
.strip().split("=")[1].split("|")
2012 if "BuildDir" in line
:
2013 BuildDir
= line
.split("=")[1].strip()
2014 if "PlatformGuid" in line
:
2015 PlatformGuid
= line
.split("=")[1].strip()
2017 for arch
in ArchList
:
2018 global_var
= os
.path
.join(BuildDir
, "GlobalVar_%s_%s.bin" % (str(PlatformGuid
),arch
))
2019 if not os
.path
.exists(global_var
):
2021 GlobalVarList
.append(global_var
)
2022 for global_var
in GlobalVarList
:
2023 data_pipe
= MemoryDataPipe()
2024 data_pipe
.load(global_var
)
2025 target
= data_pipe
.Get("P_Info").get("Target")
2026 toolchain
= data_pipe
.Get("P_Info").get("ToolChain")
2027 archlist
= data_pipe
.Get("P_Info").get("ArchList")
2028 Arch
= data_pipe
.Get("P_Info").get("Arch")
2029 active_p
= data_pipe
.Get("P_Info").get("ActivePlatform")
2030 workspacedir
= data_pipe
.Get("P_Info").get("WorkspaceDir")
2031 PackagesPath
= os
.getenv("PACKAGES_PATH")
2032 mws
.setWs(workspacedir
, PackagesPath
)
2033 LibraryBuildDirectoryList
= data_pipe
.Get("LibraryBuildDirectoryList")
2034 ModuleBuildDirectoryList
= data_pipe
.Get("ModuleBuildDirectoryList")
2036 for m_build_dir
in LibraryBuildDirectoryList
:
2037 if not os
.path
.exists(os
.path
.join(m_build_dir
,GenMake
.BuildFile
._FILE
_NAME
_[GenMake
.gMakeType
])):
2039 for m_build_dir
in ModuleBuildDirectoryList
:
2040 if not os
.path
.exists(os
.path
.join(m_build_dir
,GenMake
.BuildFile
._FILE
_NAME
_[GenMake
.gMakeType
])):
2043 workspacedir
,active_p
,target
,toolchain
,archlist
2045 Pa
= PlatformInfo(Wa
, active_p
, target
, toolchain
, Arch
,data_pipe
)
2046 Wa
.AutoGenObjectList
.append(Pa
)
2048 def SetupMakeSetting(self
,Wa
):
2050 for Pa
in Wa
.AutoGenObjectList
:
2051 for m
in Pa
._MbList
:
2052 ma
= ModuleAutoGen(Wa
,m
.MetaFile
, Pa
.BuildTarget
, Wa
.ToolChain
, Pa
.Arch
, Pa
.MetaFile
,Pa
.DataPipe
)
2053 BuildModules
.append(ma
)
2054 fdf_file
= Wa
.FlashDefinition
2056 Fdf
= FdfParser(fdf_file
.Path
)
2058 GlobalData
.gFdfParser
= Fdf
2059 if Fdf
.CurrentFdName
and Fdf
.CurrentFdName
in Fdf
.Profile
.FdDict
:
2060 FdDict
= Fdf
.Profile
.FdDict
[Fdf
.CurrentFdName
]
2061 for FdRegion
in FdDict
.RegionList
:
2062 if str(FdRegion
.RegionType
) == 'FILE' and self
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
2063 if int(FdRegion
.Offset
) % 8 != 0:
2064 EdkLogger
.error("build", FORMAT_INVALID
, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion
.Offset
))
2065 Wa
.FdfProfile
= Fdf
.Profile
2071 ## Build a platform in multi-thread mode
2073 def PerformAutoGen(self
,BuildTarget
,ToolChain
):
2074 WorkspaceAutoGenTime
= time
.time()
2075 Wa
= WorkspaceAutoGen(
2092 self
.Fdf
= Wa
.FdfFile
2093 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
2094 self
.BuildReport
.AddPlatformReport(Wa
)
2095 Wa
.CreateMakeFile(False)
2097 # Add ffs build to makefile
2099 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
2100 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
2102 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
2104 for Arch
in Wa
.ArchList
:
2106 AutoGenStart
= time
.time()
2107 GlobalData
.gGlobalDefines
['ARCH'] = Arch
2108 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
2112 for Inf
in Pa
.Platform
.Modules
:
2113 ModuleList
.append(Inf
)
2114 # Add the INF only list in FDF
2115 if GlobalData
.gFdfParser
is not None:
2116 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
2117 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
2118 if Inf
in Pa
.Platform
.Modules
:
2120 ModuleList
.append(Inf
)
2121 Pa
.DataPipe
.DataContainer
= {"FfsCommand":CmdListDict
}
2122 Pa
.DataPipe
.DataContainer
= {"Workspace_timestamp": Wa
._SrcTimeStamp
}
2123 Pa
.DataPipe
.DataContainer
= {"CommandTarget": self
.Target
}
2124 Pa
.CreateLibModuelDirs()
2125 Pa
.DataPipe
.DataContainer
= {"LibraryBuildDirectoryList":Pa
.LibraryBuildDirectoryList
}
2126 Pa
.DataPipe
.DataContainer
= {"ModuleBuildDirectoryList":Pa
.ModuleBuildDirectoryList
}
2127 Pa
.DataPipe
.DataContainer
= {"FdsCommandDict": Wa
.GenFdsCommandDict
}
2128 # Prepare the cache share data for multiprocessing
2129 Pa
.DataPipe
.DataContainer
= {"gPlatformHashFile":GlobalData
.gPlatformHashFile
}
2131 for ma
in Pa
.ModuleAutoGenList
:
2132 ModuleCodaFile
[(ma
.MetaFile
.File
,ma
.MetaFile
.Root
,ma
.Arch
,ma
.MetaFile
.Path
)] = [item
.Target
for item
in ma
.CodaTargetList
]
2133 Pa
.DataPipe
.DataContainer
= {"ModuleCodaFile":ModuleCodaFile
}
2134 # ModuleList contains all driver modules only
2135 for Module
in ModuleList
:
2136 # Get ModuleAutoGen object to generate C code file and makefile
2137 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2141 Ma
.PlatformInfo
= Pa
2143 PcdMaList
.append(Ma
)
2144 self
.AllDrivers
.add(Ma
)
2145 self
.AllModules
.add(Ma
)
2149 for m
in Pa
.GetAllModuleInfo
:
2151 module_file
,module_root
,module_path
,module_basename
,\
2152 module_originalpath
,module_arch
,IsLib
= m
2153 Ma
= ModuleAutoGen(Wa
, PathClass(module_path
, Wa
), BuildTarget
,\
2154 ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2155 self
.AllModules
.add(Ma
)
2156 data_pipe_file
= os
.path
.join(Pa
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(Pa
.Guid
),Pa
.Arch
))
2157 Pa
.DataPipe
.dump(data_pipe_file
)
2159 autogen_rt
, errorcode
= self
.StartAutoGen(mqueue
, Pa
.DataPipe
, self
.SkipAutoGen
, PcdMaList
, cqueue
)
2162 self
.AutoGenMgr
.TerminateWorkers()
2163 self
.AutoGenMgr
.join(1)
2164 raise FatalError(errorcode
)
2166 if GlobalData
.gUseHashCache
:
2167 for item
in GlobalData
.gModuleAllCacheStatus
:
2168 (MetaFilePath
, Arch
, CacheStr
, Status
) = item
2169 Ma
= ModuleAutoGen(Wa
, PathClass(MetaFilePath
, Wa
), BuildTarget
,\
2170 ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2171 if CacheStr
== "PreMakeCache" and Status
== False:
2172 self
.PreMakeCacheMiss
.add(Ma
)
2173 if CacheStr
== "PreMakeCache" and Status
== True:
2174 self
.PreMakeCacheHit
.add(Ma
)
2175 GlobalData
.gModuleCacheHit
.add(Ma
)
2176 if CacheStr
== "MakeCache" and Status
== False:
2177 self
.MakeCacheMiss
.add(Ma
)
2178 if CacheStr
== "MakeCache" and Status
== True:
2179 self
.MakeCacheHit
.add(Ma
)
2180 GlobalData
.gModuleCacheHit
.add(Ma
)
2181 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
2182 AutoGenIdFile
= os
.path
.join(GlobalData
.gConfDirectory
,".AutoGenIdFile.txt")
2183 with
open(AutoGenIdFile
,"w") as fw
:
2184 fw
.write("Arch=%s\n" % "|".join((Wa
.ArchList
)))
2185 fw
.write("BuildDir=%s\n" % Wa
.BuildDir
)
2186 fw
.write("PlatformGuid=%s\n" % str(Wa
.AutoGenObjectList
[0].Guid
))
2188 if GlobalData
.gBinCacheSource
:
2189 BuildModules
.extend(self
.MakeCacheMiss
)
2190 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheDest
:
2191 BuildModules
.extend(self
.PreMakeCacheMiss
)
2193 BuildModules
.extend(self
.AllDrivers
)
2195 self
.Progress
.Stop("done!")
2196 return Wa
, BuildModules
2198 def _MultiThreadBuildPlatform(self
):
2199 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
2200 for BuildTarget
in self
.BuildTargetList
:
2201 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
2203 for ToolChain
in self
.ToolChainList
:
2204 resetFdsGlobalVariable()
2205 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
2206 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
2207 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
2209 ExitFlag
= threading
.Event()
2211 if self
.SkipAutoGen
:
2212 Wa
= self
.VerifyAutoGenFiles()
2214 self
.SkipAutoGen
= False
2215 Wa
, self
.BuildModules
= self
.PerformAutoGen(BuildTarget
,ToolChain
)
2217 GlobalData
.gAutoGenPhase
= True
2218 self
.BuildModules
= self
.SetupMakeSetting(Wa
)
2220 Wa
, self
.BuildModules
= self
.PerformAutoGen(BuildTarget
,ToolChain
)
2221 Pa
= Wa
.AutoGenObjectList
[0]
2222 GlobalData
.gAutoGenPhase
= False
2224 if GlobalData
.gBinCacheSource
:
2225 EdkLogger
.quiet("[cache Summary]: Total module num: %s" % len(self
.AllModules
))
2226 EdkLogger
.quiet("[cache Summary]: PreMakecache miss num: %s " % len(self
.PreMakeCacheMiss
))
2227 EdkLogger
.quiet("[cache Summary]: Makecache miss num: %s " % len(self
.MakeCacheMiss
))
2229 for Arch
in Wa
.ArchList
:
2230 MakeStart
= time
.time()
2231 for Ma
in set(self
.BuildModules
):
2232 # Generate build task for the module
2233 if not Ma
.IsBinaryModule
:
2234 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
2235 # Break build if any build thread has error
2236 if BuildTask
.HasError():
2237 # we need a full version of makefile for platform
2239 BuildTask
.WaitForComplete()
2240 Pa
.CreateMakeFile(False)
2241 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2242 # Start task scheduler
2243 if not BuildTask
.IsOnGoing():
2244 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
2246 # in case there's an interruption. we need a full version of makefile for platform
2248 if BuildTask
.HasError():
2249 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2250 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
2252 MakeContiue
= time
.time()
2255 # All modules have been put in build tasks queue. Tell task scheduler
2256 # to exit if all tasks are completed
2259 BuildTask
.WaitForComplete()
2260 self
.CreateAsBuiltInf()
2261 if GlobalData
.gBinCacheDest
:
2263 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
2265 # Update PreMakeCacheChain files
2266 self
.GenLocalPreMakeCache()
2270 ModuleList
= {ma
.Guid
.upper(): ma
for ma
in self
.BuildModules
}
2271 self
.BuildModules
= []
2272 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2274 # Check for build error, and raise exception if one
2275 # has been signaled.
2277 if BuildTask
.HasError():
2278 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2280 # Create MAP file when Load Fix Address is enabled.
2281 if self
.Target
in ["", "all", "fds"]:
2282 for Arch
in Wa
.ArchList
:
2284 # Check whether the set fix address is above 4G for 32bit image.
2286 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2287 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")
2290 # Rebase module to the preferred memory address before GenFds
2293 if self
.LoadFixAddress
!= 0:
2294 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2298 # Generate FD image if there's a FDF file found
2300 GenFdsStart
= time
.time()
2301 if GenFdsApi(Wa
.GenFdsCommandDict
, self
.Db
):
2302 EdkLogger
.error("build", COMMAND_FAILURE
)
2305 # Create MAP file for all platform FVs after GenFds.
2307 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2308 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2310 # Save MAP buffer into MAP file.
2312 self
._SaveMapFile
(MapBuffer
, Wa
)
2313 self
.CreateGuidedSectionToolsFile(Wa
)
2314 ## Generate GuidedSectionTools.txt in the FV directories.
2316 def CreateGuidedSectionToolsFile(self
,Wa
):
2317 for BuildTarget
in self
.BuildTargetList
:
2318 for ToolChain
in self
.ToolChainList
:
2320 if not os
.path
.exists(FvDir
):
2323 for Arch
in self
.ArchList
:
2324 # Build up the list of supported architectures for this build
2325 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
2327 # Look through the tool definitions for GUIDed tools
2329 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.items():
2330 if attrib
.upper().endswith('_GUID'):
2331 split
= attrib
.split('_')
2332 thisPrefix
= '_'.join(split
[0:3]) + '_'
2333 if thisPrefix
== prefix
:
2334 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
2337 path
= '_'.join(split
[0:4]) + '_PATH'
2338 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2339 path
= self
.GetFullPathOfTool(path
)
2340 guidAttribs
.append((guid
, toolName
, path
))
2342 # Write out GuidedSecTools.txt
2343 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2344 toolsFile
= open(toolsFile
, 'wt')
2345 for guidedSectionTool
in guidAttribs
:
2346 print(' '.join(guidedSectionTool
), file=toolsFile
)
2349 ## Returns the full path of the tool.
2351 def GetFullPathOfTool (self
, tool
):
2352 if os
.path
.exists(tool
):
2353 return os
.path
.realpath(tool
)
2355 # We need to search for the tool using the
2356 # PATH environment variable.
2357 for dirInPath
in os
.environ
['PATH'].split(os
.pathsep
):
2358 foundPath
= os
.path
.join(dirInPath
, tool
)
2359 if os
.path
.exists(foundPath
):
2360 return os
.path
.realpath(foundPath
)
2362 # If the tool was not found in the path then we just return
2366 ## Launch the module or platform build
2369 self
.AllDrivers
= set()
2370 self
.AllModules
= set()
2371 self
.PreMakeCacheMiss
= set()
2372 self
.PreMakeCacheHit
= set()
2373 self
.MakeCacheMiss
= set()
2374 self
.MakeCacheHit
= set()
2375 if not self
.ModuleFile
:
2376 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2377 self
.SpawnMode
= False
2378 self
._BuildPlatform
()
2380 self
._MultiThreadBuildPlatform
()
2382 self
.SpawnMode
= False
2385 if self
.Target
== 'cleanall':
2386 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2388 def CreateAsBuiltInf(self
):
2389 for Module
in self
.BuildModules
:
2390 Module
.CreateAsBuiltInf()
2392 def GenDestCache(self
):
2393 for Module
in self
.AllModules
:
2394 Module
.GenPreMakefileHashList()
2395 Module
.GenMakefileHashList()
2396 Module
.CopyModuleToCache()
2398 def GenLocalPreMakeCache(self
):
2399 for Module
in self
.PreMakeCacheMiss
:
2400 Module
.GenPreMakefileHashList()
2402 ## Do some clean-up works when error occurred
2403 def Relinquish(self
):
2404 OldLogLevel
= EdkLogger
.GetLevel()
2405 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2406 Utils
.Progressor
.Abort()
2407 if self
.SpawnMode
== True:
2409 EdkLogger
.SetLevel(OldLogLevel
)
2411 def ParseDefines(DefineList
=[]):
2413 if DefineList
is not None:
2414 for Define
in DefineList
:
2415 DefineTokenList
= Define
.split("=", 1)
2416 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2417 EdkLogger
.error('build', FORMAT_INVALID
,
2418 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2419 ExtraData
=DefineTokenList
[0])
2421 if len(DefineTokenList
) == 1:
2422 DefineDict
[DefineTokenList
[0]] = "TRUE"
2424 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2429 def LogBuildTime(Time
):
2432 TimeDur
= time
.gmtime(Time
)
2433 if TimeDur
.tm_yday
> 1:
2434 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2436 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2441 ThreadNumber
= BuildOption
.ThreadNumber
2442 if ThreadNumber
is None:
2443 ThreadNumber
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
2444 if ThreadNumber
== '':
2447 ThreadNumber
= int(ThreadNumber
, 0)
2449 if ThreadNumber
== 0:
2451 ThreadNumber
= multiprocessing
.cpu_count()
2452 except (ImportError, NotImplementedError):
2455 ## Tool entrance method
2457 # This method mainly dispatch specific methods per the command line options.
2458 # If no error found, return zero value so the caller of this tool can know
2459 # if it's executed successfully or not.
2461 # @retval 0 Tool was successful
2462 # @retval 1 Tool failed
2464 LogQMaxSize
= ThreadNum() * 10
2466 StartTime
= time
.time()
2469 # Create a log Queue
2471 LogQ
= mp
.Queue(LogQMaxSize
)
2472 # Initialize log system
2473 EdkLogger
.LogClientInitialize(LogQ
)
2474 GlobalData
.gCommand
= sys
.argv
[1:]
2476 # Parse the options and args
2478 Option
, Target
= BuildOption
, BuildTarget
2479 GlobalData
.gOptions
= Option
2480 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2483 LogLevel
= EdkLogger
.INFO
2484 if Option
.verbose
is not None:
2485 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2486 LogLevel
= EdkLogger
.VERBOSE
2487 elif Option
.quiet
is not None:
2488 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2489 LogLevel
= EdkLogger
.QUIET
2490 elif Option
.debug
is not None:
2491 EdkLogger
.SetLevel(Option
.debug
+ 1)
2492 LogLevel
= Option
.debug
+ 1
2494 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2496 if Option
.WarningAsError
== True:
2497 EdkLogger
.SetWarningAsError()
2498 Log_Agent
= LogAgent(LogQ
,LogLevel
,Option
.LogFile
)
2501 if platform
.platform().find("Windows") >= 0:
2502 GlobalData
.gIsWindows
= True
2504 GlobalData
.gIsWindows
= False
2506 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2507 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2512 if len(Target
) == 0:
2514 elif len(Target
) >= 2:
2515 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2516 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2518 Target
= Target
[0].lower()
2520 if Target
not in gSupportedTarget
:
2521 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2522 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2525 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2528 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2530 Workspace
= os
.getenv("WORKSPACE")
2532 # Get files real name in workspace dir
2534 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2536 WorkingDirectory
= os
.getcwd()
2537 if not Option
.ModuleFile
:
2538 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2539 FileNum
= len(FileList
)
2541 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2542 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2544 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2546 if Option
.ModuleFile
:
2547 if os
.path
.isabs (Option
.ModuleFile
):
2548 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2549 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2550 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2551 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2553 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2555 if Option
.PlatformFile
is not None:
2556 if os
.path
.isabs (Option
.PlatformFile
):
2557 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2558 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2559 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2561 if Option
.FdfFile
is not None:
2562 if os
.path
.isabs (Option
.FdfFile
):
2563 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2564 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2565 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2566 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2568 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2570 if Option
.Flag
is not None and Option
.Flag
not in ['-c', '-s']:
2571 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2573 MyBuild
= Build(Target
, Workspace
, Option
,LogQ
)
2574 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2575 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2579 # All job done, no error found and no exception raised
2582 except FatalError
as X
:
2583 if MyBuild
is not None:
2584 # for multi-thread build exits safely
2585 MyBuild
.Relinquish()
2586 if Option
is not None and Option
.debug
is not None:
2587 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2588 ReturnCode
= X
.args
[0]
2589 except Warning as X
:
2590 # error from Fdf parser
2591 if MyBuild
is not None:
2592 # for multi-thread build exits safely
2593 MyBuild
.Relinquish()
2594 if Option
is not None and Option
.debug
is not None:
2595 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2597 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2598 ReturnCode
= FORMAT_INVALID
2599 except KeyboardInterrupt:
2600 if MyBuild
is not None:
2602 # for multi-thread build exits safely
2603 MyBuild
.Relinquish()
2604 ReturnCode
= ABORT_ERROR
2605 if Option
is not None and Option
.debug
is not None:
2606 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2608 if MyBuild
is not None:
2609 # for multi-thread build exits safely
2610 MyBuild
.Relinquish()
2612 # try to get the meta-file from the object causing exception
2613 Tb
= sys
.exc_info()[-1]
2614 MetaFile
= GlobalData
.gProcessingFile
2615 while Tb
is not None:
2616 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2617 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2622 "Unknown fatal error when processing [%s]" % MetaFile
,
2623 ExtraData
="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR
,
2626 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2627 ReturnCode
= CODE_ERROR
2629 Utils
.Progressor
.Abort()
2630 Utils
.ClearDuplicatedInf()
2634 MyBuild
.LaunchPostbuild()
2637 Conclusion
= "Failed"
2638 elif ReturnCode
== ABORT_ERROR
:
2639 Conclusion
= "Aborted"
2641 Conclusion
= "Failed"
2642 FinishTime
= time
.time()
2643 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2644 BuildDurationStr
= ""
2645 if BuildDuration
.tm_yday
> 1:
2646 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2648 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2649 if MyBuild
is not None:
2651 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2653 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2654 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2655 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2656 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2661 if __name__
== '__main__':
2663 mp
.set_start_method('spawn')
2667 ## 0-127 is a safe return range, and 1 is a standard default error
2668 if r
< 0 or r
> 127: r
= 1