2 # build a platform or a module
4 # Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
5 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
6 # Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
8 # This program and the accompanying materials
9 # are licensed and made available under the terms and conditions of the BSD License
10 # which accompanies this distribution. The full text of the license may be found at
11 # http://opensource.org/licenses/bsd-license.php
13 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 from __future__
import print_function
21 import Common
.LongFilePathOs
as os
23 from io
import BytesIO
29 import encodings
.ascii
31 import multiprocessing
34 from threading
import *
35 from optparse
import OptionParser
36 from subprocess
import *
37 from Common
import Misc
as Utils
39 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
40 from Common
.TargetTxtClassObject
import *
41 from Common
.ToolDefClassObject
import *
42 from Common
.DataType
import *
43 from Common
.BuildVersion
import gBUILD_VERSION
44 from AutoGen
.AutoGen
import *
45 from Common
.BuildToolError
import *
46 from Workspace
.WorkspaceDatabase
import WorkspaceDatabase
47 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
49 from BuildReport
import BuildReport
50 from GenPatchPcdTable
.GenPatchPcdTable
import *
51 from PatchPcdValue
.PatchPcdValue
import *
53 import Common
.EdkLogger
54 import Common
.GlobalData
as GlobalData
55 from GenFds
.GenFds
import GenFds
, GenFdsApi
57 from collections
import OrderedDict
, defaultdict
59 # Version and Copyright
60 VersionNumber
= "0.60" + ' ' + gBUILD_VERSION
61 __version__
= "%prog Version " + VersionNumber
62 __copyright__
= "Copyright (c) 2007 - 2018, Intel Corporation All rights reserved."
64 ## standard targets of build command
65 gSupportedTarget
= ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
67 ## build configuration file
68 gBuildConfiguration
= "target.txt"
69 gToolsDefinition
= "tools_def.txt"
71 TemporaryTablePattern
= re
.compile(r
'^_\d+_\d+_[a-fA-F0-9]+$')
74 ## Check environment PATH variable to make sure the specified tool is found
76 # If the tool is found in the PATH, then True is returned
77 # Otherwise, False is returned
79 def IsToolInPath(tool
):
80 if 'PATHEXT' in os
.environ
:
81 extns
= os
.environ
['PATHEXT'].split(os
.path
.pathsep
)
84 for pathDir
in os
.environ
['PATH'].split(os
.path
.pathsep
):
86 if os
.path
.exists(os
.path
.join(pathDir
, tool
+ ext
)):
90 ## Check environment variables
92 # Check environment variables that must be set for build. Currently they are
94 # WORKSPACE The directory all packages/platforms start from
95 # EDK_TOOLS_PATH The directory contains all tools needed by the build
96 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
98 # If any of above environment variable is not set or has error, the build
101 def CheckEnvVariable():
103 if "WORKSPACE" not in os
.environ
:
104 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
105 ExtraData
="WORKSPACE")
107 WorkspaceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["WORKSPACE"]))
108 if not os
.path
.exists(WorkspaceDir
):
109 EdkLogger
.error("build", FILE_NOT_FOUND
, "WORKSPACE doesn't exist", ExtraData
=WorkspaceDir
)
110 elif ' ' in WorkspaceDir
:
111 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in WORKSPACE path",
112 ExtraData
=WorkspaceDir
)
113 os
.environ
["WORKSPACE"] = WorkspaceDir
115 # set multiple workspace
116 PackagesPath
= os
.getenv("PACKAGES_PATH")
117 mws
.setWs(WorkspaceDir
, PackagesPath
)
118 if mws
.PACKAGES_PATH
:
119 for Path
in mws
.PACKAGES_PATH
:
120 if not os
.path
.exists(Path
):
121 EdkLogger
.error("build", FILE_NOT_FOUND
, "One Path in PACKAGES_PATH doesn't exist", ExtraData
=Path
)
123 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in PACKAGES_PATH", ExtraData
=Path
)
126 # Check EFI_SOURCE (Edk build convention). EDK_SOURCE will always point to ECP
128 if "ECP_SOURCE" not in os
.environ
:
129 os
.environ
["ECP_SOURCE"] = mws
.join(WorkspaceDir
, GlobalData
.gEdkCompatibilityPkg
)
130 if "EFI_SOURCE" not in os
.environ
:
131 os
.environ
["EFI_SOURCE"] = os
.environ
["ECP_SOURCE"]
132 if "EDK_SOURCE" not in os
.environ
:
133 os
.environ
["EDK_SOURCE"] = os
.environ
["ECP_SOURCE"]
136 # Unify case of characters on case-insensitive systems
138 EfiSourceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["EFI_SOURCE"]))
139 EdkSourceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_SOURCE"]))
140 EcpSourceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["ECP_SOURCE"]))
142 os
.environ
["EFI_SOURCE"] = EfiSourceDir
143 os
.environ
["EDK_SOURCE"] = EdkSourceDir
144 os
.environ
["ECP_SOURCE"] = EcpSourceDir
145 os
.environ
["EDK_TOOLS_PATH"] = os
.path
.normcase(os
.environ
["EDK_TOOLS_PATH"])
147 if not os
.path
.exists(EcpSourceDir
):
148 EdkLogger
.verbose("ECP_SOURCE = %s doesn't exist. Edk modules could not be built." % EcpSourceDir
)
149 elif ' ' in EcpSourceDir
:
150 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in ECP_SOURCE path",
151 ExtraData
=EcpSourceDir
)
152 if not os
.path
.exists(EdkSourceDir
):
153 if EdkSourceDir
== EcpSourceDir
:
154 EdkLogger
.verbose("EDK_SOURCE = %s doesn't exist. Edk modules could not be built." % EdkSourceDir
)
156 EdkLogger
.error("build", PARAMETER_INVALID
, "EDK_SOURCE does not exist",
157 ExtraData
=EdkSourceDir
)
158 elif ' ' in EdkSourceDir
:
159 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in EDK_SOURCE path",
160 ExtraData
=EdkSourceDir
)
161 if not os
.path
.exists(EfiSourceDir
):
162 if EfiSourceDir
== EcpSourceDir
:
163 EdkLogger
.verbose("EFI_SOURCE = %s doesn't exist. Edk modules could not be built." % EfiSourceDir
)
165 EdkLogger
.error("build", PARAMETER_INVALID
, "EFI_SOURCE does not exist",
166 ExtraData
=EfiSourceDir
)
167 elif ' ' in EfiSourceDir
:
168 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in EFI_SOURCE path",
169 ExtraData
=EfiSourceDir
)
171 # check those variables on single workspace case
173 # change absolute path to relative path to WORKSPACE
174 if EfiSourceDir
.upper().find(WorkspaceDir
.upper()) != 0:
175 EdkLogger
.error("build", PARAMETER_INVALID
, "EFI_SOURCE is not under WORKSPACE",
176 ExtraData
="WORKSPACE = %s\n EFI_SOURCE = %s" % (WorkspaceDir
, EfiSourceDir
))
177 if EdkSourceDir
.upper().find(WorkspaceDir
.upper()) != 0:
178 EdkLogger
.error("build", PARAMETER_INVALID
, "EDK_SOURCE is not under WORKSPACE",
179 ExtraData
="WORKSPACE = %s\n EDK_SOURCE = %s" % (WorkspaceDir
, EdkSourceDir
))
180 if EcpSourceDir
.upper().find(WorkspaceDir
.upper()) != 0:
181 EdkLogger
.error("build", PARAMETER_INVALID
, "ECP_SOURCE is not under WORKSPACE",
182 ExtraData
="WORKSPACE = %s\n ECP_SOURCE = %s" % (WorkspaceDir
, EcpSourceDir
))
184 # check EDK_TOOLS_PATH
185 if "EDK_TOOLS_PATH" not in os
.environ
:
186 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
187 ExtraData
="EDK_TOOLS_PATH")
190 if "PATH" not in os
.environ
:
191 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
194 GlobalData
.gWorkspace
= WorkspaceDir
195 GlobalData
.gEfiSource
= EfiSourceDir
196 GlobalData
.gEdkSource
= EdkSourceDir
197 GlobalData
.gEcpSource
= EcpSourceDir
199 GlobalData
.gGlobalDefines
["WORKSPACE"] = WorkspaceDir
200 GlobalData
.gGlobalDefines
["EFI_SOURCE"] = EfiSourceDir
201 GlobalData
.gGlobalDefines
["EDK_SOURCE"] = EdkSourceDir
202 GlobalData
.gGlobalDefines
["ECP_SOURCE"] = EcpSourceDir
203 GlobalData
.gGlobalDefines
["EDK_TOOLS_PATH"] = os
.environ
["EDK_TOOLS_PATH"]
205 ## Get normalized file path
207 # Convert the path to be local format, and remove the WORKSPACE path at the
208 # beginning if the file path is given in full path.
210 # @param FilePath File path to be normalized
211 # @param Workspace Workspace path which the FilePath will be checked against
213 # @retval string The normalized file path
215 def NormFile(FilePath
, Workspace
):
216 # check if the path is absolute or relative
217 if os
.path
.isabs(FilePath
):
218 FileFullPath
= os
.path
.normpath(FilePath
)
220 FileFullPath
= os
.path
.normpath(mws
.join(Workspace
, FilePath
))
221 Workspace
= mws
.getWs(Workspace
, FilePath
)
223 # check if the file path exists or not
224 if not os
.path
.isfile(FileFullPath
):
225 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath
)
227 # remove workspace directory from the beginning part of the file path
228 if Workspace
[-1] in ["\\", "/"]:
229 return FileFullPath
[len(Workspace
):]
231 return FileFullPath
[(len(Workspace
) + 1):]
233 ## Get the output of an external program
235 # This is the entrance method of thread reading output of an external program and
236 # putting them in STDOUT/STDERR of current program.
238 # @param From The stream message read from
239 # @param To The stream message put on
240 # @param ExitFlag The flag used to indicate stopping reading
242 def ReadMessage(From
, To
, ExitFlag
):
244 # read one line a time
245 Line
= From
.readline()
246 # empty string means "end"
247 if Line
is not None and Line
!= "":
254 ## Launch an external program
256 # This method will call subprocess.Popen to execute an external program with
257 # given options in specified directory. Because of the dead-lock issue during
258 # redirecting output of the external program, threads are used to to do the
261 # @param Command A list or string containing the call of the program
262 # @param WorkingDir The directory in which the program will be running
264 def LaunchCommand(Command
, WorkingDir
):
265 BeginTime
= time
.time()
266 # if working directory doesn't exist, Popen() will raise an exception
267 if not os
.path
.isdir(WorkingDir
):
268 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=WorkingDir
)
270 # Command is used as the first Argument in following Popen().
271 # It could be a string or sequence. We find that if command is a string in following Popen(),
272 # ubuntu may fail with an error message that the command is not found.
273 # So here we may need convert command from string to list instance.
274 if platform
.system() != 'Windows':
275 if not isinstance(Command
, list):
276 Command
= Command
.split()
277 Command
= ' '.join(Command
)
280 EndOfProcedure
= None
283 Proc
= Popen(Command
, stdout
=PIPE
, stderr
=PIPE
, env
=os
.environ
, cwd
=WorkingDir
, bufsize
=-1, shell
=True)
285 # launch two threads to read the STDOUT and STDERR
286 EndOfProcedure
= Event()
287 EndOfProcedure
.clear()
289 StdOutThread
= Thread(target
=ReadMessage
, args
=(Proc
.stdout
, EdkLogger
.info
, EndOfProcedure
))
290 StdOutThread
.setName("STDOUT-Redirector")
291 StdOutThread
.setDaemon(False)
295 StdErrThread
= Thread(target
=ReadMessage
, args
=(Proc
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
296 StdErrThread
.setName("STDERR-Redirector")
297 StdErrThread
.setDaemon(False)
300 # waiting for program exit
302 except: # in case of aborting
303 # terminate the threads redirecting the program output
304 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
305 if EndOfProcedure
is not None:
308 if not isinstance(Command
, type("")):
309 Command
= " ".join(Command
)
310 EdkLogger
.error("build", COMMAND_FAILURE
, "Failed to start command", ExtraData
="%s [%s]" % (Command
, WorkingDir
))
317 # check the return code of the program
318 if Proc
.returncode
!= 0:
319 if not isinstance(Command
, type("")):
320 Command
= " ".join(Command
)
321 # print out the Response file and its content when make failure
322 RespFile
= os
.path
.join(WorkingDir
, 'OUTPUT', 'respfilelist.txt')
323 if os
.path
.isfile(RespFile
):
325 RespContent
= f
.read()
327 EdkLogger
.info(RespContent
)
329 EdkLogger
.error("build", COMMAND_FAILURE
, ExtraData
="%s [%s]" % (Command
, WorkingDir
))
330 return "%dms" % (int(round((time
.time() - BeginTime
) * 1000)))
332 ## The smallest unit that can be built in multi-thread build mode
334 # This is the base class of build unit. The "Obj" parameter must provide
335 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
338 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
343 # @param self The object pointer
344 # @param Obj The object the build is working on
345 # @param Target The build target name, one of gSupportedTarget
346 # @param Dependency The BuildUnit(s) which must be completed in advance
347 # @param WorkingDir The directory build command starts in
349 def __init__(self
, Obj
, BuildCommand
, Target
, Dependency
, WorkingDir
="."):
350 self
.BuildObject
= Obj
351 self
.Dependency
= Dependency
352 self
.WorkingDir
= WorkingDir
354 self
.BuildCommand
= BuildCommand
356 EdkLogger
.error("build", OPTION_MISSING
,
357 "No build command found for this module. "
358 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
359 (Obj
.BuildTarget
, Obj
.ToolChain
, Obj
.Arch
),
365 # It just returns the string representation of self.BuildObject
367 # @param self The object pointer
370 return str(self
.BuildObject
)
372 ## "==" operator method
374 # It just compares self.BuildObject with "Other". So self.BuildObject must
375 # provide its own __eq__() method.
377 # @param self The object pointer
378 # @param Other The other BuildUnit object compared to
380 def __eq__(self
, Other
):
381 return Other
and self
.BuildObject
== Other
.BuildObject \
382 and Other
.BuildObject \
383 and self
.BuildObject
.Arch
== Other
.BuildObject
.Arch
387 # It just returns the hash value of self.BuildObject which must be hashable.
389 # @param self The object pointer
392 return hash(self
.BuildObject
) + hash(self
.BuildObject
.Arch
)
395 return repr(self
.BuildObject
)
397 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
399 # This class is for module build by nmake/make build system. The "Obj" parameter
400 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
401 # be make units missing build.
403 # Currently the "Obj" should be only ModuleAutoGen object.
405 class ModuleMakeUnit(BuildUnit
):
408 # @param self The object pointer
409 # @param Obj The ModuleAutoGen object the build is working on
410 # @param Target The build target name, one of gSupportedTarget
412 def __init__(self
, Obj
, Target
):
413 Dependency
= [ModuleMakeUnit(La
, Target
) for La
in Obj
.LibraryAutoGenList
]
414 BuildUnit
.__init
__(self
, Obj
, Obj
.BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
415 if Target
in [None, "", "all"]:
416 self
.Target
= "tbuild"
418 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
420 # This class is for platform build by nmake/make build system. The "Obj" parameter
421 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
422 # be make units missing build.
424 # Currently the "Obj" should be only PlatformAutoGen object.
426 class PlatformMakeUnit(BuildUnit
):
429 # @param self The object pointer
430 # @param Obj The PlatformAutoGen object the build is working on
431 # @param Target The build target name, one of gSupportedTarget
433 def __init__(self
, Obj
, Target
):
434 Dependency
= [ModuleMakeUnit(Lib
, Target
) for Lib
in self
.BuildObject
.LibraryAutoGenList
]
435 Dependency
.extend([ModuleMakeUnit(Mod
, Target
) for Mod
in self
.BuildObject
.ModuleAutoGenList
])
436 BuildUnit
.__init
__(self
, Obj
, Obj
.BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
438 ## The class representing the task of a module build or platform build
440 # This class manages the build tasks in multi-thread build mode. Its jobs include
441 # scheduling thread running, catching thread error, monitor the thread status, etc.
444 # queue for tasks waiting for schedule
445 _PendingQueue
= OrderedDict()
446 _PendingQueueLock
= threading
.Lock()
448 # queue for tasks ready for running
449 _ReadyQueue
= OrderedDict()
450 _ReadyQueueLock
= threading
.Lock()
452 # queue for run tasks
453 _RunningQueue
= OrderedDict()
454 _RunningQueueLock
= threading
.Lock()
456 # queue containing all build tasks, in case duplicate build
457 _TaskQueue
= OrderedDict()
459 # flag indicating error occurs in a running thread
460 _ErrorFlag
= threading
.Event()
464 # BoundedSemaphore object used to control the number of running threads
467 # flag indicating if the scheduler is started or not
468 _SchedulerStopped
= threading
.Event()
469 _SchedulerStopped
.set()
471 ## Start the task scheduler thread
473 # @param MaxThreadNumber The maximum thread number
474 # @param ExitFlag Flag used to end the scheduler
477 def StartScheduler(MaxThreadNumber
, ExitFlag
):
478 SchedulerThread
= Thread(target
=BuildTask
.Scheduler
, args
=(MaxThreadNumber
, ExitFlag
))
479 SchedulerThread
.setName("Build-Task-Scheduler")
480 SchedulerThread
.setDaemon(False)
481 SchedulerThread
.start()
482 # wait for the scheduler to be started, especially useful in Linux
483 while not BuildTask
.IsOnGoing():
488 # @param MaxThreadNumber The maximum thread number
489 # @param ExitFlag Flag used to end the scheduler
492 def Scheduler(MaxThreadNumber
, ExitFlag
):
493 BuildTask
._SchedulerStopped
.clear()
495 # use BoundedSemaphore to control the maximum running threads
496 BuildTask
._Thread
= BoundedSemaphore(MaxThreadNumber
)
498 # scheduling loop, which will exits when no pending/ready task and
499 # indicated to do so, or there's error in running thread
501 while (len(BuildTask
._PendingQueue
) > 0 or len(BuildTask
._ReadyQueue
) > 0 \
502 or not ExitFlag
.isSet()) and not BuildTask
._ErrorFlag
.isSet():
503 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Pending Queue (%d), Ready Queue (%d)"
504 % (len(BuildTask
._PendingQueue
), len(BuildTask
._ReadyQueue
)))
506 # get all pending tasks
507 BuildTask
._PendingQueueLock
.acquire()
508 BuildObjectList
= BuildTask
._PendingQueue
.keys()
510 # check if their dependency is resolved, and if true, move them
513 for BuildObject
in BuildObjectList
:
514 Bt
= BuildTask
._PendingQueue
[BuildObject
]
516 BuildTask
._ReadyQueue
[BuildObject
] = BuildTask
._PendingQueue
.pop(BuildObject
)
517 BuildTask
._PendingQueueLock
.release()
519 # launch build thread until the maximum number of threads is reached
520 while not BuildTask
._ErrorFlag
.isSet():
521 # empty ready queue, do nothing further
522 if len(BuildTask
._ReadyQueue
) == 0:
525 # wait for active thread(s) exit
526 BuildTask
._Thread
.acquire(True)
528 # start a new build thread
529 Bo
, Bt
= BuildTask
._ReadyQueue
.popitem()
531 # move into running queue
532 BuildTask
._RunningQueueLock
.acquire()
533 BuildTask
._RunningQueue
[Bo
] = Bt
534 BuildTask
._RunningQueueLock
.release()
543 # wait for all running threads exit
544 if BuildTask
._ErrorFlag
.isSet():
545 EdkLogger
.quiet("\nWaiting for all build threads exit...")
546 # while not BuildTask._ErrorFlag.isSet() and \
547 while len(BuildTask
._RunningQueue
) > 0:
548 EdkLogger
.verbose("Waiting for thread ending...(%d)" % len(BuildTask
._RunningQueue
))
549 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Threads [%s]" % ", ".join(Th
.getName() for Th
in threading
.enumerate()))
552 except BaseException
as X
:
554 # TRICK: hide the output of threads left runing, so that the user can
555 # catch the error message easily
557 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
558 BuildTask
._ErrorFlag
.set()
559 BuildTask
._ErrorMessage
= "build thread scheduler error\n\t%s" % str(X
)
561 BuildTask
._PendingQueue
.clear()
562 BuildTask
._ReadyQueue
.clear()
563 BuildTask
._RunningQueue
.clear()
564 BuildTask
._TaskQueue
.clear()
565 BuildTask
._SchedulerStopped
.set()
567 ## Wait for all running method exit
570 def WaitForComplete():
571 BuildTask
._SchedulerStopped
.wait()
573 ## Check if the scheduler is running or not
577 return not BuildTask
._SchedulerStopped
.isSet()
582 if BuildTask
.IsOnGoing():
583 BuildTask
._ErrorFlag
.set()
584 BuildTask
.WaitForComplete()
586 ## Check if there's error in running thread
588 # Since the main thread cannot catch exceptions in other thread, we have to
589 # use threading.Event to communicate this formation to main thread.
593 return BuildTask
._ErrorFlag
.isSet()
595 ## Get error message in running thread
597 # Since the main thread cannot catch exceptions in other thread, we have to
598 # use a static variable to communicate this message to main thread.
601 def GetErrorMessage():
602 return BuildTask
._ErrorMessage
604 ## Factory method to create a BuildTask object
606 # This method will check if a module is building or has been built. And if
607 # true, just return the associated BuildTask object in the _TaskQueue. If
608 # not, create and return a new BuildTask object. The new BuildTask object
609 # will be appended to the _PendingQueue for scheduling later.
611 # @param BuildItem A BuildUnit object representing a build object
612 # @param Dependency The dependent build object of BuildItem
615 def New(BuildItem
, Dependency
=None):
616 if BuildItem
in BuildTask
._TaskQueue
:
617 Bt
= BuildTask
._TaskQueue
[BuildItem
]
621 Bt
._Init
(BuildItem
, Dependency
)
622 BuildTask
._TaskQueue
[BuildItem
] = Bt
624 BuildTask
._PendingQueueLock
.acquire()
625 BuildTask
._PendingQueue
[BuildItem
] = Bt
626 BuildTask
._PendingQueueLock
.release()
630 ## The real constructor of BuildTask
632 # @param BuildItem A BuildUnit object representing a build object
633 # @param Dependency The dependent build object of BuildItem
635 def _Init(self
, BuildItem
, Dependency
=None):
636 self
.BuildItem
= BuildItem
638 self
.DependencyList
= []
639 if Dependency
is None:
640 Dependency
= BuildItem
.Dependency
642 Dependency
.extend(BuildItem
.Dependency
)
643 self
.AddDependency(Dependency
)
644 # flag indicating build completes, used to avoid unnecessary re-build
645 self
.CompleteFlag
= False
647 ## Check if all dependent build tasks are completed or not
651 for Dep
in self
.DependencyList
:
652 if Dep
.CompleteFlag
== True:
659 ## Add dependent build task
661 # @param Dependency The list of dependent build objects
663 def AddDependency(self
, Dependency
):
664 for Dep
in Dependency
:
665 if not Dep
.BuildObject
.IsBinaryModule
:
666 self
.DependencyList
.append(BuildTask
.New(Dep
)) # BuildTask list
668 ## The thread wrapper of LaunchCommand function
670 # @param Command A list or string contains the call of the command
671 # @param WorkingDir The directory in which the program will be running
673 def _CommandThread(self
, Command
, WorkingDir
):
675 self
.BuildItem
.BuildObject
.BuildTime
= LaunchCommand(Command
, WorkingDir
)
676 self
.CompleteFlag
= True
679 # TRICK: hide the output of threads left runing, so that the user can
680 # catch the error message easily
682 if not BuildTask
._ErrorFlag
.isSet():
683 GlobalData
.gBuildingModule
= "%s [%s, %s, %s]" % (str(self
.BuildItem
.BuildObject
),
684 self
.BuildItem
.BuildObject
.Arch
,
685 self
.BuildItem
.BuildObject
.ToolChain
,
686 self
.BuildItem
.BuildObject
.BuildTarget
688 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
689 BuildTask
._ErrorFlag
.set()
690 BuildTask
._ErrorMessage
= "%s broken\n %s [%s]" % \
691 (threading
.currentThread().getName(), Command
, WorkingDir
)
692 # indicate there's a thread is available for another build task
693 BuildTask
._RunningQueueLock
.acquire()
694 BuildTask
._RunningQueue
.pop(self
.BuildItem
)
695 BuildTask
._RunningQueueLock
.release()
696 BuildTask
._Thread
.release()
698 ## Start build task thread
701 EdkLogger
.quiet("Building ... %s" % repr(self
.BuildItem
))
702 Command
= self
.BuildItem
.BuildCommand
+ [self
.BuildItem
.Target
]
703 self
.BuildTread
= Thread(target
=self
._CommandThread
, args
=(Command
, self
.BuildItem
.WorkingDir
))
704 self
.BuildTread
.setName("build thread")
705 self
.BuildTread
.setDaemon(False)
706 self
.BuildTread
.start()
708 ## The class contains the information related to EFI image
713 # Constructor will load all required image information.
715 # @param BaseName The full file path of image.
716 # @param Guid The GUID for image.
717 # @param Arch Arch of this image.
718 # @param OutputDir The output directory for image.
719 # @param DebugDir The debug directory for image.
720 # @param ImageClass PeImage Information
722 def __init__(self
, BaseName
, Guid
, Arch
, OutputDir
, DebugDir
, ImageClass
):
723 self
.BaseName
= BaseName
726 self
.OutputDir
= OutputDir
727 self
.DebugDir
= DebugDir
728 self
.Image
= ImageClass
729 self
.Image
.Size
= (self
.Image
.Size
/ 0x1000 + 1) * 0x1000
731 ## The class implementing the EDK2 build process
733 # The build process includes:
734 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
735 # 2. Parse DSC file of active platform
736 # 3. Parse FDF file if any
737 # 4. Establish build database, including parse all other files (module, package)
738 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
739 # 6. Call build command
744 # Constructor will load all necessary configurations, parse platform, modules
745 # and packages and the establish a database for AutoGen.
747 # @param Target The build command target, one of gSupportedTarget
748 # @param WorkspaceDir The directory of workspace
749 # @param BuildOptions Build options passed from command line
751 def __init__(self
, Target
, WorkspaceDir
, BuildOptions
):
752 self
.WorkspaceDir
= WorkspaceDir
754 self
.PlatformFile
= BuildOptions
.PlatformFile
755 self
.ModuleFile
= BuildOptions
.ModuleFile
756 self
.ArchList
= BuildOptions
.TargetArch
757 self
.ToolChainList
= BuildOptions
.ToolChain
758 self
.BuildTargetList
= BuildOptions
.BuildTarget
759 self
.Fdf
= BuildOptions
.FdfFile
760 self
.FdList
= BuildOptions
.RomImage
761 self
.FvList
= BuildOptions
.FvImage
762 self
.CapList
= BuildOptions
.CapName
763 self
.SilentMode
= BuildOptions
.SilentMode
764 self
.ThreadNumber
= BuildOptions
.ThreadNumber
765 self
.SkipAutoGen
= BuildOptions
.SkipAutoGen
766 self
.Reparse
= BuildOptions
.Reparse
767 self
.SkuId
= BuildOptions
.SkuId
769 GlobalData
.gSKUID_CMD
= self
.SkuId
770 self
.ConfDirectory
= BuildOptions
.ConfDirectory
771 self
.SpawnMode
= True
772 self
.BuildReport
= BuildReport(BuildOptions
.ReportFile
, BuildOptions
.ReportType
)
773 self
.TargetTxt
= TargetTxtClassObject()
774 self
.ToolDef
= ToolDefClassObject()
778 GlobalData
.BuildOptionPcd
= BuildOptions
.OptionPcd
if BuildOptions
.OptionPcd
else []
779 #Set global flag for build mode
780 GlobalData
.gIgnoreSource
= BuildOptions
.IgnoreSources
781 GlobalData
.gUseHashCache
= BuildOptions
.UseHashCache
782 GlobalData
.gBinCacheDest
= BuildOptions
.BinCacheDest
783 GlobalData
.gBinCacheSource
= BuildOptions
.BinCacheSource
784 GlobalData
.gEnableGenfdsMultiThread
= BuildOptions
.GenfdsMultiThread
786 if GlobalData
.gBinCacheDest
and not GlobalData
.gUseHashCache
:
787 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination must be used together with --hash.")
789 if GlobalData
.gBinCacheSource
and not GlobalData
.gUseHashCache
:
790 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-source must be used together with --hash.")
792 if GlobalData
.gBinCacheDest
and GlobalData
.gBinCacheSource
:
793 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination can not be used together with --binary-source.")
795 if GlobalData
.gBinCacheSource
:
796 BinCacheSource
= os
.path
.normpath(GlobalData
.gBinCacheSource
)
797 if not os
.path
.isabs(BinCacheSource
):
798 BinCacheSource
= mws
.join(self
.WorkspaceDir
, BinCacheSource
)
799 GlobalData
.gBinCacheSource
= BinCacheSource
801 if GlobalData
.gBinCacheSource
is not None:
802 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-source.")
804 if GlobalData
.gBinCacheDest
:
805 BinCacheDest
= os
.path
.normpath(GlobalData
.gBinCacheDest
)
806 if not os
.path
.isabs(BinCacheDest
):
807 BinCacheDest
= mws
.join(self
.WorkspaceDir
, BinCacheDest
)
808 GlobalData
.gBinCacheDest
= BinCacheDest
810 if GlobalData
.gBinCacheDest
is not None:
811 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-destination.")
813 if self
.ConfDirectory
:
814 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
815 ConfDirectoryPath
= os
.path
.normpath(self
.ConfDirectory
)
817 if not os
.path
.isabs(ConfDirectoryPath
):
818 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
819 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
820 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, ConfDirectoryPath
)
822 if "CONF_PATH" in os
.environ
:
823 ConfDirectoryPath
= os
.path
.normcase(os
.path
.normpath(os
.environ
["CONF_PATH"]))
825 # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf
826 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, 'Conf')
827 GlobalData
.gConfDirectory
= ConfDirectoryPath
828 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
830 self
.Db
= WorkspaceDatabase()
831 self
.BuildDatabase
= self
.Db
.BuildObject
833 self
.ToolChainFamily
= None
834 self
.LoadFixAddress
= 0
835 self
.UniFlag
= BuildOptions
.Flag
836 self
.BuildModules
= []
837 self
.HashSkipModules
= []
839 self
.LaunchPrebuildFlag
= False
840 self
.PlatformBuildPath
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PlatformBuild')
841 if BuildOptions
.CommandLength
:
842 GlobalData
.gCommandMaxLength
= BuildOptions
.CommandLength
844 # print dot character during doing some time-consuming work
845 self
.Progress
= Utils
.Progressor()
846 # print current build environment and configuration
847 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
848 if "PACKAGES_PATH" in os
.environ
:
849 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
850 EdkLogger
.quiet("%-16s = %s" % ("PACKAGES_PATH", os
.path
.normcase(os
.path
.normpath(os
.environ
["PACKAGES_PATH"]))))
851 EdkLogger
.quiet("%-16s = %s" % ("ECP_SOURCE", os
.environ
["ECP_SOURCE"]))
852 EdkLogger
.quiet("%-16s = %s" % ("EDK_SOURCE", os
.environ
["EDK_SOURCE"]))
853 EdkLogger
.quiet("%-16s = %s" % ("EFI_SOURCE", os
.environ
["EFI_SOURCE"]))
854 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
855 if "EDK_TOOLS_BIN" in os
.environ
:
856 # Print the same path style with WORKSPACE env.
857 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_TOOLS_BIN"]))))
858 EdkLogger
.quiet("%-16s = %s" % ("CONF_PATH", GlobalData
.gConfDirectory
))
862 EdkLogger
.quiet("%-16s = %s" % ("PREBUILD", self
.Prebuild
))
864 EdkLogger
.quiet("%-16s = %s" % ("POSTBUILD", self
.Postbuild
))
866 self
.LaunchPrebuild()
867 self
.TargetTxt
= TargetTxtClassObject()
868 self
.ToolDef
= ToolDefClassObject()
869 if not (self
.LaunchPrebuildFlag
and os
.path
.exists(self
.PlatformBuildPath
)):
873 os
.chdir(self
.WorkspaceDir
)
875 ## Load configuration
877 # This method will parse target.txt and get the build configurations.
879 def LoadConfiguration(self
):
881 # Check target.txt and tools_def.txt and Init them
883 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(GlobalData
.gConfDirectory
, gBuildConfiguration
))
884 if os
.path
.isfile(BuildConfigurationFile
) == True:
885 StatusCode
= self
.TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
887 ToolDefinitionFile
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_CONF
]
888 if ToolDefinitionFile
== '':
889 ToolDefinitionFile
= gToolsDefinition
890 ToolDefinitionFile
= os
.path
.normpath(mws
.join(self
.WorkspaceDir
, 'Conf', ToolDefinitionFile
))
891 if os
.path
.isfile(ToolDefinitionFile
) == True:
892 StatusCode
= self
.ToolDef
.LoadToolDefFile(ToolDefinitionFile
)
894 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=ToolDefinitionFile
)
896 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
898 # if no ARCH given in command line, get it from target.txt
899 if not self
.ArchList
:
900 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TARGET_ARCH
]
901 self
.ArchList
= tuple(self
.ArchList
)
903 # if no build target given in command line, get it from target.txt
904 if not self
.BuildTargetList
:
905 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TARGET
]
907 # if no tool chain given in command line, get it from target.txt
908 if not self
.ToolChainList
:
909 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
910 if self
.ToolChainList
is None or len(self
.ToolChainList
) == 0:
911 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
913 # check if the tool chains are defined or not
914 NewToolChainList
= []
915 for ToolChain
in self
.ToolChainList
:
916 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
917 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
919 NewToolChainList
.append(ToolChain
)
920 # if no tool chain available, break the build
921 if len(NewToolChainList
) == 0:
922 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
923 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
925 self
.ToolChainList
= NewToolChainList
928 ToolDefinition
= self
.ToolDef
.ToolsDefTxtDatabase
929 for Tool
in self
.ToolChainList
:
930 if TAB_TOD_DEFINES_FAMILY
not in ToolDefinition
or Tool
not in ToolDefinition
[TAB_TOD_DEFINES_FAMILY
] \
931 or not ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
]:
932 EdkLogger
.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool
)
933 ToolChainFamily
.append(TAB_COMPILER_MSFT
)
935 ToolChainFamily
.append(ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
])
936 self
.ToolChainFamily
= ToolChainFamily
938 if self
.ThreadNumber
is None:
939 self
.ThreadNumber
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
940 if self
.ThreadNumber
== '':
941 self
.ThreadNumber
= 0
943 self
.ThreadNumber
= int(self
.ThreadNumber
, 0)
945 if self
.ThreadNumber
== 0:
947 self
.ThreadNumber
= multiprocessing
.cpu_count()
948 except (ImportError, NotImplementedError):
949 self
.ThreadNumber
= 1
951 if not self
.PlatformFile
:
952 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
954 # Try to find one in current directory
955 WorkingDirectory
= os
.getcwd()
956 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
957 FileNum
= len(FileList
)
959 EdkLogger
.error("build", OPTION_MISSING
,
960 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
962 PlatformFile
= FileList
[0]
964 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
965 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
967 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
969 ## Initialize build configuration
971 # This method will parse DSC file and merge the configurations from
972 # command line and target.txt, then get the final build configurations.
975 # parse target.txt, tools_def.txt, and platform file
976 self
.LoadConfiguration()
978 # Allow case-insensitive for those from command line or configuration file
979 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
981 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
984 def InitPreBuild(self
):
985 self
.LoadConfiguration()
986 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
988 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
989 if self
.BuildTargetList
:
990 GlobalData
.gGlobalDefines
['TARGET'] = self
.BuildTargetList
[0]
992 GlobalData
.gGlobalDefines
['ARCH'] = self
.ArchList
[0]
993 if self
.ToolChainList
:
994 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = self
.ToolChainList
[0]
995 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = self
.ToolChainList
[0]
996 if self
.ToolChainFamily
:
997 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[0]
998 if 'PREBUILD' in GlobalData
.gCommandLineDefines
:
999 self
.Prebuild
= GlobalData
.gCommandLineDefines
.get('PREBUILD')
1002 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
1003 self
.Prebuild
= str(Platform
.Prebuild
)
1007 # Evaluate all arguments and convert arguments that are WORKSPACE
1008 # relative paths to absolute paths. Filter arguments that look like
1009 # flags or do not follow the file/dir naming rules to avoid false
1010 # positives on this conversion.
1012 for Arg
in self
.Prebuild
.split():
1014 # Do not modify Arg if it looks like a flag or an absolute file path
1016 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1017 PrebuildList
.append(Arg
)
1020 # Do not modify Arg if it does not look like a Workspace relative
1021 # path that starts with a valid package directory name
1023 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1024 PrebuildList
.append(Arg
)
1027 # If Arg looks like a WORKSPACE relative path, then convert to an
1028 # absolute path and check to see if the file exists.
1030 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1031 if os
.path
.isfile(Temp
):
1033 PrebuildList
.append(Arg
)
1034 self
.Prebuild
= ' '.join(PrebuildList
)
1035 self
.Prebuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1037 def InitPostBuild(self
):
1038 if 'POSTBUILD' in GlobalData
.gCommandLineDefines
:
1039 self
.Postbuild
= GlobalData
.gCommandLineDefines
.get('POSTBUILD')
1041 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
1042 self
.Postbuild
= str(Platform
.Postbuild
)
1046 # Evaluate all arguments and convert arguments that are WORKSPACE
1047 # relative paths to absolute paths. Filter arguments that look like
1048 # flags or do not follow the file/dir naming rules to avoid false
1049 # positives on this conversion.
1051 for Arg
in self
.Postbuild
.split():
1053 # Do not modify Arg if it looks like a flag or an absolute file path
1055 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1056 PostbuildList
.append(Arg
)
1059 # Do not modify Arg if it does not look like a Workspace relative
1060 # path that starts with a valid package directory name
1062 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1063 PostbuildList
.append(Arg
)
1066 # If Arg looks like a WORKSPACE relative path, then convert to an
1067 # absolute path and check to see if the file exists.
1069 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1070 if os
.path
.isfile(Temp
):
1072 PostbuildList
.append(Arg
)
1073 self
.Postbuild
= ' '.join(PostbuildList
)
1074 self
.Postbuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1076 def PassCommandOption(self
, BuildTarget
, TargetArch
, ToolChain
, PlatformFile
, Target
):
1078 if GlobalData
.gCommand
and isinstance(GlobalData
.gCommand
, list):
1079 BuildStr
+= ' ' + ' '.join(GlobalData
.gCommand
)
1082 ToolChainFlag
= False
1083 PlatformFileFlag
= False
1085 if GlobalData
.gOptions
and not GlobalData
.gOptions
.BuildTarget
:
1087 if GlobalData
.gOptions
and not GlobalData
.gOptions
.TargetArch
:
1089 if GlobalData
.gOptions
and not GlobalData
.gOptions
.ToolChain
:
1090 ToolChainFlag
= True
1091 if GlobalData
.gOptions
and not GlobalData
.gOptions
.PlatformFile
:
1092 PlatformFileFlag
= True
1094 if TargetFlag
and BuildTarget
:
1095 if isinstance(BuildTarget
, list) or isinstance(BuildTarget
, tuple):
1096 BuildStr
+= ' -b ' + ' -b '.join(BuildTarget
)
1097 elif isinstance(BuildTarget
, str):
1098 BuildStr
+= ' -b ' + BuildTarget
1099 if ArchFlag
and TargetArch
:
1100 if isinstance(TargetArch
, list) or isinstance(TargetArch
, tuple):
1101 BuildStr
+= ' -a ' + ' -a '.join(TargetArch
)
1102 elif isinstance(TargetArch
, str):
1103 BuildStr
+= ' -a ' + TargetArch
1104 if ToolChainFlag
and ToolChain
:
1105 if isinstance(ToolChain
, list) or isinstance(ToolChain
, tuple):
1106 BuildStr
+= ' -t ' + ' -t '.join(ToolChain
)
1107 elif isinstance(ToolChain
, str):
1108 BuildStr
+= ' -t ' + ToolChain
1109 if PlatformFileFlag
and PlatformFile
:
1110 if isinstance(PlatformFile
, list) or isinstance(PlatformFile
, tuple):
1111 BuildStr
+= ' -p ' + ' -p '.join(PlatformFile
)
1112 elif isinstance(PlatformFile
, str):
1113 BuildStr
+= ' -p' + PlatformFile
1114 BuildStr
+= ' --conf=' + GlobalData
.gConfDirectory
1116 BuildStr
+= ' ' + Target
1120 def LaunchPrebuild(self
):
1122 EdkLogger
.info("\n- Prebuild Start -\n")
1123 self
.LaunchPrebuildFlag
= True
1125 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1126 # and preserve them for the rest of the main build step, because the child process environment will
1127 # evaporate as soon as it exits, we cannot get it in build step.
1129 PrebuildEnvFile
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PrebuildEnv')
1130 if os
.path
.isfile(PrebuildEnvFile
):
1131 os
.remove(PrebuildEnvFile
)
1132 if os
.path
.isfile(self
.PlatformBuildPath
):
1133 os
.remove(self
.PlatformBuildPath
)
1134 if sys
.platform
== "win32":
1135 args
= ' && '.join((self
.Prebuild
, 'set > ' + PrebuildEnvFile
))
1136 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1138 args
= ' && '.join((self
.Prebuild
, 'env > ' + PrebuildEnvFile
))
1139 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1141 # launch two threads to read the STDOUT and STDERR
1142 EndOfProcedure
= Event()
1143 EndOfProcedure
.clear()
1145 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1146 StdOutThread
.setName("STDOUT-Redirector")
1147 StdOutThread
.setDaemon(False)
1148 StdOutThread
.start()
1151 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1152 StdErrThread
.setName("STDERR-Redirector")
1153 StdErrThread
.setDaemon(False)
1154 StdErrThread
.start()
1155 # waiting for program exit
1162 if Process
.returncode
!= 0 :
1163 EdkLogger
.error("Prebuild", PREBUILD_ERROR
, 'Prebuild process is not success!')
1165 if os
.path
.exists(PrebuildEnvFile
):
1166 f
= open(PrebuildEnvFile
)
1167 envs
= f
.readlines()
1169 envs
= itertools
.imap(lambda l
: l
.split('=', 1), envs
)
1170 envs
= itertools
.ifilter(lambda l
: len(l
) == 2, envs
)
1171 envs
= itertools
.imap(lambda l
: [i
.strip() for i
in l
], envs
)
1172 os
.environ
.update(dict(envs
))
1173 EdkLogger
.info("\n- Prebuild Done -\n")
1175 def LaunchPostbuild(self
):
1177 EdkLogger
.info("\n- Postbuild Start -\n")
1178 if sys
.platform
== "win32":
1179 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1181 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1182 # launch two threads to read the STDOUT and STDERR
1183 EndOfProcedure
= Event()
1184 EndOfProcedure
.clear()
1186 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1187 StdOutThread
.setName("STDOUT-Redirector")
1188 StdOutThread
.setDaemon(False)
1189 StdOutThread
.start()
1192 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1193 StdErrThread
.setName("STDERR-Redirector")
1194 StdErrThread
.setDaemon(False)
1195 StdErrThread
.start()
1196 # waiting for program exit
1203 if Process
.returncode
!= 0 :
1204 EdkLogger
.error("Postbuild", POSTBUILD_ERROR
, 'Postbuild process is not success!')
1205 EdkLogger
.info("\n- Postbuild Done -\n")
1206 ## Build a module or platform
1208 # Create autogen code and makefile for a module or platform, and the launch
1209 # "make" command to build it
1211 # @param Target The target of build command
1212 # @param Platform The platform file
1213 # @param Module The module file
1214 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1215 # @param ToolChain The name of toolchain to build
1216 # @param Arch The arch of the module/platform
1217 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1218 # for dependent modules/Libraries
1219 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1220 # for dependent modules/Libraries
1222 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False, FfsCommand
={}):
1223 if AutoGenObject
is None:
1226 # skip file generation for cleanxxx targets, run and fds target
1227 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1228 # for target which must generate AutoGen code and makefile
1229 if not self
.SkipAutoGen
or Target
== 'genc':
1230 self
.Progress
.Start("Generating code")
1231 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1232 self
.Progress
.Stop("done!")
1233 if Target
== "genc":
1236 if not self
.SkipAutoGen
or Target
== 'genmake':
1237 self
.Progress
.Start("Generating makefile")
1238 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
, FfsCommand
)
1239 self
.Progress
.Stop("done!")
1240 if Target
== "genmake":
1243 # always recreate top/platform makefile when clean, just in case of inconsistency
1244 AutoGenObject
.CreateCodeFile(False)
1245 AutoGenObject
.CreateMakeFile(False)
1247 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1248 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1250 BuildCommand
= AutoGenObject
.BuildCommand
1251 if BuildCommand
is None or len(BuildCommand
) == 0:
1252 EdkLogger
.error("build", OPTION_MISSING
,
1253 "No build command found for this module. "
1254 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1255 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1256 ExtraData
=str(AutoGenObject
))
1258 makefile
= GenMake
.BuildFile(AutoGenObject
)._FILE
_NAME
_[GenMake
.gMakeType
]
1262 RunDir
= os
.path
.normpath(os
.path
.join(AutoGenObject
.BuildDir
, GlobalData
.gGlobalDefines
['ARCH']))
1263 Command
= '.\SecMain'
1265 LaunchCommand(Command
, RunDir
)
1270 BuildCommand
= BuildCommand
+ [Target
]
1271 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1272 self
.CreateAsBuiltInf()
1276 if Target
== 'libraries':
1277 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1278 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1279 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1283 if Target
== 'modules':
1284 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1285 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1286 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1287 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1288 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, makefile
)), 'pbuild']
1289 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1290 self
.CreateAsBuiltInf()
1294 if Target
== 'cleanlib':
1295 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1296 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1297 if os
.path
.exists(LibMakefile
):
1298 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1299 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1303 if Target
== 'clean':
1304 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1305 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, makefile
))
1306 if os
.path
.exists(ModMakefile
):
1307 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
1308 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1309 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1310 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1311 if os
.path
.exists(LibMakefile
):
1312 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1313 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1317 if Target
== 'cleanall':
1319 #os.rmdir(AutoGenObject.BuildDir)
1320 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1321 except WindowsError as X
:
1322 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1325 ## Build a module or platform
1327 # Create autogen code and makefile for a module or platform, and the launch
1328 # "make" command to build it
1330 # @param Target The target of build command
1331 # @param Platform The platform file
1332 # @param Module The module file
1333 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1334 # @param ToolChain The name of toolchain to build
1335 # @param Arch The arch of the module/platform
1336 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1337 # for dependent modules/Libraries
1338 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1339 # for dependent modules/Libraries
1341 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1342 if AutoGenObject
is None:
1345 # skip file generation for cleanxxx targets, run and fds target
1346 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1347 # for target which must generate AutoGen code and makefile
1348 if not self
.SkipAutoGen
or Target
== 'genc':
1349 self
.Progress
.Start("Generating code")
1350 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1351 self
.Progress
.Stop("done!")
1352 if Target
== "genc":
1355 if not self
.SkipAutoGen
or Target
== 'genmake':
1356 self
.Progress
.Start("Generating makefile")
1357 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1358 #AutoGenObject.CreateAsBuiltInf()
1359 self
.Progress
.Stop("done!")
1360 if Target
== "genmake":
1363 # always recreate top/platform makefile when clean, just in case of inconsistency
1364 AutoGenObject
.CreateCodeFile(False)
1365 AutoGenObject
.CreateMakeFile(False)
1367 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1368 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1370 BuildCommand
= AutoGenObject
.BuildCommand
1371 if BuildCommand
is None or len(BuildCommand
) == 0:
1372 EdkLogger
.error("build", OPTION_MISSING
,
1373 "No build command found for this module. "
1374 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1375 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1376 ExtraData
=str(AutoGenObject
))
1381 BuildCommand
= BuildCommand
+ [Target
]
1382 AutoGenObject
.BuildTime
= LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1383 self
.CreateAsBuiltInf()
1388 if GenFdsApi(AutoGenObject
.GenFdsCommandDict
, self
.Db
):
1389 EdkLogger
.error("build", COMMAND_FAILURE
)
1394 RunDir
= os
.path
.normpath(os
.path
.join(AutoGenObject
.BuildDir
, GlobalData
.gGlobalDefines
['ARCH']))
1395 Command
= '.\SecMain'
1397 LaunchCommand(Command
, RunDir
)
1401 if Target
== 'libraries':
1408 if Target
== 'cleanall':
1410 #os.rmdir(AutoGenObject.BuildDir)
1411 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1412 except WindowsError as X
:
1413 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1416 ## Rebase module image and Get function address for the input module list.
1418 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1420 AddrIsOffset
= False
1421 for InfFile
in ModuleList
:
1422 sys
.stdout
.write (".")
1424 ModuleInfo
= ModuleList
[InfFile
]
1425 ModuleName
= ModuleInfo
.BaseName
1426 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1427 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1428 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1430 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1432 # Update Image to new BaseAddress by GenFw tool
1434 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1435 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1438 # Set new address to the section header only for SMM driver.
1440 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1441 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1443 # Collect funtion address from Map file
1445 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1447 if os
.path
.exists(ImageMapTable
):
1448 OrigImageBaseAddress
= 0
1449 ImageMap
= open(ImageMapTable
, 'r')
1450 for LinStr
in ImageMap
:
1451 if len (LinStr
.strip()) == 0:
1454 # Get the preferred address set on link time.
1456 if LinStr
.find ('Preferred load address is') != -1:
1457 StrList
= LinStr
.split()
1458 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1460 StrList
= LinStr
.split()
1461 if len (StrList
) > 4:
1462 if StrList
[3] == 'f' or StrList
[3] == 'F':
1464 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1465 FunctionList
.append ((Name
, RelativeAddress
))
1466 if ModuleInfo
.Arch
== 'IPF' and Name
.endswith('_ModuleEntryPoint'):
1468 # Get the real entry point address for IPF image.
1470 ModuleInfo
.Image
.EntryPoint
= RelativeAddress
1473 # Add general information.
1476 MapBuffer
.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1478 MapBuffer
.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1480 MapBuffer
.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1482 # Add guid and general seciton section.
1484 TextSectionAddress
= 0
1485 DataSectionAddress
= 0
1486 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1487 if SectionHeader
[0] == '.text':
1488 TextSectionAddress
= SectionHeader
[1]
1489 elif SectionHeader
[0] in ['.data', '.sdata']:
1490 DataSectionAddress
= SectionHeader
[1]
1492 MapBuffer
.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1494 MapBuffer
.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1496 # Add debug image full path.
1498 MapBuffer
.write('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1500 # Add funtion address
1502 for Function
in FunctionList
:
1504 MapBuffer
.write(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1506 MapBuffer
.write(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1510 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1513 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1515 ## Collect MAP information of all FVs
1517 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1519 # First get the XIP base address for FV map file.
1520 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1521 GuidName
= re
.compile("\(GUID=[-a-fA-F0-9]+")
1522 for FvName
in Wa
.FdfProfile
.FvDict
:
1523 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1524 if not os
.path
.exists(FvMapBuffer
):
1526 FvMap
= open(FvMapBuffer
, 'r')
1527 #skip FV size information
1533 MatchGuid
= GuidPattern
.match(Line
)
1534 if MatchGuid
is not None:
1536 # Replace GUID with module name
1538 GuidString
= MatchGuid
.group()
1539 if GuidString
.upper() in ModuleList
:
1540 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1541 MapBuffer
.write(Line
)
1543 # Add the debug image full path.
1545 MatchGuid
= GuidName
.match(Line
)
1546 if MatchGuid
is not None:
1547 GuidString
= MatchGuid
.group().split("=")[1]
1548 if GuidString
.upper() in ModuleList
:
1549 MapBuffer
.write('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1553 ## Collect MAP information of all modules
1555 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1556 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1558 PatchEfiImageList
= []
1566 # reserve 4K size in SMRAM to make SMM module address not from 0.
1568 IsIpfPlatform
= False
1569 if 'IPF' in self
.ArchList
:
1570 IsIpfPlatform
= True
1571 for ModuleGuid
in ModuleList
:
1572 Module
= ModuleList
[ModuleGuid
]
1573 GlobalData
.gProcessingFile
= "%s [%s, %s, %s]" % (Module
.MetaFile
, Module
.Arch
, Module
.ToolChain
, Module
.BuildTarget
)
1575 OutputImageFile
= ''
1576 for ResultFile
in Module
.CodaTargetList
:
1577 if str(ResultFile
.Target
).endswith('.efi'):
1579 # module list for PEI, DXE, RUNTIME and SMM
1581 OutputImageFile
= os
.path
.join(Module
.OutputDir
, Module
.Name
+ '.efi')
1582 ImageClass
= PeImageClass (OutputImageFile
)
1583 if not ImageClass
.IsValid
:
1584 EdkLogger
.error("build", FILE_PARSE_FAILURE
, ExtraData
=ImageClass
.ErrorInfo
)
1585 ImageInfo
= PeImageInfo(Module
.Name
, Module
.Guid
, Module
.Arch
, Module
.OutputDir
, Module
.DebugDir
, ImageClass
)
1586 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
]:
1587 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1588 PeiSize
+= ImageInfo
.Image
.Size
1589 elif Module
.ModuleType
in [EDK_COMPONENT_TYPE_BS_DRIVER
, SUP_MODULE_DXE_DRIVER
, SUP_MODULE_UEFI_DRIVER
]:
1590 BtModuleList
[Module
.MetaFile
] = ImageInfo
1591 BtSize
+= ImageInfo
.Image
.Size
1592 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
]:
1593 RtModuleList
[Module
.MetaFile
] = ImageInfo
1594 #IPF runtime driver needs to be at 2 page alignment.
1595 if IsIpfPlatform
and ImageInfo
.Image
.Size
% 0x2000 != 0:
1596 ImageInfo
.Image
.Size
= (ImageInfo
.Image
.Size
/ 0x2000 + 1) * 0x2000
1597 RtSize
+= ImageInfo
.Image
.Size
1598 elif Module
.ModuleType
in [SUP_MODULE_SMM_CORE
, SUP_MODULE_DXE_SMM_DRIVER
, SUP_MODULE_MM_STANDALONE
, SUP_MODULE_MM_CORE_STANDALONE
]:
1599 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1600 SmmSize
+= ImageInfo
.Image
.Size
1601 if Module
.ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
1602 PiSpecVersion
= Module
.Module
.Specification
.get('PI_SPECIFICATION_VERSION', '0x00000000')
1603 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1604 if int(PiSpecVersion
, 16) < 0x0001000A:
1605 BtModuleList
[Module
.MetaFile
] = ImageInfo
1606 BtSize
+= ImageInfo
.Image
.Size
1609 # EFI image is final target.
1610 # Check EFI image contains patchable FixAddress related PCDs.
1612 if OutputImageFile
!= '':
1613 ModuleIsPatch
= False
1614 for Pcd
in Module
.ModulePcdList
:
1615 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1616 ModuleIsPatch
= True
1618 if not ModuleIsPatch
:
1619 for Pcd
in Module
.LibraryPcdList
:
1620 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1621 ModuleIsPatch
= True
1624 if not ModuleIsPatch
:
1627 # Module includes the patchable load fix address PCDs.
1628 # It will be fixed up later.
1630 PatchEfiImageList
.append (OutputImageFile
)
1633 # Get Top Memory address
1635 ReservedRuntimeMemorySize
= 0
1636 TopMemoryAddress
= 0
1637 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1638 TopMemoryAddress
= 0
1640 TopMemoryAddress
= self
.LoadFixAddress
1641 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1642 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1643 # Make IPF runtime driver at 2 page alignment.
1645 ReservedRuntimeMemorySize
= TopMemoryAddress
% 0x2000
1646 RtSize
= RtSize
+ ReservedRuntimeMemorySize
1649 # Patch FixAddress related PCDs into EFI image
1651 for EfiImage
in PatchEfiImageList
:
1652 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1653 if not os
.path
.exists(EfiImageMap
):
1656 # Get PCD offset in EFI image by GenPatchPcdTable function
1658 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1660 # Patch real PCD value by PatchPcdValue tool
1662 for PcdInfo
in PcdTable
:
1664 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1665 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
/ 0x1000))
1666 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1667 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
/ 0x1000))
1668 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1669 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
/ 0x1000))
1670 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1671 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
/ 0x1000))
1672 if ReturnValue
!= 0:
1673 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1675 MapBuffer
.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
/ 0x1000))
1676 MapBuffer
.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
/ 0x1000))
1677 MapBuffer
.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
/ 0x1000))
1678 if len (SmmModuleList
) > 0:
1679 MapBuffer
.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
/ 0x1000))
1681 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1682 BtBaseAddr
= TopMemoryAddress
- RtSize
1683 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1685 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1686 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1687 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1688 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
=False, ModeIsSmm
=True)
1689 MapBuffer
.write('\n\n')
1690 sys
.stdout
.write ("\n")
1693 ## Save platform Map file
1695 def _SaveMapFile (self
, MapBuffer
, Wa
):
1697 # Map file path is got.
1699 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1701 # Save address map into MAP file.
1703 SaveFileOnChange(MapFilePath
, MapBuffer
.getvalue(), False)
1705 if self
.LoadFixAddress
!= 0:
1706 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath
))
1709 ## Build active platform for different build targets and different tool chains
1711 def _BuildPlatform(self
):
1712 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1713 for BuildTarget
in self
.BuildTargetList
:
1714 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1716 for ToolChain
in self
.ToolChainList
:
1717 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1718 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1719 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1721 Wa
= WorkspaceAutoGen(
1738 self
.Fdf
= Wa
.FdfFile
1739 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1740 self
.BuildReport
.AddPlatformReport(Wa
)
1741 self
.Progress
.Stop("done!")
1743 # Add ffs build to makefile
1745 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1746 CmdListDict
= self
._GenFfsCmd
()
1748 for Arch
in Wa
.ArchList
:
1749 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1750 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1751 for Module
in Pa
.Platform
.Modules
:
1752 # Get ModuleAutoGen object to generate C code file and makefile
1753 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1756 self
.BuildModules
.append(Ma
)
1757 self
._BuildPa
(self
.Target
, Pa
, FfsCommand
=CmdListDict
)
1759 # Create MAP file when Load Fix Address is enabled.
1760 if self
.Target
in ["", "all", "fds"]:
1761 for Arch
in Wa
.ArchList
:
1762 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1764 # Check whether the set fix address is above 4G for 32bit image.
1766 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1767 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")
1772 for Pa
in Wa
.AutoGenObjectList
:
1773 for Ma
in Pa
.ModuleAutoGenList
:
1776 if not Ma
.IsLibrary
:
1777 ModuleList
[Ma
.Guid
.upper()] = Ma
1779 MapBuffer
= BytesIO('')
1780 if self
.LoadFixAddress
!= 0:
1782 # Rebase module to the preferred memory address before GenFds
1784 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1787 # create FDS again for the updated EFI image
1789 self
._Build
("fds", Wa
)
1791 # Create MAP file for all platform FVs after GenFds.
1793 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1795 # Save MAP buffer into MAP file.
1797 self
._SaveMapFile
(MapBuffer
, Wa
)
1799 ## Build active module for different build targets, different tool chains and different archs
1801 def _BuildModule(self
):
1802 for BuildTarget
in self
.BuildTargetList
:
1803 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1805 for ToolChain
in self
.ToolChainList
:
1806 WorkspaceAutoGenTime
= time
.time()
1807 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1808 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1809 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1812 # module build needs platform build information, so get platform
1815 Wa
= WorkspaceAutoGen(
1833 self
.Fdf
= Wa
.FdfFile
1834 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1835 Wa
.CreateMakeFile(False)
1836 # Add ffs build to makefile
1838 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1839 CmdListDict
= self
._GenFfsCmd
()
1840 self
.Progress
.Stop("done!")
1842 ExitFlag
= threading
.Event()
1844 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1845 for Arch
in Wa
.ArchList
:
1846 AutoGenStart
= time
.time()
1847 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1848 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1849 for Module
in Pa
.Platform
.Modules
:
1850 if self
.ModuleFile
.Dir
== Module
.Dir
and self
.ModuleFile
.Name
== Module
.Name
:
1851 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1852 if Ma
is None: continue
1854 if Ma
.CanSkipbyHash():
1855 self
.HashSkipModules
.append(Ma
)
1857 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1858 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1859 # for target which must generate AutoGen code and makefile
1860 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1861 self
.Progress
.Start("Generating code")
1862 Ma
.CreateCodeFile(True)
1863 self
.Progress
.Stop("done!")
1864 if self
.Target
== "genc":
1866 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1867 self
.Progress
.Start("Generating makefile")
1868 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
1869 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
1870 del CmdListDict
[Module
.File
, Arch
]
1872 Ma
.CreateMakeFile(True)
1873 self
.Progress
.Stop("done!")
1874 if self
.Target
== "genmake":
1876 self
.BuildModules
.append(Ma
)
1877 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1878 MakeStart
= time
.time()
1879 for Ma
in self
.BuildModules
:
1880 if not Ma
.IsBinaryModule
:
1881 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
1882 # Break build if any build thread has error
1883 if BuildTask
.HasError():
1884 # we need a full version of makefile for platform
1886 BuildTask
.WaitForComplete()
1887 Pa
.CreateMakeFile(False)
1888 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1889 # Start task scheduler
1890 if not BuildTask
.IsOnGoing():
1891 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1893 # in case there's an interruption. we need a full version of makefile for platform
1894 Pa
.CreateMakeFile(False)
1895 if BuildTask
.HasError():
1896 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1897 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1899 MakeContiue
= time
.time()
1901 BuildTask
.WaitForComplete()
1902 self
.CreateAsBuiltInf()
1903 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1904 if BuildTask
.HasError():
1905 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1907 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1912 "Module for [%s] is not a component of active platform."\
1913 " Please make sure that the ARCH and inf file path are"\
1914 " given in the same as in [%s]" % \
1915 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1916 ExtraData
=self
.ModuleFile
1918 # Create MAP file when Load Fix Address is enabled.
1919 if self
.Target
== "fds" and self
.Fdf
:
1920 for Arch
in Wa
.ArchList
:
1922 # Check whether the set fix address is above 4G for 32bit image.
1924 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1925 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")
1930 for Pa
in Wa
.AutoGenObjectList
:
1931 for Ma
in Pa
.ModuleAutoGenList
:
1934 if not Ma
.IsLibrary
:
1935 ModuleList
[Ma
.Guid
.upper()] = Ma
1937 MapBuffer
= BytesIO('')
1938 if self
.LoadFixAddress
!= 0:
1940 # Rebase module to the preferred memory address before GenFds
1942 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1944 # create FDS again for the updated EFI image
1946 GenFdsStart
= time
.time()
1947 self
._Build
("fds", Wa
)
1948 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
1950 # Create MAP file for all platform FVs after GenFds.
1952 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1954 # Save MAP buffer into MAP file.
1956 self
._SaveMapFile
(MapBuffer
, Wa
)
1958 def _GenFfsCmd(self
):
1959 # convert dictionary of Cmd:(Inf,Arch)
1960 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
1961 CmdSetDict
= defaultdict(set)
1962 GenFfsDict
= GenFds
.GenFfsMakefile('', GlobalData
.gFdfParser
, self
, self
.ArchList
, GlobalData
)
1963 for Cmd
in GenFfsDict
:
1964 tmpInf
, tmpArch
= GenFfsDict
[Cmd
]
1965 CmdSetDict
[tmpInf
, tmpArch
].add(Cmd
)
1968 ## Build a platform in multi-thread mode
1970 def _MultiThreadBuildPlatform(self
):
1971 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1972 for BuildTarget
in self
.BuildTargetList
:
1973 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1975 for ToolChain
in self
.ToolChainList
:
1976 WorkspaceAutoGenTime
= time
.time()
1977 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1978 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1979 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1981 Wa
= WorkspaceAutoGen(
1998 self
.Fdf
= Wa
.FdfFile
1999 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
2000 self
.BuildReport
.AddPlatformReport(Wa
)
2001 Wa
.CreateMakeFile(False)
2003 # Add ffs build to makefile
2005 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
2006 CmdListDict
= self
._GenFfsCmd
()
2008 # multi-thread exit flag
2009 ExitFlag
= threading
.Event()
2011 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
2012 for Arch
in Wa
.ArchList
:
2013 AutoGenStart
= time
.time()
2014 GlobalData
.gGlobalDefines
['ARCH'] = Arch
2015 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
2019 for Inf
in Pa
.Platform
.Modules
:
2020 ModuleList
.append(Inf
)
2021 # Add the INF only list in FDF
2022 if GlobalData
.gFdfParser
is not None:
2023 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
2024 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
2025 if Inf
in Pa
.Platform
.Modules
:
2027 ModuleList
.append(Inf
)
2028 for Module
in ModuleList
:
2029 # Get ModuleAutoGen object to generate C code file and makefile
2030 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
2034 if Ma
.CanSkipbyHash():
2035 self
.HashSkipModules
.append(Ma
)
2038 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
2039 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
2040 # for target which must generate AutoGen code and makefile
2041 if not self
.SkipAutoGen
or self
.Target
== 'genc':
2042 Ma
.CreateCodeFile(True)
2043 if self
.Target
== "genc":
2046 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
2047 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
2048 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
2049 del CmdListDict
[Module
.File
, Arch
]
2051 Ma
.CreateMakeFile(True)
2052 if self
.Target
== "genmake":
2054 self
.BuildModules
.append(Ma
)
2055 self
.Progress
.Stop("done!")
2056 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
2057 MakeStart
= time
.time()
2058 for Ma
in self
.BuildModules
:
2059 # Generate build task for the module
2060 if not Ma
.IsBinaryModule
:
2061 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
2062 # Break build if any build thread has error
2063 if BuildTask
.HasError():
2064 # we need a full version of makefile for platform
2066 BuildTask
.WaitForComplete()
2067 Pa
.CreateMakeFile(False)
2068 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2069 # Start task scheduler
2070 if not BuildTask
.IsOnGoing():
2071 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
2073 # in case there's an interruption. we need a full version of makefile for platform
2074 Pa
.CreateMakeFile(False)
2075 if BuildTask
.HasError():
2076 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2077 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
2079 MakeContiue
= time
.time()
2083 # All modules have been put in build tasks queue. Tell task scheduler
2084 # to exit if all tasks are completed
2087 BuildTask
.WaitForComplete()
2088 self
.CreateAsBuiltInf()
2089 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2091 # Check for build error, and raise exception if one
2092 # has been signaled.
2094 if BuildTask
.HasError():
2095 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2097 # Create MAP file when Load Fix Address is enabled.
2098 if self
.Target
in ["", "all", "fds"]:
2099 for Arch
in Wa
.ArchList
:
2101 # Check whether the set fix address is above 4G for 32bit image.
2103 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2104 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")
2109 for Pa
in Wa
.AutoGenObjectList
:
2110 for Ma
in Pa
.ModuleAutoGenList
:
2113 if not Ma
.IsLibrary
:
2114 ModuleList
[Ma
.Guid
.upper()] = Ma
2116 # Rebase module to the preferred memory address before GenFds
2118 MapBuffer
= BytesIO('')
2119 if self
.LoadFixAddress
!= 0:
2120 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2124 # Generate FD image if there's a FDF file found
2126 GenFdsStart
= time
.time()
2127 if GenFdsApi(Wa
.GenFdsCommandDict
, self
.Db
):
2128 EdkLogger
.error("build", COMMAND_FAILURE
)
2131 # Create MAP file for all platform FVs after GenFds.
2133 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2134 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2136 # Save MAP buffer into MAP file.
2138 self
._SaveMapFile
(MapBuffer
, Wa
)
2140 ## Generate GuidedSectionTools.txt in the FV directories.
2142 def CreateGuidedSectionToolsFile(self
):
2143 for BuildTarget
in self
.BuildTargetList
:
2144 for ToolChain
in self
.ToolChainList
:
2145 Wa
= WorkspaceAutoGen(
2162 if not os
.path
.exists(FvDir
):
2165 for Arch
in self
.ArchList
:
2166 # Build up the list of supported architectures for this build
2167 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
2169 # Look through the tool definitions for GUIDed tools
2171 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.iteritems():
2172 if attrib
.upper().endswith('_GUID'):
2173 split
= attrib
.split('_')
2174 thisPrefix
= '_'.join(split
[0:3]) + '_'
2175 if thisPrefix
== prefix
:
2176 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
2179 path
= '_'.join(split
[0:4]) + '_PATH'
2180 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2181 path
= self
.GetFullPathOfTool(path
)
2182 guidAttribs
.append((guid
, toolName
, path
))
2184 # Write out GuidedSecTools.txt
2185 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2186 toolsFile
= open(toolsFile
, 'wt')
2187 for guidedSectionTool
in guidAttribs
:
2188 print(' '.join(guidedSectionTool
), file=toolsFile
)
2191 ## Returns the full path of the tool.
2193 def GetFullPathOfTool (self
, tool
):
2194 if os
.path
.exists(tool
):
2195 return os
.path
.realpath(tool
)
2197 # We need to search for the tool using the
2198 # PATH environment variable.
2199 for dirInPath
in os
.environ
['PATH'].split(os
.pathsep
):
2200 foundPath
= os
.path
.join(dirInPath
, tool
)
2201 if os
.path
.exists(foundPath
):
2202 return os
.path
.realpath(foundPath
)
2204 # If the tool was not found in the path then we just return
2208 ## Launch the module or platform build
2211 if not self
.ModuleFile
:
2212 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2213 self
.SpawnMode
= False
2214 self
._BuildPlatform
()
2216 self
._MultiThreadBuildPlatform
()
2217 self
.CreateGuidedSectionToolsFile()
2219 self
.SpawnMode
= False
2222 if self
.Target
== 'cleanall':
2223 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2225 def CreateAsBuiltInf(self
):
2226 for Module
in self
.BuildModules
:
2227 Module
.CreateAsBuiltInf()
2228 for Module
in self
.HashSkipModules
:
2229 Module
.CreateAsBuiltInf(True)
2230 self
.BuildModules
= []
2231 self
.HashSkipModules
= []
2232 ## Do some clean-up works when error occurred
2233 def Relinquish(self
):
2234 OldLogLevel
= EdkLogger
.GetLevel()
2235 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2236 #self.DumpBuildData()
2237 Utils
.Progressor
.Abort()
2238 if self
.SpawnMode
== True:
2240 EdkLogger
.SetLevel(OldLogLevel
)
2242 def DumpBuildData(self
):
2243 CacheDirectory
= os
.path
.dirname(GlobalData
.gDatabasePath
)
2244 Utils
.CreateDirectory(CacheDirectory
)
2245 Utils
.DataDump(Utils
.gFileTimeStampCache
, os
.path
.join(CacheDirectory
, "gFileTimeStampCache"))
2246 Utils
.DataDump(Utils
.gDependencyDatabase
, os
.path
.join(CacheDirectory
, "gDependencyDatabase"))
2248 def RestoreBuildData(self
):
2249 FilePath
= os
.path
.join(os
.path
.dirname(GlobalData
.gDatabasePath
), "gFileTimeStampCache")
2250 if Utils
.gFileTimeStampCache
== {} and os
.path
.isfile(FilePath
):
2251 Utils
.gFileTimeStampCache
= Utils
.DataRestore(FilePath
)
2252 if Utils
.gFileTimeStampCache
is None:
2253 Utils
.gFileTimeStampCache
= {}
2255 FilePath
= os
.path
.join(os
.path
.dirname(GlobalData
.gDatabasePath
), "gDependencyDatabase")
2256 if Utils
.gDependencyDatabase
== {} and os
.path
.isfile(FilePath
):
2257 Utils
.gDependencyDatabase
= Utils
.DataRestore(FilePath
)
2258 if Utils
.gDependencyDatabase
is None:
2259 Utils
.gDependencyDatabase
= {}
2261 def ParseDefines(DefineList
=[]):
2263 if DefineList
is not None:
2264 for Define
in DefineList
:
2265 DefineTokenList
= Define
.split("=", 1)
2266 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2267 EdkLogger
.error('build', FORMAT_INVALID
,
2268 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2269 ExtraData
=DefineTokenList
[0])
2271 if len(DefineTokenList
) == 1:
2272 DefineDict
[DefineTokenList
[0]] = "TRUE"
2274 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2278 def SingleCheckCallback(option
, opt_str
, value
, parser
):
2279 if option
not in gParamCheck
:
2280 setattr(parser
.values
, option
.dest
, value
)
2281 gParamCheck
.append(option
)
2283 parser
.error("Option %s only allows one instance in command line!" % option
)
2285 def LogBuildTime(Time
):
2288 TimeDur
= time
.gmtime(Time
)
2289 if TimeDur
.tm_yday
> 1:
2290 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2292 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2297 ## Parse command line options
2299 # Using standard Python module optparse to parse command line option of this tool.
2301 # @retval Opt A optparse.Values object containing the parsed options
2302 # @retval Args Target of build command
2304 def MyOptionParser():
2305 Parser
= OptionParser(description
=__copyright__
, version
=__version__
, prog
="build.exe", usage
="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
2306 Parser
.add_option("-a", "--arch", action
="append", type="choice", choices
=['IA32', 'X64', 'IPF', 'EBC', 'ARM', 'AARCH64'], dest
="TargetArch",
2307 help="ARCHS is one of list: IA32, X64, IPF, ARM, AARCH64 or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.")
2308 Parser
.add_option("-p", "--platform", action
="callback", type="string", dest
="PlatformFile", callback
=SingleCheckCallback
,
2309 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
2310 Parser
.add_option("-m", "--module", action
="callback", type="string", dest
="ModuleFile", callback
=SingleCheckCallback
,
2311 help="Build the module specified by the INF file name argument.")
2312 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
2314 Parser
.add_option("-t", "--tagname", action
="append", type="string", dest
="ToolChain",
2315 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
2316 Parser
.add_option("-x", "--sku-id", action
="callback", type="string", dest
="SkuId", callback
=SingleCheckCallback
,
2317 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
2319 Parser
.add_option("-n", action
="callback", type="int", dest
="ThreadNumber", callback
=SingleCheckCallback
,
2320 help="Build the platform using multi-threaded compiler. The value overrides target.txt's MAX_CONCURRENT_THREAD_NUMBER. When value is set to 0, tool automatically detect number of "\
2321 "processor threads, set value to 1 means disable multi-thread build, and set value to more than 1 means user specify the threads number to build.")
2323 Parser
.add_option("-f", "--fdf", action
="callback", type="string", dest
="FdfFile", callback
=SingleCheckCallback
,
2324 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
2325 Parser
.add_option("-r", "--rom-image", action
="append", type="string", dest
="RomImage", default
=[],
2326 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
2327 Parser
.add_option("-i", "--fv-image", action
="append", type="string", dest
="FvImage", default
=[],
2328 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
2329 Parser
.add_option("-C", "--capsule-image", action
="append", type="string", dest
="CapName", default
=[],
2330 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
2331 Parser
.add_option("-u", "--skip-autogen", action
="store_true", dest
="SkipAutoGen", help="Skip AutoGen step.")
2332 Parser
.add_option("-e", "--re-parse", action
="store_true", dest
="Reparse", help="Re-parse all meta-data files.")
2334 Parser
.add_option("-c", "--case-insensitive", action
="store_true", dest
="CaseInsensitive", default
=False, help="Don't check case of file name.")
2336 Parser
.add_option("-w", "--warning-as-error", action
="store_true", dest
="WarningAsError", help="Treat warning in tools as error.")
2337 Parser
.add_option("-j", "--log", action
="store", dest
="LogFile", help="Put log in specified file as well as on console.")
2339 Parser
.add_option("-s", "--silent", action
="store_true", type=None, dest
="SilentMode",
2340 help="Make use of silent mode of (n)make.")
2341 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
2342 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
2343 "including library instances selected, final dependency expression, "\
2344 "and warning messages, etc.")
2345 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
2346 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
2348 Parser
.add_option("-y", "--report-file", action
="store", dest
="ReportFile", help="Create/overwrite the report to the specified filename.")
2349 Parser
.add_option("-Y", "--report-type", action
="append", type="choice", choices
=['PCD', 'LIBRARY', 'FLASH', 'DEPEX', 'BUILD_FLAGS', 'FIXED_ADDRESS', 'HASH', 'EXECUTION_ORDER'], dest
="ReportType", default
=[],
2350 help="Flags that control the type of build report to generate. Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, HASH, EXECUTION_ORDER]. "\
2351 "To specify more than one flag, repeat this option on the command line and the default flag set is [PCD, LIBRARY, FLASH, DEPEX, HASH, BUILD_FLAGS, FIXED_ADDRESS]")
2352 Parser
.add_option("-F", "--flag", action
="store", type="string", dest
="Flag",
2353 help="Specify the specific option to parse EDK UNI file. Must be one of: [-c, -s]. -c is for EDK framework UNI file, and -s is for EDK UEFI UNI file. "\
2354 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
2355 "will override the setting in [BuildOptions] section of platform DSC.")
2356 Parser
.add_option("-N", "--no-cache", action
="store_true", dest
="DisableCache", default
=False, help="Disable build cache mechanism")
2357 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
2358 Parser
.add_option("--check-usage", action
="store_true", dest
="CheckUsage", default
=False, help="Check usage content of entries listed in INF file.")
2359 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
2360 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
2361 Parser
.add_option("-l", "--cmd-len", action
="store", type="int", dest
="CommandLength", help="Specify the maximum line length of build command. Default is 4096.")
2362 Parser
.add_option("--hash", action
="store_true", dest
="UseHashCache", default
=False, help="Enable hash-based caching during build process.")
2363 Parser
.add_option("--binary-destination", action
="store", type="string", dest
="BinCacheDest", help="Generate a cache of binary files in the specified directory.")
2364 Parser
.add_option("--binary-source", action
="store", type="string", dest
="BinCacheSource", help="Consume a cache of binary files from the specified directory.")
2365 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
2366 (Opt
, Args
) = Parser
.parse_args()
2369 ## Tool entrance method
2371 # This method mainly dispatch specific methods per the command line options.
2372 # If no error found, return zero value so the caller of this tool can know
2373 # if it's executed successfully or not.
2375 # @retval 0 Tool was successful
2376 # @retval 1 Tool failed
2379 StartTime
= time
.time()
2381 # Initialize log system
2382 EdkLogger
.Initialize()
2383 GlobalData
.gCommand
= sys
.argv
[1:]
2385 # Parse the options and args
2387 (Option
, Target
) = MyOptionParser()
2388 GlobalData
.gOptions
= Option
2389 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2392 if Option
.verbose
is not None:
2393 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2394 elif Option
.quiet
is not None:
2395 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2396 elif Option
.debug
is not None:
2397 EdkLogger
.SetLevel(Option
.debug
+ 1)
2399 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2401 if Option
.LogFile
is not None:
2402 EdkLogger
.SetLogFile(Option
.LogFile
)
2404 if Option
.WarningAsError
== True:
2405 EdkLogger
.SetWarningAsError()
2407 if platform
.platform().find("Windows") >= 0:
2408 GlobalData
.gIsWindows
= True
2410 GlobalData
.gIsWindows
= False
2412 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2413 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2418 if len(Target
) == 0:
2420 elif len(Target
) >= 2:
2421 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2422 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2424 Target
= Target
[0].lower()
2426 if Target
not in gSupportedTarget
:
2427 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2428 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2431 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2434 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2436 Workspace
= os
.getenv("WORKSPACE")
2438 # Get files real name in workspace dir
2440 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2442 WorkingDirectory
= os
.getcwd()
2443 if not Option
.ModuleFile
:
2444 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2445 FileNum
= len(FileList
)
2447 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2448 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2450 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2452 if Option
.ModuleFile
:
2453 if os
.path
.isabs (Option
.ModuleFile
):
2454 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2455 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2456 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2457 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2459 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2461 if Option
.PlatformFile
is not None:
2462 if os
.path
.isabs (Option
.PlatformFile
):
2463 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2464 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2465 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2467 if Option
.FdfFile
is not None:
2468 if os
.path
.isabs (Option
.FdfFile
):
2469 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2470 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2471 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2472 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2474 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2476 if Option
.Flag
is not None and Option
.Flag
not in ['-c', '-s']:
2477 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2479 MyBuild
= Build(Target
, Workspace
, Option
)
2480 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2481 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2484 #MyBuild.DumpBuildData()
2486 # All job done, no error found and no exception raised
2489 except FatalError
as X
:
2490 if MyBuild
is not None:
2491 # for multi-thread build exits safely
2492 MyBuild
.Relinquish()
2493 if Option
is not None and Option
.debug
is not None:
2494 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2495 ReturnCode
= X
.args
[0]
2496 except Warning as X
:
2497 # error from Fdf parser
2498 if MyBuild
is not None:
2499 # for multi-thread build exits safely
2500 MyBuild
.Relinquish()
2501 if Option
is not None and Option
.debug
is not None:
2502 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2504 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2505 ReturnCode
= FORMAT_INVALID
2506 except KeyboardInterrupt:
2507 ReturnCode
= ABORT_ERROR
2508 if Option
is not None and Option
.debug
is not None:
2509 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2511 if MyBuild
is not None:
2512 # for multi-thread build exits safely
2513 MyBuild
.Relinquish()
2515 # try to get the meta-file from the object causing exception
2516 Tb
= sys
.exc_info()[-1]
2517 MetaFile
= GlobalData
.gProcessingFile
2518 while Tb
is not None:
2519 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2520 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2525 "Unknown fatal error when processing [%s]" % MetaFile
,
2526 ExtraData
="\n(Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!)\n",
2529 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2530 ReturnCode
= CODE_ERROR
2532 Utils
.Progressor
.Abort()
2533 Utils
.ClearDuplicatedInf()
2537 MyBuild
.LaunchPostbuild()
2540 Conclusion
= "Failed"
2541 elif ReturnCode
== ABORT_ERROR
:
2542 Conclusion
= "Aborted"
2544 Conclusion
= "Failed"
2545 FinishTime
= time
.time()
2546 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2547 BuildDurationStr
= ""
2548 if BuildDuration
.tm_yday
> 1:
2549 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2551 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2552 if MyBuild
is not None:
2554 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2556 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2557 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2558 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2559 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2562 if __name__
== '__main__':
2564 ## 0-127 is a safe return range, and 1 is a standard default error
2565 if r
< 0 or r
> 127: r
= 1