2 # build a platform or a module
4 # Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
5 # Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
6 # Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
8 # SPDX-License-Identifier: BSD-2-Clause-Patent
14 from __future__
import print_function
15 from __future__
import absolute_import
16 import os
.path
as path
24 import multiprocessing
25 from threading
import Thread
,Event
,BoundedSemaphore
27 from subprocess
import Popen
,PIPE
, STDOUT
28 from collections
import OrderedDict
, defaultdict
30 from AutoGen
.PlatformAutoGen
import PlatformAutoGen
31 from AutoGen
.ModuleAutoGen
import ModuleAutoGen
32 from AutoGen
.WorkspaceAutoGen
import WorkspaceAutoGen
33 from AutoGen
.AutoGenWorker
import AutoGenWorkerInProcess
,AutoGenManager
,\
35 from AutoGen
import GenMake
36 from Common
import Misc
as Utils
38 from Common
.TargetTxtClassObject
import TargetTxtDict
39 from Common
.ToolDefClassObject
import ToolDefDict
40 from buildoptions
import MyOptionParser
41 from Common
.Misc
import PathClass
,SaveFileOnChange
,RemoveDirectory
42 from Common
.StringUtils
import NormPath
43 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
44 from Common
.BuildToolError
import *
45 from Common
.DataType
import *
46 import Common
.EdkLogger
as EdkLogger
48 from Workspace
.WorkspaceDatabase
import BuildDB
50 from BuildReport
import BuildReport
51 from GenPatchPcdTable
.GenPatchPcdTable
import PeImageClass
,parsePcdInfoFromMapFile
52 from PatchPcdValue
.PatchPcdValue
import PatchBinaryFile
54 import Common
.GlobalData
as GlobalData
55 from GenFds
.GenFds
import GenFds
, GenFdsApi
56 import multiprocessing
as mp
57 from multiprocessing
import Manager
58 from AutoGen
.DataPipe
import MemoryDataPipe
59 from AutoGen
.ModuleAutoGenHelper
import WorkSpaceInfo
, PlatformInfo
60 from GenFds
.FdfParser
import FdfParser
61 from AutoGen
.IncludesAutoGen
import IncludesAutoGen
62 from GenFds
.GenFds
import resetFdsGlobalVariable
64 ## standard targets of build command
65 gSupportedTarget
= ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
67 ## build configuration file
68 gBuildConfiguration
= "target.txt"
69 gToolsDefinition
= "tools_def.txt"
71 TemporaryTablePattern
= re
.compile(r
'^_\d+_\d+_[a-fA-F0-9]+$')
74 ## Check environment PATH variable to make sure the specified tool is found
76 # If the tool is found in the PATH, then True is returned
77 # Otherwise, False is returned
79 def IsToolInPath(tool
):
80 if 'PATHEXT' in os
.environ
:
81 extns
= os
.environ
['PATHEXT'].split(os
.path
.pathsep
)
84 for pathDir
in os
.environ
['PATH'].split(os
.path
.pathsep
):
86 if os
.path
.exists(os
.path
.join(pathDir
, tool
+ ext
)):
90 ## Check environment variables
92 # Check environment variables that must be set for build. Currently they are
94 # WORKSPACE The directory all packages/platforms start from
95 # EDK_TOOLS_PATH The directory contains all tools needed by the build
96 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
98 # If any of above environment variable is not set or has error, the build
101 def CheckEnvVariable():
103 if "WORKSPACE" not in os
.environ
:
104 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
105 ExtraData
="WORKSPACE")
107 WorkspaceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["WORKSPACE"]))
108 if not os
.path
.exists(WorkspaceDir
):
109 EdkLogger
.error("build", FILE_NOT_FOUND
, "WORKSPACE doesn't exist", ExtraData
=WorkspaceDir
)
110 elif ' ' in WorkspaceDir
:
111 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in WORKSPACE path",
112 ExtraData
=WorkspaceDir
)
113 os
.environ
["WORKSPACE"] = WorkspaceDir
115 # set multiple workspace
116 PackagesPath
= os
.getenv("PACKAGES_PATH")
117 mws
.setWs(WorkspaceDir
, PackagesPath
)
118 if mws
.PACKAGES_PATH
:
119 for Path
in mws
.PACKAGES_PATH
:
120 if not os
.path
.exists(Path
):
121 EdkLogger
.error("build", FILE_NOT_FOUND
, "One Path in PACKAGES_PATH doesn't exist", ExtraData
=Path
)
123 EdkLogger
.error("build", FORMAT_NOT_SUPPORTED
, "No space is allowed in PACKAGES_PATH", ExtraData
=Path
)
126 os
.environ
["EDK_TOOLS_PATH"] = os
.path
.normcase(os
.environ
["EDK_TOOLS_PATH"])
128 # check EDK_TOOLS_PATH
129 if "EDK_TOOLS_PATH" not in os
.environ
:
130 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
131 ExtraData
="EDK_TOOLS_PATH")
134 if "PATH" not in os
.environ
:
135 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
138 GlobalData
.gWorkspace
= WorkspaceDir
140 GlobalData
.gGlobalDefines
["WORKSPACE"] = WorkspaceDir
141 GlobalData
.gGlobalDefines
["EDK_TOOLS_PATH"] = os
.environ
["EDK_TOOLS_PATH"]
143 ## Get normalized file path
145 # Convert the path to be local format, and remove the WORKSPACE path at the
146 # beginning if the file path is given in full path.
148 # @param FilePath File path to be normalized
149 # @param Workspace Workspace path which the FilePath will be checked against
151 # @retval string The normalized file path
153 def NormFile(FilePath
, Workspace
):
154 # check if the path is absolute or relative
155 if os
.path
.isabs(FilePath
):
156 FileFullPath
= os
.path
.normpath(FilePath
)
158 FileFullPath
= os
.path
.normpath(mws
.join(Workspace
, FilePath
))
159 Workspace
= mws
.getWs(Workspace
, FilePath
)
161 # check if the file path exists or not
162 if not os
.path
.isfile(FileFullPath
):
163 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath
)
165 # remove workspace directory from the beginning part of the file path
166 if Workspace
[-1] in ["\\", "/"]:
167 return FileFullPath
[len(Workspace
):]
169 return FileFullPath
[(len(Workspace
) + 1):]
171 ## Get the output of an external program
173 # This is the entrance method of thread reading output of an external program and
174 # putting them in STDOUT/STDERR of current program.
176 # @param From The stream message read from
177 # @param To The stream message put on
178 # @param ExitFlag The flag used to indicate stopping reading
180 def ReadMessage(From
, To
, ExitFlag
,MemTo
=None):
182 # read one line a time
183 Line
= From
.readline()
184 # empty string means "end"
185 if Line
is not None and Line
!= b
"":
186 LineStr
= Line
.rstrip().decode(encoding
='utf-8', errors
='ignore')
187 if MemTo
is not None:
188 if "Note: including file:" == LineStr
.lstrip()[:21]:
189 MemTo
.append(LineStr
)
192 MemTo
.append(LineStr
)
200 class MakeSubProc(Popen
):
201 def __init__(self
,*args
, **argv
):
202 super(MakeSubProc
,self
).__init
__(*args
, **argv
)
205 ## Launch an external program
207 # This method will call subprocess.Popen to execute an external program with
208 # given options in specified directory. Because of the dead-lock issue during
209 # redirecting output of the external program, threads are used to to do the
212 # @param Command A list or string containing the call of the program
213 # @param WorkingDir The directory in which the program will be running
215 def LaunchCommand(Command
, WorkingDir
,ModuleAuto
= None):
216 BeginTime
= time
.time()
217 # if working directory doesn't exist, Popen() will raise an exception
218 if not os
.path
.isdir(WorkingDir
):
219 EdkLogger
.error("build", FILE_NOT_FOUND
, ExtraData
=WorkingDir
)
221 # Command is used as the first Argument in following Popen().
222 # It could be a string or sequence. We find that if command is a string in following Popen(),
223 # ubuntu may fail with an error message that the command is not found.
224 # So here we may need convert command from string to list instance.
225 if platform
.system() != 'Windows':
226 if not isinstance(Command
, list):
227 Command
= Command
.split()
228 Command
= ' '.join(Command
)
231 EndOfProcedure
= None
234 Proc
= MakeSubProc(Command
, stdout
=PIPE
, stderr
=STDOUT
, env
=os
.environ
, cwd
=WorkingDir
, bufsize
=-1, shell
=True)
236 # launch two threads to read the STDOUT and STDERR
237 EndOfProcedure
= Event()
238 EndOfProcedure
.clear()
240 StdOutThread
= Thread(target
=ReadMessage
, args
=(Proc
.stdout
, EdkLogger
.info
, EndOfProcedure
,Proc
.ProcOut
))
241 StdOutThread
.setName("STDOUT-Redirector")
242 StdOutThread
.setDaemon(False)
246 # waiting for program exit
248 except: # in case of aborting
249 # terminate the threads redirecting the program output
250 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
251 if EndOfProcedure
is not None:
254 if not isinstance(Command
, type("")):
255 Command
= " ".join(Command
)
256 EdkLogger
.error("build", COMMAND_FAILURE
, "Failed to start command", ExtraData
="%s [%s]" % (Command
, WorkingDir
))
261 # check the return code of the program
262 if Proc
.returncode
!= 0:
263 if not isinstance(Command
, type("")):
264 Command
= " ".join(Command
)
265 # print out the Response file and its content when make failure
266 RespFile
= os
.path
.join(WorkingDir
, 'OUTPUT', 'respfilelist.txt')
267 if os
.path
.isfile(RespFile
):
269 RespContent
= f
.read()
271 EdkLogger
.info(RespContent
)
273 EdkLogger
.error("build", COMMAND_FAILURE
, ExtraData
="%s [%s]" % (Command
, WorkingDir
))
275 iau
= IncludesAutoGen(WorkingDir
,ModuleAuto
)
276 if ModuleAuto
.ToolChainFamily
== TAB_COMPILER_MSFT
:
277 iau
.CreateDepsFileForMsvc(Proc
.ProcOut
)
279 iau
.UpdateDepsFileforNonMsvc()
280 iau
.UpdateDepsFileforTrim()
281 iau
.CreateModuleDeps()
282 iau
.CreateDepsInclude()
283 return "%dms" % (int(round((time
.time() - BeginTime
) * 1000)))
285 ## The smallest unit that can be built in multi-thread build mode
287 # This is the base class of build unit. The "Obj" parameter must provide
288 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
291 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
296 # @param self The object pointer
297 # @param Obj The object the build is working on
298 # @param Target The build target name, one of gSupportedTarget
299 # @param Dependency The BuildUnit(s) which must be completed in advance
300 # @param WorkingDir The directory build command starts in
302 def __init__(self
, Obj
, BuildCommand
, Target
, Dependency
, WorkingDir
="."):
303 self
.BuildObject
= Obj
304 self
.Dependency
= Dependency
305 self
.WorkingDir
= WorkingDir
307 self
.BuildCommand
= BuildCommand
309 EdkLogger
.error("build", OPTION_MISSING
,
310 "No build command found for this module. "
311 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
312 (Obj
.BuildTarget
, Obj
.ToolChain
, Obj
.Arch
),
318 # It just returns the string representation of self.BuildObject
320 # @param self The object pointer
323 return str(self
.BuildObject
)
325 ## "==" operator method
327 # It just compares self.BuildObject with "Other". So self.BuildObject must
328 # provide its own __eq__() method.
330 # @param self The object pointer
331 # @param Other The other BuildUnit object compared to
333 def __eq__(self
, Other
):
334 return Other
and self
.BuildObject
== Other
.BuildObject \
335 and Other
.BuildObject \
336 and self
.BuildObject
.Arch
== Other
.BuildObject
.Arch
340 # It just returns the hash value of self.BuildObject which must be hashable.
342 # @param self The object pointer
345 return hash(self
.BuildObject
) + hash(self
.BuildObject
.Arch
)
348 return repr(self
.BuildObject
)
350 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
352 # This class is for module build by nmake/make build system. The "Obj" parameter
353 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
354 # be make units missing build.
356 # Currently the "Obj" should be only ModuleAutoGen object.
358 class ModuleMakeUnit(BuildUnit
):
361 # @param self The object pointer
362 # @param Obj The ModuleAutoGen object the build is working on
363 # @param Target The build target name, one of gSupportedTarget
365 def __init__(self
, Obj
, BuildCommand
,Target
):
366 Dependency
= [ModuleMakeUnit(La
, BuildCommand
,Target
) for La
in Obj
.LibraryAutoGenList
]
367 BuildUnit
.__init
__(self
, Obj
, BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
368 if Target
in [None, "", "all"]:
369 self
.Target
= "tbuild"
371 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
373 # This class is for platform build by nmake/make build system. The "Obj" parameter
374 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
375 # be make units missing build.
377 # Currently the "Obj" should be only PlatformAutoGen object.
379 class PlatformMakeUnit(BuildUnit
):
382 # @param self The object pointer
383 # @param Obj The PlatformAutoGen object the build is working on
384 # @param Target The build target name, one of gSupportedTarget
386 def __init__(self
, Obj
, BuildCommand
, Target
):
387 Dependency
= [ModuleMakeUnit(Lib
, BuildCommand
, Target
) for Lib
in self
.BuildObject
.LibraryAutoGenList
]
388 Dependency
.extend([ModuleMakeUnit(Mod
, BuildCommand
,Target
) for Mod
in self
.BuildObject
.ModuleAutoGenList
])
389 BuildUnit
.__init
__(self
, Obj
, BuildCommand
, Target
, Dependency
, Obj
.MakeFileDir
)
391 ## The class representing the task of a module build or platform build
393 # This class manages the build tasks in multi-thread build mode. Its jobs include
394 # scheduling thread running, catching thread error, monitor the thread status, etc.
397 # queue for tasks waiting for schedule
398 _PendingQueue
= OrderedDict()
399 _PendingQueueLock
= threading
.Lock()
401 # queue for tasks ready for running
402 _ReadyQueue
= OrderedDict()
403 _ReadyQueueLock
= threading
.Lock()
405 # queue for run tasks
406 _RunningQueue
= OrderedDict()
407 _RunningQueueLock
= threading
.Lock()
409 # queue containing all build tasks, in case duplicate build
410 _TaskQueue
= OrderedDict()
412 # flag indicating error occurs in a running thread
413 _ErrorFlag
= threading
.Event()
417 # BoundedSemaphore object used to control the number of running threads
420 # flag indicating if the scheduler is started or not
421 _SchedulerStopped
= threading
.Event()
422 _SchedulerStopped
.set()
424 ## Start the task scheduler thread
426 # @param MaxThreadNumber The maximum thread number
427 # @param ExitFlag Flag used to end the scheduler
430 def StartScheduler(MaxThreadNumber
, ExitFlag
):
431 SchedulerThread
= Thread(target
=BuildTask
.Scheduler
, args
=(MaxThreadNumber
, ExitFlag
))
432 SchedulerThread
.setName("Build-Task-Scheduler")
433 SchedulerThread
.setDaemon(False)
434 SchedulerThread
.start()
435 # wait for the scheduler to be started, especially useful in Linux
436 while not BuildTask
.IsOnGoing():
441 # @param MaxThreadNumber The maximum thread number
442 # @param ExitFlag Flag used to end the scheduler
445 def Scheduler(MaxThreadNumber
, ExitFlag
):
446 BuildTask
._SchedulerStopped
.clear()
448 # use BoundedSemaphore to control the maximum running threads
449 BuildTask
._Thread
= BoundedSemaphore(MaxThreadNumber
)
451 # scheduling loop, which will exits when no pending/ready task and
452 # indicated to do so, or there's error in running thread
454 while (len(BuildTask
._PendingQueue
) > 0 or len(BuildTask
._ReadyQueue
) > 0 \
455 or not ExitFlag
.isSet()) and not BuildTask
._ErrorFlag
.isSet():
456 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Pending Queue (%d), Ready Queue (%d)"
457 % (len(BuildTask
._PendingQueue
), len(BuildTask
._ReadyQueue
)))
459 # get all pending tasks
460 BuildTask
._PendingQueueLock
.acquire()
461 BuildObjectList
= list(BuildTask
._PendingQueue
.keys())
463 # check if their dependency is resolved, and if true, move them
466 for BuildObject
in BuildObjectList
:
467 Bt
= BuildTask
._PendingQueue
[BuildObject
]
469 BuildTask
._ReadyQueue
[BuildObject
] = BuildTask
._PendingQueue
.pop(BuildObject
)
470 BuildTask
._PendingQueueLock
.release()
472 # launch build thread until the maximum number of threads is reached
473 while not BuildTask
._ErrorFlag
.isSet():
474 # empty ready queue, do nothing further
475 if len(BuildTask
._ReadyQueue
) == 0:
478 # wait for active thread(s) exit
479 BuildTask
._Thread
.acquire(True)
481 # start a new build thread
482 Bo
, Bt
= BuildTask
._ReadyQueue
.popitem()
484 # move into running queue
485 BuildTask
._RunningQueueLock
.acquire()
486 BuildTask
._RunningQueue
[Bo
] = Bt
487 BuildTask
._RunningQueueLock
.release()
496 # wait for all running threads exit
497 if BuildTask
._ErrorFlag
.isSet():
498 EdkLogger
.quiet("\nWaiting for all build threads exit...")
499 # while not BuildTask._ErrorFlag.isSet() and \
500 while len(BuildTask
._RunningQueue
) > 0:
501 EdkLogger
.verbose("Waiting for thread ending...(%d)" % len(BuildTask
._RunningQueue
))
502 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Threads [%s]" % ", ".join(Th
.getName() for Th
in threading
.enumerate()))
505 except BaseException
as X
:
507 # TRICK: hide the output of threads left running, so that the user can
508 # catch the error message easily
510 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
511 BuildTask
._ErrorFlag
.set()
512 BuildTask
._ErrorMessage
= "build thread scheduler error\n\t%s" % str(X
)
514 BuildTask
._PendingQueue
.clear()
515 BuildTask
._ReadyQueue
.clear()
516 BuildTask
._RunningQueue
.clear()
517 BuildTask
._TaskQueue
.clear()
518 BuildTask
._SchedulerStopped
.set()
520 ## Wait for all running method exit
523 def WaitForComplete():
524 BuildTask
._SchedulerStopped
.wait()
526 ## Check if the scheduler is running or not
530 return not BuildTask
._SchedulerStopped
.isSet()
535 if BuildTask
.IsOnGoing():
536 BuildTask
._ErrorFlag
.set()
537 BuildTask
.WaitForComplete()
539 ## Check if there's error in running thread
541 # Since the main thread cannot catch exceptions in other thread, we have to
542 # use threading.Event to communicate this formation to main thread.
546 return BuildTask
._ErrorFlag
.isSet()
548 ## Get error message in running thread
550 # Since the main thread cannot catch exceptions in other thread, we have to
551 # use a static variable to communicate this message to main thread.
554 def GetErrorMessage():
555 return BuildTask
._ErrorMessage
557 ## Factory method to create a BuildTask object
559 # This method will check if a module is building or has been built. And if
560 # true, just return the associated BuildTask object in the _TaskQueue. If
561 # not, create and return a new BuildTask object. The new BuildTask object
562 # will be appended to the _PendingQueue for scheduling later.
564 # @param BuildItem A BuildUnit object representing a build object
565 # @param Dependency The dependent build object of BuildItem
568 def New(BuildItem
, Dependency
=None):
569 if BuildItem
in BuildTask
._TaskQueue
:
570 Bt
= BuildTask
._TaskQueue
[BuildItem
]
574 Bt
._Init
(BuildItem
, Dependency
)
575 BuildTask
._TaskQueue
[BuildItem
] = Bt
577 BuildTask
._PendingQueueLock
.acquire()
578 BuildTask
._PendingQueue
[BuildItem
] = Bt
579 BuildTask
._PendingQueueLock
.release()
583 ## The real constructor of BuildTask
585 # @param BuildItem A BuildUnit object representing a build object
586 # @param Dependency The dependent build object of BuildItem
588 def _Init(self
, BuildItem
, Dependency
=None):
589 self
.BuildItem
= BuildItem
591 self
.DependencyList
= []
592 if Dependency
is None:
593 Dependency
= BuildItem
.Dependency
595 Dependency
.extend(BuildItem
.Dependency
)
596 self
.AddDependency(Dependency
)
597 # flag indicating build completes, used to avoid unnecessary re-build
598 self
.CompleteFlag
= False
600 ## Check if all dependent build tasks are completed or not
604 for Dep
in self
.DependencyList
:
605 if Dep
.CompleteFlag
== True:
612 ## Add dependent build task
614 # @param Dependency The list of dependent build objects
616 def AddDependency(self
, Dependency
):
617 for Dep
in Dependency
:
618 if not Dep
.BuildObject
.IsBinaryModule
and not Dep
.BuildObject
.CanSkipbyCache(GlobalData
.gModuleCacheHit
):
619 self
.DependencyList
.append(BuildTask
.New(Dep
)) # BuildTask list
621 ## The thread wrapper of LaunchCommand function
623 # @param Command A list or string contains the call of the command
624 # @param WorkingDir The directory in which the program will be running
626 def _CommandThread(self
, Command
, WorkingDir
):
628 self
.BuildItem
.BuildObject
.BuildTime
= LaunchCommand(Command
, WorkingDir
,self
.BuildItem
.BuildObject
)
629 self
.CompleteFlag
= True
631 # Run hash operation post dependency to account for libs
632 # Run if --hash or --binary-destination
633 if GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
634 self
.BuildItem
.BuildObject
.GenModuleHash()
635 if GlobalData
.gBinCacheDest
:
636 self
.BuildItem
.BuildObject
.GenCMakeHash()
640 # TRICK: hide the output of threads left running, so that the user can
641 # catch the error message easily
643 if not BuildTask
._ErrorFlag
.isSet():
644 GlobalData
.gBuildingModule
= "%s [%s, %s, %s]" % (str(self
.BuildItem
.BuildObject
),
645 self
.BuildItem
.BuildObject
.Arch
,
646 self
.BuildItem
.BuildObject
.ToolChain
,
647 self
.BuildItem
.BuildObject
.BuildTarget
649 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
650 BuildTask
._ErrorFlag
.set()
651 BuildTask
._ErrorMessage
= "%s broken\n %s [%s]" % \
652 (threading
.currentThread().getName(), Command
, WorkingDir
)
654 # indicate there's a thread is available for another build task
655 BuildTask
._RunningQueueLock
.acquire()
656 BuildTask
._RunningQueue
.pop(self
.BuildItem
)
657 BuildTask
._RunningQueueLock
.release()
658 BuildTask
._Thread
.release()
660 ## Start build task thread
663 EdkLogger
.quiet("Building ... %s" % repr(self
.BuildItem
))
664 Command
= self
.BuildItem
.BuildCommand
+ [self
.BuildItem
.Target
]
665 self
.BuildTread
= Thread(target
=self
._CommandThread
, args
=(Command
, self
.BuildItem
.WorkingDir
))
666 self
.BuildTread
.setName("build thread")
667 self
.BuildTread
.setDaemon(False)
668 self
.BuildTread
.start()
670 ## The class contains the information related to EFI image
675 # Constructor will load all required image information.
677 # @param BaseName The full file path of image.
678 # @param Guid The GUID for image.
679 # @param Arch Arch of this image.
680 # @param OutputDir The output directory for image.
681 # @param DebugDir The debug directory for image.
682 # @param ImageClass PeImage Information
684 def __init__(self
, BaseName
, Guid
, Arch
, OutputDir
, DebugDir
, ImageClass
):
685 self
.BaseName
= BaseName
688 self
.OutputDir
= OutputDir
689 self
.DebugDir
= DebugDir
690 self
.Image
= ImageClass
691 self
.Image
.Size
= (self
.Image
.Size
// 0x1000 + 1) * 0x1000
693 ## The class implementing the EDK2 build process
695 # The build process includes:
696 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
697 # 2. Parse DSC file of active platform
698 # 3. Parse FDF file if any
699 # 4. Establish build database, including parse all other files (module, package)
700 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
701 # 6. Call build command
706 # Constructor will load all necessary configurations, parse platform, modules
707 # and packages and the establish a database for AutoGen.
709 # @param Target The build command target, one of gSupportedTarget
710 # @param WorkspaceDir The directory of workspace
711 # @param BuildOptions Build options passed from command line
713 def __init__(self
, Target
, WorkspaceDir
, BuildOptions
,log_q
):
714 self
.WorkspaceDir
= WorkspaceDir
716 self
.PlatformFile
= BuildOptions
.PlatformFile
717 self
.ModuleFile
= BuildOptions
.ModuleFile
718 self
.ArchList
= BuildOptions
.TargetArch
719 self
.ToolChainList
= BuildOptions
.ToolChain
720 self
.BuildTargetList
= BuildOptions
.BuildTarget
721 self
.Fdf
= BuildOptions
.FdfFile
722 self
.FdList
= BuildOptions
.RomImage
723 self
.FvList
= BuildOptions
.FvImage
724 self
.CapList
= BuildOptions
.CapName
725 self
.SilentMode
= BuildOptions
.SilentMode
726 self
.ThreadNumber
= 1
727 self
.SkipAutoGen
= BuildOptions
.SkipAutoGen
728 self
.Reparse
= BuildOptions
.Reparse
729 self
.SkuId
= BuildOptions
.SkuId
731 GlobalData
.gSKUID_CMD
= self
.SkuId
732 self
.ConfDirectory
= BuildOptions
.ConfDirectory
733 self
.SpawnMode
= True
734 self
.BuildReport
= BuildReport(BuildOptions
.ReportFile
, BuildOptions
.ReportType
)
738 TargetObj
= TargetTxtDict()
739 ToolDefObj
= ToolDefDict((os
.path
.join(os
.getenv("WORKSPACE"),"Conf")))
740 self
.TargetTxt
= TargetObj
.Target
741 self
.ToolDef
= ToolDefObj
.ToolDef
742 GlobalData
.BuildOptionPcd
= BuildOptions
.OptionPcd
if BuildOptions
.OptionPcd
else []
743 #Set global flag for build mode
744 GlobalData
.gIgnoreSource
= BuildOptions
.IgnoreSources
745 GlobalData
.gUseHashCache
= BuildOptions
.UseHashCache
746 GlobalData
.gBinCacheDest
= BuildOptions
.BinCacheDest
747 GlobalData
.gBinCacheSource
= BuildOptions
.BinCacheSource
748 GlobalData
.gEnableGenfdsMultiThread
= not BuildOptions
.NoGenfdsMultiThread
749 GlobalData
.gDisableIncludePathCheck
= BuildOptions
.DisableIncludePathCheck
751 if GlobalData
.gBinCacheDest
and not GlobalData
.gUseHashCache
:
752 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination must be used together with --hash.")
754 if GlobalData
.gBinCacheSource
and not GlobalData
.gUseHashCache
:
755 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-source must be used together with --hash.")
757 if GlobalData
.gBinCacheDest
and GlobalData
.gBinCacheSource
:
758 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, ExtraData
="--binary-destination can not be used together with --binary-source.")
760 if GlobalData
.gBinCacheSource
:
761 BinCacheSource
= os
.path
.normpath(GlobalData
.gBinCacheSource
)
762 if not os
.path
.isabs(BinCacheSource
):
763 BinCacheSource
= mws
.join(self
.WorkspaceDir
, BinCacheSource
)
764 GlobalData
.gBinCacheSource
= BinCacheSource
766 if GlobalData
.gBinCacheSource
is not None:
767 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-source.")
769 if GlobalData
.gBinCacheDest
:
770 BinCacheDest
= os
.path
.normpath(GlobalData
.gBinCacheDest
)
771 if not os
.path
.isabs(BinCacheDest
):
772 BinCacheDest
= mws
.join(self
.WorkspaceDir
, BinCacheDest
)
773 GlobalData
.gBinCacheDest
= BinCacheDest
775 if GlobalData
.gBinCacheDest
is not None:
776 EdkLogger
.error("build", OPTION_VALUE_INVALID
, ExtraData
="Invalid value of option --binary-destination.")
778 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(GlobalData
.gConfDirectory
, GlobalData
.gDatabasePath
))
779 if not os
.path
.exists(os
.path
.join(GlobalData
.gConfDirectory
, '.cache')):
780 os
.makedirs(os
.path
.join(GlobalData
.gConfDirectory
, '.cache'))
782 self
.BuildDatabase
= self
.Db
.BuildObject
784 self
.ToolChainFamily
= None
785 self
.LoadFixAddress
= 0
786 self
.UniFlag
= BuildOptions
.Flag
787 self
.BuildModules
= []
788 self
.HashSkipModules
= []
790 self
.LaunchPrebuildFlag
= False
791 self
.PlatformBuildPath
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PlatformBuild')
792 if BuildOptions
.CommandLength
:
793 GlobalData
.gCommandMaxLength
= BuildOptions
.CommandLength
795 # print dot character during doing some time-consuming work
796 self
.Progress
= Utils
.Progressor()
797 # print current build environment and configuration
798 EdkLogger
.quiet("%-16s = %s" % ("WORKSPACE", os
.environ
["WORKSPACE"]))
799 if "PACKAGES_PATH" in os
.environ
:
800 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
801 EdkLogger
.quiet("%-16s = %s" % ("PACKAGES_PATH", os
.path
.normcase(os
.path
.normpath(os
.environ
["PACKAGES_PATH"]))))
802 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os
.environ
["EDK_TOOLS_PATH"]))
803 if "EDK_TOOLS_BIN" in os
.environ
:
804 # Print the same path style with WORKSPACE env.
805 EdkLogger
.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os
.path
.normcase(os
.path
.normpath(os
.environ
["EDK_TOOLS_BIN"]))))
806 EdkLogger
.quiet("%-16s = %s" % ("CONF_PATH", GlobalData
.gConfDirectory
))
807 if "PYTHON3_ENABLE" in os
.environ
:
808 PYTHON3_ENABLE
= os
.environ
["PYTHON3_ENABLE"]
809 if PYTHON3_ENABLE
!= "TRUE":
810 PYTHON3_ENABLE
= "FALSE"
811 EdkLogger
.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE
))
812 if "PYTHON_COMMAND" in os
.environ
:
813 EdkLogger
.quiet("%-16s = %s" % ("PYTHON_COMMAND", os
.environ
["PYTHON_COMMAND"]))
817 EdkLogger
.quiet("%-16s = %s" % ("PREBUILD", self
.Prebuild
))
819 EdkLogger
.quiet("%-16s = %s" % ("POSTBUILD", self
.Postbuild
))
821 self
.LaunchPrebuild()
822 TargetObj
= TargetTxtDict()
823 ToolDefObj
= ToolDefDict((os
.path
.join(os
.getenv("WORKSPACE"), "Conf")))
824 self
.TargetTxt
= TargetObj
.Target
825 self
.ToolDef
= ToolDefObj
.ToolDef
826 if not (self
.LaunchPrebuildFlag
and os
.path
.exists(self
.PlatformBuildPath
)):
829 self
.AutoGenMgr
= None
831 os
.chdir(self
.WorkspaceDir
)
833 GlobalData
.file_lock
= mp
.Lock()
834 # Init cache data for local only
835 GlobalData
.gPackageHashFile
= dict()
836 GlobalData
.gModulePreMakeCacheStatus
= dict()
837 GlobalData
.gModuleMakeCacheStatus
= dict()
838 GlobalData
.gHashChainStatus
= dict()
839 GlobalData
.gCMakeHashFile
= dict()
840 GlobalData
.gModuleHashFile
= dict()
841 GlobalData
.gFileHashDict
= dict()
842 GlobalData
.gModuleAllCacheStatus
= set()
843 GlobalData
.gModuleCacheHit
= set()
845 def StartAutoGen(self
,mqueue
, DataPipe
,SkipAutoGen
,PcdMaList
,cqueue
):
849 feedback_q
= mp
.Queue()
850 error_event
= mp
.Event()
851 FfsCmd
= DataPipe
.Get("FfsCommand")
854 GlobalData
.FfsCmd
= FfsCmd
855 auto_workers
= [AutoGenWorkerInProcess(mqueue
,DataPipe
.dump_file
,feedback_q
,GlobalData
.file_lock
,cqueue
,self
.log_q
,error_event
) for _
in range(self
.ThreadNumber
)]
856 self
.AutoGenMgr
= AutoGenManager(auto_workers
,feedback_q
,error_event
)
857 self
.AutoGenMgr
.start()
858 for w
in auto_workers
:
860 if PcdMaList
is not None:
861 for PcdMa
in PcdMaList
:
862 # SourceFileList calling sequence impact the makefile string sequence.
863 # Create cached SourceFileList here to unify its calling sequence for both
864 # CanSkipbyPreMakeCache and CreateCodeFile/CreateMakeFile.
865 RetVal
= PcdMa
.SourceFileList
866 # Force cache miss for PCD driver
867 if GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheDest
and self
.Target
in [None, "", "all"]:
868 cqueue
.put((PcdMa
.MetaFile
.Path
, PcdMa
.Arch
, "PreMakeCache", False))
870 PcdMa
.CreateCodeFile(False)
871 PcdMa
.CreateMakeFile(False,GenFfsList
= DataPipe
.Get("FfsCommand").get((PcdMa
.MetaFile
.Path
, PcdMa
.Arch
),[]))
873 # Force cache miss for PCD driver
874 if GlobalData
.gBinCacheSource
and self
.Target
in [None, "", "all"]:
875 cqueue
.put((PcdMa
.MetaFile
.Path
, PcdMa
.Arch
, "MakeCache", False))
877 self
.AutoGenMgr
.join()
878 rt
= self
.AutoGenMgr
.Status
880 except FatalError
as e
:
881 return False, e
.args
[0]
883 return False, UNKNOWN_ERROR
885 ## Load configuration
887 # This method will parse target.txt and get the build configurations.
889 def LoadConfiguration(self
):
891 # if no ARCH given in command line, get it from target.txt
892 if not self
.ArchList
:
893 self
.ArchList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET_ARCH
]
894 self
.ArchList
= tuple(self
.ArchList
)
896 # if no build target given in command line, get it from target.txt
897 if not self
.BuildTargetList
:
898 self
.BuildTargetList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
900 # if no tool chain given in command line, get it from target.txt
901 if not self
.ToolChainList
:
902 self
.ToolChainList
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
903 if self
.ToolChainList
is None or len(self
.ToolChainList
) == 0:
904 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.\n")
906 # check if the tool chains are defined or not
907 NewToolChainList
= []
908 for ToolChain
in self
.ToolChainList
:
909 if ToolChain
not in self
.ToolDef
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]:
910 EdkLogger
.warn("build", "Tool chain [%s] is not defined" % ToolChain
)
912 NewToolChainList
.append(ToolChain
)
913 # if no tool chain available, break the build
914 if len(NewToolChainList
) == 0:
915 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
916 ExtraData
="[%s] not defined. No toolchain available for build!\n" % ", ".join(self
.ToolChainList
))
918 self
.ToolChainList
= NewToolChainList
921 ToolDefinition
= self
.ToolDef
.ToolsDefTxtDatabase
922 for Tool
in self
.ToolChainList
:
923 if TAB_TOD_DEFINES_FAMILY
not in ToolDefinition
or Tool
not in ToolDefinition
[TAB_TOD_DEFINES_FAMILY
] \
924 or not ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
]:
925 EdkLogger
.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool
)
926 ToolChainFamily
.append(TAB_COMPILER_MSFT
)
928 ToolChainFamily
.append(ToolDefinition
[TAB_TOD_DEFINES_FAMILY
][Tool
])
929 self
.ToolChainFamily
= ToolChainFamily
931 if not self
.PlatformFile
:
932 PlatformFile
= self
.TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_ACTIVE_PLATFORM
]
934 # Try to find one in current directory
935 WorkingDirectory
= os
.getcwd()
936 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.dsc')))
937 FileNum
= len(FileList
)
939 EdkLogger
.error("build", OPTION_MISSING
,
940 ExtraData
="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum
, WorkingDirectory
))
942 PlatformFile
= FileList
[0]
944 EdkLogger
.error("build", RESOURCE_NOT_AVAILABLE
,
945 ExtraData
="No active platform specified in target.txt or command line! Nothing can be built.\n")
947 self
.PlatformFile
= PathClass(NormFile(PlatformFile
, self
.WorkspaceDir
), self
.WorkspaceDir
)
948 self
.ThreadNumber
= ThreadNum()
949 ## Initialize build configuration
951 # This method will parse DSC file and merge the configurations from
952 # command line and target.txt, then get the final build configurations.
955 # parse target.txt, tools_def.txt, and platform file
956 self
.LoadConfiguration()
958 # Allow case-insensitive for those from command line or configuration file
959 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
961 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
964 def InitPreBuild(self
):
965 self
.LoadConfiguration()
966 ErrorCode
, ErrorInfo
= self
.PlatformFile
.Validate(".dsc", False)
968 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
969 if self
.BuildTargetList
:
970 GlobalData
.gGlobalDefines
['TARGET'] = self
.BuildTargetList
[0]
972 GlobalData
.gGlobalDefines
['ARCH'] = self
.ArchList
[0]
973 if self
.ToolChainList
:
974 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = self
.ToolChainList
[0]
975 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = self
.ToolChainList
[0]
976 if self
.ToolChainFamily
:
977 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[0]
978 if 'PREBUILD' in GlobalData
.gCommandLineDefines
:
979 self
.Prebuild
= GlobalData
.gCommandLineDefines
.get('PREBUILD')
982 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
983 self
.Prebuild
= str(Platform
.Prebuild
)
987 # Evaluate all arguments and convert arguments that are WORKSPACE
988 # relative paths to absolute paths. Filter arguments that look like
989 # flags or do not follow the file/dir naming rules to avoid false
990 # positives on this conversion.
992 for Arg
in self
.Prebuild
.split():
994 # Do not modify Arg if it looks like a flag or an absolute file path
996 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
997 PrebuildList
.append(Arg
)
1000 # Do not modify Arg if it does not look like a Workspace relative
1001 # path that starts with a valid package directory name
1003 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1004 PrebuildList
.append(Arg
)
1007 # If Arg looks like a WORKSPACE relative path, then convert to an
1008 # absolute path and check to see if the file exists.
1010 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1011 if os
.path
.isfile(Temp
):
1013 PrebuildList
.append(Arg
)
1014 self
.Prebuild
= ' '.join(PrebuildList
)
1015 self
.Prebuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1017 def InitPostBuild(self
):
1018 if 'POSTBUILD' in GlobalData
.gCommandLineDefines
:
1019 self
.Postbuild
= GlobalData
.gCommandLineDefines
.get('POSTBUILD')
1021 Platform
= self
.Db
.MapPlatform(str(self
.PlatformFile
))
1022 self
.Postbuild
= str(Platform
.Postbuild
)
1026 # Evaluate all arguments and convert arguments that are WORKSPACE
1027 # relative paths to absolute paths. Filter arguments that look like
1028 # flags or do not follow the file/dir naming rules to avoid false
1029 # positives on this conversion.
1031 for Arg
in self
.Postbuild
.split():
1033 # Do not modify Arg if it looks like a flag or an absolute file path
1035 if Arg
.startswith('-') or os
.path
.isabs(Arg
):
1036 PostbuildList
.append(Arg
)
1039 # Do not modify Arg if it does not look like a Workspace relative
1040 # path that starts with a valid package directory name
1042 if not Arg
[0].isalpha() or os
.path
.dirname(Arg
) == '':
1043 PostbuildList
.append(Arg
)
1046 # If Arg looks like a WORKSPACE relative path, then convert to an
1047 # absolute path and check to see if the file exists.
1049 Temp
= mws
.join(self
.WorkspaceDir
, Arg
)
1050 if os
.path
.isfile(Temp
):
1052 PostbuildList
.append(Arg
)
1053 self
.Postbuild
= ' '.join(PostbuildList
)
1054 self
.Postbuild
+= self
.PassCommandOption(self
.BuildTargetList
, self
.ArchList
, self
.ToolChainList
, self
.PlatformFile
, self
.Target
)
1056 def PassCommandOption(self
, BuildTarget
, TargetArch
, ToolChain
, PlatformFile
, Target
):
1058 if GlobalData
.gCommand
and isinstance(GlobalData
.gCommand
, list):
1059 BuildStr
+= ' ' + ' '.join(GlobalData
.gCommand
)
1062 ToolChainFlag
= False
1063 PlatformFileFlag
= False
1065 if GlobalData
.gOptions
and not GlobalData
.gOptions
.BuildTarget
:
1067 if GlobalData
.gOptions
and not GlobalData
.gOptions
.TargetArch
:
1069 if GlobalData
.gOptions
and not GlobalData
.gOptions
.ToolChain
:
1070 ToolChainFlag
= True
1071 if GlobalData
.gOptions
and not GlobalData
.gOptions
.PlatformFile
:
1072 PlatformFileFlag
= True
1074 if TargetFlag
and BuildTarget
:
1075 if isinstance(BuildTarget
, list) or isinstance(BuildTarget
, tuple):
1076 BuildStr
+= ' -b ' + ' -b '.join(BuildTarget
)
1077 elif isinstance(BuildTarget
, str):
1078 BuildStr
+= ' -b ' + BuildTarget
1079 if ArchFlag
and TargetArch
:
1080 if isinstance(TargetArch
, list) or isinstance(TargetArch
, tuple):
1081 BuildStr
+= ' -a ' + ' -a '.join(TargetArch
)
1082 elif isinstance(TargetArch
, str):
1083 BuildStr
+= ' -a ' + TargetArch
1084 if ToolChainFlag
and ToolChain
:
1085 if isinstance(ToolChain
, list) or isinstance(ToolChain
, tuple):
1086 BuildStr
+= ' -t ' + ' -t '.join(ToolChain
)
1087 elif isinstance(ToolChain
, str):
1088 BuildStr
+= ' -t ' + ToolChain
1089 if PlatformFileFlag
and PlatformFile
:
1090 if isinstance(PlatformFile
, list) or isinstance(PlatformFile
, tuple):
1091 BuildStr
+= ' -p ' + ' -p '.join(PlatformFile
)
1092 elif isinstance(PlatformFile
, str):
1093 BuildStr
+= ' -p' + PlatformFile
1094 BuildStr
+= ' --conf=' + GlobalData
.gConfDirectory
1096 BuildStr
+= ' ' + Target
1100 def LaunchPrebuild(self
):
1102 EdkLogger
.info("\n- Prebuild Start -\n")
1103 self
.LaunchPrebuildFlag
= True
1105 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1106 # and preserve them for the rest of the main build step, because the child process environment will
1107 # evaporate as soon as it exits, we cannot get it in build step.
1109 PrebuildEnvFile
= os
.path
.join(GlobalData
.gConfDirectory
, '.cache', '.PrebuildEnv')
1110 if os
.path
.isfile(PrebuildEnvFile
):
1111 os
.remove(PrebuildEnvFile
)
1112 if os
.path
.isfile(self
.PlatformBuildPath
):
1113 os
.remove(self
.PlatformBuildPath
)
1114 if sys
.platform
== "win32":
1115 args
= ' && '.join((self
.Prebuild
, 'set > ' + PrebuildEnvFile
))
1116 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1118 args
= ' && '.join((self
.Prebuild
, 'env > ' + PrebuildEnvFile
))
1119 Process
= Popen(args
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1121 # launch two threads to read the STDOUT and STDERR
1122 EndOfProcedure
= Event()
1123 EndOfProcedure
.clear()
1125 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1126 StdOutThread
.setName("STDOUT-Redirector")
1127 StdOutThread
.setDaemon(False)
1128 StdOutThread
.start()
1131 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1132 StdErrThread
.setName("STDERR-Redirector")
1133 StdErrThread
.setDaemon(False)
1134 StdErrThread
.start()
1135 # waiting for program exit
1142 if Process
.returncode
!= 0 :
1143 EdkLogger
.error("Prebuild", PREBUILD_ERROR
, 'Prebuild process is not success!')
1145 if os
.path
.exists(PrebuildEnvFile
):
1146 f
= open(PrebuildEnvFile
)
1147 envs
= f
.readlines()
1149 envs
= [l
.split("=", 1) for l
in envs
]
1150 envs
= [[I
.strip() for I
in item
] for item
in envs
if len(item
) == 2]
1151 os
.environ
.update(dict(envs
))
1152 EdkLogger
.info("\n- Prebuild Done -\n")
1154 def LaunchPostbuild(self
):
1156 EdkLogger
.info("\n- Postbuild Start -\n")
1157 if sys
.platform
== "win32":
1158 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1160 Process
= Popen(self
.Postbuild
, stdout
=PIPE
, stderr
=PIPE
, shell
=True)
1161 # launch two threads to read the STDOUT and STDERR
1162 EndOfProcedure
= Event()
1163 EndOfProcedure
.clear()
1165 StdOutThread
= Thread(target
=ReadMessage
, args
=(Process
.stdout
, EdkLogger
.info
, EndOfProcedure
))
1166 StdOutThread
.setName("STDOUT-Redirector")
1167 StdOutThread
.setDaemon(False)
1168 StdOutThread
.start()
1171 StdErrThread
= Thread(target
=ReadMessage
, args
=(Process
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
1172 StdErrThread
.setName("STDERR-Redirector")
1173 StdErrThread
.setDaemon(False)
1174 StdErrThread
.start()
1175 # waiting for program exit
1182 if Process
.returncode
!= 0 :
1183 EdkLogger
.error("Postbuild", POSTBUILD_ERROR
, 'Postbuild process is not success!')
1184 EdkLogger
.info("\n- Postbuild Done -\n")
1186 ## Build a module or platform
1188 # Create autogen code and makefile for a module or platform, and the launch
1189 # "make" command to build it
1191 # @param Target The target of build command
1192 # @param Platform The platform file
1193 # @param Module The module file
1194 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1195 # @param ToolChain The name of toolchain to build
1196 # @param Arch The arch of the module/platform
1197 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1198 # for dependent modules/Libraries
1199 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1200 # for dependent modules/Libraries
1202 def _BuildPa(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False, FfsCommand
=None, PcdMaList
=None):
1203 if AutoGenObject
is None:
1205 if FfsCommand
is None:
1207 # skip file generation for cleanxxx targets, run and fds target
1208 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1209 # for target which must generate AutoGen code and makefile
1211 for m
in AutoGenObject
.GetAllModuleInfo
:
1214 AutoGenObject
.DataPipe
.DataContainer
= {"CommandTarget": self
.Target
}
1215 AutoGenObject
.DataPipe
.DataContainer
= {"Workspace_timestamp": AutoGenObject
.Workspace
._SrcTimeStamp
}
1216 AutoGenObject
.CreateLibModuelDirs()
1217 AutoGenObject
.DataPipe
.DataContainer
= {"LibraryBuildDirectoryList":AutoGenObject
.LibraryBuildDirectoryList
}
1218 AutoGenObject
.DataPipe
.DataContainer
= {"ModuleBuildDirectoryList":AutoGenObject
.ModuleBuildDirectoryList
}
1219 AutoGenObject
.DataPipe
.DataContainer
= {"FdsCommandDict": AutoGenObject
.Workspace
.GenFdsCommandDict
}
1220 self
.Progress
.Start("Generating makefile and code")
1221 data_pipe_file
= os
.path
.join(AutoGenObject
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(AutoGenObject
.Guid
),AutoGenObject
.Arch
))
1222 AutoGenObject
.DataPipe
.dump(data_pipe_file
)
1224 autogen_rt
,errorcode
= self
.StartAutoGen(mqueue
, AutoGenObject
.DataPipe
, self
.SkipAutoGen
, PcdMaList
, cqueue
)
1225 AutoGenIdFile
= os
.path
.join(GlobalData
.gConfDirectory
,".AutoGenIdFile.txt")
1226 with
open(AutoGenIdFile
,"w") as fw
:
1227 fw
.write("Arch=%s\n" % "|".join((AutoGenObject
.Workspace
.ArchList
)))
1228 fw
.write("BuildDir=%s\n" % AutoGenObject
.Workspace
.BuildDir
)
1229 fw
.write("PlatformGuid=%s\n" % str(AutoGenObject
.Guid
))
1230 self
.Progress
.Stop("done!")
1232 self
.AutoGenMgr
.TerminateWorkers()
1233 self
.AutoGenMgr
.join(1)
1234 raise FatalError(errorcode
)
1235 AutoGenObject
.CreateCodeFile(False)
1236 AutoGenObject
.CreateMakeFile(False)
1238 # always recreate top/platform makefile when clean, just in case of inconsistency
1239 AutoGenObject
.CreateCodeFile(True)
1240 AutoGenObject
.CreateMakeFile(True)
1242 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1243 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1245 BuildCommand
= AutoGenObject
.BuildCommand
1246 if BuildCommand
is None or len(BuildCommand
) == 0:
1247 EdkLogger
.error("build", OPTION_MISSING
,
1248 "No build command found for this module. "
1249 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1250 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1251 ExtraData
=str(AutoGenObject
))
1253 makefile
= GenMake
.BuildFile(AutoGenObject
)._FILE
_NAME
_[GenMake
.gMakeType
]
1261 BuildCommand
= BuildCommand
+ [Target
]
1262 LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1263 self
.CreateAsBuiltInf()
1264 if GlobalData
.gBinCacheDest
:
1266 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
1268 # Update PreMakeCacheChain files
1269 self
.GenLocalPreMakeCache()
1270 self
.BuildModules
= []
1274 if Target
== 'libraries':
1276 for Lib
in AutoGenObject
.LibraryAutoGenList
:
1277 if not Lib
.IsBinaryModule
:
1278 DirList
.append((os
.path
.join(AutoGenObject
.BuildDir
, Lib
.BuildDir
),Lib
))
1279 for Lib
, LibAutoGen
in DirList
:
1280 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1281 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
,LibAutoGen
)
1285 if Target
== 'modules':
1287 for Lib
in AutoGenObject
.LibraryAutoGenList
:
1288 if not Lib
.IsBinaryModule
:
1289 DirList
.append((os
.path
.join(AutoGenObject
.BuildDir
, Lib
.BuildDir
),Lib
))
1290 for Lib
, LibAutoGen
in DirList
:
1291 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Lib
, makefile
)), 'pbuild']
1292 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
,LibAutoGen
)
1295 for ModuleAutoGen
in AutoGenObject
.ModuleAutoGenList
:
1296 if not ModuleAutoGen
.IsBinaryModule
:
1297 DirList
.append((os
.path
.join(AutoGenObject
.BuildDir
, ModuleAutoGen
.BuildDir
),ModuleAutoGen
))
1298 for Mod
,ModAutoGen
in DirList
:
1299 NewBuildCommand
= BuildCommand
+ ['-f', os
.path
.normpath(os
.path
.join(Mod
, makefile
)), 'pbuild']
1300 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
,ModAutoGen
)
1301 self
.CreateAsBuiltInf()
1302 if GlobalData
.gBinCacheDest
:
1304 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
1306 # Update PreMakeCacheChain files
1307 self
.GenLocalPreMakeCache()
1308 self
.BuildModules
= []
1312 if Target
== 'cleanlib':
1313 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1314 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1315 if os
.path
.exists(LibMakefile
):
1316 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1317 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1321 if Target
== 'clean':
1322 for Mod
in AutoGenObject
.ModuleBuildDirectoryList
:
1323 ModMakefile
= os
.path
.normpath(os
.path
.join(Mod
, makefile
))
1324 if os
.path
.exists(ModMakefile
):
1325 NewBuildCommand
= BuildCommand
+ ['-f', ModMakefile
, 'cleanall']
1326 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1327 for Lib
in AutoGenObject
.LibraryBuildDirectoryList
:
1328 LibMakefile
= os
.path
.normpath(os
.path
.join(Lib
, makefile
))
1329 if os
.path
.exists(LibMakefile
):
1330 NewBuildCommand
= BuildCommand
+ ['-f', LibMakefile
, 'cleanall']
1331 LaunchCommand(NewBuildCommand
, AutoGenObject
.MakeFileDir
)
1335 if Target
== 'cleanall':
1337 #os.rmdir(AutoGenObject.BuildDir)
1338 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1339 except WindowsError as X
:
1340 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1343 ## Build a module or platform
1345 # Create autogen code and makefile for a module or platform, and the launch
1346 # "make" command to build it
1348 # @param Target The target of build command
1349 # @param Platform The platform file
1350 # @param Module The module file
1351 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1352 # @param ToolChain The name of toolchain to build
1353 # @param Arch The arch of the module/platform
1354 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1355 # for dependent modules/Libraries
1356 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1357 # for dependent modules/Libraries
1359 def _Build(self
, Target
, AutoGenObject
, CreateDepsCodeFile
=True, CreateDepsMakeFile
=True, BuildModule
=False):
1360 if AutoGenObject
is None:
1363 # skip file generation for cleanxxx targets, run and fds target
1364 if Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1365 # for target which must generate AutoGen code and makefile
1366 if not self
.SkipAutoGen
or Target
== 'genc':
1367 self
.Progress
.Start("Generating code")
1368 AutoGenObject
.CreateCodeFile(CreateDepsCodeFile
)
1369 self
.Progress
.Stop("done!")
1370 if Target
== "genc":
1373 if not self
.SkipAutoGen
or Target
== 'genmake':
1374 self
.Progress
.Start("Generating makefile")
1375 AutoGenObject
.CreateMakeFile(CreateDepsMakeFile
)
1376 #AutoGenObject.CreateAsBuiltInf()
1377 self
.Progress
.Stop("done!")
1378 if Target
== "genmake":
1381 # always recreate top/platform makefile when clean, just in case of inconsistency
1382 AutoGenObject
.CreateCodeFile(True)
1383 AutoGenObject
.CreateMakeFile(True)
1385 if EdkLogger
.GetLevel() == EdkLogger
.QUIET
:
1386 EdkLogger
.quiet("Building ... %s" % repr(AutoGenObject
))
1388 BuildCommand
= AutoGenObject
.BuildCommand
1389 if BuildCommand
is None or len(BuildCommand
) == 0:
1390 EdkLogger
.error("build", OPTION_MISSING
,
1391 "No build command found for this module. "
1392 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1393 (AutoGenObject
.BuildTarget
, AutoGenObject
.ToolChain
, AutoGenObject
.Arch
),
1394 ExtraData
=str(AutoGenObject
))
1399 BuildCommand
= BuildCommand
+ [Target
]
1400 AutoGenObject
.BuildTime
= LaunchCommand(BuildCommand
, AutoGenObject
.MakeFileDir
)
1401 self
.CreateAsBuiltInf()
1402 if GlobalData
.gBinCacheDest
:
1404 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
1406 # Update PreMakeCacheChain files
1407 self
.GenLocalPreMakeCache()
1408 self
.BuildModules
= []
1413 if GenFdsApi(AutoGenObject
.GenFdsCommandDict
, self
.Db
):
1414 EdkLogger
.error("build", COMMAND_FAILURE
)
1422 if Target
== 'libraries':
1429 if Target
== 'cleanall':
1431 #os.rmdir(AutoGenObject.BuildDir)
1432 RemoveDirectory(AutoGenObject
.BuildDir
, True)
1433 except WindowsError as X
:
1434 EdkLogger
.error("build", FILE_DELETE_FAILURE
, ExtraData
=str(X
))
1437 ## Rebase module image and Get function address for the input module list.
1439 def _RebaseModule (self
, MapBuffer
, BaseAddress
, ModuleList
, AddrIsOffset
= True, ModeIsSmm
= False):
1441 AddrIsOffset
= False
1442 for InfFile
in ModuleList
:
1443 sys
.stdout
.write (".")
1445 ModuleInfo
= ModuleList
[InfFile
]
1446 ModuleName
= ModuleInfo
.BaseName
1447 ModuleOutputImage
= ModuleInfo
.Image
.FileName
1448 ModuleDebugImage
= os
.path
.join(ModuleInfo
.DebugDir
, ModuleInfo
.BaseName
+ '.efi')
1449 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1451 BaseAddress
= BaseAddress
- ModuleInfo
.Image
.Size
1453 # Update Image to new BaseAddress by GenFw tool
1455 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1456 LaunchCommand(["GenFw", "--rebase", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1459 # Set new address to the section header only for SMM driver.
1461 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleOutputImage
], ModuleInfo
.OutputDir
)
1462 LaunchCommand(["GenFw", "--address", str(BaseAddress
), "-r", ModuleDebugImage
], ModuleInfo
.DebugDir
)
1464 # Collect function address from Map file
1466 ImageMapTable
= ModuleOutputImage
.replace('.efi', '.map')
1468 if os
.path
.exists(ImageMapTable
):
1469 OrigImageBaseAddress
= 0
1470 ImageMap
= open(ImageMapTable
, 'r')
1471 for LinStr
in ImageMap
:
1472 if len (LinStr
.strip()) == 0:
1475 # Get the preferred address set on link time.
1477 if LinStr
.find ('Preferred load address is') != -1:
1478 StrList
= LinStr
.split()
1479 OrigImageBaseAddress
= int (StrList
[len(StrList
) - 1], 16)
1481 StrList
= LinStr
.split()
1482 if len (StrList
) > 4:
1483 if StrList
[3] == 'f' or StrList
[3] == 'F':
1485 RelativeAddress
= int (StrList
[2], 16) - OrigImageBaseAddress
1486 FunctionList
.append ((Name
, RelativeAddress
))
1490 # Add general information.
1493 MapBuffer
.append('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1495 MapBuffer
.append('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName
, 0 - BaseAddress
, 0 - (BaseAddress
+ ModuleInfo
.Image
.EntryPoint
)))
1497 MapBuffer
.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName
, BaseAddress
, BaseAddress
+ ModuleInfo
.Image
.EntryPoint
))
1499 # Add guid and general seciton section.
1501 TextSectionAddress
= 0
1502 DataSectionAddress
= 0
1503 for SectionHeader
in ModuleInfo
.Image
.SectionHeaderList
:
1504 if SectionHeader
[0] == '.text':
1505 TextSectionAddress
= SectionHeader
[1]
1506 elif SectionHeader
[0] in ['.data', '.sdata']:
1507 DataSectionAddress
= SectionHeader
[1]
1509 MapBuffer
.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo
.Guid
, 0 - (BaseAddress
+ TextSectionAddress
), 0 - (BaseAddress
+ DataSectionAddress
)))
1511 MapBuffer
.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo
.Guid
, BaseAddress
+ TextSectionAddress
, BaseAddress
+ DataSectionAddress
))
1513 # Add debug image full path.
1515 MapBuffer
.append('(IMAGE=%s)\n\n' % (ModuleDebugImage
))
1517 # Add function address
1519 for Function
in FunctionList
:
1521 MapBuffer
.append(' -0x%010X %s\n' % (0 - (BaseAddress
+ Function
[1]), Function
[0]))
1523 MapBuffer
.append(' 0x%010X %s\n' % (BaseAddress
+ Function
[1], Function
[0]))
1527 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1530 BaseAddress
= BaseAddress
+ ModuleInfo
.Image
.Size
1532 ## Collect MAP information of all FVs
1534 def _CollectFvMapBuffer (self
, MapBuffer
, Wa
, ModuleList
):
1536 # First get the XIP base address for FV map file.
1537 GuidPattern
= re
.compile("[-a-fA-F0-9]+")
1538 GuidName
= re
.compile(r
"\(GUID=[-a-fA-F0-9]+")
1539 for FvName
in Wa
.FdfProfile
.FvDict
:
1540 FvMapBuffer
= os
.path
.join(Wa
.FvDir
, FvName
+ '.Fv.map')
1541 if not os
.path
.exists(FvMapBuffer
):
1543 FvMap
= open(FvMapBuffer
, 'r')
1544 #skip FV size information
1550 MatchGuid
= GuidPattern
.match(Line
)
1551 if MatchGuid
is not None:
1553 # Replace GUID with module name
1555 GuidString
= MatchGuid
.group()
1556 if GuidString
.upper() in ModuleList
:
1557 Line
= Line
.replace(GuidString
, ModuleList
[GuidString
.upper()].Name
)
1558 MapBuffer
.append(Line
)
1560 # Add the debug image full path.
1562 MatchGuid
= GuidName
.match(Line
)
1563 if MatchGuid
is not None:
1564 GuidString
= MatchGuid
.group().split("=")[1]
1565 if GuidString
.upper() in ModuleList
:
1566 MapBuffer
.append('(IMAGE=%s)\n' % (os
.path
.join(ModuleList
[GuidString
.upper()].DebugDir
, ModuleList
[GuidString
.upper()].Name
+ '.efi')))
1570 ## Collect MAP information of all modules
1572 def _CollectModuleMapBuffer (self
, MapBuffer
, ModuleList
):
1573 sys
.stdout
.write ("Generate Load Module At Fix Address Map")
1575 PatchEfiImageList
= []
1583 # reserve 4K size in SMRAM to make SMM module address not from 0.
1585 for ModuleGuid
in ModuleList
:
1586 Module
= ModuleList
[ModuleGuid
]
1587 GlobalData
.gProcessingFile
= "%s [%s, %s, %s]" % (Module
.MetaFile
, Module
.Arch
, Module
.ToolChain
, Module
.BuildTarget
)
1589 OutputImageFile
= ''
1590 for ResultFile
in Module
.CodaTargetList
:
1591 if str(ResultFile
.Target
).endswith('.efi'):
1593 # module list for PEI, DXE, RUNTIME and SMM
1595 OutputImageFile
= os
.path
.join(Module
.OutputDir
, Module
.Name
+ '.efi')
1596 ImageClass
= PeImageClass (OutputImageFile
)
1597 if not ImageClass
.IsValid
:
1598 EdkLogger
.error("build", FILE_PARSE_FAILURE
, ExtraData
=ImageClass
.ErrorInfo
)
1599 ImageInfo
= PeImageInfo(Module
.Name
, Module
.Guid
, Module
.Arch
, Module
.OutputDir
, Module
.DebugDir
, ImageClass
)
1600 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
]:
1601 PeiModuleList
[Module
.MetaFile
] = ImageInfo
1602 PeiSize
+= ImageInfo
.Image
.Size
1603 elif Module
.ModuleType
in [EDK_COMPONENT_TYPE_BS_DRIVER
, SUP_MODULE_DXE_DRIVER
, SUP_MODULE_UEFI_DRIVER
]:
1604 BtModuleList
[Module
.MetaFile
] = ImageInfo
1605 BtSize
+= ImageInfo
.Image
.Size
1606 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
]:
1607 RtModuleList
[Module
.MetaFile
] = ImageInfo
1608 RtSize
+= ImageInfo
.Image
.Size
1609 elif Module
.ModuleType
in [SUP_MODULE_SMM_CORE
, SUP_MODULE_DXE_SMM_DRIVER
, SUP_MODULE_MM_STANDALONE
, SUP_MODULE_MM_CORE_STANDALONE
]:
1610 SmmModuleList
[Module
.MetaFile
] = ImageInfo
1611 SmmSize
+= ImageInfo
.Image
.Size
1612 if Module
.ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
1613 PiSpecVersion
= Module
.Module
.Specification
.get('PI_SPECIFICATION_VERSION', '0x00000000')
1614 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1615 if int(PiSpecVersion
, 16) < 0x0001000A:
1616 BtModuleList
[Module
.MetaFile
] = ImageInfo
1617 BtSize
+= ImageInfo
.Image
.Size
1620 # EFI image is final target.
1621 # Check EFI image contains patchable FixAddress related PCDs.
1623 if OutputImageFile
!= '':
1624 ModuleIsPatch
= False
1625 for Pcd
in Module
.ModulePcdList
:
1626 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1627 ModuleIsPatch
= True
1629 if not ModuleIsPatch
:
1630 for Pcd
in Module
.LibraryPcdList
:
1631 if Pcd
.Type
== TAB_PCDS_PATCHABLE_IN_MODULE
and Pcd
.TokenCName
in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET
:
1632 ModuleIsPatch
= True
1635 if not ModuleIsPatch
:
1638 # Module includes the patchable load fix address PCDs.
1639 # It will be fixed up later.
1641 PatchEfiImageList
.append (OutputImageFile
)
1644 # Get Top Memory address
1646 ReservedRuntimeMemorySize
= 0
1647 TopMemoryAddress
= 0
1648 if self
.LoadFixAddress
== 0xFFFFFFFFFFFFFFFF:
1649 TopMemoryAddress
= 0
1651 TopMemoryAddress
= self
.LoadFixAddress
1652 if TopMemoryAddress
< RtSize
+ BtSize
+ PeiSize
:
1653 EdkLogger
.error("build", PARAMETER_INVALID
, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1656 # Patch FixAddress related PCDs into EFI image
1658 for EfiImage
in PatchEfiImageList
:
1659 EfiImageMap
= EfiImage
.replace('.efi', '.map')
1660 if not os
.path
.exists(EfiImageMap
):
1663 # Get PCD offset in EFI image by GenPatchPcdTable function
1665 PcdTable
= parsePcdInfoFromMapFile(EfiImageMap
, EfiImage
)
1667 # Patch real PCD value by PatchPcdValue tool
1669 for PcdInfo
in PcdTable
:
1671 if PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE
:
1672 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE
, str (PeiSize
// 0x1000))
1673 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE
:
1674 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE
, str (BtSize
// 0x1000))
1675 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE
:
1676 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE
, str (RtSize
// 0x1000))
1677 elif PcdInfo
[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE
and len (SmmModuleList
) > 0:
1678 ReturnValue
, ErrorInfo
= PatchBinaryFile (EfiImage
, PcdInfo
[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE
, str (SmmSize
// 0x1000))
1679 if ReturnValue
!= 0:
1680 EdkLogger
.error("build", PARAMETER_INVALID
, "Patch PCD value failed", ExtraData
=ErrorInfo
)
1682 MapBuffer
.append('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize
// 0x1000))
1683 MapBuffer
.append('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize
// 0x1000))
1684 MapBuffer
.append('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize
// 0x1000))
1685 if len (SmmModuleList
) > 0:
1686 MapBuffer
.append('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize
// 0x1000))
1688 PeiBaseAddr
= TopMemoryAddress
- RtSize
- BtSize
1689 BtBaseAddr
= TopMemoryAddress
- RtSize
1690 RtBaseAddr
= TopMemoryAddress
- ReservedRuntimeMemorySize
1692 self
._RebaseModule
(MapBuffer
, PeiBaseAddr
, PeiModuleList
, TopMemoryAddress
== 0)
1693 self
._RebaseModule
(MapBuffer
, BtBaseAddr
, BtModuleList
, TopMemoryAddress
== 0)
1694 self
._RebaseModule
(MapBuffer
, RtBaseAddr
, RtModuleList
, TopMemoryAddress
== 0)
1695 self
._RebaseModule
(MapBuffer
, 0x1000, SmmModuleList
, AddrIsOffset
=False, ModeIsSmm
=True)
1696 MapBuffer
.append('\n\n')
1697 sys
.stdout
.write ("\n")
1700 ## Save platform Map file
1702 def _SaveMapFile (self
, MapBuffer
, Wa
):
1704 # Map file path is got.
1706 MapFilePath
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ '.map')
1708 # Save address map into MAP file.
1710 SaveFileOnChange(MapFilePath
, ''.join(MapBuffer
), False)
1711 if self
.LoadFixAddress
!= 0:
1712 sys
.stdout
.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath
))
1715 ## Build active platform for different build targets and different tool chains
1717 def _BuildPlatform(self
):
1718 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1719 for BuildTarget
in self
.BuildTargetList
:
1720 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1722 for ToolChain
in self
.ToolChainList
:
1723 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1724 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1725 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1727 Wa
= WorkspaceAutoGen(
1744 self
.Fdf
= Wa
.FdfFile
1745 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1746 self
.BuildReport
.AddPlatformReport(Wa
)
1747 self
.Progress
.Stop("done!")
1749 # Add ffs build to makefile
1751 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1752 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1754 for Arch
in Wa
.ArchList
:
1756 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1757 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1758 for Module
in Pa
.Platform
.Modules
:
1759 # Get ModuleAutoGen object to generate C code file and makefile
1760 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1764 Ma
.PlatformInfo
= Pa
1766 PcdMaList
.append(Ma
)
1767 self
.BuildModules
.append(Ma
)
1768 Pa
.DataPipe
.DataContainer
= {"FfsCommand":CmdListDict
}
1769 Pa
.DataPipe
.DataContainer
= {"Workspace_timestamp": Wa
._SrcTimeStamp
}
1770 self
._BuildPa
(self
.Target
, Pa
, FfsCommand
=CmdListDict
,PcdMaList
=PcdMaList
)
1772 # Create MAP file when Load Fix Address is enabled.
1773 if self
.Target
in ["", "all", "fds"]:
1774 for Arch
in Wa
.ArchList
:
1775 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1777 # Check whether the set fix address is above 4G for 32bit image.
1779 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1780 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")
1785 for Pa
in Wa
.AutoGenObjectList
:
1786 for Ma
in Pa
.ModuleAutoGenList
:
1789 if not Ma
.IsLibrary
:
1790 ModuleList
[Ma
.Guid
.upper()] = Ma
1793 if self
.LoadFixAddress
!= 0:
1795 # Rebase module to the preferred memory address before GenFds
1797 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1800 # create FDS again for the updated EFI image
1802 self
._Build
("fds", Wa
)
1804 # Create MAP file for all platform FVs after GenFds.
1806 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1808 # Save MAP buffer into MAP file.
1810 self
._SaveMapFile
(MapBuffer
, Wa
)
1811 self
.CreateGuidedSectionToolsFile(Wa
)
1813 ## Build active module for different build targets, different tool chains and different archs
1815 def _BuildModule(self
):
1816 for BuildTarget
in self
.BuildTargetList
:
1817 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
1819 for ToolChain
in self
.ToolChainList
:
1820 WorkspaceAutoGenTime
= time
.time()
1821 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
1822 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
1823 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
1826 # module build needs platform build information, so get platform
1829 Wa
= WorkspaceAutoGen(
1847 self
.Fdf
= Wa
.FdfFile
1848 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
1849 Wa
.CreateMakeFile(False)
1850 # Add ffs build to makefile
1852 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
1853 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
1855 GlobalData
.file_lock
= mp
.Lock()
1856 GlobalData
.FfsCmd
= CmdListDict
1858 self
.Progress
.Stop("done!")
1860 ExitFlag
= threading
.Event()
1862 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
1863 for Arch
in Wa
.ArchList
:
1864 AutoGenStart
= time
.time()
1865 GlobalData
.gGlobalDefines
['ARCH'] = Arch
1866 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
1867 for Module
in Pa
.Platform
.Modules
:
1868 if self
.ModuleFile
.Dir
== Module
.Dir
and self
.ModuleFile
.Name
== Module
.Name
:
1869 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
1873 Ma
.PlatformInfo
= Pa
1877 if GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheDest
and self
.Target
in [None, "", "all"]:
1878 if Ma
.CanSkipbyPreMakeCache():
1881 self
.PreMakeCacheMiss
.add(Ma
)
1883 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1884 if self
.Target
not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1885 # for target which must generate AutoGen code and makefile
1886 if not self
.SkipAutoGen
or self
.Target
== 'genc':
1887 self
.Progress
.Start("Generating code")
1888 Ma
.CreateCodeFile(True)
1889 self
.Progress
.Stop("done!")
1890 if self
.Target
== "genc":
1892 if not self
.SkipAutoGen
or self
.Target
== 'genmake':
1893 self
.Progress
.Start("Generating makefile")
1894 if CmdListDict
and self
.Fdf
and (Module
.Path
, Arch
) in CmdListDict
:
1895 Ma
.CreateMakeFile(True, CmdListDict
[Module
.Path
, Arch
])
1896 del CmdListDict
[Module
.Path
, Arch
]
1898 Ma
.CreateMakeFile(True)
1899 self
.Progress
.Stop("done!")
1900 if self
.Target
== "genmake":
1903 if GlobalData
.gBinCacheSource
and self
.Target
in [None, "", "all"]:
1904 if Ma
.CanSkipbyMakeCache():
1907 self
.MakeCacheMiss
.add(Ma
)
1909 self
.BuildModules
.append(Ma
)
1910 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
1911 MakeStart
= time
.time()
1912 for Ma
in self
.BuildModules
:
1913 if not Ma
.IsBinaryModule
:
1914 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
1915 # Break build if any build thread has error
1916 if BuildTask
.HasError():
1917 # we need a full version of makefile for platform
1919 BuildTask
.WaitForComplete()
1920 Pa
.CreateMakeFile(False)
1921 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1922 # Start task scheduler
1923 if not BuildTask
.IsOnGoing():
1924 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
1926 # in case there's an interruption. we need a full version of makefile for platform
1927 Pa
.CreateMakeFile(False)
1928 if BuildTask
.HasError():
1929 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1930 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
1932 MakeContiue
= time
.time()
1934 BuildTask
.WaitForComplete()
1935 self
.CreateAsBuiltInf()
1936 if GlobalData
.gBinCacheDest
:
1938 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
1940 # Update PreMakeCacheChain files
1941 self
.GenLocalPreMakeCache()
1942 self
.BuildModules
= []
1943 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
1944 if BuildTask
.HasError():
1945 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
1947 self
.BuildReport
.AddPlatformReport(Wa
, MaList
)
1952 "Module for [%s] is not a component of active platform."\
1953 " Please make sure that the ARCH and inf file path are"\
1954 " given in the same as in [%s]" % \
1955 (', '.join(Wa
.ArchList
), self
.PlatformFile
),
1956 ExtraData
=self
.ModuleFile
1958 # Create MAP file when Load Fix Address is enabled.
1959 if self
.Target
== "fds" and self
.Fdf
:
1960 for Arch
in Wa
.ArchList
:
1962 # Check whether the set fix address is above 4G for 32bit image.
1964 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
1965 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")
1970 for Pa
in Wa
.AutoGenObjectList
:
1971 for Ma
in Pa
.ModuleAutoGenList
:
1974 if not Ma
.IsLibrary
:
1975 ModuleList
[Ma
.Guid
.upper()] = Ma
1978 if self
.LoadFixAddress
!= 0:
1980 # Rebase module to the preferred memory address before GenFds
1982 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
1984 # create FDS again for the updated EFI image
1986 GenFdsStart
= time
.time()
1987 self
._Build
("fds", Wa
)
1988 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
1990 # Create MAP file for all platform FVs after GenFds.
1992 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
1994 # Save MAP buffer into MAP file.
1996 self
._SaveMapFile
(MapBuffer
, Wa
)
1998 def _GenFfsCmd(self
,ArchList
):
1999 # convert dictionary of Cmd:(Inf,Arch)
2000 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
2001 CmdSetDict
= defaultdict(set)
2002 GenFfsDict
= GenFds
.GenFfsMakefile('', GlobalData
.gFdfParser
, self
, ArchList
, GlobalData
)
2003 for Cmd
in GenFfsDict
:
2004 tmpInf
, tmpArch
= GenFfsDict
[Cmd
]
2005 CmdSetDict
[tmpInf
, tmpArch
].add(Cmd
)
2007 def VerifyAutoGenFiles(self
):
2008 AutoGenIdFile
= os
.path
.join(GlobalData
.gConfDirectory
,".AutoGenIdFile.txt")
2010 with
open(AutoGenIdFile
) as fd
:
2011 lines
= fd
.readlines()
2016 ArchList
= line
.strip().split("=")[1].split("|")
2017 if "BuildDir" in line
:
2018 BuildDir
= line
.split("=")[1].strip()
2019 if "PlatformGuid" in line
:
2020 PlatformGuid
= line
.split("=")[1].strip()
2022 for arch
in ArchList
:
2023 global_var
= os
.path
.join(BuildDir
, "GlobalVar_%s_%s.bin" % (str(PlatformGuid
),arch
))
2024 if not os
.path
.exists(global_var
):
2026 GlobalVarList
.append(global_var
)
2027 for global_var
in GlobalVarList
:
2028 data_pipe
= MemoryDataPipe()
2029 data_pipe
.load(global_var
)
2030 target
= data_pipe
.Get("P_Info").get("Target")
2031 toolchain
= data_pipe
.Get("P_Info").get("ToolChain")
2032 archlist
= data_pipe
.Get("P_Info").get("ArchList")
2033 Arch
= data_pipe
.Get("P_Info").get("Arch")
2034 active_p
= data_pipe
.Get("P_Info").get("ActivePlatform")
2035 workspacedir
= data_pipe
.Get("P_Info").get("WorkspaceDir")
2036 PackagesPath
= os
.getenv("PACKAGES_PATH")
2037 mws
.setWs(workspacedir
, PackagesPath
)
2038 LibraryBuildDirectoryList
= data_pipe
.Get("LibraryBuildDirectoryList")
2039 ModuleBuildDirectoryList
= data_pipe
.Get("ModuleBuildDirectoryList")
2041 for m_build_dir
in LibraryBuildDirectoryList
:
2042 if not os
.path
.exists(os
.path
.join(m_build_dir
,GenMake
.BuildFile
._FILE
_NAME
_[GenMake
.gMakeType
])):
2044 for m_build_dir
in ModuleBuildDirectoryList
:
2045 if not os
.path
.exists(os
.path
.join(m_build_dir
,GenMake
.BuildFile
._FILE
_NAME
_[GenMake
.gMakeType
])):
2048 workspacedir
,active_p
,target
,toolchain
,archlist
2050 Pa
= PlatformInfo(Wa
, active_p
, target
, toolchain
, Arch
,data_pipe
)
2051 Wa
.AutoGenObjectList
.append(Pa
)
2053 def SetupMakeSetting(self
,Wa
):
2055 for Pa
in Wa
.AutoGenObjectList
:
2056 for m
in Pa
._MbList
:
2057 ma
= ModuleAutoGen(Wa
,m
.MetaFile
, Pa
.BuildTarget
, Wa
.ToolChain
, Pa
.Arch
, Pa
.MetaFile
,Pa
.DataPipe
)
2058 BuildModules
.append(ma
)
2059 fdf_file
= Wa
.FlashDefinition
2061 Fdf
= FdfParser(fdf_file
.Path
)
2063 GlobalData
.gFdfParser
= Fdf
2064 if Fdf
.CurrentFdName
and Fdf
.CurrentFdName
in Fdf
.Profile
.FdDict
:
2065 FdDict
= Fdf
.Profile
.FdDict
[Fdf
.CurrentFdName
]
2066 for FdRegion
in FdDict
.RegionList
:
2067 if str(FdRegion
.RegionType
) == 'FILE' and self
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
2068 if int(FdRegion
.Offset
) % 8 != 0:
2069 EdkLogger
.error("build", FORMAT_INVALID
, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion
.Offset
))
2070 Wa
.FdfProfile
= Fdf
.Profile
2076 ## Build a platform in multi-thread mode
2078 def PerformAutoGen(self
,BuildTarget
,ToolChain
):
2079 WorkspaceAutoGenTime
= time
.time()
2080 Wa
= WorkspaceAutoGen(
2097 self
.Fdf
= Wa
.FdfFile
2098 self
.LoadFixAddress
= Wa
.Platform
.LoadFixAddress
2099 self
.BuildReport
.AddPlatformReport(Wa
)
2100 Wa
.CreateMakeFile(False)
2102 # Add ffs build to makefile
2104 if GlobalData
.gEnableGenfdsMultiThread
and self
.Fdf
:
2105 CmdListDict
= self
._GenFfsCmd
(Wa
.ArchList
)
2107 self
.AutoGenTime
+= int(round((time
.time() - WorkspaceAutoGenTime
)))
2109 for Arch
in Wa
.ArchList
:
2111 AutoGenStart
= time
.time()
2112 GlobalData
.gGlobalDefines
['ARCH'] = Arch
2113 Pa
= PlatformAutoGen(Wa
, self
.PlatformFile
, BuildTarget
, ToolChain
, Arch
)
2117 for Inf
in Pa
.Platform
.Modules
:
2118 ModuleList
.append(Inf
)
2119 # Add the INF only list in FDF
2120 if GlobalData
.gFdfParser
is not None:
2121 for InfName
in GlobalData
.gFdfParser
.Profile
.InfList
:
2122 Inf
= PathClass(NormPath(InfName
), self
.WorkspaceDir
, Arch
)
2123 if Inf
in Pa
.Platform
.Modules
:
2125 ModuleList
.append(Inf
)
2126 Pa
.DataPipe
.DataContainer
= {"FfsCommand":CmdListDict
}
2127 Pa
.DataPipe
.DataContainer
= {"Workspace_timestamp": Wa
._SrcTimeStamp
}
2128 Pa
.DataPipe
.DataContainer
= {"CommandTarget": self
.Target
}
2129 Pa
.CreateLibModuelDirs()
2130 Pa
.DataPipe
.DataContainer
= {"LibraryBuildDirectoryList":Pa
.LibraryBuildDirectoryList
}
2131 Pa
.DataPipe
.DataContainer
= {"ModuleBuildDirectoryList":Pa
.ModuleBuildDirectoryList
}
2132 Pa
.DataPipe
.DataContainer
= {"FdsCommandDict": Wa
.GenFdsCommandDict
}
2133 # Prepare the cache share data for multiprocessing
2134 Pa
.DataPipe
.DataContainer
= {"gPlatformHashFile":GlobalData
.gPlatformHashFile
}
2136 for ma
in Pa
.ModuleAutoGenList
:
2137 ModuleCodaFile
[(ma
.MetaFile
.File
,ma
.MetaFile
.Root
,ma
.Arch
,ma
.MetaFile
.Path
)] = [item
.Target
for item
in ma
.CodaTargetList
]
2138 Pa
.DataPipe
.DataContainer
= {"ModuleCodaFile":ModuleCodaFile
}
2139 # ModuleList contains all driver modules only
2140 for Module
in ModuleList
:
2141 # Get ModuleAutoGen object to generate C code file and makefile
2142 Ma
= ModuleAutoGen(Wa
, Module
, BuildTarget
, ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2146 Ma
.PlatformInfo
= Pa
2148 PcdMaList
.append(Ma
)
2149 self
.AllDrivers
.add(Ma
)
2150 self
.AllModules
.add(Ma
)
2154 for m
in Pa
.GetAllModuleInfo
:
2156 module_file
,module_root
,module_path
,module_basename
,\
2157 module_originalpath
,module_arch
,IsLib
= m
2158 Ma
= ModuleAutoGen(Wa
, PathClass(module_path
, Wa
), BuildTarget
,\
2159 ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2160 self
.AllModules
.add(Ma
)
2161 data_pipe_file
= os
.path
.join(Pa
.BuildDir
, "GlobalVar_%s_%s.bin" % (str(Pa
.Guid
),Pa
.Arch
))
2162 Pa
.DataPipe
.dump(data_pipe_file
)
2164 autogen_rt
, errorcode
= self
.StartAutoGen(mqueue
, Pa
.DataPipe
, self
.SkipAutoGen
, PcdMaList
, cqueue
)
2167 self
.AutoGenMgr
.TerminateWorkers()
2168 self
.AutoGenMgr
.join(1)
2169 raise FatalError(errorcode
)
2171 if GlobalData
.gUseHashCache
:
2172 for item
in GlobalData
.gModuleAllCacheStatus
:
2173 (MetaFilePath
, Arch
, CacheStr
, Status
) = item
2174 Ma
= ModuleAutoGen(Wa
, PathClass(MetaFilePath
, Wa
), BuildTarget
,\
2175 ToolChain
, Arch
, self
.PlatformFile
,Pa
.DataPipe
)
2176 if CacheStr
== "PreMakeCache" and Status
== False:
2177 self
.PreMakeCacheMiss
.add(Ma
)
2178 if CacheStr
== "PreMakeCache" and Status
== True:
2179 self
.PreMakeCacheHit
.add(Ma
)
2180 GlobalData
.gModuleCacheHit
.add(Ma
)
2181 if CacheStr
== "MakeCache" and Status
== False:
2182 self
.MakeCacheMiss
.add(Ma
)
2183 if CacheStr
== "MakeCache" and Status
== True:
2184 self
.MakeCacheHit
.add(Ma
)
2185 GlobalData
.gModuleCacheHit
.add(Ma
)
2186 self
.AutoGenTime
+= int(round((time
.time() - AutoGenStart
)))
2187 AutoGenIdFile
= os
.path
.join(GlobalData
.gConfDirectory
,".AutoGenIdFile.txt")
2188 with
open(AutoGenIdFile
,"w") as fw
:
2189 fw
.write("Arch=%s\n" % "|".join((Wa
.ArchList
)))
2190 fw
.write("BuildDir=%s\n" % Wa
.BuildDir
)
2191 fw
.write("PlatformGuid=%s\n" % str(Wa
.AutoGenObjectList
[0].Guid
))
2193 if GlobalData
.gBinCacheSource
:
2194 BuildModules
.extend(self
.MakeCacheMiss
)
2195 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheDest
:
2196 BuildModules
.extend(self
.PreMakeCacheMiss
)
2198 BuildModules
.extend(self
.AllDrivers
)
2200 self
.Progress
.Stop("done!")
2201 return Wa
, BuildModules
2203 def _MultiThreadBuildPlatform(self
):
2204 SaveFileOnChange(self
.PlatformBuildPath
, '# DO NOT EDIT \n# FILE auto-generated\n', False)
2205 for BuildTarget
in self
.BuildTargetList
:
2206 GlobalData
.gGlobalDefines
['TARGET'] = BuildTarget
2208 for ToolChain
in self
.ToolChainList
:
2209 resetFdsGlobalVariable()
2210 GlobalData
.gGlobalDefines
['TOOLCHAIN'] = ToolChain
2211 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = ToolChain
2212 GlobalData
.gGlobalDefines
['FAMILY'] = self
.ToolChainFamily
[index
]
2214 ExitFlag
= threading
.Event()
2216 if self
.SkipAutoGen
:
2217 Wa
= self
.VerifyAutoGenFiles()
2219 self
.SkipAutoGen
= False
2220 Wa
, self
.BuildModules
= self
.PerformAutoGen(BuildTarget
,ToolChain
)
2222 GlobalData
.gAutoGenPhase
= True
2223 self
.BuildModules
= self
.SetupMakeSetting(Wa
)
2225 Wa
, self
.BuildModules
= self
.PerformAutoGen(BuildTarget
,ToolChain
)
2226 Pa
= Wa
.AutoGenObjectList
[0]
2227 GlobalData
.gAutoGenPhase
= False
2229 if GlobalData
.gBinCacheSource
:
2230 EdkLogger
.quiet("[cache Summary]: Total module num: %s" % len(self
.AllModules
))
2231 EdkLogger
.quiet("[cache Summary]: PreMakecache miss num: %s " % len(self
.PreMakeCacheMiss
))
2232 EdkLogger
.quiet("[cache Summary]: Makecache miss num: %s " % len(self
.MakeCacheMiss
))
2234 for Arch
in Wa
.ArchList
:
2235 MakeStart
= time
.time()
2236 for Ma
in set(self
.BuildModules
):
2237 # Generate build task for the module
2238 if not Ma
.IsBinaryModule
:
2239 Bt
= BuildTask
.New(ModuleMakeUnit(Ma
, Pa
.BuildCommand
,self
.Target
))
2240 # Break build if any build thread has error
2241 if BuildTask
.HasError():
2242 # we need a full version of makefile for platform
2244 BuildTask
.WaitForComplete()
2245 Pa
.CreateMakeFile(False)
2246 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2247 # Start task scheduler
2248 if not BuildTask
.IsOnGoing():
2249 BuildTask
.StartScheduler(self
.ThreadNumber
, ExitFlag
)
2251 # in case there's an interruption. we need a full version of makefile for platform
2253 if BuildTask
.HasError():
2254 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2255 self
.MakeTime
+= int(round((time
.time() - MakeStart
)))
2257 MakeContiue
= time
.time()
2260 # All modules have been put in build tasks queue. Tell task scheduler
2261 # to exit if all tasks are completed
2264 BuildTask
.WaitForComplete()
2265 self
.CreateAsBuiltInf()
2266 if GlobalData
.gBinCacheDest
:
2268 elif GlobalData
.gUseHashCache
and not GlobalData
.gBinCacheSource
:
2270 # Update PreMakeCacheChain files
2271 self
.GenLocalPreMakeCache()
2275 ModuleList
= {ma
.Guid
.upper(): ma
for ma
in self
.BuildModules
}
2276 self
.BuildModules
= []
2277 self
.MakeTime
+= int(round((time
.time() - MakeContiue
)))
2279 # Check for build error, and raise exception if one
2280 # has been signaled.
2282 if BuildTask
.HasError():
2283 EdkLogger
.error("build", BUILD_ERROR
, "Failed to build module", ExtraData
=GlobalData
.gBuildingModule
)
2285 # Create MAP file when Load Fix Address is enabled.
2286 if self
.Target
in ["", "all", "fds"]:
2287 for Arch
in Wa
.ArchList
:
2289 # Check whether the set fix address is above 4G for 32bit image.
2291 if (Arch
== 'IA32' or Arch
== 'ARM') and self
.LoadFixAddress
!= 0xFFFFFFFFFFFFFFFF and self
.LoadFixAddress
>= 0x100000000:
2292 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")
2295 # Rebase module to the preferred memory address before GenFds
2298 if self
.LoadFixAddress
!= 0:
2299 self
._CollectModuleMapBuffer
(MapBuffer
, ModuleList
)
2303 # Generate FD image if there's a FDF file found
2305 GenFdsStart
= time
.time()
2306 if GenFdsApi(Wa
.GenFdsCommandDict
, self
.Db
):
2307 EdkLogger
.error("build", COMMAND_FAILURE
)
2310 # Create MAP file for all platform FVs after GenFds.
2312 self
._CollectFvMapBuffer
(MapBuffer
, Wa
, ModuleList
)
2313 self
.GenFdsTime
+= int(round((time
.time() - GenFdsStart
)))
2315 # Save MAP buffer into MAP file.
2317 self
._SaveMapFile
(MapBuffer
, Wa
)
2318 self
.CreateGuidedSectionToolsFile(Wa
)
2319 ## Generate GuidedSectionTools.txt in the FV directories.
2321 def CreateGuidedSectionToolsFile(self
,Wa
):
2322 for BuildTarget
in self
.BuildTargetList
:
2323 for ToolChain
in self
.ToolChainList
:
2325 if not os
.path
.exists(FvDir
):
2328 for Arch
in self
.ArchList
:
2329 # Build up the list of supported architectures for this build
2330 prefix
= '%s_%s_%s_' % (BuildTarget
, ToolChain
, Arch
)
2332 # Look through the tool definitions for GUIDed tools
2334 for (attrib
, value
) in self
.ToolDef
.ToolsDefTxtDictionary
.items():
2335 if attrib
.upper().endswith('_GUID'):
2336 split
= attrib
.split('_')
2337 thisPrefix
= '_'.join(split
[0:3]) + '_'
2338 if thisPrefix
== prefix
:
2339 guid
= self
.ToolDef
.ToolsDefTxtDictionary
[attrib
]
2342 path
= '_'.join(split
[0:4]) + '_PATH'
2343 path
= self
.ToolDef
.ToolsDefTxtDictionary
[path
]
2344 path
= self
.GetFullPathOfTool(path
)
2345 guidAttribs
.append((guid
, toolName
, path
))
2347 # Write out GuidedSecTools.txt
2348 toolsFile
= os
.path
.join(FvDir
, 'GuidedSectionTools.txt')
2349 toolsFile
= open(toolsFile
, 'wt')
2350 for guidedSectionTool
in guidAttribs
:
2351 print(' '.join(guidedSectionTool
), file=toolsFile
)
2354 ## Returns the full path of the tool.
2356 def GetFullPathOfTool (self
, tool
):
2357 if os
.path
.exists(tool
):
2358 return os
.path
.realpath(tool
)
2360 # We need to search for the tool using the
2361 # PATH environment variable.
2362 for dirInPath
in os
.environ
['PATH'].split(os
.pathsep
):
2363 foundPath
= os
.path
.join(dirInPath
, tool
)
2364 if os
.path
.exists(foundPath
):
2365 return os
.path
.realpath(foundPath
)
2367 # If the tool was not found in the path then we just return
2371 ## Launch the module or platform build
2374 self
.AllDrivers
= set()
2375 self
.AllModules
= set()
2376 self
.PreMakeCacheMiss
= set()
2377 self
.PreMakeCacheHit
= set()
2378 self
.MakeCacheMiss
= set()
2379 self
.MakeCacheHit
= set()
2380 if not self
.ModuleFile
:
2381 if not self
.SpawnMode
or self
.Target
not in ["", "all"]:
2382 self
.SpawnMode
= False
2383 self
._BuildPlatform
()
2385 self
._MultiThreadBuildPlatform
()
2387 self
.SpawnMode
= False
2390 if self
.Target
== 'cleanall':
2391 RemoveDirectory(os
.path
.dirname(GlobalData
.gDatabasePath
), True)
2393 def CreateAsBuiltInf(self
):
2394 for Module
in self
.BuildModules
:
2395 Module
.CreateAsBuiltInf()
2397 def GenDestCache(self
):
2398 for Module
in self
.AllModules
:
2399 Module
.GenPreMakefileHashList()
2400 Module
.GenMakefileHashList()
2401 Module
.CopyModuleToCache()
2403 def GenLocalPreMakeCache(self
):
2404 for Module
in self
.PreMakeCacheMiss
:
2405 Module
.GenPreMakefileHashList()
2407 ## Do some clean-up works when error occurred
2408 def Relinquish(self
):
2409 OldLogLevel
= EdkLogger
.GetLevel()
2410 EdkLogger
.SetLevel(EdkLogger
.ERROR
)
2411 Utils
.Progressor
.Abort()
2412 if self
.SpawnMode
== True:
2414 EdkLogger
.SetLevel(OldLogLevel
)
2416 def ParseDefines(DefineList
=[]):
2418 if DefineList
is not None:
2419 for Define
in DefineList
:
2420 DefineTokenList
= Define
.split("=", 1)
2421 if not GlobalData
.gMacroNamePattern
.match(DefineTokenList
[0]):
2422 EdkLogger
.error('build', FORMAT_INVALID
,
2423 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2424 ExtraData
=DefineTokenList
[0])
2426 if len(DefineTokenList
) == 1:
2427 DefineDict
[DefineTokenList
[0]] = "TRUE"
2429 DefineDict
[DefineTokenList
[0]] = DefineTokenList
[1].strip()
2434 def LogBuildTime(Time
):
2437 TimeDur
= time
.gmtime(Time
)
2438 if TimeDur
.tm_yday
> 1:
2439 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
) + ", %d day(s)" % (TimeDur
.tm_yday
- 1)
2441 TimeDurStr
= time
.strftime("%H:%M:%S", TimeDur
)
2446 OptionParser
= MyOptionParser()
2447 if not OptionParser
.BuildOption
and not OptionParser
.BuildTarget
:
2448 OptionParser
.GetOption()
2449 BuildOption
, BuildTarget
= OptionParser
.BuildOption
, OptionParser
.BuildTarget
2450 ThreadNumber
= BuildOption
.ThreadNumber
2451 GlobalData
.gCmdConfDir
= BuildOption
.ConfDirectory
2452 if ThreadNumber
is None:
2453 TargetObj
= TargetTxtDict()
2454 ThreadNumber
= TargetObj
.Target
.TargetTxtDictionary
[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER
]
2455 if ThreadNumber
== '':
2458 ThreadNumber
= int(ThreadNumber
, 0)
2460 if ThreadNumber
== 0:
2462 ThreadNumber
= multiprocessing
.cpu_count()
2463 except (ImportError, NotImplementedError):
2466 ## Tool entrance method
2468 # This method mainly dispatch specific methods per the command line options.
2469 # If no error found, return zero value so the caller of this tool can know
2470 # if it's executed successfully or not.
2472 # @retval 0 Tool was successful
2473 # @retval 1 Tool failed
2475 LogQMaxSize
= ThreadNum() * 10
2477 StartTime
= time
.time()
2480 # Create a log Queue
2482 LogQ
= mp
.Queue(LogQMaxSize
)
2483 # Initialize log system
2484 EdkLogger
.LogClientInitialize(LogQ
)
2485 GlobalData
.gCommand
= sys
.argv
[1:]
2487 # Parse the options and args
2489 OptionParser
= MyOptionParser()
2490 if not OptionParser
.BuildOption
and not OptionParser
.BuildTarget
:
2491 OptionParser
.GetOption()
2492 Option
, Target
= OptionParser
.BuildOption
, OptionParser
.BuildTarget
2493 GlobalData
.gOptions
= Option
2494 GlobalData
.gCaseInsensitive
= Option
.CaseInsensitive
2497 LogLevel
= EdkLogger
.INFO
2498 if Option
.verbose
is not None:
2499 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
2500 LogLevel
= EdkLogger
.VERBOSE
2501 elif Option
.quiet
is not None:
2502 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2503 LogLevel
= EdkLogger
.QUIET
2504 elif Option
.debug
is not None:
2505 EdkLogger
.SetLevel(Option
.debug
+ 1)
2506 LogLevel
= Option
.debug
+ 1
2508 EdkLogger
.SetLevel(EdkLogger
.INFO
)
2510 if Option
.WarningAsError
== True:
2511 EdkLogger
.SetWarningAsError()
2512 Log_Agent
= LogAgent(LogQ
,LogLevel
,Option
.LogFile
)
2515 if platform
.platform().find("Windows") >= 0:
2516 GlobalData
.gIsWindows
= True
2518 GlobalData
.gIsWindows
= False
2520 EdkLogger
.quiet("Build environment: %s" % platform
.platform())
2521 EdkLogger
.quiet(time
.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time
.localtime()));
2526 if len(Target
) == 0:
2528 elif len(Target
) >= 2:
2529 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "More than one targets are not supported.",
2530 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2532 Target
= Target
[0].lower()
2534 if Target
not in gSupportedTarget
:
2535 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "Not supported target [%s]." % Target
,
2536 ExtraData
="Please select one of: %s" % (' '.join(gSupportedTarget
)))
2539 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2542 GlobalData
.gCommandLineDefines
.update(ParseDefines(Option
.Macros
))
2544 Workspace
= os
.getenv("WORKSPACE")
2546 # Get files real name in workspace dir
2548 GlobalData
.gAllFiles
= Utils
.DirCache(Workspace
)
2550 WorkingDirectory
= os
.getcwd()
2551 if not Option
.ModuleFile
:
2552 FileList
= glob
.glob(os
.path
.normpath(os
.path
.join(WorkingDirectory
, '*.inf')))
2553 FileNum
= len(FileList
)
2555 EdkLogger
.error("build", OPTION_NOT_SUPPORTED
, "There are %d INF files in %s." % (FileNum
, WorkingDirectory
),
2556 ExtraData
="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2558 Option
.ModuleFile
= NormFile(FileList
[0], Workspace
)
2560 if Option
.ModuleFile
:
2561 if os
.path
.isabs (Option
.ModuleFile
):
2562 if os
.path
.normcase (os
.path
.normpath(Option
.ModuleFile
)).find (Workspace
) == 0:
2563 Option
.ModuleFile
= NormFile(os
.path
.normpath(Option
.ModuleFile
), Workspace
)
2564 Option
.ModuleFile
= PathClass(Option
.ModuleFile
, Workspace
)
2565 ErrorCode
, ErrorInfo
= Option
.ModuleFile
.Validate(".inf", False)
2567 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2569 if Option
.PlatformFile
is not None:
2570 if os
.path
.isabs (Option
.PlatformFile
):
2571 if os
.path
.normcase (os
.path
.normpath(Option
.PlatformFile
)).find (Workspace
) == 0:
2572 Option
.PlatformFile
= NormFile(os
.path
.normpath(Option
.PlatformFile
), Workspace
)
2573 Option
.PlatformFile
= PathClass(Option
.PlatformFile
, Workspace
)
2575 if Option
.FdfFile
is not None:
2576 if os
.path
.isabs (Option
.FdfFile
):
2577 if os
.path
.normcase (os
.path
.normpath(Option
.FdfFile
)).find (Workspace
) == 0:
2578 Option
.FdfFile
= NormFile(os
.path
.normpath(Option
.FdfFile
), Workspace
)
2579 Option
.FdfFile
= PathClass(Option
.FdfFile
, Workspace
)
2580 ErrorCode
, ErrorInfo
= Option
.FdfFile
.Validate(".fdf", False)
2582 EdkLogger
.error("build", ErrorCode
, ExtraData
=ErrorInfo
)
2584 if Option
.Flag
is not None and Option
.Flag
not in ['-c', '-s']:
2585 EdkLogger
.error("build", OPTION_VALUE_INVALID
, "UNI flag must be one of -c or -s")
2587 MyBuild
= Build(Target
, Workspace
, Option
,LogQ
)
2588 GlobalData
.gCommandLineDefines
['ARCH'] = ' '.join(MyBuild
.ArchList
)
2589 if not (MyBuild
.LaunchPrebuildFlag
and os
.path
.exists(MyBuild
.PlatformBuildPath
)):
2593 # All job done, no error found and no exception raised
2596 except FatalError
as X
:
2597 if MyBuild
is not None:
2598 # for multi-thread build exits safely
2599 MyBuild
.Relinquish()
2600 if Option
is not None and Option
.debug
is not None:
2601 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2602 ReturnCode
= X
.args
[0]
2603 except Warning as X
:
2604 # error from Fdf parser
2605 if MyBuild
is not None:
2606 # for multi-thread build exits safely
2607 MyBuild
.Relinquish()
2608 if Option
is not None and Option
.debug
is not None:
2609 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2611 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
2612 ReturnCode
= FORMAT_INVALID
2613 except KeyboardInterrupt:
2614 if MyBuild
is not None:
2616 # for multi-thread build exits safely
2617 MyBuild
.Relinquish()
2618 ReturnCode
= ABORT_ERROR
2619 if Option
is not None and Option
.debug
is not None:
2620 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2622 if MyBuild
is not None:
2623 # for multi-thread build exits safely
2624 MyBuild
.Relinquish()
2626 # try to get the meta-file from the object causing exception
2627 Tb
= sys
.exc_info()[-1]
2628 MetaFile
= GlobalData
.gProcessingFile
2629 while Tb
is not None:
2630 if 'self' in Tb
.tb_frame
.f_locals
and hasattr(Tb
.tb_frame
.f_locals
['self'], 'MetaFile'):
2631 MetaFile
= Tb
.tb_frame
.f_locals
['self'].MetaFile
2636 "Unknown fatal error when processing [%s]" % MetaFile
,
2637 ExtraData
="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR
,
2640 EdkLogger
.quiet("(Python %s on %s) " % (platform
.python_version(), sys
.platform
) + traceback
.format_exc())
2641 ReturnCode
= CODE_ERROR
2643 Utils
.Progressor
.Abort()
2644 Utils
.ClearDuplicatedInf()
2648 MyBuild
.LaunchPostbuild()
2651 Conclusion
= "Failed"
2652 elif ReturnCode
== ABORT_ERROR
:
2653 Conclusion
= "Aborted"
2655 Conclusion
= "Failed"
2656 FinishTime
= time
.time()
2657 BuildDuration
= time
.gmtime(int(round(FinishTime
- StartTime
)))
2658 BuildDurationStr
= ""
2659 if BuildDuration
.tm_yday
> 1:
2660 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
) + ", %d day(s)" % (BuildDuration
.tm_yday
- 1)
2662 BuildDurationStr
= time
.strftime("%H:%M:%S", BuildDuration
)
2663 if MyBuild
is not None:
2665 MyBuild
.BuildReport
.GenerateReport(BuildDurationStr
, LogBuildTime(MyBuild
.AutoGenTime
), LogBuildTime(MyBuild
.MakeTime
), LogBuildTime(MyBuild
.GenFdsTime
))
2667 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
2668 EdkLogger
.quiet("\n- %s -" % Conclusion
)
2669 EdkLogger
.quiet(time
.strftime("Build end time: %H:%M:%S, %b.%d %Y", time
.localtime()))
2670 EdkLogger
.quiet("Build total time: %s\n" % BuildDurationStr
)
2675 if __name__
== '__main__':
2677 mp
.set_start_method('spawn')
2681 ## 0-127 is a safe return range, and 1 is a standard default error
2682 if r
< 0 or r
> 127: r
= 1