]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/build/build.py
ShellPkg: Fix comments. Refine code style.
[mirror_edk2.git] / BaseTools / Source / Python / build / build.py
1 ## @file
2 # build a platform or a module
3 #
4 # Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
5 #
6 # This program and the accompanying materials
7 # are licensed and made available under the terms and conditions of the BSD License
8 # which accompanies this distribution. The full text of the license may be found at
9 # http://opensource.org/licenses/bsd-license.php
10 #
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 #
14
15 ##
16 # Import Modules
17 #
18 import Common.LongFilePathOs as os
19 import re
20 import StringIO
21 import sys
22 import glob
23 import time
24 import platform
25 import traceback
26 import encodings.ascii
27
28 from struct import *
29 from threading import *
30 from optparse import OptionParser
31 from subprocess import *
32 from Common import Misc as Utils
33
34 from Common.LongFilePathSupport import OpenLongFilePath as open
35 from Common.LongFilePathSupport import LongFilePath
36 from Common.TargetTxtClassObject import *
37 from Common.ToolDefClassObject import *
38 from Common.DataType import *
39 from Common.BuildVersion import gBUILD_VERSION
40 from AutoGen.AutoGen import *
41 from Common.BuildToolError import *
42 from Workspace.WorkspaceDatabase import *
43
44 from BuildReport import BuildReport
45 from GenPatchPcdTable.GenPatchPcdTable import *
46 from PatchPcdValue.PatchPcdValue import *
47
48 import Common.EdkLogger
49 import Common.GlobalData as GlobalData
50
51 # Version and Copyright
52 VersionNumber = "0.51" + ' ' + gBUILD_VERSION
53 __version__ = "%prog Version " + VersionNumber
54 __copyright__ = "Copyright (c) 2007 - 2014, Intel Corporation All rights reserved."
55
56 ## standard targets of build command
57 gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
58
59 ## build configuration file
60 gBuildConfiguration = "Conf/target.txt"
61 gBuildCacheDir = "Conf/.cache"
62 gToolsDefinition = "Conf/tools_def.txt"
63
64 TemporaryTablePattern = re.compile(r'^_\d+_\d+_[a-fA-F0-9]+$')
65 TmpTableDict = {}
66
67 ## Check environment PATH variable to make sure the specified tool is found
68 #
69 # If the tool is found in the PATH, then True is returned
70 # Otherwise, False is returned
71 #
72 def IsToolInPath(tool):
73 if os.environ.has_key('PATHEXT'):
74 extns = os.environ['PATHEXT'].split(os.path.pathsep)
75 else:
76 extns = ('',)
77 for pathDir in os.environ['PATH'].split(os.path.pathsep):
78 for ext in extns:
79 if os.path.exists(os.path.join(pathDir, tool + ext)):
80 return True
81 return False
82
83 ## Check environment variables
84 #
85 # Check environment variables that must be set for build. Currently they are
86 #
87 # WORKSPACE The directory all packages/platforms start from
88 # EDK_TOOLS_PATH The directory contains all tools needed by the build
89 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
90 #
91 # If any of above environment variable is not set or has error, the build
92 # will be broken.
93 #
94 def CheckEnvVariable():
95 # check WORKSPACE
96 if "WORKSPACE" not in os.environ:
97 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
98 ExtraData="WORKSPACE")
99
100 WorkspaceDir = os.path.normcase(os.path.normpath(os.environ["WORKSPACE"]))
101 if not os.path.exists(WorkspaceDir):
102 EdkLogger.error("build", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData="%s" % WorkspaceDir)
103 elif ' ' in WorkspaceDir:
104 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path",
105 ExtraData=WorkspaceDir)
106 os.environ["WORKSPACE"] = WorkspaceDir
107
108 #
109 # Check EFI_SOURCE (Edk build convention). EDK_SOURCE will always point to ECP
110 #
111 if "ECP_SOURCE" not in os.environ:
112 os.environ["ECP_SOURCE"] = os.path.join(WorkspaceDir, GlobalData.gEdkCompatibilityPkg)
113 if "EFI_SOURCE" not in os.environ:
114 os.environ["EFI_SOURCE"] = os.environ["ECP_SOURCE"]
115 if "EDK_SOURCE" not in os.environ:
116 os.environ["EDK_SOURCE"] = os.environ["ECP_SOURCE"]
117
118 #
119 # Unify case of characters on case-insensitive systems
120 #
121 EfiSourceDir = os.path.normcase(os.path.normpath(os.environ["EFI_SOURCE"]))
122 EdkSourceDir = os.path.normcase(os.path.normpath(os.environ["EDK_SOURCE"]))
123 EcpSourceDir = os.path.normcase(os.path.normpath(os.environ["ECP_SOURCE"]))
124
125 os.environ["EFI_SOURCE"] = EfiSourceDir
126 os.environ["EDK_SOURCE"] = EdkSourceDir
127 os.environ["ECP_SOURCE"] = EcpSourceDir
128 os.environ["EDK_TOOLS_PATH"] = os.path.normcase(os.environ["EDK_TOOLS_PATH"])
129
130 if not os.path.exists(EcpSourceDir):
131 EdkLogger.verbose("ECP_SOURCE = %s doesn't exist. Edk modules could not be built." % EcpSourceDir)
132 elif ' ' in EcpSourceDir:
133 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in ECP_SOURCE path",
134 ExtraData=EcpSourceDir)
135 if not os.path.exists(EdkSourceDir):
136 if EdkSourceDir == EcpSourceDir:
137 EdkLogger.verbose("EDK_SOURCE = %s doesn't exist. Edk modules could not be built." % EdkSourceDir)
138 else:
139 EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE does not exist",
140 ExtraData=EdkSourceDir)
141 elif ' ' in EdkSourceDir:
142 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EDK_SOURCE path",
143 ExtraData=EdkSourceDir)
144 if not os.path.exists(EfiSourceDir):
145 if EfiSourceDir == EcpSourceDir:
146 EdkLogger.verbose("EFI_SOURCE = %s doesn't exist. Edk modules could not be built." % EfiSourceDir)
147 else:
148 EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE does not exist",
149 ExtraData=EfiSourceDir)
150 elif ' ' in EfiSourceDir:
151 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EFI_SOURCE path",
152 ExtraData=EfiSourceDir)
153
154 # change absolute path to relative path to WORKSPACE
155 if EfiSourceDir.upper().find(WorkspaceDir.upper()) != 0:
156 EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE is not under WORKSPACE",
157 ExtraData="WORKSPACE = %s\n EFI_SOURCE = %s" % (WorkspaceDir, EfiSourceDir))
158 if EdkSourceDir.upper().find(WorkspaceDir.upper()) != 0:
159 EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE is not under WORKSPACE",
160 ExtraData="WORKSPACE = %s\n EDK_SOURCE = %s" % (WorkspaceDir, EdkSourceDir))
161 if EcpSourceDir.upper().find(WorkspaceDir.upper()) != 0:
162 EdkLogger.error("build", PARAMETER_INVALID, "ECP_SOURCE is not under WORKSPACE",
163 ExtraData="WORKSPACE = %s\n ECP_SOURCE = %s" % (WorkspaceDir, EcpSourceDir))
164
165 # check EDK_TOOLS_PATH
166 if "EDK_TOOLS_PATH" not in os.environ:
167 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
168 ExtraData="EDK_TOOLS_PATH")
169
170 # check PATH
171 if "PATH" not in os.environ:
172 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
173 ExtraData="PATH")
174
175 GlobalData.gWorkspace = WorkspaceDir
176 GlobalData.gEfiSource = EfiSourceDir
177 GlobalData.gEdkSource = EdkSourceDir
178 GlobalData.gEcpSource = EcpSourceDir
179
180 GlobalData.gGlobalDefines["WORKSPACE"] = WorkspaceDir
181 GlobalData.gGlobalDefines["EFI_SOURCE"] = EfiSourceDir
182 GlobalData.gGlobalDefines["EDK_SOURCE"] = EdkSourceDir
183 GlobalData.gGlobalDefines["ECP_SOURCE"] = EcpSourceDir
184 GlobalData.gGlobalDefines["EDK_TOOLS_PATH"] = os.environ["EDK_TOOLS_PATH"]
185
186 ## Get normalized file path
187 #
188 # Convert the path to be local format, and remove the WORKSPACE path at the
189 # beginning if the file path is given in full path.
190 #
191 # @param FilePath File path to be normalized
192 # @param Workspace Workspace path which the FilePath will be checked against
193 #
194 # @retval string The normalized file path
195 #
196 def NormFile(FilePath, Workspace):
197 # check if the path is absolute or relative
198 if os.path.isabs(FilePath):
199 FileFullPath = os.path.normpath(FilePath)
200 else:
201 FileFullPath = os.path.normpath(os.path.join(Workspace, FilePath))
202
203 # check if the file path exists or not
204 if not os.path.isfile(FileFullPath):
205 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath)
206
207 # remove workspace directory from the beginning part of the file path
208 if Workspace[-1] in ["\\", "/"]:
209 return FileFullPath[len(Workspace):]
210 else:
211 return FileFullPath[(len(Workspace) + 1):]
212
213 ## Get the output of an external program
214 #
215 # This is the entrance method of thread reading output of an external program and
216 # putting them in STDOUT/STDERR of current program.
217 #
218 # @param From The stream message read from
219 # @param To The stream message put on
220 # @param ExitFlag The flag used to indicate stopping reading
221 #
222 def ReadMessage(From, To, ExitFlag):
223 while True:
224 # read one line a time
225 Line = From.readline()
226 # empty string means "end"
227 if Line != None and Line != "":
228 To(Line.rstrip())
229 else:
230 break
231 if ExitFlag.isSet():
232 break
233
234 ## Launch an external program
235 #
236 # This method will call subprocess.Popen to execute an external program with
237 # given options in specified directory. Because of the dead-lock issue during
238 # redirecting output of the external program, threads are used to to do the
239 # redirection work.
240 #
241 # @param Command A list or string containing the call of the program
242 # @param WorkingDir The directory in which the program will be running
243 #
244 def LaunchCommand(Command, WorkingDir):
245 # if working directory doesn't exist, Popen() will raise an exception
246 if not os.path.isdir(WorkingDir):
247 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=WorkingDir)
248
249 Proc = None
250 EndOfProcedure = None
251 try:
252 # launch the command
253 Proc = Popen(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir, bufsize=-1)
254
255 # launch two threads to read the STDOUT and STDERR
256 EndOfProcedure = Event()
257 EndOfProcedure.clear()
258 if Proc.stdout:
259 StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure))
260 StdOutThread.setName("STDOUT-Redirector")
261 StdOutThread.setDaemon(False)
262 StdOutThread.start()
263
264 if Proc.stderr:
265 StdErrThread = Thread(target=ReadMessage, args=(Proc.stderr, EdkLogger.quiet, EndOfProcedure))
266 StdErrThread.setName("STDERR-Redirector")
267 StdErrThread.setDaemon(False)
268 StdErrThread.start()
269
270 # waiting for program exit
271 Proc.wait()
272 except: # in case of aborting
273 # terminate the threads redirecting the program output
274 if EndOfProcedure != None:
275 EndOfProcedure.set()
276 if Proc == None:
277 if type(Command) != type(""):
278 Command = " ".join(Command)
279 EdkLogger.error("build", COMMAND_FAILURE, "Failed to start command", ExtraData="%s [%s]" % (Command, WorkingDir))
280
281 if Proc.stdout:
282 StdOutThread.join()
283 if Proc.stderr:
284 StdErrThread.join()
285
286 # check the return code of the program
287 if Proc.returncode != 0:
288 if type(Command) != type(""):
289 Command = " ".join(Command)
290 EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir))
291
292 ## The smallest unit that can be built in multi-thread build mode
293 #
294 # This is the base class of build unit. The "Obj" parameter must provide
295 # __str__(), __eq__() and __hash__() methods. Otherwise there could be build units
296 # missing build.
297 #
298 # Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.
299 #
300 class BuildUnit:
301 ## The constructor
302 #
303 # @param self The object pointer
304 # @param Obj The object the build is working on
305 # @param Target The build target name, one of gSupportedTarget
306 # @param Dependency The BuildUnit(s) which must be completed in advance
307 # @param WorkingDir The directory build command starts in
308 #
309 def __init__(self, Obj, BuildCommand, Target, Dependency, WorkingDir="."):
310 self.BuildObject = Obj
311 self.Dependency = Dependency
312 self.WorkingDir = WorkingDir
313 self.Target = Target
314 self.BuildCommand = BuildCommand
315 if not BuildCommand:
316 EdkLogger.error("build", OPTION_MISSING,
317 "No build command found for this module. "
318 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
319 (Obj.BuildTarget, Obj.ToolChain, Obj.Arch),
320 ExtraData=str(Obj))
321
322
323 ## str() method
324 #
325 # It just returns the string representation of self.BuildObject
326 #
327 # @param self The object pointer
328 #
329 def __str__(self):
330 return str(self.BuildObject)
331
332 ## "==" operator method
333 #
334 # It just compares self.BuildObject with "Other". So self.BuildObject must
335 # provide its own __eq__() method.
336 #
337 # @param self The object pointer
338 # @param Other The other BuildUnit object compared to
339 #
340 def __eq__(self, Other):
341 return Other != None and self.BuildObject == Other.BuildObject \
342 and self.BuildObject.Arch == Other.BuildObject.Arch
343
344 ## hash() method
345 #
346 # It just returns the hash value of self.BuildObject which must be hashable.
347 #
348 # @param self The object pointer
349 #
350 def __hash__(self):
351 return hash(self.BuildObject) + hash(self.BuildObject.Arch)
352
353 def __repr__(self):
354 return repr(self.BuildObject)
355
356 ## The smallest module unit that can be built by nmake/make command in multi-thread build mode
357 #
358 # This class is for module build by nmake/make build system. The "Obj" parameter
359 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
360 # be make units missing build.
361 #
362 # Currently the "Obj" should be only ModuleAutoGen object.
363 #
364 class ModuleMakeUnit(BuildUnit):
365 ## The constructor
366 #
367 # @param self The object pointer
368 # @param Obj The ModuleAutoGen object the build is working on
369 # @param Target The build target name, one of gSupportedTarget
370 #
371 def __init__(self, Obj, Target):
372 Dependency = [ModuleMakeUnit(La, Target) for La in Obj.LibraryAutoGenList]
373 BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)
374 if Target in [None, "", "all"]:
375 self.Target = "tbuild"
376
377 ## The smallest platform unit that can be built by nmake/make command in multi-thread build mode
378 #
379 # This class is for platform build by nmake/make build system. The "Obj" parameter
380 # must provide __str__(), __eq__() and __hash__() methods. Otherwise there could
381 # be make units missing build.
382 #
383 # Currently the "Obj" should be only PlatformAutoGen object.
384 #
385 class PlatformMakeUnit(BuildUnit):
386 ## The constructor
387 #
388 # @param self The object pointer
389 # @param Obj The PlatformAutoGen object the build is working on
390 # @param Target The build target name, one of gSupportedTarget
391 #
392 def __init__(self, Obj, Target):
393 Dependency = [ModuleMakeUnit(Lib, Target) for Lib in self.BuildObject.LibraryAutoGenList]
394 Dependency.extend([ModuleMakeUnit(Mod, Target) for Mod in self.BuildObject.ModuleAutoGenList])
395 BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)
396
397 ## The class representing the task of a module build or platform build
398 #
399 # This class manages the build tasks in multi-thread build mode. Its jobs include
400 # scheduling thread running, catching thread error, monitor the thread status, etc.
401 #
402 class BuildTask:
403 # queue for tasks waiting for schedule
404 _PendingQueue = sdict()
405 _PendingQueueLock = threading.Lock()
406
407 # queue for tasks ready for running
408 _ReadyQueue = sdict()
409 _ReadyQueueLock = threading.Lock()
410
411 # queue for run tasks
412 _RunningQueue = sdict()
413 _RunningQueueLock = threading.Lock()
414
415 # queue containing all build tasks, in case duplicate build
416 _TaskQueue = sdict()
417
418 # flag indicating error occurs in a running thread
419 _ErrorFlag = threading.Event()
420 _ErrorFlag.clear()
421 _ErrorMessage = ""
422
423 # BoundedSemaphore object used to control the number of running threads
424 _Thread = None
425
426 # flag indicating if the scheduler is started or not
427 _SchedulerStopped = threading.Event()
428 _SchedulerStopped.set()
429
430 ## Start the task scheduler thread
431 #
432 # @param MaxThreadNumber The maximum thread number
433 # @param ExitFlag Flag used to end the scheduler
434 #
435 @staticmethod
436 def StartScheduler(MaxThreadNumber, ExitFlag):
437 SchedulerThread = Thread(target=BuildTask.Scheduler, args=(MaxThreadNumber, ExitFlag))
438 SchedulerThread.setName("Build-Task-Scheduler")
439 SchedulerThread.setDaemon(False)
440 SchedulerThread.start()
441 # wait for the scheduler to be started, especially useful in Linux
442 while not BuildTask.IsOnGoing():
443 time.sleep(0.01)
444
445 ## Scheduler method
446 #
447 # @param MaxThreadNumber The maximum thread number
448 # @param ExitFlag Flag used to end the scheduler
449 #
450 @staticmethod
451 def Scheduler(MaxThreadNumber, ExitFlag):
452 BuildTask._SchedulerStopped.clear()
453 try:
454 # use BoundedSemaphore to control the maximum running threads
455 BuildTask._Thread = BoundedSemaphore(MaxThreadNumber)
456 #
457 # scheduling loop, which will exits when no pending/ready task and
458 # indicated to do so, or there's error in running thread
459 #
460 while (len(BuildTask._PendingQueue) > 0 or len(BuildTask._ReadyQueue) > 0 \
461 or not ExitFlag.isSet()) and not BuildTask._ErrorFlag.isSet():
462 EdkLogger.debug(EdkLogger.DEBUG_8, "Pending Queue (%d), Ready Queue (%d)"
463 % (len(BuildTask._PendingQueue), len(BuildTask._ReadyQueue)))
464
465 # get all pending tasks
466 BuildTask._PendingQueueLock.acquire()
467 BuildObjectList = BuildTask._PendingQueue.keys()
468 #
469 # check if their dependency is resolved, and if true, move them
470 # into ready queue
471 #
472 for BuildObject in BuildObjectList:
473 Bt = BuildTask._PendingQueue[BuildObject]
474 if Bt.IsReady():
475 BuildTask._ReadyQueue[BuildObject] = BuildTask._PendingQueue.pop(BuildObject)
476 BuildTask._PendingQueueLock.release()
477
478 # launch build thread until the maximum number of threads is reached
479 while not BuildTask._ErrorFlag.isSet():
480 # empty ready queue, do nothing further
481 if len(BuildTask._ReadyQueue) == 0:
482 break
483
484 # wait for active thread(s) exit
485 BuildTask._Thread.acquire(True)
486
487 # start a new build thread
488 Bo = BuildTask._ReadyQueue.keys()[0]
489 Bt = BuildTask._ReadyQueue.pop(Bo)
490
491 # move into running queue
492 BuildTask._RunningQueueLock.acquire()
493 BuildTask._RunningQueue[Bo] = Bt
494 BuildTask._RunningQueueLock.release()
495
496 Bt.Start()
497 # avoid tense loop
498 time.sleep(0.01)
499
500 # avoid tense loop
501 time.sleep(0.01)
502
503 # wait for all running threads exit
504 if BuildTask._ErrorFlag.isSet():
505 EdkLogger.quiet("\nWaiting for all build threads exit...")
506 # while not BuildTask._ErrorFlag.isSet() and \
507 while len(BuildTask._RunningQueue) > 0:
508 EdkLogger.verbose("Waiting for thread ending...(%d)" % len(BuildTask._RunningQueue))
509 EdkLogger.debug(EdkLogger.DEBUG_8, "Threads [%s]" % ", ".join([Th.getName() for Th in threading.enumerate()]))
510 # avoid tense loop
511 time.sleep(0.1)
512 except BaseException, X:
513 #
514 # TRICK: hide the output of threads left runing, so that the user can
515 # catch the error message easily
516 #
517 EdkLogger.SetLevel(EdkLogger.ERROR)
518 BuildTask._ErrorFlag.set()
519 BuildTask._ErrorMessage = "build thread scheduler error\n\t%s" % str(X)
520
521 BuildTask._PendingQueue.clear()
522 BuildTask._ReadyQueue.clear()
523 BuildTask._RunningQueue.clear()
524 BuildTask._TaskQueue.clear()
525 BuildTask._SchedulerStopped.set()
526
527 ## Wait for all running method exit
528 #
529 @staticmethod
530 def WaitForComplete():
531 BuildTask._SchedulerStopped.wait()
532
533 ## Check if the scheduler is running or not
534 #
535 @staticmethod
536 def IsOnGoing():
537 return not BuildTask._SchedulerStopped.isSet()
538
539 ## Abort the build
540 @staticmethod
541 def Abort():
542 if BuildTask.IsOnGoing():
543 BuildTask._ErrorFlag.set()
544 BuildTask.WaitForComplete()
545
546 ## Check if there's error in running thread
547 #
548 # Since the main thread cannot catch exceptions in other thread, we have to
549 # use threading.Event to communicate this formation to main thread.
550 #
551 @staticmethod
552 def HasError():
553 return BuildTask._ErrorFlag.isSet()
554
555 ## Get error message in running thread
556 #
557 # Since the main thread cannot catch exceptions in other thread, we have to
558 # use a static variable to communicate this message to main thread.
559 #
560 @staticmethod
561 def GetErrorMessage():
562 return BuildTask._ErrorMessage
563
564 ## Factory method to create a BuildTask object
565 #
566 # This method will check if a module is building or has been built. And if
567 # true, just return the associated BuildTask object in the _TaskQueue. If
568 # not, create and return a new BuildTask object. The new BuildTask object
569 # will be appended to the _PendingQueue for scheduling later.
570 #
571 # @param BuildItem A BuildUnit object representing a build object
572 # @param Dependency The dependent build object of BuildItem
573 #
574 @staticmethod
575 def New(BuildItem, Dependency=None):
576 if BuildItem in BuildTask._TaskQueue:
577 Bt = BuildTask._TaskQueue[BuildItem]
578 return Bt
579
580 Bt = BuildTask()
581 Bt._Init(BuildItem, Dependency)
582 BuildTask._TaskQueue[BuildItem] = Bt
583
584 BuildTask._PendingQueueLock.acquire()
585 BuildTask._PendingQueue[BuildItem] = Bt
586 BuildTask._PendingQueueLock.release()
587
588 return Bt
589
590 ## The real constructor of BuildTask
591 #
592 # @param BuildItem A BuildUnit object representing a build object
593 # @param Dependency The dependent build object of BuildItem
594 #
595 def _Init(self, BuildItem, Dependency=None):
596 self.BuildItem = BuildItem
597
598 self.DependencyList = []
599 if Dependency == None:
600 Dependency = BuildItem.Dependency
601 else:
602 Dependency.extend(BuildItem.Dependency)
603 self.AddDependency(Dependency)
604 # flag indicating build completes, used to avoid unnecessary re-build
605 self.CompleteFlag = False
606
607 ## Check if all dependent build tasks are completed or not
608 #
609 def IsReady(self):
610 ReadyFlag = True
611 for Dep in self.DependencyList:
612 if Dep.CompleteFlag == True:
613 continue
614 ReadyFlag = False
615 break
616
617 return ReadyFlag
618
619 ## Add dependent build task
620 #
621 # @param Dependency The list of dependent build objects
622 #
623 def AddDependency(self, Dependency):
624 for Dep in Dependency:
625 self.DependencyList.append(BuildTask.New(Dep)) # BuildTask list
626
627 ## The thread wrapper of LaunchCommand function
628 #
629 # @param Command A list or string contains the call of the command
630 # @param WorkingDir The directory in which the program will be running
631 #
632 def _CommandThread(self, Command, WorkingDir):
633 try:
634 LaunchCommand(Command, WorkingDir)
635 self.CompleteFlag = True
636 except:
637 #
638 # TRICK: hide the output of threads left runing, so that the user can
639 # catch the error message easily
640 #
641 if not BuildTask._ErrorFlag.isSet():
642 GlobalData.gBuildingModule = "%s [%s, %s, %s]" % (str(self.BuildItem.BuildObject),
643 self.BuildItem.BuildObject.Arch,
644 self.BuildItem.BuildObject.ToolChain,
645 self.BuildItem.BuildObject.BuildTarget
646 )
647 EdkLogger.SetLevel(EdkLogger.ERROR)
648 BuildTask._ErrorFlag.set()
649 BuildTask._ErrorMessage = "%s broken\n %s [%s]" % \
650 (threading.currentThread().getName(), Command, WorkingDir)
651 # indicate there's a thread is available for another build task
652 BuildTask._RunningQueueLock.acquire()
653 BuildTask._RunningQueue.pop(self.BuildItem)
654 BuildTask._RunningQueueLock.release()
655 BuildTask._Thread.release()
656
657 ## Start build task thread
658 #
659 def Start(self):
660 EdkLogger.quiet("Building ... %s" % repr(self.BuildItem))
661 Command = self.BuildItem.BuildCommand + [self.BuildItem.Target]
662 self.BuildTread = Thread(target=self._CommandThread, args=(Command, self.BuildItem.WorkingDir))
663 self.BuildTread.setName("build thread")
664 self.BuildTread.setDaemon(False)
665 self.BuildTread.start()
666
667 ## The class contains the information related to EFI image
668 #
669 class PeImageInfo():
670 ## Constructor
671 #
672 # Constructor will load all required image information.
673 #
674 # @param BaseName The full file path of image.
675 # @param Guid The GUID for image.
676 # @param Arch Arch of this image.
677 # @param OutputDir The output directory for image.
678 # @param DebugDir The debug directory for image.
679 # @param ImageClass PeImage Information
680 #
681 def __init__(self, BaseName, Guid, Arch, OutputDir, DebugDir, ImageClass):
682 self.BaseName = BaseName
683 self.Guid = Guid
684 self.Arch = Arch
685 self.OutputDir = OutputDir
686 self.DebugDir = DebugDir
687 self.Image = ImageClass
688 self.Image.Size = (self.Image.Size / 0x1000 + 1) * 0x1000
689
690 ## The class implementing the EDK2 build process
691 #
692 # The build process includes:
693 # 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
694 # 2. Parse DSC file of active platform
695 # 3. Parse FDF file if any
696 # 4. Establish build database, including parse all other files (module, package)
697 # 5. Create AutoGen files (C code file, depex file, makefile) if necessary
698 # 6. Call build command
699 #
700 class Build():
701 ## Constructor
702 #
703 # Constructor will load all necessary configurations, parse platform, modules
704 # and packages and the establish a database for AutoGen.
705 #
706 # @param Target The build command target, one of gSupportedTarget
707 # @param WorkspaceDir The directory of workspace
708 # @param BuildOptions Build options passed from command line
709 #
710 def __init__(self, Target, WorkspaceDir, BuildOptions):
711 self.WorkspaceDir = WorkspaceDir
712 self.Target = Target
713 self.PlatformFile = BuildOptions.PlatformFile
714 self.ModuleFile = BuildOptions.ModuleFile
715 self.ArchList = BuildOptions.TargetArch
716 self.ToolChainList = BuildOptions.ToolChain
717 self.BuildTargetList= BuildOptions.BuildTarget
718 self.Fdf = BuildOptions.FdfFile
719 self.FdList = BuildOptions.RomImage
720 self.FvList = BuildOptions.FvImage
721 self.CapList = BuildOptions.CapName
722 self.SilentMode = BuildOptions.SilentMode
723 self.ThreadNumber = BuildOptions.ThreadNumber
724 self.SkipAutoGen = BuildOptions.SkipAutoGen
725 self.Reparse = BuildOptions.Reparse
726 self.SkuId = BuildOptions.SkuId
727 self.SpawnMode = True
728 self.BuildReport = BuildReport(BuildOptions.ReportFile, BuildOptions.ReportType)
729 self.TargetTxt = TargetTxtClassObject()
730 self.ToolDef = ToolDefClassObject()
731 if BuildOptions.DisableCache:
732 self.Db = WorkspaceDatabase(":memory:")
733 else:
734 self.Db = WorkspaceDatabase(None, self.Reparse)
735 self.BuildDatabase = self.Db.BuildObject
736 self.Platform = None
737 self.LoadFixAddress = 0
738 self.UniFlag = BuildOptions.Flag
739
740 # print dot character during doing some time-consuming work
741 self.Progress = Utils.Progressor()
742
743 self.InitBuild()
744
745 # print current build environment and configuration
746 EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))
747 EdkLogger.quiet("%-16s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"]))
748 EdkLogger.quiet("%-16s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"]))
749 EdkLogger.quiet("%-16s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"]))
750 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))
751
752 EdkLogger.info("")
753
754 os.chdir(self.WorkspaceDir)
755
756 ## Load configuration
757 #
758 # This method will parse target.txt and get the build configurations.
759 #
760 def LoadConfiguration(self):
761 #
762 # Check target.txt and tools_def.txt and Init them
763 #
764 BuildConfigurationFile = os.path.normpath(os.path.join(self.WorkspaceDir, gBuildConfiguration))
765 if os.path.isfile(BuildConfigurationFile) == True:
766 StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)
767
768 ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]
769 if ToolDefinitionFile == '':
770 ToolDefinitionFile = gToolsDefinition
771 ToolDefinitionFile = os.path.normpath(os.path.join(self.WorkspaceDir, ToolDefinitionFile))
772 if os.path.isfile(ToolDefinitionFile) == True:
773 StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)
774 else:
775 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)
776 else:
777 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)
778
779 # if no ARCH given in command line, get it from target.txt
780 if not self.ArchList:
781 self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH]
782 self.ArchList = tuple(self.ArchList)
783
784 # if no build target given in command line, get it from target.txt
785 if not self.BuildTargetList:
786 self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]
787
788 # if no tool chain given in command line, get it from target.txt
789 if not self.ToolChainList:
790 self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]
791 if self.ToolChainList == None or len(self.ToolChainList) == 0:
792 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")
793
794 # check if the tool chains are defined or not
795 NewToolChainList = []
796 for ToolChain in self.ToolChainList:
797 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:
798 EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)
799 else:
800 NewToolChainList.append(ToolChain)
801 # if no tool chain available, break the build
802 if len(NewToolChainList) == 0:
803 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
804 ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))
805 else:
806 self.ToolChainList = NewToolChainList
807
808 if self.ThreadNumber == None:
809 self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]
810 if self.ThreadNumber == '':
811 self.ThreadNumber = 0
812 else:
813 self.ThreadNumber = int(self.ThreadNumber, 0)
814
815 if self.ThreadNumber == 0:
816 self.ThreadNumber = 1
817
818 if not self.PlatformFile:
819 PlatformFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM]
820 if not PlatformFile:
821 # Try to find one in current directory
822 WorkingDirectory = os.getcwd()
823 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))
824 FileNum = len(FileList)
825 if FileNum >= 2:
826 EdkLogger.error("build", OPTION_MISSING,
827 ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))
828 elif FileNum == 1:
829 PlatformFile = FileList[0]
830 else:
831 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,
832 ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")
833
834 self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)
835
836 ## Initialize build configuration
837 #
838 # This method will parse DSC file and merge the configurations from
839 # command line and target.txt, then get the final build configurations.
840 #
841 def InitBuild(self):
842 # parse target.txt, tools_def.txt, and platform file
843 self.LoadConfiguration()
844
845 # Allow case-insensitive for those from command line or configuration file
846 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)
847 if ErrorCode != 0:
848 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
849
850 # create metafile database
851 self.Db.InitDatabase()
852
853 ## Build a module or platform
854 #
855 # Create autogen code and makefile for a module or platform, and the launch
856 # "make" command to build it
857 #
858 # @param Target The target of build command
859 # @param Platform The platform file
860 # @param Module The module file
861 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
862 # @param ToolChain The name of toolchain to build
863 # @param Arch The arch of the module/platform
864 # @param CreateDepModuleCodeFile Flag used to indicate creating code
865 # for dependent modules/Libraries
866 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
867 # for dependent modules/Libraries
868 #
869 def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True):
870 if AutoGenObject == None:
871 return False
872
873 # skip file generation for cleanxxx targets, run and fds target
874 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
875 # for target which must generate AutoGen code and makefile
876 if not self.SkipAutoGen or Target == 'genc':
877 self.Progress.Start("Generating code")
878 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
879 self.Progress.Stop("done!")
880 if Target == "genc":
881 return True
882
883 if not self.SkipAutoGen or Target == 'genmake':
884 self.Progress.Start("Generating makefile")
885 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)
886 AutoGenObject.CreateAsBuiltInf()
887 self.Progress.Stop("done!")
888 if Target == "genmake":
889 return True
890 else:
891 # always recreate top/platform makefile when clean, just in case of inconsistency
892 AutoGenObject.CreateCodeFile(False)
893 AutoGenObject.CreateMakeFile(False)
894
895 if EdkLogger.GetLevel() == EdkLogger.QUIET:
896 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
897
898 BuildCommand = AutoGenObject.BuildCommand
899 if BuildCommand == None or len(BuildCommand) == 0:
900 EdkLogger.error("build", OPTION_MISSING,
901 "No build command found for this module. "
902 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
903 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
904 ExtraData=str(AutoGenObject))
905
906 BuildCommand = BuildCommand + [Target]
907 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
908 if Target == 'cleanall':
909 try:
910 #os.rmdir(AutoGenObject.BuildDir)
911 RemoveDirectory(AutoGenObject.BuildDir, True)
912 #
913 # First should close DB.
914 #
915 self.Db.Close()
916 RemoveDirectory(gBuildCacheDir, True)
917 except WindowsError, X:
918 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
919 return True
920
921 ## Rebase module image and Get function address for the input module list.
922 #
923 def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):
924 if ModeIsSmm:
925 AddrIsOffset = False
926 InfFileNameList = ModuleList.keys()
927 #InfFileNameList.sort()
928 for InfFile in InfFileNameList:
929 sys.stdout.write (".")
930 sys.stdout.flush()
931 ModuleInfo = ModuleList[InfFile]
932 ModuleName = ModuleInfo.BaseName
933 ModuleOutputImage = ModuleInfo.Image.FileName
934 ModuleDebugImage = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')
935 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
936 if not ModeIsSmm:
937 BaseAddress = BaseAddress - ModuleInfo.Image.Size
938 #
939 # Update Image to new BaseAddress by GenFw tool
940 #
941 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
942 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
943 else:
944 #
945 # Set new address to the section header only for SMM driver.
946 #
947 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
948 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
949 #
950 # Collect funtion address from Map file
951 #
952 ImageMapTable = ModuleOutputImage.replace('.efi', '.map')
953 FunctionList = []
954 if os.path.exists(ImageMapTable):
955 OrigImageBaseAddress = 0
956 ImageMap = open (ImageMapTable, 'r')
957 for LinStr in ImageMap:
958 if len (LinStr.strip()) == 0:
959 continue
960 #
961 # Get the preferred address set on link time.
962 #
963 if LinStr.find ('Preferred load address is') != -1:
964 StrList = LinStr.split()
965 OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)
966
967 StrList = LinStr.split()
968 if len (StrList) > 4:
969 if StrList[3] == 'f' or StrList[3] =='F':
970 Name = StrList[1]
971 RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress
972 FunctionList.append ((Name, RelativeAddress))
973 if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'):
974 #
975 # Get the real entry point address for IPF image.
976 #
977 ModuleInfo.Image.EntryPoint = RelativeAddress
978 ImageMap.close()
979 #
980 # Add general information.
981 #
982 if ModeIsSmm:
983 MapBuffer.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
984 elif AddrIsOffset:
985 MapBuffer.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))
986 else:
987 MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
988 #
989 # Add guid and general seciton section.
990 #
991 TextSectionAddress = 0
992 DataSectionAddress = 0
993 for SectionHeader in ModuleInfo.Image.SectionHeaderList:
994 if SectionHeader[0] == '.text':
995 TextSectionAddress = SectionHeader[1]
996 elif SectionHeader[0] in ['.data', '.sdata']:
997 DataSectionAddress = SectionHeader[1]
998 if AddrIsOffset:
999 MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))
1000 else:
1001 MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))
1002 #
1003 # Add debug image full path.
1004 #
1005 MapBuffer.write('(IMAGE=%s)\n\n' % (ModuleDebugImage))
1006 #
1007 # Add funtion address
1008 #
1009 for Function in FunctionList:
1010 if AddrIsOffset:
1011 MapBuffer.write(' -0x%010X %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))
1012 else:
1013 MapBuffer.write(' 0x%010X %s\n' % (BaseAddress + Function[1], Function[0]))
1014 ImageMap.close()
1015
1016 #
1017 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1018 #
1019 if ModeIsSmm:
1020 BaseAddress = BaseAddress + ModuleInfo.Image.Size
1021
1022 ## Collect MAP information of all FVs
1023 #
1024 def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):
1025 if self.Fdf:
1026 # First get the XIP base address for FV map file.
1027 GuidPattern = re.compile("[-a-fA-F0-9]+")
1028 GuidName = re.compile("\(GUID=[-a-fA-F0-9]+")
1029 for FvName in Wa.FdfProfile.FvDict.keys():
1030 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')
1031 if not os.path.exists(FvMapBuffer):
1032 continue
1033 FvMap = open(FvMapBuffer, 'r')
1034 #skip FV size information
1035 FvMap.readline()
1036 FvMap.readline()
1037 FvMap.readline()
1038 FvMap.readline()
1039 for Line in FvMap:
1040 MatchGuid = GuidPattern.match(Line)
1041 if MatchGuid != None:
1042 #
1043 # Replace GUID with module name
1044 #
1045 GuidString = MatchGuid.group()
1046 if GuidString.upper() in ModuleList:
1047 Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)
1048 MapBuffer.write('%s' % (Line))
1049 #
1050 # Add the debug image full path.
1051 #
1052 MatchGuid = GuidName.match(Line)
1053 if MatchGuid != None:
1054 GuidString = MatchGuid.group().split("=")[1]
1055 if GuidString.upper() in ModuleList:
1056 MapBuffer.write('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))
1057
1058 FvMap.close()
1059
1060 ## Collect MAP information of all modules
1061 #
1062 def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):
1063 sys.stdout.write ("Generate Load Module At Fix Address Map")
1064 sys.stdout.flush()
1065 PatchEfiImageList = []
1066 PeiModuleList = {}
1067 BtModuleList = {}
1068 RtModuleList = {}
1069 SmmModuleList = {}
1070 PeiSize = 0
1071 BtSize = 0
1072 RtSize = 0
1073 # reserve 4K size in SMRAM to make SMM module address not from 0.
1074 SmmSize = 0x1000
1075 IsIpfPlatform = False
1076 if 'IPF' in self.ArchList:
1077 IsIpfPlatform = True
1078 for ModuleGuid in ModuleList:
1079 Module = ModuleList[ModuleGuid]
1080 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)
1081
1082 OutputImageFile = ''
1083 for ResultFile in Module.CodaTargetList:
1084 if str(ResultFile.Target).endswith('.efi'):
1085 #
1086 # module list for PEI, DXE, RUNTIME and SMM
1087 #
1088 OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')
1089 ImageClass = PeImageClass (OutputImageFile)
1090 if not ImageClass.IsValid:
1091 EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)
1092 ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)
1093 if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER','PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']:
1094 PeiModuleList[Module.MetaFile] = ImageInfo
1095 PeiSize += ImageInfo.Image.Size
1096 elif Module.ModuleType in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']:
1097 BtModuleList[Module.MetaFile] = ImageInfo
1098 BtSize += ImageInfo.Image.Size
1099 elif Module.ModuleType in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']:
1100 RtModuleList[Module.MetaFile] = ImageInfo
1101 #IPF runtime driver needs to be at 2 page alignment.
1102 if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0:
1103 ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000
1104 RtSize += ImageInfo.Image.Size
1105 elif Module.ModuleType in ['SMM_CORE', 'DXE_SMM_DRIVER']:
1106 SmmModuleList[Module.MetaFile] = ImageInfo
1107 SmmSize += ImageInfo.Image.Size
1108 if Module.ModuleType == 'DXE_SMM_DRIVER':
1109 PiSpecVersion = '0x00000000'
1110 if 'PI_SPECIFICATION_VERSION' in Module.Module.Specification:
1111 PiSpecVersion = Module.Module.Specification['PI_SPECIFICATION_VERSION']
1112 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1113 if int(PiSpecVersion, 16) < 0x0001000A:
1114 BtModuleList[Module.MetaFile] = ImageInfo
1115 BtSize += ImageInfo.Image.Size
1116 break
1117 #
1118 # EFI image is final target.
1119 # Check EFI image contains patchable FixAddress related PCDs.
1120 #
1121 if OutputImageFile != '':
1122 ModuleIsPatch = False
1123 for Pcd in Module.ModulePcdList:
1124 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:
1125 ModuleIsPatch = True
1126 break
1127 if not ModuleIsPatch:
1128 for Pcd in Module.LibraryPcdList:
1129 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:
1130 ModuleIsPatch = True
1131 break
1132
1133 if not ModuleIsPatch:
1134 continue
1135 #
1136 # Module includes the patchable load fix address PCDs.
1137 # It will be fixed up later.
1138 #
1139 PatchEfiImageList.append (OutputImageFile)
1140
1141 #
1142 # Get Top Memory address
1143 #
1144 ReservedRuntimeMemorySize = 0
1145 TopMemoryAddress = 0
1146 if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:
1147 TopMemoryAddress = 0
1148 else:
1149 TopMemoryAddress = self.LoadFixAddress
1150 if TopMemoryAddress < RtSize + BtSize + PeiSize:
1151 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1152 # Make IPF runtime driver at 2 page alignment.
1153 if IsIpfPlatform:
1154 ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000
1155 RtSize = RtSize + ReservedRuntimeMemorySize
1156
1157 #
1158 # Patch FixAddress related PCDs into EFI image
1159 #
1160 for EfiImage in PatchEfiImageList:
1161 EfiImageMap = EfiImage.replace('.efi', '.map')
1162 if not os.path.exists(EfiImageMap):
1163 continue
1164 #
1165 # Get PCD offset in EFI image by GenPatchPcdTable function
1166 #
1167 PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)
1168 #
1169 # Patch real PCD value by PatchPcdValue tool
1170 #
1171 for PcdInfo in PcdTable:
1172 ReturnValue = 0
1173 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:
1174 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize/0x1000))
1175 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:
1176 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize/0x1000))
1177 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:
1178 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize/0x1000))
1179 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:
1180 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize/0x1000))
1181 if ReturnValue != 0:
1182 EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)
1183
1184 MapBuffer.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize/0x1000))
1185 MapBuffer.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize/0x1000))
1186 MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize/0x1000))
1187 if len (SmmModuleList) > 0:
1188 MapBuffer.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize/0x1000))
1189
1190 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize
1191 BtBaseAddr = TopMemoryAddress - RtSize
1192 RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize
1193
1194 self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)
1195 self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)
1196 self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)
1197 self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset = False, ModeIsSmm = True)
1198 MapBuffer.write('\n\n')
1199 sys.stdout.write ("\n")
1200 sys.stdout.flush()
1201
1202 ## Save platform Map file
1203 #
1204 def _SaveMapFile (self, MapBuffer, Wa):
1205 #
1206 # Map file path is got.
1207 #
1208 MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')
1209 #
1210 # Save address map into MAP file.
1211 #
1212 SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)
1213 MapBuffer.close()
1214 if self.LoadFixAddress != 0:
1215 sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" %(MapFilePath))
1216 sys.stdout.flush()
1217
1218 ## Build active platform for different build targets and different tool chains
1219 #
1220 def _BuildPlatform(self):
1221 for BuildTarget in self.BuildTargetList:
1222 GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1223 for ToolChain in self.ToolChainList:
1224 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1225 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1226 Wa = WorkspaceAutoGen(
1227 self.WorkspaceDir,
1228 self.PlatformFile,
1229 BuildTarget,
1230 ToolChain,
1231 self.ArchList,
1232 self.BuildDatabase,
1233 self.TargetTxt,
1234 self.ToolDef,
1235 self.Fdf,
1236 self.FdList,
1237 self.FvList,
1238 self.CapList,
1239 self.SkuId,
1240 self.UniFlag,
1241 self.Progress
1242 )
1243 self.Fdf = Wa.FdfFile
1244 self.LoadFixAddress = Wa.Platform.LoadFixAddress
1245 self.BuildReport.AddPlatformReport(Wa)
1246 self.Progress.Stop("done!")
1247 self._Build(self.Target, Wa)
1248
1249 # Create MAP file when Load Fix Address is enabled.
1250 if self.Target in ["", "all", "fds"]:
1251 for Arch in Wa.ArchList:
1252 GlobalData.gGlobalDefines['ARCH'] = Arch
1253 #
1254 # Check whether the set fix address is above 4G for 32bit image.
1255 #
1256 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1257 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")
1258 #
1259 # Get Module List
1260 #
1261 ModuleList = {}
1262 for Pa in Wa.AutoGenObjectList:
1263 for Ma in Pa.ModuleAutoGenList:
1264 if Ma == None:
1265 continue
1266 if not Ma.IsLibrary:
1267 ModuleList[Ma.Guid.upper()] = Ma
1268
1269 MapBuffer = StringIO('')
1270 if self.LoadFixAddress != 0:
1271 #
1272 # Rebase module to the preferred memory address before GenFds
1273 #
1274 self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1275 if self.Fdf:
1276 #
1277 # create FDS again for the updated EFI image
1278 #
1279 self._Build("fds", Wa)
1280 if self.Fdf:
1281 #
1282 # Create MAP file for all platform FVs after GenFds.
1283 #
1284 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1285 #
1286 # Save MAP buffer into MAP file.
1287 #
1288 self._SaveMapFile (MapBuffer, Wa)
1289
1290 ## Build active module for different build targets, different tool chains and different archs
1291 #
1292 def _BuildModule(self):
1293 for BuildTarget in self.BuildTargetList:
1294 GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1295 for ToolChain in self.ToolChainList:
1296 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1297 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1298 #
1299 # module build needs platform build information, so get platform
1300 # AutoGen first
1301 #
1302 Wa = WorkspaceAutoGen(
1303 self.WorkspaceDir,
1304 self.PlatformFile,
1305 BuildTarget,
1306 ToolChain,
1307 self.ArchList,
1308 self.BuildDatabase,
1309 self.TargetTxt,
1310 self.ToolDef,
1311 self.Fdf,
1312 self.FdList,
1313 self.FvList,
1314 self.CapList,
1315 self.SkuId,
1316 self.UniFlag,
1317 self.Progress,
1318 self.ModuleFile
1319 )
1320 self.Fdf = Wa.FdfFile
1321 self.LoadFixAddress = Wa.Platform.LoadFixAddress
1322 Wa.CreateMakeFile(False)
1323 self.Progress.Stop("done!")
1324 MaList = []
1325 for Arch in Wa.ArchList:
1326 GlobalData.gGlobalDefines['ARCH'] = Arch
1327 Ma = ModuleAutoGen(Wa, self.ModuleFile, BuildTarget, ToolChain, Arch, self.PlatformFile)
1328 if Ma == None: continue
1329 MaList.append(Ma)
1330 self._Build(self.Target, Ma)
1331
1332 self.BuildReport.AddPlatformReport(Wa, MaList)
1333 if MaList == []:
1334 EdkLogger.error(
1335 'build',
1336 BUILD_ERROR,
1337 "Module for [%s] is not a component of active platform."\
1338 " Please make sure that the ARCH and inf file path are"\
1339 " given in the same as in [%s]" %\
1340 (', '.join(Wa.ArchList), self.PlatformFile),
1341 ExtraData=self.ModuleFile
1342 )
1343 # Create MAP file when Load Fix Address is enabled.
1344 if self.Target == "fds" and self.Fdf:
1345 for Arch in Wa.ArchList:
1346 #
1347 # Check whether the set fix address is above 4G for 32bit image.
1348 #
1349 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1350 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")
1351 #
1352 # Get Module List
1353 #
1354 ModuleList = {}
1355 for Pa in Wa.AutoGenObjectList:
1356 for Ma in Pa.ModuleAutoGenList:
1357 if Ma == None:
1358 continue
1359 if not Ma.IsLibrary:
1360 ModuleList[Ma.Guid.upper()] = Ma
1361
1362 MapBuffer = StringIO('')
1363 if self.LoadFixAddress != 0:
1364 #
1365 # Rebase module to the preferred memory address before GenFds
1366 #
1367 self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1368 #
1369 # create FDS again for the updated EFI image
1370 #
1371 self._Build("fds", Wa)
1372 #
1373 # Create MAP file for all platform FVs after GenFds.
1374 #
1375 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1376 #
1377 # Save MAP buffer into MAP file.
1378 #
1379 self._SaveMapFile (MapBuffer, Wa)
1380
1381 ## Build a platform in multi-thread mode
1382 #
1383 def _MultiThreadBuildPlatform(self):
1384 for BuildTarget in self.BuildTargetList:
1385 GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1386 for ToolChain in self.ToolChainList:
1387 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1388 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1389 Wa = WorkspaceAutoGen(
1390 self.WorkspaceDir,
1391 self.PlatformFile,
1392 BuildTarget,
1393 ToolChain,
1394 self.ArchList,
1395 self.BuildDatabase,
1396 self.TargetTxt,
1397 self.ToolDef,
1398 self.Fdf,
1399 self.FdList,
1400 self.FvList,
1401 self.CapList,
1402 self.SkuId,
1403 self.UniFlag,
1404 self.Progress
1405 )
1406 self.Fdf = Wa.FdfFile
1407 self.LoadFixAddress = Wa.Platform.LoadFixAddress
1408 self.BuildReport.AddPlatformReport(Wa)
1409 Wa.CreateMakeFile(False)
1410
1411 # multi-thread exit flag
1412 ExitFlag = threading.Event()
1413 ExitFlag.clear()
1414 for Arch in Wa.ArchList:
1415 GlobalData.gGlobalDefines['ARCH'] = Arch
1416 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
1417 if Pa == None:
1418 continue
1419 pModules = []
1420 for Module in Pa.Platform.Modules:
1421 # Get ModuleAutoGen object to generate C code file and makefile
1422 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
1423 if Ma == None:
1424 continue
1425 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1426 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1427 # for target which must generate AutoGen code and makefile
1428 if not self.SkipAutoGen or self.Target == 'genc':
1429 Ma.CreateCodeFile(True)
1430 if self.Target == "genc":
1431 continue
1432
1433 if not self.SkipAutoGen or self.Target == 'genmake':
1434 Ma.CreateMakeFile(True)
1435 Ma.CreateAsBuiltInf()
1436 if self.Target == "genmake":
1437 continue
1438 pModules.append(Ma)
1439 self.Progress.Stop("done!")
1440
1441 for Ma in pModules:
1442 # Generate build task for the module
1443 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))
1444 # Break build if any build thread has error
1445 if BuildTask.HasError():
1446 # we need a full version of makefile for platform
1447 ExitFlag.set()
1448 BuildTask.WaitForComplete()
1449 Pa.CreateMakeFile(False)
1450 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1451 # Start task scheduler
1452 if not BuildTask.IsOnGoing():
1453 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
1454
1455 # in case there's an interruption. we need a full version of makefile for platform
1456 Pa.CreateMakeFile(False)
1457 if BuildTask.HasError():
1458 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1459
1460 #
1461 # Save temp tables to a TmpTableDict.
1462 #
1463 for Key in Wa.BuildDatabase._CACHE_:
1464 if Wa.BuildDatabase._CACHE_[Key]._RawData and Wa.BuildDatabase._CACHE_[Key]._RawData._Table and Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table:
1465 if TemporaryTablePattern.match(Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table):
1466 TmpTableDict[Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table] = Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Cur
1467 #
1468 #
1469 # All modules have been put in build tasks queue. Tell task scheduler
1470 # to exit if all tasks are completed
1471 #
1472 ExitFlag.set()
1473 BuildTask.WaitForComplete()
1474
1475 #
1476 # Check for build error, and raise exception if one
1477 # has been signaled.
1478 #
1479 if BuildTask.HasError():
1480 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1481
1482 # Create MAP file when Load Fix Address is enabled.
1483 if self.Target in ["", "all", "fds"]:
1484 for Arch in Wa.ArchList:
1485 #
1486 # Check whether the set fix address is above 4G for 32bit image.
1487 #
1488 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1489 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")
1490 #
1491 # Get Module List
1492 #
1493 ModuleList = {}
1494 for Pa in Wa.AutoGenObjectList:
1495 for Ma in Pa.ModuleAutoGenList:
1496 if Ma == None:
1497 continue
1498 if not Ma.IsLibrary:
1499 ModuleList[Ma.Guid.upper()] = Ma
1500 #
1501 # Rebase module to the preferred memory address before GenFds
1502 #
1503 MapBuffer = StringIO('')
1504 if self.LoadFixAddress != 0:
1505 self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1506
1507 if self.Fdf:
1508 #
1509 # Generate FD image if there's a FDF file found
1510 #
1511 LaunchCommand(Wa.BuildCommand + ["fds"], Wa.MakeFileDir)
1512 #
1513 # Create MAP file for all platform FVs after GenFds.
1514 #
1515 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1516 #
1517 # Save MAP buffer into MAP file.
1518 #
1519 self._SaveMapFile(MapBuffer, Wa)
1520
1521 ## Generate GuidedSectionTools.txt in the FV directories.
1522 #
1523 def CreateGuidedSectionToolsFile(self):
1524 for BuildTarget in self.BuildTargetList:
1525 for ToolChain in self.ToolChainList:
1526 Wa = WorkspaceAutoGen(
1527 self.WorkspaceDir,
1528 self.PlatformFile,
1529 BuildTarget,
1530 ToolChain,
1531 self.ArchList,
1532 self.BuildDatabase,
1533 self.TargetTxt,
1534 self.ToolDef,
1535 self.Fdf,
1536 self.FdList,
1537 self.FvList,
1538 self.CapList,
1539 self.SkuId,
1540 self.UniFlag
1541 )
1542 FvDir = Wa.FvDir
1543 if not os.path.exists(FvDir):
1544 continue
1545
1546 for Arch in self.ArchList:
1547 # Build up the list of supported architectures for this build
1548 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)
1549
1550 # Look through the tool definitions for GUIDed tools
1551 guidAttribs = []
1552 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():
1553 if attrib.upper().endswith('_GUID'):
1554 split = attrib.split('_')
1555 thisPrefix = '_'.join(split[0:3]) + '_'
1556 if thisPrefix == prefix:
1557 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]
1558 guid = guid.lower()
1559 toolName = split[3]
1560 path = '_'.join(split[0:4]) + '_PATH'
1561 path = self.ToolDef.ToolsDefTxtDictionary[path]
1562 path = self.GetFullPathOfTool(path)
1563 guidAttribs.append((guid, toolName, path))
1564
1565 # Write out GuidedSecTools.txt
1566 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')
1567 toolsFile = open(toolsFile, 'wt')
1568 for guidedSectionTool in guidAttribs:
1569 print >> toolsFile, ' '.join(guidedSectionTool)
1570 toolsFile.close()
1571
1572 ## Returns the full path of the tool.
1573 #
1574 def GetFullPathOfTool (self, tool):
1575 if os.path.exists(tool):
1576 return os.path.realpath(tool)
1577 else:
1578 # We need to search for the tool using the
1579 # PATH environment variable.
1580 for dirInPath in os.environ['PATH'].split(os.pathsep):
1581 foundPath = os.path.join(dirInPath, tool)
1582 if os.path.exists(foundPath):
1583 return os.path.realpath(foundPath)
1584
1585 # If the tool was not found in the path then we just return
1586 # the input tool.
1587 return tool
1588
1589 ## Launch the module or platform build
1590 #
1591 def Launch(self):
1592 if not self.ModuleFile:
1593 if not self.SpawnMode or self.Target not in ["", "all"]:
1594 self.SpawnMode = False
1595 self._BuildPlatform()
1596 else:
1597 self._MultiThreadBuildPlatform()
1598 self.CreateGuidedSectionToolsFile()
1599 else:
1600 self.SpawnMode = False
1601 self._BuildModule()
1602
1603 ## Do some clean-up works when error occurred
1604 def Relinquish(self):
1605 OldLogLevel = EdkLogger.GetLevel()
1606 EdkLogger.SetLevel(EdkLogger.ERROR)
1607 #self.DumpBuildData()
1608 Utils.Progressor.Abort()
1609 if self.SpawnMode == True:
1610 BuildTask.Abort()
1611 EdkLogger.SetLevel(OldLogLevel)
1612
1613 def DumpBuildData(self):
1614 CacheDirectory = os.path.join(self.WorkspaceDir, gBuildCacheDir)
1615 Utils.CreateDirectory(CacheDirectory)
1616 Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))
1617 Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))
1618
1619 def RestoreBuildData(self):
1620 FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gFileTimeStampCache")
1621 if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):
1622 Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)
1623 if Utils.gFileTimeStampCache == None:
1624 Utils.gFileTimeStampCache = {}
1625
1626 FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gDependencyDatabase")
1627 if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):
1628 Utils.gDependencyDatabase = Utils.DataRestore(FilePath)
1629 if Utils.gDependencyDatabase == None:
1630 Utils.gDependencyDatabase = {}
1631
1632 def ParseDefines(DefineList=[]):
1633 DefineDict = {}
1634 if DefineList != None:
1635 for Define in DefineList:
1636 DefineTokenList = Define.split("=", 1)
1637 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):
1638 EdkLogger.error('build', FORMAT_INVALID,
1639 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
1640 ExtraData=DefineTokenList[0])
1641
1642 if len(DefineTokenList) == 1:
1643 DefineDict[DefineTokenList[0]] = "TRUE"
1644 else:
1645 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()
1646 return DefineDict
1647
1648 gParamCheck = []
1649 def SingleCheckCallback(option, opt_str, value, parser):
1650 if option not in gParamCheck:
1651 setattr(parser.values, option.dest, value)
1652 gParamCheck.append(option)
1653 else:
1654 parser.error("Option %s only allows one instance in command line!" % option)
1655
1656 ## Parse command line options
1657 #
1658 # Using standard Python module optparse to parse command line option of this tool.
1659 #
1660 # @retval Opt A optparse.Values object containing the parsed options
1661 # @retval Args Target of build command
1662 #
1663 def MyOptionParser():
1664 Parser = OptionParser(description=__copyright__,version=__version__,prog="build.exe",usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
1665 Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32','X64','IPF','EBC','ARM', 'AARCH64'], dest="TargetArch",
1666 help="ARCHS is one of list: IA32, X64, IPF, ARM, AARCH64 or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.")
1667 Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,
1668 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
1669 Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,
1670 help="Build the module specified by the INF file name argument.")
1671 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
1672 action="append")
1673 Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",
1674 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
1675 Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,
1676 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
1677
1678 Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,
1679 help="Build the platform using multi-threaded compiler. The value overrides target.txt's MAX_CONCURRENT_THREAD_NUMBER. Less than 2 will disable multi-thread builds.")
1680
1681 Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,
1682 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
1683 Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],
1684 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
1685 Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],
1686 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
1687 Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],
1688 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
1689 Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")
1690 Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")
1691
1692 Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.")
1693
1694 Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")
1695 Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")
1696
1697 Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",
1698 help="Make use of silent mode of (n)make.")
1699 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
1700 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
1701 "including library instances selected, final dependency expression, "\
1702 "and warning messages, etc.")
1703 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
1704 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
1705
1706 Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")
1707 Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD','LIBRARY','FLASH','DEPEX','BUILD_FLAGS','FIXED_ADDRESS', 'EXECUTION_ORDER'], dest="ReportType", default=[],
1708 help="Flags that control the type of build report to generate. Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, EXECUTION_ORDER]. "\
1709 "To specify more than one flag, repeat this option on the command line and the default flag set is [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS]")
1710 Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",
1711 help="Specify the specific option to parse EDK UNI file. Must be one of: [-c, -s]. -c is for EDK framework UNI file, and -s is for EDK UEFI UNI file. "\
1712 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
1713 "will override the setting in [BuildOptions] section of platform DSC.")
1714 Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism")
1715
1716 (Opt, Args)=Parser.parse_args()
1717 return (Opt, Args)
1718
1719 ## Tool entrance method
1720 #
1721 # This method mainly dispatch specific methods per the command line options.
1722 # If no error found, return zero value so the caller of this tool can know
1723 # if it's executed successfully or not.
1724 #
1725 # @retval 0 Tool was successful
1726 # @retval 1 Tool failed
1727 #
1728 def Main():
1729 StartTime = time.time()
1730
1731 # Initialize log system
1732 EdkLogger.Initialize()
1733
1734 #
1735 # Parse the options and args
1736 #
1737 (Option, Target) = MyOptionParser()
1738 GlobalData.gOptions = Option
1739 GlobalData.gCaseInsensitive = Option.CaseInsensitive
1740
1741 # Set log level
1742 if Option.verbose != None:
1743 EdkLogger.SetLevel(EdkLogger.VERBOSE)
1744 elif Option.quiet != None:
1745 EdkLogger.SetLevel(EdkLogger.QUIET)
1746 elif Option.debug != None:
1747 EdkLogger.SetLevel(Option.debug + 1)
1748 else:
1749 EdkLogger.SetLevel(EdkLogger.INFO)
1750
1751 if Option.LogFile != None:
1752 EdkLogger.SetLogFile(Option.LogFile)
1753
1754 if Option.WarningAsError == True:
1755 EdkLogger.SetWarningAsError()
1756
1757 if platform.platform().find("Windows") >= 0:
1758 GlobalData.gIsWindows = True
1759 else:
1760 GlobalData.gIsWindows = False
1761
1762 EdkLogger.quiet("Build environment: %s" % platform.platform())
1763 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));
1764 ReturnCode = 0
1765 MyBuild = None
1766 try:
1767 if len(Target) == 0:
1768 Target = "all"
1769 elif len(Target) >= 2:
1770 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",
1771 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))
1772 else:
1773 Target = Target[0].lower()
1774
1775 if Target not in gSupportedTarget:
1776 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,
1777 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))
1778
1779 #
1780 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
1781 #
1782 CheckEnvVariable()
1783 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))
1784
1785 Workspace = os.getenv("WORKSPACE")
1786 #
1787 # Get files real name in workspace dir
1788 #
1789 GlobalData.gAllFiles = Utils.DirCache(Workspace)
1790
1791 WorkingDirectory = os.getcwd()
1792 if not Option.ModuleFile:
1793 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))
1794 FileNum = len(FileList)
1795 if FileNum >= 2:
1796 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),
1797 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")
1798 elif FileNum == 1:
1799 Option.ModuleFile = NormFile(FileList[0], Workspace)
1800
1801 if Option.ModuleFile:
1802 if os.path.isabs (Option.ModuleFile):
1803 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:
1804 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)
1805 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)
1806 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)
1807 if ErrorCode != 0:
1808 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
1809
1810 if Option.PlatformFile != None:
1811 if os.path.isabs (Option.PlatformFile):
1812 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:
1813 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)
1814 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)
1815
1816 if Option.FdfFile != None:
1817 if os.path.isabs (Option.FdfFile):
1818 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:
1819 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)
1820 Option.FdfFile = PathClass(Option.FdfFile, Workspace)
1821 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)
1822 if ErrorCode != 0:
1823 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
1824
1825 if Option.Flag != None and Option.Flag not in ['-c', '-s']:
1826 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")
1827
1828 MyBuild = Build(Target, Workspace, Option)
1829 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)
1830 MyBuild.Launch()
1831 # Drop temp tables to avoid database locked.
1832 for TmpTableName in TmpTableDict:
1833 SqlCommand = """drop table IF EXISTS %s""" % TmpTableName
1834 TmpTableDict[TmpTableName].execute(SqlCommand)
1835 #MyBuild.DumpBuildData()
1836 except FatalError, X:
1837 if MyBuild != None:
1838 # for multi-thread build exits safely
1839 MyBuild.Relinquish()
1840 if Option != None and Option.debug != None:
1841 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
1842 ReturnCode = X.args[0]
1843 except Warning, X:
1844 # error from Fdf parser
1845 if MyBuild != None:
1846 # for multi-thread build exits safely
1847 MyBuild.Relinquish()
1848 if Option != None and Option.debug != None:
1849 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
1850 else:
1851 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError = False)
1852 ReturnCode = FORMAT_INVALID
1853 except KeyboardInterrupt:
1854 ReturnCode = ABORT_ERROR
1855 if Option != None and Option.debug != None:
1856 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
1857 except:
1858 if MyBuild != None:
1859 # for multi-thread build exits safely
1860 MyBuild.Relinquish()
1861
1862 # try to get the meta-file from the object causing exception
1863 Tb = sys.exc_info()[-1]
1864 MetaFile = GlobalData.gProcessingFile
1865 while Tb != None:
1866 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):
1867 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile
1868 Tb = Tb.tb_next
1869 EdkLogger.error(
1870 "\nbuild",
1871 CODE_ERROR,
1872 "Unknown fatal error when processing [%s]" % MetaFile,
1873 ExtraData="\n(Please send email to edk2-buildtools-devel@lists.sourceforge.net for help, attaching following call stack trace!)\n",
1874 RaiseError=False
1875 )
1876 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
1877 ReturnCode = CODE_ERROR
1878 finally:
1879 Utils.Progressor.Abort()
1880
1881 if ReturnCode == 0:
1882 Conclusion = "Done"
1883 elif ReturnCode == ABORT_ERROR:
1884 Conclusion = "Aborted"
1885 else:
1886 Conclusion = "Failed"
1887 FinishTime = time.time()
1888 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))
1889 BuildDurationStr = ""
1890 if BuildDuration.tm_yday > 1:
1891 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)"%(BuildDuration.tm_yday - 1)
1892 else:
1893 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)
1894 if MyBuild != None:
1895 MyBuild.BuildReport.GenerateReport(BuildDurationStr)
1896 MyBuild.Db.Close()
1897 EdkLogger.SetLevel(EdkLogger.QUIET)
1898 EdkLogger.quiet("\n- %s -" % Conclusion)
1899 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))
1900 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)
1901 return ReturnCode
1902
1903 if __name__ == '__main__':
1904 r = Main()
1905 ## 0-127 is a safe return range, and 1 is a standard default error
1906 if r < 0 or r > 127: r = 1
1907 sys.exit(r)
1908