2 # build a platform or a module
4 # Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
5 # Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
6 # Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
8 # SPDX-License-Identifier: BSD-2-Clause-Patent
14 from __future__
import print_function
15 from __future__
import absolute_import
16 import os
.path
as path
24 import multiprocessing
25 from threading
import Thread
,Event
,BoundedSemaphore
27 from subprocess
import Popen
,PIPE
28 from collections
import OrderedDict
, defaultdict
29 from Common
.buildoptions
import BuildOption
,BuildTarget
30 from AutoGen
.PlatformAutoGen
import PlatformAutoGen
31 from AutoGen
.ModuleAutoGen
import ModuleAutoGen
32 from AutoGen
.WorkspaceAutoGen
import WorkspaceAutoGen
33 from AutoGen
.AutoGenWorker
import AutoGenWorkerInProcess
,AutoGenManager
,\
35 from AutoGen
import GenMake
36 from Common
import Misc
as Utils
38 from Common
.TargetTxtClassObject
import TargetTxt
39 from Common
.ToolDefClassObject
import ToolDef
40 from Common
.Misc
import PathClass
,SaveFileOnChange
,RemoveDirectory
41 from Common
.StringUtils
import NormPath
42 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
43 from Common
.BuildToolError
import *
44 from Common
.DataType
import *
45 import Common
.EdkLogger
as EdkLogger
47 from Workspace
.WorkspaceDatabase
import BuildDB
49 from BuildReport
import BuildReport
50 from GenPatchPcdTable
.GenPatchPcdTable
import PeImageClass
,parsePcdInfoFromMapFile
51 from PatchPcdValue
.PatchPcdValue
import PatchBinaryFile
53 import Common
.GlobalData
as GlobalData
54 from GenFds
.GenFds
import GenFds
, GenFdsApi
55 import multiprocessing
as mp
56 from multiprocessing
import Manager
59 ## standard targets of build command
60 gSupportedTarget
= ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
62 ## build configuration file
63 gBuildConfiguration
= "target.txt"
64 gToolsDefinition
= "tools_def.txt"
66 TemporaryTablePattern
= re
.compile(r
'^_\d+_\d+_[a-fA-F0-9]+$')
69 ## Check environment PATH variable to make sure the specified tool is found
71 # If the tool is found in the PATH, then True is returned
72 # Otherwise, False is returned
74 def IsToolInPath(tool
):
75 if 'PATHEXT' in os
.environ
:
76 extns
= os
.environ
['PATHEXT'].split(os
.path
.pathsep
)
79 for pathDir
in os
.environ
['PATH'].split(os
.path
.pathsep
):
81 if os
.path
.exists(os
.path
.join(pathDir
, tool
+ ext
)):
85 ## Check environment variables
87 # Check environment variables that must be set for build. Currently they are
89 # WORKSPACE The directory all packages/platforms start from
90 # EDK_TOOLS_PATH The directory contains all tools needed by the build
91 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
93 # If any of above environment variable is not set or has error, the build
96 def CheckEnvVariable():
98 if "WORKSPACE" not in os
.environ
:
99 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
100 ExtraData
="WORKSPACE")
102 WorkspaceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["WORKSPACE"]))
103 if not os
.path
.exists(WorkspaceDir
):
104 EdkLogger
.error("build", FILE_NOT_FOUND
, "WORKSPACE doesn't exist", ExtraData
=WorkspaceDir
)
105 elif ' ' in WorkspaceDir
:
106 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in WORKSPACE path",
107 ExtraData
=WorkspaceDir
)
108 os
.environ
["WORKSPACE"] = WorkspaceDir
110 # set multiple workspace
111 PackagesPath
= os
.getenv("PACKAGES_PATH")
112 mws
.setWs(WorkspaceDir
, PackagesPath
)
113 if mws
.PACKAGES_PATH
:
114 for Path
in mws
.PACKAGES_PATH
:
115 if not os
.path
.exists(Path
):
116 EdkLogger
.error("build", FILE_NOT_FOUND
, "One Path in PACKAGES_PATH doesn't exist", ExtraData
=Path
)
118 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in PACKAGES_PATH", ExtraData
=Path
)
121 os
.environ
["EDK_TOOLS_PATH"] = os
.path
.normcase(os
.environ
["EDK_TOOLS_PATH"])
123 # check EDK_TOOLS_PATH
124 if "EDK_TOOLS_PATH" not in os
.environ
:
125 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
126 ExtraData
="EDK_TOOLS_PATH")
129 if "PATH" not in os
.environ
:
130 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
133 GlobalData
.gWorkspace
= WorkspaceDir
135 GlobalData
.gGlobalDefines
["WORKSPACE"] = WorkspaceDir
136 GlobalData
.gGlobalDefines
["EDK_TOOLS_PATH"] = os
.environ
["EDK_TOOLS_PATH"]
138 ## Get normalized file path
140 # Convert the path to be local format, and remove the WORKSPACE path at the
141 # beginning if the file path is given in full path.
143 # @param FilePath File path to be normalized
144 # @param Workspace Workspace path which the FilePath will be checked against
146 # @retval string The normalized file path
148 def NormFile(FilePath
, Workspace
):
149 # check if the path is absolute or relative
150 if os
.path
.isabs(FilePath
):
151 FileFullPath
= os
.path
.normpath(FilePath
)
153 FileFullPath
= os
.path
.normpath(mws
.join(Workspace
, FilePath
))
154 Workspace
= mws
.getWs(Workspace
, FilePath
)
156 # check if the file path exists or not
157 if not os
.path
.isfile(FileFullPath
):
158 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath
)
160 # remove workspace directory from the beginning part of the file path
161 if Workspace
[-1] in ["\\", "/"]:
162 return FileFullPath
[len(Workspace
):]
164 return FileFullPath
[(len(Workspace
) + 1):]
166 ## Get the output of an external program
168 # This is the entrance method of thread reading output of an external program and
169 # putting them in STDOUT/STDERR of current program.
171 # @param From The stream message read from
172 # @param To The stream message put on
173 # @param ExitFlag The flag used to indicate stopping reading
175 def ReadMessage(From
, To
, ExitFlag
):
177 # read one line a time
178 Line
= From
.readline()
179 # empty string means "end"
180 if Line
is not None and Line
!= b
"":
181 To(Line
.rstrip().decode(encoding
='utf-8', errors
='ignore'))
187 ## Launch an external program
189 # This method will call subprocess.Popen to execute an external program with
190 # given options in specified directory. Because of the dead-lock issue during
191 # redirecting output of the external program, threads are used to to do the
194 # @param Command A list or string containing the call of the program
195 # @param WorkingDir The directory in which the program will be running
197 def LaunchCommand(Command
, WorkingDir
):
198 BeginTime
= time
.time()
199 # if working directory doesn't exist, Popen() will raise an exception
200 if not os
.path
.isdir(WorkingDir
):
201 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=WorkingDir
)
203 # Command is used as the first Argument in following Popen().
204 # It could be a string or sequence. We find that if command is a string in following Popen(),
205 # ubuntu may fail with an error message that the command is not found.
206 # So here we may need convert command from string to list instance.
207 if platform
.system() != 'Windows':
208 if not isinstance(Command
, list):
209 Command
= Command
.split()
210 Command
= ' '.join(Command
)
213 EndOfProcedure
= None
216 Proc
= Popen(Command
, stdout
=PIPE
, stderr
=PIPE
, env
=os
.environ
, cwd
=WorkingDir
, bufsize
=-1, shell
=True)
218 # launch two threads to read the STDOUT and STDERR
219 EndOfProcedure
= Event()
220 EndOfProcedure
.clear()
222 StdOutThread
= Thread(target
=ReadMessage
, args
=(Proc
.stdout
, EdkLogger
.info
, EndOfProcedure
))
223 StdOutThread
.setName("STDOUT-Redirector")
224 StdOutThread
.setDaemon(False)
228 StdErrThread
= Thread(target
=ReadMessage
, args
=(Proc
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
229 StdErrThread
.setName("STDERR-Redirector")
230 StdErrThread
.setDaemon(False)
233 # waiting for program exit
235 except: # in case of aborting
236 # terminate the threads redirecting the program output
237 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
238 if EndOfProcedure
is not None:
241 if not isinstance(Command
, type("")):
242 Command
= " ".join(Command
)
243 EdkLogger
.error("build", COMMAND_FAILURE
, "Failed to start command", ExtraData
="%s [%s]" % (Command
, WorkingDir
))
250 # check the return code of the program
251 if Proc
.returncode
!= 0:
252 if not isinstance(Command
, type("")):
253 Command
= " ".join(Command
)
254 # print out the Response file and its content when make failure
255 RespFile
= os
.path
.join(WorkingDir
, 'OUTPUT', 'respfilelist.txt')
256 if os
.path
.isfile(RespFile
):
258 RespContent
= f
.read()
260 EdkLogger
.info(RespContent
)
262 EdkLogger
.error("build", COMMAND_FAILURE
, ExtraData
="%s [%s]" % (Command
, WorkingDir
))
263 return "%dms" % (int(round((time
.time() - BeginTime
) * 1000)))
265 ## The smallest unit that can be built in multi-thread build mode
267 # This is the base class of build unit. The "Obj" parameter must provide
268 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
271 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
276 # @param self The object pointer
277 # @param Obj The object the build is working on
278 # @param Target The build target name, one of gSupportedTarget
279 # @param Dependency The BuildUnit(s) which must be completed in advance
280 # @param WorkingDir The directory build command starts in
282 def __init__(self
, Obj
, BuildCommand
, Target
, Dependency
, WorkingDir
="."):
283 self
.BuildObject
= Obj
284 self
.Dependency
= Dependency
285 self
.WorkingDir
= WorkingDir
287 self
.BuildCommand
= BuildCommand
289 EdkLogger
.error("build", OPTION_MISSING
,
290 "No build command found for this module. "
291 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
292 (Obj
.BuildTarget
, Obj
.ToolChain
, Obj
.Arch
),
298 # It just returns the string representation of self.BuildObject
300 # @param self The object pointer
303 return str(self
.BuildObject
)
305 ## "==" operator method
307 # It just compares self.BuildObject with "Other". So self.BuildObject must
308 # provide its own __eq__() method.
310 # @param self The object pointer
311 # @param Other The other BuildUnit object compared to
313 def __eq__(self
, Other
):
314 return Other
and self
.BuildObject
== Other
.BuildObject \
315 and Other
.BuildObject \
316 and self
.BuildObject
.Arch
== Other
.BuildObject
.Arch
320 # It just returns the hash value of self.BuildObject which must be hashable.
322 # @param self The object pointer
325 return hash(self
.BuildObject
) + hash(self
.BuildObject
.Arch
)
328 return repr(self
.BuildObject
)
330 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
332 # This class is for module build by nmake/make build system. The "Obj" parameter
333 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
334 # be make units missing build.
336 # Currently the "Obj" should be only ModuleAutoGen object.
338 class ModuleMakeUnit(BuildUnit
):
341 # @param self The object pointer
342 # @param Obj The ModuleAutoGen object the build is working on
343 # @param Target The build target name, one of gSupportedTarget
345 def __init__(self
, Obj
, BuildCommand
,Target
):
346 Dependency
= [ModuleMakeUnit(La
, BuildCommand
,Target
) for La
in Obj
.LibraryAutoGenList
]
347 BuildUnit
.__init
__(self
, Obj
, BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
348 if Target
in [None, "", "all"]:
349 self
.Target
= "tbuild"
351 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
353 # This class is for platform build by nmake/make build system. The "Obj" parameter
354 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
355 # be make units missing build.
357 # Currently the "Obj" should be only PlatformAutoGen object.
359 class PlatformMakeUnit(BuildUnit
):
362 # @param self The object pointer
363 # @param Obj The PlatformAutoGen object the build is working on
364 # @param Target The build target name, one of gSupportedTarget
366 def __init__(self
, Obj
, BuildCommand
, Target
):
367 Dependency
= [ModuleMakeUnit(Lib
, BuildCommand
, Target
) for Lib
in self
.BuildObject
.LibraryAutoGenList
]
368 Dependency
.extend([ModuleMakeUnit(Mod
, BuildCommand
,Target
) for Mod
in self
.BuildObject
.ModuleAutoGenList
])
369 BuildUnit
.__init
__(self
, Obj
, BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
371 ## The class representing the task of a module build or platform build
373 # This class manages the build tasks in multi-thread build mode. Its jobs include
374 # scheduling thread running, catching thread error, monitor the thread status, etc.
377 # queue for tasks waiting for schedule
378 _PendingQueue
= OrderedDict()
379 _PendingQueueLock
= threading
.Lock()
381 # queue for tasks ready for running
382 _ReadyQueue
= OrderedDict()
383 _ReadyQueueLock
= threading
.Lock()
385 # queue for run tasks
386 _RunningQueue
= OrderedDict()
387 _RunningQueueLock
= threading
.Lock()
389 # queue containing all build tasks, in case duplicate build
390 _TaskQueue
= OrderedDict()
392 # flag indicating error occurs in a running thread
393 _ErrorFlag
= threading
.Event()
397 # BoundedSemaphore object used to control the number of running threads
400 # flag indicating if the scheduler is started or not
401 _SchedulerStopped
= threading
.Event()
402 _SchedulerStopped
.set()
404 ## Start the task scheduler thread
406 # @param MaxThreadNumber The maximum thread number
407 # @param ExitFlag Flag used to end the scheduler
410 def StartScheduler(MaxThreadNumber
, ExitFlag
):
411 SchedulerThread
= Thread(target
=BuildTask
.Scheduler
, args
=(MaxThreadNumber
, ExitFlag
))
412 SchedulerThread
.setName("Build-Task-Scheduler")
413 SchedulerThread
.setDaemon(False)
414 SchedulerThread
.start()
415 # wait for the scheduler to be started, especially useful in Linux
416 while not BuildTask
.IsOnGoing():
421 # @param MaxThreadNumber The maximum thread number
422 # @param ExitFlag Flag used to end the scheduler
425 def Scheduler(MaxThreadNumber
, ExitFlag
):
426 BuildTask
._SchedulerStopped
.clear()
428 # use BoundedSemaphore to control the maximum running threads
429 BuildTask
._Thread
= BoundedSemaphore(MaxThreadNumber
)
431 # scheduling loop, which will exits when no pending/ready task and
432 # indicated to do so, or there's error in running thread
434 while (len(BuildTask
._PendingQueue
) > 0 or len(BuildTask
._ReadyQueue
) > 0 \
435 or not ExitFlag
.isSet()) and not BuildTask
._ErrorFlag
.isSet():
436 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Pending Queue (%d), Ready Queue (%d)"
437 % (len(BuildTask
._PendingQueue
), len(BuildTask
._ReadyQueue
)))
439 # get all pending tasks
440 BuildTask
._PendingQueueLock
.acquire()
441 BuildObjectList
= list(BuildTask
._PendingQueue
.keys())
443 # check if their dependency is resolved, and if true, move them
446 for BuildObject
in BuildObjectList
:
447 Bt
= BuildTask
._PendingQueue
[BuildObject
]
449 BuildTask
._ReadyQueue
[BuildObject
] = BuildTask
._PendingQueue
.pop(BuildObject
)
450 BuildTask
._PendingQueueLock
.release()
452 # launch build thread until the maximum number of threads is reached
453 while not BuildTask
._ErrorFlag
.isSet():
454 # empty ready queue, do nothing further
455 if len(BuildTask
._ReadyQueue
) == 0:
458 # wait for active thread(s) exit
459 BuildTask
._Thread
.acquire(True)
461 # start a new build thread
462 Bo
, Bt
= BuildTask
._ReadyQueue
.popitem()
464 # move into running queue
465 BuildTask
._RunningQueueLock
.acquire()
466 BuildTask
._RunningQueue
[Bo
] = Bt
467 BuildTask
._RunningQueueLock
.release()
476 # wait for all running threads exit
477 if BuildTask
._ErrorFlag
.isSet():
478 EdkLogger
.quiet("\nWaiting for all build threads exit...")
479 # while not BuildTask._ErrorFlag.isSet() and \
480 while len(BuildTask
._RunningQueue
) > 0:
481 EdkLogger
.verbose("Waiting for thread ending...(%d)" % len(BuildTask
._RunningQueue
))
482 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Threads [%s]" % ", ".join(Th
.getName() for Th
in threading
.enumerate()))
485 except BaseException
as X
:
487 # TRICK: hide the output of threads left running, so that the user can
488 # catch the error message easily
490 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
491 BuildTask
._ErrorFlag
.set()
492 BuildTask
._ErrorMessage
= "build thread scheduler error\n\t%s" % str(X
)
494 BuildTask
._PendingQueue
.clear()
495 BuildTask
._ReadyQueue
.clear()
496 BuildTask
._RunningQueue
.clear()
497 BuildTask
._TaskQueue
.clear()
498 BuildTask
._SchedulerStopped
.set()
500 ## Wait for all running method exit
503 def WaitForComplete():
504 BuildTask
._SchedulerStopped
.wait()
506 ## Check if the scheduler is running or not
510 return not BuildTask
._SchedulerStopped
.isSet()
515 if BuildTask
.IsOnGoing():
516 BuildTask
._ErrorFlag
.set()
517 BuildTask
.WaitForComplete()
519 ## Check if there's error in running thread
521 # Since the main thread cannot catch exceptions in other thread, we have to
522 # use threading.Event to communicate this formation to main thread.
526 return BuildTask
._ErrorFlag
.isSet()
528 ## Get error message in running thread
530 # Since the main thread cannot catch exceptions in other thread, we have to
531 # use a static variable to communicate this message to main thread.
534 def GetErrorMessage():
535 return BuildTask
._ErrorMessage
537 ## Factory method to create a BuildTask object
539 # This method will check if a module is building or has been built. And if
540 # true, just return the associated BuildTask object in the _TaskQueue. If
541 # not, create and return a new BuildTask object. The new BuildTask object
542 # will be appended to the _PendingQueue for scheduling later.
544 # @param BuildItem A BuildUnit object representing a build object
545 # @param Dependency The dependent build object of BuildItem
548 def New(BuildItem
, Dependency
=None):
549 if BuildItem
in BuildTask
._TaskQueue
:
550 Bt
= BuildTask
._TaskQueue
[BuildItem
]
554 Bt
._Init
(BuildItem
, Dependency
)
555 BuildTask
._TaskQueue
[BuildItem
] = Bt
557 BuildTask
._PendingQueueLock
.acquire()
558 BuildTask
._PendingQueue
[BuildItem
] = Bt
559 BuildTask
._PendingQueueLock
.release()
563 ## The real constructor of BuildTask
565 # @param BuildItem A BuildUnit object representing a build object
566 # @param Dependency The dependent build object of BuildItem
568 def _Init(self
, BuildItem
, Dependency
=None):
569 self
.BuildItem
= BuildItem
571 self
.DependencyList
= []
572 if Dependency
is None:
573 Dependency
= BuildItem
.Dependency
575 Dependency
.extend(BuildItem
.Dependency
)
576 self
.AddDependency(Dependency
)
577 # flag indicating build completes, used to avoid unnecessary re-build
578 self
.CompleteFlag
= False
580 ## Check if all dependent build tasks are completed or not
584 for Dep
in self
.DependencyList
:
585 if Dep
.CompleteFlag
== True:
592 ## Add dependent build task
594 # @param Dependency The list of dependent build objects
596 def AddDependency(self
, Dependency
):
597 for Dep
in Dependency
:
598 if not Dep
.BuildObject
.IsBinaryModule
and not Dep
.BuildObject
.CanSkipbyCache(GlobalData
.gCacheIR
):
599 self
.DependencyList
.append(BuildTask
.New(Dep
)) # BuildTask list
601 ## The thread wrapper of LaunchCommand function
603 # @param Command A list or string contains the call of the command
604 # @param WorkingDir The directory in which the program will be running
606 def _CommandThread(self
, Command
, WorkingDir
):
608 self
.BuildItem
.BuildObject
.BuildTime
= LaunchCommand(Command
, WorkingDir
)
609 self
.CompleteFlag
= True
611 # Run hash operation post dependency, to account for libs
612 if GlobalData
.gUseHashCache
and self
.BuildItem
.BuildObject
.IsLibrary
:
613 HashFile
= path
.join(self
.BuildItem
.BuildObject
.BuildDir
, self
.BuildItem
.BuildObject
.Name
+ ".hash")
614 SaveFileOnChange(HashFile
, self
.BuildItem
.BuildObject
.GenModuleHash(), True)
617 # TRICK: hide the output of threads left running, so that the user can
618 # catch the error message easily
620 if not BuildTask
._ErrorFlag
.isSet():
621 GlobalData
.gBuildingModule
= "%s [%s, %s, %s]" % (str(self
.BuildItem
.BuildObject
),
622 self
.BuildItem
.BuildObject
.Arch
,
623 self
.BuildItem
.BuildObject
.ToolChain
,
624 self
.BuildItem
.BuildObject
.BuildTarget
626 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
627 BuildTask
._ErrorFlag
.set()
628 BuildTask
._ErrorMessage
= "%s broken\n %s [%s]" % \
629 (threading
.currentThread().getName(), Command
, WorkingDir
)
631 # Set the value used by hash invalidation flow in GlobalData.gModuleBuildTracking to 'SUCCESS'
632 # If Module or Lib is being tracked, it did not fail header check test, and built successfully
633 if (self
.BuildItem
.BuildObject
in GlobalData
.gModuleBuildTracking
and
634 GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
] != 'FAIL_METAFILE' and
635 not BuildTask
._ErrorFlag
.isSet()
637 GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
] = 'SUCCESS'
639 # indicate there's a thread is available for another build task
640 BuildTask
._RunningQueueLock
.acquire()
641 BuildTask
._RunningQueue
.pop(self
.BuildItem
)
642 BuildTask
._RunningQueueLock
.release()
643 BuildTask
._Thread
.release()
645 ## Start build task thread
648 EdkLogger
.quiet("Building ... %s" % repr(self
.BuildItem
))
649 Command
= self
.BuildItem
.BuildCommand
+ [self
.BuildItem
.Target
]
650 self
.BuildTread
= Thread(target
=self
._CommandThread
, args
=(Command
, self
.BuildItem
.WorkingDir
))
651 self
.BuildTread
.setName("build thread")
652 self
.BuildTread
.setDaemon(False)
653 self
.BuildTread
.start()
655 ## The class contains the information related to EFI image
660 # Constructor will load all required image information.
662 # @param BaseName The full file path of image.
663 # @param Guid The GUID for image.
664 # @param Arch Arch of this image.
665 # @param OutputDir The output directory for image.
666 # @param DebugDir The debug directory for image.
667 # @param ImageClass PeImage Information
669 def __init__(self
, BaseName
, Guid
, Arch
, OutputDir
, DebugDir
, ImageClass
):
670 self
.BaseName
= BaseName
673 self
.OutputDir
= OutputDir
674 self
.DebugDir
= DebugDir
675 self
.Image
= ImageClass
676 self
.Image
.Size
= (self
.Image
.Size
// 0x1000 + 1) * 0x1000
678 ## The class implementing the EDK2 build process
680 # The build process includes:
681 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
682 # 2. Parse DSC file of active platform
683 # 3. Parse FDF file if any
684 # 4. Establish build database, including parse all other files (module, package)
685 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
686 # 6. Call build command
691 # Constructor will load all necessary configurations, parse platform, modules
692 # and packages and the establish a database for AutoGen.
694 # @param Target The build command target, one of gSupportedTarget
695 # @param WorkspaceDir The directory of workspace
696 # @param BuildOptions Build options passed from command line
698 def __init__(self
, Target
, WorkspaceDir
, BuildOptions
,log_q
):
699 self
.WorkspaceDir
= WorkspaceDir
701 self
.PlatformFile
= BuildOptions
.PlatformFile
702 self
.ModuleFile
= BuildOptions
.ModuleFile
703 self
.ArchList
= BuildOptions
.TargetArch
704 self
.ToolChainList
= BuildOptions
.ToolChain
705 self
.BuildTargetList
= BuildOptions
.BuildTarget
706 self
.Fdf
= BuildOptions
.FdfFile
707 self
.FdList
= BuildOptions
.RomImage
708 self
.FvList
= BuildOptions
.FvImage
709 self
.CapList
= BuildOptions
.CapName
710 self
.SilentMode
= BuildOptions
.SilentMode
711 self
.ThreadNumber
= 1
712 self
.SkipAutoGen
= BuildOptions
.SkipAutoGen
713 self
.Reparse
= BuildOptions
.Reparse
714 self
.SkuId
= BuildOptions
.SkuId
716 GlobalData
.gSKUID_CMD
= self
.SkuId
717 self
.ConfDirectory
= BuildOptions
.ConfDirectory
718 self
.SpawnMode
= True
719 self
.BuildReport
= BuildReport(BuildOptions
.ReportFile
, BuildOptions
.ReportType
)
720 self
.TargetTxt
= TargetTxt
721 self
.ToolDef
= ToolDef
725 GlobalData
.BuildOptionPcd
= BuildOptions
.OptionPcd
if BuildOptions
.OptionPcd
else []
726 #Set global flag for build mode
727 GlobalData
.gIgnoreSource
= BuildOptions
.IgnoreSources
728 GlobalData
.gUseHashCache
= BuildOptions
.UseHashCache
729 GlobalData
.gBinCacheDest
= BuildOptions
.BinCacheDest
730 GlobalData
.gBinCacheSource
= BuildOptions
.BinCacheSource
731 GlobalData
.gEnableGenfdsMultiThread
= BuildOptions
.GenfdsMultiThread
732 GlobalData
.gDisableIncludePathCheck
= BuildOptions
.DisableIncludePathCheck
734 if GlobalData
.gBinCacheDest
and not GlobalData
.gUseHashCache
:
735 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination must be used together with --hash.")
737 if GlobalData
.gBinCacheSource
and not GlobalData
.gUseHashCache
:
738 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-source must be used together with --hash.")
740 if GlobalData
.gBinCacheDest
and GlobalData
.gBinCacheSource
:
741 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination can not be used together with --binary-source.")
743 if GlobalData
.gBinCacheSource
:
744 BinCacheSource
= os
.path
.normpath(GlobalData
.gBinCacheSource
)
745 if not os
.path
.isabs(BinCacheSource
):
746 BinCacheSource
= mws
.join(self
.WorkspaceDir
, BinCacheSource
)
747 GlobalData
.gBinCacheSource
= BinCacheSource
749 if GlobalData
.gBinCacheSource
is not None:
750 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-source.")
752 if GlobalData
.gBinCacheDest
:
753 BinCacheDest
= os
.path
.normpath(GlobalData
.gBinCacheDest
)
754 if not os
.path
.isabs(BinCacheDest
):
755 BinCacheDest
= mws
.join(self
.WorkspaceDir
, BinCacheDest
)
756 GlobalData
.gBinCacheDest
= BinCacheDest
758 if GlobalData
.gBinCacheDest
is not None:
759 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-destination.")
761 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(GlobalData
.gConfDirectory
, GlobalData
.gDatabasePath
))
762 if not os
.path
.exists(os
.path
.join(GlobalData
.gConfDirectory
, '.cache')):
763 os
.makedirs(os
.path
.join(GlobalData
.gConfDirectory
, '.cache'))
765 self
.BuildDatabase
= self
.Db
.BuildObject
767 self
.ToolChainFamily
= None
768 self
.LoadFixAddress
= 0
769 self
.UniFlag
= BuildOptions
.Flag
770 self
.BuildModules
= []
771 self
.HashSkipModules
= []
773 self
.LaunchPrebuildFlag
= False
774 self
.PlatformBuildPath
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PlatformBuild')
775 if BuildOptions
.CommandLength
:
776 GlobalData
.gCommandMaxLength
= BuildOptions
.CommandLength
778 # print dot character during doing some time-consuming work
779 self
.Progress
= Utils
.Progressor()
780 # print current build environment and configuration
781 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
782 if "PACKAGES_PATH" in os
.environ
:
783 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
784 EdkLogger
.quiet("%-16s = %s" % ("PACKAGES_PATH", os
.path
.normcase(os
.path
.normpath(os
.environ
["PACKAGES_PATH"]))))
785 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
786 if "EDK_TOOLS_BIN" in os
.environ
:
787 # Print the same path style with WORKSPACE env.
788 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_TOOLS_BIN"]))))
789 EdkLogger
.quiet("%-16s = %s" % ("CONF_PATH", GlobalData
.gConfDirectory
))
790 if "PYTHON3_ENABLE" in os
.environ
:
791 PYTHON3_ENABLE
= os
.environ
["PYTHON3_ENABLE"]
792 if PYTHON3_ENABLE
!= "TRUE":
793 PYTHON3_ENABLE
= "FALSE"
794 EdkLogger
.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE
))
795 if "PYTHON_COMMAND" in os
.environ
:
796 EdkLogger
.quiet("%-16s = %s" % ("PYTHON_COMMAND", os
.environ
["PYTHON_COMMAND"]))
800 EdkLogger
.quiet("%-16s = %s" % ("PREBUILD", self
.Prebuild
))
802 EdkLogger
.quiet("%-16s = %s" % ("POSTBUILD", self
.Postbuild
))
804 self
.LaunchPrebuild()
805 self
.TargetTxt
= TargetTxt
806 self
.ToolDef
= ToolDef
807 if not (self
.LaunchPrebuildFlag
and os
.path
.exists(self
.PlatformBuildPath
)):
810 self
.AutoGenMgr
= None
812 os
.chdir(self
.WorkspaceDir
)
813 GlobalData
.gCacheIR
= Manager().dict()
815 def StartAutoGen(self
,mqueue
, DataPipe
,SkipAutoGen
,PcdMaList
,share_data
):
819 feedback_q
= mp
.Queue()
820 file_lock
= mp
.Lock()
821 error_event
= mp
.Event()
822 GlobalData
.file_lock
= file_lock
823 FfsCmd
= DataPipe
.Get("FfsCommand")
826 GlobalData
.FfsCmd
= FfsCmd
827 GlobalData
.libConstPcd
= DataPipe
.Get("LibConstPcd")
828 GlobalData
.Refes
= DataPipe
.Get("REFS")
829 auto_workers
= [AutoGenWorkerInProcess(mqueue
,DataPipe
.dump_file
,feedback_q
,file_lock
,share_data
,self
.log_q
,error_event
) for _
in range(self
.ThreadNumber
)]
830 self
.AutoGenMgr
= AutoGenManager(auto_workers
,feedback_q
,error_event
)
831 self
.AutoGenMgr
.start()
832 for w
in auto_workers
:
834 if PcdMaList
is not None:
835 for PcdMa
in PcdMaList
:
836 if GlobalData
.gBinCacheSource
and self
.Target
in [None, "", "all"]:
837 PcdMa
.GenModuleFilesHash(share_data
)
838 PcdMa
.GenPreMakefileHash(share_data
)
839 if PcdMa
.CanSkipbyPreMakefileCache(share_data
):
842 PcdMa
.CreateCodeFile(False)
843 PcdMa
.CreateMakeFile(False,GenFfsList
= DataPipe
.Get("FfsCommand").get((PcdMa
.MetaFile
.File
, PcdMa
.Arch
),[]))
845 if GlobalData
.gBinCacheSource
and self
.Target
in [None, "", "all"]:
846 PcdMa
.GenMakeHeaderFilesHash(share_data
)
847 PcdMa
.GenMakeHash(share_data
)
848 if PcdMa
.CanSkipbyMakeCache(share_data
):
851 self
.AutoGenMgr
.join()
852 rt
= self
.AutoGenMgr
.Status
854 except FatalError
as e
:
855 return False, e
.args
[0]
857 return False, UNKNOWN_ERROR
859 ## Load configuration
861 # This method will parse target.txt and get the build configurations.
863 def LoadConfiguration(self
):
865 # if no ARCH given in command line, get it from target.txt
866 if not self
.ArchList
:
867 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET_ARCH
]
868 self
.ArchList
= tuple(self
.ArchList
)
870 # if no build target given in command line, get it from target.txt
871 if not self
.BuildTargetList
:
872 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
874 # if no tool chain given in command line, get it from target.txt
875 if not self
.ToolChainList
:
876 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
877 if self
.ToolChainList
is None or len(self
.ToolChainList
) == 0:
878 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
880 # check if the tool chains are defined or not
881 NewToolChainList
= []
882 for ToolChain
in self
.ToolChainList
:
883 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
884 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
886 NewToolChainList
.append(ToolChain
)
887 # if no tool chain available, break the build
888 if len(NewToolChainList
) == 0:
889 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
890 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
892 self
.ToolChainList
= NewToolChainList
895 ToolDefinition
= self
.ToolDef
.ToolsDefTxtDatabase
896 for Tool
in self
.ToolChainList
:
897 if TAB_TOD_DEFINES_FAMILY
not in ToolDefinition
or Tool
not in ToolDefinition
[TAB_TOD_DEFINES_FAMILY
] \
898 or not ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
]:
899 EdkLogger
.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool
)
900 ToolChainFamily
.append(TAB_COMPILER_MSFT
)
902 ToolChainFamily
.append(ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
])
903 self
.ToolChainFamily
= ToolChainFamily
905 if not self
.PlatformFile
:
906 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
908 # Try to find one in current directory
909 WorkingDirectory
= os
.getcwd()
910 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
911 FileNum
= len(FileList
)
913 EdkLogger
.error("build", OPTION_MISSING
,
914 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
916 PlatformFile
= FileList
[0]
918 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
919 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
921 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
922 self
.ThreadNumber
= ThreadNum()
923 ## Initialize build configuration
925 # This method will parse DSC file and merge the configurations from
926 # command line and target.txt, then get the final build configurations.
929 # parse target.txt, tools_def.txt, and platform file
930 self
.LoadConfiguration()
932 # Allow case-insensitive for those from command line or configuration file
933 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
935 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
938 def InitPreBuild(self
):
939 self
.LoadConfiguration()
940 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
942 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
943 if self
.BuildTargetList
:
944 GlobalData
.gGlobalDefines
['TARGET'] = self
.BuildTargetList
[0]
946 GlobalData
.gGlobalDefines
['ARCH'] = self
.ArchList
[0]
947 if self
.ToolChainList
:
948 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = self
.ToolChainList
[0]
949 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = self
.ToolChainList
[0]
950 if self
.ToolChainFamily
:
951 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[0]
952 if 'PREBUILD' in GlobalData
.gCommandLineDefines
:
953 self
.Prebuild
= GlobalData
.gCommandLineDefines
.get('PREBUILD')
956 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
957 self
.Prebuild
= str(Platform
.Prebuild
)
961 # Evaluate all arguments and convert arguments that are WORKSPACE
962 # relative paths to absolute paths. Filter arguments that look like
963 # flags or do not follow the file/dir naming rules to avoid false
964 # positives on this conversion.
966 for Arg
in self
.Prebuild
.split():
968 # Do not modify Arg if it looks like a flag or an absolute file path
970 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
971 PrebuildList
.append(Arg
)
974 # Do not modify Arg if it does not look like a Workspace relative
975 # path that starts with a valid package directory name
977 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
978 PrebuildList
.append(Arg
)
981 # If Arg looks like a WORKSPACE relative path, then convert to an
982 # absolute path and check to see if the file exists.
984 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
985 if os
.path
.isfile(Temp
):
987 PrebuildList
.append(Arg
)
988 self
.Prebuild
= ' '.join(PrebuildList
)
989 self
.Prebuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
991 def InitPostBuild(self
):
992 if 'POSTBUILD' in GlobalData
.gCommandLineDefines
:
993 self
.Postbuild
= GlobalData
.gCommandLineDefines
.get('POSTBUILD')
995 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
996 self
.Postbuild
= str(Platform
.Postbuild
)
1000 # Evaluate all arguments and convert arguments that are WORKSPACE
1001 # relative paths to absolute paths. Filter arguments that look like
1002 # flags or do not follow the file/dir naming rules to avoid false
1003 # positives on this conversion.
1005 for Arg
in self
.Postbuild
.split():
1007 # Do not modify Arg if it looks like a flag or an absolute file path
1009 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1010 PostbuildList
.append(Arg
)
1013 # Do not modify Arg if it does not look like a Workspace relative
1014 # path that starts with a valid package directory name
1016 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1017 PostbuildList
.append(Arg
)
1020 # If Arg looks like a WORKSPACE relative path, then convert to an
1021 # absolute path and check to see if the file exists.
1023 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1024 if os
.path
.isfile(Temp
):
1026 PostbuildList
.append(Arg
)
1027 self
.Postbuild
= ' '.join(PostbuildList
)
1028 self
.Postbuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1030 def PassCommandOption(self
, BuildTarget
, TargetArch
, ToolChain
, PlatformFile
, Target
):
1032 if GlobalData
.gCommand
and isinstance(GlobalData
.gCommand
, list):
1033 BuildStr
+= ' ' + ' '.join(GlobalData
.gCommand
)
1036 ToolChainFlag
= False
1037 PlatformFileFlag
= False
1039 if GlobalData
.gOptions
and not GlobalData
.gOptions
.BuildTarget
:
1041 if GlobalData
.gOptions
and not GlobalData
.gOptions
.TargetArch
:
1043 if GlobalData
.gOptions
and not GlobalData
.gOptions
.ToolChain
:
1044 ToolChainFlag
= True
1045 if GlobalData
.gOptions
and not GlobalData
.gOptions
.PlatformFile
:
1046 PlatformFileFlag
= True
1048 if TargetFlag
and BuildTarget
:
1049 if isinstance(BuildTarget
, list) or isinstance(BuildTarget
, tuple):
1050 BuildStr
+= ' -b ' + ' -b '.join(BuildTarget
)
1051 elif isinstance(BuildTarget
, str):
1052 BuildStr
+= ' -b ' + BuildTarget
1053 if ArchFlag
and TargetArch
:
1054 if isinstance(TargetArch
, list) or isinstance(TargetArch
, tuple):
1055 BuildStr
+= ' -a ' + ' -a '.join(TargetArch
)
1056 elif isinstance(TargetArch
, str):
1057 BuildStr
+= ' -a ' + TargetArch
1058 if ToolChainFlag
and ToolChain
:
1059 if isinstance(ToolChain
, list) or isinstance(ToolChain
, tuple):
1060 BuildStr
+= ' -t ' + ' -t '.join(ToolChain
)
1061 elif isinstance(ToolChain
, str):
1062 BuildStr
+= ' -t ' + ToolChain
1063 if PlatformFileFlag
and PlatformFile
:
1064 if isinstance(PlatformFile
, list) or isinstance(PlatformFile
, tuple):
1065 BuildStr
+= ' -p ' + ' -p '.join(PlatformFile
)
1066 elif isinstance(PlatformFile
, str):
1067 BuildStr
+= ' -p' + PlatformFile
1068 BuildStr
+= ' --conf=' + GlobalData
.gConfDirectory
1070 BuildStr
+= ' ' + Target
1074 def LaunchPrebuild(self
):
1076 EdkLogger
.info("\n- Prebuild Start -\n")
1077 self
.LaunchPrebuildFlag
= True
1079 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1080 # and preserve them for the rest of the main build step, because the child process environment will
1081 # evaporate as soon as it exits, we cannot get it in build step.
1083 PrebuildEnvFile
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PrebuildEnv')
1084 if os
.path
.isfile(PrebuildEnvFile
):
1085 os
.remove(PrebuildEnvFile
)
1086 if os
.path
.isfile(self
.PlatformBuildPath
):
1087 os
.remove(self
.PlatformBuildPath
)
1088 if sys
.platform
== "win32":
1089 args
= ' && '.join((self
.Prebuild
, 'set > ' + PrebuildEnvFile
))
1090 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1092 args
= ' && '.join((self
.Prebuild
, 'env > ' + PrebuildEnvFile
))
1093 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1095 # launch two threads to read the STDOUT and STDERR
1096 EndOfProcedure
= Event()
1097 EndOfProcedure
.clear()
1099 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1100 StdOutThread
.setName("STDOUT-Redirector")
1101 StdOutThread
.setDaemon(False)
1102 StdOutThread
.start()
1105 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1106 StdErrThread
.setName("STDERR-Redirector")
1107 StdErrThread
.setDaemon(False)
1108 StdErrThread
.start()
1109 # waiting for program exit
1116 if Process
.returncode
!= 0 :
1117 EdkLogger
.error("Prebuild", PREBUILD_ERROR
, 'Prebuild process is not success!')
1119 if os
.path
.exists(PrebuildEnvFile
):
1120 f
= open(PrebuildEnvFile
)
1121 envs
= f
.readlines()
1123 envs
= [l
.split("=", 1) for l
in envs
]
1124 envs
= [[I
.strip() for I
in item
] for item
in envs
if len(item
) == 2]
1125 os
.environ
.update(dict(envs
))
1126 EdkLogger
.info("\n- Prebuild Done -\n")
1128 def LaunchPostbuild(self
):
1130 EdkLogger
.info("\n- Postbuild Start -\n")
1131 if sys
.platform
== "win32":
1132 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1134 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1135 # launch two threads to read the STDOUT and STDERR
1136 EndOfProcedure
= Event()
1137 EndOfProcedure
.clear()
1139 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1140 StdOutThread
.setName("STDOUT-Redirector")
1141 StdOutThread
.setDaemon(False)
1142 StdOutThread
.start()
1145 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1146 StdErrThread
.setName("STDERR-Redirector")
1147 StdErrThread
.setDaemon(False)
1148 StdErrThread
.start()
1149 # waiting for program exit
1156 if Process
.returncode
!= 0 :
1157 EdkLogger
.error("Postbuild", POSTBUILD_ERROR
, 'Postbuild process is not success!')
1158 EdkLogger
.info("\n- Postbuild Done -\n")
1160 ## Error handling for hash feature
1162 # On BuildTask error, iterate through the Module Build tracking
1163 # dictionary to determine wheather a module failed to build. Invalidate
1164 # the hash associated with that module by removing it from storage.
1167 def invalidateHash(self
):
1168 # Only for hashing feature
1169 if not GlobalData
.gUseHashCache
:
1172 # GlobalData.gModuleBuildTracking contains only modules or libs that cannot be skipped by hash
1173 for Ma
in GlobalData
.gModuleBuildTracking
:
1174 # Skip invalidating for Successful Module/Lib builds
1175 if GlobalData
.gModuleBuildTracking
[Ma
] == 'SUCCESS':
1178 # The module failed to build, failed to start building, or failed the header check test from this point on
1180 # Remove .hash from build
1181 ModuleHashFile
= os
.path
.join(Ma
.BuildDir
, Ma
.Name
+ ".hash")
1182 if os
.path
.exists(ModuleHashFile
):
1183 os
.remove(ModuleHashFile
)
1185 # Remove .hash file from cache
1186 if GlobalData
.gBinCacheDest
:
1187 FileDir
= os
.path
.join(GlobalData
.gBinCacheDest
, Ma
.PlatformInfo
.OutputDir
, Ma
.BuildTarget
+ "_" + Ma
.ToolChain
, Ma
.Arch
, Ma
.SourceDir
, Ma
.MetaFile
.BaseName
)
1188 HashFile
= os
.path
.join(FileDir
, Ma
.Name
+ '.hash')
1189 if os
.path
.exists(HashFile
):
1192 ## Build a module or platform
1194 # Create autogen code and makefile for a module or platform, and the launch
1195 # "make" command to build it
1197 # @param Target The target of build command
1198 # @param Platform The platform file
1199 # @param Module The module file
1200 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1201 # @param ToolChain The name of toolchain to build
1202 # @param Arch The arch of the module/platform
1203 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1204 # for dependent modules/Libraries
1205 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1206 # for dependent modules/Libraries
1208 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False, FfsCommand
=None, PcdMaList
=None):
1209 if AutoGenObject
is None:
1211 if FfsCommand
is None:
1213 # skip file generation for cleanxxx targets, run and fds target
1214 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1215 # for target which must generate AutoGen code and makefile
1217 for m
in AutoGenObject
.GetAllModuleInfo
:
1220 AutoGenObject
.DataPipe
.DataContainer
= {"FfsCommand":FfsCommand
}
1221 AutoGenObject
.DataPipe
.DataContainer
= {"CommandTarget": self
.Target
}
1222 self
.Progress
.Start("Generating makefile and code")
1223 data_pipe_file
= os
.path
.join(AutoGenObject
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(AutoGenObject
.Guid
),AutoGenObject
.Arch
))
1224 AutoGenObject
.DataPipe
.dump(data_pipe_file
)
1225 autogen_rt
,errorcode
= self
.StartAutoGen(mqueue
, AutoGenObject
.DataPipe
, self
.SkipAutoGen
, PcdMaList
, GlobalData
.gCacheIR
)
1226 self
.Progress
.Stop("done!")
1228 self
.AutoGenMgr
.TerminateWorkers()
1229 self
.AutoGenMgr
.join(0.1)
1230 raise FatalError(errorcode
)
1231 AutoGenObject
.CreateCodeFile(False)
1232 AutoGenObject
.CreateMakeFile(False)
1234 # always recreate top/platform makefile when clean, just in case of inconsistency
1235 AutoGenObject
.CreateCodeFile(True)
1236 AutoGenObject
.CreateMakeFile(True)
1238 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1239 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1241 BuildCommand
= AutoGenObject
.BuildCommand
1242 if BuildCommand
is None or len(BuildCommand
) == 0:
1243 EdkLogger
.error("build", OPTION_MISSING
,
1244 "No build command found for this module. "
1245 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1246 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1247 ExtraData
=str(AutoGenObject
))
1249 makefile
= GenMake
.BuildFile(AutoGenObject
)._FILE
_NAME
_[GenMake
.gMakeType
]
1257 BuildCommand
= BuildCommand
+ [Target
]
1258 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1259 self
.CreateAsBuiltInf()
1260 if GlobalData
.gBinCacheDest
:
1261 self
.UpdateBuildCache()
1262 self
.BuildModules
= []
1266 if Target
== 'libraries':
1267 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1268 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1269 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1273 if Target
== 'modules':
1274 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1275 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1276 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1277 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1278 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, makefile
)), 'pbuild']
1279 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1280 self
.CreateAsBuiltInf()
1281 if GlobalData
.gBinCacheDest
:
1282 self
.UpdateBuildCache()
1283 self
.BuildModules
= []
1287 if Target
== 'cleanlib':
1288 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1289 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1290 if os
.path
.exists(LibMakefile
):
1291 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1292 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1296 if Target
== 'clean':
1297 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1298 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, makefile
))
1299 if os
.path
.exists(ModMakefile
):
1300 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
1301 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1302 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1303 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1304 if os
.path
.exists(LibMakefile
):
1305 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1306 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1310 if Target
== 'cleanall':
1312 #os.rmdir(AutoGenObject.BuildDir)
1313 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1314 except WindowsError as X
:
1315 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1318 ## Build a module or platform
1320 # Create autogen code and makefile for a module or platform, and the launch
1321 # "make" command to build it
1323 # @param Target The target of build command
1324 # @param Platform The platform file
1325 # @param Module The module file
1326 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1327 # @param ToolChain The name of toolchain to build
1328 # @param Arch The arch of the module/platform
1329 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1330 # for dependent modules/Libraries
1331 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1332 # for dependent modules/Libraries
1334 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1335 if AutoGenObject
is None:
1338 # skip file generation for cleanxxx targets, run and fds target
1339 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1340 # for target which must generate AutoGen code and makefile
1341 if not self
.SkipAutoGen
or Target
== 'genc':
1342 self
.Progress
.Start("Generating code")
1343 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1344 self
.Progress
.Stop("done!")
1345 if Target
== "genc":
1348 if not self
.SkipAutoGen
or Target
== 'genmake':
1349 self
.Progress
.Start("Generating makefile")
1350 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1351 #AutoGenObject.CreateAsBuiltInf()
1352 self
.Progress
.Stop("done!")
1353 if Target
== "genmake":
1356 # always recreate top/platform makefile when clean, just in case of inconsistency
1357 AutoGenObject
.CreateCodeFile(True)
1358 AutoGenObject
.CreateMakeFile(True)
1360 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1361 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1363 BuildCommand
= AutoGenObject
.BuildCommand
1364 if BuildCommand
is None or len(BuildCommand
) == 0:
1365 EdkLogger
.error("build", OPTION_MISSING
,
1366 "No build command found for this module. "
1367 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1368 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1369 ExtraData
=str(AutoGenObject
))
1374 BuildCommand
= BuildCommand
+ [Target
]
1375 AutoGenObject
.BuildTime
= LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1376 self
.CreateAsBuiltInf()
1377 if GlobalData
.gBinCacheDest
:
1378 self
.UpdateBuildCache()
1379 self
.BuildModules
= []
1384 if GenFdsApi(AutoGenObject
.GenFdsCommandDict
, self
.Db
):
1385 EdkLogger
.error("build", COMMAND_FAILURE
)
1393 if Target
== 'libraries':
1400 if Target
== 'cleanall':
1402 #os.rmdir(AutoGenObject.BuildDir)
1403 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1404 except WindowsError as X
:
1405 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1408 ## Rebase module image and Get function address for the input module list.
1410 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1412 AddrIsOffset
= False
1413 for InfFile
in ModuleList
:
1414 sys
.stdout
.write (".")
1416 ModuleInfo
= ModuleList
[InfFile
]
1417 ModuleName
= ModuleInfo
.BaseName
1418 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1419 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1420 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1422 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1424 # Update Image to new BaseAddress by GenFw tool
1426 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1427 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1430 # Set new address to the section header only for SMM driver.
1432 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1433 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1435 # Collect function address from Map file
1437 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1439 if os
.path
.exists(ImageMapTable
):
1440 OrigImageBaseAddress
= 0
1441 ImageMap
= open(ImageMapTable
, 'r')
1442 for LinStr
in ImageMap
:
1443 if len (LinStr
.strip()) == 0:
1446 # Get the preferred address set on link time.
1448 if LinStr
.find ('Preferred load address is') != -1:
1449 StrList
= LinStr
.split()
1450 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1452 StrList
= LinStr
.split()
1453 if len (StrList
) > 4:
1454 if StrList
[3] == 'f' or StrList
[3] == 'F':
1456 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1457 FunctionList
.append ((Name
, RelativeAddress
))
1461 # Add general information.
1464 MapBuffer
.append('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1466 MapBuffer
.append('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1468 MapBuffer
.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1470 # Add guid and general seciton section.
1472 TextSectionAddress
= 0
1473 DataSectionAddress
= 0
1474 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1475 if SectionHeader
[0] == '.text':
1476 TextSectionAddress
= SectionHeader
[1]
1477 elif SectionHeader
[0] in ['.data', '.sdata']:
1478 DataSectionAddress
= SectionHeader
[1]
1480 MapBuffer
.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1482 MapBuffer
.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1484 # Add debug image full path.
1486 MapBuffer
.append('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1488 # Add function address
1490 for Function
in FunctionList
:
1492 MapBuffer
.append(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1494 MapBuffer
.append(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1498 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1501 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1503 ## Collect MAP information of all FVs
1505 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1507 # First get the XIP base address for FV map file.
1508 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1509 GuidName
= re
.compile(r
"\(GUID=[-a-fA-F0-9]+")
1510 for FvName
in Wa
.FdfProfile
.FvDict
:
1511 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1512 if not os
.path
.exists(FvMapBuffer
):
1514 FvMap
= open(FvMapBuffer
, 'r')
1515 #skip FV size information
1521 MatchGuid
= GuidPattern
.match(Line
)
1522 if MatchGuid
is not None:
1524 # Replace GUID with module name
1526 GuidString
= MatchGuid
.group()
1527 if GuidString
.upper() in ModuleList
:
1528 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1529 MapBuffer
.append(Line
)
1531 # Add the debug image full path.
1533 MatchGuid
= GuidName
.match(Line
)
1534 if MatchGuid
is not None:
1535 GuidString
= MatchGuid
.group().split("=")[1]
1536 if GuidString
.upper() in ModuleList
:
1537 MapBuffer
.append('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1541 ## Collect MAP information of all modules
1543 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1544 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1546 PatchEfiImageList
= []
1554 # reserve 4K size in SMRAM to make SMM module address not from 0.
1556 for ModuleGuid
in ModuleList
:
1557 Module
= ModuleList
[ModuleGuid
]
1558 GlobalData
.gProcessingFile
= "%s [%s, %s, %s]" % (Module
.MetaFile
, Module
.Arch
, Module
.ToolChain
, Module
.BuildTarget
)
1560 OutputImageFile
= ''
1561 for ResultFile
in Module
.CodaTargetList
:
1562 if str(ResultFile
.Target
).endswith('.efi'):
1564 # module list for PEI, DXE, RUNTIME and SMM
1566 OutputImageFile
= os
.path
.join(Module
.OutputDir
, Module
.Name
+ '.efi')
1567 ImageClass
= PeImageClass (OutputImageFile
)
1568 if not ImageClass
.IsValid
:
1569 EdkLogger
.error("build", FILE_PARSE_FAILURE
, ExtraData
=ImageClass
.ErrorInfo
)
1570 ImageInfo
= PeImageInfo(Module
.Name
, Module
.Guid
, Module
.Arch
, Module
.OutputDir
, Module
.DebugDir
, ImageClass
)
1571 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
]:
1572 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1573 PeiSize
+= ImageInfo
.Image
.Size
1574 elif Module
.ModuleType
in [EDK_COMPONENT_TYPE_BS_DRIVER
, SUP_MODULE_DXE_DRIVER
, SUP_MODULE_UEFI_DRIVER
]:
1575 BtModuleList
[Module
.MetaFile
] = ImageInfo
1576 BtSize
+= ImageInfo
.Image
.Size
1577 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
]:
1578 RtModuleList
[Module
.MetaFile
] = ImageInfo
1579 RtSize
+= ImageInfo
.Image
.Size
1580 elif Module
.ModuleType
in [SUP_MODULE_SMM_CORE
, SUP_MODULE_DXE_SMM_DRIVER
, SUP_MODULE_MM_STANDALONE
, SUP_MODULE_MM_CORE_STANDALONE
]:
1581 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1582 SmmSize
+= ImageInfo
.Image
.Size
1583 if Module
.ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
1584 PiSpecVersion
= Module
.Module
.Specification
.get('PI_SPECIFICATION_VERSION', '0x00000000')
1585 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1586 if int(PiSpecVersion
, 16) < 0x0001000A:
1587 BtModuleList
[Module
.MetaFile
] = ImageInfo
1588 BtSize
+= ImageInfo
.Image
.Size
1591 # EFI image is final target.
1592 # Check EFI image contains patchable FixAddress related PCDs.
1594 if OutputImageFile
!= '':
1595 ModuleIsPatch
= False
1596 for Pcd
in Module
.ModulePcdList
:
1597 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1598 ModuleIsPatch
= True
1600 if not ModuleIsPatch
:
1601 for Pcd
in Module
.LibraryPcdList
:
1602 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1603 ModuleIsPatch
= True
1606 if not ModuleIsPatch
:
1609 # Module includes the patchable load fix address PCDs.
1610 # It will be fixed up later.
1612 PatchEfiImageList
.append (OutputImageFile
)
1615 # Get Top Memory address
1617 ReservedRuntimeMemorySize
= 0
1618 TopMemoryAddress
= 0
1619 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1620 TopMemoryAddress
= 0
1622 TopMemoryAddress
= self
.LoadFixAddress
1623 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1624 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1627 # Patch FixAddress related PCDs into EFI image
1629 for EfiImage
in PatchEfiImageList
:
1630 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1631 if not os
.path
.exists(EfiImageMap
):
1634 # Get PCD offset in EFI image by GenPatchPcdTable function
1636 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1638 # Patch real PCD value by PatchPcdValue tool
1640 for PcdInfo
in PcdTable
:
1642 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1643 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
// 0x1000))
1644 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1645 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
// 0x1000))
1646 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1647 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
// 0x1000))
1648 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1649 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
// 0x1000))
1650 if ReturnValue
!= 0:
1651 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1653 MapBuffer
.append('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
// 0x1000))
1654 MapBuffer
.append('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
// 0x1000))
1655 MapBuffer
.append('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
// 0x1000))
1656 if len (SmmModuleList
) > 0:
1657 MapBuffer
.append('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
// 0x1000))
1659 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1660 BtBaseAddr
= TopMemoryAddress
- RtSize
1661 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1663 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1664 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1665 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1666 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
=False, ModeIsSmm
=True)
1667 MapBuffer
.append('\n\n')
1668 sys
.stdout
.write ("\n")
1671 ## Save platform Map file
1673 def _SaveMapFile (self
, MapBuffer
, Wa
):
1675 # Map file path is got.
1677 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1679 # Save address map into MAP file.
1681 SaveFileOnChange(MapFilePath
, ''.join(MapBuffer
), False)
1682 if self
.LoadFixAddress
!= 0:
1683 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath
))
1686 ## Build active platform for different build targets and different tool chains
1688 def _BuildPlatform(self
):
1689 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1690 for BuildTarget
in self
.BuildTargetList
:
1691 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1693 for ToolChain
in self
.ToolChainList
:
1694 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1695 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1696 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1698 Wa
= WorkspaceAutoGen(
1715 self
.Fdf
= Wa
.FdfFile
1716 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1717 self
.BuildReport
.AddPlatformReport(Wa
)
1718 self
.Progress
.Stop("done!")
1720 # Add ffs build to makefile
1722 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1723 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1725 for Arch
in Wa
.ArchList
:
1727 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1728 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1729 for Module
in Pa
.Platform
.Modules
:
1730 # Get ModuleAutoGen object to generate C code file and makefile
1731 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1735 Ma
.PlatformInfo
= Pa
1737 PcdMaList
.append(Ma
)
1738 self
.BuildModules
.append(Ma
)
1739 self
._BuildPa
(self
.Target
, Pa
, FfsCommand
=CmdListDict
,PcdMaList
=PcdMaList
)
1741 # Create MAP file when Load Fix Address is enabled.
1742 if self
.Target
in ["", "all", "fds"]:
1743 for Arch
in Wa
.ArchList
:
1744 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1746 # Check whether the set fix address is above 4G for 32bit image.
1748 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1749 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")
1754 for Pa
in Wa
.AutoGenObjectList
:
1755 for Ma
in Pa
.ModuleAutoGenList
:
1758 if not Ma
.IsLibrary
:
1759 ModuleList
[Ma
.Guid
.upper()] = Ma
1762 if self
.LoadFixAddress
!= 0:
1764 # Rebase module to the preferred memory address before GenFds
1766 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1769 # create FDS again for the updated EFI image
1771 self
._Build
("fds", Wa
)
1773 # Create MAP file for all platform FVs after GenFds.
1775 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1777 # Save MAP buffer into MAP file.
1779 self
._SaveMapFile
(MapBuffer
, Wa
)
1781 ## Build active module for different build targets, different tool chains and different archs
1783 def _BuildModule(self
):
1784 for BuildTarget
in self
.BuildTargetList
:
1785 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1787 for ToolChain
in self
.ToolChainList
:
1788 WorkspaceAutoGenTime
= time
.time()
1789 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1790 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1791 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1794 # module build needs platform build information, so get platform
1797 Wa
= WorkspaceAutoGen(
1815 self
.Fdf
= Wa
.FdfFile
1816 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1817 Wa
.CreateMakeFile(False)
1818 # Add ffs build to makefile
1820 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1821 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1823 # Add Platform and Package level hash in share_data for module hash calculation later
1824 if GlobalData
.gBinCacheSource
or GlobalData
.gBinCacheDest
:
1825 GlobalData
.gCacheIR
[('PlatformHash')] = GlobalData
.gPlatformHash
1826 for PkgName
in GlobalData
.gPackageHash
.keys():
1827 GlobalData
.gCacheIR
[(PkgName
, 'PackageHash')] = GlobalData
.gPackageHash
[PkgName
]
1828 GlobalData
.file_lock
= mp
.Lock()
1829 GlobalData
.FfsCmd
= CmdListDict
1831 self
.Progress
.Stop("done!")
1833 ExitFlag
= threading
.Event()
1835 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1836 for Arch
in Wa
.ArchList
:
1837 AutoGenStart
= time
.time()
1838 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1839 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1840 GlobalData
.libConstPcd
= Pa
.DataPipe
.Get("LibConstPcd")
1841 GlobalData
.Refes
= Pa
.DataPipe
.Get("REFS")
1842 for Module
in Pa
.Platform
.Modules
:
1843 if self
.ModuleFile
.Dir
== Module
.Dir
and self
.ModuleFile
.Name
== Module
.Name
:
1844 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1849 if GlobalData
.gBinCacheSource
and self
.Target
in [None, "", "all"]:
1850 Ma
.GenModuleFilesHash(GlobalData
.gCacheIR
)
1851 Ma
.GenPreMakefileHash(GlobalData
.gCacheIR
)
1852 if Ma
.CanSkipbyPreMakefileCache(GlobalData
.gCacheIR
):
1853 self
.HashSkipModules
.append(Ma
)
1854 EdkLogger
.quiet("cache hit: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1857 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1858 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1859 # for target which must generate AutoGen code and makefile
1860 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1861 self
.Progress
.Start("Generating code")
1862 Ma
.CreateCodeFile(True)
1863 self
.Progress
.Stop("done!")
1864 if self
.Target
== "genc":
1866 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1867 self
.Progress
.Start("Generating makefile")
1868 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
1869 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
1870 del CmdListDict
[Module
.File
, Arch
]
1872 Ma
.CreateMakeFile(True)
1873 self
.Progress
.Stop("done!")
1874 if self
.Target
== "genmake":
1877 if GlobalData
.gBinCacheSource
and self
.Target
in [None, "", "all"]:
1878 Ma
.GenMakeHeaderFilesHash(GlobalData
.gCacheIR
)
1879 Ma
.GenMakeHash(GlobalData
.gCacheIR
)
1880 if Ma
.CanSkipbyMakeCache(GlobalData
.gCacheIR
):
1881 self
.HashSkipModules
.append(Ma
)
1882 EdkLogger
.quiet("cache hit: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1885 EdkLogger
.quiet("cache miss: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1886 Ma
.PrintFirstMakeCacheMissFile(GlobalData
.gCacheIR
)
1888 self
.BuildModules
.append(Ma
)
1889 # Initialize all modules in tracking to 'FAIL'
1890 GlobalData
.gModuleBuildTracking
[Ma
] = 'FAIL'
1891 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1892 MakeStart
= time
.time()
1893 for Ma
in self
.BuildModules
:
1894 if not Ma
.IsBinaryModule
:
1895 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
1896 # Break build if any build thread has error
1897 if BuildTask
.HasError():
1898 # we need a full version of makefile for platform
1900 BuildTask
.WaitForComplete()
1901 self
.invalidateHash()
1902 Pa
.CreateMakeFile(False)
1903 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1904 # Start task scheduler
1905 if not BuildTask
.IsOnGoing():
1906 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1908 # in case there's an interruption. we need a full version of makefile for platform
1909 Pa
.CreateMakeFile(False)
1910 if BuildTask
.HasError():
1911 self
.invalidateHash()
1912 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1913 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1915 MakeContiue
= time
.time()
1917 BuildTask
.WaitForComplete()
1918 self
.CreateAsBuiltInf()
1919 if GlobalData
.gBinCacheDest
:
1920 self
.UpdateBuildCache()
1921 self
.BuildModules
= []
1922 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1923 if BuildTask
.HasError():
1924 self
.invalidateHash()
1925 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1927 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1932 "Module for [%s] is not a component of active platform."\
1933 " Please make sure that the ARCH and inf file path are"\
1934 " given in the same as in [%s]" % \
1935 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1936 ExtraData
=self
.ModuleFile
1938 # Create MAP file when Load Fix Address is enabled.
1939 if self
.Target
== "fds" and self
.Fdf
:
1940 for Arch
in Wa
.ArchList
:
1942 # Check whether the set fix address is above 4G for 32bit image.
1944 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1945 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")
1950 for Pa
in Wa
.AutoGenObjectList
:
1951 for Ma
in Pa
.ModuleAutoGenList
:
1954 if not Ma
.IsLibrary
:
1955 ModuleList
[Ma
.Guid
.upper()] = Ma
1958 if self
.LoadFixAddress
!= 0:
1960 # Rebase module to the preferred memory address before GenFds
1962 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1964 # create FDS again for the updated EFI image
1966 GenFdsStart
= time
.time()
1967 self
._Build
("fds", Wa
)
1968 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
1970 # Create MAP file for all platform FVs after GenFds.
1972 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1974 # Save MAP buffer into MAP file.
1976 self
._SaveMapFile
(MapBuffer
, Wa
)
1977 self
.invalidateHash()
1979 def _GenFfsCmd(self
,ArchList
):
1980 # convert dictionary of Cmd:(Inf,Arch)
1981 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
1982 CmdSetDict
= defaultdict(set)
1983 GenFfsDict
= GenFds
.GenFfsMakefile('', GlobalData
.gFdfParser
, self
, ArchList
, GlobalData
)
1984 for Cmd
in GenFfsDict
:
1985 tmpInf
, tmpArch
= GenFfsDict
[Cmd
]
1986 CmdSetDict
[tmpInf
, tmpArch
].add(Cmd
)
1989 ## Build a platform in multi-thread mode
1991 def _MultiThreadBuildPlatform(self
):
1992 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1993 for BuildTarget
in self
.BuildTargetList
:
1994 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1996 for ToolChain
in self
.ToolChainList
:
1997 WorkspaceAutoGenTime
= time
.time()
1998 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1999 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
2000 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
2002 Wa
= WorkspaceAutoGen(
2019 self
.Fdf
= Wa
.FdfFile
2020 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
2021 self
.BuildReport
.AddPlatformReport(Wa
)
2022 Wa
.CreateMakeFile(False)
2024 # Add ffs build to makefile
2026 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
2027 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
2029 # Add Platform and Package level hash in share_data for module hash calculation later
2030 if GlobalData
.gBinCacheSource
or GlobalData
.gBinCacheDest
:
2031 GlobalData
.gCacheIR
[('PlatformHash')] = GlobalData
.gPlatformHash
2032 for PkgName
in GlobalData
.gPackageHash
.keys():
2033 GlobalData
.gCacheIR
[(PkgName
, 'PackageHash')] = GlobalData
.gPackageHash
[PkgName
]
2035 # multi-thread exit flag
2036 ExitFlag
= threading
.Event()
2038 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
2039 self
.BuildModules
= []
2041 for Arch
in Wa
.ArchList
:
2043 AutoGenStart
= time
.time()
2044 GlobalData
.gGlobalDefines
['ARCH'] = Arch
2045 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
2049 for Inf
in Pa
.Platform
.Modules
:
2050 ModuleList
.append(Inf
)
2051 # Add the INF only list in FDF
2052 if GlobalData
.gFdfParser
is not None:
2053 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
2054 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
2055 if Inf
in Pa
.Platform
.Modules
:
2057 ModuleList
.append(Inf
)
2058 Pa
.DataPipe
.DataContainer
= {"FfsCommand":CmdListDict
}
2059 Pa
.DataPipe
.DataContainer
= {"Workspace_timestamp": Wa
._SrcTimeStamp
}
2060 Pa
.DataPipe
.DataContainer
= {"CommandTarget": self
.Target
}
2061 for Module
in ModuleList
:
2062 # Get ModuleAutoGen object to generate C code file and makefile
2063 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2068 Ma
.PlatformInfo
= Pa
2070 PcdMaList
.append(Ma
)
2071 TotalModules
.append(Ma
)
2072 # Initialize all modules in tracking to 'FAIL'
2073 GlobalData
.gModuleBuildTracking
[Ma
] = 'FAIL'
2076 for m
in Pa
.GetAllModuleInfo
:
2078 data_pipe_file
= os
.path
.join(Pa
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(Pa
.Guid
),Pa
.Arch
))
2079 Pa
.DataPipe
.dump(data_pipe_file
)
2080 autogen_rt
, errorcode
= self
.StartAutoGen(mqueue
, Pa
.DataPipe
, self
.SkipAutoGen
, PcdMaList
, GlobalData
.gCacheIR
)
2082 # Skip cache hit modules
2083 if GlobalData
.gBinCacheSource
:
2084 for Ma
in TotalModules
:
2085 if (Ma
.MetaFile
.Path
, Ma
.Arch
) in GlobalData
.gCacheIR
and \
2086 GlobalData
.gCacheIR
[(Ma
.MetaFile
.Path
, Ma
.Arch
)].PreMakeCacheHit
:
2087 self
.HashSkipModules
.append(Ma
)
2089 if (Ma
.MetaFile
.Path
, Ma
.Arch
) in GlobalData
.gCacheIR
and \
2090 GlobalData
.gCacheIR
[(Ma
.MetaFile
.Path
, Ma
.Arch
)].MakeCacheHit
:
2091 self
.HashSkipModules
.append(Ma
)
2093 self
.BuildModules
.append(Ma
)
2095 self
.BuildModules
.extend(TotalModules
)
2098 self
.AutoGenMgr
.TerminateWorkers()
2099 self
.AutoGenMgr
.join(0.1)
2100 raise FatalError(errorcode
)
2101 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
2102 self
.Progress
.Stop("done!")
2104 if GlobalData
.gBinCacheSource
:
2105 EdkLogger
.quiet("Total cache hit driver num: %s, cache miss driver num: %s" % (len(set(self
.HashSkipModules
)), len(set(self
.BuildModules
))))
2107 CacheNotHitMa
= set()
2108 for IR
in GlobalData
.gCacheIR
.keys():
2109 if 'PlatformHash' in IR
or 'PackageHash' in IR
:
2111 if GlobalData
.gCacheIR
[IR
].PreMakeCacheHit
or GlobalData
.gCacheIR
[IR
].MakeCacheHit
:
2114 # There might be binary module or module which has .inc files, not count for cache miss
2115 CacheNotHitMa
.add(IR
)
2116 EdkLogger
.quiet("Total module num: %s, cache hit module num: %s" % (len(CacheHitMa
)+len(CacheNotHitMa
), len(CacheHitMa
)))
2118 for Arch
in Wa
.ArchList
:
2119 MakeStart
= time
.time()
2120 for Ma
in set(self
.BuildModules
):
2121 # Generate build task for the module
2122 if not Ma
.IsBinaryModule
:
2123 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
2124 # Break build if any build thread has error
2125 if BuildTask
.HasError():
2126 # we need a full version of makefile for platform
2128 BuildTask
.WaitForComplete()
2129 self
.invalidateHash()
2130 Pa
.CreateMakeFile(False)
2131 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2132 # Start task scheduler
2133 if not BuildTask
.IsOnGoing():
2134 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
2136 # in case there's an interruption. we need a full version of makefile for platform
2137 Pa
.CreateMakeFile(False)
2138 if BuildTask
.HasError():
2139 self
.invalidateHash()
2140 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2141 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
2143 MakeContiue
= time
.time()
2147 # All modules have been put in build tasks queue. Tell task scheduler
2148 # to exit if all tasks are completed
2151 BuildTask
.WaitForComplete()
2152 self
.CreateAsBuiltInf()
2153 if GlobalData
.gBinCacheDest
:
2154 self
.UpdateBuildCache()
2155 self
.BuildModules
= []
2156 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2158 # Check for build error, and raise exception if one
2159 # has been signaled.
2161 if BuildTask
.HasError():
2162 self
.invalidateHash()
2163 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2165 # Create MAP file when Load Fix Address is enabled.
2166 if self
.Target
in ["", "all", "fds"]:
2167 for Arch
in Wa
.ArchList
:
2169 # Check whether the set fix address is above 4G for 32bit image.
2171 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2172 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")
2177 for Pa
in Wa
.AutoGenObjectList
:
2178 for Ma
in Pa
.ModuleAutoGenList
:
2181 if not Ma
.IsLibrary
:
2182 ModuleList
[Ma
.Guid
.upper()] = Ma
2184 # Rebase module to the preferred memory address before GenFds
2187 if self
.LoadFixAddress
!= 0:
2188 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2192 # Generate FD image if there's a FDF file found
2194 GenFdsStart
= time
.time()
2195 if GenFdsApi(Wa
.GenFdsCommandDict
, self
.Db
):
2196 EdkLogger
.error("build", COMMAND_FAILURE
)
2199 # Create MAP file for all platform FVs after GenFds.
2201 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2202 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2204 # Save MAP buffer into MAP file.
2206 self
._SaveMapFile
(MapBuffer
, Wa
)
2207 self
.invalidateHash()
2209 ## Generate GuidedSectionTools.txt in the FV directories.
2211 def CreateGuidedSectionToolsFile(self
):
2212 for BuildTarget
in self
.BuildTargetList
:
2213 for ToolChain
in self
.ToolChainList
:
2214 Wa
= WorkspaceAutoGen(
2231 if not os
.path
.exists(FvDir
):
2234 for Arch
in self
.ArchList
:
2235 # Build up the list of supported architectures for this build
2236 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
2238 # Look through the tool definitions for GUIDed tools
2240 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.items():
2241 if attrib
.upper().endswith('_GUID'):
2242 split
= attrib
.split('_')
2243 thisPrefix
= '_'.join(split
[0:3]) + '_'
2244 if thisPrefix
== prefix
:
2245 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
2248 path
= '_'.join(split
[0:4]) + '_PATH'
2249 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2250 path
= self
.GetFullPathOfTool(path
)
2251 guidAttribs
.append((guid
, toolName
, path
))
2253 # Write out GuidedSecTools.txt
2254 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2255 toolsFile
= open(toolsFile
, 'wt')
2256 for guidedSectionTool
in guidAttribs
:
2257 print(' '.join(guidedSectionTool
), file=toolsFile
)
2260 ## Returns the full path of the tool.
2262 def GetFullPathOfTool (self
, tool
):
2263 if os
.path
.exists(tool
):
2264 return os
.path
.realpath(tool
)
2266 # We need to search for the tool using the
2267 # PATH environment variable.
2268 for dirInPath
in os
.environ
['PATH'].split(os
.pathsep
):
2269 foundPath
= os
.path
.join(dirInPath
, tool
)
2270 if os
.path
.exists(foundPath
):
2271 return os
.path
.realpath(foundPath
)
2273 # If the tool was not found in the path then we just return
2277 ## Launch the module or platform build
2280 if not self
.ModuleFile
:
2281 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2282 self
.SpawnMode
= False
2283 self
._BuildPlatform
()
2285 self
._MultiThreadBuildPlatform
()
2286 self
.CreateGuidedSectionToolsFile()
2288 self
.SpawnMode
= False
2291 if self
.Target
== 'cleanall':
2292 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2294 def CreateAsBuiltInf(self
):
2295 for Module
in self
.BuildModules
:
2296 Module
.CreateAsBuiltInf()
2298 def UpdateBuildCache(self
):
2301 for Module
in self
.BuildModules
:
2302 Module
.CopyModuleToCache()
2303 all_mod_set
.add(Module
)
2304 for Module
in self
.HashSkipModules
:
2305 Module
.CopyModuleToCache()
2306 all_mod_set
.add(Module
)
2307 for Module
in all_mod_set
:
2308 for lib
in Module
.LibraryAutoGenList
:
2309 all_lib_set
.add(lib
)
2310 for lib
in all_lib_set
:
2311 lib
.CopyModuleToCache()
2314 self
.HashSkipModules
= []
2315 ## Do some clean-up works when error occurred
2316 def Relinquish(self
):
2317 OldLogLevel
= EdkLogger
.GetLevel()
2318 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2319 Utils
.Progressor
.Abort()
2320 if self
.SpawnMode
== True:
2322 EdkLogger
.SetLevel(OldLogLevel
)
2324 def ParseDefines(DefineList
=[]):
2326 if DefineList
is not None:
2327 for Define
in DefineList
:
2328 DefineTokenList
= Define
.split("=", 1)
2329 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2330 EdkLogger
.error('build', FORMAT_INVALID
,
2331 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2332 ExtraData
=DefineTokenList
[0])
2334 if len(DefineTokenList
) == 1:
2335 DefineDict
[DefineTokenList
[0]] = "TRUE"
2337 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2342 def LogBuildTime(Time
):
2345 TimeDur
= time
.gmtime(Time
)
2346 if TimeDur
.tm_yday
> 1:
2347 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2349 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2354 ThreadNumber
= BuildOption
.ThreadNumber
2355 if ThreadNumber
is None:
2356 ThreadNumber
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
2357 if ThreadNumber
== '':
2360 ThreadNumber
= int(ThreadNumber
, 0)
2362 if ThreadNumber
== 0:
2364 ThreadNumber
= multiprocessing
.cpu_count()
2365 except (ImportError, NotImplementedError):
2368 ## Tool entrance method
2370 # This method mainly dispatch specific methods per the command line options.
2371 # If no error found, return zero value so the caller of this tool can know
2372 # if it's executed successfully or not.
2374 # @retval 0 Tool was successful
2375 # @retval 1 Tool failed
2377 LogQMaxSize
= ThreadNum() * 10
2379 StartTime
= time
.time()
2382 # Create a log Queue
2384 LogQ
= mp
.Queue(LogQMaxSize
)
2385 # Initialize log system
2386 EdkLogger
.LogClientInitialize(LogQ
)
2387 GlobalData
.gCommand
= sys
.argv
[1:]
2389 # Parse the options and args
2391 Option
, Target
= BuildOption
, BuildTarget
2392 GlobalData
.gOptions
= Option
2393 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2396 LogLevel
= EdkLogger
.INFO
2397 if Option
.verbose
is not None:
2398 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2399 LogLevel
= EdkLogger
.VERBOSE
2400 elif Option
.quiet
is not None:
2401 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2402 LogLevel
= EdkLogger
.QUIET
2403 elif Option
.debug
is not None:
2404 EdkLogger
.SetLevel(Option
.debug
+ 1)
2405 LogLevel
= Option
.debug
+ 1
2407 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2409 if Option
.WarningAsError
== True:
2410 EdkLogger
.SetWarningAsError()
2411 Log_Agent
= LogAgent(LogQ
,LogLevel
,Option
.LogFile
)
2414 if platform
.platform().find("Windows") >= 0:
2415 GlobalData
.gIsWindows
= True
2417 GlobalData
.gIsWindows
= False
2419 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2420 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2425 if len(Target
) == 0:
2427 elif len(Target
) >= 2:
2428 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2429 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2431 Target
= Target
[0].lower()
2433 if Target
not in gSupportedTarget
:
2434 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2435 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2438 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2441 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2443 Workspace
= os
.getenv("WORKSPACE")
2445 # Get files real name in workspace dir
2447 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2449 WorkingDirectory
= os
.getcwd()
2450 if not Option
.ModuleFile
:
2451 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2452 FileNum
= len(FileList
)
2454 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2455 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2457 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2459 if Option
.ModuleFile
:
2460 if os
.path
.isabs (Option
.ModuleFile
):
2461 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2462 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2463 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2464 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2466 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2468 if Option
.PlatformFile
is not None:
2469 if os
.path
.isabs (Option
.PlatformFile
):
2470 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2471 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2472 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2474 if Option
.FdfFile
is not None:
2475 if os
.path
.isabs (Option
.FdfFile
):
2476 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2477 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2478 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2479 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2481 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2483 if Option
.Flag
is not None and Option
.Flag
not in ['-c', '-s']:
2484 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2486 MyBuild
= Build(Target
, Workspace
, Option
,LogQ
)
2487 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2488 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2492 # All job done, no error found and no exception raised
2495 except FatalError
as X
:
2496 if MyBuild
is not None:
2497 # for multi-thread build exits safely
2498 MyBuild
.Relinquish()
2499 if Option
is not None and Option
.debug
is not None:
2500 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2501 ReturnCode
= X
.args
[0]
2502 except Warning as X
:
2503 # error from Fdf parser
2504 if MyBuild
is not None:
2505 # for multi-thread build exits safely
2506 MyBuild
.Relinquish()
2507 if Option
is not None and Option
.debug
is not None:
2508 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2510 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2511 ReturnCode
= FORMAT_INVALID
2512 except KeyboardInterrupt:
2513 if MyBuild
is not None:
2515 # for multi-thread build exits safely
2516 MyBuild
.Relinquish()
2517 ReturnCode
= ABORT_ERROR
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())
2521 if MyBuild
is not None:
2522 # for multi-thread build exits safely
2523 MyBuild
.Relinquish()
2525 # try to get the meta-file from the object causing exception
2526 Tb
= sys
.exc_info()[-1]
2527 MetaFile
= GlobalData
.gProcessingFile
2528 while Tb
is not None:
2529 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2530 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2535 "Unknown fatal error when processing [%s]" % MetaFile
,
2536 ExtraData
="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR
,
2539 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2540 ReturnCode
= CODE_ERROR
2542 Utils
.Progressor
.Abort()
2543 Utils
.ClearDuplicatedInf()
2547 MyBuild
.LaunchPostbuild()
2550 Conclusion
= "Failed"
2551 elif ReturnCode
== ABORT_ERROR
:
2552 Conclusion
= "Aborted"
2554 Conclusion
= "Failed"
2555 FinishTime
= time
.time()
2556 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2557 BuildDurationStr
= ""
2558 if BuildDuration
.tm_yday
> 1:
2559 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2561 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2562 if MyBuild
is not None:
2564 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2566 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2567 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2568 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2569 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2574 if __name__
== '__main__':
2576 mp
.set_start_method('spawn')
2580 ## 0-127 is a safe return range, and 1 is a standard default error
2581 if r
< 0 or r
> 127: r
= 1