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