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