]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/build/build.py
Sync BaseTool trunk (version r2610) into EDKII BaseTools.
[mirror_edk2.git] / BaseTools / Source / Python / build / build.py
1 ## @file
2 # build a platform or a module
3 #
4 # Copyright (c) 2007 - 2013, 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.51" + ' ' + gBUILD_VERSION
51 __version__ = "%prog Version " + VersionNumber
52 __copyright__ = "Copyright (c) 2007 - 2013, 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 pModules = []
1418 for Module in Pa.Platform.Modules:
1419 # Get ModuleAutoGen object to generate C code file and makefile
1420 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
1421 if Ma == None:
1422 continue
1423 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1424 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1425 # for target which must generate AutoGen code and makefile
1426 if not self.SkipAutoGen or self.Target == 'genc':
1427 Ma.CreateCodeFile(True)
1428 if self.Target == "genc":
1429 continue
1430
1431 if not self.SkipAutoGen or self.Target == 'genmake':
1432 Ma.CreateMakeFile(True)
1433 Ma.CreateAsBuiltInf()
1434 if self.Target == "genmake":
1435 continue
1436 pModules.append(Ma)
1437 self.Progress.Stop("done!")
1438
1439 for Ma in pModules:
1440 # Generate build task for the module
1441 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))
1442 # Break build if any build thread has error
1443 if BuildTask.HasError():
1444 # we need a full version of makefile for platform
1445 ExitFlag.set()
1446 BuildTask.WaitForComplete()
1447 Pa.CreateMakeFile(False)
1448 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1449 # Start task scheduler
1450 if not BuildTask.IsOnGoing():
1451 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
1452
1453 # in case there's an interruption. we need a full version of makefile for platform
1454 Pa.CreateMakeFile(False)
1455 if BuildTask.HasError():
1456 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1457
1458 #
1459 # Save temp tables to a TmpTableDict.
1460 #
1461 for Key in Wa.BuildDatabase._CACHE_:
1462 if Wa.BuildDatabase._CACHE_[Key]._RawData and Wa.BuildDatabase._CACHE_[Key]._RawData._Table and Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table:
1463 if TemporaryTablePattern.match(Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table):
1464 TmpTableDict[Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table] = Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Cur
1465 #
1466 #
1467 # All modules have been put in build tasks queue. Tell task scheduler
1468 # to exit if all tasks are completed
1469 #
1470 ExitFlag.set()
1471 BuildTask.WaitForComplete()
1472
1473 #
1474 # Check for build error, and raise exception if one
1475 # has been signaled.
1476 #
1477 if BuildTask.HasError():
1478 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1479
1480 # Create MAP file when Load Fix Address is enabled.
1481 if self.Target in ["", "all", "fds"]:
1482 for Arch in Wa.ArchList:
1483 #
1484 # Check whether the set fix address is above 4G for 32bit image.
1485 #
1486 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1487 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")
1488 #
1489 # Get Module List
1490 #
1491 ModuleList = {}
1492 for Pa in Wa.AutoGenObjectList:
1493 for Ma in Pa.ModuleAutoGenList:
1494 if Ma == None:
1495 continue
1496 if not Ma.IsLibrary:
1497 ModuleList[Ma.Guid.upper()] = Ma
1498 #
1499 # Rebase module to the preferred memory address before GenFds
1500 #
1501 MapBuffer = StringIO('')
1502 if self.LoadFixAddress != 0:
1503 self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1504
1505 if self.Fdf:
1506 #
1507 # Generate FD image if there's a FDF file found
1508 #
1509 LaunchCommand(Wa.BuildCommand + ["fds"], Wa.MakeFileDir)
1510 #
1511 # Create MAP file for all platform FVs after GenFds.
1512 #
1513 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1514 #
1515 # Save MAP buffer into MAP file.
1516 #
1517 self._SaveMapFile(MapBuffer, Wa)
1518
1519 ## Generate GuidedSectionTools.txt in the FV directories.
1520 #
1521 def CreateGuidedSectionToolsFile(self):
1522 for BuildTarget in self.BuildTargetList:
1523 for ToolChain in self.ToolChainList:
1524 Wa = WorkspaceAutoGen(
1525 self.WorkspaceDir,
1526 self.PlatformFile,
1527 BuildTarget,
1528 ToolChain,
1529 self.ArchList,
1530 self.BuildDatabase,
1531 self.TargetTxt,
1532 self.ToolDef,
1533 self.Fdf,
1534 self.FdList,
1535 self.FvList,
1536 self.CapList,
1537 self.SkuId,
1538 self.UniFlag
1539 )
1540 FvDir = Wa.FvDir
1541 if not os.path.exists(FvDir):
1542 continue
1543
1544 for Arch in self.ArchList:
1545 # Build up the list of supported architectures for this build
1546 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)
1547
1548 # Look through the tool definitions for GUIDed tools
1549 guidAttribs = []
1550 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():
1551 if attrib.upper().endswith('_GUID'):
1552 split = attrib.split('_')
1553 thisPrefix = '_'.join(split[0:3]) + '_'
1554 if thisPrefix == prefix:
1555 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]
1556 guid = guid.lower()
1557 toolName = split[3]
1558 path = '_'.join(split[0:4]) + '_PATH'
1559 path = self.ToolDef.ToolsDefTxtDictionary[path]
1560 path = self.GetFullPathOfTool(path)
1561 guidAttribs.append((guid, toolName, path))
1562
1563 # Write out GuidedSecTools.txt
1564 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')
1565 toolsFile = open(toolsFile, 'wt')
1566 for guidedSectionTool in guidAttribs:
1567 print >> toolsFile, ' '.join(guidedSectionTool)
1568 toolsFile.close()
1569
1570 ## Returns the full path of the tool.
1571 #
1572 def GetFullPathOfTool (self, tool):
1573 if os.path.exists(tool):
1574 return os.path.realpath(tool)
1575 else:
1576 # We need to search for the tool using the
1577 # PATH environment variable.
1578 for dirInPath in os.environ['PATH'].split(os.pathsep):
1579 foundPath = os.path.join(dirInPath, tool)
1580 if os.path.exists(foundPath):
1581 return os.path.realpath(foundPath)
1582
1583 # If the tool was not found in the path then we just return
1584 # the input tool.
1585 return tool
1586
1587 ## Launch the module or platform build
1588 #
1589 def Launch(self):
1590 if not self.ModuleFile:
1591 if not self.SpawnMode or self.Target not in ["", "all"]:
1592 self.SpawnMode = False
1593 self._BuildPlatform()
1594 else:
1595 self._MultiThreadBuildPlatform()
1596 self.CreateGuidedSectionToolsFile()
1597 else:
1598 self.SpawnMode = False
1599 self._BuildModule()
1600
1601 ## Do some clean-up works when error occurred
1602 def Relinquish(self):
1603 OldLogLevel = EdkLogger.GetLevel()
1604 EdkLogger.SetLevel(EdkLogger.ERROR)
1605 #self.DumpBuildData()
1606 Utils.Progressor.Abort()
1607 if self.SpawnMode == True:
1608 BuildTask.Abort()
1609 EdkLogger.SetLevel(OldLogLevel)
1610
1611 def DumpBuildData(self):
1612 CacheDirectory = os.path.join(self.WorkspaceDir, gBuildCacheDir)
1613 Utils.CreateDirectory(CacheDirectory)
1614 Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))
1615 Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))
1616
1617 def RestoreBuildData(self):
1618 FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gFileTimeStampCache")
1619 if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):
1620 Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)
1621 if Utils.gFileTimeStampCache == None:
1622 Utils.gFileTimeStampCache = {}
1623
1624 FilePath = os.path.join(self.WorkspaceDir, gBuildCacheDir, "gDependencyDatabase")
1625 if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):
1626 Utils.gDependencyDatabase = Utils.DataRestore(FilePath)
1627 if Utils.gDependencyDatabase == None:
1628 Utils.gDependencyDatabase = {}
1629
1630 def ParseDefines(DefineList=[]):
1631 DefineDict = {}
1632 if DefineList != None:
1633 for Define in DefineList:
1634 DefineTokenList = Define.split("=", 1)
1635 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):
1636 EdkLogger.error('build', FORMAT_INVALID,
1637 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
1638 ExtraData=DefineTokenList[0])
1639
1640 if len(DefineTokenList) == 1:
1641 DefineDict[DefineTokenList[0]] = "TRUE"
1642 else:
1643 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()
1644 return DefineDict
1645
1646 gParamCheck = []
1647 def SingleCheckCallback(option, opt_str, value, parser):
1648 if option not in gParamCheck:
1649 setattr(parser.values, option.dest, value)
1650 gParamCheck.append(option)
1651 else:
1652 parser.error("Option %s only allows one instance in command line!" % option)
1653
1654 ## Parse command line options
1655 #
1656 # Using standard Python module optparse to parse command line option of this tool.
1657 #
1658 # @retval Opt A optparse.Values object containing the parsed options
1659 # @retval Args Target of build command
1660 #
1661 def MyOptionParser():
1662 Parser = OptionParser(description=__copyright__,version=__version__,prog="build.exe",usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
1663 Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32','X64','IPF','EBC','ARM', 'AARCH64'], dest="TargetArch",
1664 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.")
1665 Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,
1666 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
1667 Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,
1668 help="Build the module specified by the INF file name argument.")
1669 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
1670 action="append")
1671 Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",
1672 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
1673 Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,
1674 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
1675
1676 Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,
1677 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.")
1678
1679 Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,
1680 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
1681 Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],
1682 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
1683 Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],
1684 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
1685 Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],
1686 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
1687 Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")
1688 Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")
1689
1690 Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.")
1691
1692 Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")
1693 Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")
1694
1695 Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",
1696 help="Make use of silent mode of (n)make.")
1697 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
1698 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
1699 "including library instances selected, final dependency expression, "\
1700 "and warning messages, etc.")
1701 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
1702 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
1703
1704 Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")
1705 Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD','LIBRARY','FLASH','DEPEX','BUILD_FLAGS','FIXED_ADDRESS', 'EXECUTION_ORDER'], dest="ReportType", default=[],
1706 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]. "\
1707 "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]")
1708 Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",
1709 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. "\
1710 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
1711 "will override the setting in [BuildOptions] section of platform DSC.")
1712 Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism")
1713
1714 (Opt, Args)=Parser.parse_args()
1715 return (Opt, Args)
1716
1717 ## Tool entrance method
1718 #
1719 # This method mainly dispatch specific methods per the command line options.
1720 # If no error found, return zero value so the caller of this tool can know
1721 # if it's executed successfully or not.
1722 #
1723 # @retval 0 Tool was successful
1724 # @retval 1 Tool failed
1725 #
1726 def Main():
1727 StartTime = time.time()
1728
1729 # Initialize log system
1730 EdkLogger.Initialize()
1731
1732 #
1733 # Parse the options and args
1734 #
1735 (Option, Target) = MyOptionParser()
1736 GlobalData.gOptions = Option
1737 GlobalData.gCaseInsensitive = Option.CaseInsensitive
1738
1739 # Set log level
1740 if Option.verbose != None:
1741 EdkLogger.SetLevel(EdkLogger.VERBOSE)
1742 elif Option.quiet != None:
1743 EdkLogger.SetLevel(EdkLogger.QUIET)
1744 elif Option.debug != None:
1745 EdkLogger.SetLevel(Option.debug + 1)
1746 else:
1747 EdkLogger.SetLevel(EdkLogger.INFO)
1748
1749 if Option.LogFile != None:
1750 EdkLogger.SetLogFile(Option.LogFile)
1751
1752 if Option.WarningAsError == True:
1753 EdkLogger.SetWarningAsError()
1754
1755 if platform.platform().find("Windows") >= 0:
1756 GlobalData.gIsWindows = True
1757 else:
1758 GlobalData.gIsWindows = False
1759
1760 EdkLogger.quiet("Build environment: %s" % platform.platform())
1761 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));
1762 ReturnCode = 0
1763 MyBuild = None
1764 try:
1765 if len(Target) == 0:
1766 Target = "all"
1767 elif len(Target) >= 2:
1768 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",
1769 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))
1770 else:
1771 Target = Target[0].lower()
1772
1773 if Target not in gSupportedTarget:
1774 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,
1775 ExtraData="Please select one of: %s" %(' '.join(gSupportedTarget)))
1776
1777 #
1778 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
1779 #
1780 CheckEnvVariable()
1781 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))
1782
1783 Workspace = os.getenv("WORKSPACE")
1784 #
1785 # Get files real name in workspace dir
1786 #
1787 GlobalData.gAllFiles = Utils.DirCache(Workspace)
1788
1789 WorkingDirectory = os.getcwd()
1790 if not Option.ModuleFile:
1791 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))
1792 FileNum = len(FileList)
1793 if FileNum >= 2:
1794 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),
1795 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")
1796 elif FileNum == 1:
1797 Option.ModuleFile = NormFile(FileList[0], Workspace)
1798
1799 if Option.ModuleFile:
1800 if os.path.isabs (Option.ModuleFile):
1801 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:
1802 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)
1803 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)
1804 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)
1805 if ErrorCode != 0:
1806 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
1807
1808 if Option.PlatformFile != None:
1809 if os.path.isabs (Option.PlatformFile):
1810 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:
1811 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)
1812 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)
1813
1814 if Option.FdfFile != None:
1815 if os.path.isabs (Option.FdfFile):
1816 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:
1817 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)
1818 Option.FdfFile = PathClass(Option.FdfFile, Workspace)
1819 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)
1820 if ErrorCode != 0:
1821 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
1822
1823 if Option.Flag != None and Option.Flag not in ['-c', '-s']:
1824 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")
1825
1826 MyBuild = Build(Target, Workspace, Option)
1827 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)
1828 MyBuild.Launch()
1829 # Drop temp tables to avoid database locked.
1830 for TmpTableName in TmpTableDict:
1831 SqlCommand = """drop table IF EXISTS %s""" % TmpTableName
1832 TmpTableDict[TmpTableName].execute(SqlCommand)
1833 #MyBuild.DumpBuildData()
1834 except FatalError, X:
1835 if MyBuild != None:
1836 # for multi-thread build exits safely
1837 MyBuild.Relinquish()
1838 if Option != None and Option.debug != None:
1839 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
1840 ReturnCode = X.args[0]
1841 except Warning, X:
1842 # error from Fdf parser
1843 if MyBuild != None:
1844 # for multi-thread build exits safely
1845 MyBuild.Relinquish()
1846 if Option != None and Option.debug != None:
1847 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
1848 else:
1849 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError = False)
1850 ReturnCode = FORMAT_INVALID
1851 except KeyboardInterrupt:
1852 ReturnCode = ABORT_ERROR
1853 if Option != None and Option.debug != None:
1854 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
1855 except:
1856 if MyBuild != None:
1857 # for multi-thread build exits safely
1858 MyBuild.Relinquish()
1859
1860 # try to get the meta-file from the object causing exception
1861 Tb = sys.exc_info()[-1]
1862 MetaFile = GlobalData.gProcessingFile
1863 while Tb != None:
1864 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):
1865 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile
1866 Tb = Tb.tb_next
1867 EdkLogger.error(
1868 "\nbuild",
1869 CODE_ERROR,
1870 "Unknown fatal error when processing [%s]" % MetaFile,
1871 ExtraData="\n(Please send email to edk2-buildtools-devel@lists.sourceforge.net for help, attaching following call stack trace!)\n",
1872 RaiseError=False
1873 )
1874 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
1875 ReturnCode = CODE_ERROR
1876 finally:
1877 Utils.Progressor.Abort()
1878
1879 if ReturnCode == 0:
1880 Conclusion = "Done"
1881 elif ReturnCode == ABORT_ERROR:
1882 Conclusion = "Aborted"
1883 else:
1884 Conclusion = "Failed"
1885 FinishTime = time.time()
1886 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))
1887 BuildDurationStr = ""
1888 if BuildDuration.tm_yday > 1:
1889 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)"%(BuildDuration.tm_yday - 1)
1890 else:
1891 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)
1892 if MyBuild != None:
1893 MyBuild.BuildReport.GenerateReport(BuildDurationStr)
1894 MyBuild.Db.Close()
1895 EdkLogger.SetLevel(EdkLogger.QUIET)
1896 EdkLogger.quiet("\n- %s -" % Conclusion)
1897 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))
1898 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)
1899 return ReturnCode
1900
1901 if __name__ == '__main__':
1902 r = Main()
1903 ## 0-127 is a safe return range, and 1 is a standard default error
1904 if r < 0 or r > 127: r = 1
1905 sys.exit(r)
1906