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