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