2 # build a platform or a module
4 # Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
5 # Copyright (c) 2007 - 2017, 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
27 import encodings
.ascii
31 from threading
import *
32 from optparse
import OptionParser
33 from subprocess
import *
34 from Common
import Misc
as Utils
36 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
37 from Common
.LongFilePathSupport
import LongFilePath
38 from Common
.TargetTxtClassObject
import *
39 from Common
.ToolDefClassObject
import *
40 from Common
.DataType
import *
41 from Common
.BuildVersion
import gBUILD_VERSION
42 from AutoGen
.AutoGen
import *
43 from Common
.BuildToolError
import *
44 from Workspace
.WorkspaceDatabase
import *
45 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
47 from BuildReport
import BuildReport
48 from GenPatchPcdTable
.GenPatchPcdTable
import *
49 from PatchPcdValue
.PatchPcdValue
import *
51 import Common
.EdkLogger
52 import Common
.GlobalData
as GlobalData
54 # Version and Copyright
55 VersionNumber
= "0.60" + ' ' + gBUILD_VERSION
56 __version__
= "%prog Version " + VersionNumber
57 __copyright__
= "Copyright (c) 2007 - 2017, Intel Corporation All rights reserved."
59 ## standard targets of build command
60 gSupportedTarget
= ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
62 ## build configuration file
63 gBuildConfiguration
= "target.txt"
64 gToolsDefinition
= "tools_def.txt"
66 TemporaryTablePattern
= re
.compile(r
'^_\d+_\d+_[a-fA-F0-9]+$')
69 ## Check environment PATH variable to make sure the specified tool is found
71 # If the tool is found in the PATH, then True is returned
72 # Otherwise, False is returned
74 def IsToolInPath(tool
):
75 if os
.environ
.has_key('PATHEXT'):
76 extns
= os
.environ
['PATHEXT'].split(os
.path
.pathsep
)
79 for pathDir
in os
.environ
['PATH'].split(os
.path
.pathsep
):
81 if os
.path
.exists(os
.path
.join(pathDir
, tool
+ ext
)):
85 ## Check environment variables
87 # Check environment variables that must be set for build. Currently they are
89 # WORKSPACE The directory all packages/platforms start from
90 # EDK_TOOLS_PATH The directory contains all tools needed by the build
91 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
93 # If any of above environment variable is not set or has error, the build
96 def CheckEnvVariable():
98 if "WORKSPACE" not in os
.environ
:
99 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
100 ExtraData
="WORKSPACE")
102 WorkspaceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["WORKSPACE"]))
103 if not os
.path
.exists(WorkspaceDir
):
104 EdkLogger
.error("build", FILE_NOT_FOUND
, "WORKSPACE doesn't exist", ExtraData
="%s" % WorkspaceDir
)
105 elif ' ' in WorkspaceDir
:
106 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in WORKSPACE path",
107 ExtraData
=WorkspaceDir
)
108 os
.environ
["WORKSPACE"] = WorkspaceDir
110 # set multiple workspace
111 PackagesPath
= os
.getenv("PACKAGES_PATH")
112 mws
.setWs(WorkspaceDir
, PackagesPath
)
113 if mws
.PACKAGES_PATH
:
114 for Path
in mws
.PACKAGES_PATH
:
115 if not os
.path
.exists(Path
):
116 EdkLogger
.error("build", FILE_NOT_FOUND
, "One Path in PACKAGES_PATH doesn't exist", ExtraData
="%s" % Path
)
118 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in PACKAGES_PATH", ExtraData
=Path
)
121 # Check EFI_SOURCE (Edk build convention). EDK_SOURCE will always point to ECP
123 if "ECP_SOURCE" not in os
.environ
:
124 os
.environ
["ECP_SOURCE"] = mws
.join(WorkspaceDir
, GlobalData
.gEdkCompatibilityPkg
)
125 if "EFI_SOURCE" not in os
.environ
:
126 os
.environ
["EFI_SOURCE"] = os
.environ
["ECP_SOURCE"]
127 if "EDK_SOURCE" not in os
.environ
:
128 os
.environ
["EDK_SOURCE"] = os
.environ
["ECP_SOURCE"]
131 # Unify case of characters on case-insensitive systems
133 EfiSourceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["EFI_SOURCE"]))
134 EdkSourceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_SOURCE"]))
135 EcpSourceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["ECP_SOURCE"]))
137 os
.environ
["EFI_SOURCE"] = EfiSourceDir
138 os
.environ
["EDK_SOURCE"] = EdkSourceDir
139 os
.environ
["ECP_SOURCE"] = EcpSourceDir
140 os
.environ
["EDK_TOOLS_PATH"] = os
.path
.normcase(os
.environ
["EDK_TOOLS_PATH"])
142 if not os
.path
.exists(EcpSourceDir
):
143 EdkLogger
.verbose("ECP_SOURCE = %s doesn't exist. Edk modules could not be built." % EcpSourceDir
)
144 elif ' ' in EcpSourceDir
:
145 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in ECP_SOURCE path",
146 ExtraData
=EcpSourceDir
)
147 if not os
.path
.exists(EdkSourceDir
):
148 if EdkSourceDir
== EcpSourceDir
:
149 EdkLogger
.verbose("EDK_SOURCE = %s doesn't exist. Edk modules could not be built." % EdkSourceDir
)
151 EdkLogger
.error("build", PARAMETER_INVALID
, "EDK_SOURCE does not exist",
152 ExtraData
=EdkSourceDir
)
153 elif ' ' in EdkSourceDir
:
154 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in EDK_SOURCE path",
155 ExtraData
=EdkSourceDir
)
156 if not os
.path
.exists(EfiSourceDir
):
157 if EfiSourceDir
== EcpSourceDir
:
158 EdkLogger
.verbose("EFI_SOURCE = %s doesn't exist. Edk modules could not be built." % EfiSourceDir
)
160 EdkLogger
.error("build", PARAMETER_INVALID
, "EFI_SOURCE does not exist",
161 ExtraData
=EfiSourceDir
)
162 elif ' ' in EfiSourceDir
:
163 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in EFI_SOURCE path",
164 ExtraData
=EfiSourceDir
)
166 # check those variables on single workspace case
168 # change absolute path to relative path to WORKSPACE
169 if EfiSourceDir
.upper().find(WorkspaceDir
.upper()) != 0:
170 EdkLogger
.error("build", PARAMETER_INVALID
, "EFI_SOURCE is not under WORKSPACE",
171 ExtraData
="WORKSPACE = %s\n EFI_SOURCE = %s" % (WorkspaceDir
, EfiSourceDir
))
172 if EdkSourceDir
.upper().find(WorkspaceDir
.upper()) != 0:
173 EdkLogger
.error("build", PARAMETER_INVALID
, "EDK_SOURCE is not under WORKSPACE",
174 ExtraData
="WORKSPACE = %s\n EDK_SOURCE = %s" % (WorkspaceDir
, EdkSourceDir
))
175 if EcpSourceDir
.upper().find(WorkspaceDir
.upper()) != 0:
176 EdkLogger
.error("build", PARAMETER_INVALID
, "ECP_SOURCE is not under WORKSPACE",
177 ExtraData
="WORKSPACE = %s\n ECP_SOURCE = %s" % (WorkspaceDir
, EcpSourceDir
))
179 # check EDK_TOOLS_PATH
180 if "EDK_TOOLS_PATH" not in os
.environ
:
181 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
182 ExtraData
="EDK_TOOLS_PATH")
185 if "PATH" not in os
.environ
:
186 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
189 GlobalData
.gWorkspace
= WorkspaceDir
190 GlobalData
.gEfiSource
= EfiSourceDir
191 GlobalData
.gEdkSource
= EdkSourceDir
192 GlobalData
.gEcpSource
= EcpSourceDir
194 GlobalData
.gGlobalDefines
["WORKSPACE"] = WorkspaceDir
195 GlobalData
.gGlobalDefines
["EFI_SOURCE"] = EfiSourceDir
196 GlobalData
.gGlobalDefines
["EDK_SOURCE"] = EdkSourceDir
197 GlobalData
.gGlobalDefines
["ECP_SOURCE"] = EcpSourceDir
198 GlobalData
.gGlobalDefines
["EDK_TOOLS_PATH"] = os
.environ
["EDK_TOOLS_PATH"]
200 ## Get normalized file path
202 # Convert the path to be local format, and remove the WORKSPACE path at the
203 # beginning if the file path is given in full path.
205 # @param FilePath File path to be normalized
206 # @param Workspace Workspace path which the FilePath will be checked against
208 # @retval string The normalized file path
210 def NormFile(FilePath
, Workspace
):
211 # check if the path is absolute or relative
212 if os
.path
.isabs(FilePath
):
213 FileFullPath
= os
.path
.normpath(FilePath
)
215 FileFullPath
= os
.path
.normpath(mws
.join(Workspace
, FilePath
))
216 Workspace
= mws
.getWs(Workspace
, FilePath
)
218 # check if the file path exists or not
219 if not os
.path
.isfile(FileFullPath
):
220 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath
)
222 # remove workspace directory from the beginning part of the file path
223 if Workspace
[-1] in ["\\", "/"]:
224 return FileFullPath
[len(Workspace
):]
226 return FileFullPath
[(len(Workspace
) + 1):]
228 ## Get the output of an external program
230 # This is the entrance method of thread reading output of an external program and
231 # putting them in STDOUT/STDERR of current program.
233 # @param From The stream message read from
234 # @param To The stream message put on
235 # @param ExitFlag The flag used to indicate stopping reading
237 def ReadMessage(From
, To
, ExitFlag
):
239 # read one line a time
240 Line
= From
.readline()
241 # empty string means "end"
242 if Line
!= None and Line
!= "":
249 ## Launch an external program
251 # This method will call subprocess.Popen to execute an external program with
252 # given options in specified directory. Because of the dead-lock issue during
253 # redirecting output of the external program, threads are used to to do the
256 # @param Command A list or string containing the call of the program
257 # @param WorkingDir The directory in which the program will be running
259 def LaunchCommand(Command
, WorkingDir
):
260 BeginTime
= time
.time()
261 # if working directory doesn't exist, Popen() will raise an exception
262 if not os
.path
.isdir(WorkingDir
):
263 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=WorkingDir
)
265 # Command is used as the first Argument in following Popen().
266 # It could be a string or sequence. We find that if command is a string in following Popen(),
267 # ubuntu may fail with an error message that the command is not found.
268 # So here we may need convert command from string to list instance.
269 if platform
.system() != 'Windows':
270 if not isinstance(Command
, list):
271 Command
= Command
.split()
272 Command
= ' '.join(Command
)
275 EndOfProcedure
= None
278 Proc
= Popen(Command
, stdout
=PIPE
, stderr
=PIPE
, env
=os
.environ
, cwd
=WorkingDir
, bufsize
=-1, shell
=True)
280 # launch two threads to read the STDOUT and STDERR
281 EndOfProcedure
= Event()
282 EndOfProcedure
.clear()
284 StdOutThread
= Thread(target
=ReadMessage
, args
=(Proc
.stdout
, EdkLogger
.info
, EndOfProcedure
))
285 StdOutThread
.setName("STDOUT-Redirector")
286 StdOutThread
.setDaemon(False)
290 StdErrThread
= Thread(target
=ReadMessage
, args
=(Proc
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
291 StdErrThread
.setName("STDERR-Redirector")
292 StdErrThread
.setDaemon(False)
295 # waiting for program exit
297 except: # in case of aborting
298 # terminate the threads redirecting the program output
299 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
300 if EndOfProcedure
!= None:
303 if type(Command
) != type(""):
304 Command
= " ".join(Command
)
305 EdkLogger
.error("build", COMMAND_FAILURE
, "Failed to start command", ExtraData
="%s [%s]" % (Command
, WorkingDir
))
312 # check the return code of the program
313 if Proc
.returncode
!= 0:
314 if type(Command
) != type(""):
315 Command
= " ".join(Command
)
316 # print out the Response file and its content when make failure
317 RespFile
= os
.path
.join(WorkingDir
, 'OUTPUT', 'respfilelist.txt')
318 if os
.path
.isfile(RespFile
):
320 RespContent
= f
.read()
322 EdkLogger
.info(RespContent
)
324 EdkLogger
.error("build", COMMAND_FAILURE
, ExtraData
="%s [%s]" % (Command
, WorkingDir
))
325 return "%dms" % (int(round((time
.time() - BeginTime
) * 1000)))
327 ## The smallest unit that can be built in multi-thread build mode
329 # This is the base class of build unit. The "Obj" parameter must provide
330 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
333 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
338 # @param self The object pointer
339 # @param Obj The object the build is working on
340 # @param Target The build target name, one of gSupportedTarget
341 # @param Dependency The BuildUnit(s) which must be completed in advance
342 # @param WorkingDir The directory build command starts in
344 def __init__(self
, Obj
, BuildCommand
, Target
, Dependency
, WorkingDir
="."):
345 self
.BuildObject
= Obj
346 self
.Dependency
= Dependency
347 self
.WorkingDir
= WorkingDir
349 self
.BuildCommand
= BuildCommand
351 EdkLogger
.error("build", OPTION_MISSING
,
352 "No build command found for this module. "
353 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
354 (Obj
.BuildTarget
, Obj
.ToolChain
, Obj
.Arch
),
360 # It just returns the string representation of self.BuildObject
362 # @param self The object pointer
365 return str(self
.BuildObject
)
367 ## "==" operator method
369 # It just compares self.BuildObject with "Other". So self.BuildObject must
370 # provide its own __eq__() method.
372 # @param self The object pointer
373 # @param Other The other BuildUnit object compared to
375 def __eq__(self
, Other
):
376 return Other
!= None and self
.BuildObject
== Other
.BuildObject \
377 and self
.BuildObject
.Arch
== Other
.BuildObject
.Arch
381 # It just returns the hash value of self.BuildObject which must be hashable.
383 # @param self The object pointer
386 return hash(self
.BuildObject
) + hash(self
.BuildObject
.Arch
)
389 return repr(self
.BuildObject
)
391 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
393 # This class is for module build by nmake/make build system. The "Obj" parameter
394 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
395 # be make units missing build.
397 # Currently the "Obj" should be only ModuleAutoGen object.
399 class ModuleMakeUnit(BuildUnit
):
402 # @param self The object pointer
403 # @param Obj The ModuleAutoGen object the build is working on
404 # @param Target The build target name, one of gSupportedTarget
406 def __init__(self
, Obj
, Target
):
407 Dependency
= [ModuleMakeUnit(La
, Target
) for La
in Obj
.LibraryAutoGenList
]
408 BuildUnit
.__init
__(self
, Obj
, Obj
.BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
409 if Target
in [None, "", "all"]:
410 self
.Target
= "tbuild"
412 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
414 # This class is for platform build by nmake/make build system. The "Obj" parameter
415 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
416 # be make units missing build.
418 # Currently the "Obj" should be only PlatformAutoGen object.
420 class PlatformMakeUnit(BuildUnit
):
423 # @param self The object pointer
424 # @param Obj The PlatformAutoGen object the build is working on
425 # @param Target The build target name, one of gSupportedTarget
427 def __init__(self
, Obj
, Target
):
428 Dependency
= [ModuleMakeUnit(Lib
, Target
) for Lib
in self
.BuildObject
.LibraryAutoGenList
]
429 Dependency
.extend([ModuleMakeUnit(Mod
, Target
) for Mod
in self
.BuildObject
.ModuleAutoGenList
])
430 BuildUnit
.__init
__(self
, Obj
, Obj
.BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
432 ## The class representing the task of a module build or platform build
434 # This class manages the build tasks in multi-thread build mode. Its jobs include
435 # scheduling thread running, catching thread error, monitor the thread status, etc.
438 # queue for tasks waiting for schedule
439 _PendingQueue
= sdict()
440 _PendingQueueLock
= threading
.Lock()
442 # queue for tasks ready for running
443 _ReadyQueue
= sdict()
444 _ReadyQueueLock
= threading
.Lock()
446 # queue for run tasks
447 _RunningQueue
= sdict()
448 _RunningQueueLock
= threading
.Lock()
450 # queue containing all build tasks, in case duplicate build
453 # flag indicating error occurs in a running thread
454 _ErrorFlag
= threading
.Event()
458 # BoundedSemaphore object used to control the number of running threads
461 # flag indicating if the scheduler is started or not
462 _SchedulerStopped
= threading
.Event()
463 _SchedulerStopped
.set()
465 ## Start the task scheduler thread
467 # @param MaxThreadNumber The maximum thread number
468 # @param ExitFlag Flag used to end the scheduler
471 def StartScheduler(MaxThreadNumber
, ExitFlag
):
472 SchedulerThread
= Thread(target
=BuildTask
.Scheduler
, args
=(MaxThreadNumber
, ExitFlag
))
473 SchedulerThread
.setName("Build-Task-Scheduler")
474 SchedulerThread
.setDaemon(False)
475 SchedulerThread
.start()
476 # wait for the scheduler to be started, especially useful in Linux
477 while not BuildTask
.IsOnGoing():
482 # @param MaxThreadNumber The maximum thread number
483 # @param ExitFlag Flag used to end the scheduler
486 def Scheduler(MaxThreadNumber
, ExitFlag
):
487 BuildTask
._SchedulerStopped
.clear()
489 # use BoundedSemaphore to control the maximum running threads
490 BuildTask
._Thread
= BoundedSemaphore(MaxThreadNumber
)
492 # scheduling loop, which will exits when no pending/ready task and
493 # indicated to do so, or there's error in running thread
495 while (len(BuildTask
._PendingQueue
) > 0 or len(BuildTask
._ReadyQueue
) > 0 \
496 or not ExitFlag
.isSet()) and not BuildTask
._ErrorFlag
.isSet():
497 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Pending Queue (%d), Ready Queue (%d)"
498 % (len(BuildTask
._PendingQueue
), len(BuildTask
._ReadyQueue
)))
500 # get all pending tasks
501 BuildTask
._PendingQueueLock
.acquire()
502 BuildObjectList
= BuildTask
._PendingQueue
.keys()
504 # check if their dependency is resolved, and if true, move them
507 for BuildObject
in BuildObjectList
:
508 Bt
= BuildTask
._PendingQueue
[BuildObject
]
510 BuildTask
._ReadyQueue
[BuildObject
] = BuildTask
._PendingQueue
.pop(BuildObject
)
511 BuildTask
._PendingQueueLock
.release()
513 # launch build thread until the maximum number of threads is reached
514 while not BuildTask
._ErrorFlag
.isSet():
515 # empty ready queue, do nothing further
516 if len(BuildTask
._ReadyQueue
) == 0:
519 # wait for active thread(s) exit
520 BuildTask
._Thread
.acquire(True)
522 # start a new build thread
523 Bo
= BuildTask
._ReadyQueue
.keys()[0]
524 Bt
= BuildTask
._ReadyQueue
.pop(Bo
)
526 # move into running queue
527 BuildTask
._RunningQueueLock
.acquire()
528 BuildTask
._RunningQueue
[Bo
] = Bt
529 BuildTask
._RunningQueueLock
.release()
538 # wait for all running threads exit
539 if BuildTask
._ErrorFlag
.isSet():
540 EdkLogger
.quiet("\nWaiting for all build threads exit...")
541 # while not BuildTask._ErrorFlag.isSet() and \
542 while len(BuildTask
._RunningQueue
) > 0:
543 EdkLogger
.verbose("Waiting for thread ending...(%d)" % len(BuildTask
._RunningQueue
))
544 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Threads [%s]" % ", ".join([Th
.getName() for Th
in threading
.enumerate()]))
547 except BaseException
, X
:
549 # TRICK: hide the output of threads left runing, so that the user can
550 # catch the error message easily
552 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
553 BuildTask
._ErrorFlag
.set()
554 BuildTask
._ErrorMessage
= "build thread scheduler error\n\t%s" % str(X
)
556 BuildTask
._PendingQueue
.clear()
557 BuildTask
._ReadyQueue
.clear()
558 BuildTask
._RunningQueue
.clear()
559 BuildTask
._TaskQueue
.clear()
560 BuildTask
._SchedulerStopped
.set()
562 ## Wait for all running method exit
565 def WaitForComplete():
566 BuildTask
._SchedulerStopped
.wait()
568 ## Check if the scheduler is running or not
572 return not BuildTask
._SchedulerStopped
.isSet()
577 if BuildTask
.IsOnGoing():
578 BuildTask
._ErrorFlag
.set()
579 BuildTask
.WaitForComplete()
581 ## Check if there's error in running thread
583 # Since the main thread cannot catch exceptions in other thread, we have to
584 # use threading.Event to communicate this formation to main thread.
588 return BuildTask
._ErrorFlag
.isSet()
590 ## Get error message in running thread
592 # Since the main thread cannot catch exceptions in other thread, we have to
593 # use a static variable to communicate this message to main thread.
596 def GetErrorMessage():
597 return BuildTask
._ErrorMessage
599 ## Factory method to create a BuildTask object
601 # This method will check if a module is building or has been built. And if
602 # true, just return the associated BuildTask object in the _TaskQueue. If
603 # not, create and return a new BuildTask object. The new BuildTask object
604 # will be appended to the _PendingQueue for scheduling later.
606 # @param BuildItem A BuildUnit object representing a build object
607 # @param Dependency The dependent build object of BuildItem
610 def New(BuildItem
, Dependency
=None):
611 if BuildItem
in BuildTask
._TaskQueue
:
612 Bt
= BuildTask
._TaskQueue
[BuildItem
]
616 Bt
._Init
(BuildItem
, Dependency
)
617 BuildTask
._TaskQueue
[BuildItem
] = Bt
619 BuildTask
._PendingQueueLock
.acquire()
620 BuildTask
._PendingQueue
[BuildItem
] = Bt
621 BuildTask
._PendingQueueLock
.release()
625 ## The real constructor of BuildTask
627 # @param BuildItem A BuildUnit object representing a build object
628 # @param Dependency The dependent build object of BuildItem
630 def _Init(self
, BuildItem
, Dependency
=None):
631 self
.BuildItem
= BuildItem
633 self
.DependencyList
= []
634 if Dependency
== None:
635 Dependency
= BuildItem
.Dependency
637 Dependency
.extend(BuildItem
.Dependency
)
638 self
.AddDependency(Dependency
)
639 # flag indicating build completes, used to avoid unnecessary re-build
640 self
.CompleteFlag
= False
642 ## Check if all dependent build tasks are completed or not
646 for Dep
in self
.DependencyList
:
647 if Dep
.CompleteFlag
== True:
654 ## Add dependent build task
656 # @param Dependency The list of dependent build objects
658 def AddDependency(self
, Dependency
):
659 for Dep
in Dependency
:
660 if not Dep
.BuildObject
.IsBinaryModule
:
661 self
.DependencyList
.append(BuildTask
.New(Dep
)) # BuildTask list
663 ## The thread wrapper of LaunchCommand function
665 # @param Command A list or string contains the call of the command
666 # @param WorkingDir The directory in which the program will be running
668 def _CommandThread(self
, Command
, WorkingDir
):
670 self
.BuildItem
.BuildObject
.BuildTime
= LaunchCommand(Command
, WorkingDir
)
671 self
.CompleteFlag
= True
674 # TRICK: hide the output of threads left runing, so that the user can
675 # catch the error message easily
677 if not BuildTask
._ErrorFlag
.isSet():
678 GlobalData
.gBuildingModule
= "%s [%s, %s, %s]" % (str(self
.BuildItem
.BuildObject
),
679 self
.BuildItem
.BuildObject
.Arch
,
680 self
.BuildItem
.BuildObject
.ToolChain
,
681 self
.BuildItem
.BuildObject
.BuildTarget
683 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
684 BuildTask
._ErrorFlag
.set()
685 BuildTask
._ErrorMessage
= "%s broken\n %s [%s]" % \
686 (threading
.currentThread().getName(), Command
, WorkingDir
)
687 # indicate there's a thread is available for another build task
688 BuildTask
._RunningQueueLock
.acquire()
689 BuildTask
._RunningQueue
.pop(self
.BuildItem
)
690 BuildTask
._RunningQueueLock
.release()
691 BuildTask
._Thread
.release()
693 ## Start build task thread
696 EdkLogger
.quiet("Building ... %s" % repr(self
.BuildItem
))
697 Command
= self
.BuildItem
.BuildCommand
+ [self
.BuildItem
.Target
]
698 self
.BuildTread
= Thread(target
=self
._CommandThread
, args
=(Command
, self
.BuildItem
.WorkingDir
))
699 self
.BuildTread
.setName("build thread")
700 self
.BuildTread
.setDaemon(False)
701 self
.BuildTread
.start()
703 ## The class contains the information related to EFI image
708 # Constructor will load all required image information.
710 # @param BaseName The full file path of image.
711 # @param Guid The GUID for image.
712 # @param Arch Arch of this image.
713 # @param OutputDir The output directory for image.
714 # @param DebugDir The debug directory for image.
715 # @param ImageClass PeImage Information
717 def __init__(self
, BaseName
, Guid
, Arch
, OutputDir
, DebugDir
, ImageClass
):
718 self
.BaseName
= BaseName
721 self
.OutputDir
= OutputDir
722 self
.DebugDir
= DebugDir
723 self
.Image
= ImageClass
724 self
.Image
.Size
= (self
.Image
.Size
/ 0x1000 + 1) * 0x1000
726 ## The class implementing the EDK2 build process
728 # The build process includes:
729 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
730 # 2. Parse DSC file of active platform
731 # 3. Parse FDF file if any
732 # 4. Establish build database, including parse all other files (module, package)
733 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
734 # 6. Call build command
739 # Constructor will load all necessary configurations, parse platform, modules
740 # and packages and the establish a database for AutoGen.
742 # @param Target The build command target, one of gSupportedTarget
743 # @param WorkspaceDir The directory of workspace
744 # @param BuildOptions Build options passed from command line
746 def __init__(self
, Target
, WorkspaceDir
, BuildOptions
):
747 self
.WorkspaceDir
= WorkspaceDir
749 self
.PlatformFile
= BuildOptions
.PlatformFile
750 self
.ModuleFile
= BuildOptions
.ModuleFile
751 self
.ArchList
= BuildOptions
.TargetArch
752 self
.ToolChainList
= BuildOptions
.ToolChain
753 self
.BuildTargetList
= BuildOptions
.BuildTarget
754 self
.Fdf
= BuildOptions
.FdfFile
755 self
.FdList
= BuildOptions
.RomImage
756 self
.FvList
= BuildOptions
.FvImage
757 self
.CapList
= BuildOptions
.CapName
758 self
.SilentMode
= BuildOptions
.SilentMode
759 self
.ThreadNumber
= BuildOptions
.ThreadNumber
760 self
.SkipAutoGen
= BuildOptions
.SkipAutoGen
761 self
.Reparse
= BuildOptions
.Reparse
762 self
.SkuId
= BuildOptions
.SkuId
763 self
.ConfDirectory
= BuildOptions
.ConfDirectory
764 self
.SpawnMode
= True
765 self
.BuildReport
= BuildReport(BuildOptions
.ReportFile
, BuildOptions
.ReportType
)
766 self
.TargetTxt
= TargetTxtClassObject()
767 self
.ToolDef
= ToolDefClassObject()
771 GlobalData
.BuildOptionPcd
= BuildOptions
.OptionPcd
772 #Set global flag for build mode
773 GlobalData
.gIgnoreSource
= BuildOptions
.IgnoreSources
775 if self
.ConfDirectory
:
776 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
777 ConfDirectoryPath
= os
.path
.normpath(self
.ConfDirectory
)
779 if not os
.path
.isabs(ConfDirectoryPath
):
780 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
781 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
782 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, ConfDirectoryPath
)
784 if "CONF_PATH" in os
.environ
:
785 ConfDirectoryPath
= os
.path
.normcase(os
.path
.normpath(os
.environ
["CONF_PATH"]))
787 # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf
788 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, 'Conf')
789 GlobalData
.gConfDirectory
= ConfDirectoryPath
790 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
792 if BuildOptions
.DisableCache
:
793 self
.Db
= WorkspaceDatabase(":memory:")
795 self
.Db
= WorkspaceDatabase(GlobalData
.gDatabasePath
, self
.Reparse
)
796 self
.BuildDatabase
= self
.Db
.BuildObject
798 self
.ToolChainFamily
= None
799 self
.LoadFixAddress
= 0
800 self
.UniFlag
= BuildOptions
.Flag
801 self
.BuildModules
= []
803 self
.LaunchPrebuildFlag
= False
804 self
.PlatformBuildPath
= os
.path
.join(GlobalData
.gConfDirectory
,'.cache', '.PlatformBuild')
805 if BuildOptions
.CommandLength
:
806 GlobalData
.gCommandMaxLength
= BuildOptions
.CommandLength
808 # print dot character during doing some time-consuming work
809 self
.Progress
= Utils
.Progressor()
810 # print current build environment and configuration
811 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
812 if "PACKAGES_PATH" in os
.environ
:
813 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
814 EdkLogger
.quiet("%-16s = %s" % ("PACKAGES_PATH", os
.path
.normcase(os
.path
.normpath(os
.environ
["PACKAGES_PATH"]))))
815 EdkLogger
.quiet("%-16s = %s" % ("ECP_SOURCE", os
.environ
["ECP_SOURCE"]))
816 EdkLogger
.quiet("%-16s = %s" % ("EDK_SOURCE", os
.environ
["EDK_SOURCE"]))
817 EdkLogger
.quiet("%-16s = %s" % ("EFI_SOURCE", os
.environ
["EFI_SOURCE"]))
818 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
819 if "EDK_TOOLS_BIN" in os
.environ
:
820 # Print the same path style with WORKSPACE env.
821 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_TOOLS_BIN"]))))
822 EdkLogger
.quiet("%-16s = %s" % ("CONF_PATH", GlobalData
.gConfDirectory
))
826 EdkLogger
.quiet("%-16s = %s" % ("PREBUILD", self
.Prebuild
))
828 EdkLogger
.quiet("%-16s = %s" % ("POSTBUILD", self
.Postbuild
))
830 self
.LaunchPrebuild()
831 self
.TargetTxt
= TargetTxtClassObject()
832 self
.ToolDef
= ToolDefClassObject()
833 if not (self
.LaunchPrebuildFlag
and os
.path
.exists(self
.PlatformBuildPath
)):
837 os
.chdir(self
.WorkspaceDir
)
839 ## Load configuration
841 # This method will parse target.txt and get the build configurations.
843 def LoadConfiguration(self
):
845 # Check target.txt and tools_def.txt and Init them
847 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(GlobalData
.gConfDirectory
, gBuildConfiguration
))
848 if os
.path
.isfile(BuildConfigurationFile
) == True:
849 StatusCode
= self
.TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
851 ToolDefinitionFile
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_CONF
]
852 if ToolDefinitionFile
== '':
853 ToolDefinitionFile
= gToolsDefinition
854 ToolDefinitionFile
= os
.path
.normpath(mws
.join(self
.WorkspaceDir
, 'Conf', ToolDefinitionFile
))
855 if os
.path
.isfile(ToolDefinitionFile
) == True:
856 StatusCode
= self
.ToolDef
.LoadToolDefFile(ToolDefinitionFile
)
858 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=ToolDefinitionFile
)
860 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
862 # if no ARCH given in command line, get it from target.txt
863 if not self
.ArchList
:
864 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TARGET_ARCH
]
865 self
.ArchList
= tuple(self
.ArchList
)
867 # if no build target given in command line, get it from target.txt
868 if not self
.BuildTargetList
:
869 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TARGET
]
871 # if no tool chain given in command line, get it from target.txt
872 if not self
.ToolChainList
:
873 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
874 if self
.ToolChainList
== None or len(self
.ToolChainList
) == 0:
875 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
877 # check if the tool chains are defined or not
878 NewToolChainList
= []
879 for ToolChain
in self
.ToolChainList
:
880 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
881 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
883 NewToolChainList
.append(ToolChain
)
884 # if no tool chain available, break the build
885 if len(NewToolChainList
) == 0:
886 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
887 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
889 self
.ToolChainList
= NewToolChainList
892 ToolDefinition
= self
.ToolDef
.ToolsDefTxtDatabase
893 for Tool
in self
.ToolChainList
:
894 if TAB_TOD_DEFINES_FAMILY
not in ToolDefinition
or Tool
not in ToolDefinition
[TAB_TOD_DEFINES_FAMILY
] \
895 or not ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
]:
896 EdkLogger
.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool
)
897 ToolChainFamily
.append("MSFT")
899 ToolChainFamily
.append(ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
])
900 self
.ToolChainFamily
= ToolChainFamily
902 if self
.ThreadNumber
== None:
903 self
.ThreadNumber
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
904 if self
.ThreadNumber
== '':
905 self
.ThreadNumber
= 0
907 self
.ThreadNumber
= int(self
.ThreadNumber
, 0)
909 if self
.ThreadNumber
== 0:
910 self
.ThreadNumber
= 1
912 if not self
.PlatformFile
:
913 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
915 # Try to find one in current directory
916 WorkingDirectory
= os
.getcwd()
917 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
918 FileNum
= len(FileList
)
920 EdkLogger
.error("build", OPTION_MISSING
,
921 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
923 PlatformFile
= FileList
[0]
925 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
926 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
928 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
930 ## Initialize build configuration
932 # This method will parse DSC file and merge the configurations from
933 # command line and target.txt, then get the final build configurations.
936 # parse target.txt, tools_def.txt, and platform file
937 self
.LoadConfiguration()
939 # Allow case-insensitive for those from command line or configuration file
940 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
942 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
944 # create metafile database
946 self
.Db
.InitDatabase()
948 def InitPreBuild(self
):
949 self
.LoadConfiguration()
950 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
952 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
953 if self
.BuildTargetList
:
954 GlobalData
.gGlobalDefines
['TARGET'] = self
.BuildTargetList
[0]
956 GlobalData
.gGlobalDefines
['ARCH'] = self
.ArchList
[0]
957 if self
.ToolChainList
:
958 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = self
.ToolChainList
[0]
959 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = self
.ToolChainList
[0]
960 if self
.ToolChainFamily
:
961 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[0]
962 if 'PREBUILD' in GlobalData
.gCommandLineDefines
.keys():
963 self
.Prebuild
= GlobalData
.gCommandLineDefines
.get('PREBUILD')
965 self
.Db
.InitDatabase()
967 Platform
= self
.Db
._MapPlatform
(str(self
.PlatformFile
))
968 self
.Prebuild
= str(Platform
.Prebuild
)
972 # Evaluate all arguments and convert arguments that are WORKSPACE
973 # relative paths to absolute paths. Filter arguments that look like
974 # flags or do not follow the file/dir naming rules to avoid false
975 # positives on this conversion.
977 for Arg
in self
.Prebuild
.split():
979 # Do not modify Arg if it looks like a flag or an absolute file path
981 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
982 PrebuildList
.append(Arg
)
985 # Do not modify Arg if it does not look like a Workspace relative
986 # path that starts with a valid package directory name
988 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
989 PrebuildList
.append(Arg
)
992 # If Arg looks like a WORKSPACE relative path, then convert to an
993 # absolute path and check to see if the file exists.
995 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
996 if os
.path
.isfile(Temp
):
998 PrebuildList
.append(Arg
)
999 self
.Prebuild
= ' '.join(PrebuildList
)
1000 self
.Prebuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1002 def InitPostBuild(self
):
1003 if 'POSTBUILD' in GlobalData
.gCommandLineDefines
.keys():
1004 self
.Postbuild
= GlobalData
.gCommandLineDefines
.get('POSTBUILD')
1006 Platform
= self
.Db
._MapPlatform
(str(self
.PlatformFile
))
1007 self
.Postbuild
= str(Platform
.Postbuild
)
1011 # Evaluate all arguments and convert arguments that are WORKSPACE
1012 # relative paths to absolute paths. Filter arguments that look like
1013 # flags or do not follow the file/dir naming rules to avoid false
1014 # positives on this conversion.
1016 for Arg
in self
.Postbuild
.split():
1018 # Do not modify Arg if it looks like a flag or an absolute file path
1020 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1021 PostbuildList
.append(Arg
)
1024 # Do not modify Arg if it does not look like a Workspace relative
1025 # path that starts with a valid package directory name
1027 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1028 PostbuildList
.append(Arg
)
1031 # If Arg looks like a WORKSPACE relative path, then convert to an
1032 # absolute path and check to see if the file exists.
1034 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1035 if os
.path
.isfile(Temp
):
1037 PostbuildList
.append(Arg
)
1038 self
.Postbuild
= ' '.join(PostbuildList
)
1039 self
.Postbuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1041 def PassCommandOption(self
, BuildTarget
, TargetArch
, ToolChain
, PlatformFile
, Target
):
1043 if GlobalData
.gCommand
and isinstance(GlobalData
.gCommand
, list):
1044 BuildStr
+= ' ' + ' '.join(GlobalData
.gCommand
)
1047 ToolChainFlag
= False
1048 PlatformFileFlag
= False
1050 if GlobalData
.gOptions
and not GlobalData
.gOptions
.BuildTarget
:
1052 if GlobalData
.gOptions
and not GlobalData
.gOptions
.TargetArch
:
1054 if GlobalData
.gOptions
and not GlobalData
.gOptions
.ToolChain
:
1055 ToolChainFlag
= True
1056 if GlobalData
.gOptions
and not GlobalData
.gOptions
.PlatformFile
:
1057 PlatformFileFlag
= True
1059 if TargetFlag
and BuildTarget
:
1060 if isinstance(BuildTarget
, list) or isinstance(BuildTarget
, tuple):
1061 BuildStr
+= ' -b ' + ' -b '.join(BuildTarget
)
1062 elif isinstance(BuildTarget
, str):
1063 BuildStr
+= ' -b ' + BuildTarget
1064 if ArchFlag
and TargetArch
:
1065 if isinstance(TargetArch
, list) or isinstance(TargetArch
, tuple):
1066 BuildStr
+= ' -a ' + ' -a '.join(TargetArch
)
1067 elif isinstance(TargetArch
, str):
1068 BuildStr
+= ' -a ' + TargetArch
1069 if ToolChainFlag
and ToolChain
:
1070 if isinstance(ToolChain
, list) or isinstance(ToolChain
, tuple):
1071 BuildStr
+= ' -t ' + ' -t '.join(ToolChain
)
1072 elif isinstance(ToolChain
, str):
1073 BuildStr
+= ' -t ' + ToolChain
1074 if PlatformFileFlag
and PlatformFile
:
1075 if isinstance(PlatformFile
, list) or isinstance(PlatformFile
, tuple):
1076 BuildStr
+= ' -p ' + ' -p '.join(PlatformFile
)
1077 elif isinstance(PlatformFile
, str):
1078 BuildStr
+= ' -p' + PlatformFile
1079 BuildStr
+= ' --conf=' + GlobalData
.gConfDirectory
1081 BuildStr
+= ' ' + Target
1085 def LaunchPrebuild(self
):
1087 EdkLogger
.info("\n- Prebuild Start -\n")
1088 self
.LaunchPrebuildFlag
= True
1090 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1091 # and preserve them for the rest of the main build step, because the child process environment will
1092 # evaporate as soon as it exits, we cannot get it in build step.
1094 PrebuildEnvFile
= os
.path
.join(GlobalData
.gConfDirectory
,'.cache','.PrebuildEnv')
1095 if os
.path
.isfile(PrebuildEnvFile
):
1096 os
.remove(PrebuildEnvFile
)
1097 if os
.path
.isfile(self
.PlatformBuildPath
):
1098 os
.remove(self
.PlatformBuildPath
)
1099 if sys
.platform
== "win32":
1100 args
= ' && '.join((self
.Prebuild
, 'set > ' + PrebuildEnvFile
))
1101 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1103 args
= ' && '.join((self
.Prebuild
, 'env > ' + PrebuildEnvFile
))
1104 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1106 # launch two threads to read the STDOUT and STDERR
1107 EndOfProcedure
= Event()
1108 EndOfProcedure
.clear()
1110 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1111 StdOutThread
.setName("STDOUT-Redirector")
1112 StdOutThread
.setDaemon(False)
1113 StdOutThread
.start()
1116 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1117 StdErrThread
.setName("STDERR-Redirector")
1118 StdErrThread
.setDaemon(False)
1119 StdErrThread
.start()
1120 # waiting for program exit
1127 if Process
.returncode
!= 0 :
1128 EdkLogger
.error("Prebuild", PREBUILD_ERROR
, 'Prebuild process is not success!')
1130 if os
.path
.exists(PrebuildEnvFile
):
1131 f
= open(PrebuildEnvFile
)
1132 envs
= f
.readlines()
1134 envs
= itertools
.imap(lambda l
: l
.split('=',1), envs
)
1135 envs
= itertools
.ifilter(lambda l
: len(l
) == 2, envs
)
1136 envs
= itertools
.imap(lambda l
: [i
.strip() for i
in l
], envs
)
1137 os
.environ
.update(dict(envs
))
1138 EdkLogger
.info("\n- Prebuild Done -\n")
1140 def LaunchPostbuild(self
):
1142 EdkLogger
.info("\n- Postbuild Start -\n")
1143 if sys
.platform
== "win32":
1144 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1146 Process
= Popen(self
.Postbuild
, 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("Postbuild", POSTBUILD_ERROR
, 'Postbuild process is not success!')
1170 EdkLogger
.info("\n- Postbuild Done -\n")
1171 ## Build a module or platform
1173 # Create autogen code and makefile for a module or platform, and the launch
1174 # "make" command to build it
1176 # @param Target The target of build command
1177 # @param Platform The platform file
1178 # @param Module The module file
1179 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1180 # @param ToolChain The name of toolchain to build
1181 # @param Arch The arch of the module/platform
1182 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1183 # for dependent modules/Libraries
1184 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1185 # for dependent modules/Libraries
1187 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1188 if AutoGenObject
== None:
1191 # skip file generation for cleanxxx targets, run and fds target
1192 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1193 # for target which must generate AutoGen code and makefile
1194 if not self
.SkipAutoGen
or Target
== 'genc':
1195 self
.Progress
.Start("Generating code")
1196 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1197 self
.Progress
.Stop("done!")
1198 if Target
== "genc":
1201 if not self
.SkipAutoGen
or Target
== 'genmake':
1202 self
.Progress
.Start("Generating makefile")
1203 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1204 self
.Progress
.Stop("done!")
1205 if Target
== "genmake":
1208 # always recreate top/platform makefile when clean, just in case of inconsistency
1209 AutoGenObject
.CreateCodeFile(False)
1210 AutoGenObject
.CreateMakeFile(False)
1212 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1213 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1215 BuildCommand
= AutoGenObject
.BuildCommand
1216 if BuildCommand
== None or len(BuildCommand
) == 0:
1217 EdkLogger
.error("build", OPTION_MISSING
,
1218 "No build command found for this module. "
1219 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1220 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1221 ExtraData
=str(AutoGenObject
))
1223 makefile
= GenMake
.BuildFile(AutoGenObject
)._FILE
_NAME
_[GenMake
.gMakeType
]
1227 RunDir
= os
.path
.normpath(os
.path
.join(AutoGenObject
.BuildDir
, GlobalData
.gGlobalDefines
['ARCH']))
1228 Command
= '.\SecMain'
1230 LaunchCommand(Command
, RunDir
)
1235 BuildCommand
= BuildCommand
+ [Target
]
1236 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1237 self
.CreateAsBuiltInf()
1241 if Target
== 'libraries':
1242 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1243 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1244 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1248 if Target
== 'modules':
1249 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1250 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1251 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1252 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1253 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, makefile
)), 'pbuild']
1254 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1255 self
.CreateAsBuiltInf()
1259 if Target
== 'cleanlib':
1260 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1261 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1262 if os
.path
.exists(LibMakefile
):
1263 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1264 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1268 if Target
== 'clean':
1269 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1270 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, makefile
))
1271 if os
.path
.exists(ModMakefile
):
1272 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
1273 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1274 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1275 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1276 if os
.path
.exists(LibMakefile
):
1277 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1278 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1282 if Target
== 'cleanall':
1284 #os.rmdir(AutoGenObject.BuildDir)
1285 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1286 except WindowsError, X
:
1287 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1290 ## Build a module or platform
1292 # Create autogen code and makefile for a module or platform, and the launch
1293 # "make" command to build it
1295 # @param Target The target of build command
1296 # @param Platform The platform file
1297 # @param Module The module file
1298 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1299 # @param ToolChain The name of toolchain to build
1300 # @param Arch The arch of the module/platform
1301 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1302 # for dependent modules/Libraries
1303 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1304 # for dependent modules/Libraries
1306 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1307 if AutoGenObject
== None:
1310 # skip file generation for cleanxxx targets, run and fds target
1311 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1312 # for target which must generate AutoGen code and makefile
1313 if not self
.SkipAutoGen
or Target
== 'genc':
1314 self
.Progress
.Start("Generating code")
1315 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1316 self
.Progress
.Stop("done!")
1317 if Target
== "genc":
1320 if not self
.SkipAutoGen
or Target
== 'genmake':
1321 self
.Progress
.Start("Generating makefile")
1322 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1323 #AutoGenObject.CreateAsBuiltInf()
1324 self
.Progress
.Stop("done!")
1325 if Target
== "genmake":
1328 # always recreate top/platform makefile when clean, just in case of inconsistency
1329 AutoGenObject
.CreateCodeFile(False)
1330 AutoGenObject
.CreateMakeFile(False)
1332 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1333 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1335 BuildCommand
= AutoGenObject
.BuildCommand
1336 if BuildCommand
== None or len(BuildCommand
) == 0:
1337 EdkLogger
.error("build", OPTION_MISSING
,
1338 "No build command found for this module. "
1339 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1340 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1341 ExtraData
=str(AutoGenObject
))
1346 BuildCommand
= BuildCommand
+ [Target
]
1347 AutoGenObject
.BuildTime
= LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1348 self
.CreateAsBuiltInf()
1353 LaunchCommand(AutoGenObject
.GenFdsCommand
, AutoGenObject
.MakeFileDir
)
1358 RunDir
= os
.path
.normpath(os
.path
.join(AutoGenObject
.BuildDir
, GlobalData
.gGlobalDefines
['ARCH']))
1359 Command
= '.\SecMain'
1361 LaunchCommand(Command
, RunDir
)
1365 if Target
== 'libraries':
1372 if Target
== 'cleanall':
1374 #os.rmdir(AutoGenObject.BuildDir)
1375 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1376 except WindowsError, X
:
1377 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1380 ## Rebase module image and Get function address for the input module list.
1382 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1384 AddrIsOffset
= False
1385 InfFileNameList
= ModuleList
.keys()
1386 #InfFileNameList.sort()
1387 for InfFile
in InfFileNameList
:
1388 sys
.stdout
.write (".")
1390 ModuleInfo
= ModuleList
[InfFile
]
1391 ModuleName
= ModuleInfo
.BaseName
1392 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1393 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1394 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1396 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1398 # Update Image to new BaseAddress by GenFw tool
1400 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1401 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1404 # Set new address to the section header only for SMM driver.
1406 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1407 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1409 # Collect funtion address from Map file
1411 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1413 if os
.path
.exists(ImageMapTable
):
1414 OrigImageBaseAddress
= 0
1415 ImageMap
= open(ImageMapTable
, 'r')
1416 for LinStr
in ImageMap
:
1417 if len (LinStr
.strip()) == 0:
1420 # Get the preferred address set on link time.
1422 if LinStr
.find ('Preferred load address is') != -1:
1423 StrList
= LinStr
.split()
1424 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1426 StrList
= LinStr
.split()
1427 if len (StrList
) > 4:
1428 if StrList
[3] == 'f' or StrList
[3] == 'F':
1430 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1431 FunctionList
.append ((Name
, RelativeAddress
))
1432 if ModuleInfo
.Arch
== 'IPF' and Name
.endswith('_ModuleEntryPoint'):
1434 # Get the real entry point address for IPF image.
1436 ModuleInfo
.Image
.EntryPoint
= RelativeAddress
1439 # Add general information.
1442 MapBuffer
.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1444 MapBuffer
.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1446 MapBuffer
.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1448 # Add guid and general seciton section.
1450 TextSectionAddress
= 0
1451 DataSectionAddress
= 0
1452 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1453 if SectionHeader
[0] == '.text':
1454 TextSectionAddress
= SectionHeader
[1]
1455 elif SectionHeader
[0] in ['.data', '.sdata']:
1456 DataSectionAddress
= SectionHeader
[1]
1458 MapBuffer
.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1460 MapBuffer
.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1462 # Add debug image full path.
1464 MapBuffer
.write('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1466 # Add funtion address
1468 for Function
in FunctionList
:
1470 MapBuffer
.write(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1472 MapBuffer
.write(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1476 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1479 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1481 ## Collect MAP information of all FVs
1483 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1485 # First get the XIP base address for FV map file.
1486 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1487 GuidName
= re
.compile("\(GUID=[-a-fA-F0-9]+")
1488 for FvName
in Wa
.FdfProfile
.FvDict
.keys():
1489 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1490 if not os
.path
.exists(FvMapBuffer
):
1492 FvMap
= open(FvMapBuffer
, 'r')
1493 #skip FV size information
1499 MatchGuid
= GuidPattern
.match(Line
)
1500 if MatchGuid
!= None:
1502 # Replace GUID with module name
1504 GuidString
= MatchGuid
.group()
1505 if GuidString
.upper() in ModuleList
:
1506 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1507 MapBuffer
.write('%s' % (Line
))
1509 # Add the debug image full path.
1511 MatchGuid
= GuidName
.match(Line
)
1512 if MatchGuid
!= None:
1513 GuidString
= MatchGuid
.group().split("=")[1]
1514 if GuidString
.upper() in ModuleList
:
1515 MapBuffer
.write('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1519 ## Collect MAP information of all modules
1521 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1522 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1524 PatchEfiImageList
= []
1532 # reserve 4K size in SMRAM to make SMM module address not from 0.
1534 IsIpfPlatform
= False
1535 if 'IPF' in self
.ArchList
:
1536 IsIpfPlatform
= True
1537 for ModuleGuid
in ModuleList
:
1538 Module
= ModuleList
[ModuleGuid
]
1539 GlobalData
.gProcessingFile
= "%s [%s, %s, %s]" % (Module
.MetaFile
, Module
.Arch
, Module
.ToolChain
, Module
.BuildTarget
)
1541 OutputImageFile
= ''
1542 for ResultFile
in Module
.CodaTargetList
:
1543 if str(ResultFile
.Target
).endswith('.efi'):
1545 # module list for PEI, DXE, RUNTIME and SMM
1547 OutputImageFile
= os
.path
.join(Module
.OutputDir
, Module
.Name
+ '.efi')
1548 ImageClass
= PeImageClass (OutputImageFile
)
1549 if not ImageClass
.IsValid
:
1550 EdkLogger
.error("build", FILE_PARSE_FAILURE
, ExtraData
=ImageClass
.ErrorInfo
)
1551 ImageInfo
= PeImageInfo(Module
.Name
, Module
.Guid
, Module
.Arch
, Module
.OutputDir
, Module
.DebugDir
, ImageClass
)
1552 if Module
.ModuleType
in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER', 'PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']:
1553 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1554 PeiSize
+= ImageInfo
.Image
.Size
1555 elif Module
.ModuleType
in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']:
1556 BtModuleList
[Module
.MetaFile
] = ImageInfo
1557 BtSize
+= ImageInfo
.Image
.Size
1558 elif Module
.ModuleType
in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']:
1559 RtModuleList
[Module
.MetaFile
] = ImageInfo
1560 #IPF runtime driver needs to be at 2 page alignment.
1561 if IsIpfPlatform
and ImageInfo
.Image
.Size
% 0x2000 != 0:
1562 ImageInfo
.Image
.Size
= (ImageInfo
.Image
.Size
/ 0x2000 + 1) * 0x2000
1563 RtSize
+= ImageInfo
.Image
.Size
1564 elif Module
.ModuleType
in ['SMM_CORE', 'DXE_SMM_DRIVER', 'MM_STANDALONE', 'MM_CORE_STANDALONE']:
1565 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1566 SmmSize
+= ImageInfo
.Image
.Size
1567 if Module
.ModuleType
== 'DXE_SMM_DRIVER':
1568 PiSpecVersion
= '0x00000000'
1569 if 'PI_SPECIFICATION_VERSION' in Module
.Module
.Specification
:
1570 PiSpecVersion
= Module
.Module
.Specification
['PI_SPECIFICATION_VERSION']
1571 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1572 if int(PiSpecVersion
, 16) < 0x0001000A:
1573 BtModuleList
[Module
.MetaFile
] = ImageInfo
1574 BtSize
+= ImageInfo
.Image
.Size
1577 # EFI image is final target.
1578 # Check EFI image contains patchable FixAddress related PCDs.
1580 if OutputImageFile
!= '':
1581 ModuleIsPatch
= False
1582 for Pcd
in Module
.ModulePcdList
:
1583 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST
:
1584 ModuleIsPatch
= True
1586 if not ModuleIsPatch
:
1587 for Pcd
in Module
.LibraryPcdList
:
1588 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST
:
1589 ModuleIsPatch
= True
1592 if not ModuleIsPatch
:
1595 # Module includes the patchable load fix address PCDs.
1596 # It will be fixed up later.
1598 PatchEfiImageList
.append (OutputImageFile
)
1601 # Get Top Memory address
1603 ReservedRuntimeMemorySize
= 0
1604 TopMemoryAddress
= 0
1605 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1606 TopMemoryAddress
= 0
1608 TopMemoryAddress
= self
.LoadFixAddress
1609 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1610 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1611 # Make IPF runtime driver at 2 page alignment.
1613 ReservedRuntimeMemorySize
= TopMemoryAddress
% 0x2000
1614 RtSize
= RtSize
+ ReservedRuntimeMemorySize
1617 # Patch FixAddress related PCDs into EFI image
1619 for EfiImage
in PatchEfiImageList
:
1620 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1621 if not os
.path
.exists(EfiImageMap
):
1624 # Get PCD offset in EFI image by GenPatchPcdTable function
1626 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1628 # Patch real PCD value by PatchPcdValue tool
1630 for PcdInfo
in PcdTable
:
1632 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1633 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
/ 0x1000))
1634 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1635 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
/ 0x1000))
1636 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1637 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
/ 0x1000))
1638 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1639 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
/ 0x1000))
1640 if ReturnValue
!= 0:
1641 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1643 MapBuffer
.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
/ 0x1000))
1644 MapBuffer
.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
/ 0x1000))
1645 MapBuffer
.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
/ 0x1000))
1646 if len (SmmModuleList
) > 0:
1647 MapBuffer
.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
/ 0x1000))
1649 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1650 BtBaseAddr
= TopMemoryAddress
- RtSize
1651 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1653 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1654 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1655 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1656 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
=False, ModeIsSmm
=True)
1657 MapBuffer
.write('\n\n')
1658 sys
.stdout
.write ("\n")
1661 ## Save platform Map file
1663 def _SaveMapFile (self
, MapBuffer
, Wa
):
1665 # Map file path is got.
1667 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1669 # Save address map into MAP file.
1671 SaveFileOnChange(MapFilePath
, MapBuffer
.getvalue(), False)
1673 if self
.LoadFixAddress
!= 0:
1674 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath
))
1677 ## Build active platform for different build targets and different tool chains
1679 def _BuildPlatform(self
):
1680 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1681 for BuildTarget
in self
.BuildTargetList
:
1682 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1684 for ToolChain
in self
.ToolChainList
:
1685 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1686 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1687 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1689 Wa
= WorkspaceAutoGen(
1706 self
.Fdf
= Wa
.FdfFile
1707 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1708 self
.BuildReport
.AddPlatformReport(Wa
)
1709 self
.Progress
.Stop("done!")
1710 for Arch
in Wa
.ArchList
:
1711 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1712 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1713 for Module
in Pa
.Platform
.Modules
:
1714 # Get ModuleAutoGen object to generate C code file and makefile
1715 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1718 self
.BuildModules
.append(Ma
)
1719 self
._BuildPa
(self
.Target
, Pa
)
1721 # Create MAP file when Load Fix Address is enabled.
1722 if self
.Target
in ["", "all", "fds"]:
1723 for Arch
in Wa
.ArchList
:
1724 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1726 # Check whether the set fix address is above 4G for 32bit image.
1728 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1729 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS can't be set to larger than or equal to 4G for the platform with IA32 or ARM arch modules")
1734 for Pa
in Wa
.AutoGenObjectList
:
1735 for Ma
in Pa
.ModuleAutoGenList
:
1738 if not Ma
.IsLibrary
:
1739 ModuleList
[Ma
.Guid
.upper()] = Ma
1741 MapBuffer
= StringIO('')
1742 if self
.LoadFixAddress
!= 0:
1744 # Rebase module to the preferred memory address before GenFds
1746 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1749 # create FDS again for the updated EFI image
1751 self
._Build
("fds", Wa
)
1753 # Create MAP file for all platform FVs after GenFds.
1755 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1757 # Save MAP buffer into MAP file.
1759 self
._SaveMapFile
(MapBuffer
, Wa
)
1761 ## Build active module for different build targets, different tool chains and different archs
1763 def _BuildModule(self
):
1764 for BuildTarget
in self
.BuildTargetList
:
1765 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1767 for ToolChain
in self
.ToolChainList
:
1768 WorkspaceAutoGenTime
= time
.time()
1769 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1770 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1771 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1774 # module build needs platform build information, so get platform
1777 Wa
= WorkspaceAutoGen(
1795 self
.Fdf
= Wa
.FdfFile
1796 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1797 Wa
.CreateMakeFile(False)
1798 self
.Progress
.Stop("done!")
1800 ExitFlag
= threading
.Event()
1802 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1803 for Arch
in Wa
.ArchList
:
1804 AutoGenStart
= time
.time()
1805 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1806 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1807 for Module
in Pa
.Platform
.Modules
:
1808 if self
.ModuleFile
.Dir
== Module
.Dir
and self
.ModuleFile
.File
== Module
.File
:
1809 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1810 if Ma
== None: continue
1812 self
.BuildModules
.append(Ma
)
1813 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1814 MakeStart
= time
.time()
1815 for Ma
in self
.BuildModules
:
1816 if not Ma
.IsBinaryModule
:
1817 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
1818 # Break build if any build thread has error
1819 if BuildTask
.HasError():
1820 # we need a full version of makefile for platform
1822 BuildTask
.WaitForComplete()
1823 Pa
.CreateMakeFile(False)
1824 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1825 # Start task scheduler
1826 if not BuildTask
.IsOnGoing():
1827 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1829 # in case there's an interruption. we need a full version of makefile for platform
1830 Pa
.CreateMakeFile(False)
1831 if BuildTask
.HasError():
1832 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1833 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1835 MakeContiue
= time
.time()
1837 BuildTask
.WaitForComplete()
1838 self
.CreateAsBuiltInf()
1839 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1840 if BuildTask
.HasError():
1841 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1843 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1848 "Module for [%s] is not a component of active platform."\
1849 " Please make sure that the ARCH and inf file path are"\
1850 " given in the same as in [%s]" % \
1851 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1852 ExtraData
=self
.ModuleFile
1854 # Create MAP file when Load Fix Address is enabled.
1855 if self
.Target
== "fds" and self
.Fdf
:
1856 for Arch
in Wa
.ArchList
:
1858 # Check whether the set fix address is above 4G for 32bit image.
1860 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1861 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")
1866 for Pa
in Wa
.AutoGenObjectList
:
1867 for Ma
in Pa
.ModuleAutoGenList
:
1870 if not Ma
.IsLibrary
:
1871 ModuleList
[Ma
.Guid
.upper()] = Ma
1873 MapBuffer
= StringIO('')
1874 if self
.LoadFixAddress
!= 0:
1876 # Rebase module to the preferred memory address before GenFds
1878 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1880 # create FDS again for the updated EFI image
1882 GenFdsStart
= time
.time()
1883 self
._Build
("fds", Wa
)
1884 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
1886 # Create MAP file for all platform FVs after GenFds.
1888 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1890 # Save MAP buffer into MAP file.
1892 self
._SaveMapFile
(MapBuffer
, Wa
)
1894 ## Build a platform in multi-thread mode
1896 def _MultiThreadBuildPlatform(self
):
1897 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1898 for BuildTarget
in self
.BuildTargetList
:
1899 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1901 for ToolChain
in self
.ToolChainList
:
1902 WorkspaceAutoGenTime
= time
.time()
1903 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1904 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1905 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1907 Wa
= WorkspaceAutoGen(
1924 self
.Fdf
= Wa
.FdfFile
1925 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1926 self
.BuildReport
.AddPlatformReport(Wa
)
1927 Wa
.CreateMakeFile(False)
1929 # multi-thread exit flag
1930 ExitFlag
= threading
.Event()
1932 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1933 for Arch
in Wa
.ArchList
:
1934 AutoGenStart
= time
.time()
1935 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1936 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1940 for Inf
in Pa
.Platform
.Modules
:
1941 ModuleList
.append(Inf
)
1942 # Add the INF only list in FDF
1943 if GlobalData
.gFdfParser
!= None:
1944 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
1945 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
1946 if Inf
in Pa
.Platform
.Modules
:
1948 ModuleList
.append(Inf
)
1949 for Module
in ModuleList
:
1950 # Get ModuleAutoGen object to generate C code file and makefile
1951 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1955 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1956 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1957 # for target which must generate AutoGen code and makefile
1958 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1959 Ma
.CreateCodeFile(True)
1960 if self
.Target
== "genc":
1963 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1964 Ma
.CreateMakeFile(True)
1965 if self
.Target
== "genmake":
1967 self
.BuildModules
.append(Ma
)
1968 self
.Progress
.Stop("done!")
1969 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1970 MakeStart
= time
.time()
1971 for Ma
in self
.BuildModules
:
1972 # Generate build task for the module
1973 if not Ma
.IsBinaryModule
:
1974 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
1975 # Break build if any build thread has error
1976 if BuildTask
.HasError():
1977 # we need a full version of makefile for platform
1979 BuildTask
.WaitForComplete()
1980 Pa
.CreateMakeFile(False)
1981 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1982 # Start task scheduler
1983 if not BuildTask
.IsOnGoing():
1984 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1986 # in case there's an interruption. we need a full version of makefile for platform
1987 Pa
.CreateMakeFile(False)
1988 if BuildTask
.HasError():
1989 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1990 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1992 MakeContiue
= time
.time()
1994 # Save temp tables to a TmpTableDict.
1996 for Key
in Wa
.BuildDatabase
._CACHE
_:
1997 if Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
and Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
._Table
and Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
._Table
.Table
:
1998 if TemporaryTablePattern
.match(Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
._Table
.Table
):
1999 TmpTableDict
[Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
._Table
.Table
] = Wa
.BuildDatabase
._CACHE
_[Key
]._RawData
._Table
.Cur
2002 # All modules have been put in build tasks queue. Tell task scheduler
2003 # to exit if all tasks are completed
2006 BuildTask
.WaitForComplete()
2007 self
.CreateAsBuiltInf()
2008 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2010 # Check for build error, and raise exception if one
2011 # has been signaled.
2013 if BuildTask
.HasError():
2014 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2016 # Create MAP file when Load Fix Address is enabled.
2017 if self
.Target
in ["", "all", "fds"]:
2018 for Arch
in Wa
.ArchList
:
2020 # Check whether the set fix address is above 4G for 32bit image.
2022 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2023 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")
2028 for Pa
in Wa
.AutoGenObjectList
:
2029 for Ma
in Pa
.ModuleAutoGenList
:
2032 if not Ma
.IsLibrary
:
2033 ModuleList
[Ma
.Guid
.upper()] = Ma
2035 # Rebase module to the preferred memory address before GenFds
2037 MapBuffer
= StringIO('')
2038 if self
.LoadFixAddress
!= 0:
2039 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2043 # Generate FD image if there's a FDF file found
2045 GenFdsStart
= time
.time()
2046 LaunchCommand(Wa
.GenFdsCommand
, os
.getcwd())
2049 # Create MAP file for all platform FVs after GenFds.
2051 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2052 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2054 # Save MAP buffer into MAP file.
2056 self
._SaveMapFile
(MapBuffer
, Wa
)
2058 ## Generate GuidedSectionTools.txt in the FV directories.
2060 def CreateGuidedSectionToolsFile(self
):
2061 for BuildTarget
in self
.BuildTargetList
:
2062 for ToolChain
in self
.ToolChainList
:
2063 Wa
= WorkspaceAutoGen(
2080 if not os
.path
.exists(FvDir
):
2083 for Arch
in self
.ArchList
:
2084 # Build up the list of supported architectures for this build
2085 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
2087 # Look through the tool definitions for GUIDed tools
2089 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.iteritems():
2090 if attrib
.upper().endswith('_GUID'):
2091 split
= attrib
.split('_')
2092 thisPrefix
= '_'.join(split
[0:3]) + '_'
2093 if thisPrefix
== prefix
:
2094 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
2097 path
= '_'.join(split
[0:4]) + '_PATH'
2098 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2099 path
= self
.GetFullPathOfTool(path
)
2100 guidAttribs
.append((guid
, toolName
, path
))
2102 # Write out GuidedSecTools.txt
2103 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2104 toolsFile
= open(toolsFile
, 'wt')
2105 for guidedSectionTool
in guidAttribs
:
2106 print >> toolsFile
, ' '.join(guidedSectionTool
)
2109 ## Returns the full path of the tool.
2111 def GetFullPathOfTool (self
, tool
):
2112 if os
.path
.exists(tool
):
2113 return os
.path
.realpath(tool
)
2115 # We need to search for the tool using the
2116 # PATH environment variable.
2117 for dirInPath
in os
.environ
['PATH'].split(os
.pathsep
):
2118 foundPath
= os
.path
.join(dirInPath
, tool
)
2119 if os
.path
.exists(foundPath
):
2120 return os
.path
.realpath(foundPath
)
2122 # If the tool was not found in the path then we just return
2126 ## Launch the module or platform build
2129 if not self
.ModuleFile
:
2130 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2131 self
.SpawnMode
= False
2132 self
._BuildPlatform
()
2134 self
._MultiThreadBuildPlatform
()
2135 self
.CreateGuidedSectionToolsFile()
2137 self
.SpawnMode
= False
2140 if self
.Target
== 'cleanall':
2142 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2144 def CreateAsBuiltInf(self
):
2145 for Module
in self
.BuildModules
:
2146 Module
.CreateAsBuiltInf()
2147 self
.BuildModules
= []
2148 ## Do some clean-up works when error occurred
2149 def Relinquish(self
):
2150 OldLogLevel
= EdkLogger
.GetLevel()
2151 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2152 #self.DumpBuildData()
2153 Utils
.Progressor
.Abort()
2154 if self
.SpawnMode
== True:
2156 EdkLogger
.SetLevel(OldLogLevel
)
2158 def DumpBuildData(self
):
2159 CacheDirectory
= os
.path
.dirname(GlobalData
.gDatabasePath
)
2160 Utils
.CreateDirectory(CacheDirectory
)
2161 Utils
.DataDump(Utils
.gFileTimeStampCache
, os
.path
.join(CacheDirectory
, "gFileTimeStampCache"))
2162 Utils
.DataDump(Utils
.gDependencyDatabase
, os
.path
.join(CacheDirectory
, "gDependencyDatabase"))
2164 def RestoreBuildData(self
):
2165 FilePath
= os
.path
.join(os
.path
.dirname(GlobalData
.gDatabasePath
), "gFileTimeStampCache")
2166 if Utils
.gFileTimeStampCache
== {} and os
.path
.isfile(FilePath
):
2167 Utils
.gFileTimeStampCache
= Utils
.DataRestore(FilePath
)
2168 if Utils
.gFileTimeStampCache
== None:
2169 Utils
.gFileTimeStampCache
= {}
2171 FilePath
= os
.path
.join(os
.path
.dirname(GlobalData
.gDatabasePath
), "gDependencyDatabase")
2172 if Utils
.gDependencyDatabase
== {} and os
.path
.isfile(FilePath
):
2173 Utils
.gDependencyDatabase
= Utils
.DataRestore(FilePath
)
2174 if Utils
.gDependencyDatabase
== None:
2175 Utils
.gDependencyDatabase
= {}
2177 def ParseDefines(DefineList
=[]):
2179 if DefineList
!= None:
2180 for Define
in DefineList
:
2181 DefineTokenList
= Define
.split("=", 1)
2182 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2183 EdkLogger
.error('build', FORMAT_INVALID
,
2184 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2185 ExtraData
=DefineTokenList
[0])
2187 if len(DefineTokenList
) == 1:
2188 DefineDict
[DefineTokenList
[0]] = "TRUE"
2190 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2194 def SingleCheckCallback(option
, opt_str
, value
, parser
):
2195 if option
not in gParamCheck
:
2196 setattr(parser
.values
, option
.dest
, value
)
2197 gParamCheck
.append(option
)
2199 parser
.error("Option %s only allows one instance in command line!" % option
)
2201 def LogBuildTime(Time
):
2204 TimeDur
= time
.gmtime(Time
)
2205 if TimeDur
.tm_yday
> 1:
2206 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2208 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2213 ## Parse command line options
2215 # Using standard Python module optparse to parse command line option of this tool.
2217 # @retval Opt A optparse.Values object containing the parsed options
2218 # @retval Args Target of build command
2220 def MyOptionParser():
2221 Parser
= OptionParser(description
=__copyright__
, version
=__version__
, prog
="build.exe", usage
="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
2222 Parser
.add_option("-a", "--arch", action
="append", type="choice", choices
=['IA32', 'X64', 'IPF', 'EBC', 'ARM', 'AARCH64'], dest
="TargetArch",
2223 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.")
2224 Parser
.add_option("-p", "--platform", action
="callback", type="string", dest
="PlatformFile", callback
=SingleCheckCallback
,
2225 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
2226 Parser
.add_option("-m", "--module", action
="callback", type="string", dest
="ModuleFile", callback
=SingleCheckCallback
,
2227 help="Build the module specified by the INF file name argument.")
2228 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
2230 Parser
.add_option("-t", "--tagname", action
="append", type="string", dest
="ToolChain",
2231 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
2232 Parser
.add_option("-x", "--sku-id", action
="callback", type="string", dest
="SkuId", callback
=SingleCheckCallback
,
2233 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
2235 Parser
.add_option("-n", action
="callback", type="int", dest
="ThreadNumber", callback
=SingleCheckCallback
,
2236 help="Build the platform using multi-threaded compiler. The value overrides target.txt's MAX_CONCURRENT_THREAD_NUMBER. Less than 2 will disable multi-thread builds.")
2238 Parser
.add_option("-f", "--fdf", action
="callback", type="string", dest
="FdfFile", callback
=SingleCheckCallback
,
2239 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
2240 Parser
.add_option("-r", "--rom-image", action
="append", type="string", dest
="RomImage", default
=[],
2241 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
2242 Parser
.add_option("-i", "--fv-image", action
="append", type="string", dest
="FvImage", default
=[],
2243 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
2244 Parser
.add_option("-C", "--capsule-image", action
="append", type="string", dest
="CapName", default
=[],
2245 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
2246 Parser
.add_option("-u", "--skip-autogen", action
="store_true", dest
="SkipAutoGen", help="Skip AutoGen step.")
2247 Parser
.add_option("-e", "--re-parse", action
="store_true", dest
="Reparse", help="Re-parse all meta-data files.")
2249 Parser
.add_option("-c", "--case-insensitive", action
="store_true", dest
="CaseInsensitive", default
=False, help="Don't check case of file name.")
2251 Parser
.add_option("-w", "--warning-as-error", action
="store_true", dest
="WarningAsError", help="Treat warning in tools as error.")
2252 Parser
.add_option("-j", "--log", action
="store", dest
="LogFile", help="Put log in specified file as well as on console.")
2254 Parser
.add_option("-s", "--silent", action
="store_true", type=None, dest
="SilentMode",
2255 help="Make use of silent mode of (n)make.")
2256 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
2257 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
2258 "including library instances selected, final dependency expression, "\
2259 "and warning messages, etc.")
2260 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
2261 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
2263 Parser
.add_option("-y", "--report-file", action
="store", dest
="ReportFile", help="Create/overwrite the report to the specified filename.")
2264 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
=[],
2265 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]. "\
2266 "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]")
2267 Parser
.add_option("-F", "--flag", action
="store", type="string", dest
="Flag",
2268 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. "\
2269 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
2270 "will override the setting in [BuildOptions] section of platform DSC.")
2271 Parser
.add_option("-N", "--no-cache", action
="store_true", dest
="DisableCache", default
=False, help="Disable build cache mechanism")
2272 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
2273 Parser
.add_option("--check-usage", action
="store_true", dest
="CheckUsage", default
=False, help="Check usage content of entries listed in INF file.")
2274 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
2275 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
2276 Parser
.add_option("-l", "--cmd-len", action
="store", type="int", dest
="CommandLength", help="Specify the maximum line length of build command. Default is 4096.")
2278 (Opt
, Args
) = Parser
.parse_args()
2281 ## Tool entrance method
2283 # This method mainly dispatch specific methods per the command line options.
2284 # If no error found, return zero value so the caller of this tool can know
2285 # if it's executed successfully or not.
2287 # @retval 0 Tool was successful
2288 # @retval 1 Tool failed
2291 StartTime
= time
.time()
2293 # Initialize log system
2294 EdkLogger
.Initialize()
2295 GlobalData
.gCommand
= sys
.argv
[1:]
2297 # Parse the options and args
2299 (Option
, Target
) = MyOptionParser()
2300 GlobalData
.gOptions
= Option
2301 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2304 if Option
.verbose
!= None:
2305 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2306 elif Option
.quiet
!= None:
2307 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2308 elif Option
.debug
!= None:
2309 EdkLogger
.SetLevel(Option
.debug
+ 1)
2311 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2313 if Option
.LogFile
!= None:
2314 EdkLogger
.SetLogFile(Option
.LogFile
)
2316 if Option
.WarningAsError
== True:
2317 EdkLogger
.SetWarningAsError()
2319 if platform
.platform().find("Windows") >= 0:
2320 GlobalData
.gIsWindows
= True
2322 GlobalData
.gIsWindows
= False
2324 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2325 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2330 if len(Target
) == 0:
2332 elif len(Target
) >= 2:
2333 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2334 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2336 Target
= Target
[0].lower()
2338 if Target
not in gSupportedTarget
:
2339 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2340 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2343 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2346 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2348 Workspace
= os
.getenv("WORKSPACE")
2350 # Get files real name in workspace dir
2352 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2354 WorkingDirectory
= os
.getcwd()
2355 if not Option
.ModuleFile
:
2356 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2357 FileNum
= len(FileList
)
2359 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2360 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2362 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2364 if Option
.ModuleFile
:
2365 if os
.path
.isabs (Option
.ModuleFile
):
2366 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2367 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2368 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2369 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2371 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2373 if Option
.PlatformFile
!= None:
2374 if os
.path
.isabs (Option
.PlatformFile
):
2375 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2376 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2377 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2379 if Option
.FdfFile
!= None:
2380 if os
.path
.isabs (Option
.FdfFile
):
2381 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2382 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2383 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2384 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2386 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2388 if Option
.Flag
!= None and Option
.Flag
not in ['-c', '-s']:
2389 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2391 MyBuild
= Build(Target
, Workspace
, Option
)
2392 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2393 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2395 # Drop temp tables to avoid database locked.
2396 for TmpTableName
in TmpTableDict
:
2397 SqlCommand
= """drop table IF EXISTS %s""" % TmpTableName
2398 TmpTableDict
[TmpTableName
].execute(SqlCommand
)
2399 #MyBuild.DumpBuildData()
2401 # All job done, no error found and no exception raised
2404 except FatalError
, X
:
2406 # for multi-thread build exits safely
2407 MyBuild
.Relinquish()
2408 if Option
!= None and Option
.debug
!= None:
2409 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2410 ReturnCode
= X
.args
[0]
2412 # error from Fdf parser
2414 # for multi-thread build exits safely
2415 MyBuild
.Relinquish()
2416 if Option
!= None and Option
.debug
!= None:
2417 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2419 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2420 ReturnCode
= FORMAT_INVALID
2421 except KeyboardInterrupt:
2422 ReturnCode
= ABORT_ERROR
2423 if Option
!= None and Option
.debug
!= None:
2424 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2427 # for multi-thread build exits safely
2428 MyBuild
.Relinquish()
2430 # try to get the meta-file from the object causing exception
2431 Tb
= sys
.exc_info()[-1]
2432 MetaFile
= GlobalData
.gProcessingFile
2434 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2435 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2440 "Unknown fatal error when processing [%s]" % MetaFile
,
2441 ExtraData
="\n(Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!)\n",
2444 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2445 ReturnCode
= CODE_ERROR
2447 Utils
.Progressor
.Abort()
2448 Utils
.ClearDuplicatedInf()
2452 MyBuild
.LaunchPostbuild()
2455 Conclusion
= "Failed"
2456 elif ReturnCode
== ABORT_ERROR
:
2457 Conclusion
= "Aborted"
2459 Conclusion
= "Failed"
2460 FinishTime
= time
.time()
2461 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2462 BuildDurationStr
= ""
2463 if BuildDuration
.tm_yday
> 1:
2464 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2466 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2469 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2471 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2472 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2473 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2474 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2477 if __name__
== '__main__':
2479 ## 0-127 is a safe return range, and 1 is a standard default error
2480 if r
< 0 or r
> 127: r
= 1