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