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>
7 # This program and the accompanying materials
8 # are licensed and made available under the terms and conditions of the BSD License
9 # which accompanies this distribution. The full text of the license may be found at
10 # http://opensource.org/licenses/bsd-license.php
12 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 import Common
.LongFilePathOs
as os
21 from io
import BytesIO
27 import encodings
.ascii
29 import multiprocessing
32 from threading
import *
33 from optparse
import OptionParser
34 from subprocess
import *
35 from Common
import Misc
as Utils
37 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
38 from Common
.LongFilePathSupport
import LongFilePath
39 from Common
.TargetTxtClassObject
import *
40 from Common
.ToolDefClassObject
import *
41 from Common
.DataType
import *
42 from Common
.BuildVersion
import gBUILD_VERSION
43 from AutoGen
.AutoGen
import *
44 from Common
.BuildToolError
import *
45 from Workspace
.WorkspaceDatabase
import *
46 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
48 from BuildReport
import BuildReport
49 from GenPatchPcdTable
.GenPatchPcdTable
import *
50 from PatchPcdValue
.PatchPcdValue
import *
52 import Common
.EdkLogger
53 import Common
.GlobalData
as GlobalData
54 from GenFds
.GenFds
import GenFds
56 from collections
import OrderedDict
, defaultdict
58 # Version and Copyright
59 VersionNumber
= "0.60" + ' ' + gBUILD_VERSION
60 __version__
= "%prog Version " + VersionNumber
61 __copyright__
= "Copyright (c) 2007 - 2018, Intel Corporation All rights reserved."
63 ## standard targets of build command
64 gSupportedTarget
= ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
66 ## build configuration file
67 gBuildConfiguration
= "target.txt"
68 gToolsDefinition
= "tools_def.txt"
70 TemporaryTablePattern
= re
.compile(r
'^_\d+_\d+_[a-fA-F0-9]+$')
73 ## Check environment PATH variable to make sure the specified tool is found
75 # If the tool is found in the PATH, then True is returned
76 # Otherwise, False is returned
78 def IsToolInPath(tool
):
79 if 'PATHEXT' in os
.environ
:
80 extns
= os
.environ
['PATHEXT'].split(os
.path
.pathsep
)
83 for pathDir
in os
.environ
['PATH'].split(os
.path
.pathsep
):
85 if os
.path
.exists(os
.path
.join(pathDir
, tool
+ ext
)):
89 ## Check environment variables
91 # Check environment variables that must be set for build. Currently they are
93 # WORKSPACE The directory all packages/platforms start from
94 # EDK_TOOLS_PATH The directory contains all tools needed by the build
95 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
97 # If any of above environment variable is not set or has error, the build
100 def CheckEnvVariable():
102 if "WORKSPACE" not in os
.environ
:
103 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
104 ExtraData
="WORKSPACE")
106 WorkspaceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["WORKSPACE"]))
107 if not os
.path
.exists(WorkspaceDir
):
108 EdkLogger
.error("build", FILE_NOT_FOUND
, "WORKSPACE doesn't exist", ExtraData
=WorkspaceDir
)
109 elif ' ' in WorkspaceDir
:
110 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in WORKSPACE path",
111 ExtraData
=WorkspaceDir
)
112 os
.environ
["WORKSPACE"] = WorkspaceDir
114 # set multiple workspace
115 PackagesPath
= os
.getenv("PACKAGES_PATH")
116 mws
.setWs(WorkspaceDir
, PackagesPath
)
117 if mws
.PACKAGES_PATH
:
118 for Path
in mws
.PACKAGES_PATH
:
119 if not os
.path
.exists(Path
):
120 EdkLogger
.error("build", FILE_NOT_FOUND
, "One Path in PACKAGES_PATH doesn't exist", ExtraData
=Path
)
122 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in PACKAGES_PATH", ExtraData
=Path
)
125 # Check EFI_SOURCE (Edk build convention). EDK_SOURCE will always point to ECP
127 if "ECP_SOURCE" not in os
.environ
:
128 os
.environ
["ECP_SOURCE"] = mws
.join(WorkspaceDir
, GlobalData
.gEdkCompatibilityPkg
)
129 if "EFI_SOURCE" not in os
.environ
:
130 os
.environ
["EFI_SOURCE"] = os
.environ
["ECP_SOURCE"]
131 if "EDK_SOURCE" not in os
.environ
:
132 os
.environ
["EDK_SOURCE"] = os
.environ
["ECP_SOURCE"]
135 # Unify case of characters on case-insensitive systems
137 EfiSourceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["EFI_SOURCE"]))
138 EdkSourceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_SOURCE"]))
139 EcpSourceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["ECP_SOURCE"]))
141 os
.environ
["EFI_SOURCE"] = EfiSourceDir
142 os
.environ
["EDK_SOURCE"] = EdkSourceDir
143 os
.environ
["ECP_SOURCE"] = EcpSourceDir
144 os
.environ
["EDK_TOOLS_PATH"] = os
.path
.normcase(os
.environ
["EDK_TOOLS_PATH"])
146 if not os
.path
.exists(EcpSourceDir
):
147 EdkLogger
.verbose("ECP_SOURCE = %s doesn't exist. Edk modules could not be built." % EcpSourceDir
)
148 elif ' ' in EcpSourceDir
:
149 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in ECP_SOURCE path",
150 ExtraData
=EcpSourceDir
)
151 if not os
.path
.exists(EdkSourceDir
):
152 if EdkSourceDir
== EcpSourceDir
:
153 EdkLogger
.verbose("EDK_SOURCE = %s doesn't exist. Edk modules could not be built." % EdkSourceDir
)
155 EdkLogger
.error("build", PARAMETER_INVALID
, "EDK_SOURCE does not exist",
156 ExtraData
=EdkSourceDir
)
157 elif ' ' in EdkSourceDir
:
158 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in EDK_SOURCE path",
159 ExtraData
=EdkSourceDir
)
160 if not os
.path
.exists(EfiSourceDir
):
161 if EfiSourceDir
== EcpSourceDir
:
162 EdkLogger
.verbose("EFI_SOURCE = %s doesn't exist. Edk modules could not be built." % EfiSourceDir
)
164 EdkLogger
.error("build", PARAMETER_INVALID
, "EFI_SOURCE does not exist",
165 ExtraData
=EfiSourceDir
)
166 elif ' ' in EfiSourceDir
:
167 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in EFI_SOURCE path",
168 ExtraData
=EfiSourceDir
)
170 # check those variables on single workspace case
172 # change absolute path to relative path to WORKSPACE
173 if EfiSourceDir
.upper().find(WorkspaceDir
.upper()) != 0:
174 EdkLogger
.error("build", PARAMETER_INVALID
, "EFI_SOURCE is not under WORKSPACE",
175 ExtraData
="WORKSPACE = %s\n EFI_SOURCE = %s" % (WorkspaceDir
, EfiSourceDir
))
176 if EdkSourceDir
.upper().find(WorkspaceDir
.upper()) != 0:
177 EdkLogger
.error("build", PARAMETER_INVALID
, "EDK_SOURCE is not under WORKSPACE",
178 ExtraData
="WORKSPACE = %s\n EDK_SOURCE = %s" % (WorkspaceDir
, EdkSourceDir
))
179 if EcpSourceDir
.upper().find(WorkspaceDir
.upper()) != 0:
180 EdkLogger
.error("build", PARAMETER_INVALID
, "ECP_SOURCE is not under WORKSPACE",
181 ExtraData
="WORKSPACE = %s\n ECP_SOURCE = %s" % (WorkspaceDir
, EcpSourceDir
))
183 # check EDK_TOOLS_PATH
184 if "EDK_TOOLS_PATH" not in os
.environ
:
185 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
186 ExtraData
="EDK_TOOLS_PATH")
189 if "PATH" not in os
.environ
:
190 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
193 GlobalData
.gWorkspace
= WorkspaceDir
194 GlobalData
.gEfiSource
= EfiSourceDir
195 GlobalData
.gEdkSource
= EdkSourceDir
196 GlobalData
.gEcpSource
= EcpSourceDir
198 GlobalData
.gGlobalDefines
["WORKSPACE"] = WorkspaceDir
199 GlobalData
.gGlobalDefines
["EFI_SOURCE"] = EfiSourceDir
200 GlobalData
.gGlobalDefines
["EDK_SOURCE"] = EdkSourceDir
201 GlobalData
.gGlobalDefines
["ECP_SOURCE"] = EcpSourceDir
202 GlobalData
.gGlobalDefines
["EDK_TOOLS_PATH"] = os
.environ
["EDK_TOOLS_PATH"]
204 ## Get normalized file path
206 # Convert the path to be local format, and remove the WORKSPACE path at the
207 # beginning if the file path is given in full path.
209 # @param FilePath File path to be normalized
210 # @param Workspace Workspace path which the FilePath will be checked against
212 # @retval string The normalized file path
214 def NormFile(FilePath
, Workspace
):
215 # check if the path is absolute or relative
216 if os
.path
.isabs(FilePath
):
217 FileFullPath
= os
.path
.normpath(FilePath
)
219 FileFullPath
= os
.path
.normpath(mws
.join(Workspace
, FilePath
))
220 Workspace
= mws
.getWs(Workspace
, FilePath
)
222 # check if the file path exists or not
223 if not os
.path
.isfile(FileFullPath
):
224 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath
)
226 # remove workspace directory from the beginning part of the file path
227 if Workspace
[-1] in ["\\", "/"]:
228 return FileFullPath
[len(Workspace
):]
230 return FileFullPath
[(len(Workspace
) + 1):]
232 ## Get the output of an external program
234 # This is the entrance method of thread reading output of an external program and
235 # putting them in STDOUT/STDERR of current program.
237 # @param From The stream message read from
238 # @param To The stream message put on
239 # @param ExitFlag The flag used to indicate stopping reading
241 def ReadMessage(From
, To
, ExitFlag
):
243 # read one line a time
244 Line
= From
.readline()
245 # empty string means "end"
246 if Line
is not None and Line
!= "":
253 ## Launch an external program
255 # This method will call subprocess.Popen to execute an external program with
256 # given options in specified directory. Because of the dead-lock issue during
257 # redirecting output of the external program, threads are used to to do the
260 # @param Command A list or string containing the call of the program
261 # @param WorkingDir The directory in which the program will be running
263 def LaunchCommand(Command
, WorkingDir
):
264 BeginTime
= time
.time()
265 # if working directory doesn't exist, Popen() will raise an exception
266 if not os
.path
.isdir(WorkingDir
):
267 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=WorkingDir
)
269 # Command is used as the first Argument in following Popen().
270 # It could be a string or sequence. We find that if command is a string in following Popen(),
271 # ubuntu may fail with an error message that the command is not found.
272 # So here we may need convert command from string to list instance.
273 if platform
.system() != 'Windows':
274 if not isinstance(Command
, list):
275 Command
= Command
.split()
276 Command
= ' '.join(Command
)
279 EndOfProcedure
= None
282 Proc
= Popen(Command
, stdout
=PIPE
, stderr
=PIPE
, env
=os
.environ
, cwd
=WorkingDir
, bufsize
=-1, shell
=True)
284 # launch two threads to read the STDOUT and STDERR
285 EndOfProcedure
= Event()
286 EndOfProcedure
.clear()
288 StdOutThread
= Thread(target
=ReadMessage
, args
=(Proc
.stdout
, EdkLogger
.info
, EndOfProcedure
))
289 StdOutThread
.setName("STDOUT-Redirector")
290 StdOutThread
.setDaemon(False)
294 StdErrThread
= Thread(target
=ReadMessage
, args
=(Proc
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
295 StdErrThread
.setName("STDERR-Redirector")
296 StdErrThread
.setDaemon(False)
299 # waiting for program exit
301 except: # in case of aborting
302 # terminate the threads redirecting the program output
303 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
304 if EndOfProcedure
is not None:
307 if not isinstance(Command
, type("")):
308 Command
= " ".join(Command
)
309 EdkLogger
.error("build", COMMAND_FAILURE
, "Failed to start command", ExtraData
="%s [%s]" % (Command
, WorkingDir
))
316 # check the return code of the program
317 if Proc
.returncode
!= 0:
318 if not isinstance(Command
, type("")):
319 Command
= " ".join(Command
)
320 # print out the Response file and its content when make failure
321 RespFile
= os
.path
.join(WorkingDir
, 'OUTPUT', 'respfilelist.txt')
322 if os
.path
.isfile(RespFile
):
324 RespContent
= f
.read()
326 EdkLogger
.info(RespContent
)
328 EdkLogger
.error("build", COMMAND_FAILURE
, ExtraData
="%s [%s]" % (Command
, WorkingDir
))
329 return "%dms" % (int(round((time
.time() - BeginTime
) * 1000)))
331 ## The smallest unit that can be built in multi-thread build mode
333 # This is the base class of build unit. The "Obj" parameter must provide
334 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
337 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
342 # @param self The object pointer
343 # @param Obj The object the build is working on
344 # @param Target The build target name, one of gSupportedTarget
345 # @param Dependency The BuildUnit(s) which must be completed in advance
346 # @param WorkingDir The directory build command starts in
348 def __init__(self
, Obj
, BuildCommand
, Target
, Dependency
, WorkingDir
="."):
349 self
.BuildObject
= Obj
350 self
.Dependency
= Dependency
351 self
.WorkingDir
= WorkingDir
353 self
.BuildCommand
= BuildCommand
355 EdkLogger
.error("build", OPTION_MISSING
,
356 "No build command found for this module. "
357 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
358 (Obj
.BuildTarget
, Obj
.ToolChain
, Obj
.Arch
),
364 # It just returns the string representation of self.BuildObject
366 # @param self The object pointer
369 return str(self
.BuildObject
)
371 ## "==" operator method
373 # It just compares self.BuildObject with "Other". So self.BuildObject must
374 # provide its own __eq__() method.
376 # @param self The object pointer
377 # @param Other The other BuildUnit object compared to
379 def __eq__(self
, Other
):
380 return Other
and self
.BuildObject
== Other
.BuildObject \
381 and Other
.BuildObject \
382 and self
.BuildObject
.Arch
== Other
.BuildObject
.Arch
386 # It just returns the hash value of self.BuildObject which must be hashable.
388 # @param self The object pointer
391 return hash(self
.BuildObject
) + hash(self
.BuildObject
.Arch
)
394 return repr(self
.BuildObject
)
396 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
398 # This class is for module build by nmake/make build system. The "Obj" parameter
399 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
400 # be make units missing build.
402 # Currently the "Obj" should be only ModuleAutoGen object.
404 class ModuleMakeUnit(BuildUnit
):
407 # @param self The object pointer
408 # @param Obj The ModuleAutoGen object the build is working on
409 # @param Target The build target name, one of gSupportedTarget
411 def __init__(self
, Obj
, Target
):
412 Dependency
= [ModuleMakeUnit(La
, Target
) for La
in Obj
.LibraryAutoGenList
]
413 BuildUnit
.__init
__(self
, Obj
, Obj
.BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
414 if Target
in [None, "", "all"]:
415 self
.Target
= "tbuild"
417 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
419 # This class is for platform build by nmake/make build system. The "Obj" parameter
420 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
421 # be make units missing build.
423 # Currently the "Obj" should be only PlatformAutoGen object.
425 class PlatformMakeUnit(BuildUnit
):
428 # @param self The object pointer
429 # @param Obj The PlatformAutoGen object the build is working on
430 # @param Target The build target name, one of gSupportedTarget
432 def __init__(self
, Obj
, Target
):
433 Dependency
= [ModuleMakeUnit(Lib
, Target
) for Lib
in self
.BuildObject
.LibraryAutoGenList
]
434 Dependency
.extend([ModuleMakeUnit(Mod
, Target
) for Mod
in self
.BuildObject
.ModuleAutoGenList
])
435 BuildUnit
.__init
__(self
, Obj
, Obj
.BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
437 ## The class representing the task of a module build or platform build
439 # This class manages the build tasks in multi-thread build mode. Its jobs include
440 # scheduling thread running, catching thread error, monitor the thread status, etc.
443 # queue for tasks waiting for schedule
444 _PendingQueue
= OrderedDict()
445 _PendingQueueLock
= threading
.Lock()
447 # queue for tasks ready for running
448 _ReadyQueue
= OrderedDict()
449 _ReadyQueueLock
= threading
.Lock()
451 # queue for run tasks
452 _RunningQueue
= OrderedDict()
453 _RunningQueueLock
= threading
.Lock()
455 # queue containing all build tasks, in case duplicate build
456 _TaskQueue
= OrderedDict()
458 # flag indicating error occurs in a running thread
459 _ErrorFlag
= threading
.Event()
463 # BoundedSemaphore object used to control the number of running threads
466 # flag indicating if the scheduler is started or not
467 _SchedulerStopped
= threading
.Event()
468 _SchedulerStopped
.set()
470 ## Start the task scheduler thread
472 # @param MaxThreadNumber The maximum thread number
473 # @param ExitFlag Flag used to end the scheduler
476 def StartScheduler(MaxThreadNumber
, ExitFlag
):
477 SchedulerThread
= Thread(target
=BuildTask
.Scheduler
, args
=(MaxThreadNumber
, ExitFlag
))
478 SchedulerThread
.setName("Build-Task-Scheduler")
479 SchedulerThread
.setDaemon(False)
480 SchedulerThread
.start()
481 # wait for the scheduler to be started, especially useful in Linux
482 while not BuildTask
.IsOnGoing():
487 # @param MaxThreadNumber The maximum thread number
488 # @param ExitFlag Flag used to end the scheduler
491 def Scheduler(MaxThreadNumber
, ExitFlag
):
492 BuildTask
._SchedulerStopped
.clear()
494 # use BoundedSemaphore to control the maximum running threads
495 BuildTask
._Thread
= BoundedSemaphore(MaxThreadNumber
)
497 # scheduling loop, which will exits when no pending/ready task and
498 # indicated to do so, or there's error in running thread
500 while (len(BuildTask
._PendingQueue
) > 0 or len(BuildTask
._ReadyQueue
) > 0 \
501 or not ExitFlag
.isSet()) and not BuildTask
._ErrorFlag
.isSet():
502 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Pending Queue (%d), Ready Queue (%d)"
503 % (len(BuildTask
._PendingQueue
), len(BuildTask
._ReadyQueue
)))
505 # get all pending tasks
506 BuildTask
._PendingQueueLock
.acquire()
507 BuildObjectList
= BuildTask
._PendingQueue
.keys()
509 # check if their dependency is resolved, and if true, move them
512 for BuildObject
in BuildObjectList
:
513 Bt
= BuildTask
._PendingQueue
[BuildObject
]
515 BuildTask
._ReadyQueue
[BuildObject
] = BuildTask
._PendingQueue
.pop(BuildObject
)
516 BuildTask
._PendingQueueLock
.release()
518 # launch build thread until the maximum number of threads is reached
519 while not BuildTask
._ErrorFlag
.isSet():
520 # empty ready queue, do nothing further
521 if len(BuildTask
._ReadyQueue
) == 0:
524 # wait for active thread(s) exit
525 BuildTask
._Thread
.acquire(True)
527 # start a new build thread
528 Bo
, Bt
= BuildTask
._ReadyQueue
.popitem()
530 # move into running queue
531 BuildTask
._RunningQueueLock
.acquire()
532 BuildTask
._RunningQueue
[Bo
] = Bt
533 BuildTask
._RunningQueueLock
.release()
542 # wait for all running threads exit
543 if BuildTask
._ErrorFlag
.isSet():
544 EdkLogger
.quiet("\nWaiting for all build threads exit...")
545 # while not BuildTask._ErrorFlag.isSet() and \
546 while len(BuildTask
._RunningQueue
) > 0:
547 EdkLogger
.verbose("Waiting for thread ending...(%d)" % len(BuildTask
._RunningQueue
))
548 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Threads [%s]" % ", ".join(Th
.getName() for Th
in threading
.enumerate()))
551 except BaseException
as X
:
553 # TRICK: hide the output of threads left runing, so that the user can
554 # catch the error message easily
556 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
557 BuildTask
._ErrorFlag
.set()
558 BuildTask
._ErrorMessage
= "build thread scheduler error\n\t%s" % str(X
)
560 BuildTask
._PendingQueue
.clear()
561 BuildTask
._ReadyQueue
.clear()
562 BuildTask
._RunningQueue
.clear()
563 BuildTask
._TaskQueue
.clear()
564 BuildTask
._SchedulerStopped
.set()
566 ## Wait for all running method exit
569 def WaitForComplete():
570 BuildTask
._SchedulerStopped
.wait()
572 ## Check if the scheduler is running or not
576 return not BuildTask
._SchedulerStopped
.isSet()
581 if BuildTask
.IsOnGoing():
582 BuildTask
._ErrorFlag
.set()
583 BuildTask
.WaitForComplete()
585 ## Check if there's error in running thread
587 # Since the main thread cannot catch exceptions in other thread, we have to
588 # use threading.Event to communicate this formation to main thread.
592 return BuildTask
._ErrorFlag
.isSet()
594 ## Get error message in running thread
596 # Since the main thread cannot catch exceptions in other thread, we have to
597 # use a static variable to communicate this message to main thread.
600 def GetErrorMessage():
601 return BuildTask
._ErrorMessage
603 ## Factory method to create a BuildTask object
605 # This method will check if a module is building or has been built. And if
606 # true, just return the associated BuildTask object in the _TaskQueue. If
607 # not, create and return a new BuildTask object. The new BuildTask object
608 # will be appended to the _PendingQueue for scheduling later.
610 # @param BuildItem A BuildUnit object representing a build object
611 # @param Dependency The dependent build object of BuildItem
614 def New(BuildItem
, Dependency
=None):
615 if BuildItem
in BuildTask
._TaskQueue
:
616 Bt
= BuildTask
._TaskQueue
[BuildItem
]
620 Bt
._Init
(BuildItem
, Dependency
)
621 BuildTask
._TaskQueue
[BuildItem
] = Bt
623 BuildTask
._PendingQueueLock
.acquire()
624 BuildTask
._PendingQueue
[BuildItem
] = Bt
625 BuildTask
._PendingQueueLock
.release()
629 ## The real constructor of BuildTask
631 # @param BuildItem A BuildUnit object representing a build object
632 # @param Dependency The dependent build object of BuildItem
634 def _Init(self
, BuildItem
, Dependency
=None):
635 self
.BuildItem
= BuildItem
637 self
.DependencyList
= []
638 if Dependency
is None:
639 Dependency
= BuildItem
.Dependency
641 Dependency
.extend(BuildItem
.Dependency
)
642 self
.AddDependency(Dependency
)
643 # flag indicating build completes, used to avoid unnecessary re-build
644 self
.CompleteFlag
= False
646 ## Check if all dependent build tasks are completed or not
650 for Dep
in self
.DependencyList
:
651 if Dep
.CompleteFlag
== True:
658 ## Add dependent build task
660 # @param Dependency The list of dependent build objects
662 def AddDependency(self
, Dependency
):
663 for Dep
in Dependency
:
664 if not Dep
.BuildObject
.IsBinaryModule
:
665 self
.DependencyList
.append(BuildTask
.New(Dep
)) # BuildTask list
667 ## The thread wrapper of LaunchCommand function
669 # @param Command A list or string contains the call of the command
670 # @param WorkingDir The directory in which the program will be running
672 def _CommandThread(self
, Command
, WorkingDir
):
674 self
.BuildItem
.BuildObject
.BuildTime
= LaunchCommand(Command
, WorkingDir
)
675 self
.CompleteFlag
= True
678 # TRICK: hide the output of threads left runing, so that the user can
679 # catch the error message easily
681 if not BuildTask
._ErrorFlag
.isSet():
682 GlobalData
.gBuildingModule
= "%s [%s, %s, %s]" % (str(self
.BuildItem
.BuildObject
),
683 self
.BuildItem
.BuildObject
.Arch
,
684 self
.BuildItem
.BuildObject
.ToolChain
,
685 self
.BuildItem
.BuildObject
.BuildTarget
687 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
688 BuildTask
._ErrorFlag
.set()
689 BuildTask
._ErrorMessage
= "%s broken\n %s [%s]" % \
690 (threading
.currentThread().getName(), Command
, WorkingDir
)
691 # indicate there's a thread is available for another build task
692 BuildTask
._RunningQueueLock
.acquire()
693 BuildTask
._RunningQueue
.pop(self
.BuildItem
)
694 BuildTask
._RunningQueueLock
.release()
695 BuildTask
._Thread
.release()
697 ## Start build task thread
700 EdkLogger
.quiet("Building ... %s" % repr(self
.BuildItem
))
701 Command
= self
.BuildItem
.BuildCommand
+ [self
.BuildItem
.Target
]
702 self
.BuildTread
= Thread(target
=self
._CommandThread
, args
=(Command
, self
.BuildItem
.WorkingDir
))
703 self
.BuildTread
.setName("build thread")
704 self
.BuildTread
.setDaemon(False)
705 self
.BuildTread
.start()
707 ## The class contains the information related to EFI image
712 # Constructor will load all required image information.
714 # @param BaseName The full file path of image.
715 # @param Guid The GUID for image.
716 # @param Arch Arch of this image.
717 # @param OutputDir The output directory for image.
718 # @param DebugDir The debug directory for image.
719 # @param ImageClass PeImage Information
721 def __init__(self
, BaseName
, Guid
, Arch
, OutputDir
, DebugDir
, ImageClass
):
722 self
.BaseName
= BaseName
725 self
.OutputDir
= OutputDir
726 self
.DebugDir
= DebugDir
727 self
.Image
= ImageClass
728 self
.Image
.Size
= (self
.Image
.Size
/ 0x1000 + 1) * 0x1000
730 ## The class implementing the EDK2 build process
732 # The build process includes:
733 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
734 # 2. Parse DSC file of active platform
735 # 3. Parse FDF file if any
736 # 4. Establish build database, including parse all other files (module, package)
737 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
738 # 6. Call build command
743 # Constructor will load all necessary configurations, parse platform, modules
744 # and packages and the establish a database for AutoGen.
746 # @param Target The build command target, one of gSupportedTarget
747 # @param WorkspaceDir The directory of workspace
748 # @param BuildOptions Build options passed from command line
750 def __init__(self
, Target
, WorkspaceDir
, BuildOptions
):
751 self
.WorkspaceDir
= WorkspaceDir
753 self
.PlatformFile
= BuildOptions
.PlatformFile
754 self
.ModuleFile
= BuildOptions
.ModuleFile
755 self
.ArchList
= BuildOptions
.TargetArch
756 self
.ToolChainList
= BuildOptions
.ToolChain
757 self
.BuildTargetList
= BuildOptions
.BuildTarget
758 self
.Fdf
= BuildOptions
.FdfFile
759 self
.FdList
= BuildOptions
.RomImage
760 self
.FvList
= BuildOptions
.FvImage
761 self
.CapList
= BuildOptions
.CapName
762 self
.SilentMode
= BuildOptions
.SilentMode
763 self
.ThreadNumber
= BuildOptions
.ThreadNumber
764 self
.SkipAutoGen
= BuildOptions
.SkipAutoGen
765 self
.Reparse
= BuildOptions
.Reparse
766 self
.SkuId
= BuildOptions
.SkuId
768 GlobalData
.gSKUID_CMD
= self
.SkuId
769 self
.ConfDirectory
= BuildOptions
.ConfDirectory
770 self
.SpawnMode
= True
771 self
.BuildReport
= BuildReport(BuildOptions
.ReportFile
, BuildOptions
.ReportType
)
772 self
.TargetTxt
= TargetTxtClassObject()
773 self
.ToolDef
= ToolDefClassObject()
777 GlobalData
.BuildOptionPcd
= BuildOptions
.OptionPcd
if BuildOptions
.OptionPcd
else []
778 #Set global flag for build mode
779 GlobalData
.gIgnoreSource
= BuildOptions
.IgnoreSources
780 GlobalData
.gUseHashCache
= BuildOptions
.UseHashCache
781 GlobalData
.gBinCacheDest
= BuildOptions
.BinCacheDest
782 GlobalData
.gBinCacheSource
= BuildOptions
.BinCacheSource
783 GlobalData
.gEnableGenfdsMultiThread
= BuildOptions
.GenfdsMultiThread
785 if GlobalData
.gBinCacheDest
and not GlobalData
.gUseHashCache
:
786 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination must be used together with --hash.")
788 if GlobalData
.gBinCacheSource
and not GlobalData
.gUseHashCache
:
789 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-source must be used together with --hash.")
791 if GlobalData
.gBinCacheDest
and GlobalData
.gBinCacheSource
:
792 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination can not be used together with --binary-source.")
794 if GlobalData
.gBinCacheSource
:
795 BinCacheSource
= os
.path
.normpath(GlobalData
.gBinCacheSource
)
796 if not os
.path
.isabs(BinCacheSource
):
797 BinCacheSource
= mws
.join(self
.WorkspaceDir
, BinCacheSource
)
798 GlobalData
.gBinCacheSource
= BinCacheSource
800 if GlobalData
.gBinCacheSource
is not None:
801 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-source.")
803 if GlobalData
.gBinCacheDest
:
804 BinCacheDest
= os
.path
.normpath(GlobalData
.gBinCacheDest
)
805 if not os
.path
.isabs(BinCacheDest
):
806 BinCacheDest
= mws
.join(self
.WorkspaceDir
, BinCacheDest
)
807 GlobalData
.gBinCacheDest
= BinCacheDest
809 if GlobalData
.gBinCacheDest
is not None:
810 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-destination.")
812 if self
.ConfDirectory
:
813 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
814 ConfDirectoryPath
= os
.path
.normpath(self
.ConfDirectory
)
816 if not os
.path
.isabs(ConfDirectoryPath
):
817 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
818 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
819 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, ConfDirectoryPath
)
821 if "CONF_PATH" in os
.environ
:
822 ConfDirectoryPath
= os
.path
.normcase(os
.path
.normpath(os
.environ
["CONF_PATH"]))
824 # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf
825 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, 'Conf')
826 GlobalData
.gConfDirectory
= ConfDirectoryPath
827 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
829 if BuildOptions
.DisableCache
:
830 self
.Db
= WorkspaceDatabase(":memory:")
832 self
.Db
= WorkspaceDatabase(GlobalData
.gDatabasePath
, self
.Reparse
)
833 self
.BuildDatabase
= self
.Db
.BuildObject
835 self
.ToolChainFamily
= None
836 self
.LoadFixAddress
= 0
837 self
.UniFlag
= BuildOptions
.Flag
838 self
.BuildModules
= []
839 self
.HashSkipModules
= []
841 self
.LaunchPrebuildFlag
= False
842 self
.PlatformBuildPath
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PlatformBuild')
843 if BuildOptions
.CommandLength
:
844 GlobalData
.gCommandMaxLength
= BuildOptions
.CommandLength
846 # print dot character during doing some time-consuming work
847 self
.Progress
= Utils
.Progressor()
848 # print current build environment and configuration
849 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
850 if "PACKAGES_PATH" in os
.environ
:
851 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
852 EdkLogger
.quiet("%-16s = %s" % ("PACKAGES_PATH", os
.path
.normcase(os
.path
.normpath(os
.environ
["PACKAGES_PATH"]))))
853 EdkLogger
.quiet("%-16s = %s" % ("ECP_SOURCE", os
.environ
["ECP_SOURCE"]))
854 EdkLogger
.quiet("%-16s = %s" % ("EDK_SOURCE", os
.environ
["EDK_SOURCE"]))
855 EdkLogger
.quiet("%-16s = %s" % ("EFI_SOURCE", os
.environ
["EFI_SOURCE"]))
856 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
857 if "EDK_TOOLS_BIN" in os
.environ
:
858 # Print the same path style with WORKSPACE env.
859 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_TOOLS_BIN"]))))
860 EdkLogger
.quiet("%-16s = %s" % ("CONF_PATH", GlobalData
.gConfDirectory
))
864 EdkLogger
.quiet("%-16s = %s" % ("PREBUILD", self
.Prebuild
))
866 EdkLogger
.quiet("%-16s = %s" % ("POSTBUILD", self
.Postbuild
))
868 self
.LaunchPrebuild()
869 self
.TargetTxt
= TargetTxtClassObject()
870 self
.ToolDef
= ToolDefClassObject()
871 if not (self
.LaunchPrebuildFlag
and os
.path
.exists(self
.PlatformBuildPath
)):
875 os
.chdir(self
.WorkspaceDir
)
877 ## Load configuration
879 # This method will parse target.txt and get the build configurations.
881 def LoadConfiguration(self
):
883 # Check target.txt and tools_def.txt and Init them
885 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(GlobalData
.gConfDirectory
, gBuildConfiguration
))
886 if os
.path
.isfile(BuildConfigurationFile
) == True:
887 StatusCode
= self
.TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
889 ToolDefinitionFile
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_CONF
]
890 if ToolDefinitionFile
== '':
891 ToolDefinitionFile
= gToolsDefinition
892 ToolDefinitionFile
= os
.path
.normpath(mws
.join(self
.WorkspaceDir
, 'Conf', ToolDefinitionFile
))
893 if os
.path
.isfile(ToolDefinitionFile
) == True:
894 StatusCode
= self
.ToolDef
.LoadToolDefFile(ToolDefinitionFile
)
896 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=ToolDefinitionFile
)
898 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
900 # if no ARCH given in command line, get it from target.txt
901 if not self
.ArchList
:
902 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TARGET_ARCH
]
903 self
.ArchList
= tuple(self
.ArchList
)
905 # if no build target given in command line, get it from target.txt
906 if not self
.BuildTargetList
:
907 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TARGET
]
909 # if no tool chain given in command line, get it from target.txt
910 if not self
.ToolChainList
:
911 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
912 if self
.ToolChainList
is None or len(self
.ToolChainList
) == 0:
913 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
915 # check if the tool chains are defined or not
916 NewToolChainList
= []
917 for ToolChain
in self
.ToolChainList
:
918 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
919 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
921 NewToolChainList
.append(ToolChain
)
922 # if no tool chain available, break the build
923 if len(NewToolChainList
) == 0:
924 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
925 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
927 self
.ToolChainList
= NewToolChainList
930 ToolDefinition
= self
.ToolDef
.ToolsDefTxtDatabase
931 for Tool
in self
.ToolChainList
:
932 if TAB_TOD_DEFINES_FAMILY
not in ToolDefinition
or Tool
not in ToolDefinition
[TAB_TOD_DEFINES_FAMILY
] \
933 or not ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
]:
934 EdkLogger
.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool
)
935 ToolChainFamily
.append(TAB_COMPILER_MSFT
)
937 ToolChainFamily
.append(ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
])
938 self
.ToolChainFamily
= ToolChainFamily
940 if self
.ThreadNumber
is None:
941 self
.ThreadNumber
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
942 if self
.ThreadNumber
== '':
943 self
.ThreadNumber
= 0
945 self
.ThreadNumber
= int(self
.ThreadNumber
, 0)
947 if self
.ThreadNumber
== 0:
949 self
.ThreadNumber
= multiprocessing
.cpu_count()
950 except (ImportError, NotImplementedError):
951 self
.ThreadNumber
= 1
953 if not self
.PlatformFile
:
954 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
956 # Try to find one in current directory
957 WorkingDirectory
= os
.getcwd()
958 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
959 FileNum
= len(FileList
)
961 EdkLogger
.error("build", OPTION_MISSING
,
962 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
964 PlatformFile
= FileList
[0]
966 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
967 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
969 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
971 ## Initialize build configuration
973 # This method will parse DSC file and merge the configurations from
974 # command line and target.txt, then get the final build configurations.
977 # parse target.txt, tools_def.txt, and platform file
978 self
.LoadConfiguration()
980 # Allow case-insensitive for those from command line or configuration file
981 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
983 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
985 # create metafile database
987 self
.Db
.InitDatabase()
989 def InitPreBuild(self
):
990 self
.LoadConfiguration()
991 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
993 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
994 if self
.BuildTargetList
:
995 GlobalData
.gGlobalDefines
['TARGET'] = self
.BuildTargetList
[0]
997 GlobalData
.gGlobalDefines
['ARCH'] = self
.ArchList
[0]
998 if self
.ToolChainList
:
999 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = self
.ToolChainList
[0]
1000 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = self
.ToolChainList
[0]
1001 if self
.ToolChainFamily
:
1002 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[0]
1003 if 'PREBUILD' in GlobalData
.gCommandLineDefines
:
1004 self
.Prebuild
= GlobalData
.gCommandLineDefines
.get('PREBUILD')
1006 self
.Db
.InitDatabase()
1008 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
1009 self
.Prebuild
= str(Platform
.Prebuild
)
1013 # Evaluate all arguments and convert arguments that are WORKSPACE
1014 # relative paths to absolute paths. Filter arguments that look like
1015 # flags or do not follow the file/dir naming rules to avoid false
1016 # positives on this conversion.
1018 for Arg
in self
.Prebuild
.split():
1020 # Do not modify Arg if it looks like a flag or an absolute file path
1022 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1023 PrebuildList
.append(Arg
)
1026 # Do not modify Arg if it does not look like a Workspace relative
1027 # path that starts with a valid package directory name
1029 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1030 PrebuildList
.append(Arg
)
1033 # If Arg looks like a WORKSPACE relative path, then convert to an
1034 # absolute path and check to see if the file exists.
1036 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1037 if os
.path
.isfile(Temp
):
1039 PrebuildList
.append(Arg
)
1040 self
.Prebuild
= ' '.join(PrebuildList
)
1041 self
.Prebuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1043 def InitPostBuild(self
):
1044 if 'POSTBUILD' in GlobalData
.gCommandLineDefines
:
1045 self
.Postbuild
= GlobalData
.gCommandLineDefines
.get('POSTBUILD')
1047 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
1048 self
.Postbuild
= str(Platform
.Postbuild
)
1052 # Evaluate all arguments and convert arguments that are WORKSPACE
1053 # relative paths to absolute paths. Filter arguments that look like
1054 # flags or do not follow the file/dir naming rules to avoid false
1055 # positives on this conversion.
1057 for Arg
in self
.Postbuild
.split():
1059 # Do not modify Arg if it looks like a flag or an absolute file path
1061 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1062 PostbuildList
.append(Arg
)
1065 # Do not modify Arg if it does not look like a Workspace relative
1066 # path that starts with a valid package directory name
1068 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1069 PostbuildList
.append(Arg
)
1072 # If Arg looks like a WORKSPACE relative path, then convert to an
1073 # absolute path and check to see if the file exists.
1075 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1076 if os
.path
.isfile(Temp
):
1078 PostbuildList
.append(Arg
)
1079 self
.Postbuild
= ' '.join(PostbuildList
)
1080 self
.Postbuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1082 def PassCommandOption(self
, BuildTarget
, TargetArch
, ToolChain
, PlatformFile
, Target
):
1084 if GlobalData
.gCommand
and isinstance(GlobalData
.gCommand
, list):
1085 BuildStr
+= ' ' + ' '.join(GlobalData
.gCommand
)
1088 ToolChainFlag
= False
1089 PlatformFileFlag
= False
1091 if GlobalData
.gOptions
and not GlobalData
.gOptions
.BuildTarget
:
1093 if GlobalData
.gOptions
and not GlobalData
.gOptions
.TargetArch
:
1095 if GlobalData
.gOptions
and not GlobalData
.gOptions
.ToolChain
:
1096 ToolChainFlag
= True
1097 if GlobalData
.gOptions
and not GlobalData
.gOptions
.PlatformFile
:
1098 PlatformFileFlag
= True
1100 if TargetFlag
and BuildTarget
:
1101 if isinstance(BuildTarget
, list) or isinstance(BuildTarget
, tuple):
1102 BuildStr
+= ' -b ' + ' -b '.join(BuildTarget
)
1103 elif isinstance(BuildTarget
, str):
1104 BuildStr
+= ' -b ' + BuildTarget
1105 if ArchFlag
and TargetArch
:
1106 if isinstance(TargetArch
, list) or isinstance(TargetArch
, tuple):
1107 BuildStr
+= ' -a ' + ' -a '.join(TargetArch
)
1108 elif isinstance(TargetArch
, str):
1109 BuildStr
+= ' -a ' + TargetArch
1110 if ToolChainFlag
and ToolChain
:
1111 if isinstance(ToolChain
, list) or isinstance(ToolChain
, tuple):
1112 BuildStr
+= ' -t ' + ' -t '.join(ToolChain
)
1113 elif isinstance(ToolChain
, str):
1114 BuildStr
+= ' -t ' + ToolChain
1115 if PlatformFileFlag
and PlatformFile
:
1116 if isinstance(PlatformFile
, list) or isinstance(PlatformFile
, tuple):
1117 BuildStr
+= ' -p ' + ' -p '.join(PlatformFile
)
1118 elif isinstance(PlatformFile
, str):
1119 BuildStr
+= ' -p' + PlatformFile
1120 BuildStr
+= ' --conf=' + GlobalData
.gConfDirectory
1122 BuildStr
+= ' ' + Target
1126 def LaunchPrebuild(self
):
1128 EdkLogger
.info("\n- Prebuild Start -\n")
1129 self
.LaunchPrebuildFlag
= True
1131 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1132 # and preserve them for the rest of the main build step, because the child process environment will
1133 # evaporate as soon as it exits, we cannot get it in build step.
1135 PrebuildEnvFile
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PrebuildEnv')
1136 if os
.path
.isfile(PrebuildEnvFile
):
1137 os
.remove(PrebuildEnvFile
)
1138 if os
.path
.isfile(self
.PlatformBuildPath
):
1139 os
.remove(self
.PlatformBuildPath
)
1140 if sys
.platform
== "win32":
1141 args
= ' && '.join((self
.Prebuild
, 'set > ' + PrebuildEnvFile
))
1142 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1144 args
= ' && '.join((self
.Prebuild
, 'env > ' + PrebuildEnvFile
))
1145 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1147 # launch two threads to read the STDOUT and STDERR
1148 EndOfProcedure
= Event()
1149 EndOfProcedure
.clear()
1151 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1152 StdOutThread
.setName("STDOUT-Redirector")
1153 StdOutThread
.setDaemon(False)
1154 StdOutThread
.start()
1157 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1158 StdErrThread
.setName("STDERR-Redirector")
1159 StdErrThread
.setDaemon(False)
1160 StdErrThread
.start()
1161 # waiting for program exit
1168 if Process
.returncode
!= 0 :
1169 EdkLogger
.error("Prebuild", PREBUILD_ERROR
, 'Prebuild process is not success!')
1171 if os
.path
.exists(PrebuildEnvFile
):
1172 f
= open(PrebuildEnvFile
)
1173 envs
= f
.readlines()
1175 envs
= itertools
.imap(lambda l
: l
.split('=', 1), envs
)
1176 envs
= itertools
.ifilter(lambda l
: len(l
) == 2, envs
)
1177 envs
= itertools
.imap(lambda l
: [i
.strip() for i
in l
], envs
)
1178 os
.environ
.update(dict(envs
))
1179 EdkLogger
.info("\n- Prebuild Done -\n")
1181 def LaunchPostbuild(self
):
1183 EdkLogger
.info("\n- Postbuild Start -\n")
1184 if sys
.platform
== "win32":
1185 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1187 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1188 # launch two threads to read the STDOUT and STDERR
1189 EndOfProcedure
= Event()
1190 EndOfProcedure
.clear()
1192 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1193 StdOutThread
.setName("STDOUT-Redirector")
1194 StdOutThread
.setDaemon(False)
1195 StdOutThread
.start()
1198 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1199 StdErrThread
.setName("STDERR-Redirector")
1200 StdErrThread
.setDaemon(False)
1201 StdErrThread
.start()
1202 # waiting for program exit
1209 if Process
.returncode
!= 0 :
1210 EdkLogger
.error("Postbuild", POSTBUILD_ERROR
, 'Postbuild process is not success!')
1211 EdkLogger
.info("\n- Postbuild Done -\n")
1212 ## Build a module or platform
1214 # Create autogen code and makefile for a module or platform, and the launch
1215 # "make" command to build it
1217 # @param Target The target of build command
1218 # @param Platform The platform file
1219 # @param Module The module file
1220 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1221 # @param ToolChain The name of toolchain to build
1222 # @param Arch The arch of the module/platform
1223 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1224 # for dependent modules/Libraries
1225 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1226 # for dependent modules/Libraries
1228 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False, FfsCommand
={}):
1229 if AutoGenObject
is None:
1232 # skip file generation for cleanxxx targets, run and fds target
1233 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1234 # for target which must generate AutoGen code and makefile
1235 if not self
.SkipAutoGen
or Target
== 'genc':
1236 self
.Progress
.Start("Generating code")
1237 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1238 self
.Progress
.Stop("done!")
1239 if Target
== "genc":
1242 if not self
.SkipAutoGen
or Target
== 'genmake':
1243 self
.Progress
.Start("Generating makefile")
1244 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
, FfsCommand
)
1245 self
.Progress
.Stop("done!")
1246 if Target
== "genmake":
1249 # always recreate top/platform makefile when clean, just in case of inconsistency
1250 AutoGenObject
.CreateCodeFile(False)
1251 AutoGenObject
.CreateMakeFile(False)
1253 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1254 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1256 BuildCommand
= AutoGenObject
.BuildCommand
1257 if BuildCommand
is None or len(BuildCommand
) == 0:
1258 EdkLogger
.error("build", OPTION_MISSING
,
1259 "No build command found for this module. "
1260 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1261 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1262 ExtraData
=str(AutoGenObject
))
1264 makefile
= GenMake
.BuildFile(AutoGenObject
)._FILE
_NAME
_[GenMake
.gMakeType
]
1268 RunDir
= os
.path
.normpath(os
.path
.join(AutoGenObject
.BuildDir
, GlobalData
.gGlobalDefines
['ARCH']))
1269 Command
= '.\SecMain'
1271 LaunchCommand(Command
, RunDir
)
1276 BuildCommand
= BuildCommand
+ [Target
]
1277 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1278 self
.CreateAsBuiltInf()
1282 if Target
== 'libraries':
1283 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1284 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1285 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1289 if Target
== 'modules':
1290 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1291 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1292 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1293 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1294 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, makefile
)), 'pbuild']
1295 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1296 self
.CreateAsBuiltInf()
1300 if Target
== 'cleanlib':
1301 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1302 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1303 if os
.path
.exists(LibMakefile
):
1304 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1305 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1309 if Target
== 'clean':
1310 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1311 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, makefile
))
1312 if os
.path
.exists(ModMakefile
):
1313 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
1314 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1315 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1316 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1317 if os
.path
.exists(LibMakefile
):
1318 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1319 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1323 if Target
== 'cleanall':
1325 #os.rmdir(AutoGenObject.BuildDir)
1326 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1327 except WindowsError as X
:
1328 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1331 ## Build a module or platform
1333 # Create autogen code and makefile for a module or platform, and the launch
1334 # "make" command to build it
1336 # @param Target The target of build command
1337 # @param Platform The platform file
1338 # @param Module The module file
1339 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1340 # @param ToolChain The name of toolchain to build
1341 # @param Arch The arch of the module/platform
1342 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1343 # for dependent modules/Libraries
1344 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1345 # for dependent modules/Libraries
1347 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1348 if AutoGenObject
is None:
1351 # skip file generation for cleanxxx targets, run and fds target
1352 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1353 # for target which must generate AutoGen code and makefile
1354 if not self
.SkipAutoGen
or Target
== 'genc':
1355 self
.Progress
.Start("Generating code")
1356 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1357 self
.Progress
.Stop("done!")
1358 if Target
== "genc":
1361 if not self
.SkipAutoGen
or Target
== 'genmake':
1362 self
.Progress
.Start("Generating makefile")
1363 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1364 #AutoGenObject.CreateAsBuiltInf()
1365 self
.Progress
.Stop("done!")
1366 if Target
== "genmake":
1369 # always recreate top/platform makefile when clean, just in case of inconsistency
1370 AutoGenObject
.CreateCodeFile(False)
1371 AutoGenObject
.CreateMakeFile(False)
1373 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1374 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1376 BuildCommand
= AutoGenObject
.BuildCommand
1377 if BuildCommand
is None or len(BuildCommand
) == 0:
1378 EdkLogger
.error("build", OPTION_MISSING
,
1379 "No build command found for this module. "
1380 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1381 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1382 ExtraData
=str(AutoGenObject
))
1387 BuildCommand
= BuildCommand
+ [Target
]
1388 AutoGenObject
.BuildTime
= LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1389 self
.CreateAsBuiltInf()
1394 LaunchCommand(AutoGenObject
.GenFdsCommand
, AutoGenObject
.MakeFileDir
)
1399 RunDir
= os
.path
.normpath(os
.path
.join(AutoGenObject
.BuildDir
, GlobalData
.gGlobalDefines
['ARCH']))
1400 Command
= '.\SecMain'
1402 LaunchCommand(Command
, RunDir
)
1406 if Target
== 'libraries':
1413 if Target
== 'cleanall':
1415 #os.rmdir(AutoGenObject.BuildDir)
1416 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1417 except WindowsError as X
:
1418 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1421 ## Rebase module image and Get function address for the input module list.
1423 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1425 AddrIsOffset
= False
1426 for InfFile
in ModuleList
:
1427 sys
.stdout
.write (".")
1429 ModuleInfo
= ModuleList
[InfFile
]
1430 ModuleName
= ModuleInfo
.BaseName
1431 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1432 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1433 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1435 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1437 # Update Image to new BaseAddress by GenFw tool
1439 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1440 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1443 # Set new address to the section header only for SMM driver.
1445 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1446 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1448 # Collect funtion address from Map file
1450 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1452 if os
.path
.exists(ImageMapTable
):
1453 OrigImageBaseAddress
= 0
1454 ImageMap
= open(ImageMapTable
, 'r')
1455 for LinStr
in ImageMap
:
1456 if len (LinStr
.strip()) == 0:
1459 # Get the preferred address set on link time.
1461 if LinStr
.find ('Preferred load address is') != -1:
1462 StrList
= LinStr
.split()
1463 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1465 StrList
= LinStr
.split()
1466 if len (StrList
) > 4:
1467 if StrList
[3] == 'f' or StrList
[3] == 'F':
1469 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1470 FunctionList
.append ((Name
, RelativeAddress
))
1471 if ModuleInfo
.Arch
== 'IPF' and Name
.endswith('_ModuleEntryPoint'):
1473 # Get the real entry point address for IPF image.
1475 ModuleInfo
.Image
.EntryPoint
= RelativeAddress
1478 # Add general information.
1481 MapBuffer
.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1483 MapBuffer
.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1485 MapBuffer
.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1487 # Add guid and general seciton section.
1489 TextSectionAddress
= 0
1490 DataSectionAddress
= 0
1491 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1492 if SectionHeader
[0] == '.text':
1493 TextSectionAddress
= SectionHeader
[1]
1494 elif SectionHeader
[0] in ['.data', '.sdata']:
1495 DataSectionAddress
= SectionHeader
[1]
1497 MapBuffer
.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1499 MapBuffer
.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1501 # Add debug image full path.
1503 MapBuffer
.write('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1505 # Add funtion address
1507 for Function
in FunctionList
:
1509 MapBuffer
.write(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1511 MapBuffer
.write(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1515 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1518 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1520 ## Collect MAP information of all FVs
1522 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1524 # First get the XIP base address for FV map file.
1525 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1526 GuidName
= re
.compile("\(GUID=[-a-fA-F0-9]+")
1527 for FvName
in Wa
.FdfProfile
.FvDict
:
1528 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1529 if not os
.path
.exists(FvMapBuffer
):
1531 FvMap
= open(FvMapBuffer
, 'r')
1532 #skip FV size information
1538 MatchGuid
= GuidPattern
.match(Line
)
1539 if MatchGuid
is not None:
1541 # Replace GUID with module name
1543 GuidString
= MatchGuid
.group()
1544 if GuidString
.upper() in ModuleList
:
1545 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1546 MapBuffer
.write(Line
)
1548 # Add the debug image full path.
1550 MatchGuid
= GuidName
.match(Line
)
1551 if MatchGuid
is not None:
1552 GuidString
= MatchGuid
.group().split("=")[1]
1553 if GuidString
.upper() in ModuleList
:
1554 MapBuffer
.write('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1558 ## Collect MAP information of all modules
1560 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1561 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1563 PatchEfiImageList
= []
1571 # reserve 4K size in SMRAM to make SMM module address not from 0.
1573 IsIpfPlatform
= False
1574 if 'IPF' in self
.ArchList
:
1575 IsIpfPlatform
= True
1576 for ModuleGuid
in ModuleList
:
1577 Module
= ModuleList
[ModuleGuid
]
1578 GlobalData
.gProcessingFile
= "%s [%s, %s, %s]" % (Module
.MetaFile
, Module
.Arch
, Module
.ToolChain
, Module
.BuildTarget
)
1580 OutputImageFile
= ''
1581 for ResultFile
in Module
.CodaTargetList
:
1582 if str(ResultFile
.Target
).endswith('.efi'):
1584 # module list for PEI, DXE, RUNTIME and SMM
1586 OutputImageFile
= os
.path
.join(Module
.OutputDir
, Module
.Name
+ '.efi')
1587 ImageClass
= PeImageClass (OutputImageFile
)
1588 if not ImageClass
.IsValid
:
1589 EdkLogger
.error("build", FILE_PARSE_FAILURE
, ExtraData
=ImageClass
.ErrorInfo
)
1590 ImageInfo
= PeImageInfo(Module
.Name
, Module
.Guid
, Module
.Arch
, Module
.OutputDir
, Module
.DebugDir
, ImageClass
)
1591 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
]:
1592 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1593 PeiSize
+= ImageInfo
.Image
.Size
1594 elif Module
.ModuleType
in [EDK_COMPONENT_TYPE_BS_DRIVER
, SUP_MODULE_DXE_DRIVER
, SUP_MODULE_UEFI_DRIVER
]:
1595 BtModuleList
[Module
.MetaFile
] = ImageInfo
1596 BtSize
+= ImageInfo
.Image
.Size
1597 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
]:
1598 RtModuleList
[Module
.MetaFile
] = ImageInfo
1599 #IPF runtime driver needs to be at 2 page alignment.
1600 if IsIpfPlatform
and ImageInfo
.Image
.Size
% 0x2000 != 0:
1601 ImageInfo
.Image
.Size
= (ImageInfo
.Image
.Size
/ 0x2000 + 1) * 0x2000
1602 RtSize
+= ImageInfo
.Image
.Size
1603 elif Module
.ModuleType
in [SUP_MODULE_SMM_CORE
, SUP_MODULE_DXE_SMM_DRIVER
, SUP_MODULE_MM_STANDALONE
, SUP_MODULE_MM_CORE_STANDALONE
]:
1604 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1605 SmmSize
+= ImageInfo
.Image
.Size
1606 if Module
.ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
1607 PiSpecVersion
= Module
.Module
.Specification
.get('PI_SPECIFICATION_VERSION', '0x00000000')
1608 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1609 if int(PiSpecVersion
, 16) < 0x0001000A:
1610 BtModuleList
[Module
.MetaFile
] = ImageInfo
1611 BtSize
+= ImageInfo
.Image
.Size
1614 # EFI image is final target.
1615 # Check EFI image contains patchable FixAddress related PCDs.
1617 if OutputImageFile
!= '':
1618 ModuleIsPatch
= False
1619 for Pcd
in Module
.ModulePcdList
:
1620 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1621 ModuleIsPatch
= True
1623 if not ModuleIsPatch
:
1624 for Pcd
in Module
.LibraryPcdList
:
1625 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1626 ModuleIsPatch
= True
1629 if not ModuleIsPatch
:
1632 # Module includes the patchable load fix address PCDs.
1633 # It will be fixed up later.
1635 PatchEfiImageList
.append (OutputImageFile
)
1638 # Get Top Memory address
1640 ReservedRuntimeMemorySize
= 0
1641 TopMemoryAddress
= 0
1642 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1643 TopMemoryAddress
= 0
1645 TopMemoryAddress
= self
.LoadFixAddress
1646 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1647 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1648 # Make IPF runtime driver at 2 page alignment.
1650 ReservedRuntimeMemorySize
= TopMemoryAddress
% 0x2000
1651 RtSize
= RtSize
+ ReservedRuntimeMemorySize
1654 # Patch FixAddress related PCDs into EFI image
1656 for EfiImage
in PatchEfiImageList
:
1657 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1658 if not os
.path
.exists(EfiImageMap
):
1661 # Get PCD offset in EFI image by GenPatchPcdTable function
1663 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1665 # Patch real PCD value by PatchPcdValue tool
1667 for PcdInfo
in PcdTable
:
1669 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1670 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
/ 0x1000))
1671 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1672 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
/ 0x1000))
1673 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1674 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
/ 0x1000))
1675 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1676 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
/ 0x1000))
1677 if ReturnValue
!= 0:
1678 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1680 MapBuffer
.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
/ 0x1000))
1681 MapBuffer
.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
/ 0x1000))
1682 MapBuffer
.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
/ 0x1000))
1683 if len (SmmModuleList
) > 0:
1684 MapBuffer
.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
/ 0x1000))
1686 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1687 BtBaseAddr
= TopMemoryAddress
- RtSize
1688 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1690 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1691 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1692 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1693 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
=False, ModeIsSmm
=True)
1694 MapBuffer
.write('\n\n')
1695 sys
.stdout
.write ("\n")
1698 ## Save platform Map file
1700 def _SaveMapFile (self
, MapBuffer
, Wa
):
1702 # Map file path is got.
1704 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1706 # Save address map into MAP file.
1708 SaveFileOnChange(MapFilePath
, MapBuffer
.getvalue(), False)
1710 if self
.LoadFixAddress
!= 0:
1711 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath
))
1714 ## Build active platform for different build targets and different tool chains
1716 def _BuildPlatform(self
):
1717 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1718 for BuildTarget
in self
.BuildTargetList
:
1719 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1721 for ToolChain
in self
.ToolChainList
:
1722 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1723 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1724 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1726 Wa
= WorkspaceAutoGen(
1743 self
.Fdf
= Wa
.FdfFile
1744 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1745 self
.BuildReport
.AddPlatformReport(Wa
)
1746 self
.Progress
.Stop("done!")
1748 # Add ffs build to makefile
1750 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1751 CmdListDict
= self
._GenFfsCmd
()
1753 for Arch
in Wa
.ArchList
:
1754 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1755 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1756 for Module
in Pa
.Platform
.Modules
:
1757 # Get ModuleAutoGen object to generate C code file and makefile
1758 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1761 self
.BuildModules
.append(Ma
)
1762 self
._BuildPa
(self
.Target
, Pa
, FfsCommand
=CmdListDict
)
1764 # Create MAP file when Load Fix Address is enabled.
1765 if self
.Target
in ["", "all", "fds"]:
1766 for Arch
in Wa
.ArchList
:
1767 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1769 # Check whether the set fix address is above 4G for 32bit image.
1771 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1772 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")
1777 for Pa
in Wa
.AutoGenObjectList
:
1778 for Ma
in Pa
.ModuleAutoGenList
:
1781 if not Ma
.IsLibrary
:
1782 ModuleList
[Ma
.Guid
.upper()] = Ma
1784 MapBuffer
= BytesIO('')
1785 if self
.LoadFixAddress
!= 0:
1787 # Rebase module to the preferred memory address before GenFds
1789 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1792 # create FDS again for the updated EFI image
1794 self
._Build
("fds", Wa
)
1796 # Create MAP file for all platform FVs after GenFds.
1798 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1800 # Save MAP buffer into MAP file.
1802 self
._SaveMapFile
(MapBuffer
, Wa
)
1804 ## Build active module for different build targets, different tool chains and different archs
1806 def _BuildModule(self
):
1807 for BuildTarget
in self
.BuildTargetList
:
1808 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1810 for ToolChain
in self
.ToolChainList
:
1811 WorkspaceAutoGenTime
= time
.time()
1812 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1813 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1814 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1817 # module build needs platform build information, so get platform
1820 Wa
= WorkspaceAutoGen(
1838 self
.Fdf
= Wa
.FdfFile
1839 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1840 Wa
.CreateMakeFile(False)
1841 # Add ffs build to makefile
1843 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1844 CmdListDict
= self
._GenFfsCmd
()
1845 self
.Progress
.Stop("done!")
1847 ExitFlag
= threading
.Event()
1849 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1850 for Arch
in Wa
.ArchList
:
1851 AutoGenStart
= time
.time()
1852 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1853 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1854 for Module
in Pa
.Platform
.Modules
:
1855 if self
.ModuleFile
.Dir
== Module
.Dir
and self
.ModuleFile
.Name
== Module
.Name
:
1856 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1857 if Ma
is None: continue
1859 if Ma
.CanSkipbyHash():
1860 self
.HashSkipModules
.append(Ma
)
1862 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1863 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1864 # for target which must generate AutoGen code and makefile
1865 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1866 self
.Progress
.Start("Generating code")
1867 Ma
.CreateCodeFile(True)
1868 self
.Progress
.Stop("done!")
1869 if self
.Target
== "genc":
1871 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1872 self
.Progress
.Start("Generating makefile")
1873 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
1874 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
1875 del CmdListDict
[Module
.File
, Arch
]
1877 Ma
.CreateMakeFile(True)
1878 self
.Progress
.Stop("done!")
1879 if self
.Target
== "genmake":
1881 self
.BuildModules
.append(Ma
)
1882 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1883 MakeStart
= time
.time()
1884 for Ma
in self
.BuildModules
:
1885 if not Ma
.IsBinaryModule
:
1886 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
1887 # Break build if any build thread has error
1888 if BuildTask
.HasError():
1889 # we need a full version of makefile for platform
1891 BuildTask
.WaitForComplete()
1892 Pa
.CreateMakeFile(False)
1893 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1894 # Start task scheduler
1895 if not BuildTask
.IsOnGoing():
1896 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1898 # in case there's an interruption. we need a full version of makefile for platform
1899 Pa
.CreateMakeFile(False)
1900 if BuildTask
.HasError():
1901 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1902 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1904 MakeContiue
= time
.time()
1906 BuildTask
.WaitForComplete()
1907 self
.CreateAsBuiltInf()
1908 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1909 if BuildTask
.HasError():
1910 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1912 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1917 "Module for [%s] is not a component of active platform."\
1918 " Please make sure that the ARCH and inf file path are"\
1919 " given in the same as in [%s]" % \
1920 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1921 ExtraData
=self
.ModuleFile
1923 # Create MAP file when Load Fix Address is enabled.
1924 if self
.Target
== "fds" and self
.Fdf
:
1925 for Arch
in Wa
.ArchList
:
1927 # Check whether the set fix address is above 4G for 32bit image.
1929 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1930 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")
1935 for Pa
in Wa
.AutoGenObjectList
:
1936 for Ma
in Pa
.ModuleAutoGenList
:
1939 if not Ma
.IsLibrary
:
1940 ModuleList
[Ma
.Guid
.upper()] = Ma
1942 MapBuffer
= BytesIO('')
1943 if self
.LoadFixAddress
!= 0:
1945 # Rebase module to the preferred memory address before GenFds
1947 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1949 # create FDS again for the updated EFI image
1951 GenFdsStart
= time
.time()
1952 self
._Build
("fds", Wa
)
1953 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
1955 # Create MAP file for all platform FVs after GenFds.
1957 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1959 # Save MAP buffer into MAP file.
1961 self
._SaveMapFile
(MapBuffer
, Wa
)
1963 def _GenFfsCmd(self
):
1964 # convert dictionary of Cmd:(Inf,Arch)
1965 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
1966 CmdSetDict
= defaultdict(set)
1967 GenFfsDict
= GenFds
.GenFfsMakefile('', GlobalData
.gFdfParser
, self
, self
.ArchList
, GlobalData
)
1968 for Cmd
in GenFfsDict
:
1969 tmpInf
, tmpArch
= GenFfsDict
[Cmd
]
1970 CmdSetDict
[tmpInf
, tmpArch
].add(Cmd
)
1973 ## Build a platform in multi-thread mode
1975 def _MultiThreadBuildPlatform(self
):
1976 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1977 for BuildTarget
in self
.BuildTargetList
:
1978 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1980 for ToolChain
in self
.ToolChainList
:
1981 WorkspaceAutoGenTime
= time
.time()
1982 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1983 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1984 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1986 Wa
= WorkspaceAutoGen(
2003 self
.Fdf
= Wa
.FdfFile
2004 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
2005 self
.BuildReport
.AddPlatformReport(Wa
)
2006 Wa
.CreateMakeFile(False)
2008 # Add ffs build to makefile
2010 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
2011 CmdListDict
= self
._GenFfsCmd
()
2013 # multi-thread exit flag
2014 ExitFlag
= threading
.Event()
2016 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
2017 for Arch
in Wa
.ArchList
:
2018 AutoGenStart
= time
.time()
2019 GlobalData
.gGlobalDefines
['ARCH'] = Arch
2020 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
2024 for Inf
in Pa
.Platform
.Modules
:
2025 ModuleList
.append(Inf
)
2026 # Add the INF only list in FDF
2027 if GlobalData
.gFdfParser
is not None:
2028 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
2029 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
2030 if Inf
in Pa
.Platform
.Modules
:
2032 ModuleList
.append(Inf
)
2033 for Module
in ModuleList
:
2034 # Get ModuleAutoGen object to generate C code file and makefile
2035 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
2039 if Ma
.CanSkipbyHash():
2040 self
.HashSkipModules
.append(Ma
)
2043 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
2044 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
2045 # for target which must generate AutoGen code and makefile
2046 if not self
.SkipAutoGen
or self
.Target
== 'genc':
2047 Ma
.CreateCodeFile(True)
2048 if self
.Target
== "genc":
2051 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
2052 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
2053 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
2054 del CmdListDict
[Module
.File
, Arch
]
2056 Ma
.CreateMakeFile(True)
2057 if self
.Target
== "genmake":
2059 self
.BuildModules
.append(Ma
)
2060 self
.Progress
.Stop("done!")
2061 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
2062 MakeStart
= time
.time()
2063 for Ma
in self
.BuildModules
:
2064 # Generate build task for the module
2065 if not Ma
.IsBinaryModule
:
2066 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
2067 # Break build if any build thread has error
2068 if BuildTask
.HasError():
2069 # we need a full version of makefile for platform
2071 BuildTask
.WaitForComplete()
2072 Pa
.CreateMakeFile(False)
2073 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2074 # Start task scheduler
2075 if not BuildTask
.IsOnGoing():
2076 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
2078 # in case there's an interruption. we need a full version of makefile for platform
2079 Pa
.CreateMakeFile(False)
2080 if BuildTask
.HasError():
2081 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2082 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
2084 MakeContiue
= time
.time()
2086 # Save temp tables to a TmpTableDict.
2088 for Key
in Wa
.BuildDatabase
._CACHE
_:
2089 if Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
and Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
._Table
and Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
._Table
.Table
:
2090 if TemporaryTablePattern
.match(Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
._Table
.Table
):
2091 TmpTableDict
[Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
._Table
.Table
] = Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
._Table
.Cur
2094 # All modules have been put in build tasks queue. Tell task scheduler
2095 # to exit if all tasks are completed
2098 BuildTask
.WaitForComplete()
2099 self
.CreateAsBuiltInf()
2100 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2102 # Check for build error, and raise exception if one
2103 # has been signaled.
2105 if BuildTask
.HasError():
2106 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2108 # Create MAP file when Load Fix Address is enabled.
2109 if self
.Target
in ["", "all", "fds"]:
2110 for Arch
in Wa
.ArchList
:
2112 # Check whether the set fix address is above 4G for 32bit image.
2114 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2115 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")
2120 for Pa
in Wa
.AutoGenObjectList
:
2121 for Ma
in Pa
.ModuleAutoGenList
:
2124 if not Ma
.IsLibrary
:
2125 ModuleList
[Ma
.Guid
.upper()] = Ma
2127 # Rebase module to the preferred memory address before GenFds
2129 MapBuffer
= BytesIO('')
2130 if self
.LoadFixAddress
!= 0:
2131 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2135 # Generate FD image if there's a FDF file found
2137 GenFdsStart
= time
.time()
2138 LaunchCommand(Wa
.GenFdsCommand
, os
.getcwd())
2141 # Create MAP file for all platform FVs after GenFds.
2143 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2144 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2146 # Save MAP buffer into MAP file.
2148 self
._SaveMapFile
(MapBuffer
, Wa
)
2150 ## Generate GuidedSectionTools.txt in the FV directories.
2152 def CreateGuidedSectionToolsFile(self
):
2153 for BuildTarget
in self
.BuildTargetList
:
2154 for ToolChain
in self
.ToolChainList
:
2155 Wa
= WorkspaceAutoGen(
2172 if not os
.path
.exists(FvDir
):
2175 for Arch
in self
.ArchList
:
2176 # Build up the list of supported architectures for this build
2177 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
2179 # Look through the tool definitions for GUIDed tools
2181 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.iteritems():
2182 if attrib
.upper().endswith('_GUID'):
2183 split
= attrib
.split('_')
2184 thisPrefix
= '_'.join(split
[0:3]) + '_'
2185 if thisPrefix
== prefix
:
2186 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
2189 path
= '_'.join(split
[0:4]) + '_PATH'
2190 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2191 path
= self
.GetFullPathOfTool(path
)
2192 guidAttribs
.append((guid
, toolName
, path
))
2194 # Write out GuidedSecTools.txt
2195 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2196 toolsFile
= open(toolsFile
, 'wt')
2197 for guidedSectionTool
in guidAttribs
:
2198 print(' '.join(guidedSectionTool
), file=toolsFile
)
2201 ## Returns the full path of the tool.
2203 def GetFullPathOfTool (self
, tool
):
2204 if os
.path
.exists(tool
):
2205 return os
.path
.realpath(tool
)
2207 # We need to search for the tool using the
2208 # PATH environment variable.
2209 for dirInPath
in os
.environ
['PATH'].split(os
.pathsep
):
2210 foundPath
= os
.path
.join(dirInPath
, tool
)
2211 if os
.path
.exists(foundPath
):
2212 return os
.path
.realpath(foundPath
)
2214 # If the tool was not found in the path then we just return
2218 ## Launch the module or platform build
2221 if not self
.ModuleFile
:
2222 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2223 self
.SpawnMode
= False
2224 self
._BuildPlatform
()
2226 self
._MultiThreadBuildPlatform
()
2227 self
.CreateGuidedSectionToolsFile()
2229 self
.SpawnMode
= False
2232 if self
.Target
== 'cleanall':
2234 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2236 def CreateAsBuiltInf(self
):
2237 for Module
in self
.BuildModules
:
2238 Module
.CreateAsBuiltInf()
2239 for Module
in self
.HashSkipModules
:
2240 Module
.CreateAsBuiltInf(True)
2241 self
.BuildModules
= []
2242 self
.HashSkipModules
= []
2243 ## Do some clean-up works when error occurred
2244 def Relinquish(self
):
2245 OldLogLevel
= EdkLogger
.GetLevel()
2246 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2247 #self.DumpBuildData()
2248 Utils
.Progressor
.Abort()
2249 if self
.SpawnMode
== True:
2251 EdkLogger
.SetLevel(OldLogLevel
)
2253 def DumpBuildData(self
):
2254 CacheDirectory
= os
.path
.dirname(GlobalData
.gDatabasePath
)
2255 Utils
.CreateDirectory(CacheDirectory
)
2256 Utils
.DataDump(Utils
.gFileTimeStampCache
, os
.path
.join(CacheDirectory
, "gFileTimeStampCache"))
2257 Utils
.DataDump(Utils
.gDependencyDatabase
, os
.path
.join(CacheDirectory
, "gDependencyDatabase"))
2259 def RestoreBuildData(self
):
2260 FilePath
= os
.path
.join(os
.path
.dirname(GlobalData
.gDatabasePath
), "gFileTimeStampCache")
2261 if Utils
.gFileTimeStampCache
== {} and os
.path
.isfile(FilePath
):
2262 Utils
.gFileTimeStampCache
= Utils
.DataRestore(FilePath
)
2263 if Utils
.gFileTimeStampCache
is None:
2264 Utils
.gFileTimeStampCache
= {}
2266 FilePath
= os
.path
.join(os
.path
.dirname(GlobalData
.gDatabasePath
), "gDependencyDatabase")
2267 if Utils
.gDependencyDatabase
== {} and os
.path
.isfile(FilePath
):
2268 Utils
.gDependencyDatabase
= Utils
.DataRestore(FilePath
)
2269 if Utils
.gDependencyDatabase
is None:
2270 Utils
.gDependencyDatabase
= {}
2272 def ParseDefines(DefineList
=[]):
2274 if DefineList
is not None:
2275 for Define
in DefineList
:
2276 DefineTokenList
= Define
.split("=", 1)
2277 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2278 EdkLogger
.error('build', FORMAT_INVALID
,
2279 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2280 ExtraData
=DefineTokenList
[0])
2282 if len(DefineTokenList
) == 1:
2283 DefineDict
[DefineTokenList
[0]] = "TRUE"
2285 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2289 def SingleCheckCallback(option
, opt_str
, value
, parser
):
2290 if option
not in gParamCheck
:
2291 setattr(parser
.values
, option
.dest
, value
)
2292 gParamCheck
.append(option
)
2294 parser
.error("Option %s only allows one instance in command line!" % option
)
2296 def LogBuildTime(Time
):
2299 TimeDur
= time
.gmtime(Time
)
2300 if TimeDur
.tm_yday
> 1:
2301 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2303 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2308 ## Parse command line options
2310 # Using standard Python module optparse to parse command line option of this tool.
2312 # @retval Opt A optparse.Values object containing the parsed options
2313 # @retval Args Target of build command
2315 def MyOptionParser():
2316 Parser
= OptionParser(description
=__copyright__
, version
=__version__
, prog
="build.exe", usage
="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
2317 Parser
.add_option("-a", "--arch", action
="append", type="choice", choices
=['IA32', 'X64', 'IPF', 'EBC', 'ARM', 'AARCH64'], dest
="TargetArch",
2318 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.")
2319 Parser
.add_option("-p", "--platform", action
="callback", type="string", dest
="PlatformFile", callback
=SingleCheckCallback
,
2320 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
2321 Parser
.add_option("-m", "--module", action
="callback", type="string", dest
="ModuleFile", callback
=SingleCheckCallback
,
2322 help="Build the module specified by the INF file name argument.")
2323 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
2325 Parser
.add_option("-t", "--tagname", action
="append", type="string", dest
="ToolChain",
2326 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
2327 Parser
.add_option("-x", "--sku-id", action
="callback", type="string", dest
="SkuId", callback
=SingleCheckCallback
,
2328 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
2330 Parser
.add_option("-n", action
="callback", type="int", dest
="ThreadNumber", callback
=SingleCheckCallback
,
2331 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 "\
2332 "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.")
2334 Parser
.add_option("-f", "--fdf", action
="callback", type="string", dest
="FdfFile", callback
=SingleCheckCallback
,
2335 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
2336 Parser
.add_option("-r", "--rom-image", action
="append", type="string", dest
="RomImage", default
=[],
2337 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
2338 Parser
.add_option("-i", "--fv-image", action
="append", type="string", dest
="FvImage", default
=[],
2339 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
2340 Parser
.add_option("-C", "--capsule-image", action
="append", type="string", dest
="CapName", default
=[],
2341 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
2342 Parser
.add_option("-u", "--skip-autogen", action
="store_true", dest
="SkipAutoGen", help="Skip AutoGen step.")
2343 Parser
.add_option("-e", "--re-parse", action
="store_true", dest
="Reparse", help="Re-parse all meta-data files.")
2345 Parser
.add_option("-c", "--case-insensitive", action
="store_true", dest
="CaseInsensitive", default
=False, help="Don't check case of file name.")
2347 Parser
.add_option("-w", "--warning-as-error", action
="store_true", dest
="WarningAsError", help="Treat warning in tools as error.")
2348 Parser
.add_option("-j", "--log", action
="store", dest
="LogFile", help="Put log in specified file as well as on console.")
2350 Parser
.add_option("-s", "--silent", action
="store_true", type=None, dest
="SilentMode",
2351 help="Make use of silent mode of (n)make.")
2352 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
2353 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
2354 "including library instances selected, final dependency expression, "\
2355 "and warning messages, etc.")
2356 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
2357 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
2359 Parser
.add_option("-y", "--report-file", action
="store", dest
="ReportFile", help="Create/overwrite the report to the specified filename.")
2360 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
=[],
2361 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]. "\
2362 "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]")
2363 Parser
.add_option("-F", "--flag", action
="store", type="string", dest
="Flag",
2364 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. "\
2365 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
2366 "will override the setting in [BuildOptions] section of platform DSC.")
2367 Parser
.add_option("-N", "--no-cache", action
="store_true", dest
="DisableCache", default
=False, help="Disable build cache mechanism")
2368 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
2369 Parser
.add_option("--check-usage", action
="store_true", dest
="CheckUsage", default
=False, help="Check usage content of entries listed in INF file.")
2370 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
2371 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
2372 Parser
.add_option("-l", "--cmd-len", action
="store", type="int", dest
="CommandLength", help="Specify the maximum line length of build command. Default is 4096.")
2373 Parser
.add_option("--hash", action
="store_true", dest
="UseHashCache", default
=False, help="Enable hash-based caching during build process.")
2374 Parser
.add_option("--binary-destination", action
="store", type="string", dest
="BinCacheDest", help="Generate a cache of binary files in the specified directory.")
2375 Parser
.add_option("--binary-source", action
="store", type="string", dest
="BinCacheSource", help="Consume a cache of binary files from the specified directory.")
2376 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
2377 (Opt
, Args
) = Parser
.parse_args()
2380 ## Tool entrance method
2382 # This method mainly dispatch specific methods per the command line options.
2383 # If no error found, return zero value so the caller of this tool can know
2384 # if it's executed successfully or not.
2386 # @retval 0 Tool was successful
2387 # @retval 1 Tool failed
2390 StartTime
= time
.time()
2392 # Initialize log system
2393 EdkLogger
.Initialize()
2394 GlobalData
.gCommand
= sys
.argv
[1:]
2396 # Parse the options and args
2398 (Option
, Target
) = MyOptionParser()
2399 GlobalData
.gOptions
= Option
2400 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2403 if Option
.verbose
is not None:
2404 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2405 elif Option
.quiet
is not None:
2406 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2407 elif Option
.debug
is not None:
2408 EdkLogger
.SetLevel(Option
.debug
+ 1)
2410 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2412 if Option
.LogFile
is not None:
2413 EdkLogger
.SetLogFile(Option
.LogFile
)
2415 if Option
.WarningAsError
== True:
2416 EdkLogger
.SetWarningAsError()
2418 if platform
.platform().find("Windows") >= 0:
2419 GlobalData
.gIsWindows
= True
2421 GlobalData
.gIsWindows
= False
2423 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2424 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2429 if len(Target
) == 0:
2431 elif len(Target
) >= 2:
2432 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2433 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2435 Target
= Target
[0].lower()
2437 if Target
not in gSupportedTarget
:
2438 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2439 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2442 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2445 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2447 Workspace
= os
.getenv("WORKSPACE")
2449 # Get files real name in workspace dir
2451 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2453 WorkingDirectory
= os
.getcwd()
2454 if not Option
.ModuleFile
:
2455 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2456 FileNum
= len(FileList
)
2458 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2459 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2461 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2463 if Option
.ModuleFile
:
2464 if os
.path
.isabs (Option
.ModuleFile
):
2465 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2466 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2467 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2468 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2470 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2472 if Option
.PlatformFile
is not None:
2473 if os
.path
.isabs (Option
.PlatformFile
):
2474 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2475 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2476 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2478 if Option
.FdfFile
is not None:
2479 if os
.path
.isabs (Option
.FdfFile
):
2480 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2481 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2482 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2483 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2485 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2487 if Option
.Flag
is not None and Option
.Flag
not in ['-c', '-s']:
2488 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2490 MyBuild
= Build(Target
, Workspace
, Option
)
2491 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2492 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2494 # Drop temp tables to avoid database locked.
2495 for TmpTableName
in TmpTableDict
:
2496 SqlCommand
= """drop table IF EXISTS %s""" % TmpTableName
2497 TmpTableDict
[TmpTableName
].execute(SqlCommand
)
2498 #MyBuild.DumpBuildData()
2500 # All job done, no error found and no exception raised
2503 except FatalError
as X
:
2504 if MyBuild
is not None:
2505 # for multi-thread build exits safely
2506 MyBuild
.Relinquish()
2507 if Option
is not None and Option
.debug
is not None:
2508 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2509 ReturnCode
= X
.args
[0]
2510 except Warning as X
:
2511 # error from Fdf parser
2512 if MyBuild
is not None:
2513 # for multi-thread build exits safely
2514 MyBuild
.Relinquish()
2515 if Option
is not None and Option
.debug
is not None:
2516 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2518 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2519 ReturnCode
= FORMAT_INVALID
2520 except KeyboardInterrupt:
2521 ReturnCode
= ABORT_ERROR
2522 if Option
is not None and Option
.debug
is not None:
2523 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2525 if MyBuild
is not None:
2526 # for multi-thread build exits safely
2527 MyBuild
.Relinquish()
2529 # try to get the meta-file from the object causing exception
2530 Tb
= sys
.exc_info()[-1]
2531 MetaFile
= GlobalData
.gProcessingFile
2532 while Tb
is not None:
2533 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2534 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2539 "Unknown fatal error when processing [%s]" % MetaFile
,
2540 ExtraData
="\n(Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!)\n",
2543 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2544 ReturnCode
= CODE_ERROR
2546 Utils
.Progressor
.Abort()
2547 Utils
.ClearDuplicatedInf()
2551 MyBuild
.LaunchPostbuild()
2554 Conclusion
= "Failed"
2555 elif ReturnCode
== ABORT_ERROR
:
2556 Conclusion
= "Aborted"
2558 Conclusion
= "Failed"
2559 FinishTime
= time
.time()
2560 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2561 BuildDurationStr
= ""
2562 if BuildDuration
.tm_yday
> 1:
2563 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2565 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2566 if MyBuild
is not None:
2568 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2570 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2571 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2572 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2573 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2576 if __name__
== '__main__':
2578 ## 0-127 is a safe return range, and 1 is a standard default error
2579 if r
< 0 or r
> 127: r
= 1