2 # build a platform or a module
4 # Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
5 # Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
6 # Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
8 # SPDX-License-Identifier: BSD-2-Clause-Patent
14 from __future__
import print_function
15 from __future__
import absolute_import
16 import os
.path
as path
24 import multiprocessing
25 from threading
import Thread
,Event
,BoundedSemaphore
27 from subprocess
import Popen
,PIPE
28 from collections
import OrderedDict
, defaultdict
29 from optparse
import OptionParser
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
46 from Common
.BuildVersion
import gBUILD_VERSION
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
58 # Version and Copyright
59 VersionNumber
= "0.60" + ' ' + gBUILD_VERSION
60 __version__
= "%prog Version " + VersionNumber
61 __copyright__
= "Copyright (c) 2007 - 2018, Intel Corporation All rights reserved."
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
):
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 To(Line
.rstrip().decode(encoding
='utf-8', errors
='ignore'))
191 ## Launch an external program
193 # This method will call subprocess.Popen to execute an external program with
194 # given options in specified directory. Because of the dead-lock issue during
195 # redirecting output of the external program, threads are used to to do the
198 # @param Command A list or string containing the call of the program
199 # @param WorkingDir The directory in which the program will be running
201 def LaunchCommand(Command
, WorkingDir
):
202 BeginTime
= time
.time()
203 # if working directory doesn't exist, Popen() will raise an exception
204 if not os
.path
.isdir(WorkingDir
):
205 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=WorkingDir
)
207 # Command is used as the first Argument in following Popen().
208 # It could be a string or sequence. We find that if command is a string in following Popen(),
209 # ubuntu may fail with an error message that the command is not found.
210 # So here we may need convert command from string to list instance.
211 if platform
.system() != 'Windows':
212 if not isinstance(Command
, list):
213 Command
= Command
.split()
214 Command
= ' '.join(Command
)
217 EndOfProcedure
= None
220 Proc
= Popen(Command
, stdout
=PIPE
, stderr
=PIPE
, env
=os
.environ
, cwd
=WorkingDir
, bufsize
=-1, shell
=True)
222 # launch two threads to read the STDOUT and STDERR
223 EndOfProcedure
= Event()
224 EndOfProcedure
.clear()
226 StdOutThread
= Thread(target
=ReadMessage
, args
=(Proc
.stdout
, EdkLogger
.info
, EndOfProcedure
))
227 StdOutThread
.setName("STDOUT-Redirector")
228 StdOutThread
.setDaemon(False)
232 StdErrThread
= Thread(target
=ReadMessage
, args
=(Proc
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
233 StdErrThread
.setName("STDERR-Redirector")
234 StdErrThread
.setDaemon(False)
237 # waiting for program exit
239 except: # in case of aborting
240 # terminate the threads redirecting the program output
241 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
242 if EndOfProcedure
is not None:
245 if not isinstance(Command
, type("")):
246 Command
= " ".join(Command
)
247 EdkLogger
.error("build", COMMAND_FAILURE
, "Failed to start command", ExtraData
="%s [%s]" % (Command
, WorkingDir
))
254 # check the return code of the program
255 if Proc
.returncode
!= 0:
256 if not isinstance(Command
, type("")):
257 Command
= " ".join(Command
)
258 # print out the Response file and its content when make failure
259 RespFile
= os
.path
.join(WorkingDir
, 'OUTPUT', 'respfilelist.txt')
260 if os
.path
.isfile(RespFile
):
262 RespContent
= f
.read()
264 EdkLogger
.info(RespContent
)
266 EdkLogger
.error("build", COMMAND_FAILURE
, ExtraData
="%s [%s]" % (Command
, WorkingDir
))
267 return "%dms" % (int(round((time
.time() - BeginTime
) * 1000)))
269 ## The smallest unit that can be built in multi-thread build mode
271 # This is the base class of build unit. The "Obj" parameter must provide
272 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
275 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
280 # @param self The object pointer
281 # @param Obj The object the build is working on
282 # @param Target The build target name, one of gSupportedTarget
283 # @param Dependency The BuildUnit(s) which must be completed in advance
284 # @param WorkingDir The directory build command starts in
286 def __init__(self
, Obj
, BuildCommand
, Target
, Dependency
, WorkingDir
="."):
287 self
.BuildObject
= Obj
288 self
.Dependency
= Dependency
289 self
.WorkingDir
= WorkingDir
291 self
.BuildCommand
= BuildCommand
293 EdkLogger
.error("build", OPTION_MISSING
,
294 "No build command found for this module. "
295 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
296 (Obj
.BuildTarget
, Obj
.ToolChain
, Obj
.Arch
),
302 # It just returns the string representation of self.BuildObject
304 # @param self The object pointer
307 return str(self
.BuildObject
)
309 ## "==" operator method
311 # It just compares self.BuildObject with "Other". So self.BuildObject must
312 # provide its own __eq__() method.
314 # @param self The object pointer
315 # @param Other The other BuildUnit object compared to
317 def __eq__(self
, Other
):
318 return Other
and self
.BuildObject
== Other
.BuildObject \
319 and Other
.BuildObject \
320 and self
.BuildObject
.Arch
== Other
.BuildObject
.Arch
324 # It just returns the hash value of self.BuildObject which must be hashable.
326 # @param self The object pointer
329 return hash(self
.BuildObject
) + hash(self
.BuildObject
.Arch
)
332 return repr(self
.BuildObject
)
334 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
336 # This class is for module build by nmake/make build system. The "Obj" parameter
337 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
338 # be make units missing build.
340 # Currently the "Obj" should be only ModuleAutoGen object.
342 class ModuleMakeUnit(BuildUnit
):
345 # @param self The object pointer
346 # @param Obj The ModuleAutoGen object the build is working on
347 # @param Target The build target name, one of gSupportedTarget
349 def __init__(self
, Obj
, BuildCommand
,Target
):
350 Dependency
= [ModuleMakeUnit(La
, BuildCommand
,Target
) for La
in Obj
.LibraryAutoGenList
]
351 BuildUnit
.__init
__(self
, Obj
, BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
352 if Target
in [None, "", "all"]:
353 self
.Target
= "tbuild"
355 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
357 # This class is for platform build by nmake/make build system. The "Obj" parameter
358 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
359 # be make units missing build.
361 # Currently the "Obj" should be only PlatformAutoGen object.
363 class PlatformMakeUnit(BuildUnit
):
366 # @param self The object pointer
367 # @param Obj The PlatformAutoGen object the build is working on
368 # @param Target The build target name, one of gSupportedTarget
370 def __init__(self
, Obj
, BuildCommand
, Target
):
371 Dependency
= [ModuleMakeUnit(Lib
, BuildCommand
, Target
) for Lib
in self
.BuildObject
.LibraryAutoGenList
]
372 Dependency
.extend([ModuleMakeUnit(Mod
, BuildCommand
,Target
) for Mod
in self
.BuildObject
.ModuleAutoGenList
])
373 BuildUnit
.__init
__(self
, Obj
, BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
375 ## The class representing the task of a module build or platform build
377 # This class manages the build tasks in multi-thread build mode. Its jobs include
378 # scheduling thread running, catching thread error, monitor the thread status, etc.
381 # queue for tasks waiting for schedule
382 _PendingQueue
= OrderedDict()
383 _PendingQueueLock
= threading
.Lock()
385 # queue for tasks ready for running
386 _ReadyQueue
= OrderedDict()
387 _ReadyQueueLock
= threading
.Lock()
389 # queue for run tasks
390 _RunningQueue
= OrderedDict()
391 _RunningQueueLock
= threading
.Lock()
393 # queue containing all build tasks, in case duplicate build
394 _TaskQueue
= OrderedDict()
396 # flag indicating error occurs in a running thread
397 _ErrorFlag
= threading
.Event()
401 # BoundedSemaphore object used to control the number of running threads
404 # flag indicating if the scheduler is started or not
405 _SchedulerStopped
= threading
.Event()
406 _SchedulerStopped
.set()
408 ## Start the task scheduler thread
410 # @param MaxThreadNumber The maximum thread number
411 # @param ExitFlag Flag used to end the scheduler
414 def StartScheduler(MaxThreadNumber
, ExitFlag
):
415 SchedulerThread
= Thread(target
=BuildTask
.Scheduler
, args
=(MaxThreadNumber
, ExitFlag
))
416 SchedulerThread
.setName("Build-Task-Scheduler")
417 SchedulerThread
.setDaemon(False)
418 SchedulerThread
.start()
419 # wait for the scheduler to be started, especially useful in Linux
420 while not BuildTask
.IsOnGoing():
425 # @param MaxThreadNumber The maximum thread number
426 # @param ExitFlag Flag used to end the scheduler
429 def Scheduler(MaxThreadNumber
, ExitFlag
):
430 BuildTask
._SchedulerStopped
.clear()
432 # use BoundedSemaphore to control the maximum running threads
433 BuildTask
._Thread
= BoundedSemaphore(MaxThreadNumber
)
435 # scheduling loop, which will exits when no pending/ready task and
436 # indicated to do so, or there's error in running thread
438 while (len(BuildTask
._PendingQueue
) > 0 or len(BuildTask
._ReadyQueue
) > 0 \
439 or not ExitFlag
.isSet()) and not BuildTask
._ErrorFlag
.isSet():
440 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Pending Queue (%d), Ready Queue (%d)"
441 % (len(BuildTask
._PendingQueue
), len(BuildTask
._ReadyQueue
)))
443 # get all pending tasks
444 BuildTask
._PendingQueueLock
.acquire()
445 BuildObjectList
= list(BuildTask
._PendingQueue
.keys())
447 # check if their dependency is resolved, and if true, move them
450 for BuildObject
in BuildObjectList
:
451 Bt
= BuildTask
._PendingQueue
[BuildObject
]
453 BuildTask
._ReadyQueue
[BuildObject
] = BuildTask
._PendingQueue
.pop(BuildObject
)
454 BuildTask
._PendingQueueLock
.release()
456 # launch build thread until the maximum number of threads is reached
457 while not BuildTask
._ErrorFlag
.isSet():
458 # empty ready queue, do nothing further
459 if len(BuildTask
._ReadyQueue
) == 0:
462 # wait for active thread(s) exit
463 BuildTask
._Thread
.acquire(True)
465 # start a new build thread
466 Bo
, Bt
= BuildTask
._ReadyQueue
.popitem()
468 # move into running queue
469 BuildTask
._RunningQueueLock
.acquire()
470 BuildTask
._RunningQueue
[Bo
] = Bt
471 BuildTask
._RunningQueueLock
.release()
480 # wait for all running threads exit
481 if BuildTask
._ErrorFlag
.isSet():
482 EdkLogger
.quiet("\nWaiting for all build threads exit...")
483 # while not BuildTask._ErrorFlag.isSet() and \
484 while len(BuildTask
._RunningQueue
) > 0:
485 EdkLogger
.verbose("Waiting for thread ending...(%d)" % len(BuildTask
._RunningQueue
))
486 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Threads [%s]" % ", ".join(Th
.getName() for Th
in threading
.enumerate()))
489 except BaseException
as X
:
491 # TRICK: hide the output of threads left running, so that the user can
492 # catch the error message easily
494 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
495 BuildTask
._ErrorFlag
.set()
496 BuildTask
._ErrorMessage
= "build thread scheduler error\n\t%s" % str(X
)
498 BuildTask
._PendingQueue
.clear()
499 BuildTask
._ReadyQueue
.clear()
500 BuildTask
._RunningQueue
.clear()
501 BuildTask
._TaskQueue
.clear()
502 BuildTask
._SchedulerStopped
.set()
504 ## Wait for all running method exit
507 def WaitForComplete():
508 BuildTask
._SchedulerStopped
.wait()
510 ## Check if the scheduler is running or not
514 return not BuildTask
._SchedulerStopped
.isSet()
519 if BuildTask
.IsOnGoing():
520 BuildTask
._ErrorFlag
.set()
521 BuildTask
.WaitForComplete()
523 ## Check if there's error in running thread
525 # Since the main thread cannot catch exceptions in other thread, we have to
526 # use threading.Event to communicate this formation to main thread.
530 return BuildTask
._ErrorFlag
.isSet()
532 ## Get error message in running thread
534 # Since the main thread cannot catch exceptions in other thread, we have to
535 # use a static variable to communicate this message to main thread.
538 def GetErrorMessage():
539 return BuildTask
._ErrorMessage
541 ## Factory method to create a BuildTask object
543 # This method will check if a module is building or has been built. And if
544 # true, just return the associated BuildTask object in the _TaskQueue. If
545 # not, create and return a new BuildTask object. The new BuildTask object
546 # will be appended to the _PendingQueue for scheduling later.
548 # @param BuildItem A BuildUnit object representing a build object
549 # @param Dependency The dependent build object of BuildItem
552 def New(BuildItem
, Dependency
=None):
553 if BuildItem
in BuildTask
._TaskQueue
:
554 Bt
= BuildTask
._TaskQueue
[BuildItem
]
558 Bt
._Init
(BuildItem
, Dependency
)
559 BuildTask
._TaskQueue
[BuildItem
] = Bt
561 BuildTask
._PendingQueueLock
.acquire()
562 BuildTask
._PendingQueue
[BuildItem
] = Bt
563 BuildTask
._PendingQueueLock
.release()
567 ## The real constructor of BuildTask
569 # @param BuildItem A BuildUnit object representing a build object
570 # @param Dependency The dependent build object of BuildItem
572 def _Init(self
, BuildItem
, Dependency
=None):
573 self
.BuildItem
= BuildItem
575 self
.DependencyList
= []
576 if Dependency
is None:
577 Dependency
= BuildItem
.Dependency
579 Dependency
.extend(BuildItem
.Dependency
)
580 self
.AddDependency(Dependency
)
581 # flag indicating build completes, used to avoid unnecessary re-build
582 self
.CompleteFlag
= False
584 ## Check if all dependent build tasks are completed or not
588 for Dep
in self
.DependencyList
:
589 if Dep
.CompleteFlag
== True:
596 ## Add dependent build task
598 # @param Dependency The list of dependent build objects
600 def AddDependency(self
, Dependency
):
601 for Dep
in Dependency
:
602 if not Dep
.BuildObject
.IsBinaryModule
and not Dep
.BuildObject
.CanSkipbyHash():
603 self
.DependencyList
.append(BuildTask
.New(Dep
)) # BuildTask list
605 ## The thread wrapper of LaunchCommand function
607 # @param Command A list or string contains the call of the command
608 # @param WorkingDir The directory in which the program will be running
610 def _CommandThread(self
, Command
, WorkingDir
):
612 self
.BuildItem
.BuildObject
.BuildTime
= LaunchCommand(Command
, WorkingDir
)
613 self
.CompleteFlag
= True
615 # Run hash operation post dependency, to account for libs
616 if GlobalData
.gUseHashCache
and self
.BuildItem
.BuildObject
.IsLibrary
:
617 HashFile
= path
.join(self
.BuildItem
.BuildObject
.BuildDir
, self
.BuildItem
.BuildObject
.Name
+ ".hash")
618 SaveFileOnChange(HashFile
, self
.BuildItem
.BuildObject
.GenModuleHash(), True)
621 # TRICK: hide the output of threads left running, so that the user can
622 # catch the error message easily
624 if not BuildTask
._ErrorFlag
.isSet():
625 GlobalData
.gBuildingModule
= "%s [%s, %s, %s]" % (str(self
.BuildItem
.BuildObject
),
626 self
.BuildItem
.BuildObject
.Arch
,
627 self
.BuildItem
.BuildObject
.ToolChain
,
628 self
.BuildItem
.BuildObject
.BuildTarget
630 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
631 BuildTask
._ErrorFlag
.set()
632 BuildTask
._ErrorMessage
= "%s broken\n %s [%s]" % \
633 (threading
.currentThread().getName(), Command
, WorkingDir
)
635 # Set the value used by hash invalidation flow in GlobalData.gModuleBuildTracking to 'SUCCESS'
636 # If Module or Lib is being tracked, it did not fail header check test, and built successfully
637 if (self
.BuildItem
.BuildObject
.Arch
in GlobalData
.gModuleBuildTracking
and
638 self
.BuildItem
.BuildObject
in GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
.Arch
] and
639 GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
.Arch
][self
.BuildItem
.BuildObject
] != 'FAIL_METAFILE' and
640 not BuildTask
._ErrorFlag
.isSet()
642 GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
.Arch
][self
.BuildItem
.BuildObject
] = 'SUCCESS'
644 # indicate there's a thread is available for another build task
645 BuildTask
._RunningQueueLock
.acquire()
646 BuildTask
._RunningQueue
.pop(self
.BuildItem
)
647 BuildTask
._RunningQueueLock
.release()
648 BuildTask
._Thread
.release()
650 ## Start build task thread
653 EdkLogger
.quiet("Building ... %s" % repr(self
.BuildItem
))
654 Command
= self
.BuildItem
.BuildCommand
+ [self
.BuildItem
.Target
]
655 self
.BuildTread
= Thread(target
=self
._CommandThread
, args
=(Command
, self
.BuildItem
.WorkingDir
))
656 self
.BuildTread
.setName("build thread")
657 self
.BuildTread
.setDaemon(False)
658 self
.BuildTread
.start()
660 ## The class contains the information related to EFI image
665 # Constructor will load all required image information.
667 # @param BaseName The full file path of image.
668 # @param Guid The GUID for image.
669 # @param Arch Arch of this image.
670 # @param OutputDir The output directory for image.
671 # @param DebugDir The debug directory for image.
672 # @param ImageClass PeImage Information
674 def __init__(self
, BaseName
, Guid
, Arch
, OutputDir
, DebugDir
, ImageClass
):
675 self
.BaseName
= BaseName
678 self
.OutputDir
= OutputDir
679 self
.DebugDir
= DebugDir
680 self
.Image
= ImageClass
681 self
.Image
.Size
= (self
.Image
.Size
// 0x1000 + 1) * 0x1000
683 ## The class implementing the EDK2 build process
685 # The build process includes:
686 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
687 # 2. Parse DSC file of active platform
688 # 3. Parse FDF file if any
689 # 4. Establish build database, including parse all other files (module, package)
690 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
691 # 6. Call build command
696 # Constructor will load all necessary configurations, parse platform, modules
697 # and packages and the establish a database for AutoGen.
699 # @param Target The build command target, one of gSupportedTarget
700 # @param WorkspaceDir The directory of workspace
701 # @param BuildOptions Build options passed from command line
703 def __init__(self
, Target
, WorkspaceDir
, BuildOptions
,log_q
):
704 self
.WorkspaceDir
= WorkspaceDir
706 self
.PlatformFile
= BuildOptions
.PlatformFile
707 self
.ModuleFile
= BuildOptions
.ModuleFile
708 self
.ArchList
= BuildOptions
.TargetArch
709 self
.ToolChainList
= BuildOptions
.ToolChain
710 self
.BuildTargetList
= BuildOptions
.BuildTarget
711 self
.Fdf
= BuildOptions
.FdfFile
712 self
.FdList
= BuildOptions
.RomImage
713 self
.FvList
= BuildOptions
.FvImage
714 self
.CapList
= BuildOptions
.CapName
715 self
.SilentMode
= BuildOptions
.SilentMode
716 self
.ThreadNumber
= BuildOptions
.ThreadNumber
717 self
.SkipAutoGen
= BuildOptions
.SkipAutoGen
718 self
.Reparse
= BuildOptions
.Reparse
719 self
.SkuId
= BuildOptions
.SkuId
721 GlobalData
.gSKUID_CMD
= self
.SkuId
722 self
.ConfDirectory
= BuildOptions
.ConfDirectory
723 self
.SpawnMode
= True
724 self
.BuildReport
= BuildReport(BuildOptions
.ReportFile
, BuildOptions
.ReportType
)
725 self
.TargetTxt
= TargetTxt
726 self
.ToolDef
= ToolDef
730 GlobalData
.BuildOptionPcd
= BuildOptions
.OptionPcd
if BuildOptions
.OptionPcd
else []
731 #Set global flag for build mode
732 GlobalData
.gIgnoreSource
= BuildOptions
.IgnoreSources
733 GlobalData
.gUseHashCache
= BuildOptions
.UseHashCache
734 GlobalData
.gBinCacheDest
= BuildOptions
.BinCacheDest
735 GlobalData
.gBinCacheSource
= BuildOptions
.BinCacheSource
736 GlobalData
.gEnableGenfdsMultiThread
= BuildOptions
.GenfdsMultiThread
737 GlobalData
.gDisableIncludePathCheck
= BuildOptions
.DisableIncludePathCheck
739 if GlobalData
.gBinCacheDest
and not GlobalData
.gUseHashCache
:
740 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination must be used together with --hash.")
742 if GlobalData
.gBinCacheSource
and not GlobalData
.gUseHashCache
:
743 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-source must be used together with --hash.")
745 if GlobalData
.gBinCacheDest
and GlobalData
.gBinCacheSource
:
746 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination can not be used together with --binary-source.")
748 if GlobalData
.gBinCacheSource
:
749 BinCacheSource
= os
.path
.normpath(GlobalData
.gBinCacheSource
)
750 if not os
.path
.isabs(BinCacheSource
):
751 BinCacheSource
= mws
.join(self
.WorkspaceDir
, BinCacheSource
)
752 GlobalData
.gBinCacheSource
= BinCacheSource
754 if GlobalData
.gBinCacheSource
is not None:
755 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-source.")
757 if GlobalData
.gBinCacheDest
:
758 BinCacheDest
= os
.path
.normpath(GlobalData
.gBinCacheDest
)
759 if not os
.path
.isabs(BinCacheDest
):
760 BinCacheDest
= mws
.join(self
.WorkspaceDir
, BinCacheDest
)
761 GlobalData
.gBinCacheDest
= BinCacheDest
763 if GlobalData
.gBinCacheDest
is not None:
764 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-destination.")
766 if self
.ConfDirectory
:
767 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
768 ConfDirectoryPath
= os
.path
.normpath(self
.ConfDirectory
)
770 if not os
.path
.isabs(ConfDirectoryPath
):
771 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
772 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
773 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, ConfDirectoryPath
)
775 if "CONF_PATH" in os
.environ
:
776 ConfDirectoryPath
= os
.path
.normcase(os
.path
.normpath(os
.environ
["CONF_PATH"]))
778 # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf
779 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, 'Conf')
780 GlobalData
.gConfDirectory
= ConfDirectoryPath
781 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
782 if not os
.path
.exists(os
.path
.join(GlobalData
.gConfDirectory
, '.cache')):
783 os
.makedirs(os
.path
.join(GlobalData
.gConfDirectory
, '.cache'))
785 self
.BuildDatabase
= self
.Db
.BuildObject
787 self
.ToolChainFamily
= None
788 self
.LoadFixAddress
= 0
789 self
.UniFlag
= BuildOptions
.Flag
790 self
.BuildModules
= []
791 self
.HashSkipModules
= []
793 self
.LaunchPrebuildFlag
= False
794 self
.PlatformBuildPath
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PlatformBuild')
795 if BuildOptions
.CommandLength
:
796 GlobalData
.gCommandMaxLength
= BuildOptions
.CommandLength
798 # print dot character during doing some time-consuming work
799 self
.Progress
= Utils
.Progressor()
800 # print current build environment and configuration
801 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
802 if "PACKAGES_PATH" in os
.environ
:
803 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
804 EdkLogger
.quiet("%-16s = %s" % ("PACKAGES_PATH", os
.path
.normcase(os
.path
.normpath(os
.environ
["PACKAGES_PATH"]))))
805 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
806 if "EDK_TOOLS_BIN" in os
.environ
:
807 # Print the same path style with WORKSPACE env.
808 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_TOOLS_BIN"]))))
809 EdkLogger
.quiet("%-16s = %s" % ("CONF_PATH", GlobalData
.gConfDirectory
))
810 if "PYTHON3_ENABLE" in os
.environ
:
811 PYTHON3_ENABLE
= os
.environ
["PYTHON3_ENABLE"]
812 if PYTHON3_ENABLE
!= "TRUE":
813 PYTHON3_ENABLE
= "FALSE"
814 EdkLogger
.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE
))
815 if "PYTHON_COMMAND" in os
.environ
:
816 EdkLogger
.quiet("%-16s = %s" % ("PYTHON_COMMAND", os
.environ
["PYTHON_COMMAND"]))
820 EdkLogger
.quiet("%-16s = %s" % ("PREBUILD", self
.Prebuild
))
822 EdkLogger
.quiet("%-16s = %s" % ("POSTBUILD", self
.Postbuild
))
824 self
.LaunchPrebuild()
825 self
.TargetTxt
= TargetTxt
826 self
.ToolDef
= ToolDef
827 if not (self
.LaunchPrebuildFlag
and os
.path
.exists(self
.PlatformBuildPath
)):
830 self
.AutoGenMgr
= None
832 os
.chdir(self
.WorkspaceDir
)
833 self
.share_data
= Manager().dict()
835 def StartAutoGen(self
,mqueue
, DataPipe
,SkipAutoGen
,PcdMaList
,share_data
):
839 feedback_q
= mp
.Queue()
840 file_lock
= mp
.Lock()
841 error_event
= mp
.Event()
842 auto_workers
= [AutoGenWorkerInProcess(mqueue
,DataPipe
.dump_file
,feedback_q
,file_lock
,share_data
,self
.log_q
,error_event
) for _
in range(self
.ThreadNumber
)]
843 self
.AutoGenMgr
= AutoGenManager(auto_workers
,feedback_q
,error_event
)
844 self
.AutoGenMgr
.start()
845 for w
in auto_workers
:
847 if PcdMaList
is not None:
848 for PcdMa
in PcdMaList
:
849 PcdMa
.CreateCodeFile(False)
850 PcdMa
.CreateMakeFile(False,GenFfsList
= DataPipe
.Get("FfsCommand").get((PcdMa
.MetaFile
.File
, PcdMa
.Arch
),[]))
852 self
.AutoGenMgr
.join()
853 rt
= self
.AutoGenMgr
.Status
855 except Exception as e
:
856 return False,e
.errcode
858 ## Load configuration
860 # This method will parse target.txt and get the build configurations.
862 def LoadConfiguration(self
):
864 # if no ARCH given in command line, get it from target.txt
865 if not self
.ArchList
:
866 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET_ARCH
]
867 self
.ArchList
= tuple(self
.ArchList
)
869 # if no build target given in command line, get it from target.txt
870 if not self
.BuildTargetList
:
871 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
873 # if no tool chain given in command line, get it from target.txt
874 if not self
.ToolChainList
:
875 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
876 if self
.ToolChainList
is None or len(self
.ToolChainList
) == 0:
877 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
879 # check if the tool chains are defined or not
880 NewToolChainList
= []
881 for ToolChain
in self
.ToolChainList
:
882 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
883 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
885 NewToolChainList
.append(ToolChain
)
886 # if no tool chain available, break the build
887 if len(NewToolChainList
) == 0:
888 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
889 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
891 self
.ToolChainList
= NewToolChainList
894 ToolDefinition
= self
.ToolDef
.ToolsDefTxtDatabase
895 for Tool
in self
.ToolChainList
:
896 if TAB_TOD_DEFINES_FAMILY
not in ToolDefinition
or Tool
not in ToolDefinition
[TAB_TOD_DEFINES_FAMILY
] \
897 or not ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
]:
898 EdkLogger
.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool
)
899 ToolChainFamily
.append(TAB_COMPILER_MSFT
)
901 ToolChainFamily
.append(ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
])
902 self
.ToolChainFamily
= ToolChainFamily
904 if self
.ThreadNumber
is None:
905 self
.ThreadNumber
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
906 if self
.ThreadNumber
== '':
907 self
.ThreadNumber
= 0
909 self
.ThreadNumber
= int(self
.ThreadNumber
, 0)
911 if self
.ThreadNumber
== 0:
913 self
.ThreadNumber
= multiprocessing
.cpu_count()
914 except (ImportError, NotImplementedError):
915 self
.ThreadNumber
= 1
917 if not self
.PlatformFile
:
918 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
920 # Try to find one in current directory
921 WorkingDirectory
= os
.getcwd()
922 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
923 FileNum
= len(FileList
)
925 EdkLogger
.error("build", OPTION_MISSING
,
926 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
928 PlatformFile
= FileList
[0]
930 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
931 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
933 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
935 ## Initialize build configuration
937 # This method will parse DSC file and merge the configurations from
938 # command line and target.txt, then get the final build configurations.
941 # parse target.txt, tools_def.txt, and platform file
942 self
.LoadConfiguration()
944 # Allow case-insensitive for those from command line or configuration file
945 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
947 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
950 def InitPreBuild(self
):
951 self
.LoadConfiguration()
952 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
954 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
955 if self
.BuildTargetList
:
956 GlobalData
.gGlobalDefines
['TARGET'] = self
.BuildTargetList
[0]
958 GlobalData
.gGlobalDefines
['ARCH'] = self
.ArchList
[0]
959 if self
.ToolChainList
:
960 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = self
.ToolChainList
[0]
961 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = self
.ToolChainList
[0]
962 if self
.ToolChainFamily
:
963 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[0]
964 if 'PREBUILD' in GlobalData
.gCommandLineDefines
:
965 self
.Prebuild
= GlobalData
.gCommandLineDefines
.get('PREBUILD')
968 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
969 self
.Prebuild
= str(Platform
.Prebuild
)
973 # Evaluate all arguments and convert arguments that are WORKSPACE
974 # relative paths to absolute paths. Filter arguments that look like
975 # flags or do not follow the file/dir naming rules to avoid false
976 # positives on this conversion.
978 for Arg
in self
.Prebuild
.split():
980 # Do not modify Arg if it looks like a flag or an absolute file path
982 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
983 PrebuildList
.append(Arg
)
986 # Do not modify Arg if it does not look like a Workspace relative
987 # path that starts with a valid package directory name
989 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
990 PrebuildList
.append(Arg
)
993 # If Arg looks like a WORKSPACE relative path, then convert to an
994 # absolute path and check to see if the file exists.
996 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
997 if os
.path
.isfile(Temp
):
999 PrebuildList
.append(Arg
)
1000 self
.Prebuild
= ' '.join(PrebuildList
)
1001 self
.Prebuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1003 def InitPostBuild(self
):
1004 if 'POSTBUILD' in GlobalData
.gCommandLineDefines
:
1005 self
.Postbuild
= GlobalData
.gCommandLineDefines
.get('POSTBUILD')
1007 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
1008 self
.Postbuild
= str(Platform
.Postbuild
)
1012 # Evaluate all arguments and convert arguments that are WORKSPACE
1013 # relative paths to absolute paths. Filter arguments that look like
1014 # flags or do not follow the file/dir naming rules to avoid false
1015 # positives on this conversion.
1017 for Arg
in self
.Postbuild
.split():
1019 # Do not modify Arg if it looks like a flag or an absolute file path
1021 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1022 PostbuildList
.append(Arg
)
1025 # Do not modify Arg if it does not look like a Workspace relative
1026 # path that starts with a valid package directory name
1028 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1029 PostbuildList
.append(Arg
)
1032 # If Arg looks like a WORKSPACE relative path, then convert to an
1033 # absolute path and check to see if the file exists.
1035 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1036 if os
.path
.isfile(Temp
):
1038 PostbuildList
.append(Arg
)
1039 self
.Postbuild
= ' '.join(PostbuildList
)
1040 self
.Postbuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1042 def PassCommandOption(self
, BuildTarget
, TargetArch
, ToolChain
, PlatformFile
, Target
):
1044 if GlobalData
.gCommand
and isinstance(GlobalData
.gCommand
, list):
1045 BuildStr
+= ' ' + ' '.join(GlobalData
.gCommand
)
1048 ToolChainFlag
= False
1049 PlatformFileFlag
= False
1051 if GlobalData
.gOptions
and not GlobalData
.gOptions
.BuildTarget
:
1053 if GlobalData
.gOptions
and not GlobalData
.gOptions
.TargetArch
:
1055 if GlobalData
.gOptions
and not GlobalData
.gOptions
.ToolChain
:
1056 ToolChainFlag
= True
1057 if GlobalData
.gOptions
and not GlobalData
.gOptions
.PlatformFile
:
1058 PlatformFileFlag
= True
1060 if TargetFlag
and BuildTarget
:
1061 if isinstance(BuildTarget
, list) or isinstance(BuildTarget
, tuple):
1062 BuildStr
+= ' -b ' + ' -b '.join(BuildTarget
)
1063 elif isinstance(BuildTarget
, str):
1064 BuildStr
+= ' -b ' + BuildTarget
1065 if ArchFlag
and TargetArch
:
1066 if isinstance(TargetArch
, list) or isinstance(TargetArch
, tuple):
1067 BuildStr
+= ' -a ' + ' -a '.join(TargetArch
)
1068 elif isinstance(TargetArch
, str):
1069 BuildStr
+= ' -a ' + TargetArch
1070 if ToolChainFlag
and ToolChain
:
1071 if isinstance(ToolChain
, list) or isinstance(ToolChain
, tuple):
1072 BuildStr
+= ' -t ' + ' -t '.join(ToolChain
)
1073 elif isinstance(ToolChain
, str):
1074 BuildStr
+= ' -t ' + ToolChain
1075 if PlatformFileFlag
and PlatformFile
:
1076 if isinstance(PlatformFile
, list) or isinstance(PlatformFile
, tuple):
1077 BuildStr
+= ' -p ' + ' -p '.join(PlatformFile
)
1078 elif isinstance(PlatformFile
, str):
1079 BuildStr
+= ' -p' + PlatformFile
1080 BuildStr
+= ' --conf=' + GlobalData
.gConfDirectory
1082 BuildStr
+= ' ' + Target
1086 def LaunchPrebuild(self
):
1088 EdkLogger
.info("\n- Prebuild Start -\n")
1089 self
.LaunchPrebuildFlag
= True
1091 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1092 # and preserve them for the rest of the main build step, because the child process environment will
1093 # evaporate as soon as it exits, we cannot get it in build step.
1095 PrebuildEnvFile
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PrebuildEnv')
1096 if os
.path
.isfile(PrebuildEnvFile
):
1097 os
.remove(PrebuildEnvFile
)
1098 if os
.path
.isfile(self
.PlatformBuildPath
):
1099 os
.remove(self
.PlatformBuildPath
)
1100 if sys
.platform
== "win32":
1101 args
= ' && '.join((self
.Prebuild
, 'set > ' + PrebuildEnvFile
))
1102 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1104 args
= ' && '.join((self
.Prebuild
, 'env > ' + PrebuildEnvFile
))
1105 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1107 # launch two threads to read the STDOUT and STDERR
1108 EndOfProcedure
= Event()
1109 EndOfProcedure
.clear()
1111 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1112 StdOutThread
.setName("STDOUT-Redirector")
1113 StdOutThread
.setDaemon(False)
1114 StdOutThread
.start()
1117 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1118 StdErrThread
.setName("STDERR-Redirector")
1119 StdErrThread
.setDaemon(False)
1120 StdErrThread
.start()
1121 # waiting for program exit
1128 if Process
.returncode
!= 0 :
1129 EdkLogger
.error("Prebuild", PREBUILD_ERROR
, 'Prebuild process is not success!')
1131 if os
.path
.exists(PrebuildEnvFile
):
1132 f
= open(PrebuildEnvFile
)
1133 envs
= f
.readlines()
1135 envs
= [l
.split("=", 1) for l
in envs
]
1136 envs
= [[I
.strip() for I
in item
] for item
in envs
if len(item
) == 2]
1137 os
.environ
.update(dict(envs
))
1138 EdkLogger
.info("\n- Prebuild Done -\n")
1140 def LaunchPostbuild(self
):
1142 EdkLogger
.info("\n- Postbuild Start -\n")
1143 if sys
.platform
== "win32":
1144 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1146 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1147 # launch two threads to read the STDOUT and STDERR
1148 EndOfProcedure
= Event()
1149 EndOfProcedure
.clear()
1151 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1152 StdOutThread
.setName("STDOUT-Redirector")
1153 StdOutThread
.setDaemon(False)
1154 StdOutThread
.start()
1157 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1158 StdErrThread
.setName("STDERR-Redirector")
1159 StdErrThread
.setDaemon(False)
1160 StdErrThread
.start()
1161 # waiting for program exit
1168 if Process
.returncode
!= 0 :
1169 EdkLogger
.error("Postbuild", POSTBUILD_ERROR
, 'Postbuild process is not success!')
1170 EdkLogger
.info("\n- Postbuild Done -\n")
1172 ## Error handling for hash feature
1174 # On BuildTask error, iterate through the Module Build tracking
1175 # dictionary to determine wheather a module failed to build. Invalidate
1176 # the hash associated with that module by removing it from storage.
1179 def invalidateHash(self
):
1180 # Only for hashing feature
1181 if not GlobalData
.gUseHashCache
:
1184 # GlobalData.gModuleBuildTracking contains only modules or libs that cannot be skipped by hash
1185 for moduleAutoGenObjArch
in GlobalData
.gModuleBuildTracking
.keys():
1186 for moduleAutoGenObj
in GlobalData
.gModuleBuildTracking
[moduleAutoGenObjArch
].keys():
1187 # Skip invalidating for Successful Module/Lib builds
1188 if GlobalData
.gModuleBuildTracking
[moduleAutoGenObjArch
][moduleAutoGenObj
] == 'SUCCESS':
1191 # The module failed to build, failed to start building, or failed the header check test from this point on
1193 # Remove .hash from build
1194 ModuleHashFile
= os
.path
.join(moduleAutoGenObj
.BuildDir
, moduleAutoGenObj
.Name
+ ".hash")
1195 if os
.path
.exists(ModuleHashFile
):
1196 os
.remove(ModuleHashFile
)
1198 # Remove .hash file from cache
1199 if GlobalData
.gBinCacheDest
:
1200 FileDir
= os
.path
.join(GlobalData
.gBinCacheDest
, moduleAutoGenObj
.Arch
, moduleAutoGenObj
.SourceDir
, moduleAutoGenObj
.MetaFile
.BaseName
)
1201 HashFile
= os
.path
.join(FileDir
, moduleAutoGenObj
.Name
+ '.hash')
1202 if os
.path
.exists(HashFile
):
1205 ## Build a module or platform
1207 # Create autogen code and makefile for a module or platform, and the launch
1208 # "make" command to build it
1210 # @param Target The target of build command
1211 # @param Platform The platform file
1212 # @param Module The module file
1213 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1214 # @param ToolChain The name of toolchain to build
1215 # @param Arch The arch of the module/platform
1216 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1217 # for dependent modules/Libraries
1218 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1219 # for dependent modules/Libraries
1221 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False, FfsCommand
=None, PcdMaList
=None):
1222 if AutoGenObject
is None:
1224 if FfsCommand
is None:
1226 # skip file generation for cleanxxx targets, run and fds target
1227 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1228 # for target which must generate AutoGen code and makefile
1230 for m
in AutoGenObject
.GetAllModuleInfo
:
1233 AutoGenObject
.DataPipe
.DataContainer
= {"FfsCommand":FfsCommand
}
1234 self
.Progress
.Start("Generating makefile and code")
1235 data_pipe_file
= os
.path
.join(AutoGenObject
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(AutoGenObject
.Guid
),AutoGenObject
.Arch
))
1236 AutoGenObject
.DataPipe
.dump(data_pipe_file
)
1237 autogen_rt
, errorcode
= self
.StartAutoGen(mqueue
, AutoGenObject
.DataPipe
, self
.SkipAutoGen
, PcdMaList
,self
.share_data
)
1238 self
.Progress
.Stop("done!")
1240 self
.AutoGenMgr
.TerminateWorkers()
1241 self
.AutoGenMgr
.join(0.1)
1242 raise FatalError(errorcode
)
1243 AutoGenObject
.CreateCodeFile(False)
1244 AutoGenObject
.CreateMakeFile(False)
1246 # always recreate top/platform makefile when clean, just in case of inconsistency
1247 AutoGenObject
.CreateCodeFile(True)
1248 AutoGenObject
.CreateMakeFile(True)
1250 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1251 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1253 BuildCommand
= AutoGenObject
.BuildCommand
1254 if BuildCommand
is None or len(BuildCommand
) == 0:
1255 EdkLogger
.error("build", OPTION_MISSING
,
1256 "No build command found for this module. "
1257 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1258 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1259 ExtraData
=str(AutoGenObject
))
1261 makefile
= GenMake
.BuildFile(AutoGenObject
)._FILE
_NAME
_[GenMake
.gMakeType
]
1269 BuildCommand
= BuildCommand
+ [Target
]
1270 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1271 self
.CreateAsBuiltInf()
1272 if GlobalData
.gBinCacheDest
:
1273 self
.UpdateBuildCache()
1274 self
.BuildModules
= []
1278 if Target
== 'libraries':
1279 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1280 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1281 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1285 if Target
== 'modules':
1286 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1287 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1288 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1289 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1290 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, makefile
)), 'pbuild']
1291 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1292 self
.CreateAsBuiltInf()
1293 if GlobalData
.gBinCacheDest
:
1294 self
.UpdateBuildCache()
1295 self
.BuildModules
= []
1299 if Target
== 'cleanlib':
1300 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1301 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1302 if os
.path
.exists(LibMakefile
):
1303 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1304 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1308 if Target
== 'clean':
1309 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1310 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, makefile
))
1311 if os
.path
.exists(ModMakefile
):
1312 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
1313 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1314 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1315 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1316 if os
.path
.exists(LibMakefile
):
1317 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1318 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1322 if Target
== 'cleanall':
1324 #os.rmdir(AutoGenObject.BuildDir)
1325 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1326 except WindowsError as X
:
1327 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1330 ## Build a module or platform
1332 # Create autogen code and makefile for a module or platform, and the launch
1333 # "make" command to build it
1335 # @param Target The target of build command
1336 # @param Platform The platform file
1337 # @param Module The module file
1338 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1339 # @param ToolChain The name of toolchain to build
1340 # @param Arch The arch of the module/platform
1341 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1342 # for dependent modules/Libraries
1343 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1344 # for dependent modules/Libraries
1346 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1347 if AutoGenObject
is None:
1350 # skip file generation for cleanxxx targets, run and fds target
1351 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1352 # for target which must generate AutoGen code and makefile
1353 if not self
.SkipAutoGen
or Target
== 'genc':
1354 self
.Progress
.Start("Generating code")
1355 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1356 self
.Progress
.Stop("done!")
1357 if Target
== "genc":
1360 if not self
.SkipAutoGen
or Target
== 'genmake':
1361 self
.Progress
.Start("Generating makefile")
1362 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1363 #AutoGenObject.CreateAsBuiltInf()
1364 self
.Progress
.Stop("done!")
1365 if Target
== "genmake":
1368 # always recreate top/platform makefile when clean, just in case of inconsistency
1369 AutoGenObject
.CreateCodeFile(True)
1370 AutoGenObject
.CreateMakeFile(True)
1372 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1373 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1375 BuildCommand
= AutoGenObject
.BuildCommand
1376 if BuildCommand
is None or len(BuildCommand
) == 0:
1377 EdkLogger
.error("build", OPTION_MISSING
,
1378 "No build command found for this module. "
1379 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1380 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1381 ExtraData
=str(AutoGenObject
))
1386 BuildCommand
= BuildCommand
+ [Target
]
1387 AutoGenObject
.BuildTime
= LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1388 self
.CreateAsBuiltInf()
1389 if GlobalData
.gBinCacheDest
:
1390 self
.UpdateBuildCache()
1391 self
.BuildModules
= []
1396 if GenFdsApi(AutoGenObject
.GenFdsCommandDict
, self
.Db
):
1397 EdkLogger
.error("build", COMMAND_FAILURE
)
1405 if Target
== 'libraries':
1412 if Target
== 'cleanall':
1414 #os.rmdir(AutoGenObject.BuildDir)
1415 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1416 except WindowsError as X
:
1417 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1420 ## Rebase module image and Get function address for the input module list.
1422 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1424 AddrIsOffset
= False
1425 for InfFile
in ModuleList
:
1426 sys
.stdout
.write (".")
1428 ModuleInfo
= ModuleList
[InfFile
]
1429 ModuleName
= ModuleInfo
.BaseName
1430 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1431 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1432 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1434 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1436 # Update Image to new BaseAddress by GenFw tool
1438 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1439 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1442 # Set new address to the section header only for SMM driver.
1444 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1445 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1447 # Collect function address from Map file
1449 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1451 if os
.path
.exists(ImageMapTable
):
1452 OrigImageBaseAddress
= 0
1453 ImageMap
= open(ImageMapTable
, 'r')
1454 for LinStr
in ImageMap
:
1455 if len (LinStr
.strip()) == 0:
1458 # Get the preferred address set on link time.
1460 if LinStr
.find ('Preferred load address is') != -1:
1461 StrList
= LinStr
.split()
1462 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1464 StrList
= LinStr
.split()
1465 if len (StrList
) > 4:
1466 if StrList
[3] == 'f' or StrList
[3] == 'F':
1468 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1469 FunctionList
.append ((Name
, RelativeAddress
))
1473 # Add general information.
1476 MapBuffer
.append('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1478 MapBuffer
.append('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1480 MapBuffer
.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1482 # Add guid and general seciton section.
1484 TextSectionAddress
= 0
1485 DataSectionAddress
= 0
1486 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1487 if SectionHeader
[0] == '.text':
1488 TextSectionAddress
= SectionHeader
[1]
1489 elif SectionHeader
[0] in ['.data', '.sdata']:
1490 DataSectionAddress
= SectionHeader
[1]
1492 MapBuffer
.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1494 MapBuffer
.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1496 # Add debug image full path.
1498 MapBuffer
.append('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1500 # Add function address
1502 for Function
in FunctionList
:
1504 MapBuffer
.append(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1506 MapBuffer
.append(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1510 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1513 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1515 ## Collect MAP information of all FVs
1517 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1519 # First get the XIP base address for FV map file.
1520 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1521 GuidName
= re
.compile(r
"\(GUID=[-a-fA-F0-9]+")
1522 for FvName
in Wa
.FdfProfile
.FvDict
:
1523 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1524 if not os
.path
.exists(FvMapBuffer
):
1526 FvMap
= open(FvMapBuffer
, 'r')
1527 #skip FV size information
1533 MatchGuid
= GuidPattern
.match(Line
)
1534 if MatchGuid
is not None:
1536 # Replace GUID with module name
1538 GuidString
= MatchGuid
.group()
1539 if GuidString
.upper() in ModuleList
:
1540 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1541 MapBuffer
.append(Line
)
1543 # Add the debug image full path.
1545 MatchGuid
= GuidName
.match(Line
)
1546 if MatchGuid
is not None:
1547 GuidString
= MatchGuid
.group().split("=")[1]
1548 if GuidString
.upper() in ModuleList
:
1549 MapBuffer
.append('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1553 ## Collect MAP information of all modules
1555 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1556 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1558 PatchEfiImageList
= []
1566 # reserve 4K size in SMRAM to make SMM module address not from 0.
1568 for ModuleGuid
in ModuleList
:
1569 Module
= ModuleList
[ModuleGuid
]
1570 GlobalData
.gProcessingFile
= "%s [%s, %s, %s]" % (Module
.MetaFile
, Module
.Arch
, Module
.ToolChain
, Module
.BuildTarget
)
1572 OutputImageFile
= ''
1573 for ResultFile
in Module
.CodaTargetList
:
1574 if str(ResultFile
.Target
).endswith('.efi'):
1576 # module list for PEI, DXE, RUNTIME and SMM
1578 OutputImageFile
= os
.path
.join(Module
.OutputDir
, Module
.Name
+ '.efi')
1579 ImageClass
= PeImageClass (OutputImageFile
)
1580 if not ImageClass
.IsValid
:
1581 EdkLogger
.error("build", FILE_PARSE_FAILURE
, ExtraData
=ImageClass
.ErrorInfo
)
1582 ImageInfo
= PeImageInfo(Module
.Name
, Module
.Guid
, Module
.Arch
, Module
.OutputDir
, Module
.DebugDir
, ImageClass
)
1583 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
]:
1584 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1585 PeiSize
+= ImageInfo
.Image
.Size
1586 elif Module
.ModuleType
in [EDK_COMPONENT_TYPE_BS_DRIVER
, SUP_MODULE_DXE_DRIVER
, SUP_MODULE_UEFI_DRIVER
]:
1587 BtModuleList
[Module
.MetaFile
] = ImageInfo
1588 BtSize
+= ImageInfo
.Image
.Size
1589 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
]:
1590 RtModuleList
[Module
.MetaFile
] = ImageInfo
1591 RtSize
+= ImageInfo
.Image
.Size
1592 elif Module
.ModuleType
in [SUP_MODULE_SMM_CORE
, SUP_MODULE_DXE_SMM_DRIVER
, SUP_MODULE_MM_STANDALONE
, SUP_MODULE_MM_CORE_STANDALONE
]:
1593 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1594 SmmSize
+= ImageInfo
.Image
.Size
1595 if Module
.ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
1596 PiSpecVersion
= Module
.Module
.Specification
.get('PI_SPECIFICATION_VERSION', '0x00000000')
1597 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1598 if int(PiSpecVersion
, 16) < 0x0001000A:
1599 BtModuleList
[Module
.MetaFile
] = ImageInfo
1600 BtSize
+= ImageInfo
.Image
.Size
1603 # EFI image is final target.
1604 # Check EFI image contains patchable FixAddress related PCDs.
1606 if OutputImageFile
!= '':
1607 ModuleIsPatch
= False
1608 for Pcd
in Module
.ModulePcdList
:
1609 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1610 ModuleIsPatch
= True
1612 if not ModuleIsPatch
:
1613 for Pcd
in Module
.LibraryPcdList
:
1614 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1615 ModuleIsPatch
= True
1618 if not ModuleIsPatch
:
1621 # Module includes the patchable load fix address PCDs.
1622 # It will be fixed up later.
1624 PatchEfiImageList
.append (OutputImageFile
)
1627 # Get Top Memory address
1629 ReservedRuntimeMemorySize
= 0
1630 TopMemoryAddress
= 0
1631 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1632 TopMemoryAddress
= 0
1634 TopMemoryAddress
= self
.LoadFixAddress
1635 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1636 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1639 # Patch FixAddress related PCDs into EFI image
1641 for EfiImage
in PatchEfiImageList
:
1642 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1643 if not os
.path
.exists(EfiImageMap
):
1646 # Get PCD offset in EFI image by GenPatchPcdTable function
1648 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1650 # Patch real PCD value by PatchPcdValue tool
1652 for PcdInfo
in PcdTable
:
1654 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1655 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
// 0x1000))
1656 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1657 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
// 0x1000))
1658 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1659 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
// 0x1000))
1660 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1661 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
// 0x1000))
1662 if ReturnValue
!= 0:
1663 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1665 MapBuffer
.append('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
// 0x1000))
1666 MapBuffer
.append('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
// 0x1000))
1667 MapBuffer
.append('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
// 0x1000))
1668 if len (SmmModuleList
) > 0:
1669 MapBuffer
.append('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
// 0x1000))
1671 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1672 BtBaseAddr
= TopMemoryAddress
- RtSize
1673 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1675 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1676 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1677 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1678 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
=False, ModeIsSmm
=True)
1679 MapBuffer
.append('\n\n')
1680 sys
.stdout
.write ("\n")
1683 ## Save platform Map file
1685 def _SaveMapFile (self
, MapBuffer
, Wa
):
1687 # Map file path is got.
1689 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1691 # Save address map into MAP file.
1693 SaveFileOnChange(MapFilePath
, ''.join(MapBuffer
), False)
1694 if self
.LoadFixAddress
!= 0:
1695 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath
))
1698 ## Build active platform for different build targets and different tool chains
1700 def _BuildPlatform(self
):
1701 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1702 for BuildTarget
in self
.BuildTargetList
:
1703 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1705 for ToolChain
in self
.ToolChainList
:
1706 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1707 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1708 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1710 Wa
= WorkspaceAutoGen(
1727 self
.Fdf
= Wa
.FdfFile
1728 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1729 self
.BuildReport
.AddPlatformReport(Wa
)
1730 self
.Progress
.Stop("done!")
1732 # Add ffs build to makefile
1734 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1735 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1737 for Arch
in Wa
.ArchList
:
1739 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1740 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1741 for Module
in Pa
.Platform
.Modules
:
1742 # Get ModuleAutoGen object to generate C code file and makefile
1743 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1747 Ma
.PlatformInfo
= Pa
1749 PcdMaList
.append(Ma
)
1750 self
.BuildModules
.append(Ma
)
1751 self
._BuildPa
(self
.Target
, Pa
, FfsCommand
=CmdListDict
,PcdMaList
=PcdMaList
)
1753 # Create MAP file when Load Fix Address is enabled.
1754 if self
.Target
in ["", "all", "fds"]:
1755 for Arch
in Wa
.ArchList
:
1756 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1758 # Check whether the set fix address is above 4G for 32bit image.
1760 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1761 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")
1766 for Pa
in Wa
.AutoGenObjectList
:
1767 for Ma
in Pa
.ModuleAutoGenList
:
1770 if not Ma
.IsLibrary
:
1771 ModuleList
[Ma
.Guid
.upper()] = Ma
1774 if self
.LoadFixAddress
!= 0:
1776 # Rebase module to the preferred memory address before GenFds
1778 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1781 # create FDS again for the updated EFI image
1783 self
._Build
("fds", Wa
)
1785 # Create MAP file for all platform FVs after GenFds.
1787 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1789 # Save MAP buffer into MAP file.
1791 self
._SaveMapFile
(MapBuffer
, Wa
)
1793 ## Build active module for different build targets, different tool chains and different archs
1795 def _BuildModule(self
):
1796 for BuildTarget
in self
.BuildTargetList
:
1797 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1799 for ToolChain
in self
.ToolChainList
:
1800 WorkspaceAutoGenTime
= time
.time()
1801 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1802 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1803 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1806 # module build needs platform build information, so get platform
1809 Wa
= WorkspaceAutoGen(
1827 self
.Fdf
= Wa
.FdfFile
1828 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1829 Wa
.CreateMakeFile(False)
1830 # Add ffs build to makefile
1832 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1833 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1834 self
.Progress
.Stop("done!")
1836 ExitFlag
= threading
.Event()
1838 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1839 for Arch
in Wa
.ArchList
:
1840 AutoGenStart
= time
.time()
1841 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1842 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1843 for Module
in Pa
.Platform
.Modules
:
1844 if self
.ModuleFile
.Dir
== Module
.Dir
and self
.ModuleFile
.Name
== Module
.Name
:
1845 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1849 if Ma
.CanSkipbyHash():
1850 self
.HashSkipModules
.append(Ma
)
1851 if GlobalData
.gBinCacheSource
:
1852 EdkLogger
.quiet("cache hit: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1855 if GlobalData
.gBinCacheSource
:
1856 EdkLogger
.quiet("cache miss: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1857 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1858 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1859 # for target which must generate AutoGen code and makefile
1860 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1861 self
.Progress
.Start("Generating code")
1862 Ma
.CreateCodeFile(True)
1863 self
.Progress
.Stop("done!")
1864 if self
.Target
== "genc":
1866 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1867 self
.Progress
.Start("Generating makefile")
1868 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
1869 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
1870 del CmdListDict
[Module
.File
, Arch
]
1872 Ma
.CreateMakeFile(True)
1873 self
.Progress
.Stop("done!")
1874 if self
.Target
== "genmake":
1876 self
.BuildModules
.append(Ma
)
1877 # Initialize all modules in tracking to 'FAIL'
1878 if Ma
.Arch
not in GlobalData
.gModuleBuildTracking
:
1879 GlobalData
.gModuleBuildTracking
[Ma
.Arch
] = dict()
1880 if Ma
not in GlobalData
.gModuleBuildTracking
[Ma
.Arch
]:
1881 GlobalData
.gModuleBuildTracking
[Ma
.Arch
][Ma
] = 'FAIL'
1882 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1883 MakeStart
= time
.time()
1884 for Ma
in self
.BuildModules
:
1885 if not Ma
.IsBinaryModule
:
1886 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
1887 # Break build if any build thread has error
1888 if BuildTask
.HasError():
1889 # we need a full version of makefile for platform
1891 BuildTask
.WaitForComplete()
1892 self
.invalidateHash()
1893 Pa
.CreateMakeFile(False)
1894 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1895 # Start task scheduler
1896 if not BuildTask
.IsOnGoing():
1897 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1899 # in case there's an interruption. we need a full version of makefile for platform
1900 Pa
.CreateMakeFile(False)
1901 if BuildTask
.HasError():
1902 self
.invalidateHash()
1903 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1904 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1906 MakeContiue
= time
.time()
1908 BuildTask
.WaitForComplete()
1909 self
.CreateAsBuiltInf()
1910 if GlobalData
.gBinCacheDest
:
1911 self
.UpdateBuildCache()
1912 self
.BuildModules
= []
1913 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1914 if BuildTask
.HasError():
1915 self
.invalidateHash()
1916 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1918 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1923 "Module for [%s] is not a component of active platform."\
1924 " Please make sure that the ARCH and inf file path are"\
1925 " given in the same as in [%s]" % \
1926 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1927 ExtraData
=self
.ModuleFile
1929 # Create MAP file when Load Fix Address is enabled.
1930 if self
.Target
== "fds" and self
.Fdf
:
1931 for Arch
in Wa
.ArchList
:
1933 # Check whether the set fix address is above 4G for 32bit image.
1935 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1936 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")
1941 for Pa
in Wa
.AutoGenObjectList
:
1942 for Ma
in Pa
.ModuleAutoGenList
:
1945 if not Ma
.IsLibrary
:
1946 ModuleList
[Ma
.Guid
.upper()] = Ma
1949 if self
.LoadFixAddress
!= 0:
1951 # Rebase module to the preferred memory address before GenFds
1953 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1955 # create FDS again for the updated EFI image
1957 GenFdsStart
= time
.time()
1958 self
._Build
("fds", Wa
)
1959 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
1961 # Create MAP file for all platform FVs after GenFds.
1963 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1965 # Save MAP buffer into MAP file.
1967 self
._SaveMapFile
(MapBuffer
, Wa
)
1968 self
.invalidateHash()
1970 def _GenFfsCmd(self
,ArchList
):
1971 # convert dictionary of Cmd:(Inf,Arch)
1972 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
1973 CmdSetDict
= defaultdict(set)
1974 GenFfsDict
= GenFds
.GenFfsMakefile('', GlobalData
.gFdfParser
, self
, ArchList
, GlobalData
)
1975 for Cmd
in GenFfsDict
:
1976 tmpInf
, tmpArch
= GenFfsDict
[Cmd
]
1977 CmdSetDict
[tmpInf
, tmpArch
].add(Cmd
)
1980 ## Build a platform in multi-thread mode
1982 def _MultiThreadBuildPlatform(self
):
1983 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1984 for BuildTarget
in self
.BuildTargetList
:
1985 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1987 for ToolChain
in self
.ToolChainList
:
1988 WorkspaceAutoGenTime
= time
.time()
1989 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1990 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1991 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1993 Wa
= WorkspaceAutoGen(
2010 self
.Fdf
= Wa
.FdfFile
2011 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
2012 self
.BuildReport
.AddPlatformReport(Wa
)
2013 Wa
.CreateMakeFile(False)
2015 # Add ffs build to makefile
2017 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
2018 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
2020 # multi-thread exit flag
2021 ExitFlag
= threading
.Event()
2023 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
2024 self
.BuildModules
= []
2025 for Arch
in Wa
.ArchList
:
2027 AutoGenStart
= time
.time()
2028 GlobalData
.gGlobalDefines
['ARCH'] = Arch
2029 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
2033 for Inf
in Pa
.Platform
.Modules
:
2034 ModuleList
.append(Inf
)
2035 # Add the INF only list in FDF
2036 if GlobalData
.gFdfParser
is not None:
2037 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
2038 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
2039 if Inf
in Pa
.Platform
.Modules
:
2041 ModuleList
.append(Inf
)
2042 Pa
.DataPipe
.DataContainer
= {"FfsCommand":CmdListDict
}
2043 Pa
.DataPipe
.DataContainer
= {"Workspace_timestamp": Wa
._SrcTimeStamp
}
2044 for Module
in ModuleList
:
2045 # Get ModuleAutoGen object to generate C code file and makefile
2046 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2051 Ma
.PlatformInfo
= Pa
2053 PcdMaList
.append(Ma
)
2054 if Ma
.CanSkipbyHash():
2055 self
.HashSkipModules
.append(Ma
)
2056 if GlobalData
.gBinCacheSource
:
2057 EdkLogger
.quiet("cache hit: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
2060 if GlobalData
.gBinCacheSource
:
2061 EdkLogger
.quiet("cache miss: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
2063 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
2064 # for target which must generate AutoGen code and makefile
2066 self
.BuildModules
.append(Ma
)
2067 # Initialize all modules in tracking to 'FAIL'
2068 if Ma
.Arch
not in GlobalData
.gModuleBuildTracking
:
2069 GlobalData
.gModuleBuildTracking
[Ma
.Arch
] = dict()
2070 if Ma
not in GlobalData
.gModuleBuildTracking
[Ma
.Arch
]:
2071 GlobalData
.gModuleBuildTracking
[Ma
.Arch
][Ma
] = 'FAIL'
2073 for m
in Pa
.GetAllModuleInfo
:
2075 data_pipe_file
= os
.path
.join(Pa
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(Pa
.Guid
),Pa
.Arch
))
2076 Pa
.DataPipe
.dump(data_pipe_file
)
2077 autogen_rt
, errorcode
= self
.StartAutoGen(mqueue
, Pa
.DataPipe
, self
.SkipAutoGen
, PcdMaList
,self
.share_data
)
2078 self
.Progress
.Stop("done!")
2079 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
2081 self
.AutoGenMgr
.TerminateWorkers()
2082 self
.AutoGenMgr
.join(0.1)
2083 raise FatalError(errorcode
)
2084 for Arch
in Wa
.ArchList
:
2085 MakeStart
= time
.time()
2086 for Ma
in self
.BuildModules
:
2087 # Generate build task for the module
2088 if not Ma
.IsBinaryModule
:
2089 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
2090 # Break build if any build thread has error
2091 if BuildTask
.HasError():
2092 # we need a full version of makefile for platform
2094 BuildTask
.WaitForComplete()
2095 self
.invalidateHash()
2096 Pa
.CreateMakeFile(False)
2097 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2098 # Start task scheduler
2099 if not BuildTask
.IsOnGoing():
2100 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
2102 # in case there's an interruption. we need a full version of makefile for platform
2103 Pa
.CreateMakeFile(False)
2104 if BuildTask
.HasError():
2105 self
.invalidateHash()
2106 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2107 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
2109 MakeContiue
= time
.time()
2113 # All modules have been put in build tasks queue. Tell task scheduler
2114 # to exit if all tasks are completed
2117 BuildTask
.WaitForComplete()
2118 self
.CreateAsBuiltInf()
2119 if GlobalData
.gBinCacheDest
:
2120 self
.UpdateBuildCache()
2121 self
.BuildModules
= []
2122 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2124 # Check for build error, and raise exception if one
2125 # has been signaled.
2127 if BuildTask
.HasError():
2128 self
.invalidateHash()
2129 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2131 # Create MAP file when Load Fix Address is enabled.
2132 if self
.Target
in ["", "all", "fds"]:
2133 for Arch
in Wa
.ArchList
:
2135 # Check whether the set fix address is above 4G for 32bit image.
2137 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2138 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")
2143 for Pa
in Wa
.AutoGenObjectList
:
2144 for Ma
in Pa
.ModuleAutoGenList
:
2147 if not Ma
.IsLibrary
:
2148 ModuleList
[Ma
.Guid
.upper()] = Ma
2150 # Rebase module to the preferred memory address before GenFds
2153 if self
.LoadFixAddress
!= 0:
2154 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2158 # Generate FD image if there's a FDF file found
2160 GenFdsStart
= time
.time()
2161 if GenFdsApi(Wa
.GenFdsCommandDict
, self
.Db
):
2162 EdkLogger
.error("build", COMMAND_FAILURE
)
2165 # Create MAP file for all platform FVs after GenFds.
2167 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2168 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2170 # Save MAP buffer into MAP file.
2172 self
._SaveMapFile
(MapBuffer
, Wa
)
2173 self
.invalidateHash()
2175 ## Generate GuidedSectionTools.txt in the FV directories.
2177 def CreateGuidedSectionToolsFile(self
):
2178 for BuildTarget
in self
.BuildTargetList
:
2179 for ToolChain
in self
.ToolChainList
:
2180 Wa
= WorkspaceAutoGen(
2197 if not os
.path
.exists(FvDir
):
2200 for Arch
in self
.ArchList
:
2201 # Build up the list of supported architectures for this build
2202 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
2204 # Look through the tool definitions for GUIDed tools
2206 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.items():
2207 if attrib
.upper().endswith('_GUID'):
2208 split
= attrib
.split('_')
2209 thisPrefix
= '_'.join(split
[0:3]) + '_'
2210 if thisPrefix
== prefix
:
2211 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
2214 path
= '_'.join(split
[0:4]) + '_PATH'
2215 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2216 path
= self
.GetFullPathOfTool(path
)
2217 guidAttribs
.append((guid
, toolName
, path
))
2219 # Write out GuidedSecTools.txt
2220 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2221 toolsFile
= open(toolsFile
, 'wt')
2222 for guidedSectionTool
in guidAttribs
:
2223 print(' '.join(guidedSectionTool
), file=toolsFile
)
2226 ## Returns the full path of the tool.
2228 def GetFullPathOfTool (self
, tool
):
2229 if os
.path
.exists(tool
):
2230 return os
.path
.realpath(tool
)
2232 # We need to search for the tool using the
2233 # PATH environment variable.
2234 for dirInPath
in os
.environ
['PATH'].split(os
.pathsep
):
2235 foundPath
= os
.path
.join(dirInPath
, tool
)
2236 if os
.path
.exists(foundPath
):
2237 return os
.path
.realpath(foundPath
)
2239 # If the tool was not found in the path then we just return
2243 ## Launch the module or platform build
2246 if not self
.ModuleFile
:
2247 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2248 self
.SpawnMode
= False
2249 self
._BuildPlatform
()
2251 self
._MultiThreadBuildPlatform
()
2252 self
.CreateGuidedSectionToolsFile()
2254 self
.SpawnMode
= False
2257 if self
.Target
== 'cleanall':
2258 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2260 def CreateAsBuiltInf(self
):
2261 for Module
in self
.BuildModules
:
2262 Module
.CreateAsBuiltInf()
2264 def UpdateBuildCache(self
):
2267 for Module
in self
.BuildModules
:
2268 Module
.CopyModuleToCache()
2269 all_mod_set
.add(Module
)
2270 for Module
in self
.HashSkipModules
:
2271 Module
.CopyModuleToCache()
2272 all_mod_set
.add(Module
)
2273 for Module
in all_mod_set
:
2274 for lib
in Module
.LibraryAutoGenList
:
2275 all_lib_set
.add(lib
)
2276 for lib
in all_lib_set
:
2277 lib
.CopyModuleToCache()
2280 self
.HashSkipModules
= []
2281 ## Do some clean-up works when error occurred
2282 def Relinquish(self
):
2283 OldLogLevel
= EdkLogger
.GetLevel()
2284 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2285 Utils
.Progressor
.Abort()
2286 if self
.SpawnMode
== True:
2288 EdkLogger
.SetLevel(OldLogLevel
)
2290 def ParseDefines(DefineList
=[]):
2292 if DefineList
is not None:
2293 for Define
in DefineList
:
2294 DefineTokenList
= Define
.split("=", 1)
2295 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2296 EdkLogger
.error('build', FORMAT_INVALID
,
2297 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2298 ExtraData
=DefineTokenList
[0])
2300 if len(DefineTokenList
) == 1:
2301 DefineDict
[DefineTokenList
[0]] = "TRUE"
2303 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2307 def SingleCheckCallback(option
, opt_str
, value
, parser
):
2308 if option
not in gParamCheck
:
2309 setattr(parser
.values
, option
.dest
, value
)
2310 gParamCheck
.append(option
)
2312 parser
.error("Option %s only allows one instance in command line!" % option
)
2314 def LogBuildTime(Time
):
2317 TimeDur
= time
.gmtime(Time
)
2318 if TimeDur
.tm_yday
> 1:
2319 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2321 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2326 ## Parse command line options
2328 # Using standard Python module optparse to parse command line option of this tool.
2330 # @retval Opt A optparse.Values object containing the parsed options
2331 # @retval Args Target of build command
2333 def MyOptionParser():
2334 Parser
= OptionParser(description
=__copyright__
, version
=__version__
, prog
="build.exe", usage
="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
2335 Parser
.add_option("-a", "--arch", action
="append", type="choice", choices
=['IA32', 'X64', 'EBC', 'ARM', 'AARCH64'], dest
="TargetArch",
2336 help="ARCHS is one of list: IA32, X64, ARM, AARCH64 or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.")
2337 Parser
.add_option("-p", "--platform", action
="callback", type="string", dest
="PlatformFile", callback
=SingleCheckCallback
,
2338 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
2339 Parser
.add_option("-m", "--module", action
="callback", type="string", dest
="ModuleFile", callback
=SingleCheckCallback
,
2340 help="Build the module specified by the INF file name argument.")
2341 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
2343 Parser
.add_option("-t", "--tagname", action
="append", type="string", dest
="ToolChain",
2344 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
2345 Parser
.add_option("-x", "--sku-id", action
="callback", type="string", dest
="SkuId", callback
=SingleCheckCallback
,
2346 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
2348 Parser
.add_option("-n", action
="callback", type="int", dest
="ThreadNumber", callback
=SingleCheckCallback
,
2349 help="Build the platform using multi-threaded compiler. The value overrides target.txt's MAX_CONCURRENT_THREAD_NUMBER. When value is set to 0, tool automatically detect number of "\
2350 "processor threads, set value to 1 means disable multi-thread build, and set value to more than 1 means user specify the threads number to build.")
2352 Parser
.add_option("-f", "--fdf", action
="callback", type="string", dest
="FdfFile", callback
=SingleCheckCallback
,
2353 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
2354 Parser
.add_option("-r", "--rom-image", action
="append", type="string", dest
="RomImage", default
=[],
2355 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
2356 Parser
.add_option("-i", "--fv-image", action
="append", type="string", dest
="FvImage", default
=[],
2357 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
2358 Parser
.add_option("-C", "--capsule-image", action
="append", type="string", dest
="CapName", default
=[],
2359 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
2360 Parser
.add_option("-u", "--skip-autogen", action
="store_true", dest
="SkipAutoGen", help="Skip AutoGen step.")
2361 Parser
.add_option("-e", "--re-parse", action
="store_true", dest
="Reparse", help="Re-parse all meta-data files.")
2363 Parser
.add_option("-c", "--case-insensitive", action
="store_true", dest
="CaseInsensitive", default
=False, help="Don't check case of file name.")
2365 Parser
.add_option("-w", "--warning-as-error", action
="store_true", dest
="WarningAsError", help="Treat warning in tools as error.")
2366 Parser
.add_option("-j", "--log", action
="store", dest
="LogFile", help="Put log in specified file as well as on console.")
2368 Parser
.add_option("-s", "--silent", action
="store_true", type=None, dest
="SilentMode",
2369 help="Make use of silent mode of (n)make.")
2370 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
2371 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
2372 "including library instances selected, final dependency expression, "\
2373 "and warning messages, etc.")
2374 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
2375 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
2377 Parser
.add_option("-y", "--report-file", action
="store", dest
="ReportFile", help="Create/overwrite the report to the specified filename.")
2378 Parser
.add_option("-Y", "--report-type", action
="append", type="choice", choices
=['PCD', 'LIBRARY', 'FLASH', 'DEPEX', 'BUILD_FLAGS', 'FIXED_ADDRESS', 'HASH', 'EXECUTION_ORDER'], dest
="ReportType", default
=[],
2379 help="Flags that control the type of build report to generate. Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, HASH, EXECUTION_ORDER]. "\
2380 "To specify more than one flag, repeat this option on the command line and the default flag set is [PCD, LIBRARY, FLASH, DEPEX, HASH, BUILD_FLAGS, FIXED_ADDRESS]")
2381 Parser
.add_option("-F", "--flag", action
="store", type="string", dest
="Flag",
2382 help="Specify the specific option to parse EDK UNI file. Must be one of: [-c, -s]. -c is for EDK framework UNI file, and -s is for EDK UEFI UNI file. "\
2383 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
2384 "will override the setting in [BuildOptions] section of platform DSC.")
2385 Parser
.add_option("-N", "--no-cache", action
="store_true", dest
="DisableCache", default
=False, help="Disable build cache mechanism")
2386 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
2387 Parser
.add_option("--check-usage", action
="store_true", dest
="CheckUsage", default
=False, help="Check usage content of entries listed in INF file.")
2388 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
2389 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
2390 Parser
.add_option("-l", "--cmd-len", action
="store", type="int", dest
="CommandLength", help="Specify the maximum line length of build command. Default is 4096.")
2391 Parser
.add_option("--hash", action
="store_true", dest
="UseHashCache", default
=False, help="Enable hash-based caching during build process.")
2392 Parser
.add_option("--binary-destination", action
="store", type="string", dest
="BinCacheDest", help="Generate a cache of binary files in the specified directory.")
2393 Parser
.add_option("--binary-source", action
="store", type="string", dest
="BinCacheSource", help="Consume a cache of binary files from the specified directory.")
2394 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
2395 Parser
.add_option("--disable-include-path-check", action
="store_true", dest
="DisableIncludePathCheck", default
=False, help="Disable the include path check for outside of package.")
2396 (Opt
, Args
) = Parser
.parse_args()
2399 ## Tool entrance method
2401 # This method mainly dispatch specific methods per the command line options.
2402 # If no error found, return zero value so the caller of this tool can know
2403 # if it's executed successfully or not.
2405 # @retval 0 Tool was successful
2406 # @retval 1 Tool failed
2409 StartTime
= time
.time()
2412 # Create a log Queue
2415 # Initialize log system
2416 EdkLogger
.LogClientInitialize(LogQ
)
2417 GlobalData
.gCommand
= sys
.argv
[1:]
2419 # Parse the options and args
2421 (Option
, Target
) = MyOptionParser()
2422 GlobalData
.gOptions
= Option
2423 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2426 LogLevel
= EdkLogger
.INFO
2427 if Option
.verbose
is not None:
2428 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2429 LogLevel
= EdkLogger
.VERBOSE
2430 elif Option
.quiet
is not None:
2431 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2432 LogLevel
= EdkLogger
.QUIET
2433 elif Option
.debug
is not None:
2434 EdkLogger
.SetLevel(Option
.debug
+ 1)
2435 LogLevel
= Option
.debug
+ 1
2437 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2439 if Option
.WarningAsError
== True:
2440 EdkLogger
.SetWarningAsError()
2441 Log_Agent
= LogAgent(LogQ
,LogLevel
,Option
.LogFile
)
2444 if platform
.platform().find("Windows") >= 0:
2445 GlobalData
.gIsWindows
= True
2447 GlobalData
.gIsWindows
= False
2449 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2450 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2455 if len(Target
) == 0:
2457 elif len(Target
) >= 2:
2458 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2459 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2461 Target
= Target
[0].lower()
2463 if Target
not in gSupportedTarget
:
2464 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2465 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2468 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2471 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2473 Workspace
= os
.getenv("WORKSPACE")
2475 # Get files real name in workspace dir
2477 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2479 WorkingDirectory
= os
.getcwd()
2480 if not Option
.ModuleFile
:
2481 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2482 FileNum
= len(FileList
)
2484 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2485 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2487 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2489 if Option
.ModuleFile
:
2490 if os
.path
.isabs (Option
.ModuleFile
):
2491 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2492 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2493 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2494 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2496 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2498 if Option
.PlatformFile
is not None:
2499 if os
.path
.isabs (Option
.PlatformFile
):
2500 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2501 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2502 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2504 if Option
.FdfFile
is not None:
2505 if os
.path
.isabs (Option
.FdfFile
):
2506 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2507 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2508 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2509 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2511 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2513 if Option
.Flag
is not None and Option
.Flag
not in ['-c', '-s']:
2514 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2516 MyBuild
= Build(Target
, Workspace
, Option
,LogQ
)
2517 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2518 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2522 # All job done, no error found and no exception raised
2525 except FatalError
as X
:
2526 if MyBuild
is not None:
2527 # for multi-thread build exits safely
2528 MyBuild
.Relinquish()
2529 if Option
is not None and Option
.debug
is not None:
2530 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2531 ReturnCode
= X
.args
[0]
2532 except Warning as X
:
2533 # error from Fdf parser
2534 if MyBuild
is not None:
2535 # for multi-thread build exits safely
2536 MyBuild
.Relinquish()
2537 if Option
is not None and Option
.debug
is not None:
2538 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2540 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2541 ReturnCode
= FORMAT_INVALID
2542 except KeyboardInterrupt:
2543 if MyBuild
is not None:
2545 # for multi-thread build exits safely
2546 MyBuild
.Relinquish()
2547 ReturnCode
= ABORT_ERROR
2548 if Option
is not None and Option
.debug
is not None:
2549 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2551 if MyBuild
is not None:
2552 # for multi-thread build exits safely
2553 MyBuild
.Relinquish()
2555 # try to get the meta-file from the object causing exception
2556 Tb
= sys
.exc_info()[-1]
2557 MetaFile
= GlobalData
.gProcessingFile
2558 while Tb
is not None:
2559 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2560 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2565 "Unknown fatal error when processing [%s]" % MetaFile
,
2566 ExtraData
="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR
,
2569 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2570 ReturnCode
= CODE_ERROR
2572 Utils
.Progressor
.Abort()
2573 Utils
.ClearDuplicatedInf()
2577 MyBuild
.LaunchPostbuild()
2580 Conclusion
= "Failed"
2581 elif ReturnCode
== ABORT_ERROR
:
2582 Conclusion
= "Aborted"
2584 Conclusion
= "Failed"
2585 FinishTime
= time
.time()
2586 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2587 BuildDurationStr
= ""
2588 if BuildDuration
.tm_yday
> 1:
2589 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2591 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2592 if MyBuild
is not None:
2594 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2596 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2597 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2598 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2599 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2604 if __name__
== '__main__':
2606 mp
.set_start_method('spawn')
2610 ## 0-127 is a safe return range, and 1 is a standard default error
2611 if r
< 0 or r
> 127: r
= 1