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