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