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 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
.CanSkipbyHash():
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
.Arch
in GlobalData
.gModuleBuildTracking
and
634 self
.BuildItem
.BuildObject
in GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
.Arch
] and
635 GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
.Arch
][self
.BuildItem
.BuildObject
] != 'FAIL_METAFILE' and
636 not BuildTask
._ErrorFlag
.isSet()
638 GlobalData
.gModuleBuildTracking
[self
.BuildItem
.BuildObject
.Arch
][self
.BuildItem
.BuildObject
] = 'SUCCESS'
640 # indicate there's a thread is available for another build task
641 BuildTask
._RunningQueueLock
.acquire()
642 BuildTask
._RunningQueue
.pop(self
.BuildItem
)
643 BuildTask
._RunningQueueLock
.release()
644 BuildTask
._Thread
.release()
646 ## Start build task thread
649 EdkLogger
.quiet("Building ... %s" % repr(self
.BuildItem
))
650 Command
= self
.BuildItem
.BuildCommand
+ [self
.BuildItem
.Target
]
651 self
.BuildTread
= Thread(target
=self
._CommandThread
, args
=(Command
, self
.BuildItem
.WorkingDir
))
652 self
.BuildTread
.setName("build thread")
653 self
.BuildTread
.setDaemon(False)
654 self
.BuildTread
.start()
656 ## The class contains the information related to EFI image
661 # Constructor will load all required image information.
663 # @param BaseName The full file path of image.
664 # @param Guid The GUID for image.
665 # @param Arch Arch of this image.
666 # @param OutputDir The output directory for image.
667 # @param DebugDir The debug directory for image.
668 # @param ImageClass PeImage Information
670 def __init__(self
, BaseName
, Guid
, Arch
, OutputDir
, DebugDir
, ImageClass
):
671 self
.BaseName
= BaseName
674 self
.OutputDir
= OutputDir
675 self
.DebugDir
= DebugDir
676 self
.Image
= ImageClass
677 self
.Image
.Size
= (self
.Image
.Size
// 0x1000 + 1) * 0x1000
679 ## The class implementing the EDK2 build process
681 # The build process includes:
682 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
683 # 2. Parse DSC file of active platform
684 # 3. Parse FDF file if any
685 # 4. Establish build database, including parse all other files (module, package)
686 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
687 # 6. Call build command
692 # Constructor will load all necessary configurations, parse platform, modules
693 # and packages and the establish a database for AutoGen.
695 # @param Target The build command target, one of gSupportedTarget
696 # @param WorkspaceDir The directory of workspace
697 # @param BuildOptions Build options passed from command line
699 def __init__(self
, Target
, WorkspaceDir
, BuildOptions
,log_q
):
700 self
.WorkspaceDir
= WorkspaceDir
702 self
.PlatformFile
= BuildOptions
.PlatformFile
703 self
.ModuleFile
= BuildOptions
.ModuleFile
704 self
.ArchList
= BuildOptions
.TargetArch
705 self
.ToolChainList
= BuildOptions
.ToolChain
706 self
.BuildTargetList
= BuildOptions
.BuildTarget
707 self
.Fdf
= BuildOptions
.FdfFile
708 self
.FdList
= BuildOptions
.RomImage
709 self
.FvList
= BuildOptions
.FvImage
710 self
.CapList
= BuildOptions
.CapName
711 self
.SilentMode
= BuildOptions
.SilentMode
712 self
.ThreadNumber
= 1
713 self
.SkipAutoGen
= BuildOptions
.SkipAutoGen
714 self
.Reparse
= BuildOptions
.Reparse
715 self
.SkuId
= BuildOptions
.SkuId
717 GlobalData
.gSKUID_CMD
= self
.SkuId
718 self
.ConfDirectory
= BuildOptions
.ConfDirectory
719 self
.SpawnMode
= True
720 self
.BuildReport
= BuildReport(BuildOptions
.ReportFile
, BuildOptions
.ReportType
)
721 self
.TargetTxt
= TargetTxt
722 self
.ToolDef
= ToolDef
726 GlobalData
.BuildOptionPcd
= BuildOptions
.OptionPcd
if BuildOptions
.OptionPcd
else []
727 #Set global flag for build mode
728 GlobalData
.gIgnoreSource
= BuildOptions
.IgnoreSources
729 GlobalData
.gUseHashCache
= BuildOptions
.UseHashCache
730 GlobalData
.gBinCacheDest
= BuildOptions
.BinCacheDest
731 GlobalData
.gBinCacheSource
= BuildOptions
.BinCacheSource
732 GlobalData
.gEnableGenfdsMultiThread
= BuildOptions
.GenfdsMultiThread
733 GlobalData
.gDisableIncludePathCheck
= BuildOptions
.DisableIncludePathCheck
735 if GlobalData
.gBinCacheDest
and not GlobalData
.gUseHashCache
:
736 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination must be used together with --hash.")
738 if GlobalData
.gBinCacheSource
and not GlobalData
.gUseHashCache
:
739 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-source must be used together with --hash.")
741 if GlobalData
.gBinCacheDest
and GlobalData
.gBinCacheSource
:
742 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination can not be used together with --binary-source.")
744 if GlobalData
.gBinCacheSource
:
745 BinCacheSource
= os
.path
.normpath(GlobalData
.gBinCacheSource
)
746 if not os
.path
.isabs(BinCacheSource
):
747 BinCacheSource
= mws
.join(self
.WorkspaceDir
, BinCacheSource
)
748 GlobalData
.gBinCacheSource
= BinCacheSource
750 if GlobalData
.gBinCacheSource
is not None:
751 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-source.")
753 if GlobalData
.gBinCacheDest
:
754 BinCacheDest
= os
.path
.normpath(GlobalData
.gBinCacheDest
)
755 if not os
.path
.isabs(BinCacheDest
):
756 BinCacheDest
= mws
.join(self
.WorkspaceDir
, BinCacheDest
)
757 GlobalData
.gBinCacheDest
= BinCacheDest
759 if GlobalData
.gBinCacheDest
is not None:
760 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-destination.")
762 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(GlobalData
.gConfDirectory
, GlobalData
.gDatabasePath
))
763 if not os
.path
.exists(os
.path
.join(GlobalData
.gConfDirectory
, '.cache')):
764 os
.makedirs(os
.path
.join(GlobalData
.gConfDirectory
, '.cache'))
766 self
.BuildDatabase
= self
.Db
.BuildObject
768 self
.ToolChainFamily
= None
769 self
.LoadFixAddress
= 0
770 self
.UniFlag
= BuildOptions
.Flag
771 self
.BuildModules
= []
772 self
.HashSkipModules
= []
774 self
.LaunchPrebuildFlag
= False
775 self
.PlatformBuildPath
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PlatformBuild')
776 if BuildOptions
.CommandLength
:
777 GlobalData
.gCommandMaxLength
= BuildOptions
.CommandLength
779 # print dot character during doing some time-consuming work
780 self
.Progress
= Utils
.Progressor()
781 # print current build environment and configuration
782 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
783 if "PACKAGES_PATH" in os
.environ
:
784 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
785 EdkLogger
.quiet("%-16s = %s" % ("PACKAGES_PATH", os
.path
.normcase(os
.path
.normpath(os
.environ
["PACKAGES_PATH"]))))
786 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
787 if "EDK_TOOLS_BIN" in os
.environ
:
788 # Print the same path style with WORKSPACE env.
789 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_TOOLS_BIN"]))))
790 EdkLogger
.quiet("%-16s = %s" % ("CONF_PATH", GlobalData
.gConfDirectory
))
791 if "PYTHON3_ENABLE" in os
.environ
:
792 PYTHON3_ENABLE
= os
.environ
["PYTHON3_ENABLE"]
793 if PYTHON3_ENABLE
!= "TRUE":
794 PYTHON3_ENABLE
= "FALSE"
795 EdkLogger
.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE
))
796 if "PYTHON_COMMAND" in os
.environ
:
797 EdkLogger
.quiet("%-16s = %s" % ("PYTHON_COMMAND", os
.environ
["PYTHON_COMMAND"]))
801 EdkLogger
.quiet("%-16s = %s" % ("PREBUILD", self
.Prebuild
))
803 EdkLogger
.quiet("%-16s = %s" % ("POSTBUILD", self
.Postbuild
))
805 self
.LaunchPrebuild()
806 self
.TargetTxt
= TargetTxt
807 self
.ToolDef
= ToolDef
808 if not (self
.LaunchPrebuildFlag
and os
.path
.exists(self
.PlatformBuildPath
)):
811 self
.AutoGenMgr
= None
813 os
.chdir(self
.WorkspaceDir
)
814 self
.share_data
= Manager().dict()
816 def StartAutoGen(self
,mqueue
, DataPipe
,SkipAutoGen
,PcdMaList
,share_data
):
820 feedback_q
= mp
.Queue()
821 file_lock
= mp
.Lock()
822 error_event
= mp
.Event()
823 auto_workers
= [AutoGenWorkerInProcess(mqueue
,DataPipe
.dump_file
,feedback_q
,file_lock
,share_data
,self
.log_q
,error_event
) for _
in range(self
.ThreadNumber
)]
824 self
.AutoGenMgr
= AutoGenManager(auto_workers
,feedback_q
,error_event
)
825 self
.AutoGenMgr
.start()
826 for w
in auto_workers
:
828 if PcdMaList
is not None:
829 for PcdMa
in PcdMaList
:
830 PcdMa
.CreateCodeFile(False)
831 PcdMa
.CreateMakeFile(False,GenFfsList
= DataPipe
.Get("FfsCommand").get((PcdMa
.MetaFile
.File
, PcdMa
.Arch
),[]))
833 self
.AutoGenMgr
.join()
834 rt
= self
.AutoGenMgr
.Status
836 except Exception as e
:
837 return False,e
.errcode
839 ## Load configuration
841 # This method will parse target.txt and get the build configurations.
843 def LoadConfiguration(self
):
845 # if no ARCH given in command line, get it from target.txt
846 if not self
.ArchList
:
847 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET_ARCH
]
848 self
.ArchList
= tuple(self
.ArchList
)
850 # if no build target given in command line, get it from target.txt
851 if not self
.BuildTargetList
:
852 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
854 # if no tool chain given in command line, get it from target.txt
855 if not self
.ToolChainList
:
856 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
857 if self
.ToolChainList
is None or len(self
.ToolChainList
) == 0:
858 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
860 # check if the tool chains are defined or not
861 NewToolChainList
= []
862 for ToolChain
in self
.ToolChainList
:
863 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
864 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
866 NewToolChainList
.append(ToolChain
)
867 # if no tool chain available, break the build
868 if len(NewToolChainList
) == 0:
869 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
870 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
872 self
.ToolChainList
= NewToolChainList
875 ToolDefinition
= self
.ToolDef
.ToolsDefTxtDatabase
876 for Tool
in self
.ToolChainList
:
877 if TAB_TOD_DEFINES_FAMILY
not in ToolDefinition
or Tool
not in ToolDefinition
[TAB_TOD_DEFINES_FAMILY
] \
878 or not ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
]:
879 EdkLogger
.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool
)
880 ToolChainFamily
.append(TAB_COMPILER_MSFT
)
882 ToolChainFamily
.append(ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
])
883 self
.ToolChainFamily
= ToolChainFamily
885 if not self
.PlatformFile
:
886 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
888 # Try to find one in current directory
889 WorkingDirectory
= os
.getcwd()
890 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
891 FileNum
= len(FileList
)
893 EdkLogger
.error("build", OPTION_MISSING
,
894 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
896 PlatformFile
= FileList
[0]
898 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
899 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
901 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
902 self
.ThreadNumber
= ThreadNum()
903 ## Initialize build configuration
905 # This method will parse DSC file and merge the configurations from
906 # command line and target.txt, then get the final build configurations.
909 # parse target.txt, tools_def.txt, and platform file
910 self
.LoadConfiguration()
912 # Allow case-insensitive for those from command line or configuration file
913 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
915 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
918 def InitPreBuild(self
):
919 self
.LoadConfiguration()
920 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
922 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
923 if self
.BuildTargetList
:
924 GlobalData
.gGlobalDefines
['TARGET'] = self
.BuildTargetList
[0]
926 GlobalData
.gGlobalDefines
['ARCH'] = self
.ArchList
[0]
927 if self
.ToolChainList
:
928 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = self
.ToolChainList
[0]
929 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = self
.ToolChainList
[0]
930 if self
.ToolChainFamily
:
931 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[0]
932 if 'PREBUILD' in GlobalData
.gCommandLineDefines
:
933 self
.Prebuild
= GlobalData
.gCommandLineDefines
.get('PREBUILD')
936 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
937 self
.Prebuild
= str(Platform
.Prebuild
)
941 # Evaluate all arguments and convert arguments that are WORKSPACE
942 # relative paths to absolute paths. Filter arguments that look like
943 # flags or do not follow the file/dir naming rules to avoid false
944 # positives on this conversion.
946 for Arg
in self
.Prebuild
.split():
948 # Do not modify Arg if it looks like a flag or an absolute file path
950 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
951 PrebuildList
.append(Arg
)
954 # Do not modify Arg if it does not look like a Workspace relative
955 # path that starts with a valid package directory name
957 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
958 PrebuildList
.append(Arg
)
961 # If Arg looks like a WORKSPACE relative path, then convert to an
962 # absolute path and check to see if the file exists.
964 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
965 if os
.path
.isfile(Temp
):
967 PrebuildList
.append(Arg
)
968 self
.Prebuild
= ' '.join(PrebuildList
)
969 self
.Prebuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
971 def InitPostBuild(self
):
972 if 'POSTBUILD' in GlobalData
.gCommandLineDefines
:
973 self
.Postbuild
= GlobalData
.gCommandLineDefines
.get('POSTBUILD')
975 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
976 self
.Postbuild
= str(Platform
.Postbuild
)
980 # Evaluate all arguments and convert arguments that are WORKSPACE
981 # relative paths to absolute paths. Filter arguments that look like
982 # flags or do not follow the file/dir naming rules to avoid false
983 # positives on this conversion.
985 for Arg
in self
.Postbuild
.split():
987 # Do not modify Arg if it looks like a flag or an absolute file path
989 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
990 PostbuildList
.append(Arg
)
993 # Do not modify Arg if it does not look like a Workspace relative
994 # path that starts with a valid package directory name
996 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
997 PostbuildList
.append(Arg
)
1000 # If Arg looks like a WORKSPACE relative path, then convert to an
1001 # absolute path and check to see if the file exists.
1003 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1004 if os
.path
.isfile(Temp
):
1006 PostbuildList
.append(Arg
)
1007 self
.Postbuild
= ' '.join(PostbuildList
)
1008 self
.Postbuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1010 def PassCommandOption(self
, BuildTarget
, TargetArch
, ToolChain
, PlatformFile
, Target
):
1012 if GlobalData
.gCommand
and isinstance(GlobalData
.gCommand
, list):
1013 BuildStr
+= ' ' + ' '.join(GlobalData
.gCommand
)
1016 ToolChainFlag
= False
1017 PlatformFileFlag
= False
1019 if GlobalData
.gOptions
and not GlobalData
.gOptions
.BuildTarget
:
1021 if GlobalData
.gOptions
and not GlobalData
.gOptions
.TargetArch
:
1023 if GlobalData
.gOptions
and not GlobalData
.gOptions
.ToolChain
:
1024 ToolChainFlag
= True
1025 if GlobalData
.gOptions
and not GlobalData
.gOptions
.PlatformFile
:
1026 PlatformFileFlag
= True
1028 if TargetFlag
and BuildTarget
:
1029 if isinstance(BuildTarget
, list) or isinstance(BuildTarget
, tuple):
1030 BuildStr
+= ' -b ' + ' -b '.join(BuildTarget
)
1031 elif isinstance(BuildTarget
, str):
1032 BuildStr
+= ' -b ' + BuildTarget
1033 if ArchFlag
and TargetArch
:
1034 if isinstance(TargetArch
, list) or isinstance(TargetArch
, tuple):
1035 BuildStr
+= ' -a ' + ' -a '.join(TargetArch
)
1036 elif isinstance(TargetArch
, str):
1037 BuildStr
+= ' -a ' + TargetArch
1038 if ToolChainFlag
and ToolChain
:
1039 if isinstance(ToolChain
, list) or isinstance(ToolChain
, tuple):
1040 BuildStr
+= ' -t ' + ' -t '.join(ToolChain
)
1041 elif isinstance(ToolChain
, str):
1042 BuildStr
+= ' -t ' + ToolChain
1043 if PlatformFileFlag
and PlatformFile
:
1044 if isinstance(PlatformFile
, list) or isinstance(PlatformFile
, tuple):
1045 BuildStr
+= ' -p ' + ' -p '.join(PlatformFile
)
1046 elif isinstance(PlatformFile
, str):
1047 BuildStr
+= ' -p' + PlatformFile
1048 BuildStr
+= ' --conf=' + GlobalData
.gConfDirectory
1050 BuildStr
+= ' ' + Target
1054 def LaunchPrebuild(self
):
1056 EdkLogger
.info("\n- Prebuild Start -\n")
1057 self
.LaunchPrebuildFlag
= True
1059 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1060 # and preserve them for the rest of the main build step, because the child process environment will
1061 # evaporate as soon as it exits, we cannot get it in build step.
1063 PrebuildEnvFile
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PrebuildEnv')
1064 if os
.path
.isfile(PrebuildEnvFile
):
1065 os
.remove(PrebuildEnvFile
)
1066 if os
.path
.isfile(self
.PlatformBuildPath
):
1067 os
.remove(self
.PlatformBuildPath
)
1068 if sys
.platform
== "win32":
1069 args
= ' && '.join((self
.Prebuild
, 'set > ' + PrebuildEnvFile
))
1070 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1072 args
= ' && '.join((self
.Prebuild
, 'env > ' + PrebuildEnvFile
))
1073 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1075 # launch two threads to read the STDOUT and STDERR
1076 EndOfProcedure
= Event()
1077 EndOfProcedure
.clear()
1079 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1080 StdOutThread
.setName("STDOUT-Redirector")
1081 StdOutThread
.setDaemon(False)
1082 StdOutThread
.start()
1085 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1086 StdErrThread
.setName("STDERR-Redirector")
1087 StdErrThread
.setDaemon(False)
1088 StdErrThread
.start()
1089 # waiting for program exit
1096 if Process
.returncode
!= 0 :
1097 EdkLogger
.error("Prebuild", PREBUILD_ERROR
, 'Prebuild process is not success!')
1099 if os
.path
.exists(PrebuildEnvFile
):
1100 f
= open(PrebuildEnvFile
)
1101 envs
= f
.readlines()
1103 envs
= [l
.split("=", 1) for l
in envs
]
1104 envs
= [[I
.strip() for I
in item
] for item
in envs
if len(item
) == 2]
1105 os
.environ
.update(dict(envs
))
1106 EdkLogger
.info("\n- Prebuild Done -\n")
1108 def LaunchPostbuild(self
):
1110 EdkLogger
.info("\n- Postbuild Start -\n")
1111 if sys
.platform
== "win32":
1112 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1114 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1115 # launch two threads to read the STDOUT and STDERR
1116 EndOfProcedure
= Event()
1117 EndOfProcedure
.clear()
1119 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1120 StdOutThread
.setName("STDOUT-Redirector")
1121 StdOutThread
.setDaemon(False)
1122 StdOutThread
.start()
1125 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1126 StdErrThread
.setName("STDERR-Redirector")
1127 StdErrThread
.setDaemon(False)
1128 StdErrThread
.start()
1129 # waiting for program exit
1136 if Process
.returncode
!= 0 :
1137 EdkLogger
.error("Postbuild", POSTBUILD_ERROR
, 'Postbuild process is not success!')
1138 EdkLogger
.info("\n- Postbuild Done -\n")
1140 ## Error handling for hash feature
1142 # On BuildTask error, iterate through the Module Build tracking
1143 # dictionary to determine wheather a module failed to build. Invalidate
1144 # the hash associated with that module by removing it from storage.
1147 def invalidateHash(self
):
1148 # Only for hashing feature
1149 if not GlobalData
.gUseHashCache
:
1152 # GlobalData.gModuleBuildTracking contains only modules or libs that cannot be skipped by hash
1153 for moduleAutoGenObjArch
in GlobalData
.gModuleBuildTracking
.keys():
1154 for moduleAutoGenObj
in GlobalData
.gModuleBuildTracking
[moduleAutoGenObjArch
].keys():
1155 # Skip invalidating for Successful Module/Lib builds
1156 if GlobalData
.gModuleBuildTracking
[moduleAutoGenObjArch
][moduleAutoGenObj
] == 'SUCCESS':
1159 # The module failed to build, failed to start building, or failed the header check test from this point on
1161 # Remove .hash from build
1162 ModuleHashFile
= os
.path
.join(moduleAutoGenObj
.BuildDir
, moduleAutoGenObj
.Name
+ ".hash")
1163 if os
.path
.exists(ModuleHashFile
):
1164 os
.remove(ModuleHashFile
)
1166 # Remove .hash file from cache
1167 if GlobalData
.gBinCacheDest
:
1168 FileDir
= os
.path
.join(GlobalData
.gBinCacheDest
, moduleAutoGenObj
.Arch
, moduleAutoGenObj
.SourceDir
, moduleAutoGenObj
.MetaFile
.BaseName
)
1169 HashFile
= os
.path
.join(FileDir
, moduleAutoGenObj
.Name
+ '.hash')
1170 if os
.path
.exists(HashFile
):
1173 ## Build a module or platform
1175 # Create autogen code and makefile for a module or platform, and the launch
1176 # "make" command to build it
1178 # @param Target The target of build command
1179 # @param Platform The platform file
1180 # @param Module The module file
1181 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1182 # @param ToolChain The name of toolchain to build
1183 # @param Arch The arch of the module/platform
1184 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1185 # for dependent modules/Libraries
1186 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1187 # for dependent modules/Libraries
1189 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False, FfsCommand
=None, PcdMaList
=None):
1190 if AutoGenObject
is None:
1192 if FfsCommand
is None:
1194 # skip file generation for cleanxxx targets, run and fds target
1195 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1196 # for target which must generate AutoGen code and makefile
1198 for m
in AutoGenObject
.GetAllModuleInfo
:
1201 AutoGenObject
.DataPipe
.DataContainer
= {"FfsCommand":FfsCommand
}
1202 self
.Progress
.Start("Generating makefile and code")
1203 data_pipe_file
= os
.path
.join(AutoGenObject
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(AutoGenObject
.Guid
),AutoGenObject
.Arch
))
1204 AutoGenObject
.DataPipe
.dump(data_pipe_file
)
1205 autogen_rt
, errorcode
= self
.StartAutoGen(mqueue
, AutoGenObject
.DataPipe
, self
.SkipAutoGen
, PcdMaList
,self
.share_data
)
1206 self
.Progress
.Stop("done!")
1208 self
.AutoGenMgr
.TerminateWorkers()
1209 self
.AutoGenMgr
.join(0.1)
1210 raise FatalError(errorcode
)
1211 AutoGenObject
.CreateCodeFile(False)
1212 AutoGenObject
.CreateMakeFile(False)
1214 # always recreate top/platform makefile when clean, just in case of inconsistency
1215 AutoGenObject
.CreateCodeFile(True)
1216 AutoGenObject
.CreateMakeFile(True)
1218 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1219 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1221 BuildCommand
= AutoGenObject
.BuildCommand
1222 if BuildCommand
is None or len(BuildCommand
) == 0:
1223 EdkLogger
.error("build", OPTION_MISSING
,
1224 "No build command found for this module. "
1225 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1226 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1227 ExtraData
=str(AutoGenObject
))
1229 makefile
= GenMake
.BuildFile(AutoGenObject
)._FILE
_NAME
_[GenMake
.gMakeType
]
1237 BuildCommand
= BuildCommand
+ [Target
]
1238 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1239 self
.CreateAsBuiltInf()
1240 if GlobalData
.gBinCacheDest
:
1241 self
.UpdateBuildCache()
1242 self
.BuildModules
= []
1246 if Target
== 'libraries':
1247 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1248 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1249 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1253 if Target
== 'modules':
1254 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1255 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1256 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1257 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1258 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, makefile
)), 'pbuild']
1259 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1260 self
.CreateAsBuiltInf()
1261 if GlobalData
.gBinCacheDest
:
1262 self
.UpdateBuildCache()
1263 self
.BuildModules
= []
1267 if Target
== 'cleanlib':
1268 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1269 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1270 if os
.path
.exists(LibMakefile
):
1271 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1272 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1276 if Target
== 'clean':
1277 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1278 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, makefile
))
1279 if os
.path
.exists(ModMakefile
):
1280 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
1281 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1282 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1283 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1284 if os
.path
.exists(LibMakefile
):
1285 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1286 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1290 if Target
== 'cleanall':
1292 #os.rmdir(AutoGenObject.BuildDir)
1293 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1294 except WindowsError as X
:
1295 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1298 ## Build a module or platform
1300 # Create autogen code and makefile for a module or platform, and the launch
1301 # "make" command to build it
1303 # @param Target The target of build command
1304 # @param Platform The platform file
1305 # @param Module The module file
1306 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1307 # @param ToolChain The name of toolchain to build
1308 # @param Arch The arch of the module/platform
1309 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1310 # for dependent modules/Libraries
1311 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1312 # for dependent modules/Libraries
1314 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1315 if AutoGenObject
is None:
1318 # skip file generation for cleanxxx targets, run and fds target
1319 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1320 # for target which must generate AutoGen code and makefile
1321 if not self
.SkipAutoGen
or Target
== 'genc':
1322 self
.Progress
.Start("Generating code")
1323 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1324 self
.Progress
.Stop("done!")
1325 if Target
== "genc":
1328 if not self
.SkipAutoGen
or Target
== 'genmake':
1329 self
.Progress
.Start("Generating makefile")
1330 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1331 #AutoGenObject.CreateAsBuiltInf()
1332 self
.Progress
.Stop("done!")
1333 if Target
== "genmake":
1336 # always recreate top/platform makefile when clean, just in case of inconsistency
1337 AutoGenObject
.CreateCodeFile(True)
1338 AutoGenObject
.CreateMakeFile(True)
1340 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1341 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1343 BuildCommand
= AutoGenObject
.BuildCommand
1344 if BuildCommand
is None or len(BuildCommand
) == 0:
1345 EdkLogger
.error("build", OPTION_MISSING
,
1346 "No build command found for this module. "
1347 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1348 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1349 ExtraData
=str(AutoGenObject
))
1354 BuildCommand
= BuildCommand
+ [Target
]
1355 AutoGenObject
.BuildTime
= LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1356 self
.CreateAsBuiltInf()
1357 if GlobalData
.gBinCacheDest
:
1358 self
.UpdateBuildCache()
1359 self
.BuildModules
= []
1364 if GenFdsApi(AutoGenObject
.GenFdsCommandDict
, self
.Db
):
1365 EdkLogger
.error("build", COMMAND_FAILURE
)
1373 if Target
== 'libraries':
1380 if Target
== 'cleanall':
1382 #os.rmdir(AutoGenObject.BuildDir)
1383 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1384 except WindowsError as X
:
1385 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1388 ## Rebase module image and Get function address for the input module list.
1390 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1392 AddrIsOffset
= False
1393 for InfFile
in ModuleList
:
1394 sys
.stdout
.write (".")
1396 ModuleInfo
= ModuleList
[InfFile
]
1397 ModuleName
= ModuleInfo
.BaseName
1398 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1399 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1400 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1402 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1404 # Update Image to new BaseAddress by GenFw tool
1406 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1407 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1410 # Set new address to the section header only for SMM driver.
1412 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1413 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1415 # Collect function address from Map file
1417 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1419 if os
.path
.exists(ImageMapTable
):
1420 OrigImageBaseAddress
= 0
1421 ImageMap
= open(ImageMapTable
, 'r')
1422 for LinStr
in ImageMap
:
1423 if len (LinStr
.strip()) == 0:
1426 # Get the preferred address set on link time.
1428 if LinStr
.find ('Preferred load address is') != -1:
1429 StrList
= LinStr
.split()
1430 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1432 StrList
= LinStr
.split()
1433 if len (StrList
) > 4:
1434 if StrList
[3] == 'f' or StrList
[3] == 'F':
1436 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1437 FunctionList
.append ((Name
, RelativeAddress
))
1441 # Add general information.
1444 MapBuffer
.append('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1446 MapBuffer
.append('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1448 MapBuffer
.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1450 # Add guid and general seciton section.
1452 TextSectionAddress
= 0
1453 DataSectionAddress
= 0
1454 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1455 if SectionHeader
[0] == '.text':
1456 TextSectionAddress
= SectionHeader
[1]
1457 elif SectionHeader
[0] in ['.data', '.sdata']:
1458 DataSectionAddress
= SectionHeader
[1]
1460 MapBuffer
.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1462 MapBuffer
.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1464 # Add debug image full path.
1466 MapBuffer
.append('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1468 # Add function address
1470 for Function
in FunctionList
:
1472 MapBuffer
.append(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1474 MapBuffer
.append(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1478 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1481 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1483 ## Collect MAP information of all FVs
1485 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1487 # First get the XIP base address for FV map file.
1488 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1489 GuidName
= re
.compile(r
"\(GUID=[-a-fA-F0-9]+")
1490 for FvName
in Wa
.FdfProfile
.FvDict
:
1491 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1492 if not os
.path
.exists(FvMapBuffer
):
1494 FvMap
= open(FvMapBuffer
, 'r')
1495 #skip FV size information
1501 MatchGuid
= GuidPattern
.match(Line
)
1502 if MatchGuid
is not None:
1504 # Replace GUID with module name
1506 GuidString
= MatchGuid
.group()
1507 if GuidString
.upper() in ModuleList
:
1508 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1509 MapBuffer
.append(Line
)
1511 # Add the debug image full path.
1513 MatchGuid
= GuidName
.match(Line
)
1514 if MatchGuid
is not None:
1515 GuidString
= MatchGuid
.group().split("=")[1]
1516 if GuidString
.upper() in ModuleList
:
1517 MapBuffer
.append('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1521 ## Collect MAP information of all modules
1523 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1524 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1526 PatchEfiImageList
= []
1534 # reserve 4K size in SMRAM to make SMM module address not from 0.
1536 for ModuleGuid
in ModuleList
:
1537 Module
= ModuleList
[ModuleGuid
]
1538 GlobalData
.gProcessingFile
= "%s [%s, %s, %s]" % (Module
.MetaFile
, Module
.Arch
, Module
.ToolChain
, Module
.BuildTarget
)
1540 OutputImageFile
= ''
1541 for ResultFile
in Module
.CodaTargetList
:
1542 if str(ResultFile
.Target
).endswith('.efi'):
1544 # module list for PEI, DXE, RUNTIME and SMM
1546 OutputImageFile
= os
.path
.join(Module
.OutputDir
, Module
.Name
+ '.efi')
1547 ImageClass
= PeImageClass (OutputImageFile
)
1548 if not ImageClass
.IsValid
:
1549 EdkLogger
.error("build", FILE_PARSE_FAILURE
, ExtraData
=ImageClass
.ErrorInfo
)
1550 ImageInfo
= PeImageInfo(Module
.Name
, Module
.Guid
, Module
.Arch
, Module
.OutputDir
, Module
.DebugDir
, ImageClass
)
1551 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
]:
1552 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1553 PeiSize
+= ImageInfo
.Image
.Size
1554 elif Module
.ModuleType
in [EDK_COMPONENT_TYPE_BS_DRIVER
, SUP_MODULE_DXE_DRIVER
, SUP_MODULE_UEFI_DRIVER
]:
1555 BtModuleList
[Module
.MetaFile
] = ImageInfo
1556 BtSize
+= ImageInfo
.Image
.Size
1557 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
]:
1558 RtModuleList
[Module
.MetaFile
] = ImageInfo
1559 RtSize
+= ImageInfo
.Image
.Size
1560 elif Module
.ModuleType
in [SUP_MODULE_SMM_CORE
, SUP_MODULE_DXE_SMM_DRIVER
, SUP_MODULE_MM_STANDALONE
, SUP_MODULE_MM_CORE_STANDALONE
]:
1561 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1562 SmmSize
+= ImageInfo
.Image
.Size
1563 if Module
.ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
1564 PiSpecVersion
= Module
.Module
.Specification
.get('PI_SPECIFICATION_VERSION', '0x00000000')
1565 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1566 if int(PiSpecVersion
, 16) < 0x0001000A:
1567 BtModuleList
[Module
.MetaFile
] = ImageInfo
1568 BtSize
+= ImageInfo
.Image
.Size
1571 # EFI image is final target.
1572 # Check EFI image contains patchable FixAddress related PCDs.
1574 if OutputImageFile
!= '':
1575 ModuleIsPatch
= False
1576 for Pcd
in Module
.ModulePcdList
:
1577 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1578 ModuleIsPatch
= True
1580 if not ModuleIsPatch
:
1581 for Pcd
in Module
.LibraryPcdList
:
1582 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1583 ModuleIsPatch
= True
1586 if not ModuleIsPatch
:
1589 # Module includes the patchable load fix address PCDs.
1590 # It will be fixed up later.
1592 PatchEfiImageList
.append (OutputImageFile
)
1595 # Get Top Memory address
1597 ReservedRuntimeMemorySize
= 0
1598 TopMemoryAddress
= 0
1599 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1600 TopMemoryAddress
= 0
1602 TopMemoryAddress
= self
.LoadFixAddress
1603 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1604 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1607 # Patch FixAddress related PCDs into EFI image
1609 for EfiImage
in PatchEfiImageList
:
1610 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1611 if not os
.path
.exists(EfiImageMap
):
1614 # Get PCD offset in EFI image by GenPatchPcdTable function
1616 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1618 # Patch real PCD value by PatchPcdValue tool
1620 for PcdInfo
in PcdTable
:
1622 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1623 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
// 0x1000))
1624 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1625 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
// 0x1000))
1626 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1627 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
// 0x1000))
1628 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1629 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
// 0x1000))
1630 if ReturnValue
!= 0:
1631 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1633 MapBuffer
.append('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
// 0x1000))
1634 MapBuffer
.append('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
// 0x1000))
1635 MapBuffer
.append('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
// 0x1000))
1636 if len (SmmModuleList
) > 0:
1637 MapBuffer
.append('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
// 0x1000))
1639 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1640 BtBaseAddr
= TopMemoryAddress
- RtSize
1641 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1643 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1644 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1645 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1646 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
=False, ModeIsSmm
=True)
1647 MapBuffer
.append('\n\n')
1648 sys
.stdout
.write ("\n")
1651 ## Save platform Map file
1653 def _SaveMapFile (self
, MapBuffer
, Wa
):
1655 # Map file path is got.
1657 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1659 # Save address map into MAP file.
1661 SaveFileOnChange(MapFilePath
, ''.join(MapBuffer
), False)
1662 if self
.LoadFixAddress
!= 0:
1663 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath
))
1666 ## Build active platform for different build targets and different tool chains
1668 def _BuildPlatform(self
):
1669 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1670 for BuildTarget
in self
.BuildTargetList
:
1671 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1673 for ToolChain
in self
.ToolChainList
:
1674 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1675 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1676 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1678 Wa
= WorkspaceAutoGen(
1695 self
.Fdf
= Wa
.FdfFile
1696 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1697 self
.BuildReport
.AddPlatformReport(Wa
)
1698 self
.Progress
.Stop("done!")
1700 # Add ffs build to makefile
1702 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1703 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1705 for Arch
in Wa
.ArchList
:
1707 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1708 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1709 for Module
in Pa
.Platform
.Modules
:
1710 # Get ModuleAutoGen object to generate C code file and makefile
1711 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1715 Ma
.PlatformInfo
= Pa
1717 PcdMaList
.append(Ma
)
1718 self
.BuildModules
.append(Ma
)
1719 self
._BuildPa
(self
.Target
, Pa
, FfsCommand
=CmdListDict
,PcdMaList
=PcdMaList
)
1721 # Create MAP file when Load Fix Address is enabled.
1722 if self
.Target
in ["", "all", "fds"]:
1723 for Arch
in Wa
.ArchList
:
1724 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1726 # Check whether the set fix address is above 4G for 32bit image.
1728 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1729 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")
1734 for Pa
in Wa
.AutoGenObjectList
:
1735 for Ma
in Pa
.ModuleAutoGenList
:
1738 if not Ma
.IsLibrary
:
1739 ModuleList
[Ma
.Guid
.upper()] = Ma
1742 if self
.LoadFixAddress
!= 0:
1744 # Rebase module to the preferred memory address before GenFds
1746 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1749 # create FDS again for the updated EFI image
1751 self
._Build
("fds", Wa
)
1753 # Create MAP file for all platform FVs after GenFds.
1755 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1757 # Save MAP buffer into MAP file.
1759 self
._SaveMapFile
(MapBuffer
, Wa
)
1761 ## Build active module for different build targets, different tool chains and different archs
1763 def _BuildModule(self
):
1764 for BuildTarget
in self
.BuildTargetList
:
1765 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1767 for ToolChain
in self
.ToolChainList
:
1768 WorkspaceAutoGenTime
= time
.time()
1769 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1770 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1771 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1774 # module build needs platform build information, so get platform
1777 Wa
= WorkspaceAutoGen(
1795 self
.Fdf
= Wa
.FdfFile
1796 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1797 Wa
.CreateMakeFile(False)
1798 # Add ffs build to makefile
1800 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1801 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1802 self
.Progress
.Stop("done!")
1804 ExitFlag
= threading
.Event()
1806 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1807 for Arch
in Wa
.ArchList
:
1808 AutoGenStart
= time
.time()
1809 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1810 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1811 for Module
in Pa
.Platform
.Modules
:
1812 if self
.ModuleFile
.Dir
== Module
.Dir
and self
.ModuleFile
.Name
== Module
.Name
:
1813 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1817 if Ma
.CanSkipbyHash():
1818 self
.HashSkipModules
.append(Ma
)
1819 if GlobalData
.gBinCacheSource
:
1820 EdkLogger
.quiet("cache hit: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1823 if GlobalData
.gBinCacheSource
:
1824 EdkLogger
.quiet("cache miss: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
1825 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1826 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1827 # for target which must generate AutoGen code and makefile
1828 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1829 self
.Progress
.Start("Generating code")
1830 Ma
.CreateCodeFile(True)
1831 self
.Progress
.Stop("done!")
1832 if self
.Target
== "genc":
1834 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1835 self
.Progress
.Start("Generating makefile")
1836 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
1837 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
1838 del CmdListDict
[Module
.File
, Arch
]
1840 Ma
.CreateMakeFile(True)
1841 self
.Progress
.Stop("done!")
1842 if self
.Target
== "genmake":
1844 self
.BuildModules
.append(Ma
)
1845 # Initialize all modules in tracking to 'FAIL'
1846 if Ma
.Arch
not in GlobalData
.gModuleBuildTracking
:
1847 GlobalData
.gModuleBuildTracking
[Ma
.Arch
] = dict()
1848 if Ma
not in GlobalData
.gModuleBuildTracking
[Ma
.Arch
]:
1849 GlobalData
.gModuleBuildTracking
[Ma
.Arch
][Ma
] = 'FAIL'
1850 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1851 MakeStart
= time
.time()
1852 for Ma
in self
.BuildModules
:
1853 if not Ma
.IsBinaryModule
:
1854 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
1855 # Break build if any build thread has error
1856 if BuildTask
.HasError():
1857 # we need a full version of makefile for platform
1859 BuildTask
.WaitForComplete()
1860 self
.invalidateHash()
1861 Pa
.CreateMakeFile(False)
1862 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1863 # Start task scheduler
1864 if not BuildTask
.IsOnGoing():
1865 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1867 # in case there's an interruption. we need a full version of makefile for platform
1868 Pa
.CreateMakeFile(False)
1869 if BuildTask
.HasError():
1870 self
.invalidateHash()
1871 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1872 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1874 MakeContiue
= time
.time()
1876 BuildTask
.WaitForComplete()
1877 self
.CreateAsBuiltInf()
1878 if GlobalData
.gBinCacheDest
:
1879 self
.UpdateBuildCache()
1880 self
.BuildModules
= []
1881 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1882 if BuildTask
.HasError():
1883 self
.invalidateHash()
1884 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1886 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1891 "Module for [%s] is not a component of active platform."\
1892 " Please make sure that the ARCH and inf file path are"\
1893 " given in the same as in [%s]" % \
1894 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1895 ExtraData
=self
.ModuleFile
1897 # Create MAP file when Load Fix Address is enabled.
1898 if self
.Target
== "fds" and self
.Fdf
:
1899 for Arch
in Wa
.ArchList
:
1901 # Check whether the set fix address is above 4G for 32bit image.
1903 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1904 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")
1909 for Pa
in Wa
.AutoGenObjectList
:
1910 for Ma
in Pa
.ModuleAutoGenList
:
1913 if not Ma
.IsLibrary
:
1914 ModuleList
[Ma
.Guid
.upper()] = Ma
1917 if self
.LoadFixAddress
!= 0:
1919 # Rebase module to the preferred memory address before GenFds
1921 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1923 # create FDS again for the updated EFI image
1925 GenFdsStart
= time
.time()
1926 self
._Build
("fds", Wa
)
1927 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
1929 # Create MAP file for all platform FVs after GenFds.
1931 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1933 # Save MAP buffer into MAP file.
1935 self
._SaveMapFile
(MapBuffer
, Wa
)
1936 self
.invalidateHash()
1938 def _GenFfsCmd(self
,ArchList
):
1939 # convert dictionary of Cmd:(Inf,Arch)
1940 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
1941 CmdSetDict
= defaultdict(set)
1942 GenFfsDict
= GenFds
.GenFfsMakefile('', GlobalData
.gFdfParser
, self
, ArchList
, GlobalData
)
1943 for Cmd
in GenFfsDict
:
1944 tmpInf
, tmpArch
= GenFfsDict
[Cmd
]
1945 CmdSetDict
[tmpInf
, tmpArch
].add(Cmd
)
1948 ## Build a platform in multi-thread mode
1950 def _MultiThreadBuildPlatform(self
):
1951 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1952 for BuildTarget
in self
.BuildTargetList
:
1953 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1955 for ToolChain
in self
.ToolChainList
:
1956 WorkspaceAutoGenTime
= time
.time()
1957 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1958 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1959 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1961 Wa
= WorkspaceAutoGen(
1978 self
.Fdf
= Wa
.FdfFile
1979 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1980 self
.BuildReport
.AddPlatformReport(Wa
)
1981 Wa
.CreateMakeFile(False)
1983 # Add ffs build to makefile
1985 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1986 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1988 # multi-thread exit flag
1989 ExitFlag
= threading
.Event()
1991 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1992 self
.BuildModules
= []
1993 for Arch
in Wa
.ArchList
:
1995 AutoGenStart
= time
.time()
1996 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1997 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
2001 for Inf
in Pa
.Platform
.Modules
:
2002 ModuleList
.append(Inf
)
2003 # Add the INF only list in FDF
2004 if GlobalData
.gFdfParser
is not None:
2005 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
2006 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
2007 if Inf
in Pa
.Platform
.Modules
:
2009 ModuleList
.append(Inf
)
2010 Pa
.DataPipe
.DataContainer
= {"FfsCommand":CmdListDict
}
2011 Pa
.DataPipe
.DataContainer
= {"Workspace_timestamp": Wa
._SrcTimeStamp
}
2012 for Module
in ModuleList
:
2013 # Get ModuleAutoGen object to generate C code file and makefile
2014 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2019 Ma
.PlatformInfo
= Pa
2021 PcdMaList
.append(Ma
)
2022 if Ma
.CanSkipbyHash():
2023 self
.HashSkipModules
.append(Ma
)
2024 if GlobalData
.gBinCacheSource
:
2025 EdkLogger
.quiet("cache hit: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
2028 if GlobalData
.gBinCacheSource
:
2029 EdkLogger
.quiet("cache miss: %s[%s]" % (Ma
.MetaFile
.Path
, Ma
.Arch
))
2031 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
2032 # for target which must generate AutoGen code and makefile
2034 self
.BuildModules
.append(Ma
)
2035 # Initialize all modules in tracking to 'FAIL'
2036 if Ma
.Arch
not in GlobalData
.gModuleBuildTracking
:
2037 GlobalData
.gModuleBuildTracking
[Ma
.Arch
] = dict()
2038 if Ma
not in GlobalData
.gModuleBuildTracking
[Ma
.Arch
]:
2039 GlobalData
.gModuleBuildTracking
[Ma
.Arch
][Ma
] = 'FAIL'
2041 for m
in Pa
.GetAllModuleInfo
:
2043 data_pipe_file
= os
.path
.join(Pa
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(Pa
.Guid
),Pa
.Arch
))
2044 Pa
.DataPipe
.dump(data_pipe_file
)
2045 autogen_rt
, errorcode
= self
.StartAutoGen(mqueue
, Pa
.DataPipe
, self
.SkipAutoGen
, PcdMaList
,self
.share_data
)
2048 self
.AutoGenMgr
.TerminateWorkers()
2049 self
.AutoGenMgr
.join(0.1)
2050 raise FatalError(errorcode
)
2051 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
2052 self
.Progress
.Stop("done!")
2053 for Arch
in Wa
.ArchList
:
2054 MakeStart
= time
.time()
2055 for Ma
in self
.BuildModules
:
2056 # Generate build task for the module
2057 if not Ma
.IsBinaryModule
:
2058 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
2059 # Break build if any build thread has error
2060 if BuildTask
.HasError():
2061 # we need a full version of makefile for platform
2063 BuildTask
.WaitForComplete()
2064 self
.invalidateHash()
2065 Pa
.CreateMakeFile(False)
2066 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2067 # Start task scheduler
2068 if not BuildTask
.IsOnGoing():
2069 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
2071 # in case there's an interruption. we need a full version of makefile for platform
2072 Pa
.CreateMakeFile(False)
2073 if BuildTask
.HasError():
2074 self
.invalidateHash()
2075 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2076 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
2078 MakeContiue
= time
.time()
2082 # All modules have been put in build tasks queue. Tell task scheduler
2083 # to exit if all tasks are completed
2086 BuildTask
.WaitForComplete()
2087 self
.CreateAsBuiltInf()
2088 if GlobalData
.gBinCacheDest
:
2089 self
.UpdateBuildCache()
2090 self
.BuildModules
= []
2091 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2093 # Check for build error, and raise exception if one
2094 # has been signaled.
2096 if BuildTask
.HasError():
2097 self
.invalidateHash()
2098 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2100 # Create MAP file when Load Fix Address is enabled.
2101 if self
.Target
in ["", "all", "fds"]:
2102 for Arch
in Wa
.ArchList
:
2104 # Check whether the set fix address is above 4G for 32bit image.
2106 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2107 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")
2112 for Pa
in Wa
.AutoGenObjectList
:
2113 for Ma
in Pa
.ModuleAutoGenList
:
2116 if not Ma
.IsLibrary
:
2117 ModuleList
[Ma
.Guid
.upper()] = Ma
2119 # Rebase module to the preferred memory address before GenFds
2122 if self
.LoadFixAddress
!= 0:
2123 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2127 # Generate FD image if there's a FDF file found
2129 GenFdsStart
= time
.time()
2130 if GenFdsApi(Wa
.GenFdsCommandDict
, self
.Db
):
2131 EdkLogger
.error("build", COMMAND_FAILURE
)
2134 # Create MAP file for all platform FVs after GenFds.
2136 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2137 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2139 # Save MAP buffer into MAP file.
2141 self
._SaveMapFile
(MapBuffer
, Wa
)
2142 self
.invalidateHash()
2144 ## Generate GuidedSectionTools.txt in the FV directories.
2146 def CreateGuidedSectionToolsFile(self
):
2147 for BuildTarget
in self
.BuildTargetList
:
2148 for ToolChain
in self
.ToolChainList
:
2149 Wa
= WorkspaceAutoGen(
2166 if not os
.path
.exists(FvDir
):
2169 for Arch
in self
.ArchList
:
2170 # Build up the list of supported architectures for this build
2171 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
2173 # Look through the tool definitions for GUIDed tools
2175 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.items():
2176 if attrib
.upper().endswith('_GUID'):
2177 split
= attrib
.split('_')
2178 thisPrefix
= '_'.join(split
[0:3]) + '_'
2179 if thisPrefix
== prefix
:
2180 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
2183 path
= '_'.join(split
[0:4]) + '_PATH'
2184 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2185 path
= self
.GetFullPathOfTool(path
)
2186 guidAttribs
.append((guid
, toolName
, path
))
2188 # Write out GuidedSecTools.txt
2189 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2190 toolsFile
= open(toolsFile
, 'wt')
2191 for guidedSectionTool
in guidAttribs
:
2192 print(' '.join(guidedSectionTool
), file=toolsFile
)
2195 ## Returns the full path of the tool.
2197 def GetFullPathOfTool (self
, tool
):
2198 if os
.path
.exists(tool
):
2199 return os
.path
.realpath(tool
)
2201 # We need to search for the tool using the
2202 # PATH environment variable.
2203 for dirInPath
in os
.environ
['PATH'].split(os
.pathsep
):
2204 foundPath
= os
.path
.join(dirInPath
, tool
)
2205 if os
.path
.exists(foundPath
):
2206 return os
.path
.realpath(foundPath
)
2208 # If the tool was not found in the path then we just return
2212 ## Launch the module or platform build
2215 if not self
.ModuleFile
:
2216 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2217 self
.SpawnMode
= False
2218 self
._BuildPlatform
()
2220 self
._MultiThreadBuildPlatform
()
2221 self
.CreateGuidedSectionToolsFile()
2223 self
.SpawnMode
= False
2226 if self
.Target
== 'cleanall':
2227 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2229 def CreateAsBuiltInf(self
):
2230 for Module
in self
.BuildModules
:
2231 Module
.CreateAsBuiltInf()
2233 def UpdateBuildCache(self
):
2236 for Module
in self
.BuildModules
:
2237 Module
.CopyModuleToCache()
2238 all_mod_set
.add(Module
)
2239 for Module
in self
.HashSkipModules
:
2240 Module
.CopyModuleToCache()
2241 all_mod_set
.add(Module
)
2242 for Module
in all_mod_set
:
2243 for lib
in Module
.LibraryAutoGenList
:
2244 all_lib_set
.add(lib
)
2245 for lib
in all_lib_set
:
2246 lib
.CopyModuleToCache()
2249 self
.HashSkipModules
= []
2250 ## Do some clean-up works when error occurred
2251 def Relinquish(self
):
2252 OldLogLevel
= EdkLogger
.GetLevel()
2253 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2254 Utils
.Progressor
.Abort()
2255 if self
.SpawnMode
== True:
2257 EdkLogger
.SetLevel(OldLogLevel
)
2259 def ParseDefines(DefineList
=[]):
2261 if DefineList
is not None:
2262 for Define
in DefineList
:
2263 DefineTokenList
= Define
.split("=", 1)
2264 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2265 EdkLogger
.error('build', FORMAT_INVALID
,
2266 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2267 ExtraData
=DefineTokenList
[0])
2269 if len(DefineTokenList
) == 1:
2270 DefineDict
[DefineTokenList
[0]] = "TRUE"
2272 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2277 def LogBuildTime(Time
):
2280 TimeDur
= time
.gmtime(Time
)
2281 if TimeDur
.tm_yday
> 1:
2282 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2284 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2289 ThreadNumber
= BuildOption
.ThreadNumber
2290 if ThreadNumber
is None:
2291 ThreadNumber
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
2292 if ThreadNumber
== '':
2295 ThreadNumber
= int(ThreadNumber
, 0)
2297 if ThreadNumber
== 0:
2299 ThreadNumber
= multiprocessing
.cpu_count()
2300 except (ImportError, NotImplementedError):
2303 ## Tool entrance method
2305 # This method mainly dispatch specific methods per the command line options.
2306 # If no error found, return zero value so the caller of this tool can know
2307 # if it's executed successfully or not.
2309 # @retval 0 Tool was successful
2310 # @retval 1 Tool failed
2312 LogQMaxSize
= ThreadNum() * 10
2314 StartTime
= time
.time()
2317 # Create a log Queue
2319 LogQ
= mp
.Queue(LogQMaxSize
)
2320 # Initialize log system
2321 EdkLogger
.LogClientInitialize(LogQ
)
2322 GlobalData
.gCommand
= sys
.argv
[1:]
2324 # Parse the options and args
2326 Option
, Target
= BuildOption
, BuildTarget
2327 GlobalData
.gOptions
= Option
2328 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2331 LogLevel
= EdkLogger
.INFO
2332 if Option
.verbose
is not None:
2333 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2334 LogLevel
= EdkLogger
.VERBOSE
2335 elif Option
.quiet
is not None:
2336 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2337 LogLevel
= EdkLogger
.QUIET
2338 elif Option
.debug
is not None:
2339 EdkLogger
.SetLevel(Option
.debug
+ 1)
2340 LogLevel
= Option
.debug
+ 1
2342 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2344 if Option
.WarningAsError
== True:
2345 EdkLogger
.SetWarningAsError()
2346 Log_Agent
= LogAgent(LogQ
,LogLevel
,Option
.LogFile
)
2349 if platform
.platform().find("Windows") >= 0:
2350 GlobalData
.gIsWindows
= True
2352 GlobalData
.gIsWindows
= False
2354 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2355 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2360 if len(Target
) == 0:
2362 elif len(Target
) >= 2:
2363 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2364 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2366 Target
= Target
[0].lower()
2368 if Target
not in gSupportedTarget
:
2369 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2370 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2373 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2376 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2378 Workspace
= os
.getenv("WORKSPACE")
2380 # Get files real name in workspace dir
2382 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2384 WorkingDirectory
= os
.getcwd()
2385 if not Option
.ModuleFile
:
2386 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2387 FileNum
= len(FileList
)
2389 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2390 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2392 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2394 if Option
.ModuleFile
:
2395 if os
.path
.isabs (Option
.ModuleFile
):
2396 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2397 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2398 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2399 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2401 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2403 if Option
.PlatformFile
is not None:
2404 if os
.path
.isabs (Option
.PlatformFile
):
2405 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2406 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2407 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2409 if Option
.FdfFile
is not None:
2410 if os
.path
.isabs (Option
.FdfFile
):
2411 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2412 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2413 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2414 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2416 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2418 if Option
.Flag
is not None and Option
.Flag
not in ['-c', '-s']:
2419 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2421 MyBuild
= Build(Target
, Workspace
, Option
,LogQ
)
2422 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2423 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2427 # All job done, no error found and no exception raised
2430 except FatalError
as X
:
2431 if MyBuild
is not None:
2432 # for multi-thread build exits safely
2433 MyBuild
.Relinquish()
2434 if Option
is not None and Option
.debug
is not None:
2435 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2436 ReturnCode
= X
.args
[0]
2437 except Warning as X
:
2438 # error from Fdf parser
2439 if MyBuild
is not None:
2440 # for multi-thread build exits safely
2441 MyBuild
.Relinquish()
2442 if Option
is not None and Option
.debug
is not None:
2443 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2445 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2446 ReturnCode
= FORMAT_INVALID
2447 except KeyboardInterrupt:
2448 if MyBuild
is not None:
2450 # for multi-thread build exits safely
2451 MyBuild
.Relinquish()
2452 ReturnCode
= ABORT_ERROR
2453 if Option
is not None and Option
.debug
is not None:
2454 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2456 if MyBuild
is not None:
2457 # for multi-thread build exits safely
2458 MyBuild
.Relinquish()
2460 # try to get the meta-file from the object causing exception
2461 Tb
= sys
.exc_info()[-1]
2462 MetaFile
= GlobalData
.gProcessingFile
2463 while Tb
is not None:
2464 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2465 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2470 "Unknown fatal error when processing [%s]" % MetaFile
,
2471 ExtraData
="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR
,
2474 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2475 ReturnCode
= CODE_ERROR
2477 Utils
.Progressor
.Abort()
2478 Utils
.ClearDuplicatedInf()
2482 MyBuild
.LaunchPostbuild()
2485 Conclusion
= "Failed"
2486 elif ReturnCode
== ABORT_ERROR
:
2487 Conclusion
= "Aborted"
2489 Conclusion
= "Failed"
2490 FinishTime
= time
.time()
2491 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2492 BuildDurationStr
= ""
2493 if BuildDuration
.tm_yday
> 1:
2494 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2496 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2497 if MyBuild
is not None:
2499 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2501 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2502 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2503 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2504 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2509 if __name__
== '__main__':
2511 mp
.set_start_method('spawn')
2515 ## 0-127 is a safe return range, and 1 is a standard default error
2516 if r
< 0 or r
> 127: r
= 1