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