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 TargetTxtClassObject
41 from Common
.ToolDefClassObject
import ToolDefClassObject
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
[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
[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
[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
[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
[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
[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