]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/build/build.py
e5693c0d27a2010ef5a20803386cbce48934f55a
[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, 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
66 ## standard targets of build command
67 gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
68
69 ## build configuration file
70 gBuildConfiguration = "target.txt"
71 gToolsDefinition = "tools_def.txt"
72
73 TemporaryTablePattern = re.compile(r'^_\d+_\d+_[a-fA-F0-9]+$')
74 TmpTableDict = {}
75
76 ## Check environment PATH variable to make sure the specified tool is found
77 #
78 # If the tool is found in the PATH, then True is returned
79 # Otherwise, False is returned
80 #
81 def IsToolInPath(tool):
82 if 'PATHEXT' in os.environ:
83 extns = os.environ['PATHEXT'].split(os.path.pathsep)
84 else:
85 extns = ('',)
86 for pathDir in os.environ['PATH'].split(os.path.pathsep):
87 for ext in extns:
88 if os.path.exists(os.path.join(pathDir, tool + ext)):
89 return True
90 return False
91
92 ## Check environment variables
93 #
94 # Check environment variables that must be set for build. Currently they are
95 #
96 # WORKSPACE The directory all packages/platforms start from
97 # EDK_TOOLS_PATH The directory contains all tools needed by the build
98 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
99 #
100 # If any of above environment variable is not set or has error, the build
101 # will be broken.
102 #
103 def CheckEnvVariable():
104 # check WORKSPACE
105 if "WORKSPACE" not in os.environ:
106 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
107 ExtraData="WORKSPACE")
108
109 WorkspaceDir = os.path.normcase(os.path.normpath(os.environ["WORKSPACE"]))
110 if not os.path.exists(WorkspaceDir):
111 EdkLogger.error("build", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData=WorkspaceDir)
112 elif ' ' in WorkspaceDir:
113 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path",
114 ExtraData=WorkspaceDir)
115 os.environ["WORKSPACE"] = WorkspaceDir
116
117 # set multiple workspace
118 PackagesPath = os.getenv("PACKAGES_PATH")
119 mws.setWs(WorkspaceDir, PackagesPath)
120 if mws.PACKAGES_PATH:
121 for Path in mws.PACKAGES_PATH:
122 if not os.path.exists(Path):
123 EdkLogger.error("build", FILE_NOT_FOUND, "One Path in PACKAGES_PATH doesn't exist", ExtraData=Path)
124 elif ' ' in Path:
125 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in PACKAGES_PATH", ExtraData=Path)
126
127
128 os.environ["EDK_TOOLS_PATH"] = os.path.normcase(os.environ["EDK_TOOLS_PATH"])
129
130 # check EDK_TOOLS_PATH
131 if "EDK_TOOLS_PATH" not in os.environ:
132 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
133 ExtraData="EDK_TOOLS_PATH")
134
135 # check PATH
136 if "PATH" not in os.environ:
137 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
138 ExtraData="PATH")
139
140 GlobalData.gWorkspace = WorkspaceDir
141
142 GlobalData.gGlobalDefines["WORKSPACE"] = WorkspaceDir
143 GlobalData.gGlobalDefines["EDK_TOOLS_PATH"] = os.environ["EDK_TOOLS_PATH"]
144
145 ## Get normalized file path
146 #
147 # Convert the path to be local format, and remove the WORKSPACE path at the
148 # beginning if the file path is given in full path.
149 #
150 # @param FilePath File path to be normalized
151 # @param Workspace Workspace path which the FilePath will be checked against
152 #
153 # @retval string The normalized file path
154 #
155 def NormFile(FilePath, Workspace):
156 # check if the path is absolute or relative
157 if os.path.isabs(FilePath):
158 FileFullPath = os.path.normpath(FilePath)
159 else:
160 FileFullPath = os.path.normpath(mws.join(Workspace, FilePath))
161 Workspace = mws.getWs(Workspace, FilePath)
162
163 # check if the file path exists or not
164 if not os.path.isfile(FileFullPath):
165 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath)
166
167 # remove workspace directory from the beginning part of the file path
168 if Workspace[-1] in ["\\", "/"]:
169 return FileFullPath[len(Workspace):]
170 else:
171 return FileFullPath[(len(Workspace) + 1):]
172
173 ## Get the output of an external program
174 #
175 # This is the entrance method of thread reading output of an external program and
176 # putting them in STDOUT/STDERR of current program.
177 #
178 # @param From The stream message read from
179 # @param To The stream message put on
180 # @param ExitFlag The flag used to indicate stopping reading
181 #
182 def ReadMessage(From, To, ExitFlag,MemTo=None):
183 while True:
184 # read one line a time
185 Line = From.readline()
186 # empty string means "end"
187 if Line is not None and Line != b"":
188 LineStr = Line.rstrip().decode(encoding='utf-8', errors='ignore')
189 if MemTo is not None:
190 if "Note: including file:" == LineStr.lstrip()[:21]:
191 MemTo.append(LineStr)
192 else:
193 To(LineStr)
194 MemTo.append(LineStr)
195 else:
196 To(LineStr)
197 else:
198 break
199 if ExitFlag.isSet():
200 break
201
202 class MakeSubProc(Popen):
203 def __init__(self,*args, **argv):
204 super(MakeSubProc,self).__init__(*args, **argv)
205 self.ProcOut = []
206
207 ## Launch an external program
208 #
209 # This method will call subprocess.Popen to execute an external program with
210 # given options in specified directory. Because of the dead-lock issue during
211 # redirecting output of the external program, threads are used to to do the
212 # redirection work.
213 #
214 # @param Command A list or string containing the call of the program
215 # @param WorkingDir The directory in which the program will be running
216 #
217 def LaunchCommand(Command, WorkingDir,ModuleAuto = None):
218 BeginTime = time.time()
219 # if working directory doesn't exist, Popen() will raise an exception
220 if not os.path.isdir(WorkingDir):
221 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=WorkingDir)
222
223 # Command is used as the first Argument in following Popen().
224 # It could be a string or sequence. We find that if command is a string in following Popen(),
225 # ubuntu may fail with an error message that the command is not found.
226 # So here we may need convert command from string to list instance.
227 if platform.system() != 'Windows':
228 if not isinstance(Command, list):
229 Command = Command.split()
230 Command = ' '.join(Command)
231
232 Proc = None
233 EndOfProcedure = None
234 try:
235 # launch the command
236 Proc = MakeSubProc(Command, stdout=PIPE, stderr=STDOUT, env=os.environ, cwd=WorkingDir, bufsize=-1, shell=True)
237
238 # launch two threads to read the STDOUT and STDERR
239 EndOfProcedure = Event()
240 EndOfProcedure.clear()
241 if Proc.stdout:
242 StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure,Proc.ProcOut))
243 StdOutThread.setName("STDOUT-Redirector")
244 StdOutThread.setDaemon(False)
245 StdOutThread.start()
246
247
248 # waiting for program exit
249 Proc.wait()
250 except: # in case of aborting
251 # terminate the threads redirecting the program output
252 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
253 if EndOfProcedure is not None:
254 EndOfProcedure.set()
255 if Proc is None:
256 if not isinstance(Command, type("")):
257 Command = " ".join(Command)
258 EdkLogger.error("build", COMMAND_FAILURE, "Failed to start command", ExtraData="%s [%s]" % (Command, WorkingDir))
259
260 if Proc.stdout:
261 StdOutThread.join()
262
263 # check the return code of the program
264 if Proc.returncode != 0:
265 if not isinstance(Command, type("")):
266 Command = " ".join(Command)
267 # print out the Response file and its content when make failure
268 RespFile = os.path.join(WorkingDir, 'OUTPUT', 'respfilelist.txt')
269 if os.path.isfile(RespFile):
270 f = open(RespFile)
271 RespContent = f.read()
272 f.close()
273 EdkLogger.info(RespContent)
274
275 EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir))
276 if ModuleAuto:
277 iau = IncludesAutoGen(WorkingDir,ModuleAuto)
278 if ModuleAuto.ToolChainFamily == TAB_COMPILER_MSFT:
279 iau.CreateDepsFileForMsvc(Proc.ProcOut)
280 else:
281 iau.UpdateDepsFileforNonMsvc()
282 iau.UpdateDepsFileforTrim()
283 iau.CreateModuleDeps()
284 iau.CreateDepsInclude()
285 iau.CreateDepsTarget()
286 return "%dms" % (int(round((time.time() - BeginTime) * 1000)))
287
288 ## The smallest unit that can be built in multi-thread build mode
289 #
290 # This is the base class of build unit. The "Obj" parameter must provide
291 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
292 # missing build.
293 #
294 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
295 #
296 class BuildUnit:
297 ## The constructor
298 #
299 # @param self The object pointer
300 # @param Obj The object the build is working on
301 # @param Target The build target name, one of gSupportedTarget
302 # @param Dependency The BuildUnit(s) which must be completed in advance
303 # @param WorkingDir The directory build command starts in
304 #
305 def __init__(self, Obj, BuildCommand, Target, Dependency, WorkingDir="."):
306 self.BuildObject = Obj
307 self.Dependency = Dependency
308 self.WorkingDir = WorkingDir
309 self.Target = Target
310 self.BuildCommand = BuildCommand
311 if not BuildCommand:
312 EdkLogger.error("build", OPTION_MISSING,
313 "No build command found for this module. "
314 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
315 (Obj.BuildTarget, Obj.ToolChain, Obj.Arch),
316 ExtraData=str(Obj))
317
318
319 ## str() method
320 #
321 # It just returns the string representation of self.BuildObject
322 #
323 # @param self The object pointer
324 #
325 def __str__(self):
326 return str(self.BuildObject)
327
328 ## "==" operator method
329 #
330 # It just compares self.BuildObject with "Other". So self.BuildObject must
331 # provide its own __eq__() method.
332 #
333 # @param self The object pointer
334 # @param Other The other BuildUnit object compared to
335 #
336 def __eq__(self, Other):
337 return Other and self.BuildObject == Other.BuildObject \
338 and Other.BuildObject \
339 and self.BuildObject.Arch == Other.BuildObject.Arch
340
341 ## hash() method
342 #
343 # It just returns the hash value of self.BuildObject which must be hashable.
344 #
345 # @param self The object pointer
346 #
347 def __hash__(self):
348 return hash(self.BuildObject) + hash(self.BuildObject.Arch)
349
350 def __repr__(self):
351 return repr(self.BuildObject)
352
353 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
354 #
355 # This class is for module build by nmake/make build system. The "Obj" parameter
356 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
357 # be make units missing build.
358 #
359 # Currently the "Obj" should be only ModuleAutoGen object.
360 #
361 class ModuleMakeUnit(BuildUnit):
362 ## The constructor
363 #
364 # @param self The object pointer
365 # @param Obj The ModuleAutoGen object the build is working on
366 # @param Target The build target name, one of gSupportedTarget
367 #
368 def __init__(self, Obj, BuildCommand,Target):
369 Dependency = [ModuleMakeUnit(La, BuildCommand,Target) for La in Obj.LibraryAutoGenList]
370 BuildUnit.__init__(self, Obj, BuildCommand, Target, Dependency, Obj.MakeFileDir)
371 if Target in [None, "", "all"]:
372 self.Target = "tbuild"
373
374 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
375 #
376 # This class is for platform build by nmake/make build system. The "Obj" parameter
377 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
378 # be make units missing build.
379 #
380 # Currently the "Obj" should be only PlatformAutoGen object.
381 #
382 class PlatformMakeUnit(BuildUnit):
383 ## The constructor
384 #
385 # @param self The object pointer
386 # @param Obj The PlatformAutoGen object the build is working on
387 # @param Target The build target name, one of gSupportedTarget
388 #
389 def __init__(self, Obj, BuildCommand, Target):
390 Dependency = [ModuleMakeUnit(Lib, BuildCommand, Target) for Lib in self.BuildObject.LibraryAutoGenList]
391 Dependency.extend([ModuleMakeUnit(Mod, BuildCommand,Target) for Mod in self.BuildObject.ModuleAutoGenList])
392 BuildUnit.__init__(self, Obj, BuildCommand, Target, Dependency, Obj.MakeFileDir)
393
394 ## The class representing the task of a module build or platform build
395 #
396 # This class manages the build tasks in multi-thread build mode. Its jobs include
397 # scheduling thread running, catching thread error, monitor the thread status, etc.
398 #
399 class BuildTask:
400 # queue for tasks waiting for schedule
401 _PendingQueue = OrderedDict()
402 _PendingQueueLock = threading.Lock()
403
404 # queue for tasks ready for running
405 _ReadyQueue = OrderedDict()
406 _ReadyQueueLock = threading.Lock()
407
408 # queue for run tasks
409 _RunningQueue = OrderedDict()
410 _RunningQueueLock = threading.Lock()
411
412 # queue containing all build tasks, in case duplicate build
413 _TaskQueue = OrderedDict()
414
415 # flag indicating error occurs in a running thread
416 _ErrorFlag = threading.Event()
417 _ErrorFlag.clear()
418 _ErrorMessage = ""
419
420 # BoundedSemaphore object used to control the number of running threads
421 _Thread = None
422
423 # flag indicating if the scheduler is started or not
424 _SchedulerStopped = threading.Event()
425 _SchedulerStopped.set()
426
427 ## Start the task scheduler thread
428 #
429 # @param MaxThreadNumber The maximum thread number
430 # @param ExitFlag Flag used to end the scheduler
431 #
432 @staticmethod
433 def StartScheduler(MaxThreadNumber, ExitFlag):
434 SchedulerThread = Thread(target=BuildTask.Scheduler, args=(MaxThreadNumber, ExitFlag))
435 SchedulerThread.setName("Build-Task-Scheduler")
436 SchedulerThread.setDaemon(False)
437 SchedulerThread.start()
438 # wait for the scheduler to be started, especially useful in Linux
439 while not BuildTask.IsOnGoing():
440 time.sleep(0.01)
441
442 ## Scheduler method
443 #
444 # @param MaxThreadNumber The maximum thread number
445 # @param ExitFlag Flag used to end the scheduler
446 #
447 @staticmethod
448 def Scheduler(MaxThreadNumber, ExitFlag):
449 BuildTask._SchedulerStopped.clear()
450 try:
451 # use BoundedSemaphore to control the maximum running threads
452 BuildTask._Thread = BoundedSemaphore(MaxThreadNumber)
453 #
454 # scheduling loop, which will exits when no pending/ready task and
455 # indicated to do so, or there's error in running thread
456 #
457 while (len(BuildTask._PendingQueue) > 0 or len(BuildTask._ReadyQueue) > 0 \
458 or not ExitFlag.isSet()) and not BuildTask._ErrorFlag.isSet():
459 EdkLogger.debug(EdkLogger.DEBUG_8, "Pending Queue (%d), Ready Queue (%d)"
460 % (len(BuildTask._PendingQueue), len(BuildTask._ReadyQueue)))
461
462 # get all pending tasks
463 BuildTask._PendingQueueLock.acquire()
464 BuildObjectList = list(BuildTask._PendingQueue.keys())
465 #
466 # check if their dependency is resolved, and if true, move them
467 # into ready queue
468 #
469 for BuildObject in BuildObjectList:
470 Bt = BuildTask._PendingQueue[BuildObject]
471 if Bt.IsReady():
472 BuildTask._ReadyQueue[BuildObject] = BuildTask._PendingQueue.pop(BuildObject)
473 BuildTask._PendingQueueLock.release()
474
475 # launch build thread until the maximum number of threads is reached
476 while not BuildTask._ErrorFlag.isSet():
477 # empty ready queue, do nothing further
478 if len(BuildTask._ReadyQueue) == 0:
479 break
480
481 # wait for active thread(s) exit
482 BuildTask._Thread.acquire(True)
483
484 # start a new build thread
485 Bo, Bt = BuildTask._ReadyQueue.popitem()
486
487 # move into running queue
488 BuildTask._RunningQueueLock.acquire()
489 BuildTask._RunningQueue[Bo] = Bt
490 BuildTask._RunningQueueLock.release()
491
492 Bt.Start()
493 # avoid tense loop
494 time.sleep(0.01)
495
496 # avoid tense loop
497 time.sleep(0.01)
498
499 # wait for all running threads exit
500 if BuildTask._ErrorFlag.isSet():
501 EdkLogger.quiet("\nWaiting for all build threads exit...")
502 # while not BuildTask._ErrorFlag.isSet() and \
503 while len(BuildTask._RunningQueue) > 0:
504 EdkLogger.verbose("Waiting for thread ending...(%d)" % len(BuildTask._RunningQueue))
505 EdkLogger.debug(EdkLogger.DEBUG_8, "Threads [%s]" % ", ".join(Th.getName() for Th in threading.enumerate()))
506 # avoid tense loop
507 time.sleep(0.1)
508 except BaseException as X:
509 #
510 # TRICK: hide the output of threads left running, so that the user can
511 # catch the error message easily
512 #
513 EdkLogger.SetLevel(EdkLogger.ERROR)
514 BuildTask._ErrorFlag.set()
515 BuildTask._ErrorMessage = "build thread scheduler error\n\t%s" % str(X)
516
517 BuildTask._PendingQueue.clear()
518 BuildTask._ReadyQueue.clear()
519 BuildTask._RunningQueue.clear()
520 BuildTask._TaskQueue.clear()
521 BuildTask._SchedulerStopped.set()
522
523 ## Wait for all running method exit
524 #
525 @staticmethod
526 def WaitForComplete():
527 BuildTask._SchedulerStopped.wait()
528
529 ## Check if the scheduler is running or not
530 #
531 @staticmethod
532 def IsOnGoing():
533 return not BuildTask._SchedulerStopped.isSet()
534
535 ## Abort the build
536 @staticmethod
537 def Abort():
538 if BuildTask.IsOnGoing():
539 BuildTask._ErrorFlag.set()
540 BuildTask.WaitForComplete()
541
542 ## Check if there's error in running thread
543 #
544 # Since the main thread cannot catch exceptions in other thread, we have to
545 # use threading.Event to communicate this formation to main thread.
546 #
547 @staticmethod
548 def HasError():
549 return BuildTask._ErrorFlag.isSet()
550
551 ## Get error message in running thread
552 #
553 # Since the main thread cannot catch exceptions in other thread, we have to
554 # use a static variable to communicate this message to main thread.
555 #
556 @staticmethod
557 def GetErrorMessage():
558 return BuildTask._ErrorMessage
559
560 ## Factory method to create a BuildTask object
561 #
562 # This method will check if a module is building or has been built. And if
563 # true, just return the associated BuildTask object in the _TaskQueue. If
564 # not, create and return a new BuildTask object. The new BuildTask object
565 # will be appended to the _PendingQueue for scheduling later.
566 #
567 # @param BuildItem A BuildUnit object representing a build object
568 # @param Dependency The dependent build object of BuildItem
569 #
570 @staticmethod
571 def New(BuildItem, Dependency=None):
572 if BuildItem in BuildTask._TaskQueue:
573 Bt = BuildTask._TaskQueue[BuildItem]
574 return Bt
575
576 Bt = BuildTask()
577 Bt._Init(BuildItem, Dependency)
578 BuildTask._TaskQueue[BuildItem] = Bt
579
580 BuildTask._PendingQueueLock.acquire()
581 BuildTask._PendingQueue[BuildItem] = Bt
582 BuildTask._PendingQueueLock.release()
583
584 return Bt
585
586 ## The real constructor of BuildTask
587 #
588 # @param BuildItem A BuildUnit object representing a build object
589 # @param Dependency The dependent build object of BuildItem
590 #
591 def _Init(self, BuildItem, Dependency=None):
592 self.BuildItem = BuildItem
593
594 self.DependencyList = []
595 if Dependency is None:
596 Dependency = BuildItem.Dependency
597 else:
598 Dependency.extend(BuildItem.Dependency)
599 self.AddDependency(Dependency)
600 # flag indicating build completes, used to avoid unnecessary re-build
601 self.CompleteFlag = False
602
603 ## Check if all dependent build tasks are completed or not
604 #
605 def IsReady(self):
606 ReadyFlag = True
607 for Dep in self.DependencyList:
608 if Dep.CompleteFlag == True:
609 continue
610 ReadyFlag = False
611 break
612
613 return ReadyFlag
614
615 ## Add dependent build task
616 #
617 # @param Dependency The list of dependent build objects
618 #
619 def AddDependency(self, Dependency):
620 for Dep in Dependency:
621 if not Dep.BuildObject.IsBinaryModule and not Dep.BuildObject.CanSkipbyCache(GlobalData.gModuleCacheHit):
622 self.DependencyList.append(BuildTask.New(Dep)) # BuildTask list
623
624 ## The thread wrapper of LaunchCommand function
625 #
626 # @param Command A list or string contains the call of the command
627 # @param WorkingDir The directory in which the program will be running
628 #
629 def _CommandThread(self, Command, WorkingDir):
630 try:
631 self.BuildItem.BuildObject.BuildTime = LaunchCommand(Command, WorkingDir,self.BuildItem.BuildObject)
632 self.CompleteFlag = True
633
634 # Run hash operation post dependency to account for libs
635 # Run if --hash or --binary-destination
636 if GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:
637 self.BuildItem.BuildObject.GenModuleHash()
638 if GlobalData.gBinCacheDest:
639 self.BuildItem.BuildObject.GenCMakeHash()
640
641 except:
642 #
643 # TRICK: hide the output of threads left running, so that the user can
644 # catch the error message easily
645 #
646 if not BuildTask._ErrorFlag.isSet():
647 GlobalData.gBuildingModule = "%s [%s, %s, %s]" % (str(self.BuildItem.BuildObject),
648 self.BuildItem.BuildObject.Arch,
649 self.BuildItem.BuildObject.ToolChain,
650 self.BuildItem.BuildObject.BuildTarget
651 )
652 EdkLogger.SetLevel(EdkLogger.ERROR)
653 BuildTask._ErrorFlag.set()
654 BuildTask._ErrorMessage = "%s broken\n %s [%s]" % \
655 (threading.currentThread().getName(), Command, WorkingDir)
656
657 # indicate there's a thread is available for another build task
658 BuildTask._RunningQueueLock.acquire()
659 BuildTask._RunningQueue.pop(self.BuildItem)
660 BuildTask._RunningQueueLock.release()
661 BuildTask._Thread.release()
662
663 ## Start build task thread
664 #
665 def Start(self):
666 EdkLogger.quiet("Building ... %s" % repr(self.BuildItem))
667 Command = self.BuildItem.BuildCommand + [self.BuildItem.Target]
668 self.BuildTread = Thread(target=self._CommandThread, args=(Command, self.BuildItem.WorkingDir))
669 self.BuildTread.setName("build thread")
670 self.BuildTread.setDaemon(False)
671 self.BuildTread.start()
672
673 ## The class contains the information related to EFI image
674 #
675 class PeImageInfo():
676 ## Constructor
677 #
678 # Constructor will load all required image information.
679 #
680 # @param BaseName The full file path of image.
681 # @param Guid The GUID for image.
682 # @param Arch Arch of this image.
683 # @param OutputDir The output directory for image.
684 # @param DebugDir The debug directory for image.
685 # @param ImageClass PeImage Information
686 #
687 def __init__(self, BaseName, Guid, Arch, OutputDir, DebugDir, ImageClass):
688 self.BaseName = BaseName
689 self.Guid = Guid
690 self.Arch = Arch
691 self.OutputDir = OutputDir
692 self.DebugDir = DebugDir
693 self.Image = ImageClass
694 self.Image.Size = (self.Image.Size // 0x1000 + 1) * 0x1000
695
696 ## The class implementing the EDK2 build process
697 #
698 # The build process includes:
699 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
700 # 2. Parse DSC file of active platform
701 # 3. Parse FDF file if any
702 # 4. Establish build database, including parse all other files (module, package)
703 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
704 # 6. Call build command
705 #
706 class Build():
707 ## Constructor
708 #
709 # Constructor will load all necessary configurations, parse platform, modules
710 # and packages and the establish a database for AutoGen.
711 #
712 # @param Target The build command target, one of gSupportedTarget
713 # @param WorkspaceDir The directory of workspace
714 # @param BuildOptions Build options passed from command line
715 #
716 def __init__(self, Target, WorkspaceDir, BuildOptions,log_q):
717 self.WorkspaceDir = WorkspaceDir
718 self.Target = Target
719 self.PlatformFile = BuildOptions.PlatformFile
720 self.ModuleFile = BuildOptions.ModuleFile
721 self.ArchList = BuildOptions.TargetArch
722 self.ToolChainList = BuildOptions.ToolChain
723 self.BuildTargetList= BuildOptions.BuildTarget
724 self.Fdf = BuildOptions.FdfFile
725 self.FdList = BuildOptions.RomImage
726 self.FvList = BuildOptions.FvImage
727 self.CapList = BuildOptions.CapName
728 self.SilentMode = BuildOptions.SilentMode
729 self.ThreadNumber = 1
730 self.SkipAutoGen = BuildOptions.SkipAutoGen
731 self.Reparse = BuildOptions.Reparse
732 self.SkuId = BuildOptions.SkuId
733 if self.SkuId:
734 GlobalData.gSKUID_CMD = self.SkuId
735 self.ConfDirectory = BuildOptions.ConfDirectory
736 self.SpawnMode = True
737 self.BuildReport = BuildReport(BuildOptions.ReportFile, BuildOptions.ReportType)
738 self.AutoGenTime = 0
739 self.MakeTime = 0
740 self.GenFdsTime = 0
741 self.MakeFileName = ""
742 TargetObj = TargetTxtDict()
743 ToolDefObj = ToolDefDict((os.path.join(os.getenv("WORKSPACE"),"Conf")))
744 self.TargetTxt = TargetObj.Target
745 self.ToolDef = ToolDefObj.ToolDef
746 GlobalData.BuildOptionPcd = BuildOptions.OptionPcd if BuildOptions.OptionPcd else []
747 #Set global flag for build mode
748 GlobalData.gIgnoreSource = BuildOptions.IgnoreSources
749 GlobalData.gUseHashCache = BuildOptions.UseHashCache
750 GlobalData.gBinCacheDest = BuildOptions.BinCacheDest
751 GlobalData.gBinCacheSource = BuildOptions.BinCacheSource
752 GlobalData.gEnableGenfdsMultiThread = not BuildOptions.NoGenfdsMultiThread
753 GlobalData.gDisableIncludePathCheck = BuildOptions.DisableIncludePathCheck
754
755 if GlobalData.gBinCacheDest and not GlobalData.gUseHashCache:
756 EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-destination must be used together with --hash.")
757
758 if GlobalData.gBinCacheSource and not GlobalData.gUseHashCache:
759 EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-source must be used together with --hash.")
760
761 if GlobalData.gBinCacheDest and GlobalData.gBinCacheSource:
762 EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-destination can not be used together with --binary-source.")
763
764 if GlobalData.gBinCacheSource:
765 BinCacheSource = os.path.normpath(GlobalData.gBinCacheSource)
766 if not os.path.isabs(BinCacheSource):
767 BinCacheSource = mws.join(self.WorkspaceDir, BinCacheSource)
768 GlobalData.gBinCacheSource = BinCacheSource
769 else:
770 if GlobalData.gBinCacheSource is not None:
771 EdkLogger.error("build", OPTION_VALUE_INVALID, ExtraData="Invalid value of option --binary-source.")
772
773 if GlobalData.gBinCacheDest:
774 BinCacheDest = os.path.normpath(GlobalData.gBinCacheDest)
775 if not os.path.isabs(BinCacheDest):
776 BinCacheDest = mws.join(self.WorkspaceDir, BinCacheDest)
777 GlobalData.gBinCacheDest = BinCacheDest
778 else:
779 if GlobalData.gBinCacheDest is not None:
780 EdkLogger.error("build", OPTION_VALUE_INVALID, ExtraData="Invalid value of option --binary-destination.")
781
782 GlobalData.gDatabasePath = os.path.normpath(os.path.join(GlobalData.gConfDirectory, GlobalData.gDatabasePath))
783 if not os.path.exists(os.path.join(GlobalData.gConfDirectory, '.cache')):
784 os.makedirs(os.path.join(GlobalData.gConfDirectory, '.cache'))
785 self.Db = BuildDB
786 self.BuildDatabase = self.Db.BuildObject
787 self.Platform = None
788 self.ToolChainFamily = None
789 self.LoadFixAddress = 0
790 self.UniFlag = BuildOptions.Flag
791 self.BuildModules = []
792 self.HashSkipModules = []
793 self.Db_Flag = False
794 self.LaunchPrebuildFlag = False
795 self.PlatformBuildPath = os.path.join(GlobalData.gConfDirectory, '.cache', '.PlatformBuild')
796 if BuildOptions.CommandLength:
797 GlobalData.gCommandMaxLength = BuildOptions.CommandLength
798
799 # print dot character during doing some time-consuming work
800 self.Progress = Utils.Progressor()
801 # print current build environment and configuration
802 EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))
803 if "PACKAGES_PATH" in os.environ:
804 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
805 EdkLogger.quiet("%-16s = %s" % ("PACKAGES_PATH", os.path.normcase(os.path.normpath(os.environ["PACKAGES_PATH"]))))
806 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))
807 if "EDK_TOOLS_BIN" in os.environ:
808 # Print the same path style with WORKSPACE env.
809 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os.path.normcase(os.path.normpath(os.environ["EDK_TOOLS_BIN"]))))
810 EdkLogger.quiet("%-16s = %s" % ("CONF_PATH", GlobalData.gConfDirectory))
811 if "PYTHON3_ENABLE" in os.environ:
812 PYTHON3_ENABLE = os.environ["PYTHON3_ENABLE"]
813 if PYTHON3_ENABLE != "TRUE":
814 PYTHON3_ENABLE = "FALSE"
815 EdkLogger.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE))
816 if "PYTHON_COMMAND" in os.environ:
817 EdkLogger.quiet("%-16s = %s" % ("PYTHON_COMMAND", os.environ["PYTHON_COMMAND"]))
818 self.InitPreBuild()
819 self.InitPostBuild()
820 if self.Prebuild:
821 EdkLogger.quiet("%-16s = %s" % ("PREBUILD", self.Prebuild))
822 if self.Postbuild:
823 EdkLogger.quiet("%-16s = %s" % ("POSTBUILD", self.Postbuild))
824 if self.Prebuild:
825 self.LaunchPrebuild()
826 TargetObj = TargetTxtDict()
827 ToolDefObj = ToolDefDict((os.path.join(os.getenv("WORKSPACE"), "Conf")))
828 self.TargetTxt = TargetObj.Target
829 self.ToolDef = ToolDefObj.ToolDef
830 if not (self.LaunchPrebuildFlag and os.path.exists(self.PlatformBuildPath)):
831 self.InitBuild()
832
833 self.AutoGenMgr = None
834 EdkLogger.info("")
835 os.chdir(self.WorkspaceDir)
836 self.log_q = log_q
837 GlobalData.file_lock = mp.Lock()
838 # Init cache data for local only
839 GlobalData.gPackageHashFile = dict()
840 GlobalData.gModulePreMakeCacheStatus = dict()
841 GlobalData.gModuleMakeCacheStatus = dict()
842 GlobalData.gHashChainStatus = dict()
843 GlobalData.gCMakeHashFile = dict()
844 GlobalData.gModuleHashFile = dict()
845 GlobalData.gFileHashDict = dict()
846 GlobalData.gModuleAllCacheStatus = set()
847 GlobalData.gModuleCacheHit = set()
848
849 def StartAutoGen(self,mqueue, DataPipe,SkipAutoGen,PcdMaList,cqueue):
850 try:
851 if SkipAutoGen:
852 return True,0
853 feedback_q = mp.Queue()
854 error_event = mp.Event()
855 FfsCmd = DataPipe.Get("FfsCommand")
856 if FfsCmd is None:
857 FfsCmd = {}
858 GlobalData.FfsCmd = FfsCmd
859 auto_workers = [AutoGenWorkerInProcess(mqueue,DataPipe.dump_file,feedback_q,GlobalData.file_lock,cqueue,self.log_q,error_event) for _ in range(self.ThreadNumber)]
860 self.AutoGenMgr = AutoGenManager(auto_workers,feedback_q,error_event)
861 self.AutoGenMgr.start()
862 for w in auto_workers:
863 w.start()
864 if PcdMaList is not None:
865 for PcdMa in PcdMaList:
866 # SourceFileList calling sequence impact the makefile string sequence.
867 # Create cached SourceFileList here to unify its calling sequence for both
868 # CanSkipbyPreMakeCache and CreateCodeFile/CreateMakeFile.
869 RetVal = PcdMa.SourceFileList
870 # Force cache miss for PCD driver
871 if GlobalData.gUseHashCache and not GlobalData.gBinCacheDest and self.Target in [None, "", "all"]:
872 cqueue.put((PcdMa.MetaFile.Path, PcdMa.Arch, "PreMakeCache", False))
873
874 PcdMa.CreateCodeFile(False)
875 PcdMa.CreateMakeFile(False,GenFfsList = DataPipe.Get("FfsCommand").get((PcdMa.MetaFile.Path, PcdMa.Arch),[]))
876 PcdMa.CreateAsBuiltInf()
877 # Force cache miss for PCD driver
878 if GlobalData.gBinCacheSource and self.Target in [None, "", "all"]:
879 cqueue.put((PcdMa.MetaFile.Path, PcdMa.Arch, "MakeCache", False))
880
881 self.AutoGenMgr.join()
882 rt = self.AutoGenMgr.Status
883 err = 0
884 if not rt:
885 err = UNKNOWN_ERROR
886 return rt, err
887 except FatalError as e:
888 return False, e.args[0]
889 except:
890 return False, UNKNOWN_ERROR
891
892 ## Add TOOLCHAIN and FAMILY declared in DSC [BuildOptions] to ToolsDefTxtDatabase.
893 #
894 # Loop through the set of build targets, tool chains, and archs provided on either
895 # the command line or in target.txt to discover FAMILY and TOOLCHAIN delclarations
896 # in [BuildOptions] sections that may be within !if expressions that may use
897 # $(TARGET), $(TOOLCHAIN), $(TOOLCHAIN_TAG), or $(ARCH) operands.
898 #
899 def GetToolChainAndFamilyFromDsc (self, File):
900 SavedGlobalDefines = GlobalData.gGlobalDefines.copy()
901 for BuildTarget in self.BuildTargetList:
902 GlobalData.gGlobalDefines['TARGET'] = BuildTarget
903 for BuildToolChain in self.ToolChainList:
904 GlobalData.gGlobalDefines['TOOLCHAIN'] = BuildToolChain
905 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = BuildToolChain
906 for BuildArch in self.ArchList:
907 GlobalData.gGlobalDefines['ARCH'] = BuildArch
908 dscobj = self.BuildDatabase[File, BuildArch]
909 for KeyFamily, Key, KeyCodeBase in dscobj.BuildOptions:
910 try:
911 Target, ToolChain, Arch, Tool, Attr = Key.split('_')
912 except:
913 continue
914 if ToolChain == TAB_STAR or Attr != TAB_TOD_DEFINES_FAMILY:
915 continue
916 try:
917 Family = dscobj.BuildOptions[(KeyFamily, Key, KeyCodeBase)]
918 Family = Family.strip().strip('=').strip()
919 except:
920 continue
921 if TAB_TOD_DEFINES_FAMILY not in self.ToolDef.ToolsDefTxtDatabase:
922 self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY] = {}
923 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY]:
924 self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][ToolChain] = Family
925 if TAB_TOD_DEFINES_BUILDRULEFAMILY not in self.ToolDef.ToolsDefTxtDatabase:
926 self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY] = {}
927 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY]:
928 self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][ToolChain] = Family
929 if TAB_TOD_DEFINES_TOOL_CHAIN_TAG not in self.ToolDef.ToolsDefTxtDatabase:
930 self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG] = []
931 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:
932 self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG].append(ToolChain)
933 GlobalData.gGlobalDefines = SavedGlobalDefines
934
935 ## Load configuration
936 #
937 # This method will parse target.txt and get the build configurations.
938 #
939 def LoadConfiguration(self):
940
941 # if no ARCH given in command line, get it from target.txt
942 if not self.ArchList:
943 self.ArchList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET_ARCH]
944 self.ArchList = tuple(self.ArchList)
945
946 # if no build target given in command line, get it from target.txt
947 if not self.BuildTargetList:
948 self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET]
949
950 # if no tool chain given in command line, get it from target.txt
951 if not self.ToolChainList:
952 self.ToolChainList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TOOL_CHAIN_TAG]
953 if self.ToolChainList is None or len(self.ToolChainList) == 0:
954 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")
955
956 if not self.PlatformFile:
957 PlatformFile = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_ACTIVE_PLATFORM]
958 if not PlatformFile:
959 # Try to find one in current directory
960 WorkingDirectory = os.getcwd()
961 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))
962 FileNum = len(FileList)
963 if FileNum >= 2:
964 EdkLogger.error("build", OPTION_MISSING,
965 ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))
966 elif FileNum == 1:
967 PlatformFile = FileList[0]
968 else:
969 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
970 ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")
971
972 self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)
973
974 self.GetToolChainAndFamilyFromDsc (self.PlatformFile)
975
976 # check if the tool chains are defined or not
977 NewToolChainList = []
978 for ToolChain in self.ToolChainList:
979 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:
980 EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)
981 else:
982 NewToolChainList.append(ToolChain)
983 # if no tool chain available, break the build
984 if len(NewToolChainList) == 0:
985 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
986 ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))
987 else:
988 self.ToolChainList = NewToolChainList
989
990 ToolChainFamily = []
991 ToolDefinition = self.ToolDef.ToolsDefTxtDatabase
992 for Tool in self.ToolChainList:
993 if TAB_TOD_DEFINES_FAMILY not in ToolDefinition or Tool not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \
994 or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool]:
995 EdkLogger.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool)
996 ToolChainFamily.append(TAB_COMPILER_MSFT)
997 else:
998 ToolChainFamily.append(ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool])
999 self.ToolChainFamily = ToolChainFamily
1000
1001 self.ThreadNumber = ThreadNum()
1002 ## Initialize build configuration
1003 #
1004 # This method will parse DSC file and merge the configurations from
1005 # command line and target.txt, then get the final build configurations.
1006 #
1007 def InitBuild(self):
1008 # parse target.txt, tools_def.txt, and platform file
1009 self.LoadConfiguration()
1010
1011 # Allow case-insensitive for those from command line or configuration file
1012 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)
1013 if ErrorCode != 0:
1014 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
1015
1016
1017 def InitPreBuild(self):
1018 self.LoadConfiguration()
1019 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)
1020 if ErrorCode != 0:
1021 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
1022 if self.BuildTargetList:
1023 GlobalData.gGlobalDefines['TARGET'] = self.BuildTargetList[0]
1024 if self.ArchList:
1025 GlobalData.gGlobalDefines['ARCH'] = self.ArchList[0]
1026 if self.ToolChainList:
1027 GlobalData.gGlobalDefines['TOOLCHAIN'] = self.ToolChainList[0]
1028 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = self.ToolChainList[0]
1029 if self.ToolChainFamily:
1030 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[0]
1031 if 'PREBUILD' in GlobalData.gCommandLineDefines:
1032 self.Prebuild = GlobalData.gCommandLineDefines.get('PREBUILD')
1033 else:
1034 self.Db_Flag = True
1035 Platform = self.Db.MapPlatform(str(self.PlatformFile))
1036 self.Prebuild = str(Platform.Prebuild)
1037 if self.Prebuild:
1038 PrebuildList = []
1039 #
1040 # Evaluate all arguments and convert arguments that are WORKSPACE
1041 # relative paths to absolute paths. Filter arguments that look like
1042 # flags or do not follow the file/dir naming rules to avoid false
1043 # positives on this conversion.
1044 #
1045 for Arg in self.Prebuild.split():
1046 #
1047 # Do not modify Arg if it looks like a flag or an absolute file path
1048 #
1049 if Arg.startswith('-') or os.path.isabs(Arg):
1050 PrebuildList.append(Arg)
1051 continue
1052 #
1053 # Do not modify Arg if it does not look like a Workspace relative
1054 # path that starts with a valid package directory name
1055 #
1056 if not Arg[0].isalpha() or os.path.dirname(Arg) == '':
1057 PrebuildList.append(Arg)
1058 continue
1059 #
1060 # If Arg looks like a WORKSPACE relative path, then convert to an
1061 # absolute path and check to see if the file exists.
1062 #
1063 Temp = mws.join(self.WorkspaceDir, Arg)
1064 if os.path.isfile(Temp):
1065 Arg = Temp
1066 PrebuildList.append(Arg)
1067 self.Prebuild = ' '.join(PrebuildList)
1068 self.Prebuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)
1069
1070 def InitPostBuild(self):
1071 if 'POSTBUILD' in GlobalData.gCommandLineDefines:
1072 self.Postbuild = GlobalData.gCommandLineDefines.get('POSTBUILD')
1073 else:
1074 Platform = self.Db.MapPlatform(str(self.PlatformFile))
1075 self.Postbuild = str(Platform.Postbuild)
1076 if self.Postbuild:
1077 PostbuildList = []
1078 #
1079 # Evaluate all arguments and convert arguments that are WORKSPACE
1080 # relative paths to absolute paths. Filter arguments that look like
1081 # flags or do not follow the file/dir naming rules to avoid false
1082 # positives on this conversion.
1083 #
1084 for Arg in self.Postbuild.split():
1085 #
1086 # Do not modify Arg if it looks like a flag or an absolute file path
1087 #
1088 if Arg.startswith('-') or os.path.isabs(Arg):
1089 PostbuildList.append(Arg)
1090 continue
1091 #
1092 # Do not modify Arg if it does not look like a Workspace relative
1093 # path that starts with a valid package directory name
1094 #
1095 if not Arg[0].isalpha() or os.path.dirname(Arg) == '':
1096 PostbuildList.append(Arg)
1097 continue
1098 #
1099 # If Arg looks like a WORKSPACE relative path, then convert to an
1100 # absolute path and check to see if the file exists.
1101 #
1102 Temp = mws.join(self.WorkspaceDir, Arg)
1103 if os.path.isfile(Temp):
1104 Arg = Temp
1105 PostbuildList.append(Arg)
1106 self.Postbuild = ' '.join(PostbuildList)
1107 self.Postbuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)
1108
1109 def PassCommandOption(self, BuildTarget, TargetArch, ToolChain, PlatformFile, Target):
1110 BuildStr = ''
1111 if GlobalData.gCommand and isinstance(GlobalData.gCommand, list):
1112 BuildStr += ' ' + ' '.join(GlobalData.gCommand)
1113 TargetFlag = False
1114 ArchFlag = False
1115 ToolChainFlag = False
1116 PlatformFileFlag = False
1117
1118 if GlobalData.gOptions and not GlobalData.gOptions.BuildTarget:
1119 TargetFlag = True
1120 if GlobalData.gOptions and not GlobalData.gOptions.TargetArch:
1121 ArchFlag = True
1122 if GlobalData.gOptions and not GlobalData.gOptions.ToolChain:
1123 ToolChainFlag = True
1124 if GlobalData.gOptions and not GlobalData.gOptions.PlatformFile:
1125 PlatformFileFlag = True
1126
1127 if TargetFlag and BuildTarget:
1128 if isinstance(BuildTarget, list) or isinstance(BuildTarget, tuple):
1129 BuildStr += ' -b ' + ' -b '.join(BuildTarget)
1130 elif isinstance(BuildTarget, str):
1131 BuildStr += ' -b ' + BuildTarget
1132 if ArchFlag and TargetArch:
1133 if isinstance(TargetArch, list) or isinstance(TargetArch, tuple):
1134 BuildStr += ' -a ' + ' -a '.join(TargetArch)
1135 elif isinstance(TargetArch, str):
1136 BuildStr += ' -a ' + TargetArch
1137 if ToolChainFlag and ToolChain:
1138 if isinstance(ToolChain, list) or isinstance(ToolChain, tuple):
1139 BuildStr += ' -t ' + ' -t '.join(ToolChain)
1140 elif isinstance(ToolChain, str):
1141 BuildStr += ' -t ' + ToolChain
1142 if PlatformFileFlag and PlatformFile:
1143 if isinstance(PlatformFile, list) or isinstance(PlatformFile, tuple):
1144 BuildStr += ' -p ' + ' -p '.join(PlatformFile)
1145 elif isinstance(PlatformFile, str):
1146 BuildStr += ' -p' + PlatformFile
1147 BuildStr += ' --conf=' + GlobalData.gConfDirectory
1148 if Target:
1149 BuildStr += ' ' + Target
1150
1151 return BuildStr
1152
1153 def LaunchPrebuild(self):
1154 if self.Prebuild:
1155 EdkLogger.info("\n- Prebuild Start -\n")
1156 self.LaunchPrebuildFlag = True
1157 #
1158 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script
1159 # and preserve them for the rest of the main build step, because the child process environment will
1160 # evaporate as soon as it exits, we cannot get it in build step.
1161 #
1162 PrebuildEnvFile = os.path.join(GlobalData.gConfDirectory, '.cache', '.PrebuildEnv')
1163 if os.path.isfile(PrebuildEnvFile):
1164 os.remove(PrebuildEnvFile)
1165 if os.path.isfile(self.PlatformBuildPath):
1166 os.remove(self.PlatformBuildPath)
1167 if sys.platform == "win32":
1168 args = ' && '.join((self.Prebuild, 'set > ' + PrebuildEnvFile))
1169 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)
1170 else:
1171 args = ' && '.join((self.Prebuild, 'env > ' + PrebuildEnvFile))
1172 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)
1173
1174 # launch two threads to read the STDOUT and STDERR
1175 EndOfProcedure = Event()
1176 EndOfProcedure.clear()
1177 if Process.stdout:
1178 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))
1179 StdOutThread.setName("STDOUT-Redirector")
1180 StdOutThread.setDaemon(False)
1181 StdOutThread.start()
1182
1183 if Process.stderr:
1184 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))
1185 StdErrThread.setName("STDERR-Redirector")
1186 StdErrThread.setDaemon(False)
1187 StdErrThread.start()
1188 # waiting for program exit
1189 Process.wait()
1190
1191 if Process.stdout:
1192 StdOutThread.join()
1193 if Process.stderr:
1194 StdErrThread.join()
1195 if Process.returncode != 0 :
1196 EdkLogger.error("Prebuild", PREBUILD_ERROR, 'Prebuild process is not success!')
1197
1198 if os.path.exists(PrebuildEnvFile):
1199 f = open(PrebuildEnvFile)
1200 envs = f.readlines()
1201 f.close()
1202 envs = [l.split("=", 1) for l in envs ]
1203 envs = [[I.strip() for I in item] for item in envs if len(item) == 2]
1204 os.environ.update(dict(envs))
1205 EdkLogger.info("\n- Prebuild Done -\n")
1206
1207 def LaunchPostbuild(self):
1208 if self.Postbuild:
1209 EdkLogger.info("\n- Postbuild Start -\n")
1210 if sys.platform == "win32":
1211 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)
1212 else:
1213 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)
1214 # launch two threads to read the STDOUT and STDERR
1215 EndOfProcedure = Event()
1216 EndOfProcedure.clear()
1217 if Process.stdout:
1218 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))
1219 StdOutThread.setName("STDOUT-Redirector")
1220 StdOutThread.setDaemon(False)
1221 StdOutThread.start()
1222
1223 if Process.stderr:
1224 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))
1225 StdErrThread.setName("STDERR-Redirector")
1226 StdErrThread.setDaemon(False)
1227 StdErrThread.start()
1228 # waiting for program exit
1229 Process.wait()
1230
1231 if Process.stdout:
1232 StdOutThread.join()
1233 if Process.stderr:
1234 StdErrThread.join()
1235 if Process.returncode != 0 :
1236 EdkLogger.error("Postbuild", POSTBUILD_ERROR, 'Postbuild process is not success!')
1237 EdkLogger.info("\n- Postbuild Done -\n")
1238
1239 ## Build a module or platform
1240 #
1241 # Create autogen code and makefile for a module or platform, and the launch
1242 # "make" command to build it
1243 #
1244 # @param Target The target of build command
1245 # @param Platform The platform file
1246 # @param Module The module file
1247 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1248 # @param ToolChain The name of toolchain to build
1249 # @param Arch The arch of the module/platform
1250 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1251 # for dependent modules/Libraries
1252 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1253 # for dependent modules/Libraries
1254 #
1255 def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False, FfsCommand=None, PcdMaList=None):
1256 if AutoGenObject is None:
1257 return False
1258 if FfsCommand is None:
1259 FfsCommand = {}
1260 # skip file generation for cleanxxx targets, run and fds target
1261 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1262 # for target which must generate AutoGen code and makefile
1263 mqueue = mp.Queue()
1264 for m in AutoGenObject.GetAllModuleInfo:
1265 mqueue.put(m)
1266 mqueue.put((None,None,None,None,None,None,None))
1267 AutoGenObject.DataPipe.DataContainer = {"CommandTarget": self.Target}
1268 AutoGenObject.DataPipe.DataContainer = {"Workspace_timestamp": AutoGenObject.Workspace._SrcTimeStamp}
1269 AutoGenObject.CreateLibModuelDirs()
1270 AutoGenObject.DataPipe.DataContainer = {"LibraryBuildDirectoryList":AutoGenObject.LibraryBuildDirectoryList}
1271 AutoGenObject.DataPipe.DataContainer = {"ModuleBuildDirectoryList":AutoGenObject.ModuleBuildDirectoryList}
1272 AutoGenObject.DataPipe.DataContainer = {"FdsCommandDict": AutoGenObject.Workspace.GenFdsCommandDict}
1273 self.Progress.Start("Generating makefile and code")
1274 data_pipe_file = os.path.join(AutoGenObject.BuildDir, "GlobalVar_%s_%s.bin" % (str(AutoGenObject.Guid),AutoGenObject.Arch))
1275 AutoGenObject.DataPipe.dump(data_pipe_file)
1276 cqueue = mp.Queue()
1277 autogen_rt,errorcode = self.StartAutoGen(mqueue, AutoGenObject.DataPipe, self.SkipAutoGen, PcdMaList, cqueue)
1278 AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt")
1279 with open(AutoGenIdFile,"w") as fw:
1280 fw.write("Arch=%s\n" % "|".join((AutoGenObject.Workspace.ArchList)))
1281 fw.write("BuildDir=%s\n" % AutoGenObject.Workspace.BuildDir)
1282 fw.write("PlatformGuid=%s\n" % str(AutoGenObject.Guid))
1283 self.Progress.Stop("done!")
1284 if not autogen_rt:
1285 self.AutoGenMgr.TerminateWorkers()
1286 self.AutoGenMgr.join(1)
1287 raise FatalError(errorcode)
1288 AutoGenObject.CreateCodeFile(False)
1289 AutoGenObject.CreateMakeFile(False)
1290 else:
1291 # always recreate top/platform makefile when clean, just in case of inconsistency
1292 AutoGenObject.CreateCodeFile(True)
1293 AutoGenObject.CreateMakeFile(True)
1294
1295 if EdkLogger.GetLevel() == EdkLogger.QUIET:
1296 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
1297
1298 BuildCommand = AutoGenObject.BuildCommand
1299 if BuildCommand is None or len(BuildCommand) == 0:
1300 EdkLogger.error("build", OPTION_MISSING,
1301 "No build command found for this module. "
1302 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1303 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
1304 ExtraData=str(AutoGenObject))
1305
1306 # run
1307 if Target == 'run':
1308 return True
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 if not self.MakeFileName:
2186 self.MakeFileName = Pa.MakeFile
2187
2188 Pa.DataPipe.DataContainer = {"LibraryBuildDirectoryList":Pa.LibraryBuildDirectoryList}
2189 Pa.DataPipe.DataContainer = {"ModuleBuildDirectoryList":Pa.ModuleBuildDirectoryList}
2190 Pa.DataPipe.DataContainer = {"FdsCommandDict": Wa.GenFdsCommandDict}
2191 # Prepare the cache share data for multiprocessing
2192 Pa.DataPipe.DataContainer = {"gPlatformHashFile":GlobalData.gPlatformHashFile}
2193 ModuleCodaFile = {}
2194 for ma in Pa.ModuleAutoGenList:
2195 ModuleCodaFile[(ma.MetaFile.File,ma.MetaFile.Root,ma.Arch,ma.MetaFile.Path)] = [item.Target for item in ma.CodaTargetList]
2196 Pa.DataPipe.DataContainer = {"ModuleCodaFile":ModuleCodaFile}
2197 # ModuleList contains all driver modules only
2198 for Module in ModuleList:
2199 # Get ModuleAutoGen object to generate C code file and makefile
2200 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)
2201 if Ma is None:
2202 continue
2203 if Ma.PcdIsDriver:
2204 Ma.PlatformInfo = Pa
2205 Ma.Workspace = Wa
2206 PcdMaList.append(Ma)
2207 self.AllDrivers.add(Ma)
2208 self.AllModules.add(Ma)
2209
2210 mqueue = mp.Queue()
2211 cqueue = mp.Queue()
2212 for m in Pa.GetAllModuleInfo:
2213 mqueue.put(m)
2214 module_file,module_root,module_path,module_basename,\
2215 module_originalpath,module_arch,IsLib = m
2216 Ma = ModuleAutoGen(Wa, PathClass(module_path, Wa), BuildTarget,\
2217 ToolChain, Arch, self.PlatformFile,Pa.DataPipe)
2218 self.AllModules.add(Ma)
2219 data_pipe_file = os.path.join(Pa.BuildDir, "GlobalVar_%s_%s.bin" % (str(Pa.Guid),Pa.Arch))
2220 Pa.DataPipe.dump(data_pipe_file)
2221
2222 mqueue.put((None,None,None,None,None,None,None))
2223 autogen_rt, errorcode = self.StartAutoGen(mqueue, Pa.DataPipe, self.SkipAutoGen, PcdMaList, cqueue)
2224
2225 if not autogen_rt:
2226 self.AutoGenMgr.TerminateWorkers()
2227 self.AutoGenMgr.join(1)
2228 raise FatalError(errorcode)
2229
2230 if GlobalData.gUseHashCache:
2231 for item in GlobalData.gModuleAllCacheStatus:
2232 (MetaFilePath, Arch, CacheStr, Status) = item
2233 Ma = ModuleAutoGen(Wa, PathClass(MetaFilePath, Wa), BuildTarget,\
2234 ToolChain, Arch, self.PlatformFile,Pa.DataPipe)
2235 if CacheStr == "PreMakeCache" and Status == False:
2236 self.PreMakeCacheMiss.add(Ma)
2237 if CacheStr == "PreMakeCache" and Status == True:
2238 self.PreMakeCacheHit.add(Ma)
2239 GlobalData.gModuleCacheHit.add(Ma)
2240 if CacheStr == "MakeCache" and Status == False:
2241 self.MakeCacheMiss.add(Ma)
2242 if CacheStr == "MakeCache" and Status == True:
2243 self.MakeCacheHit.add(Ma)
2244 GlobalData.gModuleCacheHit.add(Ma)
2245 self.AutoGenTime += int(round((time.time() - AutoGenStart)))
2246 AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt")
2247 with open(AutoGenIdFile,"w") as fw:
2248 fw.write("Arch=%s\n" % "|".join((Wa.ArchList)))
2249 fw.write("BuildDir=%s\n" % Wa.BuildDir)
2250 fw.write("PlatformGuid=%s\n" % str(Wa.AutoGenObjectList[0].Guid))
2251
2252 if GlobalData.gBinCacheSource:
2253 BuildModules.extend(self.MakeCacheMiss)
2254 elif GlobalData.gUseHashCache and not GlobalData.gBinCacheDest:
2255 BuildModules.extend(self.PreMakeCacheMiss)
2256 else:
2257 BuildModules.extend(self.AllDrivers)
2258
2259 self.Progress.Stop("done!")
2260 return Wa, BuildModules
2261
2262 def _MultiThreadBuildPlatform(self):
2263 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)
2264 for BuildTarget in self.BuildTargetList:
2265 GlobalData.gGlobalDefines['TARGET'] = BuildTarget
2266 index = 0
2267 for ToolChain in self.ToolChainList:
2268 resetFdsGlobalVariable()
2269 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
2270 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
2271 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
2272 index += 1
2273 ExitFlag = threading.Event()
2274 ExitFlag.clear()
2275 if self.SkipAutoGen:
2276 Wa = self.VerifyAutoGenFiles()
2277 if Wa is None:
2278 self.SkipAutoGen = False
2279 Wa, self.BuildModules = self.PerformAutoGen(BuildTarget,ToolChain)
2280 else:
2281 GlobalData.gAutoGenPhase = True
2282 self.BuildModules = self.SetupMakeSetting(Wa)
2283 else:
2284 Wa, self.BuildModules = self.PerformAutoGen(BuildTarget,ToolChain)
2285 Pa = Wa.AutoGenObjectList[0]
2286 GlobalData.gAutoGenPhase = False
2287
2288 if GlobalData.gBinCacheSource:
2289 EdkLogger.quiet("[cache Summary]: Total module num: %s" % len(self.AllModules))
2290 EdkLogger.quiet("[cache Summary]: PreMakecache miss num: %s " % len(self.PreMakeCacheMiss))
2291 EdkLogger.quiet("[cache Summary]: Makecache miss num: %s " % len(self.MakeCacheMiss))
2292
2293 for Arch in Wa.ArchList:
2294 MakeStart = time.time()
2295 for Ma in set(self.BuildModules):
2296 # Generate build task for the module
2297 if not Ma.IsBinaryModule:
2298 Bt = BuildTask.New(ModuleMakeUnit(Ma, Pa.BuildCommand,self.Target))
2299 # Break build if any build thread has error
2300 if BuildTask.HasError():
2301 # we need a full version of makefile for platform
2302 ExitFlag.set()
2303 BuildTask.WaitForComplete()
2304 Pa.CreateMakeFile(False)
2305 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
2306 # Start task scheduler
2307 if not BuildTask.IsOnGoing():
2308 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
2309
2310 # in case there's an interruption. we need a full version of makefile for platform
2311
2312 if BuildTask.HasError():
2313 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
2314 self.MakeTime += int(round((time.time() - MakeStart)))
2315
2316 MakeContiue = time.time()
2317 #
2318 #
2319 # All modules have been put in build tasks queue. Tell task scheduler
2320 # to exit if all tasks are completed
2321 #
2322 ExitFlag.set()
2323 BuildTask.WaitForComplete()
2324 if GlobalData.gBinCacheDest:
2325 self.GenDestCache()
2326 elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:
2327 # Only for --hash
2328 # Update PreMakeCacheChain files
2329 self.GenLocalPreMakeCache()
2330 #
2331 # Get Module List
2332 #
2333 ModuleList = {ma.Guid.upper(): ma for ma in self.BuildModules}
2334 self.BuildModules = []
2335 self.MakeTime += int(round((time.time() - MakeContiue)))
2336 #
2337 # Check for build error, and raise exception if one
2338 # has been signaled.
2339 #
2340 if BuildTask.HasError():
2341 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
2342
2343 # Create MAP file when Load Fix Address is enabled.
2344 if self.Target in ["", "all", "fds"]:
2345 for Arch in Wa.ArchList:
2346 #
2347 # Check whether the set fix address is above 4G for 32bit image.
2348 #
2349 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
2350 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")
2351
2352 #
2353 # Rebase module to the preferred memory address before GenFds
2354 #
2355 MapBuffer = []
2356 if self.LoadFixAddress != 0:
2357 self._CollectModuleMapBuffer(MapBuffer, ModuleList)
2358
2359 if self.Fdf:
2360 #
2361 # Generate FD image if there's a FDF file found
2362 #
2363 GenFdsStart = time.time()
2364 if GenFdsApi(Wa.GenFdsCommandDict, self.Db):
2365 EdkLogger.error("build", COMMAND_FAILURE)
2366 Threshold = self.GetFreeSizeThreshold()
2367 if Threshold:
2368 self.CheckFreeSizeThreshold(Threshold, Wa.FvDir)
2369
2370 #
2371 # Create MAP file for all platform FVs after GenFds.
2372 #
2373 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
2374 self.GenFdsTime += int(round((time.time() - GenFdsStart)))
2375 #
2376 # Save MAP buffer into MAP file.
2377 #
2378 self._SaveMapFile(MapBuffer, Wa)
2379 self.CreateGuidedSectionToolsFile(Wa)
2380
2381 ## GetFreeSizeThreshold()
2382 #
2383 # @retval int Threshold value
2384 #
2385 def GetFreeSizeThreshold(self):
2386 Threshold = None
2387 Threshold_Str = GlobalData.gCommandLineDefines.get('FV_SPARE_SPACE_THRESHOLD')
2388 if Threshold_Str:
2389 try:
2390 if Threshold_Str.lower().startswith('0x'):
2391 Threshold = int(Threshold_Str, 16)
2392 else:
2393 Threshold = int(Threshold_Str)
2394 except:
2395 EdkLogger.warn("build", 'incorrect value for FV_SPARE_SPACE_THRESHOLD %s.Only decimal or hex format is allowed.' % Threshold_Str)
2396 return Threshold
2397
2398 def CheckFreeSizeThreshold(self, Threshold=None, FvDir=None):
2399 if not isinstance(Threshold, int):
2400 return
2401 if not isinstance(FvDir, str) or not FvDir:
2402 return
2403 FdfParserObject = GlobalData.gFdfParser
2404 FvRegionNameList = [FvName for FvName in FdfParserObject.Profile.FvDict if FdfParserObject.Profile.FvDict[FvName].FvRegionInFD]
2405 for FvName in FdfParserObject.Profile.FvDict:
2406 if FvName in FvRegionNameList:
2407 FvSpaceInfoFileName = os.path.join(FvDir, FvName.upper() + '.Fv.map')
2408 if os.path.exists(FvSpaceInfoFileName):
2409 FileLinesList = getlines(FvSpaceInfoFileName)
2410 for Line in FileLinesList:
2411 NameValue = Line.split('=')
2412 if len(NameValue) == 2 and NameValue[0].strip() == 'EFI_FV_SPACE_SIZE':
2413 FreeSizeValue = int(NameValue[1].strip(), 0)
2414 if FreeSizeValue < Threshold:
2415 EdkLogger.error("build", FV_FREESIZE_ERROR,
2416 '%s FV free space %d is not enough to meet with the required spare space %d set by -D FV_SPARE_SPACE_THRESHOLD option.' % (
2417 FvName, FreeSizeValue, Threshold))
2418 break
2419
2420 ## Generate GuidedSectionTools.txt in the FV directories.
2421 #
2422 def CreateGuidedSectionToolsFile(self,Wa):
2423 for BuildTarget in self.BuildTargetList:
2424 for ToolChain in self.ToolChainList:
2425 FvDir = Wa.FvDir
2426 if not os.path.exists(FvDir):
2427 continue
2428
2429 for Arch in self.ArchList:
2430 # Look through the tool definitions for GUIDed tools
2431 guidAttribs = []
2432 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.items():
2433 GuidBuildTarget, GuidToolChain, GuidArch, GuidTool, GuidAttr = attrib.split('_')
2434 if GuidAttr.upper() == 'GUID':
2435 if GuidBuildTarget == TAB_STAR:
2436 GuidBuildTarget = BuildTarget
2437 if GuidToolChain == TAB_STAR:
2438 GuidToolChain = ToolChain
2439 if GuidArch == TAB_STAR:
2440 GuidArch = Arch
2441 if GuidBuildTarget == BuildTarget and GuidToolChain == ToolChain and GuidArch == Arch:
2442 path = '_'.join(attrib.split('_')[:-1]) + '_PATH'
2443 if path in self.ToolDef.ToolsDefTxtDictionary:
2444 path = self.ToolDef.ToolsDefTxtDictionary[path]
2445 path = self.GetRealPathOfTool(path)
2446 guidAttribs.append((value.lower(), GuidTool, path))
2447 # Sort by GuidTool name
2448 sorted (guidAttribs, key=lambda x: x[1])
2449 # Write out GuidedSecTools.txt
2450 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')
2451 toolsFile = open(toolsFile, 'wt')
2452 for guidedSectionTool in guidAttribs:
2453 print(' '.join(guidedSectionTool), file=toolsFile)
2454 toolsFile.close()
2455
2456 ## Returns the real path of the tool.
2457 #
2458 def GetRealPathOfTool (self, tool):
2459 if os.path.exists(tool):
2460 return os.path.realpath(tool)
2461 return tool
2462
2463 ## Launch the module or platform build
2464 #
2465 def Launch(self):
2466 self.AllDrivers = set()
2467 self.AllModules = set()
2468 self.PreMakeCacheMiss = set()
2469 self.PreMakeCacheHit = set()
2470 self.MakeCacheMiss = set()
2471 self.MakeCacheHit = set()
2472 if not self.ModuleFile:
2473 if not self.SpawnMode or self.Target not in ["", "all"]:
2474 self.SpawnMode = False
2475 self._BuildPlatform()
2476 else:
2477 self._MultiThreadBuildPlatform()
2478 else:
2479 self.SpawnMode = False
2480 self._BuildModule()
2481
2482 if self.Target == 'cleanall':
2483 RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)
2484
2485 def CreateAsBuiltInf(self):
2486 for Module in self.BuildModules:
2487 Module.CreateAsBuiltInf()
2488
2489 def GenDestCache(self):
2490 for Module in self.AllModules:
2491 Module.GenPreMakefileHashList()
2492 Module.GenMakefileHashList()
2493 Module.CopyModuleToCache()
2494
2495 def GenLocalPreMakeCache(self):
2496 for Module in self.PreMakeCacheMiss:
2497 Module.GenPreMakefileHashList()
2498
2499 ## Do some clean-up works when error occurred
2500 def Relinquish(self):
2501 OldLogLevel = EdkLogger.GetLevel()
2502 EdkLogger.SetLevel(EdkLogger.ERROR)
2503 Utils.Progressor.Abort()
2504 if self.SpawnMode == True:
2505 BuildTask.Abort()
2506 EdkLogger.SetLevel(OldLogLevel)
2507
2508 def ParseDefines(DefineList=[]):
2509 DefineDict = {}
2510 if DefineList is not None:
2511 for Define in DefineList:
2512 DefineTokenList = Define.split("=", 1)
2513 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):
2514 EdkLogger.error('build', FORMAT_INVALID,
2515 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2516 ExtraData=DefineTokenList[0])
2517
2518 if len(DefineTokenList) == 1:
2519 DefineDict[DefineTokenList[0]] = "TRUE"
2520 else:
2521 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()
2522 return DefineDict
2523
2524
2525
2526 def LogBuildTime(Time):
2527 if Time:
2528 TimeDurStr = ''
2529 TimeDur = time.gmtime(Time)
2530 if TimeDur.tm_yday > 1:
2531 TimeDurStr = time.strftime("%H:%M:%S", TimeDur) + ", %d day(s)" % (TimeDur.tm_yday - 1)
2532 else:
2533 TimeDurStr = time.strftime("%H:%M:%S", TimeDur)
2534 return TimeDurStr
2535 else:
2536 return None
2537 def ThreadNum():
2538 OptionParser = MyOptionParser()
2539 if not OptionParser.BuildOption and not OptionParser.BuildTarget:
2540 OptionParser.GetOption()
2541 BuildOption, BuildTarget = OptionParser.BuildOption, OptionParser.BuildTarget
2542 ThreadNumber = BuildOption.ThreadNumber
2543 GlobalData.gCmdConfDir = BuildOption.ConfDirectory
2544 if ThreadNumber is None:
2545 TargetObj = TargetTxtDict()
2546 ThreadNumber = TargetObj.Target.TargetTxtDictionary[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]
2547 if ThreadNumber == '':
2548 ThreadNumber = 0
2549 else:
2550 ThreadNumber = int(ThreadNumber, 0)
2551
2552 if ThreadNumber == 0:
2553 try:
2554 ThreadNumber = multiprocessing.cpu_count()
2555 except (ImportError, NotImplementedError):
2556 ThreadNumber = 1
2557 return ThreadNumber
2558 ## Tool entrance method
2559 #
2560 # This method mainly dispatch specific methods per the command line options.
2561 # If no error found, return zero value so the caller of this tool can know
2562 # if it's executed successfully or not.
2563 #
2564 # @retval 0 Tool was successful
2565 # @retval 1 Tool failed
2566 #
2567 LogQMaxSize = ThreadNum() * 10
2568 def Main():
2569 StartTime = time.time()
2570
2571 #
2572 # Create a log Queue
2573 #
2574 LogQ = mp.Queue(LogQMaxSize)
2575 # Initialize log system
2576 EdkLogger.LogClientInitialize(LogQ)
2577 GlobalData.gCommand = sys.argv[1:]
2578 #
2579 # Parse the options and args
2580 #
2581 OptionParser = MyOptionParser()
2582 if not OptionParser.BuildOption and not OptionParser.BuildTarget:
2583 OptionParser.GetOption()
2584 Option, Target = OptionParser.BuildOption, OptionParser.BuildTarget
2585 GlobalData.gOptions = Option
2586 GlobalData.gCaseInsensitive = Option.CaseInsensitive
2587
2588 # Set log level
2589 LogLevel = EdkLogger.INFO
2590 if Option.verbose is not None:
2591 EdkLogger.SetLevel(EdkLogger.VERBOSE)
2592 LogLevel = EdkLogger.VERBOSE
2593 elif Option.quiet is not None:
2594 EdkLogger.SetLevel(EdkLogger.QUIET)
2595 LogLevel = EdkLogger.QUIET
2596 elif Option.debug is not None:
2597 EdkLogger.SetLevel(Option.debug + 1)
2598 LogLevel = Option.debug + 1
2599 else:
2600 EdkLogger.SetLevel(EdkLogger.INFO)
2601
2602 if Option.WarningAsError == True:
2603 EdkLogger.SetWarningAsError()
2604 Log_Agent = LogAgent(LogQ,LogLevel,Option.LogFile)
2605 Log_Agent.start()
2606
2607 if platform.platform().find("Windows") >= 0:
2608 GlobalData.gIsWindows = True
2609 else:
2610 GlobalData.gIsWindows = False
2611
2612 EdkLogger.quiet("Build environment: %s" % platform.platform())
2613 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));
2614 ReturnCode = 0
2615 MyBuild = None
2616 BuildError = True
2617 try:
2618 if len(Target) == 0:
2619 Target = "all"
2620 elif len(Target) >= 2:
2621 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",
2622 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))
2623 else:
2624 Target = Target[0].lower()
2625
2626 if Target not in gSupportedTarget:
2627 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,
2628 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))
2629
2630 #
2631 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2632 #
2633 CheckEnvVariable()
2634 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))
2635
2636 Workspace = os.getenv("WORKSPACE")
2637 #
2638 # Get files real name in workspace dir
2639 #
2640 GlobalData.gAllFiles = Utils.DirCache(Workspace)
2641
2642 WorkingDirectory = os.getcwd()
2643 if not Option.ModuleFile:
2644 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))
2645 FileNum = len(FileList)
2646 if FileNum >= 2:
2647 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),
2648 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2649 elif FileNum == 1:
2650 Option.ModuleFile = NormFile(FileList[0], Workspace)
2651
2652 if Option.ModuleFile:
2653 if os.path.isabs (Option.ModuleFile):
2654 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:
2655 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)
2656 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)
2657 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)
2658 if ErrorCode != 0:
2659 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
2660
2661 if Option.PlatformFile is not None:
2662 if os.path.isabs (Option.PlatformFile):
2663 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:
2664 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)
2665 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)
2666
2667 if Option.FdfFile is not None:
2668 if os.path.isabs (Option.FdfFile):
2669 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:
2670 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)
2671 Option.FdfFile = PathClass(Option.FdfFile, Workspace)
2672 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)
2673 if ErrorCode != 0:
2674 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
2675
2676 if Option.Flag is not None and Option.Flag not in ['-c', '-s']:
2677 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")
2678
2679 MyBuild = Build(Target, Workspace, Option,LogQ)
2680 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)
2681 if not (MyBuild.LaunchPrebuildFlag and os.path.exists(MyBuild.PlatformBuildPath)):
2682 MyBuild.Launch()
2683
2684 #
2685 # All job done, no error found and no exception raised
2686 #
2687 BuildError = False
2688 except FatalError as X:
2689 if MyBuild is not None:
2690 # for multi-thread build exits safely
2691 MyBuild.Relinquish()
2692 if Option is not None and Option.debug is not None:
2693 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2694 ReturnCode = X.args[0]
2695 except Warning as X:
2696 # error from Fdf parser
2697 if MyBuild is not None:
2698 # for multi-thread build exits safely
2699 MyBuild.Relinquish()
2700 if Option is not None and Option.debug is not None:
2701 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2702 else:
2703 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)
2704 ReturnCode = FORMAT_INVALID
2705 except KeyboardInterrupt:
2706 if MyBuild is not None:
2707
2708 # for multi-thread build exits safely
2709 MyBuild.Relinquish()
2710 ReturnCode = ABORT_ERROR
2711 if Option is not None and Option.debug is not None:
2712 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2713 except:
2714 if MyBuild is not None:
2715 # for multi-thread build exits safely
2716 MyBuild.Relinquish()
2717
2718 # try to get the meta-file from the object causing exception
2719 Tb = sys.exc_info()[-1]
2720 MetaFile = GlobalData.gProcessingFile
2721 while Tb is not None:
2722 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):
2723 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile
2724 Tb = Tb.tb_next
2725 EdkLogger.error(
2726 "\nbuild",
2727 CODE_ERROR,
2728 "Unknown fatal error when processing [%s]" % MetaFile,
2729 ExtraData="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR,
2730 RaiseError=False
2731 )
2732 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2733 ReturnCode = CODE_ERROR
2734 finally:
2735 Utils.Progressor.Abort()
2736 Utils.ClearDuplicatedInf()
2737
2738 if ReturnCode == 0:
2739 try:
2740 MyBuild.LaunchPostbuild()
2741 Conclusion = "Done"
2742 except:
2743 Conclusion = "Failed"
2744 elif ReturnCode == ABORT_ERROR:
2745 Conclusion = "Aborted"
2746 else:
2747 Conclusion = "Failed"
2748 FinishTime = time.time()
2749 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))
2750 BuildDurationStr = ""
2751 if BuildDuration.tm_yday > 1:
2752 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)" % (BuildDuration.tm_yday - 1)
2753 else:
2754 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)
2755 if MyBuild is not None:
2756 if not BuildError:
2757 MyBuild.BuildReport.GenerateReport(BuildDurationStr, LogBuildTime(MyBuild.AutoGenTime), LogBuildTime(MyBuild.MakeTime), LogBuildTime(MyBuild.GenFdsTime))
2758
2759 EdkLogger.SetLevel(EdkLogger.QUIET)
2760 EdkLogger.quiet("\n- %s -" % Conclusion)
2761 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))
2762 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)
2763 Log_Agent.kill()
2764 Log_Agent.join()
2765 return ReturnCode
2766
2767 if __name__ == '__main__':
2768 try:
2769 mp.set_start_method('spawn')
2770 except:
2771 pass
2772 r = Main()
2773 ## 0-127 is a safe return range, and 1 is a standard default error
2774 if r < 0 or r > 127: r = 1
2775 sys.exit(r)