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
34 from AutoGen
import GenMake
35 from Common
import Misc
as Utils
37 from Common
.TargetTxtClassObject
import TargetTxt
38 from Common
.ToolDefClassObject
import ToolDef
39 from Common
.Misc
import PathClass
,SaveFileOnChange
,RemoveDirectory
40 from Common
.StringUtils
import NormPath
41 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
42 from Common
.BuildToolError
import *
43 from Common
.DataType
import *
44 import Common
.EdkLogger
as EdkLogger
45 from Common
.BuildVersion
import gBUILD_VERSION
46 from Workspace
.WorkspaceDatabase
import BuildDB
48 from BuildReport
import BuildReport
49 from GenPatchPcdTable
.GenPatchPcdTable
import PeImageClass
,parsePcdInfoFromMapFile
50 from PatchPcdValue
.PatchPcdValue
import PatchBinaryFile
52 import Common
.GlobalData
as GlobalData
53 from GenFds
.GenFds
import GenFds
, GenFdsApi
54 import multiprocessing
as mp
56 # Version and Copyright
57 VersionNumber
= "0.60" + ' ' + gBUILD_VERSION
58 __version__
= "%prog Version " + VersionNumber
59 __copyright__
= "Copyright (c) 2007 - 2018, Intel Corporation All rights reserved."
61 ## standard targets of build command
62 gSupportedTarget
= ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
64 ## build configuration file
65 gBuildConfiguration
= "target.txt"
66 gToolsDefinition
= "tools_def.txt"
68 TemporaryTablePattern
= re
.compile(r
'^_\d+_\d+_[a-fA-F0-9]+$')
71 ## Check environment PATH variable to make sure the specified tool is found
73 # If the tool is found in the PATH, then True is returned
74 # Otherwise, False is returned
76 def IsToolInPath(tool
):
77 if 'PATHEXT' in os
.environ
:
78 extns
= os
.environ
['PATHEXT'].split(os
.path
.pathsep
)
81 for pathDir
in os
.environ
['PATH'].split(os
.path
.pathsep
):
83 if os
.path
.exists(os
.path
.join(pathDir
, tool
+ ext
)):
87 ## Check environment variables
89 # Check environment variables that must be set for build. Currently they are
91 # WORKSPACE The directory all packages/platforms start from
92 # EDK_TOOLS_PATH The directory contains all tools needed by the build
93 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
95 # If any of above environment variable is not set or has error, the build
98 def CheckEnvVariable():
100 if "WORKSPACE" not in os
.environ
:
101 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
102 ExtraData
="WORKSPACE")
104 WorkspaceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["WORKSPACE"]))
105 if not os
.path
.exists(WorkspaceDir
):
106 EdkLogger
.error("build", FILE_NOT_FOUND
, "WORKSPACE doesn't exist", ExtraData
=WorkspaceDir
)
107 elif ' ' in WorkspaceDir
:
108 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in WORKSPACE path",
109 ExtraData
=WorkspaceDir
)
110 os
.environ
["WORKSPACE"] = WorkspaceDir
112 # set multiple workspace
113 PackagesPath
= os
.getenv("PACKAGES_PATH")
114 mws
.setWs(WorkspaceDir
, PackagesPath
)
115 if mws
.PACKAGES_PATH
:
116 for Path
in mws
.PACKAGES_PATH
:
117 if not os
.path
.exists(Path
):
118 EdkLogger
.error("build", FILE_NOT_FOUND
, "One Path in PACKAGES_PATH doesn't exist", ExtraData
=Path
)
120 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in PACKAGES_PATH", ExtraData
=Path
)
123 os
.environ
["EDK_TOOLS_PATH"] = os
.path
.normcase(os
.environ
["EDK_TOOLS_PATH"])
125 # check EDK_TOOLS_PATH
126 if "EDK_TOOLS_PATH" not in os
.environ
:
127 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
128 ExtraData
="EDK_TOOLS_PATH")
131 if "PATH" not in os
.environ
:
132 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
135 GlobalData
.gWorkspace
= WorkspaceDir
137 GlobalData
.gGlobalDefines
["WORKSPACE"] = WorkspaceDir
138 GlobalData
.gGlobalDefines
["EDK_TOOLS_PATH"] = os
.environ
["EDK_TOOLS_PATH"]
140 ## Get normalized file path
142 # Convert the path to be local format, and remove the WORKSPACE path at the
143 # beginning if the file path is given in full path.
145 # @param FilePath File path to be normalized
146 # @param Workspace Workspace path which the FilePath will be checked against
148 # @retval string The normalized file path
150 def NormFile(FilePath
, Workspace
):
151 # check if the path is absolute or relative
152 if os
.path
.isabs(FilePath
):
153 FileFullPath
= os
.path
.normpath(FilePath
)
155 FileFullPath
= os
.path
.normpath(mws
.join(Workspace
, FilePath
))
156 Workspace
= mws
.getWs(Workspace
, FilePath
)
158 # check if the file path exists or not
159 if not os
.path
.isfile(FileFullPath
):
160 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath
)
162 # remove workspace directory from the beginning part of the file path
163 if Workspace
[-1] in ["\\", "/"]:
164 return FileFullPath
[len(Workspace
):]
166 return FileFullPath
[(len(Workspace
) + 1):]
168 ## Get the output of an external program
170 # This is the entrance method of thread reading output of an external program and
171 # putting them in STDOUT/STDERR of current program.
173 # @param From The stream message read from
174 # @param To The stream message put on
175 # @param ExitFlag The flag used to indicate stopping reading
177 def ReadMessage(From
, To
, ExitFlag
):
179 # read one line a time
180 Line
= From
.readline()
181 # empty string means "end"
182 if Line
is not None and Line
!= b
"":
183 To(Line
.rstrip().decode(encoding
='utf-8', errors
='ignore'))
189 ## Launch an external program
191 # This method will call subprocess.Popen to execute an external program with
192 # given options in specified directory. Because of the dead-lock issue during
193 # redirecting output of the external program, threads are used to to do the
196 # @param Command A list or string containing the call of the program
197 # @param WorkingDir The directory in which the program will be running
199 def LaunchCommand(Command
, WorkingDir
):
200 BeginTime
= time
.time()
201 # if working directory doesn't exist, Popen() will raise an exception
202 if not os
.path
.isdir(WorkingDir
):
203 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=WorkingDir
)
205 # Command is used as the first Argument in following Popen().
206 # It could be a string or sequence. We find that if command is a string in following Popen(),
207 # ubuntu may fail with an error message that the command is not found.
208 # So here we may need convert command from string to list instance.
209 if platform
.system() != 'Windows':
210 if not isinstance(Command
, list):
211 Command
= Command
.split()
212 Command
= ' '.join(Command
)
215 EndOfProcedure
= None
218 Proc
= Popen(Command
, stdout
=PIPE
, stderr
=PIPE
, env
=os
.environ
, cwd
=WorkingDir
, bufsize
=-1, shell
=True)
220 # launch two threads to read the STDOUT and STDERR
221 EndOfProcedure
= Event()
222 EndOfProcedure
.clear()
224 StdOutThread
= Thread(target
=ReadMessage
, args
=(Proc
.stdout
, EdkLogger
.info
, EndOfProcedure
))
225 StdOutThread
.setName("STDOUT-Redirector")
226 StdOutThread
.setDaemon(False)
230 StdErrThread
= Thread(target
=ReadMessage
, args
=(Proc
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
231 StdErrThread
.setName("STDERR-Redirector")
232 StdErrThread
.setDaemon(False)
235 # waiting for program exit
237 except: # in case of aborting
238 # terminate the threads redirecting the program output
239 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
240 if EndOfProcedure
is not None:
243 if not isinstance(Command
, type("")):
244 Command
= " ".join(Command
)
245 EdkLogger
.error("build", COMMAND_FAILURE
, "Failed to start command", ExtraData
="%s [%s]" % (Command
, WorkingDir
))
252 # check the return code of the program
253 if Proc
.returncode
!= 0:
254 if not isinstance(Command
, type("")):
255 Command
= " ".join(Command
)
256 # print out the Response file and its content when make failure
257 RespFile
= os
.path
.join(WorkingDir
, 'OUTPUT', 'respfilelist.txt')
258 if os
.path
.isfile(RespFile
):
260 RespContent
= f
.read()
262 EdkLogger
.info(RespContent
)
264 EdkLogger
.error("build", COMMAND_FAILURE
, ExtraData
="%s [%s]" % (Command
, WorkingDir
))
265 return "%dms" % (int(round((time
.time() - BeginTime
) * 1000)))
267 ## The smallest unit that can be built in multi-thread build mode
269 # This is the base class of build unit. The "Obj" parameter must provide
270 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
273 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
278 # @param self The object pointer
279 # @param Obj The object the build is working on
280 # @param Target The build target name, one of gSupportedTarget
281 # @param Dependency The BuildUnit(s) which must be completed in advance
282 # @param WorkingDir The directory build command starts in
284 def __init__(self
, Obj
, BuildCommand
, Target
, Dependency
, WorkingDir
="."):
285 self
.BuildObject
= Obj
286 self
.Dependency
= Dependency
287 self
.WorkingDir
= WorkingDir
289 self
.BuildCommand
= BuildCommand
291 EdkLogger
.error("build", OPTION_MISSING
,
292 "No build command found for this module. "
293 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
294 (Obj
.BuildTarget
, Obj
.ToolChain
, Obj
.Arch
),
300 # It just returns the string representation of self.BuildObject
302 # @param self The object pointer
305 return str(self
.BuildObject
)
307 ## "==" operator method
309 # It just compares self.BuildObject with "Other". So self.BuildObject must
310 # provide its own __eq__() method.
312 # @param self The object pointer
313 # @param Other The other BuildUnit object compared to
315 def __eq__(self
, Other
):
316 return Other
and self
.BuildObject
== Other
.BuildObject \
317 and Other
.BuildObject \
318 and self
.BuildObject
.Arch
== Other
.BuildObject
.Arch
322 # It just returns the hash value of self.BuildObject which must be hashable.
324 # @param self The object pointer
327 return hash(self
.BuildObject
) + hash(self
.BuildObject
.Arch
)
330 return repr(self
.BuildObject
)
332 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
334 # This class is for module build by nmake/make build system. The "Obj" parameter
335 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
336 # be make units missing build.
338 # Currently the "Obj" should be only ModuleAutoGen object.
340 class ModuleMakeUnit(BuildUnit
):
343 # @param self The object pointer
344 # @param Obj The ModuleAutoGen object the build is working on
345 # @param Target The build target name, one of gSupportedTarget
347 def __init__(self
, Obj
, BuildCommand
,Target
):
348 Dependency
= [ModuleMakeUnit(La
, BuildCommand
,Target
) for La
in Obj
.LibraryAutoGenList
]
349 BuildUnit
.__init
__(self
, Obj
, BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
350 if Target
in [None, "", "all"]:
351 self
.Target
= "tbuild"
353 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
355 # This class is for platform build by nmake/make build system. The "Obj" parameter
356 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
357 # be make units missing build.
359 # Currently the "Obj" should be only PlatformAutoGen object.
361 class PlatformMakeUnit(BuildUnit
):
364 # @param self The object pointer
365 # @param Obj The PlatformAutoGen object the build is working on
366 # @param Target The build target name, one of gSupportedTarget
368 def __init__(self
, Obj
, BuildCommand
, Target
):
369 Dependency
= [ModuleMakeUnit(Lib
, BuildCommand
, Target
) for Lib
in self
.BuildObject
.LibraryAutoGenList
]
370 Dependency
.extend([ModuleMakeUnit(Mod
, BuildCommand
,Target
) for Mod
in self
.BuildObject
.ModuleAutoGenList
])
371 BuildUnit
.__init
__(self
, Obj
, BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
373 ## The class representing the task of a module build or platform build
375 # This class manages the build tasks in multi-thread build mode. Its jobs include
376 # scheduling thread running, catching thread error, monitor the thread status, etc.
379 # queue for tasks waiting for schedule
380 _PendingQueue
= OrderedDict()
381 _PendingQueueLock
= threading
.Lock()
383 # queue for tasks ready for running
384 _ReadyQueue
= OrderedDict()
385 _ReadyQueueLock
= threading
.Lock()
387 # queue for run tasks
388 _RunningQueue
= OrderedDict()
389 _RunningQueueLock
= threading
.Lock()
391 # queue containing all build tasks, in case duplicate build
392 _TaskQueue
= OrderedDict()
394 # flag indicating error occurs in a running thread
395 _ErrorFlag
= threading
.Event()
399 # BoundedSemaphore object used to control the number of running threads
402 # flag indicating if the scheduler is started or not
403 _SchedulerStopped
= threading
.Event()
404 _SchedulerStopped
.set()
406 ## Start the task scheduler thread
408 # @param MaxThreadNumber The maximum thread number
409 # @param ExitFlag Flag used to end the scheduler
412 def StartScheduler(MaxThreadNumber
, ExitFlag
):
413 SchedulerThread
= Thread(target
=BuildTask
.Scheduler
, args
=(MaxThreadNumber
, ExitFlag
))
414 SchedulerThread
.setName("Build-Task-Scheduler")
415 SchedulerThread
.setDaemon(False)
416 SchedulerThread
.start()
417 # wait for the scheduler to be started, especially useful in Linux
418 while not BuildTask
.IsOnGoing():
423 # @param MaxThreadNumber The maximum thread number
424 # @param ExitFlag Flag used to end the scheduler
427 def Scheduler(MaxThreadNumber
, ExitFlag
):
428 BuildTask
._SchedulerStopped
.clear()
430 # use BoundedSemaphore to control the maximum running threads
431 BuildTask
._Thread
= BoundedSemaphore(MaxThreadNumber
)
433 # scheduling loop, which will exits when no pending/ready task and
434 # indicated to do so, or there's error in running thread
436 while (len(BuildTask
._PendingQueue
) > 0 or len(BuildTask
._ReadyQueue
) > 0 \
437 or not ExitFlag
.isSet()) and not BuildTask
._ErrorFlag
.isSet():
438 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Pending Queue (%d), Ready Queue (%d)"
439 % (len(BuildTask
._PendingQueue
), len(BuildTask
._ReadyQueue
)))
441 # get all pending tasks
442 BuildTask
._PendingQueueLock
.acquire()
443 BuildObjectList
= list(BuildTask
._PendingQueue
.keys())
445 # check if their dependency is resolved, and if true, move them
448 for BuildObject
in BuildObjectList
:
449 Bt
= BuildTask
._PendingQueue
[BuildObject
]
451 BuildTask
._ReadyQueue
[BuildObject
] = BuildTask
._PendingQueue
.pop(BuildObject
)
452 BuildTask
._PendingQueueLock
.release()
454 # launch build thread until the maximum number of threads is reached
455 while not BuildTask
._ErrorFlag
.isSet():
456 # empty ready queue, do nothing further
457 if len(BuildTask
._ReadyQueue
) == 0:
460 # wait for active thread(s) exit
461 BuildTask
._Thread
.acquire(True)
463 # start a new build thread
464 Bo
, Bt
= BuildTask
._ReadyQueue
.popitem()
466 # move into running queue
467 BuildTask
._RunningQueueLock
.acquire()
468 BuildTask
._RunningQueue
[Bo
] = Bt
469 BuildTask
._RunningQueueLock
.release()
478 # wait for all running threads exit
479 if BuildTask
._ErrorFlag
.isSet():
480 EdkLogger
.quiet("\nWaiting for all build threads exit...")
481 # while not BuildTask._ErrorFlag.isSet() and \
482 while len(BuildTask
._RunningQueue
) > 0:
483 EdkLogger
.verbose("Waiting for thread ending...(%d)" % len(BuildTask
._RunningQueue
))
484 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Threads [%s]" % ", ".join(Th
.getName() for Th
in threading
.enumerate()))
487 except BaseException
as X
:
489 # TRICK: hide the output of threads left running, so that the user can
490 # catch the error message easily
492 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
493 BuildTask
._ErrorFlag
.set()
494 BuildTask
._ErrorMessage
= "build thread scheduler error\n\t%s" % str(X
)
496 BuildTask
._PendingQueue
.clear()
497 BuildTask
._ReadyQueue
.clear()
498 BuildTask
._RunningQueue
.clear()
499 BuildTask
._TaskQueue
.clear()
500 BuildTask
._SchedulerStopped
.set()
502 ## Wait for all running method exit
505 def WaitForComplete():
506 BuildTask
._SchedulerStopped
.wait()
508 ## Check if the scheduler is running or not
512 return not BuildTask
._SchedulerStopped
.isSet()
517 if BuildTask
.IsOnGoing():
518 BuildTask
._ErrorFlag
.set()
519 BuildTask
.WaitForComplete()
521 ## Check if there's error in running thread
523 # Since the main thread cannot catch exceptions in other thread, we have to
524 # use threading.Event to communicate this formation to main thread.
528 return BuildTask
._ErrorFlag
.isSet()
530 ## Get error message in running thread
532 # Since the main thread cannot catch exceptions in other thread, we have to
533 # use a static variable to communicate this message to main thread.
536 def GetErrorMessage():
537 return BuildTask
._ErrorMessage
539 ## Factory method to create a BuildTask object
541 # This method will check if a module is building or has been built. And if
542 # true, just return the associated BuildTask object in the _TaskQueue. If
543 # not, create and return a new BuildTask object. The new BuildTask object
544 # will be appended to the _PendingQueue for scheduling later.
546 # @param BuildItem A BuildUnit object representing a build object
547 # @param Dependency The dependent build object of BuildItem
550 def New(BuildItem
, Dependency
=None):
551 if BuildItem
in BuildTask
._TaskQueue
:
552 Bt
= BuildTask
._TaskQueue
[BuildItem
]
556 Bt
._Init
(BuildItem
, Dependency
)
557 BuildTask
._TaskQueue
[BuildItem
] = Bt
559 BuildTask
._PendingQueueLock
.acquire()
560 BuildTask
._PendingQueue
[BuildItem
] = Bt
561 BuildTask
._PendingQueueLock
.release()
565 ## The real constructor of BuildTask
567 # @param BuildItem A BuildUnit object representing a build object
568 # @param Dependency The dependent build object of BuildItem
570 def _Init(self
, BuildItem
, Dependency
=None):
571 self
.BuildItem
= BuildItem
573 self
.DependencyList
= []
574 if Dependency
is None:
575 Dependency
= BuildItem
.Dependency
577 Dependency
.extend(BuildItem
.Dependency
)
578 self
.AddDependency(Dependency
)
579 # flag indicating build completes, used to avoid unnecessary re-build
580 self
.CompleteFlag
= False
582 ## Check if all dependent build tasks are completed or not
586 for Dep
in self
.DependencyList
:
587 if Dep
.CompleteFlag
== True:
594 ## Add dependent build task
596 # @param Dependency The list of dependent build objects
598 def AddDependency(self
, Dependency
):
599 for Dep
in Dependency
:
600 if not Dep
.BuildObject
.IsBinaryModule
and not Dep
.BuildObject
.CanSkipbyHash():
601 self
.DependencyList
.append(BuildTask
.New(Dep
)) # BuildTask list
603 ## The thread wrapper of LaunchCommand function
605 # @param Command A list or string contains the call of the command
606 # @param WorkingDir The directory in which the program will be running
608 def _CommandThread(self
, Command
, WorkingDir
):
610 self
.BuildItem
.BuildObject
.BuildTime
= LaunchCommand(Command
, WorkingDir
)
611 self
.CompleteFlag
= True
613 # Run hash operation post dependency, to account for libs
614 if GlobalData
.gUseHashCache
and self
.BuildItem
.BuildObject
.IsLibrary
:
615 HashFile
= path
.join(self
.BuildItem
.BuildObject
.BuildDir
, self
.BuildItem
.BuildObject
.Name
+ ".hash")
616 SaveFileOnChange(HashFile
, self
.BuildItem
.BuildObject
.GenModuleHash(), True)
619 # TRICK: hide the output of threads left running, so that the user can
620 # catch the error message easily
622 if not BuildTask
._ErrorFlag
.isSet():
623 GlobalData
.gBuildingModule
= "%s [%s, %s, %s]" % (str(self
.BuildItem
.BuildObject
),
624 self
.BuildItem
.BuildObject
.Arch
,
625 self
.BuildItem
.BuildObject
.ToolChain
,
626 self
.BuildItem
.BuildObject
.BuildTarget
628 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
629 BuildTask
._ErrorFlag
.set()
630 BuildTask
._ErrorMessage
= "%s broken\n %s [%s]" % \
631 (threading
.currentThread().getName(), Command
, WorkingDir
)
633 # Set the value used by hash invalidation flow in GlobalData.gModuleBuildTracking to 'SUCCESS'
634 # If Module or Lib is being tracked, it did not fail header check test, and built successfully
635 if (self
.BuildItem
.BuildObject
.Arch
in GlobalData
.gModuleBuildTracking
and
636 self
.BuildItem
.BuildObject
in GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
.Arch
] and
637 GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
.Arch
][self
.BuildItem
.BuildObject
] != 'FAIL_METAFILE' and
638 not BuildTask
._ErrorFlag
.isSet()
640 GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
.Arch
][self
.BuildItem
.BuildObject
] = 'SUCCESS'
642 # indicate there's a thread is available for another build task
643 BuildTask
._RunningQueueLock
.acquire()
644 BuildTask
._RunningQueue
.pop(self
.BuildItem
)
645 BuildTask
._RunningQueueLock
.release()
646 BuildTask
._Thread
.release()
648 ## Start build task thread
651 EdkLogger
.quiet("Building ... %s" % repr(self
.BuildItem
))
652 Command
= self
.BuildItem
.BuildCommand
+ [self
.BuildItem
.Target
]
653 self
.BuildTread
= Thread(target
=self
._CommandThread
, args
=(Command
, self
.BuildItem
.WorkingDir
))
654 self
.BuildTread
.setName("build thread")
655 self
.BuildTread
.setDaemon(False)
656 self
.BuildTread
.start()
658 ## The class contains the information related to EFI image
663 # Constructor will load all required image information.
665 # @param BaseName The full file path of image.
666 # @param Guid The GUID for image.
667 # @param Arch Arch of this image.
668 # @param OutputDir The output directory for image.
669 # @param DebugDir The debug directory for image.
670 # @param ImageClass PeImage Information
672 def __init__(self
, BaseName
, Guid
, Arch
, OutputDir
, DebugDir
, ImageClass
):
673 self
.BaseName
= BaseName
676 self
.OutputDir
= OutputDir
677 self
.DebugDir
= DebugDir
678 self
.Image
= ImageClass
679 self
.Image
.Size
= (self
.Image
.Size
// 0x1000 + 1) * 0x1000
681 ## The class implementing the EDK2 build process
683 # The build process includes:
684 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
685 # 2. Parse DSC file of active platform
686 # 3. Parse FDF file if any
687 # 4. Establish build database, including parse all other files (module, package)
688 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
689 # 6. Call build command
694 # Constructor will load all necessary configurations, parse platform, modules
695 # and packages and the establish a database for AutoGen.
697 # @param Target The build command target, one of gSupportedTarget
698 # @param WorkspaceDir The directory of workspace
699 # @param BuildOptions Build options passed from command line
701 def __init__(self
, Target
, WorkspaceDir
, BuildOptions
):
702 self
.WorkspaceDir
= WorkspaceDir
704 self
.PlatformFile
= BuildOptions
.PlatformFile
705 self
.ModuleFile
= BuildOptions
.ModuleFile
706 self
.ArchList
= BuildOptions
.TargetArch
707 self
.ToolChainList
= BuildOptions
.ToolChain
708 self
.BuildTargetList
= BuildOptions
.BuildTarget
709 self
.Fdf
= BuildOptions
.FdfFile
710 self
.FdList
= BuildOptions
.RomImage
711 self
.FvList
= BuildOptions
.FvImage
712 self
.CapList
= BuildOptions
.CapName
713 self
.SilentMode
= BuildOptions
.SilentMode
714 self
.ThreadNumber
= BuildOptions
.ThreadNumber
715 self
.SkipAutoGen
= BuildOptions
.SkipAutoGen
716 self
.Reparse
= BuildOptions
.Reparse
717 self
.SkuId
= BuildOptions
.SkuId
719 GlobalData
.gSKUID_CMD
= self
.SkuId
720 self
.ConfDirectory
= BuildOptions
.ConfDirectory
721 self
.SpawnMode
= True
722 self
.BuildReport
= BuildReport(BuildOptions
.ReportFile
, BuildOptions
.ReportType
)
723 self
.TargetTxt
= TargetTxt
724 self
.ToolDef
= ToolDef
728 GlobalData
.BuildOptionPcd
= BuildOptions
.OptionPcd
if BuildOptions
.OptionPcd
else []
729 #Set global flag for build mode
730 GlobalData
.gIgnoreSource
= BuildOptions
.IgnoreSources
731 GlobalData
.gUseHashCache
= BuildOptions
.UseHashCache
732 GlobalData
.gBinCacheDest
= BuildOptions
.BinCacheDest
733 GlobalData
.gBinCacheSource
= BuildOptions
.BinCacheSource
734 GlobalData
.gEnableGenfdsMultiThread
= BuildOptions
.GenfdsMultiThread
735 GlobalData
.gDisableIncludePathCheck
= BuildOptions
.DisableIncludePathCheck
737 if GlobalData
.gBinCacheDest
and not GlobalData
.gUseHashCache
:
738 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination must be used together with --hash.")
740 if GlobalData
.gBinCacheSource
and not GlobalData
.gUseHashCache
:
741 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-source must be used together with --hash.")
743 if GlobalData
.gBinCacheDest
and GlobalData
.gBinCacheSource
:
744 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination can not be used together with --binary-source.")
746 if GlobalData
.gBinCacheSource
:
747 BinCacheSource
= os
.path
.normpath(GlobalData
.gBinCacheSource
)
748 if not os
.path
.isabs(BinCacheSource
):
749 BinCacheSource
= mws
.join(self
.WorkspaceDir
, BinCacheSource
)
750 GlobalData
.gBinCacheSource
= BinCacheSource
752 if GlobalData
.gBinCacheSource
is not None:
753 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-source.")
755 if GlobalData
.gBinCacheDest
:
756 BinCacheDest
= os
.path
.normpath(GlobalData
.gBinCacheDest
)
757 if not os
.path
.isabs(BinCacheDest
):
758 BinCacheDest
= mws
.join(self
.WorkspaceDir
, BinCacheDest
)
759 GlobalData
.gBinCacheDest
= BinCacheDest
761 if GlobalData
.gBinCacheDest
is not None:
762 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-destination.")
764 if self
.ConfDirectory
:
765 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
766 ConfDirectoryPath
= os
.path
.normpath(self
.ConfDirectory
)
768 if not os
.path
.isabs(ConfDirectoryPath
):
769 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
770 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
771 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, ConfDirectoryPath
)
773 if "CONF_PATH" in os
.environ
:
774 ConfDirectoryPath
= os
.path
.normcase(os
.path
.normpath(os
.environ
["CONF_PATH"]))
776 # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf
777 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, 'Conf')
778 GlobalData
.gConfDirectory
= ConfDirectoryPath
779 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
780 if not os
.path
.exists(os
.path
.join(GlobalData
.gConfDirectory
, '.cache')):
781 os
.makedirs(os
.path
.join(GlobalData
.gConfDirectory
, '.cache'))
783 self
.BuildDatabase
= self
.Db
.BuildObject
785 self
.ToolChainFamily
= None
786 self
.LoadFixAddress
= 0
787 self
.UniFlag
= BuildOptions
.Flag
788 self
.BuildModules
= []
789 self
.HashSkipModules
= []
791 self
.LaunchPrebuildFlag
= False
792 self
.PlatformBuildPath
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PlatformBuild')
793 if BuildOptions
.CommandLength
:
794 GlobalData
.gCommandMaxLength
= BuildOptions
.CommandLength
796 # print dot character during doing some time-consuming work
797 self
.Progress
= Utils
.Progressor()
798 # print current build environment and configuration
799 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
800 if "PACKAGES_PATH" in os
.environ
:
801 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
802 EdkLogger
.quiet("%-16s = %s" % ("PACKAGES_PATH", os
.path
.normcase(os
.path
.normpath(os
.environ
["PACKAGES_PATH"]))))
803 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
804 if "EDK_TOOLS_BIN" in os
.environ
:
805 # Print the same path style with WORKSPACE env.
806 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_TOOLS_BIN"]))))
807 EdkLogger
.quiet("%-16s = %s" % ("CONF_PATH", GlobalData
.gConfDirectory
))
808 if "PYTHON3_ENABLE" in os
.environ
:
809 PYTHON3_ENABLE
= os
.environ
["PYTHON3_ENABLE"]
810 if PYTHON3_ENABLE
!= "TRUE":
811 PYTHON3_ENABLE
= "FALSE"
812 EdkLogger
.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE
))
813 if "PYTHON_COMMAND" in os
.environ
:
814 EdkLogger
.quiet("%-16s = %s" % ("PYTHON_COMMAND", os
.environ
["PYTHON_COMMAND"]))
818 EdkLogger
.quiet("%-16s = %s" % ("PREBUILD", self
.Prebuild
))
820 EdkLogger
.quiet("%-16s = %s" % ("POSTBUILD", self
.Postbuild
))
822 self
.LaunchPrebuild()
823 self
.TargetTxt
= TargetTxt
824 self
.ToolDef
= ToolDef
825 if not (self
.LaunchPrebuildFlag
and os
.path
.exists(self
.PlatformBuildPath
)):
828 self
.AutoGenMgr
= None
830 os
.chdir(self
.WorkspaceDir
)
831 def StartAutoGen(self
,mqueue
, DataPipe
,SkipAutoGen
,PcdMaList
):
835 feedback_q
= mp
.Queue()
836 file_lock
= mp
.Lock()
837 error_event
= mp
.Event()
838 auto_workers
= [AutoGenWorkerInProcess(mqueue
,DataPipe
.dump_file
,feedback_q
,file_lock
,error_event
) for _
in range(self
.ThreadNumber
)]
839 self
.AutoGenMgr
= AutoGenManager(auto_workers
,feedback_q
,error_event
)
840 self
.AutoGenMgr
.start()
841 for w
in auto_workers
:
843 if PcdMaList
is not None:
844 for PcdMa
in PcdMaList
:
845 PcdMa
.CreateCodeFile(False)
846 PcdMa
.CreateMakeFile(False,GenFfsList
= DataPipe
.Get("FfsCommand").get((PcdMa
.MetaFile
.File
, PcdMa
.Arch
),[]))
848 self
.AutoGenMgr
.join()
849 rt
= self
.AutoGenMgr
.Status
851 except Exception as e
:
852 return False,e
.errcode
854 ## Load configuration
856 # This method will parse target.txt and get the build configurations.
858 def LoadConfiguration(self
):
860 # if no ARCH given in command line, get it from target.txt
861 if not self
.ArchList
:
862 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET_ARCH
]
863 self
.ArchList
= tuple(self
.ArchList
)
865 # if no build target given in command line, get it from target.txt
866 if not self
.BuildTargetList
:
867 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
869 # if no tool chain given in command line, get it from target.txt
870 if not self
.ToolChainList
:
871 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
872 if self
.ToolChainList
is None or len(self
.ToolChainList
) == 0:
873 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
875 # check if the tool chains are defined or not
876 NewToolChainList
= []
877 for ToolChain
in self
.ToolChainList
:
878 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
879 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
881 NewToolChainList
.append(ToolChain
)
882 # if no tool chain available, break the build
883 if len(NewToolChainList
) == 0:
884 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
885 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
887 self
.ToolChainList
= NewToolChainList
890 ToolDefinition
= self
.ToolDef
.ToolsDefTxtDatabase
891 for Tool
in self
.ToolChainList
:
892 if TAB_TOD_DEFINES_FAMILY
not in ToolDefinition
or Tool
not in ToolDefinition
[TAB_TOD_DEFINES_FAMILY
] \
893 or not ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
]:
894 EdkLogger
.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool
)
895 ToolChainFamily
.append(TAB_COMPILER_MSFT
)
897 ToolChainFamily
.append(ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
])
898 self
.ToolChainFamily
= ToolChainFamily
900 if self
.ThreadNumber
is None:
901 self
.ThreadNumber
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
902 if self
.ThreadNumber
== '':
903 self
.ThreadNumber
= 0
905 self
.ThreadNumber
= int(self
.ThreadNumber
, 0)
907 if self
.ThreadNumber
== 0:
909 self
.ThreadNumber
= multiprocessing
.cpu_count()
910 except (ImportError, NotImplementedError):
911 self
.ThreadNumber
= 1
913 if not self
.PlatformFile
:
914 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
916 # Try to find one in current directory
917 WorkingDirectory
= os
.getcwd()
918 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
919 FileNum
= len(FileList
)
921 EdkLogger
.error("build", OPTION_MISSING
,
922 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
924 PlatformFile
= FileList
[0]
926 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
927 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
929 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
931 ## Initialize build configuration
933 # This method will parse DSC file and merge the configurations from
934 # command line and target.txt, then get the final build configurations.
937 # parse target.txt, tools_def.txt, and platform file
938 self
.LoadConfiguration()
940 # Allow case-insensitive for those from command line or configuration file
941 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
943 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
946 def InitPreBuild(self
):
947 self
.LoadConfiguration()
948 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
950 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
951 if self
.BuildTargetList
:
952 GlobalData
.gGlobalDefines
['TARGET'] = self
.BuildTargetList
[0]
954 GlobalData
.gGlobalDefines
['ARCH'] = self
.ArchList
[0]
955 if self
.ToolChainList
:
956 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = self
.ToolChainList
[0]
957 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = self
.ToolChainList
[0]
958 if self
.ToolChainFamily
:
959 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[0]
960 if 'PREBUILD' in GlobalData
.gCommandLineDefines
:
961 self
.Prebuild
= GlobalData
.gCommandLineDefines
.get('PREBUILD')
964 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
965 self
.Prebuild
= str(Platform
.Prebuild
)
969 # Evaluate all arguments and convert arguments that are WORKSPACE
970 # relative paths to absolute paths. Filter arguments that look like
971 # flags or do not follow the file/dir naming rules to avoid false
972 # positives on this conversion.
974 for Arg
in self
.Prebuild
.split():
976 # Do not modify Arg if it looks like a flag or an absolute file path
978 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
979 PrebuildList
.append(Arg
)
982 # Do not modify Arg if it does not look like a Workspace relative
983 # path that starts with a valid package directory name
985 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
986 PrebuildList
.append(Arg
)
989 # If Arg looks like a WORKSPACE relative path, then convert to an
990 # absolute path and check to see if the file exists.
992 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
993 if os
.path
.isfile(Temp
):
995 PrebuildList
.append(Arg
)
996 self
.Prebuild
= ' '.join(PrebuildList
)
997 self
.Prebuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
999 def InitPostBuild(self
):
1000 if 'POSTBUILD' in GlobalData
.gCommandLineDefines
:
1001 self
.Postbuild
= GlobalData
.gCommandLineDefines
.get('POSTBUILD')
1003 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
1004 self
.Postbuild
= str(Platform
.Postbuild
)
1008 # Evaluate all arguments and convert arguments that are WORKSPACE
1009 # relative paths to absolute paths. Filter arguments that look like
1010 # flags or do not follow the file/dir naming rules to avoid false
1011 # positives on this conversion.
1013 for Arg
in self
.Postbuild
.split():
1015 # Do not modify Arg if it looks like a flag or an absolute file path
1017 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1018 PostbuildList
.append(Arg
)
1021 # Do not modify Arg if it does not look like a Workspace relative
1022 # path that starts with a valid package directory name
1024 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1025 PostbuildList
.append(Arg
)
1028 # If Arg looks like a WORKSPACE relative path, then convert to an
1029 # absolute path and check to see if the file exists.
1031 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1032 if os
.path
.isfile(Temp
):
1034 PostbuildList
.append(Arg
)
1035 self
.Postbuild
= ' '.join(PostbuildList
)
1036 self
.Postbuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1038 def PassCommandOption(self
, BuildTarget
, TargetArch
, ToolChain
, PlatformFile
, Target
):
1040 if GlobalData
.gCommand
and isinstance(GlobalData
.gCommand
, list):
1041 BuildStr
+= ' ' + ' '.join(GlobalData
.gCommand
)
1044 ToolChainFlag
= False
1045 PlatformFileFlag
= False
1047 if GlobalData
.gOptions
and not GlobalData
.gOptions
.BuildTarget
:
1049 if GlobalData
.gOptions
and not GlobalData
.gOptions
.TargetArch
:
1051 if GlobalData
.gOptions
and not GlobalData
.gOptions
.ToolChain
:
1052 ToolChainFlag
= True
1053 if GlobalData
.gOptions
and not GlobalData
.gOptions
.PlatformFile
:
1054 PlatformFileFlag
= True
1056 if TargetFlag
and BuildTarget
:
1057 if isinstance(BuildTarget
, list) or isinstance(BuildTarget
, tuple):
1058 BuildStr
+= ' -b ' + ' -b '.join(BuildTarget
)
1059 elif isinstance(BuildTarget
, str):
1060 BuildStr
+= ' -b ' + BuildTarget
1061 if ArchFlag
and TargetArch
:
1062 if isinstance(TargetArch
, list) or isinstance(TargetArch
, tuple):
1063 BuildStr
+= ' -a ' + ' -a '.join(TargetArch
)
1064 elif isinstance(TargetArch
, str):
1065 BuildStr
+= ' -a ' + TargetArch
1066 if ToolChainFlag
and ToolChain
:
1067 if isinstance(ToolChain
, list) or isinstance(ToolChain
, tuple):
1068 BuildStr
+= ' -t ' + ' -t '.join(ToolChain
)
1069 elif isinstance(ToolChain
, str):
1070 BuildStr
+= ' -t ' + ToolChain
1071 if PlatformFileFlag
and PlatformFile
:
1072 if isinstance(PlatformFile
, list) or isinstance(PlatformFile
, tuple):
1073 BuildStr
+= ' -p ' + ' -p '.join(PlatformFile
)
1074 elif isinstance(PlatformFile
, str):
1075 BuildStr
+= ' -p' + PlatformFile
1076 BuildStr
+= ' --conf=' + GlobalData
.gConfDirectory
1078 BuildStr
+= ' ' + Target
1082 def LaunchPrebuild(self
):
1084 EdkLogger
.info("\n- Prebuild Start -\n")
1085 self
.LaunchPrebuildFlag
= True
1087 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1088 # and preserve them for the rest of the main build step, because the child process environment will
1089 # evaporate as soon as it exits, we cannot get it in build step.
1091 PrebuildEnvFile
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PrebuildEnv')
1092 if os
.path
.isfile(PrebuildEnvFile
):
1093 os
.remove(PrebuildEnvFile
)
1094 if os
.path
.isfile(self
.PlatformBuildPath
):
1095 os
.remove(self
.PlatformBuildPath
)
1096 if sys
.platform
== "win32":
1097 args
= ' && '.join((self
.Prebuild
, 'set > ' + PrebuildEnvFile
))
1098 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1100 args
= ' && '.join((self
.Prebuild
, 'env > ' + PrebuildEnvFile
))
1101 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1103 # launch two threads to read the STDOUT and STDERR
1104 EndOfProcedure
= Event()
1105 EndOfProcedure
.clear()
1107 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1108 StdOutThread
.setName("STDOUT-Redirector")
1109 StdOutThread
.setDaemon(False)
1110 StdOutThread
.start()
1113 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1114 StdErrThread
.setName("STDERR-Redirector")
1115 StdErrThread
.setDaemon(False)
1116 StdErrThread
.start()
1117 # waiting for program exit
1124 if Process
.returncode
!= 0 :
1125 EdkLogger
.error("Prebuild", PREBUILD_ERROR
, 'Prebuild process is not success!')
1127 if os
.path
.exists(PrebuildEnvFile
):
1128 f
= open(PrebuildEnvFile
)
1129 envs
= f
.readlines()
1131 envs
= [l
.split("=", 1) for l
in envs
]
1132 envs
= [[I
.strip() for I
in item
] for item
in envs
if len(item
) == 2]
1133 os
.environ
.update(dict(envs
))
1134 EdkLogger
.info("\n- Prebuild Done -\n")
1136 def LaunchPostbuild(self
):
1138 EdkLogger
.info("\n- Postbuild Start -\n")
1139 if sys
.platform
== "win32":
1140 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1142 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1143 # launch two threads to read the STDOUT and STDERR
1144 EndOfProcedure
= Event()
1145 EndOfProcedure
.clear()
1147 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1148 StdOutThread
.setName("STDOUT-Redirector")
1149 StdOutThread
.setDaemon(False)
1150 StdOutThread
.start()
1153 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1154 StdErrThread
.setName("STDERR-Redirector")
1155 StdErrThread
.setDaemon(False)
1156 StdErrThread
.start()
1157 # waiting for program exit
1164 if Process
.returncode
!= 0 :
1165 EdkLogger
.error("Postbuild", POSTBUILD_ERROR
, 'Postbuild process is not success!')
1166 EdkLogger
.info("\n- Postbuild Done -\n")
1168 ## Error handling for hash feature
1170 # On BuildTask error, iterate through the Module Build tracking
1171 # dictionary to determine wheather a module failed to build. Invalidate
1172 # the hash associated with that module by removing it from storage.
1175 def invalidateHash(self
):
1176 # Only for hashing feature
1177 if not GlobalData
.gUseHashCache
:
1180 # GlobalData.gModuleBuildTracking contains only modules or libs that cannot be skipped by hash
1181 for moduleAutoGenObjArch
in GlobalData
.gModuleBuildTracking
.keys():
1182 for moduleAutoGenObj
in GlobalData
.gModuleBuildTracking
[moduleAutoGenObjArch
].keys():
1183 # Skip invalidating for Successful Module/Lib builds
1184 if GlobalData
.gModuleBuildTracking
[moduleAutoGenObjArch
][moduleAutoGenObj
] == 'SUCCESS':
1187 # The module failed to build, failed to start building, or failed the header check test from this point on
1189 # Remove .hash from build
1190 ModuleHashFile
= os
.path
.join(moduleAutoGenObj
.BuildDir
, moduleAutoGenObj
.Name
+ ".hash")
1191 if os
.path
.exists(ModuleHashFile
):
1192 os
.remove(ModuleHashFile
)
1194 # Remove .hash file from cache
1195 if GlobalData
.gBinCacheDest
:
1196 FileDir
= os
.path
.join(GlobalData
.gBinCacheDest
, moduleAutoGenObj
.Arch
, moduleAutoGenObj
.SourceDir
, moduleAutoGenObj
.MetaFile
.BaseName
)
1197 HashFile
= os
.path
.join(FileDir
, moduleAutoGenObj
.Name
+ '.hash')
1198 if os
.path
.exists(HashFile
):
1201 ## Build a module or platform
1203 # Create autogen code and makefile for a module or platform, and the launch
1204 # "make" command to build it
1206 # @param Target The target of build command
1207 # @param Platform The platform file
1208 # @param Module The module file
1209 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1210 # @param ToolChain The name of toolchain to build
1211 # @param Arch The arch of the module/platform
1212 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1213 # for dependent modules/Libraries
1214 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1215 # for dependent modules/Libraries
1217 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False, FfsCommand
=None, PcdMaList
=None):
1218 if AutoGenObject
is None:
1220 if FfsCommand
is None:
1222 # skip file generation for cleanxxx targets, run and fds target
1223 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1224 # for target which must generate AutoGen code and makefile
1226 for m
in AutoGenObject
.GetAllModuleInfo
:
1229 AutoGenObject
.DataPipe
.DataContainer
= {"FfsCommand":FfsCommand
}
1230 self
.Progress
.Start("Generating makefile and code")
1231 data_pipe_file
= os
.path
.join(AutoGenObject
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(AutoGenObject
.Guid
),AutoGenObject
.Arch
))
1232 AutoGenObject
.DataPipe
.dump(data_pipe_file
)
1233 autogen_rt
,errorcode
= self
.StartAutoGen(mqueue
, AutoGenObject
.DataPipe
, self
.SkipAutoGen
, PcdMaList
)
1234 self
.Progress
.Stop("done!")
1236 self
.AutoGenMgr
.TerminateWorkers()
1237 self
.AutoGenMgr
.join(0.1)
1238 raise FatalError(errorcode
)
1239 AutoGenObject
.CreateCodeFile(False)
1240 AutoGenObject
.CreateMakeFile(False)
1242 # always recreate top/platform makefile when clean, just in case of inconsistency
1243 AutoGenObject
.CreateCodeFile(True)
1244 AutoGenObject
.CreateMakeFile(True)
1246 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1247 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1249 BuildCommand
= AutoGenObject
.BuildCommand
1250 if BuildCommand
is None or len(BuildCommand
) == 0:
1251 EdkLogger
.error("build", OPTION_MISSING
,
1252 "No build command found for this module. "
1253 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1254 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1255 ExtraData
=str(AutoGenObject
))
1257 makefile
= GenMake
.BuildFile(AutoGenObject
)._FILE
_NAME
_[GenMake
.gMakeType
]
1265 BuildCommand
= BuildCommand
+ [Target
]
1266 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1267 self
.CreateAsBuiltInf()
1268 if GlobalData
.gBinCacheDest
:
1269 self
.UpdateBuildCache()
1270 self
.BuildModules
= []
1274 if Target
== 'libraries':
1275 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1276 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1277 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1281 if Target
== 'modules':
1282 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1283 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1284 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1285 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1286 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, makefile
)), 'pbuild']
1287 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1288 self
.CreateAsBuiltInf()
1289 if GlobalData
.gBinCacheDest
:
1290 self
.UpdateBuildCache()
1291 self
.BuildModules
= []
1295 if Target
== 'cleanlib':
1296 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1297 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1298 if os
.path
.exists(LibMakefile
):
1299 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1300 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1304 if Target
== 'clean':
1305 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1306 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, makefile
))
1307 if os
.path
.exists(ModMakefile
):
1308 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
1309 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1310 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1311 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1312 if os
.path
.exists(LibMakefile
):
1313 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1314 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1318 if Target
== 'cleanall':
1320 #os.rmdir(AutoGenObject.BuildDir)
1321 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1322 except WindowsError as X
:
1323 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1326 ## Build a module or platform
1328 # Create autogen code and makefile for a module or platform, and the launch
1329 # "make" command to build it
1331 # @param Target The target of build command
1332 # @param Platform The platform file
1333 # @param Module The module file
1334 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1335 # @param ToolChain The name of toolchain to build
1336 # @param Arch The arch of the module/platform
1337 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1338 # for dependent modules/Libraries
1339 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1340 # for dependent modules/Libraries
1342 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1343 if AutoGenObject
is None:
1346 # skip file generation for cleanxxx targets, run and fds target
1347 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1348 # for target which must generate AutoGen code and makefile
1349 if not self
.SkipAutoGen
or Target
== 'genc':
1350 self
.Progress
.Start("Generating code")
1351 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1352 self
.Progress
.Stop("done!")
1353 if Target
== "genc":
1356 if not self
.SkipAutoGen
or Target
== 'genmake':
1357 self
.Progress
.Start("Generating makefile")
1358 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1359 #AutoGenObject.CreateAsBuiltInf()
1360 self
.Progress
.Stop("done!")
1361 if Target
== "genmake":
1364 # always recreate top/platform makefile when clean, just in case of inconsistency
1365 AutoGenObject
.CreateCodeFile(True)
1366 AutoGenObject
.CreateMakeFile(True)
1368 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1369 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1371 BuildCommand
= AutoGenObject
.BuildCommand
1372 if BuildCommand
is None or len(BuildCommand
) == 0:
1373 EdkLogger
.error("build", OPTION_MISSING
,
1374 "No build command found for this module. "
1375 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1376 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1377 ExtraData
=str(AutoGenObject
))
1382 BuildCommand
= BuildCommand
+ [Target
]
1383 AutoGenObject
.BuildTime
= LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1384 self
.CreateAsBuiltInf()
1385 if GlobalData
.gBinCacheDest
:
1386 self
.UpdateBuildCache()
1387 self
.BuildModules
= []
1392 if GenFdsApi(AutoGenObject
.GenFdsCommandDict
, self
.Db
):
1393 EdkLogger
.error("build", COMMAND_FAILURE
)
1401 if Target
== 'libraries':
1408 if Target
== 'cleanall':
1410 #os.rmdir(AutoGenObject.BuildDir)
1411 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1412 except WindowsError as X
:
1413 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1416 ## Rebase module image and Get function address for the input module list.
1418 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1420 AddrIsOffset
= False
1421 for InfFile
in ModuleList
:
1422 sys
.stdout
.write (".")
1424 ModuleInfo
= ModuleList
[InfFile
]
1425 ModuleName
= ModuleInfo
.BaseName
1426 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1427 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1428 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1430 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1432 # Update Image to new BaseAddress by GenFw tool
1434 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1435 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1438 # Set new address to the section header only for SMM driver.
1440 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1441 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1443 # Collect function address from Map file
1445 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1447 if os
.path
.exists(ImageMapTable
):
1448 OrigImageBaseAddress
= 0
1449 ImageMap
= open(ImageMapTable
, 'r')
1450 for LinStr
in ImageMap
:
1451 if len (LinStr
.strip()) == 0:
1454 # Get the preferred address set on link time.
1456 if LinStr
.find ('Preferred load address is') != -1:
1457 StrList
= LinStr
.split()
1458 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1460 StrList
= LinStr
.split()
1461 if len (StrList
) > 4:
1462 if StrList
[3] == 'f' or StrList
[3] == 'F':
1464 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1465 FunctionList
.append ((Name
, RelativeAddress
))
1469 # Add general information.
1472 MapBuffer
.append('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1474 MapBuffer
.append('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1476 MapBuffer
.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1478 # Add guid and general seciton section.
1480 TextSectionAddress
= 0
1481 DataSectionAddress
= 0
1482 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1483 if SectionHeader
[0] == '.text':
1484 TextSectionAddress
= SectionHeader
[1]
1485 elif SectionHeader
[0] in ['.data', '.sdata']:
1486 DataSectionAddress
= SectionHeader
[1]
1488 MapBuffer
.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1490 MapBuffer
.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1492 # Add debug image full path.
1494 MapBuffer
.append('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1496 # Add function address
1498 for Function
in FunctionList
:
1500 MapBuffer
.append(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1502 MapBuffer
.append(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1506 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1509 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1511 ## Collect MAP information of all FVs
1513 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1515 # First get the XIP base address for FV map file.
1516 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1517 GuidName
= re
.compile(r
"\(GUID=[-a-fA-F0-9]+")
1518 for FvName
in Wa
.FdfProfile
.FvDict
:
1519 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1520 if not os
.path
.exists(FvMapBuffer
):
1522 FvMap
= open(FvMapBuffer
, 'r')
1523 #skip FV size information
1529 MatchGuid
= GuidPattern
.match(Line
)
1530 if MatchGuid
is not None:
1532 # Replace GUID with module name
1534 GuidString
= MatchGuid
.group()
1535 if GuidString
.upper() in ModuleList
:
1536 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1537 MapBuffer
.append(Line
)
1539 # Add the debug image full path.
1541 MatchGuid
= GuidName
.match(Line
)
1542 if MatchGuid
is not None:
1543 GuidString
= MatchGuid
.group().split("=")[1]
1544 if GuidString
.upper() in ModuleList
:
1545 MapBuffer
.append('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1549 ## Collect MAP information of all modules
1551 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1552 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1554 PatchEfiImageList
= []
1562 # reserve 4K size in SMRAM to make SMM module address not from 0.
1564 for ModuleGuid
in ModuleList
:
1565 Module
= ModuleList
[ModuleGuid
]
1566 GlobalData
.gProcessingFile
= "%s [%s, %s, %s]" % (Module
.MetaFile
, Module
.Arch
, Module
.ToolChain
, Module
.BuildTarget
)
1568 OutputImageFile
= ''
1569 for ResultFile
in Module
.CodaTargetList
:
1570 if str(ResultFile
.Target
).endswith('.efi'):
1572 # module list for PEI, DXE, RUNTIME and SMM
1574 OutputImageFile
= os
.path
.join(Module
.OutputDir
, Module
.Name
+ '.efi')
1575 ImageClass
= PeImageClass (OutputImageFile
)
1576 if not ImageClass
.IsValid
:
1577 EdkLogger
.error("build", FILE_PARSE_FAILURE
, ExtraData
=ImageClass
.ErrorInfo
)
1578 ImageInfo
= PeImageInfo(Module
.Name
, Module
.Guid
, Module
.Arch
, Module
.OutputDir
, Module
.DebugDir
, ImageClass
)
1579 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
]:
1580 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1581 PeiSize
+= ImageInfo
.Image
.Size
1582 elif Module
.ModuleType
in [EDK_COMPONENT_TYPE_BS_DRIVER
, SUP_MODULE_DXE_DRIVER
, SUP_MODULE_UEFI_DRIVER
]:
1583 BtModuleList
[Module
.MetaFile
] = ImageInfo
1584 BtSize
+= ImageInfo
.Image
.Size
1585 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
]:
1586 RtModuleList
[Module
.MetaFile
] = ImageInfo
1587 RtSize
+= ImageInfo
.Image
.Size
1588 elif Module
.ModuleType
in [SUP_MODULE_SMM_CORE
, SUP_MODULE_DXE_SMM_DRIVER
, SUP_MODULE_MM_STANDALONE
, SUP_MODULE_MM_CORE_STANDALONE
]:
1589 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1590 SmmSize
+= ImageInfo
.Image
.Size
1591 if Module
.ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
1592 PiSpecVersion
= Module
.Module
.Specification
.get('PI_SPECIFICATION_VERSION', '0x00000000')
1593 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1594 if int(PiSpecVersion
, 16) < 0x0001000A:
1595 BtModuleList
[Module
.MetaFile
] = ImageInfo
1596 BtSize
+= ImageInfo
.Image
.Size
1599 # EFI image is final target.
1600 # Check EFI image contains patchable FixAddress related PCDs.
1602 if OutputImageFile
!= '':
1603 ModuleIsPatch
= False
1604 for Pcd
in Module
.ModulePcdList
:
1605 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1606 ModuleIsPatch
= True
1608 if not ModuleIsPatch
:
1609 for Pcd
in Module
.LibraryPcdList
:
1610 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1611 ModuleIsPatch
= True
1614 if not ModuleIsPatch
:
1617 # Module includes the patchable load fix address PCDs.
1618 # It will be fixed up later.
1620 PatchEfiImageList
.append (OutputImageFile
)
1623 # Get Top Memory address
1625 ReservedRuntimeMemorySize
= 0
1626 TopMemoryAddress
= 0
1627 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1628 TopMemoryAddress
= 0
1630 TopMemoryAddress
= self
.LoadFixAddress
1631 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1632 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1635 # Patch FixAddress related PCDs into EFI image
1637 for EfiImage
in PatchEfiImageList
:
1638 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1639 if not os
.path
.exists(EfiImageMap
):
1642 # Get PCD offset in EFI image by GenPatchPcdTable function
1644 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1646 # Patch real PCD value by PatchPcdValue tool
1648 for PcdInfo
in PcdTable
:
1650 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1651 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
// 0x1000))
1652 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1653 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
// 0x1000))
1654 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1655 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
// 0x1000))
1656 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1657 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
// 0x1000))
1658 if ReturnValue
!= 0:
1659 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1661 MapBuffer
.append('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
// 0x1000))
1662 MapBuffer
.append('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
// 0x1000))
1663 MapBuffer
.append('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
// 0x1000))
1664 if len (SmmModuleList
) > 0:
1665 MapBuffer
.append('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
// 0x1000))
1667 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1668 BtBaseAddr
= TopMemoryAddress
- RtSize
1669 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1671 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1672 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1673 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1674 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
=False, ModeIsSmm
=True)
1675 MapBuffer
.append('\n\n')
1676 sys
.stdout
.write ("\n")
1679 ## Save platform Map file
1681 def _SaveMapFile (self
, MapBuffer
, Wa
):
1683 # Map file path is got.
1685 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1687 # Save address map into MAP file.
1689 SaveFileOnChange(MapFilePath
, ''.join(MapBuffer
), False)
1690 if self
.LoadFixAddress
!= 0:
1691 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath
))
1694 ## Build active platform for different build targets and different tool chains
1696 def _BuildPlatform(self
):
1697 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1698 for BuildTarget
in self
.BuildTargetList
:
1699 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1701 for ToolChain
in self
.ToolChainList
:
1702 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1703 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1704 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1706 Wa
= WorkspaceAutoGen(
1723 self
.Fdf
= Wa
.FdfFile
1724 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1725 self
.BuildReport
.AddPlatformReport(Wa
)
1726 self
.Progress
.Stop("done!")
1728 # Add ffs build to makefile
1730 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1731 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1733 for Arch
in Wa
.ArchList
:
1735 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1736 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1737 for Module
in Pa
.Platform
.Modules
:
1738 # Get ModuleAutoGen object to generate C code file and makefile
1739 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1743 Ma
.PlatformInfo
= Pa
1745 PcdMaList
.append(Ma
)
1746 self
.BuildModules
.append(Ma
)
1747 self
._BuildPa
(self
.Target
, Pa
, FfsCommand
=CmdListDict
,PcdMaList
=PcdMaList
)
1749 # Create MAP file when Load Fix Address is enabled.
1750 if self
.Target
in ["", "all", "fds"]:
1751 for Arch
in Wa
.ArchList
:
1752 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1754 # Check whether the set fix address is above 4G for 32bit image.
1756 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1757 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")
1762 for Pa
in Wa
.AutoGenObjectList
:
1763 for Ma
in Pa
.ModuleAutoGenList
:
1766 if not Ma
.IsLibrary
:
1767 ModuleList
[Ma
.Guid
.upper()] = Ma
1770 if self
.LoadFixAddress
!= 0:
1772 # Rebase module to the preferred memory address before GenFds
1774 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1777 # create FDS again for the updated EFI image
1779 self
._Build
("fds", Wa
)
1781 # Create MAP file for all platform FVs after GenFds.
1783 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1785 # Save MAP buffer into MAP file.
1787 self
._SaveMapFile
(MapBuffer
, Wa
)
1789 ## Build active module for different build targets, different tool chains and different archs
1791 def _BuildModule(self
):
1792 for BuildTarget
in self
.BuildTargetList
:
1793 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1795 for ToolChain
in self
.ToolChainList
:
1796 WorkspaceAutoGenTime
= time
.time()
1797 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1798 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1799 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1802 # module build needs platform build information, so get platform
1805 Wa
= WorkspaceAutoGen(
1823 self
.Fdf
= Wa
.FdfFile
1824 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1825 Wa
.CreateMakeFile(False)
1826 # Add ffs build to makefile
1828 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1829 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1830 self
.Progress
.Stop("done!")
1832 ExitFlag
= threading
.Event()
1834 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1835 for Arch
in Wa
.ArchList
:
1836 AutoGenStart
= time
.time()
1837 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1838 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1839 for Module
in Pa
.Platform
.Modules
:
1840 if self
.ModuleFile
.Dir
== Module
.Dir
and self
.ModuleFile
.Name
== Module
.Name
:
1841 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1845 if Ma
.CanSkipbyHash():
1846 self
.HashSkipModules
.append(Ma
)
1847 if GlobalData
.gBinCacheSource
:
1848 EdkLogger
.quiet("cache hit: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1851 if GlobalData
.gBinCacheSource
:
1852 EdkLogger
.quiet("cache miss: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1853 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1854 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1855 # for target which must generate AutoGen code and makefile
1856 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1857 self
.Progress
.Start("Generating code")
1858 Ma
.CreateCodeFile(True)
1859 self
.Progress
.Stop("done!")
1860 if self
.Target
== "genc":
1862 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1863 self
.Progress
.Start("Generating makefile")
1864 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
1865 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
1866 del CmdListDict
[Module
.File
, Arch
]
1868 Ma
.CreateMakeFile(True)
1869 self
.Progress
.Stop("done!")
1870 if self
.Target
== "genmake":
1872 self
.BuildModules
.append(Ma
)
1873 # Initialize all modules in tracking to 'FAIL'
1874 if Ma
.Arch
not in GlobalData
.gModuleBuildTracking
:
1875 GlobalData
.gModuleBuildTracking
[Ma
.Arch
] = dict()
1876 if Ma
not in GlobalData
.gModuleBuildTracking
[Ma
.Arch
]:
1877 GlobalData
.gModuleBuildTracking
[Ma
.Arch
][Ma
] = 'FAIL'
1878 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1879 MakeStart
= time
.time()
1880 for Ma
in self
.BuildModules
:
1881 if not Ma
.IsBinaryModule
:
1882 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
1883 # Break build if any build thread has error
1884 if BuildTask
.HasError():
1885 # we need a full version of makefile for platform
1887 BuildTask
.WaitForComplete()
1888 self
.invalidateHash()
1889 Pa
.CreateMakeFile(False)
1890 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1891 # Start task scheduler
1892 if not BuildTask
.IsOnGoing():
1893 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1895 # in case there's an interruption. we need a full version of makefile for platform
1896 Pa
.CreateMakeFile(False)
1897 if BuildTask
.HasError():
1898 self
.invalidateHash()
1899 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1900 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1902 MakeContiue
= time
.time()
1904 BuildTask
.WaitForComplete()
1905 self
.CreateAsBuiltInf()
1906 if GlobalData
.gBinCacheDest
:
1907 self
.UpdateBuildCache()
1908 self
.BuildModules
= []
1909 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1910 if BuildTask
.HasError():
1911 self
.invalidateHash()
1912 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1914 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1919 "Module for [%s] is not a component of active platform."\
1920 " Please make sure that the ARCH and inf file path are"\
1921 " given in the same as in [%s]" % \
1922 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1923 ExtraData
=self
.ModuleFile
1925 # Create MAP file when Load Fix Address is enabled.
1926 if self
.Target
== "fds" and self
.Fdf
:
1927 for Arch
in Wa
.ArchList
:
1929 # Check whether the set fix address is above 4G for 32bit image.
1931 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1932 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")
1937 for Pa
in Wa
.AutoGenObjectList
:
1938 for Ma
in Pa
.ModuleAutoGenList
:
1941 if not Ma
.IsLibrary
:
1942 ModuleList
[Ma
.Guid
.upper()] = Ma
1945 if self
.LoadFixAddress
!= 0:
1947 # Rebase module to the preferred memory address before GenFds
1949 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1951 # create FDS again for the updated EFI image
1953 GenFdsStart
= time
.time()
1954 self
._Build
("fds", Wa
)
1955 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
1957 # Create MAP file for all platform FVs after GenFds.
1959 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1961 # Save MAP buffer into MAP file.
1963 self
._SaveMapFile
(MapBuffer
, Wa
)
1964 self
.invalidateHash()
1966 def _GenFfsCmd(self
,ArchList
):
1967 # convert dictionary of Cmd:(Inf,Arch)
1968 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
1969 CmdSetDict
= defaultdict(set)
1970 GenFfsDict
= GenFds
.GenFfsMakefile('', GlobalData
.gFdfParser
, self
, ArchList
, GlobalData
)
1971 for Cmd
in GenFfsDict
:
1972 tmpInf
, tmpArch
= GenFfsDict
[Cmd
]
1973 CmdSetDict
[tmpInf
, tmpArch
].add(Cmd
)
1976 ## Build a platform in multi-thread mode
1978 def _MultiThreadBuildPlatform(self
):
1979 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1980 for BuildTarget
in self
.BuildTargetList
:
1981 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1983 for ToolChain
in self
.ToolChainList
:
1984 WorkspaceAutoGenTime
= time
.time()
1985 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1986 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1987 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1989 Wa
= WorkspaceAutoGen(
2006 self
.Fdf
= Wa
.FdfFile
2007 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
2008 self
.BuildReport
.AddPlatformReport(Wa
)
2009 Wa
.CreateMakeFile(False)
2011 # Add ffs build to makefile
2013 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
2014 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
2016 # multi-thread exit flag
2017 ExitFlag
= threading
.Event()
2019 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
2020 self
.BuildModules
= []
2021 for Arch
in Wa
.ArchList
:
2023 AutoGenStart
= time
.time()
2024 GlobalData
.gGlobalDefines
['ARCH'] = Arch
2025 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
2029 for Inf
in Pa
.Platform
.Modules
:
2030 ModuleList
.append(Inf
)
2031 # Add the INF only list in FDF
2032 if GlobalData
.gFdfParser
is not None:
2033 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
2034 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
2035 if Inf
in Pa
.Platform
.Modules
:
2037 ModuleList
.append(Inf
)
2038 Pa
.DataPipe
.DataContainer
= {"FfsCommand":CmdListDict
}
2039 Pa
.DataPipe
.DataContainer
= {"Workspace_timestamp": Wa
._SrcTimeStamp
}
2040 for Module
in ModuleList
:
2041 # Get ModuleAutoGen object to generate C code file and makefile
2042 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2047 Ma
.PlatformInfo
= Pa
2049 PcdMaList
.append(Ma
)
2050 if Ma
.CanSkipbyHash():
2051 self
.HashSkipModules
.append(Ma
)
2052 if GlobalData
.gBinCacheSource
:
2053 EdkLogger
.quiet("cache hit: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
2056 if GlobalData
.gBinCacheSource
:
2057 EdkLogger
.quiet("cache miss: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
2059 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
2060 # for target which must generate AutoGen code and makefile
2062 self
.BuildModules
.append(Ma
)
2063 # Initialize all modules in tracking to 'FAIL'
2064 if Ma
.Arch
not in GlobalData
.gModuleBuildTracking
:
2065 GlobalData
.gModuleBuildTracking
[Ma
.Arch
] = dict()
2066 if Ma
not in GlobalData
.gModuleBuildTracking
[Ma
.Arch
]:
2067 GlobalData
.gModuleBuildTracking
[Ma
.Arch
][Ma
] = 'FAIL'
2069 for m
in Pa
.GetAllModuleInfo
:
2071 data_pipe_file
= os
.path
.join(Pa
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(Pa
.Guid
),Pa
.Arch
))
2072 Pa
.DataPipe
.dump(data_pipe_file
)
2073 autogen_rt
, errorcode
= self
.StartAutoGen(mqueue
, Pa
.DataPipe
, self
.SkipAutoGen
, PcdMaList
)
2074 self
.Progress
.Stop("done!")
2075 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
2077 self
.AutoGenMgr
.TerminateWorkers()
2078 self
.AutoGenMgr
.join(0.1)
2079 raise FatalError(errorcode
)
2080 for Arch
in Wa
.ArchList
:
2081 MakeStart
= time
.time()
2082 for Ma
in self
.BuildModules
:
2083 # Generate build task for the module
2084 if not Ma
.IsBinaryModule
:
2085 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
2086 # Break build if any build thread has error
2087 if BuildTask
.HasError():
2088 # we need a full version of makefile for platform
2090 BuildTask
.WaitForComplete()
2091 self
.invalidateHash()
2092 Pa
.CreateMakeFile(False)
2093 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2094 # Start task scheduler
2095 if not BuildTask
.IsOnGoing():
2096 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
2098 # in case there's an interruption. we need a full version of makefile for platform
2099 Pa
.CreateMakeFile(False)
2100 if BuildTask
.HasError():
2101 self
.invalidateHash()
2102 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2103 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
2105 MakeContiue
= time
.time()
2109 # All modules have been put in build tasks queue. Tell task scheduler
2110 # to exit if all tasks are completed
2113 BuildTask
.WaitForComplete()
2114 self
.CreateAsBuiltInf()
2115 if GlobalData
.gBinCacheDest
:
2116 self
.UpdateBuildCache()
2117 self
.BuildModules
= []
2118 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2120 # Check for build error, and raise exception if one
2121 # has been signaled.
2123 if BuildTask
.HasError():
2124 self
.invalidateHash()
2125 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2127 # Create MAP file when Load Fix Address is enabled.
2128 if self
.Target
in ["", "all", "fds"]:
2129 for Arch
in Wa
.ArchList
:
2131 # Check whether the set fix address is above 4G for 32bit image.
2133 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2134 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")
2139 for Pa
in Wa
.AutoGenObjectList
:
2140 for Ma
in Pa
.ModuleAutoGenList
:
2143 if not Ma
.IsLibrary
:
2144 ModuleList
[Ma
.Guid
.upper()] = Ma
2146 # Rebase module to the preferred memory address before GenFds
2149 if self
.LoadFixAddress
!= 0:
2150 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2154 # Generate FD image if there's a FDF file found
2156 GenFdsStart
= time
.time()
2157 if GenFdsApi(Wa
.GenFdsCommandDict
, self
.Db
):
2158 EdkLogger
.error("build", COMMAND_FAILURE
)
2161 # Create MAP file for all platform FVs after GenFds.
2163 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2164 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2166 # Save MAP buffer into MAP file.
2168 self
._SaveMapFile
(MapBuffer
, Wa
)
2169 self
.invalidateHash()
2171 ## Generate GuidedSectionTools.txt in the FV directories.
2173 def CreateGuidedSectionToolsFile(self
):
2174 for BuildTarget
in self
.BuildTargetList
:
2175 for ToolChain
in self
.ToolChainList
:
2176 Wa
= WorkspaceAutoGen(
2193 if not os
.path
.exists(FvDir
):
2196 for Arch
in self
.ArchList
:
2197 # Build up the list of supported architectures for this build
2198 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
2200 # Look through the tool definitions for GUIDed tools
2202 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.items():
2203 if attrib
.upper().endswith('_GUID'):
2204 split
= attrib
.split('_')
2205 thisPrefix
= '_'.join(split
[0:3]) + '_'
2206 if thisPrefix
== prefix
:
2207 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
2210 path
= '_'.join(split
[0:4]) + '_PATH'
2211 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2212 path
= self
.GetFullPathOfTool(path
)
2213 guidAttribs
.append((guid
, toolName
, path
))
2215 # Write out GuidedSecTools.txt
2216 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2217 toolsFile
= open(toolsFile
, 'wt')
2218 for guidedSectionTool
in guidAttribs
:
2219 print(' '.join(guidedSectionTool
), file=toolsFile
)
2222 ## Returns the full path of the tool.
2224 def GetFullPathOfTool (self
, tool
):
2225 if os
.path
.exists(tool
):
2226 return os
.path
.realpath(tool
)
2228 # We need to search for the tool using the
2229 # PATH environment variable.
2230 for dirInPath
in os
.environ
['PATH'].split(os
.pathsep
):
2231 foundPath
= os
.path
.join(dirInPath
, tool
)
2232 if os
.path
.exists(foundPath
):
2233 return os
.path
.realpath(foundPath
)
2235 # If the tool was not found in the path then we just return
2239 ## Launch the module or platform build
2242 if not self
.ModuleFile
:
2243 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2244 self
.SpawnMode
= False
2245 self
._BuildPlatform
()
2247 self
._MultiThreadBuildPlatform
()
2248 self
.CreateGuidedSectionToolsFile()
2250 self
.SpawnMode
= False
2253 if self
.Target
== 'cleanall':
2254 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2256 def CreateAsBuiltInf(self
):
2257 for Module
in self
.BuildModules
:
2258 Module
.CreateAsBuiltInf()
2260 def UpdateBuildCache(self
):
2263 for Module
in self
.BuildModules
:
2264 Module
.CopyModuleToCache()
2265 all_mod_set
.add(Module
)
2266 for Module
in self
.HashSkipModules
:
2267 Module
.CopyModuleToCache()
2268 all_mod_set
.add(Module
)
2269 for Module
in all_mod_set
:
2270 for lib
in Module
.LibraryAutoGenList
:
2271 all_lib_set
.add(lib
)
2272 for lib
in all_lib_set
:
2273 lib
.CopyModuleToCache()
2276 self
.HashSkipModules
= []
2277 ## Do some clean-up works when error occurred
2278 def Relinquish(self
):
2279 OldLogLevel
= EdkLogger
.GetLevel()
2280 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2281 Utils
.Progressor
.Abort()
2282 if self
.SpawnMode
== True:
2284 EdkLogger
.SetLevel(OldLogLevel
)
2286 def ParseDefines(DefineList
=[]):
2288 if DefineList
is not None:
2289 for Define
in DefineList
:
2290 DefineTokenList
= Define
.split("=", 1)
2291 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2292 EdkLogger
.error('build', FORMAT_INVALID
,
2293 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2294 ExtraData
=DefineTokenList
[0])
2296 if len(DefineTokenList
) == 1:
2297 DefineDict
[DefineTokenList
[0]] = "TRUE"
2299 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2303 def SingleCheckCallback(option
, opt_str
, value
, parser
):
2304 if option
not in gParamCheck
:
2305 setattr(parser
.values
, option
.dest
, value
)
2306 gParamCheck
.append(option
)
2308 parser
.error("Option %s only allows one instance in command line!" % option
)
2310 def LogBuildTime(Time
):
2313 TimeDur
= time
.gmtime(Time
)
2314 if TimeDur
.tm_yday
> 1:
2315 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2317 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2322 ## Parse command line options
2324 # Using standard Python module optparse to parse command line option of this tool.
2326 # @retval Opt A optparse.Values object containing the parsed options
2327 # @retval Args Target of build command
2329 def MyOptionParser():
2330 Parser
= OptionParser(description
=__copyright__
, version
=__version__
, prog
="build.exe", usage
="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
2331 Parser
.add_option("-a", "--arch", action
="append", type="choice", choices
=['IA32', 'X64', 'EBC', 'ARM', 'AARCH64'], dest
="TargetArch",
2332 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.")
2333 Parser
.add_option("-p", "--platform", action
="callback", type="string", dest
="PlatformFile", callback
=SingleCheckCallback
,
2334 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
2335 Parser
.add_option("-m", "--module", action
="callback", type="string", dest
="ModuleFile", callback
=SingleCheckCallback
,
2336 help="Build the module specified by the INF file name argument.")
2337 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
2339 Parser
.add_option("-t", "--tagname", action
="append", type="string", dest
="ToolChain",
2340 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
2341 Parser
.add_option("-x", "--sku-id", action
="callback", type="string", dest
="SkuId", callback
=SingleCheckCallback
,
2342 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
2344 Parser
.add_option("-n", action
="callback", type="int", dest
="ThreadNumber", callback
=SingleCheckCallback
,
2345 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 "\
2346 "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.")
2348 Parser
.add_option("-f", "--fdf", action
="callback", type="string", dest
="FdfFile", callback
=SingleCheckCallback
,
2349 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
2350 Parser
.add_option("-r", "--rom-image", action
="append", type="string", dest
="RomImage", default
=[],
2351 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
2352 Parser
.add_option("-i", "--fv-image", action
="append", type="string", dest
="FvImage", default
=[],
2353 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
2354 Parser
.add_option("-C", "--capsule-image", action
="append", type="string", dest
="CapName", default
=[],
2355 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
2356 Parser
.add_option("-u", "--skip-autogen", action
="store_true", dest
="SkipAutoGen", help="Skip AutoGen step.")
2357 Parser
.add_option("-e", "--re-parse", action
="store_true", dest
="Reparse", help="Re-parse all meta-data files.")
2359 Parser
.add_option("-c", "--case-insensitive", action
="store_true", dest
="CaseInsensitive", default
=False, help="Don't check case of file name.")
2361 Parser
.add_option("-w", "--warning-as-error", action
="store_true", dest
="WarningAsError", help="Treat warning in tools as error.")
2362 Parser
.add_option("-j", "--log", action
="store", dest
="LogFile", help="Put log in specified file as well as on console.")
2364 Parser
.add_option("-s", "--silent", action
="store_true", type=None, dest
="SilentMode",
2365 help="Make use of silent mode of (n)make.")
2366 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
2367 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
2368 "including library instances selected, final dependency expression, "\
2369 "and warning messages, etc.")
2370 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
2371 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
2373 Parser
.add_option("-y", "--report-file", action
="store", dest
="ReportFile", help="Create/overwrite the report to the specified filename.")
2374 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
=[],
2375 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]. "\
2376 "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]")
2377 Parser
.add_option("-F", "--flag", action
="store", type="string", dest
="Flag",
2378 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. "\
2379 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
2380 "will override the setting in [BuildOptions] section of platform DSC.")
2381 Parser
.add_option("-N", "--no-cache", action
="store_true", dest
="DisableCache", default
=False, help="Disable build cache mechanism")
2382 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
2383 Parser
.add_option("--check-usage", action
="store_true", dest
="CheckUsage", default
=False, help="Check usage content of entries listed in INF file.")
2384 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
2385 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
2386 Parser
.add_option("-l", "--cmd-len", action
="store", type="int", dest
="CommandLength", help="Specify the maximum line length of build command. Default is 4096.")
2387 Parser
.add_option("--hash", action
="store_true", dest
="UseHashCache", default
=False, help="Enable hash-based caching during build process.")
2388 Parser
.add_option("--binary-destination", action
="store", type="string", dest
="BinCacheDest", help="Generate a cache of binary files in the specified directory.")
2389 Parser
.add_option("--binary-source", action
="store", type="string", dest
="BinCacheSource", help="Consume a cache of binary files from the specified directory.")
2390 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
2391 Parser
.add_option("--disable-include-path-check", action
="store_true", dest
="DisableIncludePathCheck", default
=False, help="Disable the include path check for outside of package.")
2392 (Opt
, Args
) = Parser
.parse_args()
2395 ## Tool entrance method
2397 # This method mainly dispatch specific methods per the command line options.
2398 # If no error found, return zero value so the caller of this tool can know
2399 # if it's executed successfully or not.
2401 # @retval 0 Tool was successful
2402 # @retval 1 Tool failed
2405 StartTime
= time
.time()
2407 # Initialize log system
2408 EdkLogger
.Initialize()
2409 GlobalData
.gCommand
= sys
.argv
[1:]
2411 # Parse the options and args
2413 (Option
, Target
) = MyOptionParser()
2414 GlobalData
.gOptions
= Option
2415 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2418 if Option
.verbose
is not None:
2419 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2420 elif Option
.quiet
is not None:
2421 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2422 elif Option
.debug
is not None:
2423 EdkLogger
.SetLevel(Option
.debug
+ 1)
2425 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2427 if Option
.LogFile
is not None:
2428 EdkLogger
.SetLogFile(Option
.LogFile
)
2430 if Option
.WarningAsError
== True:
2431 EdkLogger
.SetWarningAsError()
2433 if platform
.platform().find("Windows") >= 0:
2434 GlobalData
.gIsWindows
= True
2436 GlobalData
.gIsWindows
= False
2438 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2439 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2444 if len(Target
) == 0:
2446 elif len(Target
) >= 2:
2447 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2448 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2450 Target
= Target
[0].lower()
2452 if Target
not in gSupportedTarget
:
2453 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2454 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2457 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2460 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2462 Workspace
= os
.getenv("WORKSPACE")
2464 # Get files real name in workspace dir
2466 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2468 WorkingDirectory
= os
.getcwd()
2469 if not Option
.ModuleFile
:
2470 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2471 FileNum
= len(FileList
)
2473 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2474 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2476 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2478 if Option
.ModuleFile
:
2479 if os
.path
.isabs (Option
.ModuleFile
):
2480 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2481 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2482 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2483 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2485 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2487 if Option
.PlatformFile
is not None:
2488 if os
.path
.isabs (Option
.PlatformFile
):
2489 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2490 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2491 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2493 if Option
.FdfFile
is not None:
2494 if os
.path
.isabs (Option
.FdfFile
):
2495 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2496 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2497 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2498 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2500 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2502 if Option
.Flag
is not None and Option
.Flag
not in ['-c', '-s']:
2503 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2505 MyBuild
= Build(Target
, Workspace
, Option
)
2506 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2507 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2511 # All job done, no error found and no exception raised
2514 except FatalError
as X
:
2515 if MyBuild
is not None:
2516 # for multi-thread build exits safely
2517 MyBuild
.Relinquish()
2518 if Option
is not None and Option
.debug
is not None:
2519 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2520 ReturnCode
= X
.args
[0]
2521 except Warning as X
:
2522 # error from Fdf parser
2523 if MyBuild
is not None:
2524 # for multi-thread build exits safely
2525 MyBuild
.Relinquish()
2526 if Option
is not None and Option
.debug
is not None:
2527 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2529 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2530 ReturnCode
= FORMAT_INVALID
2531 except KeyboardInterrupt:
2532 if MyBuild
is not None:
2534 # for multi-thread build exits safely
2535 MyBuild
.Relinquish()
2536 ReturnCode
= ABORT_ERROR
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 if MyBuild
is not None:
2541 # for multi-thread build exits safely
2542 MyBuild
.Relinquish()
2544 # try to get the meta-file from the object causing exception
2545 Tb
= sys
.exc_info()[-1]
2546 MetaFile
= GlobalData
.gProcessingFile
2547 while Tb
is not None:
2548 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2549 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2554 "Unknown fatal error when processing [%s]" % MetaFile
,
2555 ExtraData
="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR
,
2558 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2559 ReturnCode
= CODE_ERROR
2561 Utils
.Progressor
.Abort()
2562 Utils
.ClearDuplicatedInf()
2566 MyBuild
.LaunchPostbuild()
2569 Conclusion
= "Failed"
2570 elif ReturnCode
== ABORT_ERROR
:
2571 Conclusion
= "Aborted"
2573 Conclusion
= "Failed"
2574 FinishTime
= time
.time()
2575 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2576 BuildDurationStr
= ""
2577 if BuildDuration
.tm_yday
> 1:
2578 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2580 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2581 if MyBuild
is not None:
2583 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2585 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2586 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2587 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2588 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2591 if __name__
== '__main__':
2593 mp
.set_start_method('spawn')
2597 ## 0-127 is a safe return range, and 1 is a standard default error
2598 if r
< 0 or r
> 127: r
= 1