2 # build a platform or a module
4 # Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
5 # Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
6 # Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
8 # This program and the accompanying materials
9 # are licensed and made available under the terms and conditions of the BSD License
10 # which accompanies this distribution. The full text of the license may be found at
11 # http://opensource.org/licenses/bsd-license.php
13 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 from __future__
import print_function
21 import Common
.LongFilePathOs
as os
23 from io
import BytesIO
29 import encodings
.ascii
31 import multiprocessing
34 from threading
import *
36 from optparse
import OptionParser
37 from subprocess
import *
38 from Common
import Misc
as Utils
40 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
41 from Common
.TargetTxtClassObject
import TargetTxtClassObject
42 from Common
.ToolDefClassObject
import ToolDefClassObject
43 from Common
.DataType
import *
44 from Common
.BuildVersion
import gBUILD_VERSION
45 from AutoGen
.AutoGen
import *
46 from Common
.BuildToolError
import *
47 from Workspace
.WorkspaceDatabase
import WorkspaceDatabase
48 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
50 from BuildReport
import BuildReport
51 from GenPatchPcdTable
.GenPatchPcdTable
import *
52 from PatchPcdValue
.PatchPcdValue
import *
54 import Common
.EdkLogger
55 import Common
.GlobalData
as GlobalData
56 from GenFds
.GenFds
import GenFds
, GenFdsApi
58 from collections
import OrderedDict
, defaultdict
60 # Version and Copyright
61 VersionNumber
= "0.60" + ' ' + gBUILD_VERSION
62 __version__
= "%prog Version " + VersionNumber
63 __copyright__
= "Copyright (c) 2007 - 2018, Intel Corporation All rights reserved."
65 ## standard targets of build command
66 gSupportedTarget
= ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
68 ## build configuration file
69 gBuildConfiguration
= "target.txt"
70 gToolsDefinition
= "tools_def.txt"
72 TemporaryTablePattern
= re
.compile(r
'^_\d+_\d+_[a-fA-F0-9]+$')
75 ## Check environment PATH variable to make sure the specified tool is found
77 # If the tool is found in the PATH, then True is returned
78 # Otherwise, False is returned
80 def IsToolInPath(tool
):
81 if 'PATHEXT' in os
.environ
:
82 extns
= os
.environ
['PATHEXT'].split(os
.path
.pathsep
)
85 for pathDir
in os
.environ
['PATH'].split(os
.path
.pathsep
):
87 if os
.path
.exists(os
.path
.join(pathDir
, tool
+ ext
)):
91 ## Check environment variables
93 # Check environment variables that must be set for build. Currently they are
95 # WORKSPACE The directory all packages/platforms start from
96 # EDK_TOOLS_PATH The directory contains all tools needed by the build
97 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
99 # If any of above environment variable is not set or has error, the build
102 def CheckEnvVariable():
104 if "WORKSPACE" not in os
.environ
:
105 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
106 ExtraData
="WORKSPACE")
108 WorkspaceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["WORKSPACE"]))
109 if not os
.path
.exists(WorkspaceDir
):
110 EdkLogger
.error("build", FILE_NOT_FOUND
, "WORKSPACE doesn't exist", ExtraData
=WorkspaceDir
)
111 elif ' ' in WorkspaceDir
:
112 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in WORKSPACE path",
113 ExtraData
=WorkspaceDir
)
114 os
.environ
["WORKSPACE"] = WorkspaceDir
116 # set multiple workspace
117 PackagesPath
= os
.getenv("PACKAGES_PATH")
118 mws
.setWs(WorkspaceDir
, PackagesPath
)
119 if mws
.PACKAGES_PATH
:
120 for Path
in mws
.PACKAGES_PATH
:
121 if not os
.path
.exists(Path
):
122 EdkLogger
.error("build", FILE_NOT_FOUND
, "One Path in PACKAGES_PATH doesn't exist", ExtraData
=Path
)
124 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in PACKAGES_PATH", ExtraData
=Path
)
127 os
.environ
["EDK_TOOLS_PATH"] = os
.path
.normcase(os
.environ
["EDK_TOOLS_PATH"])
129 # check EDK_TOOLS_PATH
130 if "EDK_TOOLS_PATH" not in os
.environ
:
131 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
132 ExtraData
="EDK_TOOLS_PATH")
135 if "PATH" not in os
.environ
:
136 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
139 GlobalData
.gWorkspace
= WorkspaceDir
141 GlobalData
.gGlobalDefines
["WORKSPACE"] = WorkspaceDir
142 GlobalData
.gGlobalDefines
["EDK_TOOLS_PATH"] = os
.environ
["EDK_TOOLS_PATH"]
144 ## Get normalized file path
146 # Convert the path to be local format, and remove the WORKSPACE path at the
147 # beginning if the file path is given in full path.
149 # @param FilePath File path to be normalized
150 # @param Workspace Workspace path which the FilePath will be checked against
152 # @retval string The normalized file path
154 def NormFile(FilePath
, Workspace
):
155 # check if the path is absolute or relative
156 if os
.path
.isabs(FilePath
):
157 FileFullPath
= os
.path
.normpath(FilePath
)
159 FileFullPath
= os
.path
.normpath(mws
.join(Workspace
, FilePath
))
160 Workspace
= mws
.getWs(Workspace
, FilePath
)
162 # check if the file path exists or not
163 if not os
.path
.isfile(FileFullPath
):
164 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath
)
166 # remove workspace directory from the beginning part of the file path
167 if Workspace
[-1] in ["\\", "/"]:
168 return FileFullPath
[len(Workspace
):]
170 return FileFullPath
[(len(Workspace
) + 1):]
172 ## Get the output of an external program
174 # This is the entrance method of thread reading output of an external program and
175 # putting them in STDOUT/STDERR of current program.
177 # @param From The stream message read from
178 # @param To The stream message put on
179 # @param ExitFlag The flag used to indicate stopping reading
181 def ReadMessage(From
, To
, ExitFlag
):
183 # read one line a time
184 Line
= From
.readline()
185 # empty string means "end"
186 if Line
is not None and Line
!= "":
193 ## Launch an external program
195 # This method will call subprocess.Popen to execute an external program with
196 # given options in specified directory. Because of the dead-lock issue during
197 # redirecting output of the external program, threads are used to to do the
200 # @param Command A list or string containing the call of the program
201 # @param WorkingDir The directory in which the program will be running
203 def LaunchCommand(Command
, WorkingDir
):
204 BeginTime
= time
.time()
205 # if working directory doesn't exist, Popen() will raise an exception
206 if not os
.path
.isdir(WorkingDir
):
207 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=WorkingDir
)
209 # Command is used as the first Argument in following Popen().
210 # It could be a string or sequence. We find that if command is a string in following Popen(),
211 # ubuntu may fail with an error message that the command is not found.
212 # So here we may need convert command from string to list instance.
213 if platform
.system() != 'Windows':
214 if not isinstance(Command
, list):
215 Command
= Command
.split()
216 Command
= ' '.join(Command
)
219 EndOfProcedure
= None
222 Proc
= Popen(Command
, stdout
=PIPE
, stderr
=PIPE
, env
=os
.environ
, cwd
=WorkingDir
, bufsize
=-1, shell
=True)
224 # launch two threads to read the STDOUT and STDERR
225 EndOfProcedure
= Event()
226 EndOfProcedure
.clear()
228 StdOutThread
= Thread(target
=ReadMessage
, args
=(Proc
.stdout
, EdkLogger
.info
, EndOfProcedure
))
229 StdOutThread
.setName("STDOUT-Redirector")
230 StdOutThread
.setDaemon(False)
234 StdErrThread
= Thread(target
=ReadMessage
, args
=(Proc
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
235 StdErrThread
.setName("STDERR-Redirector")
236 StdErrThread
.setDaemon(False)
239 # waiting for program exit
241 except: # in case of aborting
242 # terminate the threads redirecting the program output
243 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
244 if EndOfProcedure
is not None:
247 if not isinstance(Command
, type("")):
248 Command
= " ".join(Command
)
249 EdkLogger
.error("build", COMMAND_FAILURE
, "Failed to start command", ExtraData
="%s [%s]" % (Command
, WorkingDir
))
256 # check the return code of the program
257 if Proc
.returncode
!= 0:
258 if not isinstance(Command
, type("")):
259 Command
= " ".join(Command
)
260 # print out the Response file and its content when make failure
261 RespFile
= os
.path
.join(WorkingDir
, 'OUTPUT', 'respfilelist.txt')
262 if os
.path
.isfile(RespFile
):
264 RespContent
= f
.read()
266 EdkLogger
.info(RespContent
)
268 EdkLogger
.error("build", COMMAND_FAILURE
, ExtraData
="%s [%s]" % (Command
, WorkingDir
))
269 return "%dms" % (int(round((time
.time() - BeginTime
) * 1000)))
271 ## The smallest unit that can be built in multi-thread build mode
273 # This is the base class of build unit. The "Obj" parameter must provide
274 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
277 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
282 # @param self The object pointer
283 # @param Obj The object the build is working on
284 # @param Target The build target name, one of gSupportedTarget
285 # @param Dependency The BuildUnit(s) which must be completed in advance
286 # @param WorkingDir The directory build command starts in
288 def __init__(self
, Obj
, BuildCommand
, Target
, Dependency
, WorkingDir
="."):
289 self
.BuildObject
= Obj
290 self
.Dependency
= Dependency
291 self
.WorkingDir
= WorkingDir
293 self
.BuildCommand
= BuildCommand
295 EdkLogger
.error("build", OPTION_MISSING
,
296 "No build command found for this module. "
297 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
298 (Obj
.BuildTarget
, Obj
.ToolChain
, Obj
.Arch
),
304 # It just returns the string representation of self.BuildObject
306 # @param self The object pointer
309 return str(self
.BuildObject
)
311 ## "==" operator method
313 # It just compares self.BuildObject with "Other". So self.BuildObject must
314 # provide its own __eq__() method.
316 # @param self The object pointer
317 # @param Other The other BuildUnit object compared to
319 def __eq__(self
, Other
):
320 return Other
and self
.BuildObject
== Other
.BuildObject \
321 and Other
.BuildObject \
322 and self
.BuildObject
.Arch
== Other
.BuildObject
.Arch
326 # It just returns the hash value of self.BuildObject which must be hashable.
328 # @param self The object pointer
331 return hash(self
.BuildObject
) + hash(self
.BuildObject
.Arch
)
334 return repr(self
.BuildObject
)
336 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
338 # This class is for module build by nmake/make build system. The "Obj" parameter
339 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
340 # be make units missing build.
342 # Currently the "Obj" should be only ModuleAutoGen object.
344 class ModuleMakeUnit(BuildUnit
):
347 # @param self The object pointer
348 # @param Obj The ModuleAutoGen object the build is working on
349 # @param Target The build target name, one of gSupportedTarget
351 def __init__(self
, Obj
, Target
):
352 Dependency
= [ModuleMakeUnit(La
, Target
) for La
in Obj
.LibraryAutoGenList
]
353 BuildUnit
.__init
__(self
, Obj
, Obj
.BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
354 if Target
in [None, "", "all"]:
355 self
.Target
= "tbuild"
357 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
359 # This class is for platform build by nmake/make build system. The "Obj" parameter
360 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
361 # be make units missing build.
363 # Currently the "Obj" should be only PlatformAutoGen object.
365 class PlatformMakeUnit(BuildUnit
):
368 # @param self The object pointer
369 # @param Obj The PlatformAutoGen object the build is working on
370 # @param Target The build target name, one of gSupportedTarget
372 def __init__(self
, Obj
, Target
):
373 Dependency
= [ModuleMakeUnit(Lib
, Target
) for Lib
in self
.BuildObject
.LibraryAutoGenList
]
374 Dependency
.extend([ModuleMakeUnit(Mod
, Target
) for Mod
in self
.BuildObject
.ModuleAutoGenList
])
375 BuildUnit
.__init
__(self
, Obj
, Obj
.BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
377 ## The class representing the task of a module build or platform build
379 # This class manages the build tasks in multi-thread build mode. Its jobs include
380 # scheduling thread running, catching thread error, monitor the thread status, etc.
383 # queue for tasks waiting for schedule
384 _PendingQueue
= OrderedDict()
385 _PendingQueueLock
= threading
.Lock()
387 # queue for tasks ready for running
388 _ReadyQueue
= OrderedDict()
389 _ReadyQueueLock
= threading
.Lock()
391 # queue for run tasks
392 _RunningQueue
= OrderedDict()
393 _RunningQueueLock
= threading
.Lock()
395 # queue containing all build tasks, in case duplicate build
396 _TaskQueue
= OrderedDict()
398 # flag indicating error occurs in a running thread
399 _ErrorFlag
= threading
.Event()
403 # BoundedSemaphore object used to control the number of running threads
406 # flag indicating if the scheduler is started or not
407 _SchedulerStopped
= threading
.Event()
408 _SchedulerStopped
.set()
410 ## Start the task scheduler thread
412 # @param MaxThreadNumber The maximum thread number
413 # @param ExitFlag Flag used to end the scheduler
416 def StartScheduler(MaxThreadNumber
, ExitFlag
):
417 SchedulerThread
= Thread(target
=BuildTask
.Scheduler
, args
=(MaxThreadNumber
, ExitFlag
))
418 SchedulerThread
.setName("Build-Task-Scheduler")
419 SchedulerThread
.setDaemon(False)
420 SchedulerThread
.start()
421 # wait for the scheduler to be started, especially useful in Linux
422 while not BuildTask
.IsOnGoing():
427 # @param MaxThreadNumber The maximum thread number
428 # @param ExitFlag Flag used to end the scheduler
431 def Scheduler(MaxThreadNumber
, ExitFlag
):
432 BuildTask
._SchedulerStopped
.clear()
434 # use BoundedSemaphore to control the maximum running threads
435 BuildTask
._Thread
= BoundedSemaphore(MaxThreadNumber
)
437 # scheduling loop, which will exits when no pending/ready task and
438 # indicated to do so, or there's error in running thread
440 while (len(BuildTask
._PendingQueue
) > 0 or len(BuildTask
._ReadyQueue
) > 0 \
441 or not ExitFlag
.isSet()) and not BuildTask
._ErrorFlag
.isSet():
442 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Pending Queue (%d), Ready Queue (%d)"
443 % (len(BuildTask
._PendingQueue
), len(BuildTask
._ReadyQueue
)))
445 # get all pending tasks
446 BuildTask
._PendingQueueLock
.acquire()
447 BuildObjectList
= BuildTask
._PendingQueue
.keys()
449 # check if their dependency is resolved, and if true, move them
452 for BuildObject
in BuildObjectList
:
453 Bt
= BuildTask
._PendingQueue
[BuildObject
]
455 BuildTask
._ReadyQueue
[BuildObject
] = BuildTask
._PendingQueue
.pop(BuildObject
)
456 BuildTask
._PendingQueueLock
.release()
458 # launch build thread until the maximum number of threads is reached
459 while not BuildTask
._ErrorFlag
.isSet():
460 # empty ready queue, do nothing further
461 if len(BuildTask
._ReadyQueue
) == 0:
464 # wait for active thread(s) exit
465 BuildTask
._Thread
.acquire(True)
467 # start a new build thread
468 Bo
, Bt
= BuildTask
._ReadyQueue
.popitem()
470 # move into running queue
471 BuildTask
._RunningQueueLock
.acquire()
472 BuildTask
._RunningQueue
[Bo
] = Bt
473 BuildTask
._RunningQueueLock
.release()
482 # wait for all running threads exit
483 if BuildTask
._ErrorFlag
.isSet():
484 EdkLogger
.quiet("\nWaiting for all build threads exit...")
485 # while not BuildTask._ErrorFlag.isSet() and \
486 while len(BuildTask
._RunningQueue
) > 0:
487 EdkLogger
.verbose("Waiting for thread ending...(%d)" % len(BuildTask
._RunningQueue
))
488 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Threads [%s]" % ", ".join(Th
.getName() for Th
in threading
.enumerate()))
491 except BaseException
as X
:
493 # TRICK: hide the output of threads left runing, so that the user can
494 # catch the error message easily
496 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
497 BuildTask
._ErrorFlag
.set()
498 BuildTask
._ErrorMessage
= "build thread scheduler error\n\t%s" % str(X
)
500 BuildTask
._PendingQueue
.clear()
501 BuildTask
._ReadyQueue
.clear()
502 BuildTask
._RunningQueue
.clear()
503 BuildTask
._TaskQueue
.clear()
504 BuildTask
._SchedulerStopped
.set()
506 ## Wait for all running method exit
509 def WaitForComplete():
510 BuildTask
._SchedulerStopped
.wait()
512 ## Check if the scheduler is running or not
516 return not BuildTask
._SchedulerStopped
.isSet()
521 if BuildTask
.IsOnGoing():
522 BuildTask
._ErrorFlag
.set()
523 BuildTask
.WaitForComplete()
525 ## Check if there's error in running thread
527 # Since the main thread cannot catch exceptions in other thread, we have to
528 # use threading.Event to communicate this formation to main thread.
532 return BuildTask
._ErrorFlag
.isSet()
534 ## Get error message in running thread
536 # Since the main thread cannot catch exceptions in other thread, we have to
537 # use a static variable to communicate this message to main thread.
540 def GetErrorMessage():
541 return BuildTask
._ErrorMessage
543 ## Factory method to create a BuildTask object
545 # This method will check if a module is building or has been built. And if
546 # true, just return the associated BuildTask object in the _TaskQueue. If
547 # not, create and return a new BuildTask object. The new BuildTask object
548 # will be appended to the _PendingQueue for scheduling later.
550 # @param BuildItem A BuildUnit object representing a build object
551 # @param Dependency The dependent build object of BuildItem
554 def New(BuildItem
, Dependency
=None):
555 if BuildItem
in BuildTask
._TaskQueue
:
556 Bt
= BuildTask
._TaskQueue
[BuildItem
]
560 Bt
._Init
(BuildItem
, Dependency
)
561 BuildTask
._TaskQueue
[BuildItem
] = Bt
563 BuildTask
._PendingQueueLock
.acquire()
564 BuildTask
._PendingQueue
[BuildItem
] = Bt
565 BuildTask
._PendingQueueLock
.release()
569 ## The real constructor of BuildTask
571 # @param BuildItem A BuildUnit object representing a build object
572 # @param Dependency The dependent build object of BuildItem
574 def _Init(self
, BuildItem
, Dependency
=None):
575 self
.BuildItem
= BuildItem
577 self
.DependencyList
= []
578 if Dependency
is None:
579 Dependency
= BuildItem
.Dependency
581 Dependency
.extend(BuildItem
.Dependency
)
582 self
.AddDependency(Dependency
)
583 # flag indicating build completes, used to avoid unnecessary re-build
584 self
.CompleteFlag
= False
586 ## Check if all dependent build tasks are completed or not
590 for Dep
in self
.DependencyList
:
591 if Dep
.CompleteFlag
== True:
598 ## Add dependent build task
600 # @param Dependency The list of dependent build objects
602 def AddDependency(self
, Dependency
):
603 for Dep
in Dependency
:
604 if not Dep
.BuildObject
.IsBinaryModule
:
605 self
.DependencyList
.append(BuildTask
.New(Dep
)) # BuildTask list
607 ## The thread wrapper of LaunchCommand function
609 # @param Command A list or string contains the call of the command
610 # @param WorkingDir The directory in which the program will be running
612 def _CommandThread(self
, Command
, WorkingDir
):
614 self
.BuildItem
.BuildObject
.BuildTime
= LaunchCommand(Command
, WorkingDir
)
615 self
.CompleteFlag
= True
618 # TRICK: hide the output of threads left runing, so that the user can
619 # catch the error message easily
621 if not BuildTask
._ErrorFlag
.isSet():
622 GlobalData
.gBuildingModule
= "%s [%s, %s, %s]" % (str(self
.BuildItem
.BuildObject
),
623 self
.BuildItem
.BuildObject
.Arch
,
624 self
.BuildItem
.BuildObject
.ToolChain
,
625 self
.BuildItem
.BuildObject
.BuildTarget
627 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
628 BuildTask
._ErrorFlag
.set()
629 BuildTask
._ErrorMessage
= "%s broken\n %s [%s]" % \
630 (threading
.currentThread().getName(), Command
, WorkingDir
)
631 # indicate there's a thread is available for another build task
632 BuildTask
._RunningQueueLock
.acquire()
633 BuildTask
._RunningQueue
.pop(self
.BuildItem
)
634 BuildTask
._RunningQueueLock
.release()
635 BuildTask
._Thread
.release()
637 ## Start build task thread
640 EdkLogger
.quiet("Building ... %s" % repr(self
.BuildItem
))
641 Command
= self
.BuildItem
.BuildCommand
+ [self
.BuildItem
.Target
]
642 self
.BuildTread
= Thread(target
=self
._CommandThread
, args
=(Command
, self
.BuildItem
.WorkingDir
))
643 self
.BuildTread
.setName("build thread")
644 self
.BuildTread
.setDaemon(False)
645 self
.BuildTread
.start()
647 ## The class contains the information related to EFI image
652 # Constructor will load all required image information.
654 # @param BaseName The full file path of image.
655 # @param Guid The GUID for image.
656 # @param Arch Arch of this image.
657 # @param OutputDir The output directory for image.
658 # @param DebugDir The debug directory for image.
659 # @param ImageClass PeImage Information
661 def __init__(self
, BaseName
, Guid
, Arch
, OutputDir
, DebugDir
, ImageClass
):
662 self
.BaseName
= BaseName
665 self
.OutputDir
= OutputDir
666 self
.DebugDir
= DebugDir
667 self
.Image
= ImageClass
668 self
.Image
.Size
= (self
.Image
.Size
/ 0x1000 + 1) * 0x1000
670 ## The class implementing the EDK2 build process
672 # The build process includes:
673 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
674 # 2. Parse DSC file of active platform
675 # 3. Parse FDF file if any
676 # 4. Establish build database, including parse all other files (module, package)
677 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
678 # 6. Call build command
683 # Constructor will load all necessary configurations, parse platform, modules
684 # and packages and the establish a database for AutoGen.
686 # @param Target The build command target, one of gSupportedTarget
687 # @param WorkspaceDir The directory of workspace
688 # @param BuildOptions Build options passed from command line
690 def __init__(self
, Target
, WorkspaceDir
, BuildOptions
):
691 self
.WorkspaceDir
= WorkspaceDir
693 self
.PlatformFile
= BuildOptions
.PlatformFile
694 self
.ModuleFile
= BuildOptions
.ModuleFile
695 self
.ArchList
= BuildOptions
.TargetArch
696 self
.ToolChainList
= BuildOptions
.ToolChain
697 self
.BuildTargetList
= BuildOptions
.BuildTarget
698 self
.Fdf
= BuildOptions
.FdfFile
699 self
.FdList
= BuildOptions
.RomImage
700 self
.FvList
= BuildOptions
.FvImage
701 self
.CapList
= BuildOptions
.CapName
702 self
.SilentMode
= BuildOptions
.SilentMode
703 self
.ThreadNumber
= BuildOptions
.ThreadNumber
704 self
.SkipAutoGen
= BuildOptions
.SkipAutoGen
705 self
.Reparse
= BuildOptions
.Reparse
706 self
.SkuId
= BuildOptions
.SkuId
708 GlobalData
.gSKUID_CMD
= self
.SkuId
709 self
.ConfDirectory
= BuildOptions
.ConfDirectory
710 self
.SpawnMode
= True
711 self
.BuildReport
= BuildReport(BuildOptions
.ReportFile
, BuildOptions
.ReportType
)
712 self
.TargetTxt
= TargetTxtClassObject()
713 self
.ToolDef
= ToolDefClassObject()
717 GlobalData
.BuildOptionPcd
= BuildOptions
.OptionPcd
if BuildOptions
.OptionPcd
else []
718 #Set global flag for build mode
719 GlobalData
.gIgnoreSource
= BuildOptions
.IgnoreSources
720 GlobalData
.gUseHashCache
= BuildOptions
.UseHashCache
721 GlobalData
.gBinCacheDest
= BuildOptions
.BinCacheDest
722 GlobalData
.gBinCacheSource
= BuildOptions
.BinCacheSource
723 GlobalData
.gEnableGenfdsMultiThread
= BuildOptions
.GenfdsMultiThread
725 if GlobalData
.gBinCacheDest
and not GlobalData
.gUseHashCache
:
726 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination must be used together with --hash.")
728 if GlobalData
.gBinCacheSource
and not GlobalData
.gUseHashCache
:
729 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-source must be used together with --hash.")
731 if GlobalData
.gBinCacheDest
and GlobalData
.gBinCacheSource
:
732 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination can not be used together with --binary-source.")
734 if GlobalData
.gBinCacheSource
:
735 BinCacheSource
= os
.path
.normpath(GlobalData
.gBinCacheSource
)
736 if not os
.path
.isabs(BinCacheSource
):
737 BinCacheSource
= mws
.join(self
.WorkspaceDir
, BinCacheSource
)
738 GlobalData
.gBinCacheSource
= BinCacheSource
740 if GlobalData
.gBinCacheSource
is not None:
741 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-source.")
743 if GlobalData
.gBinCacheDest
:
744 BinCacheDest
= os
.path
.normpath(GlobalData
.gBinCacheDest
)
745 if not os
.path
.isabs(BinCacheDest
):
746 BinCacheDest
= mws
.join(self
.WorkspaceDir
, BinCacheDest
)
747 GlobalData
.gBinCacheDest
= BinCacheDest
749 if GlobalData
.gBinCacheDest
is not None:
750 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-destination.")
752 if self
.ConfDirectory
:
753 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
754 ConfDirectoryPath
= os
.path
.normpath(self
.ConfDirectory
)
756 if not os
.path
.isabs(ConfDirectoryPath
):
757 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
758 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
759 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, ConfDirectoryPath
)
761 if "CONF_PATH" in os
.environ
:
762 ConfDirectoryPath
= os
.path
.normcase(os
.path
.normpath(os
.environ
["CONF_PATH"]))
764 # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf
765 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, 'Conf')
766 GlobalData
.gConfDirectory
= ConfDirectoryPath
767 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
769 self
.Db
= WorkspaceDatabase()
770 self
.BuildDatabase
= self
.Db
.BuildObject
772 self
.ToolChainFamily
= None
773 self
.LoadFixAddress
= 0
774 self
.UniFlag
= BuildOptions
.Flag
775 self
.BuildModules
= []
776 self
.HashSkipModules
= []
778 self
.LaunchPrebuildFlag
= False
779 self
.PlatformBuildPath
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PlatformBuild')
780 if BuildOptions
.CommandLength
:
781 GlobalData
.gCommandMaxLength
= BuildOptions
.CommandLength
783 # print dot character during doing some time-consuming work
784 self
.Progress
= Utils
.Progressor()
785 # print current build environment and configuration
786 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
787 if "PACKAGES_PATH" in os
.environ
:
788 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
789 EdkLogger
.quiet("%-16s = %s" % ("PACKAGES_PATH", os
.path
.normcase(os
.path
.normpath(os
.environ
["PACKAGES_PATH"]))))
790 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
791 if "EDK_TOOLS_BIN" in os
.environ
:
792 # Print the same path style with WORKSPACE env.
793 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_TOOLS_BIN"]))))
794 EdkLogger
.quiet("%-16s = %s" % ("CONF_PATH", GlobalData
.gConfDirectory
))
798 EdkLogger
.quiet("%-16s = %s" % ("PREBUILD", self
.Prebuild
))
800 EdkLogger
.quiet("%-16s = %s" % ("POSTBUILD", self
.Postbuild
))
802 self
.LaunchPrebuild()
803 self
.TargetTxt
= TargetTxtClassObject()
804 self
.ToolDef
= ToolDefClassObject()
805 if not (self
.LaunchPrebuildFlag
and os
.path
.exists(self
.PlatformBuildPath
)):
809 os
.chdir(self
.WorkspaceDir
)
811 ## Load configuration
813 # This method will parse target.txt and get the build configurations.
815 def LoadConfiguration(self
):
817 # Check target.txt and tools_def.txt and Init them
819 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(GlobalData
.gConfDirectory
, gBuildConfiguration
))
820 if os
.path
.isfile(BuildConfigurationFile
) == True:
821 StatusCode
= self
.TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
823 ToolDefinitionFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_CONF
]
824 if ToolDefinitionFile
== '':
825 ToolDefinitionFile
= gToolsDefinition
826 ToolDefinitionFile
= os
.path
.normpath(mws
.join(self
.WorkspaceDir
, 'Conf', ToolDefinitionFile
))
827 if os
.path
.isfile(ToolDefinitionFile
) == True:
828 StatusCode
= self
.ToolDef
.LoadToolDefFile(ToolDefinitionFile
)
830 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=ToolDefinitionFile
)
832 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
834 # if no ARCH given in command line, get it from target.txt
835 if not self
.ArchList
:
836 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET_ARCH
]
837 self
.ArchList
= tuple(self
.ArchList
)
839 # if no build target given in command line, get it from target.txt
840 if not self
.BuildTargetList
:
841 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
843 # if no tool chain given in command line, get it from target.txt
844 if not self
.ToolChainList
:
845 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
846 if self
.ToolChainList
is None or len(self
.ToolChainList
) == 0:
847 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
849 # check if the tool chains are defined or not
850 NewToolChainList
= []
851 for ToolChain
in self
.ToolChainList
:
852 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
853 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
855 NewToolChainList
.append(ToolChain
)
856 # if no tool chain available, break the build
857 if len(NewToolChainList
) == 0:
858 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
859 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
861 self
.ToolChainList
= NewToolChainList
864 ToolDefinition
= self
.ToolDef
.ToolsDefTxtDatabase
865 for Tool
in self
.ToolChainList
:
866 if TAB_TOD_DEFINES_FAMILY
not in ToolDefinition
or Tool
not in ToolDefinition
[TAB_TOD_DEFINES_FAMILY
] \
867 or not ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
]:
868 EdkLogger
.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool
)
869 ToolChainFamily
.append(TAB_COMPILER_MSFT
)
871 ToolChainFamily
.append(ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
])
872 self
.ToolChainFamily
= ToolChainFamily
874 if self
.ThreadNumber
is None:
875 self
.ThreadNumber
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
876 if self
.ThreadNumber
== '':
877 self
.ThreadNumber
= 0
879 self
.ThreadNumber
= int(self
.ThreadNumber
, 0)
881 if self
.ThreadNumber
== 0:
883 self
.ThreadNumber
= multiprocessing
.cpu_count()
884 except (ImportError, NotImplementedError):
885 self
.ThreadNumber
= 1
887 if not self
.PlatformFile
:
888 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
890 # Try to find one in current directory
891 WorkingDirectory
= os
.getcwd()
892 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
893 FileNum
= len(FileList
)
895 EdkLogger
.error("build", OPTION_MISSING
,
896 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
898 PlatformFile
= FileList
[0]
900 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
901 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
903 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
905 ## Initialize build configuration
907 # This method will parse DSC file and merge the configurations from
908 # command line and target.txt, then get the final build configurations.
911 # parse target.txt, tools_def.txt, and platform file
912 self
.LoadConfiguration()
914 # Allow case-insensitive for those from command line or configuration file
915 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
917 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
920 def InitPreBuild(self
):
921 self
.LoadConfiguration()
922 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
924 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
925 if self
.BuildTargetList
:
926 GlobalData
.gGlobalDefines
['TARGET'] = self
.BuildTargetList
[0]
928 GlobalData
.gGlobalDefines
['ARCH'] = self
.ArchList
[0]
929 if self
.ToolChainList
:
930 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = self
.ToolChainList
[0]
931 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = self
.ToolChainList
[0]
932 if self
.ToolChainFamily
:
933 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[0]
934 if 'PREBUILD' in GlobalData
.gCommandLineDefines
:
935 self
.Prebuild
= GlobalData
.gCommandLineDefines
.get('PREBUILD')
938 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
939 self
.Prebuild
= str(Platform
.Prebuild
)
943 # Evaluate all arguments and convert arguments that are WORKSPACE
944 # relative paths to absolute paths. Filter arguments that look like
945 # flags or do not follow the file/dir naming rules to avoid false
946 # positives on this conversion.
948 for Arg
in self
.Prebuild
.split():
950 # Do not modify Arg if it looks like a flag or an absolute file path
952 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
953 PrebuildList
.append(Arg
)
956 # Do not modify Arg if it does not look like a Workspace relative
957 # path that starts with a valid package directory name
959 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
960 PrebuildList
.append(Arg
)
963 # If Arg looks like a WORKSPACE relative path, then convert to an
964 # absolute path and check to see if the file exists.
966 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
967 if os
.path
.isfile(Temp
):
969 PrebuildList
.append(Arg
)
970 self
.Prebuild
= ' '.join(PrebuildList
)
971 self
.Prebuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
973 def InitPostBuild(self
):
974 if 'POSTBUILD' in GlobalData
.gCommandLineDefines
:
975 self
.Postbuild
= GlobalData
.gCommandLineDefines
.get('POSTBUILD')
977 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
978 self
.Postbuild
= str(Platform
.Postbuild
)
982 # Evaluate all arguments and convert arguments that are WORKSPACE
983 # relative paths to absolute paths. Filter arguments that look like
984 # flags or do not follow the file/dir naming rules to avoid false
985 # positives on this conversion.
987 for Arg
in self
.Postbuild
.split():
989 # Do not modify Arg if it looks like a flag or an absolute file path
991 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
992 PostbuildList
.append(Arg
)
995 # Do not modify Arg if it does not look like a Workspace relative
996 # path that starts with a valid package directory name
998 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
999 PostbuildList
.append(Arg
)
1002 # If Arg looks like a WORKSPACE relative path, then convert to an
1003 # absolute path and check to see if the file exists.
1005 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1006 if os
.path
.isfile(Temp
):
1008 PostbuildList
.append(Arg
)
1009 self
.Postbuild
= ' '.join(PostbuildList
)
1010 self
.Postbuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1012 def PassCommandOption(self
, BuildTarget
, TargetArch
, ToolChain
, PlatformFile
, Target
):
1014 if GlobalData
.gCommand
and isinstance(GlobalData
.gCommand
, list):
1015 BuildStr
+= ' ' + ' '.join(GlobalData
.gCommand
)
1018 ToolChainFlag
= False
1019 PlatformFileFlag
= False
1021 if GlobalData
.gOptions
and not GlobalData
.gOptions
.BuildTarget
:
1023 if GlobalData
.gOptions
and not GlobalData
.gOptions
.TargetArch
:
1025 if GlobalData
.gOptions
and not GlobalData
.gOptions
.ToolChain
:
1026 ToolChainFlag
= True
1027 if GlobalData
.gOptions
and not GlobalData
.gOptions
.PlatformFile
:
1028 PlatformFileFlag
= True
1030 if TargetFlag
and BuildTarget
:
1031 if isinstance(BuildTarget
, list) or isinstance(BuildTarget
, tuple):
1032 BuildStr
+= ' -b ' + ' -b '.join(BuildTarget
)
1033 elif isinstance(BuildTarget
, str):
1034 BuildStr
+= ' -b ' + BuildTarget
1035 if ArchFlag
and TargetArch
:
1036 if isinstance(TargetArch
, list) or isinstance(TargetArch
, tuple):
1037 BuildStr
+= ' -a ' + ' -a '.join(TargetArch
)
1038 elif isinstance(TargetArch
, str):
1039 BuildStr
+= ' -a ' + TargetArch
1040 if ToolChainFlag
and ToolChain
:
1041 if isinstance(ToolChain
, list) or isinstance(ToolChain
, tuple):
1042 BuildStr
+= ' -t ' + ' -t '.join(ToolChain
)
1043 elif isinstance(ToolChain
, str):
1044 BuildStr
+= ' -t ' + ToolChain
1045 if PlatformFileFlag
and PlatformFile
:
1046 if isinstance(PlatformFile
, list) or isinstance(PlatformFile
, tuple):
1047 BuildStr
+= ' -p ' + ' -p '.join(PlatformFile
)
1048 elif isinstance(PlatformFile
, str):
1049 BuildStr
+= ' -p' + PlatformFile
1050 BuildStr
+= ' --conf=' + GlobalData
.gConfDirectory
1052 BuildStr
+= ' ' + Target
1056 def LaunchPrebuild(self
):
1058 EdkLogger
.info("\n- Prebuild Start -\n")
1059 self
.LaunchPrebuildFlag
= True
1061 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1062 # and preserve them for the rest of the main build step, because the child process environment will
1063 # evaporate as soon as it exits, we cannot get it in build step.
1065 PrebuildEnvFile
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PrebuildEnv')
1066 if os
.path
.isfile(PrebuildEnvFile
):
1067 os
.remove(PrebuildEnvFile
)
1068 if os
.path
.isfile(self
.PlatformBuildPath
):
1069 os
.remove(self
.PlatformBuildPath
)
1070 if sys
.platform
== "win32":
1071 args
= ' && '.join((self
.Prebuild
, 'set > ' + PrebuildEnvFile
))
1072 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1074 args
= ' && '.join((self
.Prebuild
, 'env > ' + PrebuildEnvFile
))
1075 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1077 # launch two threads to read the STDOUT and STDERR
1078 EndOfProcedure
= Event()
1079 EndOfProcedure
.clear()
1081 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1082 StdOutThread
.setName("STDOUT-Redirector")
1083 StdOutThread
.setDaemon(False)
1084 StdOutThread
.start()
1087 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1088 StdErrThread
.setName("STDERR-Redirector")
1089 StdErrThread
.setDaemon(False)
1090 StdErrThread
.start()
1091 # waiting for program exit
1098 if Process
.returncode
!= 0 :
1099 EdkLogger
.error("Prebuild", PREBUILD_ERROR
, 'Prebuild process is not success!')
1101 if os
.path
.exists(PrebuildEnvFile
):
1102 f
= open(PrebuildEnvFile
)
1103 envs
= f
.readlines()
1105 envs
= itertools
.imap(lambda l
: l
.split('=', 1), envs
)
1106 envs
= itertools
.ifilter(lambda l
: len(l
) == 2, envs
)
1107 envs
= itertools
.imap(lambda l
: [i
.strip() for i
in l
], envs
)
1108 os
.environ
.update(dict(envs
))
1109 EdkLogger
.info("\n- Prebuild Done -\n")
1111 def LaunchPostbuild(self
):
1113 EdkLogger
.info("\n- Postbuild Start -\n")
1114 if sys
.platform
== "win32":
1115 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1117 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1118 # launch two threads to read the STDOUT and STDERR
1119 EndOfProcedure
= Event()
1120 EndOfProcedure
.clear()
1122 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1123 StdOutThread
.setName("STDOUT-Redirector")
1124 StdOutThread
.setDaemon(False)
1125 StdOutThread
.start()
1128 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1129 StdErrThread
.setName("STDERR-Redirector")
1130 StdErrThread
.setDaemon(False)
1131 StdErrThread
.start()
1132 # waiting for program exit
1139 if Process
.returncode
!= 0 :
1140 EdkLogger
.error("Postbuild", POSTBUILD_ERROR
, 'Postbuild process is not success!')
1141 EdkLogger
.info("\n- Postbuild Done -\n")
1142 ## Build a module or platform
1144 # Create autogen code and makefile for a module or platform, and the launch
1145 # "make" command to build it
1147 # @param Target The target of build command
1148 # @param Platform The platform file
1149 # @param Module The module file
1150 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1151 # @param ToolChain The name of toolchain to build
1152 # @param Arch The arch of the module/platform
1153 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1154 # for dependent modules/Libraries
1155 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1156 # for dependent modules/Libraries
1158 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False, FfsCommand
={}):
1159 if AutoGenObject
is None:
1162 # skip file generation for cleanxxx targets, run and fds target
1163 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1164 # for target which must generate AutoGen code and makefile
1165 if not self
.SkipAutoGen
or Target
== 'genc':
1166 self
.Progress
.Start("Generating code")
1167 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1168 self
.Progress
.Stop("done!")
1169 if Target
== "genc":
1172 if not self
.SkipAutoGen
or Target
== 'genmake':
1173 self
.Progress
.Start("Generating makefile")
1174 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
, FfsCommand
)
1175 self
.Progress
.Stop("done!")
1176 if Target
== "genmake":
1179 # always recreate top/platform makefile when clean, just in case of inconsistency
1180 AutoGenObject
.CreateCodeFile(False)
1181 AutoGenObject
.CreateMakeFile(False)
1183 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1184 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1186 BuildCommand
= AutoGenObject
.BuildCommand
1187 if BuildCommand
is None or len(BuildCommand
) == 0:
1188 EdkLogger
.error("build", OPTION_MISSING
,
1189 "No build command found for this module. "
1190 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1191 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1192 ExtraData
=str(AutoGenObject
))
1194 makefile
= GenMake
.BuildFile(AutoGenObject
)._FILE
_NAME
_[GenMake
.gMakeType
]
1198 RunDir
= os
.path
.normpath(os
.path
.join(AutoGenObject
.BuildDir
, GlobalData
.gGlobalDefines
['ARCH']))
1199 Command
= '.\SecMain'
1201 LaunchCommand(Command
, RunDir
)
1206 BuildCommand
= BuildCommand
+ [Target
]
1207 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1208 self
.CreateAsBuiltInf()
1212 if Target
== 'libraries':
1213 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1214 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1215 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1219 if Target
== 'modules':
1220 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1221 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1222 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1223 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1224 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, makefile
)), 'pbuild']
1225 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1226 self
.CreateAsBuiltInf()
1230 if Target
== 'cleanlib':
1231 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1232 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1233 if os
.path
.exists(LibMakefile
):
1234 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1235 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1239 if Target
== 'clean':
1240 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1241 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, makefile
))
1242 if os
.path
.exists(ModMakefile
):
1243 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
1244 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1245 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1246 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1247 if os
.path
.exists(LibMakefile
):
1248 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1249 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1253 if Target
== 'cleanall':
1255 #os.rmdir(AutoGenObject.BuildDir)
1256 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1257 except WindowsError as X
:
1258 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1261 ## Build a module or platform
1263 # Create autogen code and makefile for a module or platform, and the launch
1264 # "make" command to build it
1266 # @param Target The target of build command
1267 # @param Platform The platform file
1268 # @param Module The module file
1269 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1270 # @param ToolChain The name of toolchain to build
1271 # @param Arch The arch of the module/platform
1272 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1273 # for dependent modules/Libraries
1274 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1275 # for dependent modules/Libraries
1277 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1278 if AutoGenObject
is None:
1281 # skip file generation for cleanxxx targets, run and fds target
1282 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1283 # for target which must generate AutoGen code and makefile
1284 if not self
.SkipAutoGen
or Target
== 'genc':
1285 self
.Progress
.Start("Generating code")
1286 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1287 self
.Progress
.Stop("done!")
1288 if Target
== "genc":
1291 if not self
.SkipAutoGen
or Target
== 'genmake':
1292 self
.Progress
.Start("Generating makefile")
1293 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1294 #AutoGenObject.CreateAsBuiltInf()
1295 self
.Progress
.Stop("done!")
1296 if Target
== "genmake":
1299 # always recreate top/platform makefile when clean, just in case of inconsistency
1300 AutoGenObject
.CreateCodeFile(False)
1301 AutoGenObject
.CreateMakeFile(False)
1303 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1304 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1306 BuildCommand
= AutoGenObject
.BuildCommand
1307 if BuildCommand
is None or len(BuildCommand
) == 0:
1308 EdkLogger
.error("build", OPTION_MISSING
,
1309 "No build command found for this module. "
1310 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1311 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1312 ExtraData
=str(AutoGenObject
))
1317 BuildCommand
= BuildCommand
+ [Target
]
1318 AutoGenObject
.BuildTime
= LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1319 self
.CreateAsBuiltInf()
1324 if GenFdsApi(AutoGenObject
.GenFdsCommandDict
, self
.Db
):
1325 EdkLogger
.error("build", COMMAND_FAILURE
)
1330 RunDir
= os
.path
.normpath(os
.path
.join(AutoGenObject
.BuildDir
, GlobalData
.gGlobalDefines
['ARCH']))
1331 Command
= '.\SecMain'
1333 LaunchCommand(Command
, RunDir
)
1337 if Target
== 'libraries':
1344 if Target
== 'cleanall':
1346 #os.rmdir(AutoGenObject.BuildDir)
1347 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1348 except WindowsError as X
:
1349 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1352 ## Rebase module image and Get function address for the input module list.
1354 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1356 AddrIsOffset
= False
1357 for InfFile
in ModuleList
:
1358 sys
.stdout
.write (".")
1360 ModuleInfo
= ModuleList
[InfFile
]
1361 ModuleName
= ModuleInfo
.BaseName
1362 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1363 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1364 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1366 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1368 # Update Image to new BaseAddress by GenFw tool
1370 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1371 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1374 # Set new address to the section header only for SMM driver.
1376 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1377 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1379 # Collect funtion address from Map file
1381 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1383 if os
.path
.exists(ImageMapTable
):
1384 OrigImageBaseAddress
= 0
1385 ImageMap
= open(ImageMapTable
, 'r')
1386 for LinStr
in ImageMap
:
1387 if len (LinStr
.strip()) == 0:
1390 # Get the preferred address set on link time.
1392 if LinStr
.find ('Preferred load address is') != -1:
1393 StrList
= LinStr
.split()
1394 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1396 StrList
= LinStr
.split()
1397 if len (StrList
) > 4:
1398 if StrList
[3] == 'f' or StrList
[3] == 'F':
1400 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1401 FunctionList
.append ((Name
, RelativeAddress
))
1405 # Add general information.
1408 MapBuffer
.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1410 MapBuffer
.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1412 MapBuffer
.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1414 # Add guid and general seciton section.
1416 TextSectionAddress
= 0
1417 DataSectionAddress
= 0
1418 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1419 if SectionHeader
[0] == '.text':
1420 TextSectionAddress
= SectionHeader
[1]
1421 elif SectionHeader
[0] in ['.data', '.sdata']:
1422 DataSectionAddress
= SectionHeader
[1]
1424 MapBuffer
.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1426 MapBuffer
.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1428 # Add debug image full path.
1430 MapBuffer
.write('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1432 # Add funtion address
1434 for Function
in FunctionList
:
1436 MapBuffer
.write(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1438 MapBuffer
.write(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1442 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1445 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1447 ## Collect MAP information of all FVs
1449 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1451 # First get the XIP base address for FV map file.
1452 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1453 GuidName
= re
.compile("\(GUID=[-a-fA-F0-9]+")
1454 for FvName
in Wa
.FdfProfile
.FvDict
:
1455 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1456 if not os
.path
.exists(FvMapBuffer
):
1458 FvMap
= open(FvMapBuffer
, 'r')
1459 #skip FV size information
1465 MatchGuid
= GuidPattern
.match(Line
)
1466 if MatchGuid
is not None:
1468 # Replace GUID with module name
1470 GuidString
= MatchGuid
.group()
1471 if GuidString
.upper() in ModuleList
:
1472 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1473 MapBuffer
.write(Line
)
1475 # Add the debug image full path.
1477 MatchGuid
= GuidName
.match(Line
)
1478 if MatchGuid
is not None:
1479 GuidString
= MatchGuid
.group().split("=")[1]
1480 if GuidString
.upper() in ModuleList
:
1481 MapBuffer
.write('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1485 ## Collect MAP information of all modules
1487 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1488 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1490 PatchEfiImageList
= []
1498 # reserve 4K size in SMRAM to make SMM module address not from 0.
1500 for ModuleGuid
in ModuleList
:
1501 Module
= ModuleList
[ModuleGuid
]
1502 GlobalData
.gProcessingFile
= "%s [%s, %s, %s]" % (Module
.MetaFile
, Module
.Arch
, Module
.ToolChain
, Module
.BuildTarget
)
1504 OutputImageFile
= ''
1505 for ResultFile
in Module
.CodaTargetList
:
1506 if str(ResultFile
.Target
).endswith('.efi'):
1508 # module list for PEI, DXE, RUNTIME and SMM
1510 OutputImageFile
= os
.path
.join(Module
.OutputDir
, Module
.Name
+ '.efi')
1511 ImageClass
= PeImageClass (OutputImageFile
)
1512 if not ImageClass
.IsValid
:
1513 EdkLogger
.error("build", FILE_PARSE_FAILURE
, ExtraData
=ImageClass
.ErrorInfo
)
1514 ImageInfo
= PeImageInfo(Module
.Name
, Module
.Guid
, Module
.Arch
, Module
.OutputDir
, Module
.DebugDir
, ImageClass
)
1515 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
]:
1516 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1517 PeiSize
+= ImageInfo
.Image
.Size
1518 elif Module
.ModuleType
in [EDK_COMPONENT_TYPE_BS_DRIVER
, SUP_MODULE_DXE_DRIVER
, SUP_MODULE_UEFI_DRIVER
]:
1519 BtModuleList
[Module
.MetaFile
] = ImageInfo
1520 BtSize
+= ImageInfo
.Image
.Size
1521 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
]:
1522 RtModuleList
[Module
.MetaFile
] = ImageInfo
1523 RtSize
+= ImageInfo
.Image
.Size
1524 elif Module
.ModuleType
in [SUP_MODULE_SMM_CORE
, SUP_MODULE_DXE_SMM_DRIVER
, SUP_MODULE_MM_STANDALONE
, SUP_MODULE_MM_CORE_STANDALONE
]:
1525 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1526 SmmSize
+= ImageInfo
.Image
.Size
1527 if Module
.ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
1528 PiSpecVersion
= Module
.Module
.Specification
.get('PI_SPECIFICATION_VERSION', '0x00000000')
1529 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1530 if int(PiSpecVersion
, 16) < 0x0001000A:
1531 BtModuleList
[Module
.MetaFile
] = ImageInfo
1532 BtSize
+= ImageInfo
.Image
.Size
1535 # EFI image is final target.
1536 # Check EFI image contains patchable FixAddress related PCDs.
1538 if OutputImageFile
!= '':
1539 ModuleIsPatch
= False
1540 for Pcd
in Module
.ModulePcdList
:
1541 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1542 ModuleIsPatch
= True
1544 if not ModuleIsPatch
:
1545 for Pcd
in Module
.LibraryPcdList
:
1546 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1547 ModuleIsPatch
= True
1550 if not ModuleIsPatch
:
1553 # Module includes the patchable load fix address PCDs.
1554 # It will be fixed up later.
1556 PatchEfiImageList
.append (OutputImageFile
)
1559 # Get Top Memory address
1561 ReservedRuntimeMemorySize
= 0
1562 TopMemoryAddress
= 0
1563 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1564 TopMemoryAddress
= 0
1566 TopMemoryAddress
= self
.LoadFixAddress
1567 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1568 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1571 # Patch FixAddress related PCDs into EFI image
1573 for EfiImage
in PatchEfiImageList
:
1574 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1575 if not os
.path
.exists(EfiImageMap
):
1578 # Get PCD offset in EFI image by GenPatchPcdTable function
1580 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1582 # Patch real PCD value by PatchPcdValue tool
1584 for PcdInfo
in PcdTable
:
1586 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1587 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
/ 0x1000))
1588 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1589 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
/ 0x1000))
1590 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1591 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
/ 0x1000))
1592 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1593 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
/ 0x1000))
1594 if ReturnValue
!= 0:
1595 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1597 MapBuffer
.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
/ 0x1000))
1598 MapBuffer
.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
/ 0x1000))
1599 MapBuffer
.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
/ 0x1000))
1600 if len (SmmModuleList
) > 0:
1601 MapBuffer
.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
/ 0x1000))
1603 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1604 BtBaseAddr
= TopMemoryAddress
- RtSize
1605 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1607 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1608 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1609 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1610 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
=False, ModeIsSmm
=True)
1611 MapBuffer
.write('\n\n')
1612 sys
.stdout
.write ("\n")
1615 ## Save platform Map file
1617 def _SaveMapFile (self
, MapBuffer
, Wa
):
1619 # Map file path is got.
1621 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1623 # Save address map into MAP file.
1625 SaveFileOnChange(MapFilePath
, MapBuffer
.getvalue(), False)
1627 if self
.LoadFixAddress
!= 0:
1628 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath
))
1631 ## Build active platform for different build targets and different tool chains
1633 def _BuildPlatform(self
):
1634 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1635 for BuildTarget
in self
.BuildTargetList
:
1636 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1638 for ToolChain
in self
.ToolChainList
:
1639 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1640 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1641 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1643 Wa
= WorkspaceAutoGen(
1660 self
.Fdf
= Wa
.FdfFile
1661 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1662 self
.BuildReport
.AddPlatformReport(Wa
)
1663 self
.Progress
.Stop("done!")
1665 # Add ffs build to makefile
1667 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1668 CmdListDict
= self
._GenFfsCmd
()
1670 for Arch
in Wa
.ArchList
:
1671 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1672 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1673 for Module
in Pa
.Platform
.Modules
:
1674 # Get ModuleAutoGen object to generate C code file and makefile
1675 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1678 self
.BuildModules
.append(Ma
)
1679 self
._BuildPa
(self
.Target
, Pa
, FfsCommand
=CmdListDict
)
1681 # Create MAP file when Load Fix Address is enabled.
1682 if self
.Target
in ["", "all", "fds"]:
1683 for Arch
in Wa
.ArchList
:
1684 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1686 # Check whether the set fix address is above 4G for 32bit image.
1688 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1689 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")
1694 for Pa
in Wa
.AutoGenObjectList
:
1695 for Ma
in Pa
.ModuleAutoGenList
:
1698 if not Ma
.IsLibrary
:
1699 ModuleList
[Ma
.Guid
.upper()] = Ma
1701 MapBuffer
= BytesIO('')
1702 if self
.LoadFixAddress
!= 0:
1704 # Rebase module to the preferred memory address before GenFds
1706 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1709 # create FDS again for the updated EFI image
1711 self
._Build
("fds", Wa
)
1713 # Create MAP file for all platform FVs after GenFds.
1715 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1717 # Save MAP buffer into MAP file.
1719 self
._SaveMapFile
(MapBuffer
, Wa
)
1721 ## Build active module for different build targets, different tool chains and different archs
1723 def _BuildModule(self
):
1724 for BuildTarget
in self
.BuildTargetList
:
1725 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1727 for ToolChain
in self
.ToolChainList
:
1728 WorkspaceAutoGenTime
= time
.time()
1729 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1730 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1731 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1734 # module build needs platform build information, so get platform
1737 Wa
= WorkspaceAutoGen(
1755 self
.Fdf
= Wa
.FdfFile
1756 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1757 Wa
.CreateMakeFile(False)
1758 # Add ffs build to makefile
1760 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1761 CmdListDict
= self
._GenFfsCmd
()
1762 self
.Progress
.Stop("done!")
1764 ExitFlag
= threading
.Event()
1766 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1767 for Arch
in Wa
.ArchList
:
1768 AutoGenStart
= time
.time()
1769 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1770 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1771 for Module
in Pa
.Platform
.Modules
:
1772 if self
.ModuleFile
.Dir
== Module
.Dir
and self
.ModuleFile
.Name
== Module
.Name
:
1773 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1774 if Ma
is None: continue
1776 if Ma
.CanSkipbyHash():
1777 self
.HashSkipModules
.append(Ma
)
1779 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1780 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1781 # for target which must generate AutoGen code and makefile
1782 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1783 self
.Progress
.Start("Generating code")
1784 Ma
.CreateCodeFile(True)
1785 self
.Progress
.Stop("done!")
1786 if self
.Target
== "genc":
1788 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1789 self
.Progress
.Start("Generating makefile")
1790 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
1791 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
1792 del CmdListDict
[Module
.File
, Arch
]
1794 Ma
.CreateMakeFile(True)
1795 self
.Progress
.Stop("done!")
1796 if self
.Target
== "genmake":
1798 self
.BuildModules
.append(Ma
)
1799 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1800 MakeStart
= time
.time()
1801 for Ma
in self
.BuildModules
:
1802 if not Ma
.IsBinaryModule
:
1803 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
1804 # Break build if any build thread has error
1805 if BuildTask
.HasError():
1806 # we need a full version of makefile for platform
1808 BuildTask
.WaitForComplete()
1809 Pa
.CreateMakeFile(False)
1810 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1811 # Start task scheduler
1812 if not BuildTask
.IsOnGoing():
1813 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1815 # in case there's an interruption. we need a full version of makefile for platform
1816 Pa
.CreateMakeFile(False)
1817 if BuildTask
.HasError():
1818 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1819 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1821 MakeContiue
= time
.time()
1823 BuildTask
.WaitForComplete()
1824 self
.CreateAsBuiltInf()
1825 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1826 if BuildTask
.HasError():
1827 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1829 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1834 "Module for [%s] is not a component of active platform."\
1835 " Please make sure that the ARCH and inf file path are"\
1836 " given in the same as in [%s]" % \
1837 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1838 ExtraData
=self
.ModuleFile
1840 # Create MAP file when Load Fix Address is enabled.
1841 if self
.Target
== "fds" and self
.Fdf
:
1842 for Arch
in Wa
.ArchList
:
1844 # Check whether the set fix address is above 4G for 32bit image.
1846 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1847 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")
1852 for Pa
in Wa
.AutoGenObjectList
:
1853 for Ma
in Pa
.ModuleAutoGenList
:
1856 if not Ma
.IsLibrary
:
1857 ModuleList
[Ma
.Guid
.upper()] = Ma
1859 MapBuffer
= BytesIO('')
1860 if self
.LoadFixAddress
!= 0:
1862 # Rebase module to the preferred memory address before GenFds
1864 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1866 # create FDS again for the updated EFI image
1868 GenFdsStart
= time
.time()
1869 self
._Build
("fds", Wa
)
1870 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
1872 # Create MAP file for all platform FVs after GenFds.
1874 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1876 # Save MAP buffer into MAP file.
1878 self
._SaveMapFile
(MapBuffer
, Wa
)
1880 def _GenFfsCmd(self
):
1881 # convert dictionary of Cmd:(Inf,Arch)
1882 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
1883 CmdSetDict
= defaultdict(set)
1884 GenFfsDict
= GenFds
.GenFfsMakefile('', GlobalData
.gFdfParser
, self
, self
.ArchList
, GlobalData
)
1885 for Cmd
in GenFfsDict
:
1886 tmpInf
, tmpArch
= GenFfsDict
[Cmd
]
1887 CmdSetDict
[tmpInf
, tmpArch
].add(Cmd
)
1890 ## Build a platform in multi-thread mode
1892 def _MultiThreadBuildPlatform(self
):
1893 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1894 for BuildTarget
in self
.BuildTargetList
:
1895 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1897 for ToolChain
in self
.ToolChainList
:
1898 WorkspaceAutoGenTime
= time
.time()
1899 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1900 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1901 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1903 Wa
= WorkspaceAutoGen(
1920 self
.Fdf
= Wa
.FdfFile
1921 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1922 self
.BuildReport
.AddPlatformReport(Wa
)
1923 Wa
.CreateMakeFile(False)
1925 # Add ffs build to makefile
1927 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1928 CmdListDict
= self
._GenFfsCmd
()
1930 # multi-thread exit flag
1931 ExitFlag
= threading
.Event()
1933 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1934 for Arch
in Wa
.ArchList
:
1935 AutoGenStart
= time
.time()
1936 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1937 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1941 for Inf
in Pa
.Platform
.Modules
:
1942 ModuleList
.append(Inf
)
1943 # Add the INF only list in FDF
1944 if GlobalData
.gFdfParser
is not None:
1945 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
1946 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
1947 if Inf
in Pa
.Platform
.Modules
:
1949 ModuleList
.append(Inf
)
1950 for Module
in ModuleList
:
1951 # Get ModuleAutoGen object to generate C code file and makefile
1952 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1956 if Ma
.CanSkipbyHash():
1957 self
.HashSkipModules
.append(Ma
)
1960 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1961 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1962 # for target which must generate AutoGen code and makefile
1963 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1964 Ma
.CreateCodeFile(True)
1965 if self
.Target
== "genc":
1968 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1969 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
1970 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
1971 del CmdListDict
[Module
.File
, Arch
]
1973 Ma
.CreateMakeFile(True)
1974 if self
.Target
== "genmake":
1976 self
.BuildModules
.append(Ma
)
1977 self
.Progress
.Stop("done!")
1978 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1979 MakeStart
= time
.time()
1980 for Ma
in self
.BuildModules
:
1981 # Generate build task for the module
1982 if not Ma
.IsBinaryModule
:
1983 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
1984 # Break build if any build thread has error
1985 if BuildTask
.HasError():
1986 # we need a full version of makefile for platform
1988 BuildTask
.WaitForComplete()
1989 Pa
.CreateMakeFile(False)
1990 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1991 # Start task scheduler
1992 if not BuildTask
.IsOnGoing():
1993 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1995 # in case there's an interruption. we need a full version of makefile for platform
1996 Pa
.CreateMakeFile(False)
1997 if BuildTask
.HasError():
1998 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1999 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
2001 MakeContiue
= time
.time()
2005 # All modules have been put in build tasks queue. Tell task scheduler
2006 # to exit if all tasks are completed
2009 BuildTask
.WaitForComplete()
2010 self
.CreateAsBuiltInf()
2011 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2013 # Check for build error, and raise exception if one
2014 # has been signaled.
2016 if BuildTask
.HasError():
2017 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2019 # Create MAP file when Load Fix Address is enabled.
2020 if self
.Target
in ["", "all", "fds"]:
2021 for Arch
in Wa
.ArchList
:
2023 # Check whether the set fix address is above 4G for 32bit image.
2025 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2026 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")
2031 for Pa
in Wa
.AutoGenObjectList
:
2032 for Ma
in Pa
.ModuleAutoGenList
:
2035 if not Ma
.IsLibrary
:
2036 ModuleList
[Ma
.Guid
.upper()] = Ma
2038 # Rebase module to the preferred memory address before GenFds
2040 MapBuffer
= BytesIO('')
2041 if self
.LoadFixAddress
!= 0:
2042 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2046 # Generate FD image if there's a FDF file found
2048 GenFdsStart
= time
.time()
2049 if GenFdsApi(Wa
.GenFdsCommandDict
, self
.Db
):
2050 EdkLogger
.error("build", COMMAND_FAILURE
)
2053 # Create MAP file for all platform FVs after GenFds.
2055 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2056 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2058 # Save MAP buffer into MAP file.
2060 self
._SaveMapFile
(MapBuffer
, Wa
)
2062 ## Generate GuidedSectionTools.txt in the FV directories.
2064 def CreateGuidedSectionToolsFile(self
):
2065 for BuildTarget
in self
.BuildTargetList
:
2066 for ToolChain
in self
.ToolChainList
:
2067 Wa
= WorkspaceAutoGen(
2084 if not os
.path
.exists(FvDir
):
2087 for Arch
in self
.ArchList
:
2088 # Build up the list of supported architectures for this build
2089 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
2091 # Look through the tool definitions for GUIDed tools
2093 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.iteritems():
2094 if attrib
.upper().endswith('_GUID'):
2095 split
= attrib
.split('_')
2096 thisPrefix
= '_'.join(split
[0:3]) + '_'
2097 if thisPrefix
== prefix
:
2098 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
2101 path
= '_'.join(split
[0:4]) + '_PATH'
2102 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2103 path
= self
.GetFullPathOfTool(path
)
2104 guidAttribs
.append((guid
, toolName
, path
))
2106 # Write out GuidedSecTools.txt
2107 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2108 toolsFile
= open(toolsFile
, 'wt')
2109 for guidedSectionTool
in guidAttribs
:
2110 print(' '.join(guidedSectionTool
), file=toolsFile
)
2113 ## Returns the full path of the tool.
2115 def GetFullPathOfTool (self
, tool
):
2116 if os
.path
.exists(tool
):
2117 return os
.path
.realpath(tool
)
2119 # We need to search for the tool using the
2120 # PATH environment variable.
2121 for dirInPath
in os
.environ
['PATH'].split(os
.pathsep
):
2122 foundPath
= os
.path
.join(dirInPath
, tool
)
2123 if os
.path
.exists(foundPath
):
2124 return os
.path
.realpath(foundPath
)
2126 # If the tool was not found in the path then we just return
2130 ## Launch the module or platform build
2133 if not self
.ModuleFile
:
2134 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2135 self
.SpawnMode
= False
2136 self
._BuildPlatform
()
2138 self
._MultiThreadBuildPlatform
()
2139 self
.CreateGuidedSectionToolsFile()
2141 self
.SpawnMode
= False
2144 if self
.Target
== 'cleanall':
2145 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2147 def CreateAsBuiltInf(self
):
2148 for Module
in self
.BuildModules
:
2149 Module
.CreateAsBuiltInf()
2150 for Module
in self
.HashSkipModules
:
2151 Module
.CreateAsBuiltInf(True)
2152 self
.BuildModules
= []
2153 self
.HashSkipModules
= []
2154 ## Do some clean-up works when error occurred
2155 def Relinquish(self
):
2156 OldLogLevel
= EdkLogger
.GetLevel()
2157 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2158 Utils
.Progressor
.Abort()
2159 if self
.SpawnMode
== True:
2161 EdkLogger
.SetLevel(OldLogLevel
)
2163 def ParseDefines(DefineList
=[]):
2165 if DefineList
is not None:
2166 for Define
in DefineList
:
2167 DefineTokenList
= Define
.split("=", 1)
2168 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2169 EdkLogger
.error('build', FORMAT_INVALID
,
2170 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2171 ExtraData
=DefineTokenList
[0])
2173 if len(DefineTokenList
) == 1:
2174 DefineDict
[DefineTokenList
[0]] = "TRUE"
2176 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2180 def SingleCheckCallback(option
, opt_str
, value
, parser
):
2181 if option
not in gParamCheck
:
2182 setattr(parser
.values
, option
.dest
, value
)
2183 gParamCheck
.append(option
)
2185 parser
.error("Option %s only allows one instance in command line!" % option
)
2187 def LogBuildTime(Time
):
2190 TimeDur
= time
.gmtime(Time
)
2191 if TimeDur
.tm_yday
> 1:
2192 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2194 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2199 ## Parse command line options
2201 # Using standard Python module optparse to parse command line option of this tool.
2203 # @retval Opt A optparse.Values object containing the parsed options
2204 # @retval Args Target of build command
2206 def MyOptionParser():
2207 Parser
= OptionParser(description
=__copyright__
, version
=__version__
, prog
="build.exe", usage
="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
2208 Parser
.add_option("-a", "--arch", action
="append", type="choice", choices
=['IA32', 'X64', 'EBC', 'ARM', 'AARCH64'], dest
="TargetArch",
2209 help="ARCHS is one of list: IA32, X64, ARM, AARCH64 or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.")
2210 Parser
.add_option("-p", "--platform", action
="callback", type="string", dest
="PlatformFile", callback
=SingleCheckCallback
,
2211 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
2212 Parser
.add_option("-m", "--module", action
="callback", type="string", dest
="ModuleFile", callback
=SingleCheckCallback
,
2213 help="Build the module specified by the INF file name argument.")
2214 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
2216 Parser
.add_option("-t", "--tagname", action
="append", type="string", dest
="ToolChain",
2217 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
2218 Parser
.add_option("-x", "--sku-id", action
="callback", type="string", dest
="SkuId", callback
=SingleCheckCallback
,
2219 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
2221 Parser
.add_option("-n", action
="callback", type="int", dest
="ThreadNumber", callback
=SingleCheckCallback
,
2222 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 "\
2223 "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.")
2225 Parser
.add_option("-f", "--fdf", action
="callback", type="string", dest
="FdfFile", callback
=SingleCheckCallback
,
2226 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
2227 Parser
.add_option("-r", "--rom-image", action
="append", type="string", dest
="RomImage", default
=[],
2228 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
2229 Parser
.add_option("-i", "--fv-image", action
="append", type="string", dest
="FvImage", default
=[],
2230 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
2231 Parser
.add_option("-C", "--capsule-image", action
="append", type="string", dest
="CapName", default
=[],
2232 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
2233 Parser
.add_option("-u", "--skip-autogen", action
="store_true", dest
="SkipAutoGen", help="Skip AutoGen step.")
2234 Parser
.add_option("-e", "--re-parse", action
="store_true", dest
="Reparse", help="Re-parse all meta-data files.")
2236 Parser
.add_option("-c", "--case-insensitive", action
="store_true", dest
="CaseInsensitive", default
=False, help="Don't check case of file name.")
2238 Parser
.add_option("-w", "--warning-as-error", action
="store_true", dest
="WarningAsError", help="Treat warning in tools as error.")
2239 Parser
.add_option("-j", "--log", action
="store", dest
="LogFile", help="Put log in specified file as well as on console.")
2241 Parser
.add_option("-s", "--silent", action
="store_true", type=None, dest
="SilentMode",
2242 help="Make use of silent mode of (n)make.")
2243 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
2244 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
2245 "including library instances selected, final dependency expression, "\
2246 "and warning messages, etc.")
2247 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
2248 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
2250 Parser
.add_option("-y", "--report-file", action
="store", dest
="ReportFile", help="Create/overwrite the report to the specified filename.")
2251 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
=[],
2252 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]. "\
2253 "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]")
2254 Parser
.add_option("-F", "--flag", action
="store", type="string", dest
="Flag",
2255 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. "\
2256 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
2257 "will override the setting in [BuildOptions] section of platform DSC.")
2258 Parser
.add_option("-N", "--no-cache", action
="store_true", dest
="DisableCache", default
=False, help="Disable build cache mechanism")
2259 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
2260 Parser
.add_option("--check-usage", action
="store_true", dest
="CheckUsage", default
=False, help="Check usage content of entries listed in INF file.")
2261 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
2262 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
2263 Parser
.add_option("-l", "--cmd-len", action
="store", type="int", dest
="CommandLength", help="Specify the maximum line length of build command. Default is 4096.")
2264 Parser
.add_option("--hash", action
="store_true", dest
="UseHashCache", default
=False, help="Enable hash-based caching during build process.")
2265 Parser
.add_option("--binary-destination", action
="store", type="string", dest
="BinCacheDest", help="Generate a cache of binary files in the specified directory.")
2266 Parser
.add_option("--binary-source", action
="store", type="string", dest
="BinCacheSource", help="Consume a cache of binary files from the specified directory.")
2267 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
2268 (Opt
, Args
) = Parser
.parse_args()
2271 ## Tool entrance method
2273 # This method mainly dispatch specific methods per the command line options.
2274 # If no error found, return zero value so the caller of this tool can know
2275 # if it's executed successfully or not.
2277 # @retval 0 Tool was successful
2278 # @retval 1 Tool failed
2281 StartTime
= time
.time()
2283 # Initialize log system
2284 EdkLogger
.Initialize()
2285 GlobalData
.gCommand
= sys
.argv
[1:]
2287 # Parse the options and args
2289 (Option
, Target
) = MyOptionParser()
2290 GlobalData
.gOptions
= Option
2291 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2294 if Option
.verbose
is not None:
2295 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2296 elif Option
.quiet
is not None:
2297 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2298 elif Option
.debug
is not None:
2299 EdkLogger
.SetLevel(Option
.debug
+ 1)
2301 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2303 if Option
.LogFile
is not None:
2304 EdkLogger
.SetLogFile(Option
.LogFile
)
2306 if Option
.WarningAsError
== True:
2307 EdkLogger
.SetWarningAsError()
2309 if platform
.platform().find("Windows") >= 0:
2310 GlobalData
.gIsWindows
= True
2312 GlobalData
.gIsWindows
= False
2314 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2315 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2320 if len(Target
) == 0:
2322 elif len(Target
) >= 2:
2323 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2324 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2326 Target
= Target
[0].lower()
2328 if Target
not in gSupportedTarget
:
2329 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2330 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2333 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2336 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2338 Workspace
= os
.getenv("WORKSPACE")
2340 # Get files real name in workspace dir
2342 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2344 WorkingDirectory
= os
.getcwd()
2345 if not Option
.ModuleFile
:
2346 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2347 FileNum
= len(FileList
)
2349 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2350 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2352 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2354 if Option
.ModuleFile
:
2355 if os
.path
.isabs (Option
.ModuleFile
):
2356 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2357 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2358 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2359 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2361 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2363 if Option
.PlatformFile
is not None:
2364 if os
.path
.isabs (Option
.PlatformFile
):
2365 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2366 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2367 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2369 if Option
.FdfFile
is not None:
2370 if os
.path
.isabs (Option
.FdfFile
):
2371 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2372 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2373 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2374 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2376 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2378 if Option
.Flag
is not None and Option
.Flag
not in ['-c', '-s']:
2379 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2381 MyBuild
= Build(Target
, Workspace
, Option
)
2382 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2383 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2387 # All job done, no error found and no exception raised
2390 except FatalError
as X
:
2391 if MyBuild
is not None:
2392 # for multi-thread build exits safely
2393 MyBuild
.Relinquish()
2394 if Option
is not None and Option
.debug
is not None:
2395 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2396 ReturnCode
= X
.args
[0]
2397 except Warning as X
:
2398 # error from Fdf parser
2399 if MyBuild
is not None:
2400 # for multi-thread build exits safely
2401 MyBuild
.Relinquish()
2402 if Option
is not None and Option
.debug
is not None:
2403 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2405 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2406 ReturnCode
= FORMAT_INVALID
2407 except KeyboardInterrupt:
2408 ReturnCode
= ABORT_ERROR
2409 if Option
is not None and Option
.debug
is not None:
2410 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2412 if MyBuild
is not None:
2413 # for multi-thread build exits safely
2414 MyBuild
.Relinquish()
2416 # try to get the meta-file from the object causing exception
2417 Tb
= sys
.exc_info()[-1]
2418 MetaFile
= GlobalData
.gProcessingFile
2419 while Tb
is not None:
2420 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2421 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2426 "Unknown fatal error when processing [%s]" % MetaFile
,
2427 ExtraData
="\n(Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!)\n",
2430 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2431 ReturnCode
= CODE_ERROR
2433 Utils
.Progressor
.Abort()
2434 Utils
.ClearDuplicatedInf()
2438 MyBuild
.LaunchPostbuild()
2441 Conclusion
= "Failed"
2442 elif ReturnCode
== ABORT_ERROR
:
2443 Conclusion
= "Aborted"
2445 Conclusion
= "Failed"
2446 FinishTime
= time
.time()
2447 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2448 BuildDurationStr
= ""
2449 if BuildDuration
.tm_yday
> 1:
2450 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2452 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2453 if MyBuild
is not None:
2455 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2457 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2458 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2459 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2460 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2463 if __name__
== '__main__':
2465 ## 0-127 is a safe return range, and 1 is a standard default error
2466 if r
< 0 or r
> 127: r
= 1