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