2 # build a platform or a module
4 # Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
5 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
6 # Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
8 # This program and the accompanying materials
9 # are licensed and made available under the terms and conditions of the BSD License
10 # which accompanies this distribution. The full text of the license may be found at
11 # http://opensource.org/licenses/bsd-license.php
13 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 from __future__
import print_function
21 import Common
.LongFilePathOs
as os
23 from io
import BytesIO
29 import encodings
.ascii
31 import multiprocessing
34 from threading
import *
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 ## Make a Python object persistent on file system
77 # @param Data The object to be stored in file
78 # @param File The path of file to store the object
80 def _DataDump(Data
, File
):
84 pickle
.dump(Data
, Fd
, pickle
.HIGHEST_PROTOCOL
)
86 EdkLogger
.error("", FILE_OPEN_FAILURE
, ExtraData
=File
, RaiseError
=False)
91 ## Restore a Python object from a file
93 # @param File The path of file stored the object
95 # @retval object A python object
96 # @retval None If failure in file operation
98 def _DataRestore(File
):
102 Fd
= open(File
, 'rb')
103 Data
= pickle
.load(Fd
)
104 except Exception as e
:
105 EdkLogger
.verbose("Failed to load [%s]\n\t%s" % (File
, str(e
)))
112 ## Check environment PATH variable to make sure the specified tool is found
114 # If the tool is found in the PATH, then True is returned
115 # Otherwise, False is returned
117 def IsToolInPath(tool
):
118 if 'PATHEXT' in os
.environ
:
119 extns
= os
.environ
['PATHEXT'].split(os
.path
.pathsep
)
122 for pathDir
in os
.environ
['PATH'].split(os
.path
.pathsep
):
124 if os
.path
.exists(os
.path
.join(pathDir
, tool
+ ext
)):
128 ## Check environment variables
130 # Check environment variables that must be set for build. Currently they are
132 # WORKSPACE The directory all packages/platforms start from
133 # EDK_TOOLS_PATH The directory contains all tools needed by the build
134 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
136 # If any of above environment variable is not set or has error, the build
139 def CheckEnvVariable():
141 if "WORKSPACE" not in os
.environ
:
142 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
143 ExtraData
="WORKSPACE")
145 WorkspaceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["WORKSPACE"]))
146 if not os
.path
.exists(WorkspaceDir
):
147 EdkLogger
.error("build", FILE_NOT_FOUND
, "WORKSPACE doesn't exist", ExtraData
=WorkspaceDir
)
148 elif ' ' in WorkspaceDir
:
149 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in WORKSPACE path",
150 ExtraData
=WorkspaceDir
)
151 os
.environ
["WORKSPACE"] = WorkspaceDir
153 # set multiple workspace
154 PackagesPath
= os
.getenv("PACKAGES_PATH")
155 mws
.setWs(WorkspaceDir
, PackagesPath
)
156 if mws
.PACKAGES_PATH
:
157 for Path
in mws
.PACKAGES_PATH
:
158 if not os
.path
.exists(Path
):
159 EdkLogger
.error("build", FILE_NOT_FOUND
, "One Path in PACKAGES_PATH doesn't exist", ExtraData
=Path
)
161 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in PACKAGES_PATH", ExtraData
=Path
)
164 os
.environ
["EDK_TOOLS_PATH"] = os
.path
.normcase(os
.environ
["EDK_TOOLS_PATH"])
166 # check EDK_TOOLS_PATH
167 if "EDK_TOOLS_PATH" not in os
.environ
:
168 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
169 ExtraData
="EDK_TOOLS_PATH")
172 if "PATH" not in os
.environ
:
173 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
176 GlobalData
.gWorkspace
= WorkspaceDir
178 GlobalData
.gGlobalDefines
["WORKSPACE"] = WorkspaceDir
179 GlobalData
.gGlobalDefines
["EDK_TOOLS_PATH"] = os
.environ
["EDK_TOOLS_PATH"]
181 ## Get normalized file path
183 # Convert the path to be local format, and remove the WORKSPACE path at the
184 # beginning if the file path is given in full path.
186 # @param FilePath File path to be normalized
187 # @param Workspace Workspace path which the FilePath will be checked against
189 # @retval string The normalized file path
191 def NormFile(FilePath
, Workspace
):
192 # check if the path is absolute or relative
193 if os
.path
.isabs(FilePath
):
194 FileFullPath
= os
.path
.normpath(FilePath
)
196 FileFullPath
= os
.path
.normpath(mws
.join(Workspace
, FilePath
))
197 Workspace
= mws
.getWs(Workspace
, FilePath
)
199 # check if the file path exists or not
200 if not os
.path
.isfile(FileFullPath
):
201 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath
)
203 # remove workspace directory from the beginning part of the file path
204 if Workspace
[-1] in ["\\", "/"]:
205 return FileFullPath
[len(Workspace
):]
207 return FileFullPath
[(len(Workspace
) + 1):]
209 ## Get the output of an external program
211 # This is the entrance method of thread reading output of an external program and
212 # putting them in STDOUT/STDERR of current program.
214 # @param From The stream message read from
215 # @param To The stream message put on
216 # @param ExitFlag The flag used to indicate stopping reading
218 def ReadMessage(From
, To
, ExitFlag
):
220 # read one line a time
221 Line
= From
.readline()
222 # empty string means "end"
223 if Line
is not None and Line
!= "":
230 ## Launch an external program
232 # This method will call subprocess.Popen to execute an external program with
233 # given options in specified directory. Because of the dead-lock issue during
234 # redirecting output of the external program, threads are used to to do the
237 # @param Command A list or string containing the call of the program
238 # @param WorkingDir The directory in which the program will be running
240 def LaunchCommand(Command
, WorkingDir
):
241 BeginTime
= time
.time()
242 # if working directory doesn't exist, Popen() will raise an exception
243 if not os
.path
.isdir(WorkingDir
):
244 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=WorkingDir
)
246 # Command is used as the first Argument in following Popen().
247 # It could be a string or sequence. We find that if command is a string in following Popen(),
248 # ubuntu may fail with an error message that the command is not found.
249 # So here we may need convert command from string to list instance.
250 if platform
.system() != 'Windows':
251 if not isinstance(Command
, list):
252 Command
= Command
.split()
253 Command
= ' '.join(Command
)
256 EndOfProcedure
= None
259 Proc
= Popen(Command
, stdout
=PIPE
, stderr
=PIPE
, env
=os
.environ
, cwd
=WorkingDir
, bufsize
=-1, shell
=True)
261 # launch two threads to read the STDOUT and STDERR
262 EndOfProcedure
= Event()
263 EndOfProcedure
.clear()
265 StdOutThread
= Thread(target
=ReadMessage
, args
=(Proc
.stdout
, EdkLogger
.info
, EndOfProcedure
))
266 StdOutThread
.setName("STDOUT-Redirector")
267 StdOutThread
.setDaemon(False)
271 StdErrThread
= Thread(target
=ReadMessage
, args
=(Proc
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
272 StdErrThread
.setName("STDERR-Redirector")
273 StdErrThread
.setDaemon(False)
276 # waiting for program exit
278 except: # in case of aborting
279 # terminate the threads redirecting the program output
280 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
281 if EndOfProcedure
is not None:
284 if not isinstance(Command
, type("")):
285 Command
= " ".join(Command
)
286 EdkLogger
.error("build", COMMAND_FAILURE
, "Failed to start command", ExtraData
="%s [%s]" % (Command
, WorkingDir
))
293 # check the return code of the program
294 if Proc
.returncode
!= 0:
295 if not isinstance(Command
, type("")):
296 Command
= " ".join(Command
)
297 # print out the Response file and its content when make failure
298 RespFile
= os
.path
.join(WorkingDir
, 'OUTPUT', 'respfilelist.txt')
299 if os
.path
.isfile(RespFile
):
301 RespContent
= f
.read()
303 EdkLogger
.info(RespContent
)
305 EdkLogger
.error("build", COMMAND_FAILURE
, ExtraData
="%s [%s]" % (Command
, WorkingDir
))
306 return "%dms" % (int(round((time
.time() - BeginTime
) * 1000)))
308 ## The smallest unit that can be built in multi-thread build mode
310 # This is the base class of build unit. The "Obj" parameter must provide
311 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
314 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
319 # @param self The object pointer
320 # @param Obj The object the build is working on
321 # @param Target The build target name, one of gSupportedTarget
322 # @param Dependency The BuildUnit(s) which must be completed in advance
323 # @param WorkingDir The directory build command starts in
325 def __init__(self
, Obj
, BuildCommand
, Target
, Dependency
, WorkingDir
="."):
326 self
.BuildObject
= Obj
327 self
.Dependency
= Dependency
328 self
.WorkingDir
= WorkingDir
330 self
.BuildCommand
= BuildCommand
332 EdkLogger
.error("build", OPTION_MISSING
,
333 "No build command found for this module. "
334 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
335 (Obj
.BuildTarget
, Obj
.ToolChain
, Obj
.Arch
),
341 # It just returns the string representation of self.BuildObject
343 # @param self The object pointer
346 return str(self
.BuildObject
)
348 ## "==" operator method
350 # It just compares self.BuildObject with "Other". So self.BuildObject must
351 # provide its own __eq__() method.
353 # @param self The object pointer
354 # @param Other The other BuildUnit object compared to
356 def __eq__(self
, Other
):
357 return Other
and self
.BuildObject
== Other
.BuildObject \
358 and Other
.BuildObject \
359 and self
.BuildObject
.Arch
== Other
.BuildObject
.Arch
363 # It just returns the hash value of self.BuildObject which must be hashable.
365 # @param self The object pointer
368 return hash(self
.BuildObject
) + hash(self
.BuildObject
.Arch
)
371 return repr(self
.BuildObject
)
373 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
375 # This class is for module build by nmake/make build system. The "Obj" parameter
376 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
377 # be make units missing build.
379 # Currently the "Obj" should be only ModuleAutoGen object.
381 class ModuleMakeUnit(BuildUnit
):
384 # @param self The object pointer
385 # @param Obj The ModuleAutoGen object the build is working on
386 # @param Target The build target name, one of gSupportedTarget
388 def __init__(self
, Obj
, Target
):
389 Dependency
= [ModuleMakeUnit(La
, Target
) for La
in Obj
.LibraryAutoGenList
]
390 BuildUnit
.__init
__(self
, Obj
, Obj
.BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
391 if Target
in [None, "", "all"]:
392 self
.Target
= "tbuild"
394 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
396 # This class is for platform build by nmake/make build system. The "Obj" parameter
397 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
398 # be make units missing build.
400 # Currently the "Obj" should be only PlatformAutoGen object.
402 class PlatformMakeUnit(BuildUnit
):
405 # @param self The object pointer
406 # @param Obj The PlatformAutoGen object the build is working on
407 # @param Target The build target name, one of gSupportedTarget
409 def __init__(self
, Obj
, Target
):
410 Dependency
= [ModuleMakeUnit(Lib
, Target
) for Lib
in self
.BuildObject
.LibraryAutoGenList
]
411 Dependency
.extend([ModuleMakeUnit(Mod
, Target
) for Mod
in self
.BuildObject
.ModuleAutoGenList
])
412 BuildUnit
.__init
__(self
, Obj
, Obj
.BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
414 ## The class representing the task of a module build or platform build
416 # This class manages the build tasks in multi-thread build mode. Its jobs include
417 # scheduling thread running, catching thread error, monitor the thread status, etc.
420 # queue for tasks waiting for schedule
421 _PendingQueue
= OrderedDict()
422 _PendingQueueLock
= threading
.Lock()
424 # queue for tasks ready for running
425 _ReadyQueue
= OrderedDict()
426 _ReadyQueueLock
= threading
.Lock()
428 # queue for run tasks
429 _RunningQueue
= OrderedDict()
430 _RunningQueueLock
= threading
.Lock()
432 # queue containing all build tasks, in case duplicate build
433 _TaskQueue
= OrderedDict()
435 # flag indicating error occurs in a running thread
436 _ErrorFlag
= threading
.Event()
440 # BoundedSemaphore object used to control the number of running threads
443 # flag indicating if the scheduler is started or not
444 _SchedulerStopped
= threading
.Event()
445 _SchedulerStopped
.set()
447 ## Start the task scheduler thread
449 # @param MaxThreadNumber The maximum thread number
450 # @param ExitFlag Flag used to end the scheduler
453 def StartScheduler(MaxThreadNumber
, ExitFlag
):
454 SchedulerThread
= Thread(target
=BuildTask
.Scheduler
, args
=(MaxThreadNumber
, ExitFlag
))
455 SchedulerThread
.setName("Build-Task-Scheduler")
456 SchedulerThread
.setDaemon(False)
457 SchedulerThread
.start()
458 # wait for the scheduler to be started, especially useful in Linux
459 while not BuildTask
.IsOnGoing():
464 # @param MaxThreadNumber The maximum thread number
465 # @param ExitFlag Flag used to end the scheduler
468 def Scheduler(MaxThreadNumber
, ExitFlag
):
469 BuildTask
._SchedulerStopped
.clear()
471 # use BoundedSemaphore to control the maximum running threads
472 BuildTask
._Thread
= BoundedSemaphore(MaxThreadNumber
)
474 # scheduling loop, which will exits when no pending/ready task and
475 # indicated to do so, or there's error in running thread
477 while (len(BuildTask
._PendingQueue
) > 0 or len(BuildTask
._ReadyQueue
) > 0 \
478 or not ExitFlag
.isSet()) and not BuildTask
._ErrorFlag
.isSet():
479 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Pending Queue (%d), Ready Queue (%d)"
480 % (len(BuildTask
._PendingQueue
), len(BuildTask
._ReadyQueue
)))
482 # get all pending tasks
483 BuildTask
._PendingQueueLock
.acquire()
484 BuildObjectList
= BuildTask
._PendingQueue
.keys()
486 # check if their dependency is resolved, and if true, move them
489 for BuildObject
in BuildObjectList
:
490 Bt
= BuildTask
._PendingQueue
[BuildObject
]
492 BuildTask
._ReadyQueue
[BuildObject
] = BuildTask
._PendingQueue
.pop(BuildObject
)
493 BuildTask
._PendingQueueLock
.release()
495 # launch build thread until the maximum number of threads is reached
496 while not BuildTask
._ErrorFlag
.isSet():
497 # empty ready queue, do nothing further
498 if len(BuildTask
._ReadyQueue
) == 0:
501 # wait for active thread(s) exit
502 BuildTask
._Thread
.acquire(True)
504 # start a new build thread
505 Bo
, Bt
= BuildTask
._ReadyQueue
.popitem()
507 # move into running queue
508 BuildTask
._RunningQueueLock
.acquire()
509 BuildTask
._RunningQueue
[Bo
] = Bt
510 BuildTask
._RunningQueueLock
.release()
519 # wait for all running threads exit
520 if BuildTask
._ErrorFlag
.isSet():
521 EdkLogger
.quiet("\nWaiting for all build threads exit...")
522 # while not BuildTask._ErrorFlag.isSet() and \
523 while len(BuildTask
._RunningQueue
) > 0:
524 EdkLogger
.verbose("Waiting for thread ending...(%d)" % len(BuildTask
._RunningQueue
))
525 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Threads [%s]" % ", ".join(Th
.getName() for Th
in threading
.enumerate()))
528 except BaseException
as X
:
530 # TRICK: hide the output of threads left runing, so that the user can
531 # catch the error message easily
533 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
534 BuildTask
._ErrorFlag
.set()
535 BuildTask
._ErrorMessage
= "build thread scheduler error\n\t%s" % str(X
)
537 BuildTask
._PendingQueue
.clear()
538 BuildTask
._ReadyQueue
.clear()
539 BuildTask
._RunningQueue
.clear()
540 BuildTask
._TaskQueue
.clear()
541 BuildTask
._SchedulerStopped
.set()
543 ## Wait for all running method exit
546 def WaitForComplete():
547 BuildTask
._SchedulerStopped
.wait()
549 ## Check if the scheduler is running or not
553 return not BuildTask
._SchedulerStopped
.isSet()
558 if BuildTask
.IsOnGoing():
559 BuildTask
._ErrorFlag
.set()
560 BuildTask
.WaitForComplete()
562 ## Check if there's error in running thread
564 # Since the main thread cannot catch exceptions in other thread, we have to
565 # use threading.Event to communicate this formation to main thread.
569 return BuildTask
._ErrorFlag
.isSet()
571 ## Get error message in running thread
573 # Since the main thread cannot catch exceptions in other thread, we have to
574 # use a static variable to communicate this message to main thread.
577 def GetErrorMessage():
578 return BuildTask
._ErrorMessage
580 ## Factory method to create a BuildTask object
582 # This method will check if a module is building or has been built. And if
583 # true, just return the associated BuildTask object in the _TaskQueue. If
584 # not, create and return a new BuildTask object. The new BuildTask object
585 # will be appended to the _PendingQueue for scheduling later.
587 # @param BuildItem A BuildUnit object representing a build object
588 # @param Dependency The dependent build object of BuildItem
591 def New(BuildItem
, Dependency
=None):
592 if BuildItem
in BuildTask
._TaskQueue
:
593 Bt
= BuildTask
._TaskQueue
[BuildItem
]
597 Bt
._Init
(BuildItem
, Dependency
)
598 BuildTask
._TaskQueue
[BuildItem
] = Bt
600 BuildTask
._PendingQueueLock
.acquire()
601 BuildTask
._PendingQueue
[BuildItem
] = Bt
602 BuildTask
._PendingQueueLock
.release()
606 ## The real constructor of BuildTask
608 # @param BuildItem A BuildUnit object representing a build object
609 # @param Dependency The dependent build object of BuildItem
611 def _Init(self
, BuildItem
, Dependency
=None):
612 self
.BuildItem
= BuildItem
614 self
.DependencyList
= []
615 if Dependency
is None:
616 Dependency
= BuildItem
.Dependency
618 Dependency
.extend(BuildItem
.Dependency
)
619 self
.AddDependency(Dependency
)
620 # flag indicating build completes, used to avoid unnecessary re-build
621 self
.CompleteFlag
= False
623 ## Check if all dependent build tasks are completed or not
627 for Dep
in self
.DependencyList
:
628 if Dep
.CompleteFlag
== True:
635 ## Add dependent build task
637 # @param Dependency The list of dependent build objects
639 def AddDependency(self
, Dependency
):
640 for Dep
in Dependency
:
641 if not Dep
.BuildObject
.IsBinaryModule
:
642 self
.DependencyList
.append(BuildTask
.New(Dep
)) # BuildTask list
644 ## The thread wrapper of LaunchCommand function
646 # @param Command A list or string contains the call of the command
647 # @param WorkingDir The directory in which the program will be running
649 def _CommandThread(self
, Command
, WorkingDir
):
651 self
.BuildItem
.BuildObject
.BuildTime
= LaunchCommand(Command
, WorkingDir
)
652 self
.CompleteFlag
= True
655 # TRICK: hide the output of threads left runing, so that the user can
656 # catch the error message easily
658 if not BuildTask
._ErrorFlag
.isSet():
659 GlobalData
.gBuildingModule
= "%s [%s, %s, %s]" % (str(self
.BuildItem
.BuildObject
),
660 self
.BuildItem
.BuildObject
.Arch
,
661 self
.BuildItem
.BuildObject
.ToolChain
,
662 self
.BuildItem
.BuildObject
.BuildTarget
664 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
665 BuildTask
._ErrorFlag
.set()
666 BuildTask
._ErrorMessage
= "%s broken\n %s [%s]" % \
667 (threading
.currentThread().getName(), Command
, WorkingDir
)
668 # indicate there's a thread is available for another build task
669 BuildTask
._RunningQueueLock
.acquire()
670 BuildTask
._RunningQueue
.pop(self
.BuildItem
)
671 BuildTask
._RunningQueueLock
.release()
672 BuildTask
._Thread
.release()
674 ## Start build task thread
677 EdkLogger
.quiet("Building ... %s" % repr(self
.BuildItem
))
678 Command
= self
.BuildItem
.BuildCommand
+ [self
.BuildItem
.Target
]
679 self
.BuildTread
= Thread(target
=self
._CommandThread
, args
=(Command
, self
.BuildItem
.WorkingDir
))
680 self
.BuildTread
.setName("build thread")
681 self
.BuildTread
.setDaemon(False)
682 self
.BuildTread
.start()
684 ## The class contains the information related to EFI image
689 # Constructor will load all required image information.
691 # @param BaseName The full file path of image.
692 # @param Guid The GUID for image.
693 # @param Arch Arch of this image.
694 # @param OutputDir The output directory for image.
695 # @param DebugDir The debug directory for image.
696 # @param ImageClass PeImage Information
698 def __init__(self
, BaseName
, Guid
, Arch
, OutputDir
, DebugDir
, ImageClass
):
699 self
.BaseName
= BaseName
702 self
.OutputDir
= OutputDir
703 self
.DebugDir
= DebugDir
704 self
.Image
= ImageClass
705 self
.Image
.Size
= (self
.Image
.Size
/ 0x1000 + 1) * 0x1000
707 ## The class implementing the EDK2 build process
709 # The build process includes:
710 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
711 # 2. Parse DSC file of active platform
712 # 3. Parse FDF file if any
713 # 4. Establish build database, including parse all other files (module, package)
714 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
715 # 6. Call build command
720 # Constructor will load all necessary configurations, parse platform, modules
721 # and packages and the establish a database for AutoGen.
723 # @param Target The build command target, one of gSupportedTarget
724 # @param WorkspaceDir The directory of workspace
725 # @param BuildOptions Build options passed from command line
727 def __init__(self
, Target
, WorkspaceDir
, BuildOptions
):
728 self
.WorkspaceDir
= WorkspaceDir
730 self
.PlatformFile
= BuildOptions
.PlatformFile
731 self
.ModuleFile
= BuildOptions
.ModuleFile
732 self
.ArchList
= BuildOptions
.TargetArch
733 self
.ToolChainList
= BuildOptions
.ToolChain
734 self
.BuildTargetList
= BuildOptions
.BuildTarget
735 self
.Fdf
= BuildOptions
.FdfFile
736 self
.FdList
= BuildOptions
.RomImage
737 self
.FvList
= BuildOptions
.FvImage
738 self
.CapList
= BuildOptions
.CapName
739 self
.SilentMode
= BuildOptions
.SilentMode
740 self
.ThreadNumber
= BuildOptions
.ThreadNumber
741 self
.SkipAutoGen
= BuildOptions
.SkipAutoGen
742 self
.Reparse
= BuildOptions
.Reparse
743 self
.SkuId
= BuildOptions
.SkuId
745 GlobalData
.gSKUID_CMD
= self
.SkuId
746 self
.ConfDirectory
= BuildOptions
.ConfDirectory
747 self
.SpawnMode
= True
748 self
.BuildReport
= BuildReport(BuildOptions
.ReportFile
, BuildOptions
.ReportType
)
749 self
.TargetTxt
= TargetTxtClassObject()
750 self
.ToolDef
= ToolDefClassObject()
754 GlobalData
.BuildOptionPcd
= BuildOptions
.OptionPcd
if BuildOptions
.OptionPcd
else []
755 #Set global flag for build mode
756 GlobalData
.gIgnoreSource
= BuildOptions
.IgnoreSources
757 GlobalData
.gUseHashCache
= BuildOptions
.UseHashCache
758 GlobalData
.gBinCacheDest
= BuildOptions
.BinCacheDest
759 GlobalData
.gBinCacheSource
= BuildOptions
.BinCacheSource
760 GlobalData
.gEnableGenfdsMultiThread
= BuildOptions
.GenfdsMultiThread
762 if GlobalData
.gBinCacheDest
and not GlobalData
.gUseHashCache
:
763 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination must be used together with --hash.")
765 if GlobalData
.gBinCacheSource
and not GlobalData
.gUseHashCache
:
766 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-source must be used together with --hash.")
768 if GlobalData
.gBinCacheDest
and GlobalData
.gBinCacheSource
:
769 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination can not be used together with --binary-source.")
771 if GlobalData
.gBinCacheSource
:
772 BinCacheSource
= os
.path
.normpath(GlobalData
.gBinCacheSource
)
773 if not os
.path
.isabs(BinCacheSource
):
774 BinCacheSource
= mws
.join(self
.WorkspaceDir
, BinCacheSource
)
775 GlobalData
.gBinCacheSource
= BinCacheSource
777 if GlobalData
.gBinCacheSource
is not None:
778 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-source.")
780 if GlobalData
.gBinCacheDest
:
781 BinCacheDest
= os
.path
.normpath(GlobalData
.gBinCacheDest
)
782 if not os
.path
.isabs(BinCacheDest
):
783 BinCacheDest
= mws
.join(self
.WorkspaceDir
, BinCacheDest
)
784 GlobalData
.gBinCacheDest
= BinCacheDest
786 if GlobalData
.gBinCacheDest
is not None:
787 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-destination.")
789 if self
.ConfDirectory
:
790 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
791 ConfDirectoryPath
= os
.path
.normpath(self
.ConfDirectory
)
793 if not os
.path
.isabs(ConfDirectoryPath
):
794 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
795 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
796 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, ConfDirectoryPath
)
798 if "CONF_PATH" in os
.environ
:
799 ConfDirectoryPath
= os
.path
.normcase(os
.path
.normpath(os
.environ
["CONF_PATH"]))
801 # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf
802 ConfDirectoryPath
= mws
.join(self
.WorkspaceDir
, 'Conf')
803 GlobalData
.gConfDirectory
= ConfDirectoryPath
804 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
806 self
.Db
= WorkspaceDatabase()
807 self
.BuildDatabase
= self
.Db
.BuildObject
809 self
.ToolChainFamily
= None
810 self
.LoadFixAddress
= 0
811 self
.UniFlag
= BuildOptions
.Flag
812 self
.BuildModules
= []
813 self
.HashSkipModules
= []
815 self
.LaunchPrebuildFlag
= False
816 self
.PlatformBuildPath
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PlatformBuild')
817 if BuildOptions
.CommandLength
:
818 GlobalData
.gCommandMaxLength
= BuildOptions
.CommandLength
820 # print dot character during doing some time-consuming work
821 self
.Progress
= Utils
.Progressor()
822 # print current build environment and configuration
823 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
824 if "PACKAGES_PATH" in os
.environ
:
825 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
826 EdkLogger
.quiet("%-16s = %s" % ("PACKAGES_PATH", os
.path
.normcase(os
.path
.normpath(os
.environ
["PACKAGES_PATH"]))))
827 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
828 if "EDK_TOOLS_BIN" in os
.environ
:
829 # Print the same path style with WORKSPACE env.
830 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_TOOLS_BIN"]))))
831 EdkLogger
.quiet("%-16s = %s" % ("CONF_PATH", GlobalData
.gConfDirectory
))
835 EdkLogger
.quiet("%-16s = %s" % ("PREBUILD", self
.Prebuild
))
837 EdkLogger
.quiet("%-16s = %s" % ("POSTBUILD", self
.Postbuild
))
839 self
.LaunchPrebuild()
840 self
.TargetTxt
= TargetTxtClassObject()
841 self
.ToolDef
= ToolDefClassObject()
842 if not (self
.LaunchPrebuildFlag
and os
.path
.exists(self
.PlatformBuildPath
)):
846 os
.chdir(self
.WorkspaceDir
)
848 ## Load configuration
850 # This method will parse target.txt and get the build configurations.
852 def LoadConfiguration(self
):
854 # Check target.txt and tools_def.txt and Init them
856 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(GlobalData
.gConfDirectory
, gBuildConfiguration
))
857 if os
.path
.isfile(BuildConfigurationFile
) == True:
858 StatusCode
= self
.TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
860 ToolDefinitionFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_CONF
]
861 if ToolDefinitionFile
== '':
862 ToolDefinitionFile
= gToolsDefinition
863 ToolDefinitionFile
= os
.path
.normpath(mws
.join(self
.WorkspaceDir
, 'Conf', ToolDefinitionFile
))
864 if os
.path
.isfile(ToolDefinitionFile
) == True:
865 StatusCode
= self
.ToolDef
.LoadToolDefFile(ToolDefinitionFile
)
867 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=ToolDefinitionFile
)
869 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
871 # if no ARCH given in command line, get it from target.txt
872 if not self
.ArchList
:
873 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET_ARCH
]
874 self
.ArchList
= tuple(self
.ArchList
)
876 # if no build target given in command line, get it from target.txt
877 if not self
.BuildTargetList
:
878 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
880 # if no tool chain given in command line, get it from target.txt
881 if not self
.ToolChainList
:
882 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
883 if self
.ToolChainList
is None or len(self
.ToolChainList
) == 0:
884 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
886 # check if the tool chains are defined or not
887 NewToolChainList
= []
888 for ToolChain
in self
.ToolChainList
:
889 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
890 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
892 NewToolChainList
.append(ToolChain
)
893 # if no tool chain available, break the build
894 if len(NewToolChainList
) == 0:
895 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
896 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
898 self
.ToolChainList
= NewToolChainList
901 ToolDefinition
= self
.ToolDef
.ToolsDefTxtDatabase
902 for Tool
in self
.ToolChainList
:
903 if TAB_TOD_DEFINES_FAMILY
not in ToolDefinition
or Tool
not in ToolDefinition
[TAB_TOD_DEFINES_FAMILY
] \
904 or not ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
]:
905 EdkLogger
.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool
)
906 ToolChainFamily
.append(TAB_COMPILER_MSFT
)
908 ToolChainFamily
.append(ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
])
909 self
.ToolChainFamily
= ToolChainFamily
911 if self
.ThreadNumber
is None:
912 self
.ThreadNumber
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
913 if self
.ThreadNumber
== '':
914 self
.ThreadNumber
= 0
916 self
.ThreadNumber
= int(self
.ThreadNumber
, 0)
918 if self
.ThreadNumber
== 0:
920 self
.ThreadNumber
= multiprocessing
.cpu_count()
921 except (ImportError, NotImplementedError):
922 self
.ThreadNumber
= 1
924 if not self
.PlatformFile
:
925 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
927 # Try to find one in current directory
928 WorkingDirectory
= os
.getcwd()
929 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
930 FileNum
= len(FileList
)
932 EdkLogger
.error("build", OPTION_MISSING
,
933 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
935 PlatformFile
= FileList
[0]
937 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
938 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
940 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
942 ## Initialize build configuration
944 # This method will parse DSC file and merge the configurations from
945 # command line and target.txt, then get the final build configurations.
948 # parse target.txt, tools_def.txt, and platform file
949 self
.LoadConfiguration()
951 # Allow case-insensitive for those from command line or configuration file
952 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
954 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
957 def InitPreBuild(self
):
958 self
.LoadConfiguration()
959 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
961 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
962 if self
.BuildTargetList
:
963 GlobalData
.gGlobalDefines
['TARGET'] = self
.BuildTargetList
[0]
965 GlobalData
.gGlobalDefines
['ARCH'] = self
.ArchList
[0]
966 if self
.ToolChainList
:
967 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = self
.ToolChainList
[0]
968 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = self
.ToolChainList
[0]
969 if self
.ToolChainFamily
:
970 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[0]
971 if 'PREBUILD' in GlobalData
.gCommandLineDefines
:
972 self
.Prebuild
= GlobalData
.gCommandLineDefines
.get('PREBUILD')
975 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
976 self
.Prebuild
= str(Platform
.Prebuild
)
980 # Evaluate all arguments and convert arguments that are WORKSPACE
981 # relative paths to absolute paths. Filter arguments that look like
982 # flags or do not follow the file/dir naming rules to avoid false
983 # positives on this conversion.
985 for Arg
in self
.Prebuild
.split():
987 # Do not modify Arg if it looks like a flag or an absolute file path
989 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
990 PrebuildList
.append(Arg
)
993 # Do not modify Arg if it does not look like a Workspace relative
994 # path that starts with a valid package directory name
996 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
997 PrebuildList
.append(Arg
)
1000 # If Arg looks like a WORKSPACE relative path, then convert to an
1001 # absolute path and check to see if the file exists.
1003 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1004 if os
.path
.isfile(Temp
):
1006 PrebuildList
.append(Arg
)
1007 self
.Prebuild
= ' '.join(PrebuildList
)
1008 self
.Prebuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1010 def InitPostBuild(self
):
1011 if 'POSTBUILD' in GlobalData
.gCommandLineDefines
:
1012 self
.Postbuild
= GlobalData
.gCommandLineDefines
.get('POSTBUILD')
1014 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
1015 self
.Postbuild
= str(Platform
.Postbuild
)
1019 # Evaluate all arguments and convert arguments that are WORKSPACE
1020 # relative paths to absolute paths. Filter arguments that look like
1021 # flags or do not follow the file/dir naming rules to avoid false
1022 # positives on this conversion.
1024 for Arg
in self
.Postbuild
.split():
1026 # Do not modify Arg if it looks like a flag or an absolute file path
1028 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1029 PostbuildList
.append(Arg
)
1032 # Do not modify Arg if it does not look like a Workspace relative
1033 # path that starts with a valid package directory name
1035 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1036 PostbuildList
.append(Arg
)
1039 # If Arg looks like a WORKSPACE relative path, then convert to an
1040 # absolute path and check to see if the file exists.
1042 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1043 if os
.path
.isfile(Temp
):
1045 PostbuildList
.append(Arg
)
1046 self
.Postbuild
= ' '.join(PostbuildList
)
1047 self
.Postbuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1049 def PassCommandOption(self
, BuildTarget
, TargetArch
, ToolChain
, PlatformFile
, Target
):
1051 if GlobalData
.gCommand
and isinstance(GlobalData
.gCommand
, list):
1052 BuildStr
+= ' ' + ' '.join(GlobalData
.gCommand
)
1055 ToolChainFlag
= False
1056 PlatformFileFlag
= False
1058 if GlobalData
.gOptions
and not GlobalData
.gOptions
.BuildTarget
:
1060 if GlobalData
.gOptions
and not GlobalData
.gOptions
.TargetArch
:
1062 if GlobalData
.gOptions
and not GlobalData
.gOptions
.ToolChain
:
1063 ToolChainFlag
= True
1064 if GlobalData
.gOptions
and not GlobalData
.gOptions
.PlatformFile
:
1065 PlatformFileFlag
= True
1067 if TargetFlag
and BuildTarget
:
1068 if isinstance(BuildTarget
, list) or isinstance(BuildTarget
, tuple):
1069 BuildStr
+= ' -b ' + ' -b '.join(BuildTarget
)
1070 elif isinstance(BuildTarget
, str):
1071 BuildStr
+= ' -b ' + BuildTarget
1072 if ArchFlag
and TargetArch
:
1073 if isinstance(TargetArch
, list) or isinstance(TargetArch
, tuple):
1074 BuildStr
+= ' -a ' + ' -a '.join(TargetArch
)
1075 elif isinstance(TargetArch
, str):
1076 BuildStr
+= ' -a ' + TargetArch
1077 if ToolChainFlag
and ToolChain
:
1078 if isinstance(ToolChain
, list) or isinstance(ToolChain
, tuple):
1079 BuildStr
+= ' -t ' + ' -t '.join(ToolChain
)
1080 elif isinstance(ToolChain
, str):
1081 BuildStr
+= ' -t ' + ToolChain
1082 if PlatformFileFlag
and PlatformFile
:
1083 if isinstance(PlatformFile
, list) or isinstance(PlatformFile
, tuple):
1084 BuildStr
+= ' -p ' + ' -p '.join(PlatformFile
)
1085 elif isinstance(PlatformFile
, str):
1086 BuildStr
+= ' -p' + PlatformFile
1087 BuildStr
+= ' --conf=' + GlobalData
.gConfDirectory
1089 BuildStr
+= ' ' + Target
1093 def LaunchPrebuild(self
):
1095 EdkLogger
.info("\n- Prebuild Start -\n")
1096 self
.LaunchPrebuildFlag
= True
1098 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1099 # and preserve them for the rest of the main build step, because the child process environment will
1100 # evaporate as soon as it exits, we cannot get it in build step.
1102 PrebuildEnvFile
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PrebuildEnv')
1103 if os
.path
.isfile(PrebuildEnvFile
):
1104 os
.remove(PrebuildEnvFile
)
1105 if os
.path
.isfile(self
.PlatformBuildPath
):
1106 os
.remove(self
.PlatformBuildPath
)
1107 if sys
.platform
== "win32":
1108 args
= ' && '.join((self
.Prebuild
, 'set > ' + PrebuildEnvFile
))
1109 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1111 args
= ' && '.join((self
.Prebuild
, 'env > ' + PrebuildEnvFile
))
1112 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1114 # launch two threads to read the STDOUT and STDERR
1115 EndOfProcedure
= Event()
1116 EndOfProcedure
.clear()
1118 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1119 StdOutThread
.setName("STDOUT-Redirector")
1120 StdOutThread
.setDaemon(False)
1121 StdOutThread
.start()
1124 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1125 StdErrThread
.setName("STDERR-Redirector")
1126 StdErrThread
.setDaemon(False)
1127 StdErrThread
.start()
1128 # waiting for program exit
1135 if Process
.returncode
!= 0 :
1136 EdkLogger
.error("Prebuild", PREBUILD_ERROR
, 'Prebuild process is not success!')
1138 if os
.path
.exists(PrebuildEnvFile
):
1139 f
= open(PrebuildEnvFile
)
1140 envs
= f
.readlines()
1142 envs
= itertools
.imap(lambda l
: l
.split('=', 1), envs
)
1143 envs
= itertools
.ifilter(lambda l
: len(l
) == 2, envs
)
1144 envs
= itertools
.imap(lambda l
: [i
.strip() for i
in l
], envs
)
1145 os
.environ
.update(dict(envs
))
1146 EdkLogger
.info("\n- Prebuild Done -\n")
1148 def LaunchPostbuild(self
):
1150 EdkLogger
.info("\n- Postbuild Start -\n")
1151 if sys
.platform
== "win32":
1152 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1154 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1155 # launch two threads to read the STDOUT and STDERR
1156 EndOfProcedure
= Event()
1157 EndOfProcedure
.clear()
1159 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1160 StdOutThread
.setName("STDOUT-Redirector")
1161 StdOutThread
.setDaemon(False)
1162 StdOutThread
.start()
1165 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1166 StdErrThread
.setName("STDERR-Redirector")
1167 StdErrThread
.setDaemon(False)
1168 StdErrThread
.start()
1169 # waiting for program exit
1176 if Process
.returncode
!= 0 :
1177 EdkLogger
.error("Postbuild", POSTBUILD_ERROR
, 'Postbuild process is not success!')
1178 EdkLogger
.info("\n- Postbuild Done -\n")
1179 ## Build a module or platform
1181 # Create autogen code and makefile for a module or platform, and the launch
1182 # "make" command to build it
1184 # @param Target The target of build command
1185 # @param Platform The platform file
1186 # @param Module The module file
1187 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1188 # @param ToolChain The name of toolchain to build
1189 # @param Arch The arch of the module/platform
1190 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1191 # for dependent modules/Libraries
1192 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1193 # for dependent modules/Libraries
1195 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False, FfsCommand
={}):
1196 if AutoGenObject
is None:
1199 # skip file generation for cleanxxx targets, run and fds target
1200 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1201 # for target which must generate AutoGen code and makefile
1202 if not self
.SkipAutoGen
or Target
== 'genc':
1203 self
.Progress
.Start("Generating code")
1204 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1205 self
.Progress
.Stop("done!")
1206 if Target
== "genc":
1209 if not self
.SkipAutoGen
or Target
== 'genmake':
1210 self
.Progress
.Start("Generating makefile")
1211 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
, FfsCommand
)
1212 self
.Progress
.Stop("done!")
1213 if Target
== "genmake":
1216 # always recreate top/platform makefile when clean, just in case of inconsistency
1217 AutoGenObject
.CreateCodeFile(False)
1218 AutoGenObject
.CreateMakeFile(False)
1220 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1221 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1223 BuildCommand
= AutoGenObject
.BuildCommand
1224 if BuildCommand
is None or len(BuildCommand
) == 0:
1225 EdkLogger
.error("build", OPTION_MISSING
,
1226 "No build command found for this module. "
1227 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1228 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1229 ExtraData
=str(AutoGenObject
))
1231 makefile
= GenMake
.BuildFile(AutoGenObject
)._FILE
_NAME
_[GenMake
.gMakeType
]
1235 RunDir
= os
.path
.normpath(os
.path
.join(AutoGenObject
.BuildDir
, GlobalData
.gGlobalDefines
['ARCH']))
1236 Command
= '.\SecMain'
1238 LaunchCommand(Command
, RunDir
)
1243 BuildCommand
= BuildCommand
+ [Target
]
1244 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1245 self
.CreateAsBuiltInf()
1249 if Target
== 'libraries':
1250 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1251 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1252 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1256 if Target
== 'modules':
1257 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1258 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1259 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1260 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1261 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, makefile
)), 'pbuild']
1262 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1263 self
.CreateAsBuiltInf()
1267 if Target
== 'cleanlib':
1268 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1269 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1270 if os
.path
.exists(LibMakefile
):
1271 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1272 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1276 if Target
== 'clean':
1277 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1278 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, makefile
))
1279 if os
.path
.exists(ModMakefile
):
1280 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
1281 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1282 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1283 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1284 if os
.path
.exists(LibMakefile
):
1285 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1286 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1290 if Target
== 'cleanall':
1292 #os.rmdir(AutoGenObject.BuildDir)
1293 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1294 except WindowsError as X
:
1295 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1298 ## Build a module or platform
1300 # Create autogen code and makefile for a module or platform, and the launch
1301 # "make" command to build it
1303 # @param Target The target of build command
1304 # @param Platform The platform file
1305 # @param Module The module file
1306 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1307 # @param ToolChain The name of toolchain to build
1308 # @param Arch The arch of the module/platform
1309 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1310 # for dependent modules/Libraries
1311 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1312 # for dependent modules/Libraries
1314 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1315 if AutoGenObject
is None:
1318 # skip file generation for cleanxxx targets, run and fds target
1319 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1320 # for target which must generate AutoGen code and makefile
1321 if not self
.SkipAutoGen
or Target
== 'genc':
1322 self
.Progress
.Start("Generating code")
1323 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1324 self
.Progress
.Stop("done!")
1325 if Target
== "genc":
1328 if not self
.SkipAutoGen
or Target
== 'genmake':
1329 self
.Progress
.Start("Generating makefile")
1330 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1331 #AutoGenObject.CreateAsBuiltInf()
1332 self
.Progress
.Stop("done!")
1333 if Target
== "genmake":
1336 # always recreate top/platform makefile when clean, just in case of inconsistency
1337 AutoGenObject
.CreateCodeFile(False)
1338 AutoGenObject
.CreateMakeFile(False)
1340 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1341 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1343 BuildCommand
= AutoGenObject
.BuildCommand
1344 if BuildCommand
is None or len(BuildCommand
) == 0:
1345 EdkLogger
.error("build", OPTION_MISSING
,
1346 "No build command found for this module. "
1347 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1348 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1349 ExtraData
=str(AutoGenObject
))
1354 BuildCommand
= BuildCommand
+ [Target
]
1355 AutoGenObject
.BuildTime
= LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1356 self
.CreateAsBuiltInf()
1361 if GenFdsApi(AutoGenObject
.GenFdsCommandDict
, self
.Db
):
1362 EdkLogger
.error("build", COMMAND_FAILURE
)
1367 RunDir
= os
.path
.normpath(os
.path
.join(AutoGenObject
.BuildDir
, GlobalData
.gGlobalDefines
['ARCH']))
1368 Command
= '.\SecMain'
1370 LaunchCommand(Command
, RunDir
)
1374 if Target
== 'libraries':
1381 if Target
== 'cleanall':
1383 #os.rmdir(AutoGenObject.BuildDir)
1384 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1385 except WindowsError as X
:
1386 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1389 ## Rebase module image and Get function address for the input module list.
1391 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1393 AddrIsOffset
= False
1394 for InfFile
in ModuleList
:
1395 sys
.stdout
.write (".")
1397 ModuleInfo
= ModuleList
[InfFile
]
1398 ModuleName
= ModuleInfo
.BaseName
1399 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1400 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1401 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1403 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1405 # Update Image to new BaseAddress by GenFw tool
1407 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1408 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1411 # Set new address to the section header only for SMM driver.
1413 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1414 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1416 # Collect funtion address from Map file
1418 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1420 if os
.path
.exists(ImageMapTable
):
1421 OrigImageBaseAddress
= 0
1422 ImageMap
= open(ImageMapTable
, 'r')
1423 for LinStr
in ImageMap
:
1424 if len (LinStr
.strip()) == 0:
1427 # Get the preferred address set on link time.
1429 if LinStr
.find ('Preferred load address is') != -1:
1430 StrList
= LinStr
.split()
1431 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1433 StrList
= LinStr
.split()
1434 if len (StrList
) > 4:
1435 if StrList
[3] == 'f' or StrList
[3] == 'F':
1437 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1438 FunctionList
.append ((Name
, RelativeAddress
))
1442 # Add general information.
1445 MapBuffer
.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1447 MapBuffer
.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1449 MapBuffer
.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1451 # Add guid and general seciton section.
1453 TextSectionAddress
= 0
1454 DataSectionAddress
= 0
1455 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1456 if SectionHeader
[0] == '.text':
1457 TextSectionAddress
= SectionHeader
[1]
1458 elif SectionHeader
[0] in ['.data', '.sdata']:
1459 DataSectionAddress
= SectionHeader
[1]
1461 MapBuffer
.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1463 MapBuffer
.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1465 # Add debug image full path.
1467 MapBuffer
.write('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1469 # Add funtion address
1471 for Function
in FunctionList
:
1473 MapBuffer
.write(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1475 MapBuffer
.write(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1479 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1482 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1484 ## Collect MAP information of all FVs
1486 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1488 # First get the XIP base address for FV map file.
1489 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1490 GuidName
= re
.compile("\(GUID=[-a-fA-F0-9]+")
1491 for FvName
in Wa
.FdfProfile
.FvDict
:
1492 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1493 if not os
.path
.exists(FvMapBuffer
):
1495 FvMap
= open(FvMapBuffer
, 'r')
1496 #skip FV size information
1502 MatchGuid
= GuidPattern
.match(Line
)
1503 if MatchGuid
is not None:
1505 # Replace GUID with module name
1507 GuidString
= MatchGuid
.group()
1508 if GuidString
.upper() in ModuleList
:
1509 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1510 MapBuffer
.write(Line
)
1512 # Add the debug image full path.
1514 MatchGuid
= GuidName
.match(Line
)
1515 if MatchGuid
is not None:
1516 GuidString
= MatchGuid
.group().split("=")[1]
1517 if GuidString
.upper() in ModuleList
:
1518 MapBuffer
.write('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1522 ## Collect MAP information of all modules
1524 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1525 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1527 PatchEfiImageList
= []
1535 # reserve 4K size in SMRAM to make SMM module address not from 0.
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 [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
]:
1553 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1554 PeiSize
+= ImageInfo
.Image
.Size
1555 elif Module
.ModuleType
in [EDK_COMPONENT_TYPE_BS_DRIVER
, SUP_MODULE_DXE_DRIVER
, SUP_MODULE_UEFI_DRIVER
]:
1556 BtModuleList
[Module
.MetaFile
] = ImageInfo
1557 BtSize
+= ImageInfo
.Image
.Size
1558 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
]:
1559 RtModuleList
[Module
.MetaFile
] = ImageInfo
1560 RtSize
+= ImageInfo
.Image
.Size
1561 elif Module
.ModuleType
in [SUP_MODULE_SMM_CORE
, SUP_MODULE_DXE_SMM_DRIVER
, SUP_MODULE_MM_STANDALONE
, SUP_MODULE_MM_CORE_STANDALONE
]:
1562 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1563 SmmSize
+= ImageInfo
.Image
.Size
1564 if Module
.ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
1565 PiSpecVersion
= Module
.Module
.Specification
.get('PI_SPECIFICATION_VERSION', '0x00000000')
1566 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1567 if int(PiSpecVersion
, 16) < 0x0001000A:
1568 BtModuleList
[Module
.MetaFile
] = ImageInfo
1569 BtSize
+= ImageInfo
.Image
.Size
1572 # EFI image is final target.
1573 # Check EFI image contains patchable FixAddress related PCDs.
1575 if OutputImageFile
!= '':
1576 ModuleIsPatch
= False
1577 for Pcd
in Module
.ModulePcdList
:
1578 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1579 ModuleIsPatch
= True
1581 if not ModuleIsPatch
:
1582 for Pcd
in Module
.LibraryPcdList
:
1583 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1584 ModuleIsPatch
= True
1587 if not ModuleIsPatch
:
1590 # Module includes the patchable load fix address PCDs.
1591 # It will be fixed up later.
1593 PatchEfiImageList
.append (OutputImageFile
)
1596 # Get Top Memory address
1598 ReservedRuntimeMemorySize
= 0
1599 TopMemoryAddress
= 0
1600 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1601 TopMemoryAddress
= 0
1603 TopMemoryAddress
= self
.LoadFixAddress
1604 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1605 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1608 # Patch FixAddress related PCDs into EFI image
1610 for EfiImage
in PatchEfiImageList
:
1611 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1612 if not os
.path
.exists(EfiImageMap
):
1615 # Get PCD offset in EFI image by GenPatchPcdTable function
1617 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1619 # Patch real PCD value by PatchPcdValue tool
1621 for PcdInfo
in PcdTable
:
1623 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1624 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
/ 0x1000))
1625 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1626 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
/ 0x1000))
1627 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1628 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
/ 0x1000))
1629 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1630 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
/ 0x1000))
1631 if ReturnValue
!= 0:
1632 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1634 MapBuffer
.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
/ 0x1000))
1635 MapBuffer
.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
/ 0x1000))
1636 MapBuffer
.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
/ 0x1000))
1637 if len (SmmModuleList
) > 0:
1638 MapBuffer
.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
/ 0x1000))
1640 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1641 BtBaseAddr
= TopMemoryAddress
- RtSize
1642 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1644 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1645 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1646 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1647 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
=False, ModeIsSmm
=True)
1648 MapBuffer
.write('\n\n')
1649 sys
.stdout
.write ("\n")
1652 ## Save platform Map file
1654 def _SaveMapFile (self
, MapBuffer
, Wa
):
1656 # Map file path is got.
1658 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1660 # Save address map into MAP file.
1662 SaveFileOnChange(MapFilePath
, MapBuffer
.getvalue(), False)
1664 if self
.LoadFixAddress
!= 0:
1665 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath
))
1668 ## Build active platform for different build targets and different tool chains
1670 def _BuildPlatform(self
):
1671 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1672 for BuildTarget
in self
.BuildTargetList
:
1673 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1675 for ToolChain
in self
.ToolChainList
:
1676 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1677 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1678 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1680 Wa
= WorkspaceAutoGen(
1697 self
.Fdf
= Wa
.FdfFile
1698 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1699 self
.BuildReport
.AddPlatformReport(Wa
)
1700 self
.Progress
.Stop("done!")
1702 # Add ffs build to makefile
1704 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1705 CmdListDict
= self
._GenFfsCmd
()
1707 for Arch
in Wa
.ArchList
:
1708 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1709 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1710 for Module
in Pa
.Platform
.Modules
:
1711 # Get ModuleAutoGen object to generate C code file and makefile
1712 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1715 self
.BuildModules
.append(Ma
)
1716 self
._BuildPa
(self
.Target
, Pa
, FfsCommand
=CmdListDict
)
1718 # Create MAP file when Load Fix Address is enabled.
1719 if self
.Target
in ["", "all", "fds"]:
1720 for Arch
in Wa
.ArchList
:
1721 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1723 # Check whether the set fix address is above 4G for 32bit image.
1725 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1726 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")
1731 for Pa
in Wa
.AutoGenObjectList
:
1732 for Ma
in Pa
.ModuleAutoGenList
:
1735 if not Ma
.IsLibrary
:
1736 ModuleList
[Ma
.Guid
.upper()] = Ma
1738 MapBuffer
= BytesIO('')
1739 if self
.LoadFixAddress
!= 0:
1741 # Rebase module to the preferred memory address before GenFds
1743 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1746 # create FDS again for the updated EFI image
1748 self
._Build
("fds", Wa
)
1750 # Create MAP file for all platform FVs after GenFds.
1752 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1754 # Save MAP buffer into MAP file.
1756 self
._SaveMapFile
(MapBuffer
, Wa
)
1758 ## Build active module for different build targets, different tool chains and different archs
1760 def _BuildModule(self
):
1761 for BuildTarget
in self
.BuildTargetList
:
1762 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1764 for ToolChain
in self
.ToolChainList
:
1765 WorkspaceAutoGenTime
= time
.time()
1766 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1767 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1768 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1771 # module build needs platform build information, so get platform
1774 Wa
= WorkspaceAutoGen(
1792 self
.Fdf
= Wa
.FdfFile
1793 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1794 Wa
.CreateMakeFile(False)
1795 # Add ffs build to makefile
1797 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1798 CmdListDict
= self
._GenFfsCmd
()
1799 self
.Progress
.Stop("done!")
1801 ExitFlag
= threading
.Event()
1803 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1804 for Arch
in Wa
.ArchList
:
1805 AutoGenStart
= time
.time()
1806 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1807 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1808 for Module
in Pa
.Platform
.Modules
:
1809 if self
.ModuleFile
.Dir
== Module
.Dir
and self
.ModuleFile
.Name
== Module
.Name
:
1810 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1811 if Ma
is None: continue
1813 if Ma
.CanSkipbyHash():
1814 self
.HashSkipModules
.append(Ma
)
1816 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1817 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1818 # for target which must generate AutoGen code and makefile
1819 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1820 self
.Progress
.Start("Generating code")
1821 Ma
.CreateCodeFile(True)
1822 self
.Progress
.Stop("done!")
1823 if self
.Target
== "genc":
1825 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1826 self
.Progress
.Start("Generating makefile")
1827 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
1828 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
1829 del CmdListDict
[Module
.File
, Arch
]
1831 Ma
.CreateMakeFile(True)
1832 self
.Progress
.Stop("done!")
1833 if self
.Target
== "genmake":
1835 self
.BuildModules
.append(Ma
)
1836 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1837 MakeStart
= time
.time()
1838 for Ma
in self
.BuildModules
:
1839 if not Ma
.IsBinaryModule
:
1840 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
1841 # Break build if any build thread has error
1842 if BuildTask
.HasError():
1843 # we need a full version of makefile for platform
1845 BuildTask
.WaitForComplete()
1846 Pa
.CreateMakeFile(False)
1847 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1848 # Start task scheduler
1849 if not BuildTask
.IsOnGoing():
1850 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1852 # in case there's an interruption. we need a full version of makefile for platform
1853 Pa
.CreateMakeFile(False)
1854 if BuildTask
.HasError():
1855 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1856 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1858 MakeContiue
= time
.time()
1860 BuildTask
.WaitForComplete()
1861 self
.CreateAsBuiltInf()
1862 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1863 if BuildTask
.HasError():
1864 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1866 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1871 "Module for [%s] is not a component of active platform."\
1872 " Please make sure that the ARCH and inf file path are"\
1873 " given in the same as in [%s]" % \
1874 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1875 ExtraData
=self
.ModuleFile
1877 # Create MAP file when Load Fix Address is enabled.
1878 if self
.Target
== "fds" and self
.Fdf
:
1879 for Arch
in Wa
.ArchList
:
1881 # Check whether the set fix address is above 4G for 32bit image.
1883 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1884 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")
1889 for Pa
in Wa
.AutoGenObjectList
:
1890 for Ma
in Pa
.ModuleAutoGenList
:
1893 if not Ma
.IsLibrary
:
1894 ModuleList
[Ma
.Guid
.upper()] = Ma
1896 MapBuffer
= BytesIO('')
1897 if self
.LoadFixAddress
!= 0:
1899 # Rebase module to the preferred memory address before GenFds
1901 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1903 # create FDS again for the updated EFI image
1905 GenFdsStart
= time
.time()
1906 self
._Build
("fds", Wa
)
1907 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
1909 # Create MAP file for all platform FVs after GenFds.
1911 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1913 # Save MAP buffer into MAP file.
1915 self
._SaveMapFile
(MapBuffer
, Wa
)
1917 def _GenFfsCmd(self
):
1918 # convert dictionary of Cmd:(Inf,Arch)
1919 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
1920 CmdSetDict
= defaultdict(set)
1921 GenFfsDict
= GenFds
.GenFfsMakefile('', GlobalData
.gFdfParser
, self
, self
.ArchList
, GlobalData
)
1922 for Cmd
in GenFfsDict
:
1923 tmpInf
, tmpArch
= GenFfsDict
[Cmd
]
1924 CmdSetDict
[tmpInf
, tmpArch
].add(Cmd
)
1927 ## Build a platform in multi-thread mode
1929 def _MultiThreadBuildPlatform(self
):
1930 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1931 for BuildTarget
in self
.BuildTargetList
:
1932 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1934 for ToolChain
in self
.ToolChainList
:
1935 WorkspaceAutoGenTime
= time
.time()
1936 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1937 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1938 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1940 Wa
= WorkspaceAutoGen(
1957 self
.Fdf
= Wa
.FdfFile
1958 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1959 self
.BuildReport
.AddPlatformReport(Wa
)
1960 Wa
.CreateMakeFile(False)
1962 # Add ffs build to makefile
1964 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1965 CmdListDict
= self
._GenFfsCmd
()
1967 # multi-thread exit flag
1968 ExitFlag
= threading
.Event()
1970 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1971 for Arch
in Wa
.ArchList
:
1972 AutoGenStart
= time
.time()
1973 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1974 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1978 for Inf
in Pa
.Platform
.Modules
:
1979 ModuleList
.append(Inf
)
1980 # Add the INF only list in FDF
1981 if GlobalData
.gFdfParser
is not None:
1982 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
1983 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
1984 if Inf
in Pa
.Platform
.Modules
:
1986 ModuleList
.append(Inf
)
1987 for Module
in ModuleList
:
1988 # Get ModuleAutoGen object to generate C code file and makefile
1989 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
)
1993 if Ma
.CanSkipbyHash():
1994 self
.HashSkipModules
.append(Ma
)
1997 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1998 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1999 # for target which must generate AutoGen code and makefile
2000 if not self
.SkipAutoGen
or self
.Target
== 'genc':
2001 Ma
.CreateCodeFile(True)
2002 if self
.Target
== "genc":
2005 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
2006 if CmdListDict
and self
.Fdf
and (Module
.File
, Arch
) in CmdListDict
:
2007 Ma
.CreateMakeFile(True, CmdListDict
[Module
.File
, Arch
])
2008 del CmdListDict
[Module
.File
, Arch
]
2010 Ma
.CreateMakeFile(True)
2011 if self
.Target
== "genmake":
2013 self
.BuildModules
.append(Ma
)
2014 self
.Progress
.Stop("done!")
2015 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
2016 MakeStart
= time
.time()
2017 for Ma
in self
.BuildModules
:
2018 # Generate build task for the module
2019 if not Ma
.IsBinaryModule
:
2020 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, self
.Target
))
2021 # Break build if any build thread has error
2022 if BuildTask
.HasError():
2023 # we need a full version of makefile for platform
2025 BuildTask
.WaitForComplete()
2026 Pa
.CreateMakeFile(False)
2027 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2028 # Start task scheduler
2029 if not BuildTask
.IsOnGoing():
2030 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
2032 # in case there's an interruption. we need a full version of makefile for platform
2033 Pa
.CreateMakeFile(False)
2034 if BuildTask
.HasError():
2035 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2036 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
2038 MakeContiue
= time
.time()
2042 # All modules have been put in build tasks queue. Tell task scheduler
2043 # to exit if all tasks are completed
2046 BuildTask
.WaitForComplete()
2047 self
.CreateAsBuiltInf()
2048 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2050 # Check for build error, and raise exception if one
2051 # has been signaled.
2053 if BuildTask
.HasError():
2054 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2056 # Create MAP file when Load Fix Address is enabled.
2057 if self
.Target
in ["", "all", "fds"]:
2058 for Arch
in Wa
.ArchList
:
2060 # Check whether the set fix address is above 4G for 32bit image.
2062 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2063 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")
2068 for Pa
in Wa
.AutoGenObjectList
:
2069 for Ma
in Pa
.ModuleAutoGenList
:
2072 if not Ma
.IsLibrary
:
2073 ModuleList
[Ma
.Guid
.upper()] = Ma
2075 # Rebase module to the preferred memory address before GenFds
2077 MapBuffer
= BytesIO('')
2078 if self
.LoadFixAddress
!= 0:
2079 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2083 # Generate FD image if there's a FDF file found
2085 GenFdsStart
= time
.time()
2086 if GenFdsApi(Wa
.GenFdsCommandDict
, self
.Db
):
2087 EdkLogger
.error("build", COMMAND_FAILURE
)
2090 # Create MAP file for all platform FVs after GenFds.
2092 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2093 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2095 # Save MAP buffer into MAP file.
2097 self
._SaveMapFile
(MapBuffer
, Wa
)
2099 ## Generate GuidedSectionTools.txt in the FV directories.
2101 def CreateGuidedSectionToolsFile(self
):
2102 for BuildTarget
in self
.BuildTargetList
:
2103 for ToolChain
in self
.ToolChainList
:
2104 Wa
= WorkspaceAutoGen(
2121 if not os
.path
.exists(FvDir
):
2124 for Arch
in self
.ArchList
:
2125 # Build up the list of supported architectures for this build
2126 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
2128 # Look through the tool definitions for GUIDed tools
2130 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.iteritems():
2131 if attrib
.upper().endswith('_GUID'):
2132 split
= attrib
.split('_')
2133 thisPrefix
= '_'.join(split
[0:3]) + '_'
2134 if thisPrefix
== prefix
:
2135 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
2138 path
= '_'.join(split
[0:4]) + '_PATH'
2139 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2140 path
= self
.GetFullPathOfTool(path
)
2141 guidAttribs
.append((guid
, toolName
, path
))
2143 # Write out GuidedSecTools.txt
2144 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2145 toolsFile
= open(toolsFile
, 'wt')
2146 for guidedSectionTool
in guidAttribs
:
2147 print(' '.join(guidedSectionTool
), file=toolsFile
)
2150 ## Returns the full path of the tool.
2152 def GetFullPathOfTool (self
, tool
):
2153 if os
.path
.exists(tool
):
2154 return os
.path
.realpath(tool
)
2156 # We need to search for the tool using the
2157 # PATH environment variable.
2158 for dirInPath
in os
.environ
['PATH'].split(os
.pathsep
):
2159 foundPath
= os
.path
.join(dirInPath
, tool
)
2160 if os
.path
.exists(foundPath
):
2161 return os
.path
.realpath(foundPath
)
2163 # If the tool was not found in the path then we just return
2167 ## Launch the module or platform build
2170 if not self
.ModuleFile
:
2171 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2172 self
.SpawnMode
= False
2173 self
._BuildPlatform
()
2175 self
._MultiThreadBuildPlatform
()
2176 self
.CreateGuidedSectionToolsFile()
2178 self
.SpawnMode
= False
2181 if self
.Target
== 'cleanall':
2182 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2184 def CreateAsBuiltInf(self
):
2185 for Module
in self
.BuildModules
:
2186 Module
.CreateAsBuiltInf()
2187 for Module
in self
.HashSkipModules
:
2188 Module
.CreateAsBuiltInf(True)
2189 self
.BuildModules
= []
2190 self
.HashSkipModules
= []
2191 ## Do some clean-up works when error occurred
2192 def Relinquish(self
):
2193 OldLogLevel
= EdkLogger
.GetLevel()
2194 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2195 #self.DumpBuildData()
2196 Utils
.Progressor
.Abort()
2197 if self
.SpawnMode
== True:
2199 EdkLogger
.SetLevel(OldLogLevel
)
2201 def DumpBuildData(self
):
2202 CacheDirectory
= os
.path
.dirname(GlobalData
.gDatabasePath
)
2203 Utils
.CreateDirectory(CacheDirectory
)
2204 Utils
._DataDump
(Utils
.gFileTimeStampCache
, os
.path
.join(CacheDirectory
, "gFileTimeStampCache"))
2205 Utils
._DataDump
(Utils
.gDependencyDatabase
, os
.path
.join(CacheDirectory
, "gDependencyDatabase"))
2207 def RestoreBuildData(self
):
2208 FilePath
= os
.path
.join(os
.path
.dirname(GlobalData
.gDatabasePath
), "gFileTimeStampCache")
2209 if Utils
.gFileTimeStampCache
== {} and os
.path
.isfile(FilePath
):
2210 Utils
.gFileTimeStampCache
= Utils
._DataRestore
(FilePath
)
2211 if Utils
.gFileTimeStampCache
is None:
2212 Utils
.gFileTimeStampCache
= {}
2214 FilePath
= os
.path
.join(os
.path
.dirname(GlobalData
.gDatabasePath
), "gDependencyDatabase")
2215 if Utils
.gDependencyDatabase
== {} and os
.path
.isfile(FilePath
):
2216 Utils
.gDependencyDatabase
= Utils
._DataRestore
(FilePath
)
2217 if Utils
.gDependencyDatabase
is None:
2218 Utils
.gDependencyDatabase
= {}
2220 def ParseDefines(DefineList
=[]):
2222 if DefineList
is not None:
2223 for Define
in DefineList
:
2224 DefineTokenList
= Define
.split("=", 1)
2225 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2226 EdkLogger
.error('build', FORMAT_INVALID
,
2227 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2228 ExtraData
=DefineTokenList
[0])
2230 if len(DefineTokenList
) == 1:
2231 DefineDict
[DefineTokenList
[0]] = "TRUE"
2233 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2237 def SingleCheckCallback(option
, opt_str
, value
, parser
):
2238 if option
not in gParamCheck
:
2239 setattr(parser
.values
, option
.dest
, value
)
2240 gParamCheck
.append(option
)
2242 parser
.error("Option %s only allows one instance in command line!" % option
)
2244 def LogBuildTime(Time
):
2247 TimeDur
= time
.gmtime(Time
)
2248 if TimeDur
.tm_yday
> 1:
2249 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2251 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2256 ## Parse command line options
2258 # Using standard Python module optparse to parse command line option of this tool.
2260 # @retval Opt A optparse.Values object containing the parsed options
2261 # @retval Args Target of build command
2263 def MyOptionParser():
2264 Parser
= OptionParser(description
=__copyright__
, version
=__version__
, prog
="build.exe", usage
="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
2265 Parser
.add_option("-a", "--arch", action
="append", type="choice", choices
=['IA32', 'X64', 'EBC', 'ARM', 'AARCH64'], dest
="TargetArch",
2266 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.")
2267 Parser
.add_option("-p", "--platform", action
="callback", type="string", dest
="PlatformFile", callback
=SingleCheckCallback
,
2268 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
2269 Parser
.add_option("-m", "--module", action
="callback", type="string", dest
="ModuleFile", callback
=SingleCheckCallback
,
2270 help="Build the module specified by the INF file name argument.")
2271 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
2273 Parser
.add_option("-t", "--tagname", action
="append", type="string", dest
="ToolChain",
2274 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
2275 Parser
.add_option("-x", "--sku-id", action
="callback", type="string", dest
="SkuId", callback
=SingleCheckCallback
,
2276 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
2278 Parser
.add_option("-n", action
="callback", type="int", dest
="ThreadNumber", callback
=SingleCheckCallback
,
2279 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 "\
2280 "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.")
2282 Parser
.add_option("-f", "--fdf", action
="callback", type="string", dest
="FdfFile", callback
=SingleCheckCallback
,
2283 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
2284 Parser
.add_option("-r", "--rom-image", action
="append", type="string", dest
="RomImage", default
=[],
2285 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
2286 Parser
.add_option("-i", "--fv-image", action
="append", type="string", dest
="FvImage", default
=[],
2287 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
2288 Parser
.add_option("-C", "--capsule-image", action
="append", type="string", dest
="CapName", default
=[],
2289 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
2290 Parser
.add_option("-u", "--skip-autogen", action
="store_true", dest
="SkipAutoGen", help="Skip AutoGen step.")
2291 Parser
.add_option("-e", "--re-parse", action
="store_true", dest
="Reparse", help="Re-parse all meta-data files.")
2293 Parser
.add_option("-c", "--case-insensitive", action
="store_true", dest
="CaseInsensitive", default
=False, help="Don't check case of file name.")
2295 Parser
.add_option("-w", "--warning-as-error", action
="store_true", dest
="WarningAsError", help="Treat warning in tools as error.")
2296 Parser
.add_option("-j", "--log", action
="store", dest
="LogFile", help="Put log in specified file as well as on console.")
2298 Parser
.add_option("-s", "--silent", action
="store_true", type=None, dest
="SilentMode",
2299 help="Make use of silent mode of (n)make.")
2300 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
2301 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
2302 "including library instances selected, final dependency expression, "\
2303 "and warning messages, etc.")
2304 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
2305 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
2307 Parser
.add_option("-y", "--report-file", action
="store", dest
="ReportFile", help="Create/overwrite the report to the specified filename.")
2308 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
=[],
2309 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]. "\
2310 "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]")
2311 Parser
.add_option("-F", "--flag", action
="store", type="string", dest
="Flag",
2312 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. "\
2313 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
2314 "will override the setting in [BuildOptions] section of platform DSC.")
2315 Parser
.add_option("-N", "--no-cache", action
="store_true", dest
="DisableCache", default
=False, help="Disable build cache mechanism")
2316 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
2317 Parser
.add_option("--check-usage", action
="store_true", dest
="CheckUsage", default
=False, help="Check usage content of entries listed in INF file.")
2318 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
2319 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
2320 Parser
.add_option("-l", "--cmd-len", action
="store", type="int", dest
="CommandLength", help="Specify the maximum line length of build command. Default is 4096.")
2321 Parser
.add_option("--hash", action
="store_true", dest
="UseHashCache", default
=False, help="Enable hash-based caching during build process.")
2322 Parser
.add_option("--binary-destination", action
="store", type="string", dest
="BinCacheDest", help="Generate a cache of binary files in the specified directory.")
2323 Parser
.add_option("--binary-source", action
="store", type="string", dest
="BinCacheSource", help="Consume a cache of binary files from the specified directory.")
2324 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
2325 (Opt
, Args
) = Parser
.parse_args()
2328 ## Tool entrance method
2330 # This method mainly dispatch specific methods per the command line options.
2331 # If no error found, return zero value so the caller of this tool can know
2332 # if it's executed successfully or not.
2334 # @retval 0 Tool was successful
2335 # @retval 1 Tool failed
2338 StartTime
= time
.time()
2340 # Initialize log system
2341 EdkLogger
.Initialize()
2342 GlobalData
.gCommand
= sys
.argv
[1:]
2344 # Parse the options and args
2346 (Option
, Target
) = MyOptionParser()
2347 GlobalData
.gOptions
= Option
2348 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2351 if Option
.verbose
is not None:
2352 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2353 elif Option
.quiet
is not None:
2354 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2355 elif Option
.debug
is not None:
2356 EdkLogger
.SetLevel(Option
.debug
+ 1)
2358 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2360 if Option
.LogFile
is not None:
2361 EdkLogger
.SetLogFile(Option
.LogFile
)
2363 if Option
.WarningAsError
== True:
2364 EdkLogger
.SetWarningAsError()
2366 if platform
.platform().find("Windows") >= 0:
2367 GlobalData
.gIsWindows
= True
2369 GlobalData
.gIsWindows
= False
2371 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2372 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2377 if len(Target
) == 0:
2379 elif len(Target
) >= 2:
2380 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2381 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2383 Target
= Target
[0].lower()
2385 if Target
not in gSupportedTarget
:
2386 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2387 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2390 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2393 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2395 Workspace
= os
.getenv("WORKSPACE")
2397 # Get files real name in workspace dir
2399 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2401 WorkingDirectory
= os
.getcwd()
2402 if not Option
.ModuleFile
:
2403 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2404 FileNum
= len(FileList
)
2406 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2407 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2409 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2411 if Option
.ModuleFile
:
2412 if os
.path
.isabs (Option
.ModuleFile
):
2413 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2414 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2415 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2416 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2418 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2420 if Option
.PlatformFile
is not None:
2421 if os
.path
.isabs (Option
.PlatformFile
):
2422 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2423 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2424 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2426 if Option
.FdfFile
is not None:
2427 if os
.path
.isabs (Option
.FdfFile
):
2428 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2429 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2430 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2431 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2433 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2435 if Option
.Flag
is not None and Option
.Flag
not in ['-c', '-s']:
2436 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2438 MyBuild
= Build(Target
, Workspace
, Option
)
2439 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2440 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2443 #MyBuild.DumpBuildData()
2445 # All job done, no error found and no exception raised
2448 except FatalError
as X
:
2449 if MyBuild
is not None:
2450 # for multi-thread build exits safely
2451 MyBuild
.Relinquish()
2452 if Option
is not None and Option
.debug
is not None:
2453 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2454 ReturnCode
= X
.args
[0]
2455 except Warning as X
:
2456 # error from Fdf parser
2457 if MyBuild
is not None:
2458 # for multi-thread build exits safely
2459 MyBuild
.Relinquish()
2460 if Option
is not None and Option
.debug
is not None:
2461 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2463 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2464 ReturnCode
= FORMAT_INVALID
2465 except KeyboardInterrupt:
2466 ReturnCode
= ABORT_ERROR
2467 if Option
is not None and Option
.debug
is not None:
2468 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2470 if MyBuild
is not None:
2471 # for multi-thread build exits safely
2472 MyBuild
.Relinquish()
2474 # try to get the meta-file from the object causing exception
2475 Tb
= sys
.exc_info()[-1]
2476 MetaFile
= GlobalData
.gProcessingFile
2477 while Tb
is not None:
2478 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2479 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2484 "Unknown fatal error when processing [%s]" % MetaFile
,
2485 ExtraData
="\n(Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!)\n",
2488 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2489 ReturnCode
= CODE_ERROR
2491 Utils
.Progressor
.Abort()
2492 Utils
.ClearDuplicatedInf()
2496 MyBuild
.LaunchPostbuild()
2499 Conclusion
= "Failed"
2500 elif ReturnCode
== ABORT_ERROR
:
2501 Conclusion
= "Aborted"
2503 Conclusion
= "Failed"
2504 FinishTime
= time
.time()
2505 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2506 BuildDurationStr
= ""
2507 if BuildDuration
.tm_yday
> 1:
2508 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2510 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2511 if MyBuild
is not None:
2513 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2515 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2516 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2517 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2518 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2521 if __name__
== '__main__':
2523 ## 0-127 is a safe return range, and 1 is a standard default error
2524 if r
< 0 or r
> 127: r
= 1