]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/build/build.py
BaseTools:Add the spare space FV image size checker
[mirror_edk2.git] / BaseTools / Source / Python / build / build.py
1 ## @file
2 # build a platform or a module
3 #
4 # Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
5 # Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.<BR>
6 # Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
7 # Copyright (c) 2020, ARM Limited. All rights reserved.<BR>
8 #
9 # SPDX-License-Identifier: BSD-2-Clause-Patent
10 #
11
12 ##
13 # Import Modules
14 #
15 from __future__ import print_function
16 from __future__ import absolute_import
17 import os.path as path
18 import sys
19 import os
20 import re
21 import glob
22 import time
23 import platform
24 import traceback
25 import multiprocessing
26 from threading import Thread,Event,BoundedSemaphore
27 import threading
28 from linecache import getlines
29 from subprocess import Popen,PIPE, STDOUT
30 from collections import OrderedDict, defaultdict
31
32 from AutoGen.PlatformAutoGen import PlatformAutoGen
33 from AutoGen.ModuleAutoGen import ModuleAutoGen
34 from AutoGen.WorkspaceAutoGen import WorkspaceAutoGen
35 from AutoGen.AutoGenWorker import AutoGenWorkerInProcess,AutoGenManager,\
36 LogAgent
37 from AutoGen import GenMake
38 from Common import Misc as Utils
39
40 from Common.TargetTxtClassObject import TargetTxtDict
41 from Common.ToolDefClassObject import ToolDefDict
42 from buildoptions import MyOptionParser
43 from Common.Misc import PathClass,SaveFileOnChange,RemoveDirectory
44 from Common.StringUtils import NormPath
45 from Common.MultipleWorkspace import MultipleWorkspace as mws
46 from Common.BuildToolError import *
47 from Common.DataType import *
48 import Common.EdkLogger as EdkLogger
49
50 from Workspace.WorkspaceDatabase import BuildDB
51
52 from BuildReport import BuildReport
53 from GenPatchPcdTable.GenPatchPcdTable import PeImageClass,parsePcdInfoFromMapFile
54 from PatchPcdValue.PatchPcdValue import PatchBinaryFile
55
56 import Common.GlobalData as GlobalData
57 from GenFds.GenFds import GenFds, GenFdsApi
58 import multiprocessing as mp
59 from multiprocessing import Manager
60 from AutoGen.DataPipe import MemoryDataPipe
61 from AutoGen.ModuleAutoGenHelper import WorkSpaceInfo, PlatformInfo
62 from GenFds.FdfParser import FdfParser
63 from AutoGen.IncludesAutoGen import IncludesAutoGen
64 from GenFds.GenFds import resetFdsGlobalVariable
65
66 ## standard targets of build command
67 gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
68
69 ## build configuration file
70 gBuildConfiguration = "target.txt"
71 gToolsDefinition = "tools_def.txt"
72
73 TemporaryTablePattern = re.compile(r'^_\d+_\d+_[a-fA-F0-9]+$')
74 TmpTableDict = {}
75
76 ## Check environment PATH variable to make sure the specified tool is found
77 #
78 # If the tool is found in the PATH, then True is returned
79 # Otherwise, False is returned
80 #
81 def IsToolInPath(tool):
82 if 'PATHEXT' in os.environ:
83 extns = os.environ['PATHEXT'].split(os.path.pathsep)
84 else:
85 extns = ('',)
86 for pathDir in os.environ['PATH'].split(os.path.pathsep):
87 for ext in extns:
88 if os.path.exists(os.path.join(pathDir, tool + ext)):
89 return True
90 return False
91
92 ## Check environment variables
93 #
94 # Check environment variables that must be set for build. Currently they are
95 #
96 # WORKSPACE The directory all packages/platforms start from
97 # EDK_TOOLS_PATH The directory contains all tools needed by the build
98 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
99 #
100 # If any of above environment variable is not set or has error, the build
101 # will be broken.
102 #
103 def CheckEnvVariable():
104 # check WORKSPACE
105 if "WORKSPACE" not in os.environ:
106 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
107 ExtraData="WORKSPACE")
108
109 WorkspaceDir = os.path.normcase(os.path.normpath(os.environ["WORKSPACE"]))
110 if not os.path.exists(WorkspaceDir):
111 EdkLogger.error("build", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData=WorkspaceDir)
112 elif ' ' in WorkspaceDir:
113 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path",
114 ExtraData=WorkspaceDir)
115 os.environ["WORKSPACE"] = WorkspaceDir
116
117 # set multiple workspace
118 PackagesPath = os.getenv("PACKAGES_PATH")
119 mws.setWs(WorkspaceDir, PackagesPath)
120 if mws.PACKAGES_PATH:
121 for Path in mws.PACKAGES_PATH:
122 if not os.path.exists(Path):
123 EdkLogger.error("build", FILE_NOT_FOUND, "One Path in PACKAGES_PATH doesn't exist", ExtraData=Path)
124 elif ' ' in Path:
125 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in PACKAGES_PATH", ExtraData=Path)
126
127
128 os.environ["EDK_TOOLS_PATH"] = os.path.normcase(os.environ["EDK_TOOLS_PATH"])
129
130 # check EDK_TOOLS_PATH
131 if "EDK_TOOLS_PATH" not in os.environ:
132 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
133 ExtraData="EDK_TOOLS_PATH")
134
135 # check PATH
136 if "PATH" not in os.environ:
137 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
138 ExtraData="PATH")
139
140 GlobalData.gWorkspace = WorkspaceDir
141
142 GlobalData.gGlobalDefines["WORKSPACE"] = WorkspaceDir
143 GlobalData.gGlobalDefines["EDK_TOOLS_PATH"] = os.environ["EDK_TOOLS_PATH"]
144
145 ## Get normalized file path
146 #
147 # Convert the path to be local format, and remove the WORKSPACE path at the
148 # beginning if the file path is given in full path.
149 #
150 # @param FilePath File path to be normalized
151 # @param Workspace Workspace path which the FilePath will be checked against
152 #
153 # @retval string The normalized file path
154 #
155 def NormFile(FilePath, Workspace):
156 # check if the path is absolute or relative
157 if os.path.isabs(FilePath):
158 FileFullPath = os.path.normpath(FilePath)
159 else:
160 FileFullPath = os.path.normpath(mws.join(Workspace, FilePath))
161 Workspace = mws.getWs(Workspace, FilePath)
162
163 # check if the file path exists or not
164 if not os.path.isfile(FileFullPath):
165 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath)
166
167 # remove workspace directory from the beginning part of the file path
168 if Workspace[-1] in ["\\", "/"]:
169 return FileFullPath[len(Workspace):]
170 else:
171 return FileFullPath[(len(Workspace) + 1):]
172
173 ## Get the output of an external program
174 #
175 # This is the entrance method of thread reading output of an external program and
176 # putting them in STDOUT/STDERR of current program.
177 #
178 # @param From The stream message read from
179 # @param To The stream message put on
180 # @param ExitFlag The flag used to indicate stopping reading
181 #
182 def ReadMessage(From, To, ExitFlag,MemTo=None):
183 while True:
184 # read one line a time
185 Line = From.readline()
186 # empty string means "end"
187 if Line is not None and Line != b"":
188 LineStr = Line.rstrip().decode(encoding='utf-8', errors='ignore')
189 if MemTo is not None:
190 if "Note: including file:" == LineStr.lstrip()[:21]:
191 MemTo.append(LineStr)
192 else:
193 To(LineStr)
194 MemTo.append(LineStr)
195 else:
196 To(LineStr)
197 else:
198 break
199 if ExitFlag.isSet():
200 break
201
202 class MakeSubProc(Popen):
203 def __init__(self,*args, **argv):
204 super(MakeSubProc,self).__init__(*args, **argv)
205 self.ProcOut = []
206
207 ## Launch an external program
208 #
209 # This method will call subprocess.Popen to execute an external program with
210 # given options in specified directory. Because of the dead-lock issue during
211 # redirecting output of the external program, threads are used to to do the
212 # redirection work.
213 #
214 # @param Command A list or string containing the call of the program
215 # @param WorkingDir The directory in which the program will be running
216 #
217 def LaunchCommand(Command, WorkingDir,ModuleAuto = None):
218 BeginTime = time.time()
219 # if working directory doesn't exist, Popen() will raise an exception
220 if not os.path.isdir(WorkingDir):
221 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=WorkingDir)
222
223 # Command is used as the first Argument in following Popen().
224 # It could be a string or sequence. We find that if command is a string in following Popen(),
225 # ubuntu may fail with an error message that the command is not found.
226 # So here we may need convert command from string to list instance.
227 if platform.system() != 'Windows':
228 if not isinstance(Command, list):
229 Command = Command.split()
230 Command = ' '.join(Command)
231
232 Proc = None
233 EndOfProcedure = None
234 try:
235 # launch the command
236 Proc = MakeSubProc(Command, stdout=PIPE, stderr=STDOUT, env=os.environ, cwd=WorkingDir, bufsize=-1, shell=True)
237
238 # launch two threads to read the STDOUT and STDERR
239 EndOfProcedure = Event()
240 EndOfProcedure.clear()
241 if Proc.stdout:
242 StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure,Proc.ProcOut))
243 StdOutThread.setName("STDOUT-Redirector")
244 StdOutThread.setDaemon(False)
245 StdOutThread.start()
246
247
248 # waiting for program exit
249 Proc.wait()
250 except: # in case of aborting
251 # terminate the threads redirecting the program output
252 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
253 if EndOfProcedure is not None:
254 EndOfProcedure.set()
255 if Proc is None:
256 if not isinstance(Command, type("")):
257 Command = " ".join(Command)
258 EdkLogger.error("build", COMMAND_FAILURE, "Failed to start command", ExtraData="%s [%s]" % (Command, WorkingDir))
259
260 if Proc.stdout:
261 StdOutThread.join()
262
263 # check the return code of the program
264 if Proc.returncode != 0:
265 if not isinstance(Command, type("")):
266 Command = " ".join(Command)
267 # print out the Response file and its content when make failure
268 RespFile = os.path.join(WorkingDir, 'OUTPUT', 'respfilelist.txt')
269 if os.path.isfile(RespFile):
270 f = open(RespFile)
271 RespContent = f.read()
272 f.close()
273 EdkLogger.info(RespContent)
274
275 EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir))
276 if ModuleAuto:
277 iau = IncludesAutoGen(WorkingDir,ModuleAuto)
278 if ModuleAuto.ToolChainFamily == TAB_COMPILER_MSFT:
279 iau.CreateDepsFileForMsvc(Proc.ProcOut)
280 else:
281 iau.UpdateDepsFileforNonMsvc()
282 iau.UpdateDepsFileforTrim()
283 iau.CreateModuleDeps()
284 iau.CreateDepsInclude()
285 iau.CreateDepsTarget()
286 return "%dms" % (int(round((time.time() - BeginTime) * 1000)))
287
288 ## The smallest unit that can be built in multi-thread build mode
289 #
290 # This is the base class of build unit. The "Obj" parameter must provide
291 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
292 # missing build.
293 #
294 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
295 #
296 class BuildUnit:
297 ## The constructor
298 #
299 # @param self The object pointer
300 # @param Obj The object the build is working on
301 # @param Target The build target name, one of gSupportedTarget
302 # @param Dependency The BuildUnit(s) which must be completed in advance
303 # @param WorkingDir The directory build command starts in
304 #
305 def __init__(self, Obj, BuildCommand, Target, Dependency, WorkingDir="."):
306 self.BuildObject = Obj
307 self.Dependency = Dependency
308 self.WorkingDir = WorkingDir
309 self.Target = Target
310 self.BuildCommand = BuildCommand
311 if not BuildCommand:
312 EdkLogger.error("build", OPTION_MISSING,
313 "No build command found for this module. "
314 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
315 (Obj.BuildTarget, Obj.ToolChain, Obj.Arch),
316 ExtraData=str(Obj))
317
318
319 ## str() method
320 #
321 # It just returns the string representation of self.BuildObject
322 #
323 # @param self The object pointer
324 #
325 def __str__(self):
326 return str(self.BuildObject)
327
328 ## "==" operator method
329 #
330 # It just compares self.BuildObject with "Other". So self.BuildObject must
331 # provide its own __eq__() method.
332 #
333 # @param self The object pointer
334 # @param Other The other BuildUnit object compared to
335 #
336 def __eq__(self, Other):
337 return Other and self.BuildObject == Other.BuildObject \
338 and Other.BuildObject \
339 and self.BuildObject.Arch == Other.BuildObject.Arch
340
341 ## hash() method
342 #
343 # It just returns the hash value of self.BuildObject which must be hashable.
344 #
345 # @param self The object pointer
346 #
347 def __hash__(self):
348 return hash(self.BuildObject) + hash(self.BuildObject.Arch)
349
350 def __repr__(self):
351 return repr(self.BuildObject)
352
353 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
354 #
355 # This class is for module build by nmake/make build system. The "Obj" parameter
356 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
357 # be make units missing build.
358 #
359 # Currently the "Obj" should be only ModuleAutoGen object.
360 #
361 class ModuleMakeUnit(BuildUnit):
362 ## The constructor
363 #
364 # @param self The object pointer
365 # @param Obj The ModuleAutoGen object the build is working on
366 # @param Target The build target name, one of gSupportedTarget
367 #
368 def __init__(self, Obj, BuildCommand,Target):
369 Dependency = [ModuleMakeUnit(La, BuildCommand,Target) for La in Obj.LibraryAutoGenList]
370 BuildUnit.__init__(self, Obj, BuildCommand, Target, Dependency, Obj.MakeFileDir)
371 if Target in [None, "", "all"]:
372 self.Target = "tbuild"
373
374 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
375 #
376 # This class is for platform build by nmake/make build system. The "Obj" parameter
377 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
378 # be make units missing build.
379 #
380 # Currently the "Obj" should be only PlatformAutoGen object.
381 #
382 class PlatformMakeUnit(BuildUnit):
383 ## The constructor
384 #
385 # @param self The object pointer
386 # @param Obj The PlatformAutoGen object the build is working on
387 # @param Target The build target name, one of gSupportedTarget
388 #
389 def __init__(self, Obj, BuildCommand, Target):
390 Dependency = [ModuleMakeUnit(Lib, BuildCommand, Target) for Lib in self.BuildObject.LibraryAutoGenList]
391 Dependency.extend([ModuleMakeUnit(Mod, BuildCommand,Target) for Mod in self.BuildObject.ModuleAutoGenList])
392 BuildUnit.__init__(self, Obj, BuildCommand, Target, Dependency, Obj.MakeFileDir)
393
394 ## The class representing the task of a module build or platform build
395 #
396 # This class manages the build tasks in multi-thread build mode. Its jobs include
397 # scheduling thread running, catching thread error, monitor the thread status, etc.
398 #
399 class BuildTask:
400 # queue for tasks waiting for schedule
401 _PendingQueue = OrderedDict()
402 _PendingQueueLock = threading.Lock()
403
404 # queue for tasks ready for running
405 _ReadyQueue = OrderedDict()
406 _ReadyQueueLock = threading.Lock()
407
408 # queue for run tasks
409 _RunningQueue = OrderedDict()
410 _RunningQueueLock = threading.Lock()
411
412 # queue containing all build tasks, in case duplicate build
413 _TaskQueue = OrderedDict()
414
415 # flag indicating error occurs in a running thread
416 _ErrorFlag = threading.Event()
417 _ErrorFlag.clear()
418 _ErrorMessage = ""
419
420 # BoundedSemaphore object used to control the number of running threads
421 _Thread = None
422
423 # flag indicating if the scheduler is started or not
424 _SchedulerStopped = threading.Event()
425 _SchedulerStopped.set()
426
427 ## Start the task scheduler thread
428 #
429 # @param MaxThreadNumber The maximum thread number
430 # @param ExitFlag Flag used to end the scheduler
431 #
432 @staticmethod
433 def StartScheduler(MaxThreadNumber, ExitFlag):
434 SchedulerThread = Thread(target=BuildTask.Scheduler, args=(MaxThreadNumber, ExitFlag))
435 SchedulerThread.setName("Build-Task-Scheduler")
436 SchedulerThread.setDaemon(False)
437 SchedulerThread.start()
438 # wait for the scheduler to be started, especially useful in Linux
439 while not BuildTask.IsOnGoing():
440 time.sleep(0.01)
441
442 ## Scheduler method
443 #
444 # @param MaxThreadNumber The maximum thread number
445 # @param ExitFlag Flag used to end the scheduler
446 #
447 @staticmethod
448 def Scheduler(MaxThreadNumber, ExitFlag):
449 BuildTask._SchedulerStopped.clear()
450 try:
451 # use BoundedSemaphore to control the maximum running threads
452 BuildTask._Thread = BoundedSemaphore(MaxThreadNumber)
453 #
454 # scheduling loop, which will exits when no pending/ready task and
455 # indicated to do so, or there's error in running thread
456 #
457 while (len(BuildTask._PendingQueue) > 0 or len(BuildTask._ReadyQueue) > 0 \
458 or not ExitFlag.isSet()) and not BuildTask._ErrorFlag.isSet():
459 EdkLogger.debug(EdkLogger.DEBUG_8, "Pending Queue (%d), Ready Queue (%d)"
460 % (len(BuildTask._PendingQueue), len(BuildTask._ReadyQueue)))
461
462 # get all pending tasks
463 BuildTask._PendingQueueLock.acquire()
464 BuildObjectList = list(BuildTask._PendingQueue.keys())
465 #
466 # check if their dependency is resolved, and if true, move them
467 # into ready queue
468 #
469 for BuildObject in BuildObjectList:
470 Bt = BuildTask._PendingQueue[BuildObject]
471 if Bt.IsReady():
472 BuildTask._ReadyQueue[BuildObject] = BuildTask._PendingQueue.pop(BuildObject)
473 BuildTask._PendingQueueLock.release()
474
475 # launch build thread until the maximum number of threads is reached
476 while not BuildTask._ErrorFlag.isSet():
477 # empty ready queue, do nothing further
478 if len(BuildTask._ReadyQueue) == 0:
479 break
480
481 # wait for active thread(s) exit
482 BuildTask._Thread.acquire(True)
483
484 # start a new build thread
485 Bo, Bt = BuildTask._ReadyQueue.popitem()
486
487 # move into running queue
488 BuildTask._RunningQueueLock.acquire()
489 BuildTask._RunningQueue[Bo] = Bt
490 BuildTask._RunningQueueLock.release()
491
492 Bt.Start()
493 # avoid tense loop
494 time.sleep(0.01)
495
496 # avoid tense loop
497 time.sleep(0.01)
498
499 # wait for all running threads exit
500 if BuildTask._ErrorFlag.isSet():
501 EdkLogger.quiet("\nWaiting for all build threads exit...")
502 # while not BuildTask._ErrorFlag.isSet() and \
503 while len(BuildTask._RunningQueue) > 0:
504 EdkLogger.verbose("Waiting for thread ending...(%d)" % len(BuildTask._RunningQueue))
505 EdkLogger.debug(EdkLogger.DEBUG_8, "Threads [%s]" % ", ".join(Th.getName() for Th in threading.enumerate()))
506 # avoid tense loop
507 time.sleep(0.1)
508 except BaseException as X:
509 #
510 # TRICK: hide the output of threads left running, so that the user can
511 # catch the error message easily
512 #
513 EdkLogger.SetLevel(EdkLogger.ERROR)
514 BuildTask._ErrorFlag.set()
515 BuildTask._ErrorMessage = "build thread scheduler error\n\t%s" % str(X)
516
517 BuildTask._PendingQueue.clear()
518 BuildTask._ReadyQueue.clear()
519 BuildTask._RunningQueue.clear()
520 BuildTask._TaskQueue.clear()
521 BuildTask._SchedulerStopped.set()
522
523 ## Wait for all running method exit
524 #
525 @staticmethod
526 def WaitForComplete():
527 BuildTask._SchedulerStopped.wait()
528
529 ## Check if the scheduler is running or not
530 #
531 @staticmethod
532 def IsOnGoing():
533 return not BuildTask._SchedulerStopped.isSet()
534
535 ## Abort the build
536 @staticmethod
537 def Abort():
538 if BuildTask.IsOnGoing():
539 BuildTask._ErrorFlag.set()
540 BuildTask.WaitForComplete()
541
542 ## Check if there's error in running thread
543 #
544 # Since the main thread cannot catch exceptions in other thread, we have to
545 # use threading.Event to communicate this formation to main thread.
546 #
547 @staticmethod
548 def HasError():
549 return BuildTask._ErrorFlag.isSet()
550
551 ## Get error message in running thread
552 #
553 # Since the main thread cannot catch exceptions in other thread, we have to
554 # use a static variable to communicate this message to main thread.
555 #
556 @staticmethod
557 def GetErrorMessage():
558 return BuildTask._ErrorMessage
559
560 ## Factory method to create a BuildTask object
561 #
562 # This method will check if a module is building or has been built. And if
563 # true, just return the associated BuildTask object in the _TaskQueue. If
564 # not, create and return a new BuildTask object. The new BuildTask object
565 # will be appended to the _PendingQueue for scheduling later.
566 #
567 # @param BuildItem A BuildUnit object representing a build object
568 # @param Dependency The dependent build object of BuildItem
569 #
570 @staticmethod
571 def New(BuildItem, Dependency=None):
572 if BuildItem in BuildTask._TaskQueue:
573 Bt = BuildTask._TaskQueue[BuildItem]
574 return Bt
575
576 Bt = BuildTask()
577 Bt._Init(BuildItem, Dependency)
578 BuildTask._TaskQueue[BuildItem] = Bt
579
580 BuildTask._PendingQueueLock.acquire()
581 BuildTask._PendingQueue[BuildItem] = Bt
582 BuildTask._PendingQueueLock.release()
583
584 return Bt
585
586 ## The real constructor of BuildTask
587 #
588 # @param BuildItem A BuildUnit object representing a build object
589 # @param Dependency The dependent build object of BuildItem
590 #
591 def _Init(self, BuildItem, Dependency=None):
592 self.BuildItem = BuildItem
593
594 self.DependencyList = []
595 if Dependency is None:
596 Dependency = BuildItem.Dependency
597 else:
598 Dependency.extend(BuildItem.Dependency)
599 self.AddDependency(Dependency)
600 # flag indicating build completes, used to avoid unnecessary re-build
601 self.CompleteFlag = False
602
603 ## Check if all dependent build tasks are completed or not
604 #
605 def IsReady(self):
606 ReadyFlag = True
607 for Dep in self.DependencyList:
608 if Dep.CompleteFlag == True:
609 continue
610 ReadyFlag = False
611 break
612
613 return ReadyFlag
614
615 ## Add dependent build task
616 #
617 # @param Dependency The list of dependent build objects
618 #
619 def AddDependency(self, Dependency):
620 for Dep in Dependency:
621 if not Dep.BuildObject.IsBinaryModule and not Dep.BuildObject.CanSkipbyCache(GlobalData.gModuleCacheHit):
622 self.DependencyList.append(BuildTask.New(Dep)) # BuildTask list
623
624 ## The thread wrapper of LaunchCommand function
625 #
626 # @param Command A list or string contains the call of the command
627 # @param WorkingDir The directory in which the program will be running
628 #
629 def _CommandThread(self, Command, WorkingDir):
630 try:
631 self.BuildItem.BuildObject.BuildTime = LaunchCommand(Command, WorkingDir,self.BuildItem.BuildObject)
632 self.CompleteFlag = True
633
634 # Run hash operation post dependency to account for libs
635 # Run if --hash or --binary-destination
636 if GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:
637 self.BuildItem.BuildObject.GenModuleHash()
638 if GlobalData.gBinCacheDest:
639 self.BuildItem.BuildObject.GenCMakeHash()
640
641 except:
642 #
643 # TRICK: hide the output of threads left running, so that the user can
644 # catch the error message easily
645 #
646 if not BuildTask._ErrorFlag.isSet():
647 GlobalData.gBuildingModule = "%s [%s, %s, %s]" % (str(self.BuildItem.BuildObject),
648 self.BuildItem.BuildObject.Arch,
649 self.BuildItem.BuildObject.ToolChain,
650 self.BuildItem.BuildObject.BuildTarget
651 )
652 EdkLogger.SetLevel(EdkLogger.ERROR)
653 BuildTask._ErrorFlag.set()
654 BuildTask._ErrorMessage = "%s broken\n %s [%s]" % \
655 (threading.currentThread().getName(), Command, WorkingDir)
656
657 # indicate there's a thread is available for another build task
658 BuildTask._RunningQueueLock.acquire()
659 BuildTask._RunningQueue.pop(self.BuildItem)
660 BuildTask._RunningQueueLock.release()
661 BuildTask._Thread.release()
662
663 ## Start build task thread
664 #
665 def Start(self):
666 EdkLogger.quiet("Building ... %s" % repr(self.BuildItem))
667 Command = self.BuildItem.BuildCommand + [self.BuildItem.Target]
668 self.BuildTread = Thread(target=self._CommandThread, args=(Command, self.BuildItem.WorkingDir))
669 self.BuildTread.setName("build thread")
670 self.BuildTread.setDaemon(False)
671 self.BuildTread.start()
672
673 ## The class contains the information related to EFI image
674 #
675 class PeImageInfo():
676 ## Constructor
677 #
678 # Constructor will load all required image information.
679 #
680 # @param BaseName The full file path of image.
681 # @param Guid The GUID for image.
682 # @param Arch Arch of this image.
683 # @param OutputDir The output directory for image.
684 # @param DebugDir The debug directory for image.
685 # @param ImageClass PeImage Information
686 #
687 def __init__(self, BaseName, Guid, Arch, OutputDir, DebugDir, ImageClass):
688 self.BaseName = BaseName
689 self.Guid = Guid
690 self.Arch = Arch
691 self.OutputDir = OutputDir
692 self.DebugDir = DebugDir
693 self.Image = ImageClass
694 self.Image.Size = (self.Image.Size // 0x1000 + 1) * 0x1000
695
696 ## The class implementing the EDK2 build process
697 #
698 # The build process includes:
699 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
700 # 2. Parse DSC file of active platform
701 # 3. Parse FDF file if any
702 # 4. Establish build database, including parse all other files (module, package)
703 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
704 # 6. Call build command
705 #
706 class Build():
707 ## Constructor
708 #
709 # Constructor will load all necessary configurations, parse platform, modules
710 # and packages and the establish a database for AutoGen.
711 #
712 # @param Target The build command target, one of gSupportedTarget
713 # @param WorkspaceDir The directory of workspace
714 # @param BuildOptions Build options passed from command line
715 #
716 def __init__(self, Target, WorkspaceDir, BuildOptions,log_q):
717 self.WorkspaceDir = WorkspaceDir
718 self.Target = Target
719 self.PlatformFile = BuildOptions.PlatformFile
720 self.ModuleFile = BuildOptions.ModuleFile
721 self.ArchList = BuildOptions.TargetArch
722 self.ToolChainList = BuildOptions.ToolChain
723 self.BuildTargetList= BuildOptions.BuildTarget
724 self.Fdf = BuildOptions.FdfFile
725 self.FdList = BuildOptions.RomImage
726 self.FvList = BuildOptions.FvImage
727 self.CapList = BuildOptions.CapName
728 self.SilentMode = BuildOptions.SilentMode
729 self.ThreadNumber = 1
730 self.SkipAutoGen = BuildOptions.SkipAutoGen
731 self.Reparse = BuildOptions.Reparse
732 self.SkuId = BuildOptions.SkuId
733 if self.SkuId:
734 GlobalData.gSKUID_CMD = self.SkuId
735 self.ConfDirectory = BuildOptions.ConfDirectory
736 self.SpawnMode = True
737 self.BuildReport = BuildReport(BuildOptions.ReportFile, BuildOptions.ReportType)
738 self.AutoGenTime = 0
739 self.MakeTime = 0
740 self.GenFdsTime = 0
741 self.MakeFileName = ""
742 TargetObj = TargetTxtDict()
743 ToolDefObj = ToolDefDict((os.path.join(os.getenv("WORKSPACE"),"Conf")))
744 self.TargetTxt = TargetObj.Target
745 self.ToolDef = ToolDefObj.ToolDef
746 GlobalData.BuildOptionPcd = BuildOptions.OptionPcd if BuildOptions.OptionPcd else []
747 #Set global flag for build mode
748 GlobalData.gIgnoreSource = BuildOptions.IgnoreSources
749 GlobalData.gUseHashCache = BuildOptions.UseHashCache
750 GlobalData.gBinCacheDest = BuildOptions.BinCacheDest
751 GlobalData.gBinCacheSource = BuildOptions.BinCacheSource
752 GlobalData.gEnableGenfdsMultiThread = not BuildOptions.NoGenfdsMultiThread
753 GlobalData.gDisableIncludePathCheck = BuildOptions.DisableIncludePathCheck
754
755 if GlobalData.gBinCacheDest and not GlobalData.gUseHashCache:
756 EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-destination must be used together with --hash.")
757
758 if GlobalData.gBinCacheSource and not GlobalData.gUseHashCache:
759 EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-source must be used together with --hash.")
760
761 if GlobalData.gBinCacheDest and GlobalData.gBinCacheSource:
762 EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-destination can not be used together with --binary-source.")
763
764 if GlobalData.gBinCacheSource:
765 BinCacheSource = os.path.normpath(GlobalData.gBinCacheSource)
766 if not os.path.isabs(BinCacheSource):
767 BinCacheSource = mws.join(self.WorkspaceDir, BinCacheSource)
768 GlobalData.gBinCacheSource = BinCacheSource
769 else:
770 if GlobalData.gBinCacheSource is not None:
771 EdkLogger.error("build", OPTION_VALUE_INVALID, ExtraData="Invalid value of option --binary-source.")
772
773 if GlobalData.gBinCacheDest:
774 BinCacheDest = os.path.normpath(GlobalData.gBinCacheDest)
775 if not os.path.isabs(BinCacheDest):
776 BinCacheDest = mws.join(self.WorkspaceDir, BinCacheDest)
777 GlobalData.gBinCacheDest = BinCacheDest
778 else:
779 if GlobalData.gBinCacheDest is not None:
780 EdkLogger.error("build", OPTION_VALUE_INVALID, ExtraData="Invalid value of option --binary-destination.")
781
782 GlobalData.gDatabasePath = os.path.normpath(os.path.join(GlobalData.gConfDirectory, GlobalData.gDatabasePath))
783 if not os.path.exists(os.path.join(GlobalData.gConfDirectory, '.cache')):
784 os.makedirs(os.path.join(GlobalData.gConfDirectory, '.cache'))
785 self.Db = BuildDB
786 self.BuildDatabase = self.Db.BuildObject
787 self.Platform = None
788 self.ToolChainFamily = None
789 self.LoadFixAddress = 0
790 self.UniFlag = BuildOptions.Flag
791 self.BuildModules = []
792 self.HashSkipModules = []
793 self.Db_Flag = False
794 self.LaunchPrebuildFlag = False
795 self.PlatformBuildPath = os.path.join(GlobalData.gConfDirectory, '.cache', '.PlatformBuild')
796 if BuildOptions.CommandLength:
797 GlobalData.gCommandMaxLength = BuildOptions.CommandLength
798
799 # print dot character during doing some time-consuming work
800 self.Progress = Utils.Progressor()
801 # print current build environment and configuration
802 EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))
803 if "PACKAGES_PATH" in os.environ:
804 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
805 EdkLogger.quiet("%-16s = %s" % ("PACKAGES_PATH", os.path.normcase(os.path.normpath(os.environ["PACKAGES_PATH"]))))
806 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))
807 if "EDK_TOOLS_BIN" in os.environ:
808 # Print the same path style with WORKSPACE env.
809 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os.path.normcase(os.path.normpath(os.environ["EDK_TOOLS_BIN"]))))
810 EdkLogger.quiet("%-16s = %s" % ("CONF_PATH", GlobalData.gConfDirectory))
811 if "PYTHON3_ENABLE" in os.environ:
812 PYTHON3_ENABLE = os.environ["PYTHON3_ENABLE"]
813 if PYTHON3_ENABLE != "TRUE":
814 PYTHON3_ENABLE = "FALSE"
815 EdkLogger.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE))
816 if "PYTHON_COMMAND" in os.environ:
817 EdkLogger.quiet("%-16s = %s" % ("PYTHON_COMMAND", os.environ["PYTHON_COMMAND"]))
818 self.InitPreBuild()
819 self.InitPostBuild()
820 if self.Prebuild:
821 EdkLogger.quiet("%-16s = %s" % ("PREBUILD", self.Prebuild))
822 if self.Postbuild:
823 EdkLogger.quiet("%-16s = %s" % ("POSTBUILD", self.Postbuild))
824 if self.Prebuild:
825 self.LaunchPrebuild()
826 TargetObj = TargetTxtDict()
827 ToolDefObj = ToolDefDict((os.path.join(os.getenv("WORKSPACE"), "Conf")))
828 self.TargetTxt = TargetObj.Target
829 self.ToolDef = ToolDefObj.ToolDef
830 if not (self.LaunchPrebuildFlag and os.path.exists(self.PlatformBuildPath)):
831 self.InitBuild()
832
833 self.AutoGenMgr = None
834 EdkLogger.info("")
835 os.chdir(self.WorkspaceDir)
836 self.log_q = log_q
837 GlobalData.file_lock = mp.Lock()
838 # Init cache data for local only
839 GlobalData.gPackageHashFile = dict()
840 GlobalData.gModulePreMakeCacheStatus = dict()
841 GlobalData.gModuleMakeCacheStatus = dict()
842 GlobalData.gHashChainStatus = dict()
843 GlobalData.gCMakeHashFile = dict()
844 GlobalData.gModuleHashFile = dict()
845 GlobalData.gFileHashDict = dict()
846 GlobalData.gModuleAllCacheStatus = set()
847 GlobalData.gModuleCacheHit = set()
848
849 def StartAutoGen(self,mqueue, DataPipe,SkipAutoGen,PcdMaList,cqueue):
850 try:
851 if SkipAutoGen:
852 return True,0
853 feedback_q = mp.Queue()
854 error_event = mp.Event()
855 FfsCmd = DataPipe.Get("FfsCommand")
856 if FfsCmd is None:
857 FfsCmd = {}
858 GlobalData.FfsCmd = FfsCmd
859 auto_workers = [AutoGenWorkerInProcess(mqueue,DataPipe.dump_file,feedback_q,GlobalData.file_lock,cqueue,self.log_q,error_event) for _ in range(self.ThreadNumber)]
860 self.AutoGenMgr = AutoGenManager(auto_workers,feedback_q,error_event)
861 self.AutoGenMgr.start()
862 for w in auto_workers:
863 w.start()
864 if PcdMaList is not None:
865 for PcdMa in PcdMaList:
866 # SourceFileList calling sequence impact the makefile string sequence.
867 # Create cached SourceFileList here to unify its calling sequence for both
868 # CanSkipbyPreMakeCache and CreateCodeFile/CreateMakeFile.
869 RetVal = PcdMa.SourceFileList
870 # Force cache miss for PCD driver
871 if GlobalData.gUseHashCache and not GlobalData.gBinCacheDest and self.Target in [None, "", "all"]:
872 cqueue.put((PcdMa.MetaFile.Path, PcdMa.Arch, "PreMakeCache", False))
873
874 PcdMa.CreateCodeFile(False)
875 PcdMa.CreateMakeFile(False,GenFfsList = DataPipe.Get("FfsCommand").get((PcdMa.MetaFile.Path, PcdMa.Arch),[]))
876
877 # Force cache miss for PCD driver
878 if GlobalData.gBinCacheSource and self.Target in [None, "", "all"]:
879 cqueue.put((PcdMa.MetaFile.Path, PcdMa.Arch, "MakeCache", False))
880
881 self.AutoGenMgr.join()
882 rt = self.AutoGenMgr.Status
883 return rt, 0
884 except FatalError as e:
885 return False, e.args[0]
886 except:
887 return False, UNKNOWN_ERROR
888
889 ## Load configuration
890 #
891 # This method will parse target.txt and get the build configurations.
892 #
893 def LoadConfiguration(self):
894
895 # if no ARCH given in command line, get it from target.txt
896 if not self.ArchList:
897 self.ArchList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET_ARCH]
898 self.ArchList = tuple(self.ArchList)
899
900 # if no build target given in command line, get it from target.txt
901 if not self.BuildTargetList:
902 self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET]
903
904 # if no tool chain given in command line, get it from target.txt
905 if not self.ToolChainList:
906 self.ToolChainList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TOOL_CHAIN_TAG]
907 if self.ToolChainList is None or len(self.ToolChainList) == 0:
908 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")
909
910 # check if the tool chains are defined or not
911 NewToolChainList = []
912 for ToolChain in self.ToolChainList:
913 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:
914 EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)
915 else:
916 NewToolChainList.append(ToolChain)
917 # if no tool chain available, break the build
918 if len(NewToolChainList) == 0:
919 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
920 ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))
921 else:
922 self.ToolChainList = NewToolChainList
923
924 ToolChainFamily = []
925 ToolDefinition = self.ToolDef.ToolsDefTxtDatabase
926 for Tool in self.ToolChainList:
927 if TAB_TOD_DEFINES_FAMILY not in ToolDefinition or Tool not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \
928 or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool]:
929 EdkLogger.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool)
930 ToolChainFamily.append(TAB_COMPILER_MSFT)
931 else:
932 ToolChainFamily.append(ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool])
933 self.ToolChainFamily = ToolChainFamily
934
935 if not self.PlatformFile:
936 PlatformFile = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_ACTIVE_PLATFORM]
937 if not PlatformFile:
938 # Try to find one in current directory
939 WorkingDirectory = os.getcwd()
940 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))
941 FileNum = len(FileList)
942 if FileNum >= 2:
943 EdkLogger.error("build", OPTION_MISSING,
944 ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))
945 elif FileNum == 1:
946 PlatformFile = FileList[0]
947 else:
948 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
949 ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")
950
951 self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)
952 self.ThreadNumber = ThreadNum()
953 ## Initialize build configuration
954 #
955 # This method will parse DSC file and merge the configurations from
956 # command line and target.txt, then get the final build configurations.
957 #
958 def InitBuild(self):
959 # parse target.txt, tools_def.txt, and platform file
960 self.LoadConfiguration()
961
962 # Allow case-insensitive for those from command line or configuration file
963 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)
964 if ErrorCode != 0:
965 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
966
967
968 def InitPreBuild(self):
969 self.LoadConfiguration()
970 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)
971 if ErrorCode != 0:
972 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
973 if self.BuildTargetList:
974 GlobalData.gGlobalDefines['TARGET'] = self.BuildTargetList[0]
975 if self.ArchList:
976 GlobalData.gGlobalDefines['ARCH'] = self.ArchList[0]
977 if self.ToolChainList:
978 GlobalData.gGlobalDefines['TOOLCHAIN'] = self.ToolChainList[0]
979 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = self.ToolChainList[0]
980 if self.ToolChainFamily:
981 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[0]
982 if 'PREBUILD' in GlobalData.gCommandLineDefines:
983 self.Prebuild = GlobalData.gCommandLineDefines.get('PREBUILD')
984 else:
985 self.Db_Flag = True
986 Platform = self.Db.MapPlatform(str(self.PlatformFile))
987 self.Prebuild = str(Platform.Prebuild)
988 if self.Prebuild:
989 PrebuildList = []
990 #
991 # Evaluate all arguments and convert arguments that are WORKSPACE
992 # relative paths to absolute paths. Filter arguments that look like
993 # flags or do not follow the file/dir naming rules to avoid false
994 # positives on this conversion.
995 #
996 for Arg in self.Prebuild.split():
997 #
998 # Do not modify Arg if it looks like a flag or an absolute file path
999 #
1000 if Arg.startswith('-') or os.path.isabs(Arg):
1001 PrebuildList.append(Arg)
1002 continue
1003 #
1004 # Do not modify Arg if it does not look like a Workspace relative
1005 # path that starts with a valid package directory name
1006 #
1007 if not Arg[0].isalpha() or os.path.dirname(Arg) == '':
1008 PrebuildList.append(Arg)
1009 continue
1010 #
1011 # If Arg looks like a WORKSPACE relative path, then convert to an
1012 # absolute path and check to see if the file exists.
1013 #
1014 Temp = mws.join(self.WorkspaceDir, Arg)
1015 if os.path.isfile(Temp):
1016 Arg = Temp
1017 PrebuildList.append(Arg)
1018 self.Prebuild = ' '.join(PrebuildList)
1019 self.Prebuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)
1020
1021 def InitPostBuild(self):
1022 if 'POSTBUILD' in GlobalData.gCommandLineDefines:
1023 self.Postbuild = GlobalData.gCommandLineDefines.get('POSTBUILD')
1024 else:
1025 Platform = self.Db.MapPlatform(str(self.PlatformFile))
1026 self.Postbuild = str(Platform.Postbuild)
1027 if self.Postbuild:
1028 PostbuildList = []
1029 #
1030 # Evaluate all arguments and convert arguments that are WORKSPACE
1031 # relative paths to absolute paths. Filter arguments that look like
1032 # flags or do not follow the file/dir naming rules to avoid false
1033 # positives on this conversion.
1034 #
1035 for Arg in self.Postbuild.split():
1036 #
1037 # Do not modify Arg if it looks like a flag or an absolute file path
1038 #
1039 if Arg.startswith('-') or os.path.isabs(Arg):
1040 PostbuildList.append(Arg)
1041 continue
1042 #
1043 # Do not modify Arg if it does not look like a Workspace relative
1044 # path that starts with a valid package directory name
1045 #
1046 if not Arg[0].isalpha() or os.path.dirname(Arg) == '':
1047 PostbuildList.append(Arg)
1048 continue
1049 #
1050 # If Arg looks like a WORKSPACE relative path, then convert to an
1051 # absolute path and check to see if the file exists.
1052 #
1053 Temp = mws.join(self.WorkspaceDir, Arg)
1054 if os.path.isfile(Temp):
1055 Arg = Temp
1056 PostbuildList.append(Arg)
1057 self.Postbuild = ' '.join(PostbuildList)
1058 self.Postbuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)
1059
1060 def PassCommandOption(self, BuildTarget, TargetArch, ToolChain, PlatformFile, Target):
1061 BuildStr = ''
1062 if GlobalData.gCommand and isinstance(GlobalData.gCommand, list):
1063 BuildStr += ' ' + ' '.join(GlobalData.gCommand)
1064 TargetFlag = False
1065 ArchFlag = False
1066 ToolChainFlag = False
1067 PlatformFileFlag = False
1068
1069 if GlobalData.gOptions and not GlobalData.gOptions.BuildTarget:
1070 TargetFlag = True
1071 if GlobalData.gOptions and not GlobalData.gOptions.TargetArch:
1072 ArchFlag = True
1073 if GlobalData.gOptions and not GlobalData.gOptions.ToolChain:
1074 ToolChainFlag = True
1075 if GlobalData.gOptions and not GlobalData.gOptions.PlatformFile:
1076 PlatformFileFlag = True
1077
1078 if TargetFlag and BuildTarget:
1079 if isinstance(BuildTarget, list) or isinstance(BuildTarget, tuple):
1080 BuildStr += ' -b ' + ' -b '.join(BuildTarget)
1081 elif isinstance(BuildTarget, str):
1082 BuildStr += ' -b ' + BuildTarget
1083 if ArchFlag and TargetArch:
1084 if isinstance(TargetArch, list) or isinstance(TargetArch, tuple):
1085 BuildStr += ' -a ' + ' -a '.join(TargetArch)
1086 elif isinstance(TargetArch, str):
1087 BuildStr += ' -a ' + TargetArch
1088 if ToolChainFlag and ToolChain:
1089 if isinstance(ToolChain, list) or isinstance(ToolChain, tuple):
1090 BuildStr += ' -t ' + ' -t '.join(ToolChain)
1091 elif isinstance(ToolChain, str):
1092 BuildStr += ' -t ' + ToolChain
1093 if PlatformFileFlag and PlatformFile:
1094 if isinstance(PlatformFile, list) or isinstance(PlatformFile, tuple):
1095 BuildStr += ' -p ' + ' -p '.join(PlatformFile)
1096 elif isinstance(PlatformFile, str):
1097 BuildStr += ' -p' + PlatformFile
1098 BuildStr += ' --conf=' + GlobalData.gConfDirectory
1099 if Target:
1100 BuildStr += ' ' + Target
1101
1102 return BuildStr
1103
1104 def LaunchPrebuild(self):
1105 if self.Prebuild:
1106 EdkLogger.info("\n- Prebuild Start -\n")
1107 self.LaunchPrebuildFlag = True
1108 #
1109 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1110 # and preserve them for the rest of the main build step, because the child process environment will
1111 # evaporate as soon as it exits, we cannot get it in build step.
1112 #
1113 PrebuildEnvFile = os.path.join(GlobalData.gConfDirectory, '.cache', '.PrebuildEnv')
1114 if os.path.isfile(PrebuildEnvFile):
1115 os.remove(PrebuildEnvFile)
1116 if os.path.isfile(self.PlatformBuildPath):
1117 os.remove(self.PlatformBuildPath)
1118 if sys.platform == "win32":
1119 args = ' && '.join((self.Prebuild, 'set > ' + PrebuildEnvFile))
1120 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)
1121 else:
1122 args = ' && '.join((self.Prebuild, 'env > ' + PrebuildEnvFile))
1123 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)
1124
1125 # launch two threads to read the STDOUT and STDERR
1126 EndOfProcedure = Event()
1127 EndOfProcedure.clear()
1128 if Process.stdout:
1129 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))
1130 StdOutThread.setName("STDOUT-Redirector")
1131 StdOutThread.setDaemon(False)
1132 StdOutThread.start()
1133
1134 if Process.stderr:
1135 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))
1136 StdErrThread.setName("STDERR-Redirector")
1137 StdErrThread.setDaemon(False)
1138 StdErrThread.start()
1139 # waiting for program exit
1140 Process.wait()
1141
1142 if Process.stdout:
1143 StdOutThread.join()
1144 if Process.stderr:
1145 StdErrThread.join()
1146 if Process.returncode != 0 :
1147 EdkLogger.error("Prebuild", PREBUILD_ERROR, 'Prebuild process is not success!')
1148
1149 if os.path.exists(PrebuildEnvFile):
1150 f = open(PrebuildEnvFile)
1151 envs = f.readlines()
1152 f.close()
1153 envs = [l.split("=", 1) for l in envs ]
1154 envs = [[I.strip() for I in item] for item in envs if len(item) == 2]
1155 os.environ.update(dict(envs))
1156 EdkLogger.info("\n- Prebuild Done -\n")
1157
1158 def LaunchPostbuild(self):
1159 if self.Postbuild:
1160 EdkLogger.info("\n- Postbuild Start -\n")
1161 if sys.platform == "win32":
1162 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)
1163 else:
1164 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)
1165 # launch two threads to read the STDOUT and STDERR
1166 EndOfProcedure = Event()
1167 EndOfProcedure.clear()
1168 if Process.stdout:
1169 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))
1170 StdOutThread.setName("STDOUT-Redirector")
1171 StdOutThread.setDaemon(False)
1172 StdOutThread.start()
1173
1174 if Process.stderr:
1175 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))
1176 StdErrThread.setName("STDERR-Redirector")
1177 StdErrThread.setDaemon(False)
1178 StdErrThread.start()
1179 # waiting for program exit
1180 Process.wait()
1181
1182 if Process.stdout:
1183 StdOutThread.join()
1184 if Process.stderr:
1185 StdErrThread.join()
1186 if Process.returncode != 0 :
1187 EdkLogger.error("Postbuild", POSTBUILD_ERROR, 'Postbuild process is not success!')
1188 EdkLogger.info("\n- Postbuild Done -\n")
1189
1190 ## Build a module or platform
1191 #
1192 # Create autogen code and makefile for a module or platform, and the launch
1193 # "make" command to build it
1194 #
1195 # @param Target The target of build command
1196 # @param Platform The platform file
1197 # @param Module The module file
1198 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1199 # @param ToolChain The name of toolchain to build
1200 # @param Arch The arch of the module/platform
1201 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1202 # for dependent modules/Libraries
1203 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1204 # for dependent modules/Libraries
1205 #
1206 def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False, FfsCommand=None, PcdMaList=None):
1207 if AutoGenObject is None:
1208 return False
1209 if FfsCommand is None:
1210 FfsCommand = {}
1211 # skip file generation for cleanxxx targets, run and fds target
1212 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1213 # for target which must generate AutoGen code and makefile
1214 mqueue = mp.Queue()
1215 for m in AutoGenObject.GetAllModuleInfo:
1216 mqueue.put(m)
1217
1218 AutoGenObject.DataPipe.DataContainer = {"CommandTarget": self.Target}
1219 AutoGenObject.DataPipe.DataContainer = {"Workspace_timestamp": AutoGenObject.Workspace._SrcTimeStamp}
1220 AutoGenObject.CreateLibModuelDirs()
1221 AutoGenObject.DataPipe.DataContainer = {"LibraryBuildDirectoryList":AutoGenObject.LibraryBuildDirectoryList}
1222 AutoGenObject.DataPipe.DataContainer = {"ModuleBuildDirectoryList":AutoGenObject.ModuleBuildDirectoryList}
1223 AutoGenObject.DataPipe.DataContainer = {"FdsCommandDict": AutoGenObject.Workspace.GenFdsCommandDict}
1224 self.Progress.Start("Generating makefile and code")
1225 data_pipe_file = os.path.join(AutoGenObject.BuildDir, "GlobalVar_%s_%s.bin" % (str(AutoGenObject.Guid),AutoGenObject.Arch))
1226 AutoGenObject.DataPipe.dump(data_pipe_file)
1227 cqueue = mp.Queue()
1228 autogen_rt,errorcode = self.StartAutoGen(mqueue, AutoGenObject.DataPipe, self.SkipAutoGen, PcdMaList, cqueue)
1229 AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt")
1230 with open(AutoGenIdFile,"w") as fw:
1231 fw.write("Arch=%s\n" % "|".join((AutoGenObject.Workspace.ArchList)))
1232 fw.write("BuildDir=%s\n" % AutoGenObject.Workspace.BuildDir)
1233 fw.write("PlatformGuid=%s\n" % str(AutoGenObject.Guid))
1234 self.Progress.Stop("done!")
1235 if not autogen_rt:
1236 self.AutoGenMgr.TerminateWorkers()
1237 self.AutoGenMgr.join(1)
1238 raise FatalError(errorcode)
1239 AutoGenObject.CreateCodeFile(False)
1240 AutoGenObject.CreateMakeFile(False)
1241 else:
1242 # always recreate top/platform makefile when clean, just in case of inconsistency
1243 AutoGenObject.CreateCodeFile(True)
1244 AutoGenObject.CreateMakeFile(True)
1245
1246 if EdkLogger.GetLevel() == EdkLogger.QUIET:
1247 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
1248
1249 BuildCommand = AutoGenObject.BuildCommand
1250 if BuildCommand is None or len(BuildCommand) == 0:
1251 EdkLogger.error("build", OPTION_MISSING,
1252 "No build command found for this module. "
1253 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1254 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
1255 ExtraData=str(AutoGenObject))
1256
1257 # run
1258 if Target == 'run':
1259 return True
1260
1261 # build modules
1262 if BuildModule:
1263 BuildCommand = BuildCommand + [Target]
1264 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
1265 self.CreateAsBuiltInf()
1266 if GlobalData.gBinCacheDest:
1267 self.GenDestCache()
1268 elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:
1269 # Only for --hash
1270 # Update PreMakeCacheChain files
1271 self.GenLocalPreMakeCache()
1272 self.BuildModules = []
1273 return True
1274
1275 # build library
1276 if Target == 'libraries':
1277 DirList = []
1278 for Lib in AutoGenObject.LibraryAutoGenList:
1279 if not Lib.IsBinaryModule:
1280 DirList.append((os.path.join(AutoGenObject.BuildDir, Lib.BuildDir),Lib))
1281 for Lib, LibAutoGen in DirList:
1282 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, self.MakeFileName)), 'pbuild']
1283 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,LibAutoGen)
1284 return True
1285
1286 # build module
1287 if Target == 'modules':
1288 DirList = []
1289 for Lib in AutoGenObject.LibraryAutoGenList:
1290 if not Lib.IsBinaryModule:
1291 DirList.append((os.path.join(AutoGenObject.BuildDir, Lib.BuildDir),Lib))
1292 for Lib, LibAutoGen in DirList:
1293 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, self.MakeFileName)), 'pbuild']
1294 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,LibAutoGen)
1295
1296 DirList = []
1297 for ModuleAutoGen in AutoGenObject.ModuleAutoGenList:
1298 if not ModuleAutoGen.IsBinaryModule:
1299 DirList.append((os.path.join(AutoGenObject.BuildDir, ModuleAutoGen.BuildDir),ModuleAutoGen))
1300 for Mod,ModAutoGen in DirList:
1301 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, self.MakeFileName)), 'pbuild']
1302 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,ModAutoGen)
1303 self.CreateAsBuiltInf()
1304 if GlobalData.gBinCacheDest:
1305 self.GenDestCache()
1306 elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:
1307 # Only for --hash
1308 # Update PreMakeCacheChain files
1309 self.GenLocalPreMakeCache()
1310 self.BuildModules = []
1311 return True
1312
1313 # cleanlib
1314 if Target == 'cleanlib':
1315 for Lib in AutoGenObject.LibraryBuildDirectoryList:
1316 LibMakefile = os.path.normpath(os.path.join(Lib, self.MakeFileName))
1317 if os.path.exists(LibMakefile):
1318 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
1319 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1320 return True
1321
1322 # clean
1323 if Target == 'clean':
1324 for Mod in AutoGenObject.ModuleBuildDirectoryList:
1325 ModMakefile = os.path.normpath(os.path.join(Mod, self.MakeFileName))
1326 if os.path.exists(ModMakefile):
1327 NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']
1328 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1329 for Lib in AutoGenObject.LibraryBuildDirectoryList:
1330 LibMakefile = os.path.normpath(os.path.join(Lib, self.MakeFileName))
1331 if os.path.exists(LibMakefile):
1332 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
1333 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1334 return True
1335
1336 # cleanall
1337 if Target == 'cleanall':
1338 try:
1339 #os.rmdir(AutoGenObject.BuildDir)
1340 RemoveDirectory(AutoGenObject.BuildDir, True)
1341 except WindowsError as X:
1342 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
1343 return True
1344
1345 ## Build a module or platform
1346 #
1347 # Create autogen code and makefile for a module or platform, and the launch
1348 # "make" command to build it
1349 #
1350 # @param Target The target of build command
1351 # @param Platform The platform file
1352 # @param Module The module file
1353 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1354 # @param ToolChain The name of toolchain to build
1355 # @param Arch The arch of the module/platform
1356 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1357 # for dependent modules/Libraries
1358 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1359 # for dependent modules/Libraries
1360 #
1361 def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):
1362 if AutoGenObject is None:
1363 return False
1364
1365 # skip file generation for cleanxxx targets, run and fds target
1366 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1367 # for target which must generate AutoGen code and makefile
1368 if not self.SkipAutoGen or Target == 'genc':
1369 self.Progress.Start("Generating code")
1370 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
1371 self.Progress.Stop("done!")
1372 if Target == "genc":
1373 return True
1374
1375 if not self.SkipAutoGen or Target == 'genmake':
1376 self.Progress.Start("Generating makefile")
1377 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)
1378 #AutoGenObject.CreateAsBuiltInf()
1379 self.Progress.Stop("done!")
1380 if Target == "genmake":
1381 return True
1382 else:
1383 # always recreate top/platform makefile when clean, just in case of inconsistency
1384 AutoGenObject.CreateCodeFile(True)
1385 AutoGenObject.CreateMakeFile(True)
1386
1387 if EdkLogger.GetLevel() == EdkLogger.QUIET:
1388 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
1389
1390 BuildCommand = AutoGenObject.BuildCommand
1391 if BuildCommand is None or len(BuildCommand) == 0:
1392 EdkLogger.error("build", OPTION_MISSING,
1393 "No build command found for this module. "
1394 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1395 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
1396 ExtraData=str(AutoGenObject))
1397
1398 # build modules
1399 if BuildModule:
1400 if Target != 'fds':
1401 BuildCommand = BuildCommand + [Target]
1402 AutoGenObject.BuildTime = LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
1403 self.CreateAsBuiltInf()
1404 if GlobalData.gBinCacheDest:
1405 self.GenDestCache()
1406 elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:
1407 # Only for --hash
1408 # Update PreMakeCacheChain files
1409 self.GenLocalPreMakeCache()
1410 self.BuildModules = []
1411 return True
1412
1413 # genfds
1414 if Target == 'fds':
1415 if GenFdsApi(AutoGenObject.GenFdsCommandDict, self.Db):
1416 EdkLogger.error("build", COMMAND_FAILURE)
1417 Threshold = self.GetFreeSizeThreshold()
1418 if Threshold:
1419 self.CheckFreeSizeThreshold(Threshold, AutoGenObject.FvDir)
1420 return True
1421
1422 # run
1423 if Target == 'run':
1424 return True
1425
1426 # build library
1427 if Target == 'libraries':
1428 pass
1429
1430 # not build modules
1431
1432
1433 # cleanall
1434 if Target == 'cleanall':
1435 try:
1436 #os.rmdir(AutoGenObject.BuildDir)
1437 RemoveDirectory(AutoGenObject.BuildDir, True)
1438 except WindowsError as X:
1439 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
1440 return True
1441
1442 ## Rebase module image and Get function address for the input module list.
1443 #
1444 def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):
1445 if ModeIsSmm:
1446 AddrIsOffset = False
1447 for InfFile in ModuleList:
1448 sys.stdout.write (".")
1449 sys.stdout.flush()
1450 ModuleInfo = ModuleList[InfFile]
1451 ModuleName = ModuleInfo.BaseName
1452 ModuleOutputImage = ModuleInfo.Image.FileName
1453 ModuleDebugImage = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')
1454 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1455 if not ModeIsSmm:
1456 BaseAddress = BaseAddress - ModuleInfo.Image.Size
1457 #
1458 # Update Image to new BaseAddress by GenFw tool
1459 #
1460 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
1461 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
1462 else:
1463 #
1464 # Set new address to the section header only for SMM driver.
1465 #
1466 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
1467 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
1468 #
1469 # Collect function address from Map file
1470 #
1471 ImageMapTable = ModuleOutputImage.replace('.efi', '.map')
1472 FunctionList = []
1473 if os.path.exists(ImageMapTable):
1474 OrigImageBaseAddress = 0
1475 ImageMap = open(ImageMapTable, 'r')
1476 for LinStr in ImageMap:
1477 if len (LinStr.strip()) == 0:
1478 continue
1479 #
1480 # Get the preferred address set on link time.
1481 #
1482 if LinStr.find ('Preferred load address is') != -1:
1483 StrList = LinStr.split()
1484 OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)
1485
1486 StrList = LinStr.split()
1487 if len (StrList) > 4:
1488 if StrList[3] == 'f' or StrList[3] == 'F':
1489 Name = StrList[1]
1490 RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress
1491 FunctionList.append ((Name, RelativeAddress))
1492
1493 ImageMap.close()
1494 #
1495 # Add general information.
1496 #
1497 if ModeIsSmm:
1498 MapBuffer.append('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
1499 elif AddrIsOffset:
1500 MapBuffer.append('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))
1501 else:
1502 MapBuffer.append('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
1503 #
1504 # Add guid and general seciton section.
1505 #
1506 TextSectionAddress = 0
1507 DataSectionAddress = 0
1508 for SectionHeader in ModuleInfo.Image.SectionHeaderList:
1509 if SectionHeader[0] == '.text':
1510 TextSectionAddress = SectionHeader[1]
1511 elif SectionHeader[0] in ['.data', '.sdata']:
1512 DataSectionAddress = SectionHeader[1]
1513 if AddrIsOffset:
1514 MapBuffer.append('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))
1515 else:
1516 MapBuffer.append('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))
1517 #
1518 # Add debug image full path.
1519 #
1520 MapBuffer.append('(IMAGE=%s)\n\n' % (ModuleDebugImage))
1521 #
1522 # Add function address
1523 #
1524 for Function in FunctionList:
1525 if AddrIsOffset:
1526 MapBuffer.append(' -0x%010X %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))
1527 else:
1528 MapBuffer.append(' 0x%010X %s\n' % (BaseAddress + Function[1], Function[0]))
1529 ImageMap.close()
1530
1531 #
1532 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1533 #
1534 if ModeIsSmm:
1535 BaseAddress = BaseAddress + ModuleInfo.Image.Size
1536
1537 ## Collect MAP information of all FVs
1538 #
1539 def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):
1540 if self.Fdf:
1541 # First get the XIP base address for FV map file.
1542 GuidPattern = re.compile("[-a-fA-F0-9]+")
1543 GuidName = re.compile(r"\(GUID=[-a-fA-F0-9]+")
1544 for FvName in Wa.FdfProfile.FvDict:
1545 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')
1546 if not os.path.exists(FvMapBuffer):
1547 continue
1548 FvMap = open(FvMapBuffer, 'r')
1549 #skip FV size information
1550 FvMap.readline()
1551 FvMap.readline()
1552 FvMap.readline()
1553 FvMap.readline()
1554 for Line in FvMap:
1555 MatchGuid = GuidPattern.match(Line)
1556 if MatchGuid is not None:
1557 #
1558 # Replace GUID with module name
1559 #
1560 GuidString = MatchGuid.group()
1561 if GuidString.upper() in ModuleList:
1562 Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)
1563 MapBuffer.append(Line)
1564 #
1565 # Add the debug image full path.
1566 #
1567 MatchGuid = GuidName.match(Line)
1568 if MatchGuid is not None:
1569 GuidString = MatchGuid.group().split("=")[1]
1570 if GuidString.upper() in ModuleList:
1571 MapBuffer.append('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))
1572
1573 FvMap.close()
1574
1575 ## Collect MAP information of all modules
1576 #
1577 def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):
1578 sys.stdout.write ("Generate Load Module At Fix Address Map")
1579 sys.stdout.flush()
1580 PatchEfiImageList = []
1581 PeiModuleList = {}
1582 BtModuleList = {}
1583 RtModuleList = {}
1584 SmmModuleList = {}
1585 PeiSize = 0
1586 BtSize = 0
1587 RtSize = 0
1588 # reserve 4K size in SMRAM to make SMM module address not from 0.
1589 SmmSize = 0x1000
1590 for ModuleGuid in ModuleList:
1591 Module = ModuleList[ModuleGuid]
1592 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)
1593
1594 OutputImageFile = ''
1595 for ResultFile in Module.CodaTargetList:
1596 if str(ResultFile.Target).endswith('.efi'):
1597 #
1598 # module list for PEI, DXE, RUNTIME and SMM
1599 #
1600 OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')
1601 ImageClass = PeImageClass (OutputImageFile)
1602 if not ImageClass.IsValid:
1603 EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)
1604 ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)
1605 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]:
1606 PeiModuleList[Module.MetaFile] = ImageInfo
1607 PeiSize += ImageInfo.Image.Size
1608 elif Module.ModuleType in [EDK_COMPONENT_TYPE_BS_DRIVER, SUP_MODULE_DXE_DRIVER, SUP_MODULE_UEFI_DRIVER]:
1609 BtModuleList[Module.MetaFile] = ImageInfo
1610 BtSize += ImageInfo.Image.Size
1611 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]:
1612 RtModuleList[Module.MetaFile] = ImageInfo
1613 RtSize += ImageInfo.Image.Size
1614 elif Module.ModuleType in [SUP_MODULE_SMM_CORE, SUP_MODULE_DXE_SMM_DRIVER, SUP_MODULE_MM_STANDALONE, SUP_MODULE_MM_CORE_STANDALONE]:
1615 SmmModuleList[Module.MetaFile] = ImageInfo
1616 SmmSize += ImageInfo.Image.Size
1617 if Module.ModuleType == SUP_MODULE_DXE_SMM_DRIVER:
1618 PiSpecVersion = Module.Module.Specification.get('PI_SPECIFICATION_VERSION', '0x00000000')
1619 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1620 if int(PiSpecVersion, 16) < 0x0001000A:
1621 BtModuleList[Module.MetaFile] = ImageInfo
1622 BtSize += ImageInfo.Image.Size
1623 break
1624 #
1625 # EFI image is final target.
1626 # Check EFI image contains patchable FixAddress related PCDs.
1627 #
1628 if OutputImageFile != '':
1629 ModuleIsPatch = False
1630 for Pcd in Module.ModulePcdList:
1631 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:
1632 ModuleIsPatch = True
1633 break
1634 if not ModuleIsPatch:
1635 for Pcd in Module.LibraryPcdList:
1636 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:
1637 ModuleIsPatch = True
1638 break
1639
1640 if not ModuleIsPatch:
1641 continue
1642 #
1643 # Module includes the patchable load fix address PCDs.
1644 # It will be fixed up later.
1645 #
1646 PatchEfiImageList.append (OutputImageFile)
1647
1648 #
1649 # Get Top Memory address
1650 #
1651 ReservedRuntimeMemorySize = 0
1652 TopMemoryAddress = 0
1653 if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:
1654 TopMemoryAddress = 0
1655 else:
1656 TopMemoryAddress = self.LoadFixAddress
1657 if TopMemoryAddress < RtSize + BtSize + PeiSize:
1658 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1659
1660 #
1661 # Patch FixAddress related PCDs into EFI image
1662 #
1663 for EfiImage in PatchEfiImageList:
1664 EfiImageMap = EfiImage.replace('.efi', '.map')
1665 if not os.path.exists(EfiImageMap):
1666 continue
1667 #
1668 # Get PCD offset in EFI image by GenPatchPcdTable function
1669 #
1670 PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)
1671 #
1672 # Patch real PCD value by PatchPcdValue tool
1673 #
1674 for PcdInfo in PcdTable:
1675 ReturnValue = 0
1676 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:
1677 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize // 0x1000))
1678 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:
1679 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize // 0x1000))
1680 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:
1681 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize // 0x1000))
1682 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:
1683 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize // 0x1000))
1684 if ReturnValue != 0:
1685 EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)
1686
1687 MapBuffer.append('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize // 0x1000))
1688 MapBuffer.append('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize // 0x1000))
1689 MapBuffer.append('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize // 0x1000))
1690 if len (SmmModuleList) > 0:
1691 MapBuffer.append('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize // 0x1000))
1692
1693 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize
1694 BtBaseAddr = TopMemoryAddress - RtSize
1695 RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize
1696
1697 self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)
1698 self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)
1699 self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)
1700 self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset=False, ModeIsSmm=True)
1701 MapBuffer.append('\n\n')
1702 sys.stdout.write ("\n")
1703 sys.stdout.flush()
1704
1705 ## Save platform Map file
1706 #
1707 def _SaveMapFile (self, MapBuffer, Wa):
1708 #
1709 # Map file path is got.
1710 #
1711 MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')
1712 #
1713 # Save address map into MAP file.
1714 #
1715 SaveFileOnChange(MapFilePath, ''.join(MapBuffer), False)
1716 if self.LoadFixAddress != 0:
1717 sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath))
1718 sys.stdout.flush()
1719
1720 ## Build active platform for different build targets and different tool chains
1721 #
1722 def _BuildPlatform(self):
1723 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1724 for BuildTarget in self.BuildTargetList:
1725 GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1726 index = 0
1727 for ToolChain in self.ToolChainList:
1728 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1729 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1730 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
1731 index += 1
1732 Wa = WorkspaceAutoGen(
1733 self.WorkspaceDir,
1734 self.PlatformFile,
1735 BuildTarget,
1736 ToolChain,
1737 self.ArchList,
1738 self.BuildDatabase,
1739 self.TargetTxt,
1740 self.ToolDef,
1741 self.Fdf,
1742 self.FdList,
1743 self.FvList,
1744 self.CapList,
1745 self.SkuId,
1746 self.UniFlag,
1747 self.Progress
1748 )
1749 self.Fdf = Wa.FdfFile
1750 self.LoadFixAddress = Wa.Platform.LoadFixAddress
1751 self.BuildReport.AddPlatformReport(Wa)
1752 self.Progress.Stop("done!")
1753
1754 # Add ffs build to makefile
1755 CmdListDict = {}
1756 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:
1757 CmdListDict = self._GenFfsCmd(Wa.ArchList)
1758
1759 for Arch in Wa.ArchList:
1760 PcdMaList = []
1761 GlobalData.gGlobalDefines['ARCH'] = Arch
1762 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
1763 for Module in Pa.Platform.Modules:
1764 # Get ModuleAutoGen object to generate C code file and makefile
1765 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)
1766 if Ma is None:
1767 continue
1768 if Ma.PcdIsDriver:
1769 Ma.PlatformInfo = Pa
1770 Ma.Workspace = Wa
1771 PcdMaList.append(Ma)
1772 self.BuildModules.append(Ma)
1773 Pa.DataPipe.DataContainer = {"FfsCommand":CmdListDict}
1774 Pa.DataPipe.DataContainer = {"Workspace_timestamp": Wa._SrcTimeStamp}
1775 self._BuildPa(self.Target, Pa, FfsCommand=CmdListDict,PcdMaList=PcdMaList)
1776
1777 # Create MAP file when Load Fix Address is enabled.
1778 if self.Target in ["", "all", "fds"]:
1779 for Arch in Wa.ArchList:
1780 GlobalData.gGlobalDefines['ARCH'] = Arch
1781 #
1782 # Check whether the set fix address is above 4G for 32bit image.
1783 #
1784 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1785 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")
1786 #
1787 # Get Module List
1788 #
1789 ModuleList = {}
1790 for Pa in Wa.AutoGenObjectList:
1791 for Ma in Pa.ModuleAutoGenList:
1792 if Ma is None:
1793 continue
1794 if not Ma.IsLibrary:
1795 ModuleList[Ma.Guid.upper()] = Ma
1796
1797 MapBuffer = []
1798 if self.LoadFixAddress != 0:
1799 #
1800 # Rebase module to the preferred memory address before GenFds
1801 #
1802 self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1803 if self.Fdf:
1804 #
1805 # create FDS again for the updated EFI image
1806 #
1807 self._Build("fds", Wa)
1808 #
1809 # Create MAP file for all platform FVs after GenFds.
1810 #
1811 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1812 #
1813 # Save MAP buffer into MAP file.
1814 #
1815 self._SaveMapFile (MapBuffer, Wa)
1816 self.CreateGuidedSectionToolsFile(Wa)
1817
1818 ## Build active module for different build targets, different tool chains and different archs
1819 #
1820 def _BuildModule(self):
1821 for BuildTarget in self.BuildTargetList:
1822 GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1823 index = 0
1824 for ToolChain in self.ToolChainList:
1825 WorkspaceAutoGenTime = time.time()
1826 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1827 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1828 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
1829 index += 1
1830 #
1831 # module build needs platform build information, so get platform
1832 # AutoGen first
1833 #
1834 Wa = WorkspaceAutoGen(
1835 self.WorkspaceDir,
1836 self.PlatformFile,
1837 BuildTarget,
1838 ToolChain,
1839 self.ArchList,
1840 self.BuildDatabase,
1841 self.TargetTxt,
1842 self.ToolDef,
1843 self.Fdf,
1844 self.FdList,
1845 self.FvList,
1846 self.CapList,
1847 self.SkuId,
1848 self.UniFlag,
1849 self.Progress,
1850 self.ModuleFile
1851 )
1852 self.Fdf = Wa.FdfFile
1853 self.LoadFixAddress = Wa.Platform.LoadFixAddress
1854 Wa.CreateMakeFile(False)
1855 # Add ffs build to makefile
1856 CmdListDict = None
1857 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:
1858 CmdListDict = self._GenFfsCmd(Wa.ArchList)
1859
1860 GlobalData.file_lock = mp.Lock()
1861 GlobalData.FfsCmd = CmdListDict
1862
1863 self.Progress.Stop("done!")
1864 MaList = []
1865 ExitFlag = threading.Event()
1866 ExitFlag.clear()
1867 self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))
1868 for Arch in Wa.ArchList:
1869 AutoGenStart = time.time()
1870 GlobalData.gGlobalDefines['ARCH'] = Arch
1871 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
1872 for Module in Pa.Platform.Modules:
1873 if self.ModuleFile.Dir == Module.Dir and self.ModuleFile.Name == Module.Name:
1874 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)
1875 if Ma is None:
1876 continue
1877 if Ma.PcdIsDriver:
1878 Ma.PlatformInfo = Pa
1879 Ma.Workspace = Wa
1880 MaList.append(Ma)
1881
1882 if GlobalData.gUseHashCache and not GlobalData.gBinCacheDest and self.Target in [None, "", "all"]:
1883 if Ma.CanSkipbyPreMakeCache():
1884 continue
1885 else:
1886 self.PreMakeCacheMiss.add(Ma)
1887
1888 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1889 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1890 # for target which must generate AutoGen code and makefile
1891 if not self.SkipAutoGen or self.Target == 'genc':
1892 self.Progress.Start("Generating code")
1893 Ma.CreateCodeFile(True)
1894 self.Progress.Stop("done!")
1895 if self.Target == "genc":
1896 return True
1897 if not self.SkipAutoGen or self.Target == 'genmake':
1898 self.Progress.Start("Generating makefile")
1899 if CmdListDict and self.Fdf and (Module.Path, Arch) in CmdListDict:
1900 Ma.CreateMakeFile(True, CmdListDict[Module.Path, Arch])
1901 del CmdListDict[Module.Path, Arch]
1902 else:
1903 Ma.CreateMakeFile(True)
1904 self.Progress.Stop("done!")
1905 if self.Target == "genmake":
1906 return True
1907
1908 if GlobalData.gBinCacheSource and self.Target in [None, "", "all"]:
1909 if Ma.CanSkipbyMakeCache():
1910 continue
1911 else:
1912 self.MakeCacheMiss.add(Ma)
1913
1914 self.BuildModules.append(Ma)
1915 self.AutoGenTime += int(round((time.time() - AutoGenStart)))
1916 MakeStart = time.time()
1917 for Ma in self.BuildModules:
1918 if not Ma.IsBinaryModule:
1919 Bt = BuildTask.New(ModuleMakeUnit(Ma, Pa.BuildCommand,self.Target))
1920 # Break build if any build thread has error
1921 if BuildTask.HasError():
1922 # we need a full version of makefile for platform
1923 ExitFlag.set()
1924 BuildTask.WaitForComplete()
1925 Pa.CreateMakeFile(False)
1926 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1927 # Start task scheduler
1928 if not BuildTask.IsOnGoing():
1929 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
1930
1931 # in case there's an interruption. we need a full version of makefile for platform
1932 Pa.CreateMakeFile(False)
1933 if BuildTask.HasError():
1934 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1935 self.MakeTime += int(round((time.time() - MakeStart)))
1936
1937 MakeContiue = time.time()
1938 ExitFlag.set()
1939 BuildTask.WaitForComplete()
1940 self.CreateAsBuiltInf()
1941 if GlobalData.gBinCacheDest:
1942 self.GenDestCache()
1943 elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:
1944 # Only for --hash
1945 # Update PreMakeCacheChain files
1946 self.GenLocalPreMakeCache()
1947 self.BuildModules = []
1948 self.MakeTime += int(round((time.time() - MakeContiue)))
1949 if BuildTask.HasError():
1950 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1951
1952 self.BuildReport.AddPlatformReport(Wa, MaList)
1953 if MaList == []:
1954 EdkLogger.error(
1955 'build',
1956 BUILD_ERROR,
1957 "Module for [%s] is not a component of active platform."\
1958 " Please make sure that the ARCH and inf file path are"\
1959 " given in the same as in [%s]" % \
1960 (', '.join(Wa.ArchList), self.PlatformFile),
1961 ExtraData=self.ModuleFile
1962 )
1963 # Create MAP file when Load Fix Address is enabled.
1964 if self.Target == "fds" and self.Fdf:
1965 for Arch in Wa.ArchList:
1966 #
1967 # Check whether the set fix address is above 4G for 32bit image.
1968 #
1969 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1970 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")
1971 #
1972 # Get Module List
1973 #
1974 ModuleList = {}
1975 for Pa in Wa.AutoGenObjectList:
1976 for Ma in Pa.ModuleAutoGenList:
1977 if Ma is None:
1978 continue
1979 if not Ma.IsLibrary:
1980 ModuleList[Ma.Guid.upper()] = Ma
1981
1982 MapBuffer = []
1983 if self.LoadFixAddress != 0:
1984 #
1985 # Rebase module to the preferred memory address before GenFds
1986 #
1987 self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1988 #
1989 # create FDS again for the updated EFI image
1990 #
1991 GenFdsStart = time.time()
1992 self._Build("fds", Wa)
1993 self.GenFdsTime += int(round((time.time() - GenFdsStart)))
1994 #
1995 # Create MAP file for all platform FVs after GenFds.
1996 #
1997 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1998 #
1999 # Save MAP buffer into MAP file.
2000 #
2001 self._SaveMapFile (MapBuffer, Wa)
2002
2003 def _GenFfsCmd(self,ArchList):
2004 # convert dictionary of Cmd:(Inf,Arch)
2005 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...
2006 CmdSetDict = defaultdict(set)
2007 GenFfsDict = GenFds.GenFfsMakefile('', GlobalData.gFdfParser, self, ArchList, GlobalData)
2008 for Cmd in GenFfsDict:
2009 tmpInf, tmpArch = GenFfsDict[Cmd]
2010 CmdSetDict[tmpInf, tmpArch].add(Cmd)
2011 return CmdSetDict
2012 def VerifyAutoGenFiles(self):
2013 AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt")
2014 try:
2015 with open(AutoGenIdFile) as fd:
2016 lines = fd.readlines()
2017 except:
2018 return None
2019 for line in lines:
2020 if "Arch" in line:
2021 ArchList = line.strip().split("=")[1].split("|")
2022 if "BuildDir" in line:
2023 BuildDir = line.split("=")[1].strip()
2024 if "PlatformGuid" in line:
2025 PlatformGuid = line.split("=")[1].strip()
2026 GlobalVarList = []
2027 for arch in ArchList:
2028 global_var = os.path.join(BuildDir, "GlobalVar_%s_%s.bin" % (str(PlatformGuid),arch))
2029 if not os.path.exists(global_var):
2030 return None
2031 GlobalVarList.append(global_var)
2032 for global_var in GlobalVarList:
2033 data_pipe = MemoryDataPipe()
2034 data_pipe.load(global_var)
2035 target = data_pipe.Get("P_Info").get("Target")
2036 toolchain = data_pipe.Get("P_Info").get("ToolChain")
2037 archlist = data_pipe.Get("P_Info").get("ArchList")
2038 Arch = data_pipe.Get("P_Info").get("Arch")
2039 active_p = data_pipe.Get("P_Info").get("ActivePlatform")
2040 workspacedir = data_pipe.Get("P_Info").get("WorkspaceDir")
2041 PackagesPath = os.getenv("PACKAGES_PATH")
2042 mws.setWs(workspacedir, PackagesPath)
2043 LibraryBuildDirectoryList = data_pipe.Get("LibraryBuildDirectoryList")
2044 ModuleBuildDirectoryList = data_pipe.Get("ModuleBuildDirectoryList")
2045
2046 for m_build_dir in LibraryBuildDirectoryList:
2047 if not os.path.exists(os.path.join(m_build_dir,self.MakeFileName)):
2048 return None
2049 for m_build_dir in ModuleBuildDirectoryList:
2050 if not os.path.exists(os.path.join(m_build_dir,self.MakeFileName)):
2051 return None
2052 Wa = WorkSpaceInfo(
2053 workspacedir,active_p,target,toolchain,archlist
2054 )
2055 Pa = PlatformInfo(Wa, active_p, target, toolchain, Arch,data_pipe)
2056 Wa.AutoGenObjectList.append(Pa)
2057 return Wa
2058 def SetupMakeSetting(self,Wa):
2059 BuildModules = []
2060 for Pa in Wa.AutoGenObjectList:
2061 for m in Pa._MbList:
2062 ma = ModuleAutoGen(Wa,m.MetaFile, Pa.BuildTarget, Wa.ToolChain, Pa.Arch, Pa.MetaFile,Pa.DataPipe)
2063 BuildModules.append(ma)
2064 fdf_file = Wa.FlashDefinition
2065 if fdf_file:
2066 Fdf = FdfParser(fdf_file.Path)
2067 Fdf.ParseFile()
2068 GlobalData.gFdfParser = Fdf
2069 if Fdf.CurrentFdName and Fdf.CurrentFdName in Fdf.Profile.FdDict:
2070 FdDict = Fdf.Profile.FdDict[Fdf.CurrentFdName]
2071 for FdRegion in FdDict.RegionList:
2072 if str(FdRegion.RegionType) == 'FILE' and self.Platform.VpdToolGuid in str(FdRegion.RegionDataList):
2073 if int(FdRegion.Offset) % 8 != 0:
2074 EdkLogger.error("build", FORMAT_INVALID, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion.Offset))
2075 Wa.FdfProfile = Fdf.Profile
2076 self.Fdf = Fdf
2077 else:
2078 self.Fdf = None
2079 return BuildModules
2080
2081 ## Build a platform in multi-thread mode
2082 #
2083 def PerformAutoGen(self,BuildTarget,ToolChain):
2084 WorkspaceAutoGenTime = time.time()
2085 Wa = WorkspaceAutoGen(
2086 self.WorkspaceDir,
2087 self.PlatformFile,
2088 BuildTarget,
2089 ToolChain,
2090 self.ArchList,
2091 self.BuildDatabase,
2092 self.TargetTxt,
2093 self.ToolDef,
2094 self.Fdf,
2095 self.FdList,
2096 self.FvList,
2097 self.CapList,
2098 self.SkuId,
2099 self.UniFlag,
2100 self.Progress
2101 )
2102 self.Fdf = Wa.FdfFile
2103 self.LoadFixAddress = Wa.Platform.LoadFixAddress
2104 self.BuildReport.AddPlatformReport(Wa)
2105 Wa.CreateMakeFile(False)
2106
2107 # Add ffs build to makefile
2108 CmdListDict = {}
2109 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:
2110 CmdListDict = self._GenFfsCmd(Wa.ArchList)
2111
2112 self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))
2113 BuildModules = []
2114 for Arch in Wa.ArchList:
2115 PcdMaList = []
2116 AutoGenStart = time.time()
2117 GlobalData.gGlobalDefines['ARCH'] = Arch
2118 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
2119 if Pa is None:
2120 continue
2121 ModuleList = []
2122 for Inf in Pa.Platform.Modules:
2123 ModuleList.append(Inf)
2124 # Add the INF only list in FDF
2125 if GlobalData.gFdfParser is not None:
2126 for InfName in GlobalData.gFdfParser.Profile.InfList:
2127 Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)
2128 if Inf in Pa.Platform.Modules:
2129 continue
2130 ModuleList.append(Inf)
2131 Pa.DataPipe.DataContainer = {"FfsCommand":CmdListDict}
2132 Pa.DataPipe.DataContainer = {"Workspace_timestamp": Wa._SrcTimeStamp}
2133 Pa.DataPipe.DataContainer = {"CommandTarget": self.Target}
2134 Pa.CreateLibModuelDirs()
2135 # Fetch the MakeFileName.
2136 self.MakeFileName = Pa.MakeFileName
2137 if not self.MakeFileName:
2138 self.MakeFileName = Pa.MakeFile
2139
2140 Pa.DataPipe.DataContainer = {"LibraryBuildDirectoryList":Pa.LibraryBuildDirectoryList}
2141 Pa.DataPipe.DataContainer = {"ModuleBuildDirectoryList":Pa.ModuleBuildDirectoryList}
2142 Pa.DataPipe.DataContainer = {"FdsCommandDict": Wa.GenFdsCommandDict}
2143 # Prepare the cache share data for multiprocessing
2144 Pa.DataPipe.DataContainer = {"gPlatformHashFile":GlobalData.gPlatformHashFile}
2145 ModuleCodaFile = {}
2146 for ma in Pa.ModuleAutoGenList:
2147 ModuleCodaFile[(ma.MetaFile.File,ma.MetaFile.Root,ma.Arch,ma.MetaFile.Path)] = [item.Target for item in ma.CodaTargetList]
2148 Pa.DataPipe.DataContainer = {"ModuleCodaFile":ModuleCodaFile}
2149 # ModuleList contains all driver modules only
2150 for Module in ModuleList:
2151 # Get ModuleAutoGen object to generate C code file and makefile
2152 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)
2153 if Ma is None:
2154 continue
2155 if Ma.PcdIsDriver:
2156 Ma.PlatformInfo = Pa
2157 Ma.Workspace = Wa
2158 PcdMaList.append(Ma)
2159 self.AllDrivers.add(Ma)
2160 self.AllModules.add(Ma)
2161
2162 mqueue = mp.Queue()
2163 cqueue = mp.Queue()
2164 for m in Pa.GetAllModuleInfo:
2165 mqueue.put(m)
2166 module_file,module_root,module_path,module_basename,\
2167 module_originalpath,module_arch,IsLib = m
2168 Ma = ModuleAutoGen(Wa, PathClass(module_path, Wa), BuildTarget,\
2169 ToolChain, Arch, self.PlatformFile,Pa.DataPipe)
2170 self.AllModules.add(Ma)
2171 data_pipe_file = os.path.join(Pa.BuildDir, "GlobalVar_%s_%s.bin" % (str(Pa.Guid),Pa.Arch))
2172 Pa.DataPipe.dump(data_pipe_file)
2173
2174 autogen_rt, errorcode = self.StartAutoGen(mqueue, Pa.DataPipe, self.SkipAutoGen, PcdMaList, cqueue)
2175
2176 if not autogen_rt:
2177 self.AutoGenMgr.TerminateWorkers()
2178 self.AutoGenMgr.join(1)
2179 raise FatalError(errorcode)
2180
2181 if GlobalData.gUseHashCache:
2182 for item in GlobalData.gModuleAllCacheStatus:
2183 (MetaFilePath, Arch, CacheStr, Status) = item
2184 Ma = ModuleAutoGen(Wa, PathClass(MetaFilePath, Wa), BuildTarget,\
2185 ToolChain, Arch, self.PlatformFile,Pa.DataPipe)
2186 if CacheStr == "PreMakeCache" and Status == False:
2187 self.PreMakeCacheMiss.add(Ma)
2188 if CacheStr == "PreMakeCache" and Status == True:
2189 self.PreMakeCacheHit.add(Ma)
2190 GlobalData.gModuleCacheHit.add(Ma)
2191 if CacheStr == "MakeCache" and Status == False:
2192 self.MakeCacheMiss.add(Ma)
2193 if CacheStr == "MakeCache" and Status == True:
2194 self.MakeCacheHit.add(Ma)
2195 GlobalData.gModuleCacheHit.add(Ma)
2196 self.AutoGenTime += int(round((time.time() - AutoGenStart)))
2197 AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt")
2198 with open(AutoGenIdFile,"w") as fw:
2199 fw.write("Arch=%s\n" % "|".join((Wa.ArchList)))
2200 fw.write("BuildDir=%s\n" % Wa.BuildDir)
2201 fw.write("PlatformGuid=%s\n" % str(Wa.AutoGenObjectList[0].Guid))
2202
2203 if GlobalData.gBinCacheSource:
2204 BuildModules.extend(self.MakeCacheMiss)
2205 elif GlobalData.gUseHashCache and not GlobalData.gBinCacheDest:
2206 BuildModules.extend(self.PreMakeCacheMiss)
2207 else:
2208 BuildModules.extend(self.AllDrivers)
2209
2210 self.Progress.Stop("done!")
2211 return Wa, BuildModules
2212
2213 def _MultiThreadBuildPlatform(self):
2214 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)
2215 for BuildTarget in self.BuildTargetList:
2216 GlobalData.gGlobalDefines['TARGET'] = BuildTarget
2217 index = 0
2218 for ToolChain in self.ToolChainList:
2219 resetFdsGlobalVariable()
2220 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
2221 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
2222 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
2223 index += 1
2224 ExitFlag = threading.Event()
2225 ExitFlag.clear()
2226 if self.SkipAutoGen:
2227 Wa = self.VerifyAutoGenFiles()
2228 if Wa is None:
2229 self.SkipAutoGen = False
2230 Wa, self.BuildModules = self.PerformAutoGen(BuildTarget,ToolChain)
2231 else:
2232 GlobalData.gAutoGenPhase = True
2233 self.BuildModules = self.SetupMakeSetting(Wa)
2234 else:
2235 Wa, self.BuildModules = self.PerformAutoGen(BuildTarget,ToolChain)
2236 Pa = Wa.AutoGenObjectList[0]
2237 GlobalData.gAutoGenPhase = False
2238
2239 if GlobalData.gBinCacheSource:
2240 EdkLogger.quiet("[cache Summary]: Total module num: %s" % len(self.AllModules))
2241 EdkLogger.quiet("[cache Summary]: PreMakecache miss num: %s " % len(self.PreMakeCacheMiss))
2242 EdkLogger.quiet("[cache Summary]: Makecache miss num: %s " % len(self.MakeCacheMiss))
2243
2244 for Arch in Wa.ArchList:
2245 MakeStart = time.time()
2246 for Ma in set(self.BuildModules):
2247 # Generate build task for the module
2248 if not Ma.IsBinaryModule:
2249 Bt = BuildTask.New(ModuleMakeUnit(Ma, Pa.BuildCommand,self.Target))
2250 # Break build if any build thread has error
2251 if BuildTask.HasError():
2252 # we need a full version of makefile for platform
2253 ExitFlag.set()
2254 BuildTask.WaitForComplete()
2255 Pa.CreateMakeFile(False)
2256 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
2257 # Start task scheduler
2258 if not BuildTask.IsOnGoing():
2259 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
2260
2261 # in case there's an interruption. we need a full version of makefile for platform
2262
2263 if BuildTask.HasError():
2264 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
2265 self.MakeTime += int(round((time.time() - MakeStart)))
2266
2267 MakeContiue = time.time()
2268 #
2269 #
2270 # All modules have been put in build tasks queue. Tell task scheduler
2271 # to exit if all tasks are completed
2272 #
2273 ExitFlag.set()
2274 BuildTask.WaitForComplete()
2275 self.CreateAsBuiltInf()
2276 if GlobalData.gBinCacheDest:
2277 self.GenDestCache()
2278 elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:
2279 # Only for --hash
2280 # Update PreMakeCacheChain files
2281 self.GenLocalPreMakeCache()
2282 #
2283 # Get Module List
2284 #
2285 ModuleList = {ma.Guid.upper(): ma for ma in self.BuildModules}
2286 self.BuildModules = []
2287 self.MakeTime += int(round((time.time() - MakeContiue)))
2288 #
2289 # Check for build error, and raise exception if one
2290 # has been signaled.
2291 #
2292 if BuildTask.HasError():
2293 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
2294
2295 # Create MAP file when Load Fix Address is enabled.
2296 if self.Target in ["", "all", "fds"]:
2297 for Arch in Wa.ArchList:
2298 #
2299 # Check whether the set fix address is above 4G for 32bit image.
2300 #
2301 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
2302 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")
2303
2304 #
2305 # Rebase module to the preferred memory address before GenFds
2306 #
2307 MapBuffer = []
2308 if self.LoadFixAddress != 0:
2309 self._CollectModuleMapBuffer(MapBuffer, ModuleList)
2310
2311 if self.Fdf:
2312 #
2313 # Generate FD image if there's a FDF file found
2314 #
2315 GenFdsStart = time.time()
2316 if GenFdsApi(Wa.GenFdsCommandDict, self.Db):
2317 EdkLogger.error("build", COMMAND_FAILURE)
2318 Threshold = self.GetFreeSizeThreshold()
2319 if Threshold:
2320 self.CheckFreeSizeThreshold(Threshold, Wa.FvDir)
2321
2322 #
2323 # Create MAP file for all platform FVs after GenFds.
2324 #
2325 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
2326 self.GenFdsTime += int(round((time.time() - GenFdsStart)))
2327 #
2328 # Save MAP buffer into MAP file.
2329 #
2330 self._SaveMapFile(MapBuffer, Wa)
2331 self.CreateGuidedSectionToolsFile(Wa)
2332
2333 ## GetFreeSizeThreshold()
2334 #
2335 # @retval int Threshold value
2336 #
2337 def GetFreeSizeThreshold(self):
2338 Threshold = None
2339 Threshold_Str = GlobalData.gCommandLineDefines.get('FV_SPARE_SPACE_THRESHOLD')
2340 if Threshold_Str:
2341 try:
2342 if Threshold_Str.lower().startswith('0x'):
2343 Threshold = int(Threshold_Str, 16)
2344 else:
2345 Threshold = int(Threshold_Str)
2346 except:
2347 EdkLogger.warn("build", 'incorrect value for FV_SPARE_SPACE_THRESHOLD %s.Only decimal or hex format is allowed.' % Threshold_Str)
2348 return Threshold
2349
2350 def CheckFreeSizeThreshold(self, Threshold=None, FvDir=None):
2351 if not isinstance(Threshold, int):
2352 return
2353 if not isinstance(FvDir, str) or not FvDir:
2354 return
2355 FdfParserObject = GlobalData.gFdfParser
2356 FvRegionNameList = [FvName for FvName in FdfParserObject.Profile.FvDict if FdfParserObject.Profile.FvDict[FvName].FvRegionInFD]
2357 for FvName in FdfParserObject.Profile.FvDict:
2358 if FvName in FvRegionNameList:
2359 FvSpaceInfoFileName = os.path.join(FvDir, FvName.upper() + '.Fv.map')
2360 if os.path.exists(FvSpaceInfoFileName):
2361 FileLinesList = getlines(FvSpaceInfoFileName)
2362 for Line in FileLinesList:
2363 NameValue = Line.split('=')
2364 if len(NameValue) == 2 and NameValue[0].strip() == 'EFI_FV_SPACE_SIZE':
2365 FreeSizeValue = int(NameValue[1].strip(), 0)
2366 if FreeSizeValue < Threshold:
2367 EdkLogger.error("build", FV_FREESIZE_ERROR,
2368 '%s FV free space %d is not enough to meet with the required spare space %d set by -D FV_SPARE_SPACE_THRESHOLD option.' % (
2369 FvName, FreeSizeValue, Threshold))
2370 break
2371
2372 ## Generate GuidedSectionTools.txt in the FV directories.
2373 #
2374 def CreateGuidedSectionToolsFile(self,Wa):
2375 for BuildTarget in self.BuildTargetList:
2376 for ToolChain in self.ToolChainList:
2377 FvDir = Wa.FvDir
2378 if not os.path.exists(FvDir):
2379 continue
2380
2381 for Arch in self.ArchList:
2382 # Build up the list of supported architectures for this build
2383 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)
2384
2385 # Look through the tool definitions for GUIDed tools
2386 guidAttribs = []
2387 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.items():
2388 if attrib.upper().endswith('_GUID'):
2389 split = attrib.split('_')
2390 thisPrefix = '_'.join(split[0:3]) + '_'
2391 if thisPrefix == prefix:
2392 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]
2393 guid = guid.lower()
2394 toolName = split[3]
2395 path = '_'.join(split[0:4]) + '_PATH'
2396 path = self.ToolDef.ToolsDefTxtDictionary[path]
2397 path = self.GetRealPathOfTool(path)
2398 guidAttribs.append((guid, toolName, path))
2399
2400 # Write out GuidedSecTools.txt
2401 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')
2402 toolsFile = open(toolsFile, 'wt')
2403 for guidedSectionTool in guidAttribs:
2404 print(' '.join(guidedSectionTool), file=toolsFile)
2405 toolsFile.close()
2406
2407 ## Returns the real path of the tool.
2408 #
2409 def GetRealPathOfTool (self, tool):
2410 if os.path.exists(tool):
2411 return os.path.realpath(tool)
2412 return tool
2413
2414 ## Launch the module or platform build
2415 #
2416 def Launch(self):
2417 self.AllDrivers = set()
2418 self.AllModules = set()
2419 self.PreMakeCacheMiss = set()
2420 self.PreMakeCacheHit = set()
2421 self.MakeCacheMiss = set()
2422 self.MakeCacheHit = set()
2423 if not self.ModuleFile:
2424 if not self.SpawnMode or self.Target not in ["", "all"]:
2425 self.SpawnMode = False
2426 self._BuildPlatform()
2427 else:
2428 self._MultiThreadBuildPlatform()
2429 else:
2430 self.SpawnMode = False
2431 self._BuildModule()
2432
2433 if self.Target == 'cleanall':
2434 RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)
2435
2436 def CreateAsBuiltInf(self):
2437 for Module in self.BuildModules:
2438 Module.CreateAsBuiltInf()
2439
2440 def GenDestCache(self):
2441 for Module in self.AllModules:
2442 Module.GenPreMakefileHashList()
2443 Module.GenMakefileHashList()
2444 Module.CopyModuleToCache()
2445
2446 def GenLocalPreMakeCache(self):
2447 for Module in self.PreMakeCacheMiss:
2448 Module.GenPreMakefileHashList()
2449
2450 ## Do some clean-up works when error occurred
2451 def Relinquish(self):
2452 OldLogLevel = EdkLogger.GetLevel()
2453 EdkLogger.SetLevel(EdkLogger.ERROR)
2454 Utils.Progressor.Abort()
2455 if self.SpawnMode == True:
2456 BuildTask.Abort()
2457 EdkLogger.SetLevel(OldLogLevel)
2458
2459 def ParseDefines(DefineList=[]):
2460 DefineDict = {}
2461 if DefineList is not None:
2462 for Define in DefineList:
2463 DefineTokenList = Define.split("=", 1)
2464 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):
2465 EdkLogger.error('build', FORMAT_INVALID,
2466 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2467 ExtraData=DefineTokenList[0])
2468
2469 if len(DefineTokenList) == 1:
2470 DefineDict[DefineTokenList[0]] = "TRUE"
2471 else:
2472 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()
2473 return DefineDict
2474
2475
2476
2477 def LogBuildTime(Time):
2478 if Time:
2479 TimeDurStr = ''
2480 TimeDur = time.gmtime(Time)
2481 if TimeDur.tm_yday > 1:
2482 TimeDurStr = time.strftime("%H:%M:%S", TimeDur) + ", %d day(s)" % (TimeDur.tm_yday - 1)
2483 else:
2484 TimeDurStr = time.strftime("%H:%M:%S", TimeDur)
2485 return TimeDurStr
2486 else:
2487 return None
2488 def ThreadNum():
2489 OptionParser = MyOptionParser()
2490 if not OptionParser.BuildOption and not OptionParser.BuildTarget:
2491 OptionParser.GetOption()
2492 BuildOption, BuildTarget = OptionParser.BuildOption, OptionParser.BuildTarget
2493 ThreadNumber = BuildOption.ThreadNumber
2494 GlobalData.gCmdConfDir = BuildOption.ConfDirectory
2495 if ThreadNumber is None:
2496 TargetObj = TargetTxtDict()
2497 ThreadNumber = TargetObj.Target.TargetTxtDictionary[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]
2498 if ThreadNumber == '':
2499 ThreadNumber = 0
2500 else:
2501 ThreadNumber = int(ThreadNumber, 0)
2502
2503 if ThreadNumber == 0:
2504 try:
2505 ThreadNumber = multiprocessing.cpu_count()
2506 except (ImportError, NotImplementedError):
2507 ThreadNumber = 1
2508 return ThreadNumber
2509 ## Tool entrance method
2510 #
2511 # This method mainly dispatch specific methods per the command line options.
2512 # If no error found, return zero value so the caller of this tool can know
2513 # if it's executed successfully or not.
2514 #
2515 # @retval 0 Tool was successful
2516 # @retval 1 Tool failed
2517 #
2518 LogQMaxSize = ThreadNum() * 10
2519 def Main():
2520 StartTime = time.time()
2521
2522 #
2523 # Create a log Queue
2524 #
2525 LogQ = mp.Queue(LogQMaxSize)
2526 # Initialize log system
2527 EdkLogger.LogClientInitialize(LogQ)
2528 GlobalData.gCommand = sys.argv[1:]
2529 #
2530 # Parse the options and args
2531 #
2532 OptionParser = MyOptionParser()
2533 if not OptionParser.BuildOption and not OptionParser.BuildTarget:
2534 OptionParser.GetOption()
2535 Option, Target = OptionParser.BuildOption, OptionParser.BuildTarget
2536 GlobalData.gOptions = Option
2537 GlobalData.gCaseInsensitive = Option.CaseInsensitive
2538
2539 # Set log level
2540 LogLevel = EdkLogger.INFO
2541 if Option.verbose is not None:
2542 EdkLogger.SetLevel(EdkLogger.VERBOSE)
2543 LogLevel = EdkLogger.VERBOSE
2544 elif Option.quiet is not None:
2545 EdkLogger.SetLevel(EdkLogger.QUIET)
2546 LogLevel = EdkLogger.QUIET
2547 elif Option.debug is not None:
2548 EdkLogger.SetLevel(Option.debug + 1)
2549 LogLevel = Option.debug + 1
2550 else:
2551 EdkLogger.SetLevel(EdkLogger.INFO)
2552
2553 if Option.WarningAsError == True:
2554 EdkLogger.SetWarningAsError()
2555 Log_Agent = LogAgent(LogQ,LogLevel,Option.LogFile)
2556 Log_Agent.start()
2557
2558 if platform.platform().find("Windows") >= 0:
2559 GlobalData.gIsWindows = True
2560 else:
2561 GlobalData.gIsWindows = False
2562
2563 EdkLogger.quiet("Build environment: %s" % platform.platform())
2564 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));
2565 ReturnCode = 0
2566 MyBuild = None
2567 BuildError = True
2568 try:
2569 if len(Target) == 0:
2570 Target = "all"
2571 elif len(Target) >= 2:
2572 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",
2573 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))
2574 else:
2575 Target = Target[0].lower()
2576
2577 if Target not in gSupportedTarget:
2578 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,
2579 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))
2580
2581 #
2582 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2583 #
2584 CheckEnvVariable()
2585 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))
2586
2587 Workspace = os.getenv("WORKSPACE")
2588 #
2589 # Get files real name in workspace dir
2590 #
2591 GlobalData.gAllFiles = Utils.DirCache(Workspace)
2592
2593 WorkingDirectory = os.getcwd()
2594 if not Option.ModuleFile:
2595 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))
2596 FileNum = len(FileList)
2597 if FileNum >= 2:
2598 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),
2599 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2600 elif FileNum == 1:
2601 Option.ModuleFile = NormFile(FileList[0], Workspace)
2602
2603 if Option.ModuleFile:
2604 if os.path.isabs (Option.ModuleFile):
2605 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:
2606 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)
2607 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)
2608 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)
2609 if ErrorCode != 0:
2610 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
2611
2612 if Option.PlatformFile is not None:
2613 if os.path.isabs (Option.PlatformFile):
2614 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:
2615 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)
2616 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)
2617
2618 if Option.FdfFile is not None:
2619 if os.path.isabs (Option.FdfFile):
2620 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:
2621 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)
2622 Option.FdfFile = PathClass(Option.FdfFile, Workspace)
2623 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)
2624 if ErrorCode != 0:
2625 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
2626
2627 if Option.Flag is not None and Option.Flag not in ['-c', '-s']:
2628 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")
2629
2630 MyBuild = Build(Target, Workspace, Option,LogQ)
2631 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)
2632 if not (MyBuild.LaunchPrebuildFlag and os.path.exists(MyBuild.PlatformBuildPath)):
2633 MyBuild.Launch()
2634
2635 #
2636 # All job done, no error found and no exception raised
2637 #
2638 BuildError = False
2639 except FatalError as X:
2640 if MyBuild is not None:
2641 # for multi-thread build exits safely
2642 MyBuild.Relinquish()
2643 if Option is not None and Option.debug is not None:
2644 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2645 ReturnCode = X.args[0]
2646 except Warning as X:
2647 # error from Fdf parser
2648 if MyBuild is not None:
2649 # for multi-thread build exits safely
2650 MyBuild.Relinquish()
2651 if Option is not None and Option.debug is not None:
2652 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2653 else:
2654 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)
2655 ReturnCode = FORMAT_INVALID
2656 except KeyboardInterrupt:
2657 if MyBuild is not None:
2658
2659 # for multi-thread build exits safely
2660 MyBuild.Relinquish()
2661 ReturnCode = ABORT_ERROR
2662 if Option is not None and Option.debug is not None:
2663 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2664 except:
2665 if MyBuild is not None:
2666 # for multi-thread build exits safely
2667 MyBuild.Relinquish()
2668
2669 # try to get the meta-file from the object causing exception
2670 Tb = sys.exc_info()[-1]
2671 MetaFile = GlobalData.gProcessingFile
2672 while Tb is not None:
2673 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):
2674 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile
2675 Tb = Tb.tb_next
2676 EdkLogger.error(
2677 "\nbuild",
2678 CODE_ERROR,
2679 "Unknown fatal error when processing [%s]" % MetaFile,
2680 ExtraData="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR,
2681 RaiseError=False
2682 )
2683 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2684 ReturnCode = CODE_ERROR
2685 finally:
2686 Utils.Progressor.Abort()
2687 Utils.ClearDuplicatedInf()
2688
2689 if ReturnCode == 0:
2690 try:
2691 MyBuild.LaunchPostbuild()
2692 Conclusion = "Done"
2693 except:
2694 Conclusion = "Failed"
2695 elif ReturnCode == ABORT_ERROR:
2696 Conclusion = "Aborted"
2697 else:
2698 Conclusion = "Failed"
2699 FinishTime = time.time()
2700 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))
2701 BuildDurationStr = ""
2702 if BuildDuration.tm_yday > 1:
2703 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)" % (BuildDuration.tm_yday - 1)
2704 else:
2705 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)
2706 if MyBuild is not None:
2707 if not BuildError:
2708 MyBuild.BuildReport.GenerateReport(BuildDurationStr, LogBuildTime(MyBuild.AutoGenTime), LogBuildTime(MyBuild.MakeTime), LogBuildTime(MyBuild.GenFdsTime))
2709
2710 EdkLogger.SetLevel(EdkLogger.QUIET)
2711 EdkLogger.quiet("\n- %s -" % Conclusion)
2712 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))
2713 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)
2714 Log_Agent.kill()
2715 Log_Agent.join()
2716 return ReturnCode
2717
2718 if __name__ == '__main__':
2719 try:
2720 mp.set_start_method('spawn')
2721 except:
2722 pass
2723 r = Main()
2724 ## 0-127 is a safe return range, and 1 is a standard default error
2725 if r < 0 or r > 127: r = 1
2726 sys.exit(r)
2727