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