]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/build/build.py
BaseTools: Fix a bug for tooldef class not include the newly Env
[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 #self.LanuchPostbuild()
993 else:
994 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]))
995
996 def PassCommandOption(self, BuildTarget, TargetArch, ToolChain):
997 BuildStr = ''
998 if GlobalData.gCommand and isinstance(GlobalData.gCommand, list):
999 BuildStr += ' ' + ' '.join(GlobalData.gCommand)
1000 TargetFlag = False
1001 ArchFlag = False
1002 ToolChainFlag = False
1003
1004 if GlobalData.gOptions and not GlobalData.gOptions.BuildTarget:
1005 TargetFlag = True
1006 if GlobalData.gOptions and not GlobalData.gOptions.TargetArch:
1007 ArchFlag = True
1008 if GlobalData.gOptions and not GlobalData.gOptions.ToolChain:
1009 ToolChainFlag = True
1010
1011 if TargetFlag and BuildTarget:
1012 if isinstance(BuildTarget, list) or isinstance(BuildTarget, tuple):
1013 BuildStr += ' -b ' + ' -b '.join(BuildTarget)
1014 elif isinstance(BuildTarget, str):
1015 BuildStr += ' -b ' + BuildTarget
1016 if ArchFlag and TargetArch:
1017 if isinstance(TargetArch, list) or isinstance(TargetArch, tuple):
1018 BuildStr += ' -a ' + ' -a '.join(TargetArch)
1019 elif isinstance(TargetArch, str):
1020 BuildStr += ' -a ' + TargetArch
1021 if ToolChainFlag and ToolChain:
1022 if isinstance(ToolChain, list) or isinstance(ToolChain, tuple):
1023 BuildStr += ' -t ' + ' -t '.join(ToolChain)
1024 elif isinstance(ToolChain, str):
1025 BuildStr += ' -t ' + ToolChain
1026
1027 return BuildStr
1028
1029 def LaunchPrebuild(self):
1030 if self.Prebuild:
1031 EdkLogger.info("\n- Prebuild Start -\n")
1032 self.LaunchPrebuildFlag = True
1033 PrebuildEnvFile = os.path.join(GlobalData.gConfDirectory,'.cache','.PrebuildEnv')
1034 if os.path.isfile(PrebuildEnvFile):
1035 os.remove(PrebuildEnvFile)
1036 if os.path.isfile(self.PlatformBuildPath):
1037 os.remove(self.PlatformBuildPath)
1038 if sys.platform == "win32":
1039 args = ' && '.join((self.Prebuild, 'set > ' + PrebuildEnvFile))
1040 Process = Popen(args, stdout=PIPE, stderr=PIPE)
1041 else:
1042 args = ' && '.join((self.Prebuild, 'env > ' + PrebuildEnvFile))
1043 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True, executable="/bin/bash")
1044
1045 # launch two threads to read the STDOUT and STDERR
1046 EndOfProcedure = Event()
1047 EndOfProcedure.clear()
1048 if Process.stdout:
1049 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))
1050 StdOutThread.setName("STDOUT-Redirector")
1051 StdOutThread.setDaemon(False)
1052 StdOutThread.start()
1053
1054 if Process.stderr:
1055 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))
1056 StdErrThread.setName("STDERR-Redirector")
1057 StdErrThread.setDaemon(False)
1058 StdErrThread.start()
1059 # waiting for program exit
1060 Process.wait()
1061
1062 if Process.stdout:
1063 StdOutThread.join()
1064 if Process.stderr:
1065 StdErrThread.join()
1066 if Process.returncode != 0 :
1067 EdkLogger.error("Prebuild", PREBUILD_ERROR, 'Prebuild process is not success!')
1068
1069 if os.path.exists(PrebuildEnvFile):
1070 f = open(PrebuildEnvFile)
1071 envs = f.readlines()
1072 f.close()
1073 envs = itertools.imap(lambda l: l.split('=',1), envs)
1074 envs = itertools.ifilter(lambda l: len(l) == 2, envs)
1075 envs = itertools.imap(lambda l: [i.strip() for i in l], envs)
1076 os.environ.update(dict(envs))
1077 EdkLogger.info("\n- Prebuild Done -\n")
1078
1079 def LanuchPostbuild(self):
1080 if self.Postbuild:
1081 EdkLogger.info("\n- Postbuild Start -\n")
1082 if sys.platform == "win32":
1083 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE)
1084 else:
1085 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True, executable="/bin/bash")
1086 # launch two threads to read the STDOUT and STDERR
1087 EndOfProcedure = Event()
1088 EndOfProcedure.clear()
1089 if Process.stdout:
1090 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))
1091 StdOutThread.setName("STDOUT-Redirector")
1092 StdOutThread.setDaemon(False)
1093 StdOutThread.start()
1094
1095 if Process.stderr:
1096 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))
1097 StdErrThread.setName("STDERR-Redirector")
1098 StdErrThread.setDaemon(False)
1099 StdErrThread.start()
1100 # waiting for program exit
1101 Process.wait()
1102
1103 if Process.stdout:
1104 StdOutThread.join()
1105 if Process.stderr:
1106 StdErrThread.join()
1107 if Process.returncode != 0 :
1108 EdkLogger.error("Postbuild", POSTBUILD_ERROR, 'Postbuild process is not success!')
1109 EdkLogger.info("\n- Postbuild Done -\n")
1110 ## Build a module or platform
1111 #
1112 # Create autogen code and makefile for a module or platform, and the launch
1113 # "make" command to build it
1114 #
1115 # @param Target The target of build command
1116 # @param Platform The platform file
1117 # @param Module The module file
1118 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1119 # @param ToolChain The name of toolchain to build
1120 # @param Arch The arch of the module/platform
1121 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1122 # for dependent modules/Libraries
1123 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1124 # for dependent modules/Libraries
1125 #
1126 def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):
1127 if AutoGenObject == None:
1128 return False
1129
1130 # skip file generation for cleanxxx targets, run and fds target
1131 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1132 # for target which must generate AutoGen code and makefile
1133 if not self.SkipAutoGen or Target == 'genc':
1134 self.Progress.Start("Generating code")
1135 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
1136 self.Progress.Stop("done!")
1137 if Target == "genc":
1138 return True
1139
1140 if not self.SkipAutoGen or Target == 'genmake':
1141 self.Progress.Start("Generating makefile")
1142 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)
1143 self.Progress.Stop("done!")
1144 if Target == "genmake":
1145 return True
1146 else:
1147 # always recreate top/platform makefile when clean, just in case of inconsistency
1148 AutoGenObject.CreateCodeFile(False)
1149 AutoGenObject.CreateMakeFile(False)
1150
1151 if EdkLogger.GetLevel() == EdkLogger.QUIET:
1152 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
1153
1154 BuildCommand = AutoGenObject.BuildCommand
1155 if BuildCommand == None or len(BuildCommand) == 0:
1156 EdkLogger.error("build", OPTION_MISSING,
1157 "No build command found for this module. "
1158 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1159 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
1160 ExtraData=str(AutoGenObject))
1161
1162 makefile = GenMake.BuildFile(AutoGenObject)._FILE_NAME_[GenMake.gMakeType]
1163
1164 # run
1165 if Target == 'run':
1166 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))
1167 Command = '.\SecMain'
1168 os.chdir(RunDir)
1169 LaunchCommand(Command, RunDir)
1170 return True
1171
1172 # build modules
1173 if BuildModule:
1174 BuildCommand = BuildCommand + [Target]
1175 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
1176 self.CreateAsBuiltInf()
1177 return True
1178
1179 # build library
1180 if Target == 'libraries':
1181 for Lib in AutoGenObject.LibraryBuildDirectoryList:
1182 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']
1183 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1184 return True
1185
1186 # build module
1187 if Target == 'modules':
1188 for Lib in AutoGenObject.LibraryBuildDirectoryList:
1189 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']
1190 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1191 for Mod in AutoGenObject.ModuleBuildDirectoryList:
1192 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']
1193 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1194 self.CreateAsBuiltInf()
1195 return True
1196
1197 # cleanlib
1198 if Target == 'cleanlib':
1199 for Lib in AutoGenObject.LibraryBuildDirectoryList:
1200 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))
1201 if os.path.exists(LibMakefile):
1202 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
1203 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1204 return True
1205
1206 # clean
1207 if Target == 'clean':
1208 for Mod in AutoGenObject.ModuleBuildDirectoryList:
1209 ModMakefile = os.path.normpath(os.path.join(Mod, makefile))
1210 if os.path.exists(ModMakefile):
1211 NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']
1212 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1213 for Lib in AutoGenObject.LibraryBuildDirectoryList:
1214 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))
1215 if os.path.exists(LibMakefile):
1216 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
1217 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
1218 return True
1219
1220 # cleanall
1221 if Target == 'cleanall':
1222 try:
1223 #os.rmdir(AutoGenObject.BuildDir)
1224 RemoveDirectory(AutoGenObject.BuildDir, True)
1225 except WindowsError, X:
1226 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
1227 return True
1228
1229 ## Build a module or platform
1230 #
1231 # Create autogen code and makefile for a module or platform, and the launch
1232 # "make" command to build it
1233 #
1234 # @param Target The target of build command
1235 # @param Platform The platform file
1236 # @param Module The module file
1237 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"
1238 # @param ToolChain The name of toolchain to build
1239 # @param Arch The arch of the module/platform
1240 # @param CreateDepModuleCodeFile Flag used to indicate creating code
1241 # for dependent modules/Libraries
1242 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile
1243 # for dependent modules/Libraries
1244 #
1245 def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):
1246 if AutoGenObject == None:
1247 return False
1248
1249 # skip file generation for cleanxxx targets, run and fds target
1250 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1251 # for target which must generate AutoGen code and makefile
1252 if not self.SkipAutoGen or Target == 'genc':
1253 self.Progress.Start("Generating code")
1254 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
1255 self.Progress.Stop("done!")
1256 if Target == "genc":
1257 return True
1258
1259 if not self.SkipAutoGen or Target == 'genmake':
1260 self.Progress.Start("Generating makefile")
1261 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)
1262 #AutoGenObject.CreateAsBuiltInf()
1263 self.Progress.Stop("done!")
1264 if Target == "genmake":
1265 return True
1266 else:
1267 # always recreate top/platform makefile when clean, just in case of inconsistency
1268 AutoGenObject.CreateCodeFile(False)
1269 AutoGenObject.CreateMakeFile(False)
1270
1271 if EdkLogger.GetLevel() == EdkLogger.QUIET:
1272 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))
1273
1274 BuildCommand = AutoGenObject.BuildCommand
1275 if BuildCommand == None or len(BuildCommand) == 0:
1276 EdkLogger.error("build", OPTION_MISSING,
1277 "No build command found for this module. "
1278 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
1279 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
1280 ExtraData=str(AutoGenObject))
1281
1282 # build modules
1283 if BuildModule:
1284 if Target != 'fds':
1285 BuildCommand = BuildCommand + [Target]
1286 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
1287 self.CreateAsBuiltInf()
1288 return True
1289
1290 # genfds
1291 if Target == 'fds':
1292 LaunchCommand(AutoGenObject.GenFdsCommand, AutoGenObject.MakeFileDir)
1293 return True
1294
1295 # run
1296 if Target == 'run':
1297 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))
1298 Command = '.\SecMain'
1299 os.chdir(RunDir)
1300 LaunchCommand(Command, RunDir)
1301 return True
1302
1303 # build library
1304 if Target == 'libraries':
1305 pass
1306
1307 # not build modules
1308
1309
1310 # cleanall
1311 if Target == 'cleanall':
1312 try:
1313 #os.rmdir(AutoGenObject.BuildDir)
1314 RemoveDirectory(AutoGenObject.BuildDir, True)
1315 except WindowsError, X:
1316 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
1317 return True
1318
1319 ## Rebase module image and Get function address for the input module list.
1320 #
1321 def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):
1322 if ModeIsSmm:
1323 AddrIsOffset = False
1324 InfFileNameList = ModuleList.keys()
1325 #InfFileNameList.sort()
1326 for InfFile in InfFileNameList:
1327 sys.stdout.write (".")
1328 sys.stdout.flush()
1329 ModuleInfo = ModuleList[InfFile]
1330 ModuleName = ModuleInfo.BaseName
1331 ModuleOutputImage = ModuleInfo.Image.FileName
1332 ModuleDebugImage = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')
1333 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1334 if not ModeIsSmm:
1335 BaseAddress = BaseAddress - ModuleInfo.Image.Size
1336 #
1337 # Update Image to new BaseAddress by GenFw tool
1338 #
1339 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
1340 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
1341 else:
1342 #
1343 # Set new address to the section header only for SMM driver.
1344 #
1345 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)
1346 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)
1347 #
1348 # Collect funtion address from Map file
1349 #
1350 ImageMapTable = ModuleOutputImage.replace('.efi', '.map')
1351 FunctionList = []
1352 if os.path.exists(ImageMapTable):
1353 OrigImageBaseAddress = 0
1354 ImageMap = open(ImageMapTable, 'r')
1355 for LinStr in ImageMap:
1356 if len (LinStr.strip()) == 0:
1357 continue
1358 #
1359 # Get the preferred address set on link time.
1360 #
1361 if LinStr.find ('Preferred load address is') != -1:
1362 StrList = LinStr.split()
1363 OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)
1364
1365 StrList = LinStr.split()
1366 if len (StrList) > 4:
1367 if StrList[3] == 'f' or StrList[3] == 'F':
1368 Name = StrList[1]
1369 RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress
1370 FunctionList.append ((Name, RelativeAddress))
1371 if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'):
1372 #
1373 # Get the real entry point address for IPF image.
1374 #
1375 ModuleInfo.Image.EntryPoint = RelativeAddress
1376 ImageMap.close()
1377 #
1378 # Add general information.
1379 #
1380 if ModeIsSmm:
1381 MapBuffer.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
1382 elif AddrIsOffset:
1383 MapBuffer.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))
1384 else:
1385 MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))
1386 #
1387 # Add guid and general seciton section.
1388 #
1389 TextSectionAddress = 0
1390 DataSectionAddress = 0
1391 for SectionHeader in ModuleInfo.Image.SectionHeaderList:
1392 if SectionHeader[0] == '.text':
1393 TextSectionAddress = SectionHeader[1]
1394 elif SectionHeader[0] in ['.data', '.sdata']:
1395 DataSectionAddress = SectionHeader[1]
1396 if AddrIsOffset:
1397 MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))
1398 else:
1399 MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))
1400 #
1401 # Add debug image full path.
1402 #
1403 MapBuffer.write('(IMAGE=%s)\n\n' % (ModuleDebugImage))
1404 #
1405 # Add funtion address
1406 #
1407 for Function in FunctionList:
1408 if AddrIsOffset:
1409 MapBuffer.write(' -0x%010X %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))
1410 else:
1411 MapBuffer.write(' 0x%010X %s\n' % (BaseAddress + Function[1], Function[0]))
1412 ImageMap.close()
1413
1414 #
1415 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.
1416 #
1417 if ModeIsSmm:
1418 BaseAddress = BaseAddress + ModuleInfo.Image.Size
1419
1420 ## Collect MAP information of all FVs
1421 #
1422 def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):
1423 if self.Fdf:
1424 # First get the XIP base address for FV map file.
1425 GuidPattern = re.compile("[-a-fA-F0-9]+")
1426 GuidName = re.compile("\(GUID=[-a-fA-F0-9]+")
1427 for FvName in Wa.FdfProfile.FvDict.keys():
1428 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')
1429 if not os.path.exists(FvMapBuffer):
1430 continue
1431 FvMap = open(FvMapBuffer, 'r')
1432 #skip FV size information
1433 FvMap.readline()
1434 FvMap.readline()
1435 FvMap.readline()
1436 FvMap.readline()
1437 for Line in FvMap:
1438 MatchGuid = GuidPattern.match(Line)
1439 if MatchGuid != None:
1440 #
1441 # Replace GUID with module name
1442 #
1443 GuidString = MatchGuid.group()
1444 if GuidString.upper() in ModuleList:
1445 Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)
1446 MapBuffer.write('%s' % (Line))
1447 #
1448 # Add the debug image full path.
1449 #
1450 MatchGuid = GuidName.match(Line)
1451 if MatchGuid != None:
1452 GuidString = MatchGuid.group().split("=")[1]
1453 if GuidString.upper() in ModuleList:
1454 MapBuffer.write('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))
1455
1456 FvMap.close()
1457
1458 ## Collect MAP information of all modules
1459 #
1460 def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):
1461 sys.stdout.write ("Generate Load Module At Fix Address Map")
1462 sys.stdout.flush()
1463 PatchEfiImageList = []
1464 PeiModuleList = {}
1465 BtModuleList = {}
1466 RtModuleList = {}
1467 SmmModuleList = {}
1468 PeiSize = 0
1469 BtSize = 0
1470 RtSize = 0
1471 # reserve 4K size in SMRAM to make SMM module address not from 0.
1472 SmmSize = 0x1000
1473 IsIpfPlatform = False
1474 if 'IPF' in self.ArchList:
1475 IsIpfPlatform = True
1476 for ModuleGuid in ModuleList:
1477 Module = ModuleList[ModuleGuid]
1478 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)
1479
1480 OutputImageFile = ''
1481 for ResultFile in Module.CodaTargetList:
1482 if str(ResultFile.Target).endswith('.efi'):
1483 #
1484 # module list for PEI, DXE, RUNTIME and SMM
1485 #
1486 OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')
1487 ImageClass = PeImageClass (OutputImageFile)
1488 if not ImageClass.IsValid:
1489 EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)
1490 ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)
1491 if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER', 'PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']:
1492 PeiModuleList[Module.MetaFile] = ImageInfo
1493 PeiSize += ImageInfo.Image.Size
1494 elif Module.ModuleType in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']:
1495 BtModuleList[Module.MetaFile] = ImageInfo
1496 BtSize += ImageInfo.Image.Size
1497 elif Module.ModuleType in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']:
1498 RtModuleList[Module.MetaFile] = ImageInfo
1499 #IPF runtime driver needs to be at 2 page alignment.
1500 if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0:
1501 ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000
1502 RtSize += ImageInfo.Image.Size
1503 elif Module.ModuleType in ['SMM_CORE', 'DXE_SMM_DRIVER']:
1504 SmmModuleList[Module.MetaFile] = ImageInfo
1505 SmmSize += ImageInfo.Image.Size
1506 if Module.ModuleType == 'DXE_SMM_DRIVER':
1507 PiSpecVersion = '0x00000000'
1508 if 'PI_SPECIFICATION_VERSION' in Module.Module.Specification:
1509 PiSpecVersion = Module.Module.Specification['PI_SPECIFICATION_VERSION']
1510 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.
1511 if int(PiSpecVersion, 16) < 0x0001000A:
1512 BtModuleList[Module.MetaFile] = ImageInfo
1513 BtSize += ImageInfo.Image.Size
1514 break
1515 #
1516 # EFI image is final target.
1517 # Check EFI image contains patchable FixAddress related PCDs.
1518 #
1519 if OutputImageFile != '':
1520 ModuleIsPatch = False
1521 for Pcd in Module.ModulePcdList:
1522 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:
1523 ModuleIsPatch = True
1524 break
1525 if not ModuleIsPatch:
1526 for Pcd in Module.LibraryPcdList:
1527 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:
1528 ModuleIsPatch = True
1529 break
1530
1531 if not ModuleIsPatch:
1532 continue
1533 #
1534 # Module includes the patchable load fix address PCDs.
1535 # It will be fixed up later.
1536 #
1537 PatchEfiImageList.append (OutputImageFile)
1538
1539 #
1540 # Get Top Memory address
1541 #
1542 ReservedRuntimeMemorySize = 0
1543 TopMemoryAddress = 0
1544 if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:
1545 TopMemoryAddress = 0
1546 else:
1547 TopMemoryAddress = self.LoadFixAddress
1548 if TopMemoryAddress < RtSize + BtSize + PeiSize:
1549 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")
1550 # Make IPF runtime driver at 2 page alignment.
1551 if IsIpfPlatform:
1552 ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000
1553 RtSize = RtSize + ReservedRuntimeMemorySize
1554
1555 #
1556 # Patch FixAddress related PCDs into EFI image
1557 #
1558 for EfiImage in PatchEfiImageList:
1559 EfiImageMap = EfiImage.replace('.efi', '.map')
1560 if not os.path.exists(EfiImageMap):
1561 continue
1562 #
1563 # Get PCD offset in EFI image by GenPatchPcdTable function
1564 #
1565 PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)
1566 #
1567 # Patch real PCD value by PatchPcdValue tool
1568 #
1569 for PcdInfo in PcdTable:
1570 ReturnValue = 0
1571 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:
1572 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize / 0x1000))
1573 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:
1574 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize / 0x1000))
1575 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:
1576 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize / 0x1000))
1577 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:
1578 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize / 0x1000))
1579 if ReturnValue != 0:
1580 EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)
1581
1582 MapBuffer.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize / 0x1000))
1583 MapBuffer.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize / 0x1000))
1584 MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize / 0x1000))
1585 if len (SmmModuleList) > 0:
1586 MapBuffer.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize / 0x1000))
1587
1588 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize
1589 BtBaseAddr = TopMemoryAddress - RtSize
1590 RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize
1591
1592 self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)
1593 self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)
1594 self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)
1595 self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset=False, ModeIsSmm=True)
1596 MapBuffer.write('\n\n')
1597 sys.stdout.write ("\n")
1598 sys.stdout.flush()
1599
1600 ## Save platform Map file
1601 #
1602 def _SaveMapFile (self, MapBuffer, Wa):
1603 #
1604 # Map file path is got.
1605 #
1606 MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')
1607 #
1608 # Save address map into MAP file.
1609 #
1610 SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)
1611 MapBuffer.close()
1612 if self.LoadFixAddress != 0:
1613 sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath))
1614 sys.stdout.flush()
1615
1616 ## Build active platform for different build targets and different tool chains
1617 #
1618 def _BuildPlatform(self):
1619 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1620 for BuildTarget in self.BuildTargetList:
1621 GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1622 index = 0
1623 for ToolChain in self.ToolChainList:
1624 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1625 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1626 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
1627 index += 1
1628 Wa = WorkspaceAutoGen(
1629 self.WorkspaceDir,
1630 self.PlatformFile,
1631 BuildTarget,
1632 ToolChain,
1633 self.ArchList,
1634 self.BuildDatabase,
1635 self.TargetTxt,
1636 self.ToolDef,
1637 self.Fdf,
1638 self.FdList,
1639 self.FvList,
1640 self.CapList,
1641 self.SkuId,
1642 self.UniFlag,
1643 self.Progress
1644 )
1645 self.Fdf = Wa.FdfFile
1646 self.LoadFixAddress = Wa.Platform.LoadFixAddress
1647 self.BuildReport.AddPlatformReport(Wa)
1648 self.Progress.Stop("done!")
1649 for Arch in Wa.ArchList:
1650 GlobalData.gGlobalDefines['ARCH'] = Arch
1651 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
1652 for Module in Pa.Platform.Modules:
1653 # Get ModuleAutoGen object to generate C code file and makefile
1654 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
1655 if Ma == None:
1656 continue
1657 self.BuildModules.append(Ma)
1658 self._BuildPa(self.Target, Pa)
1659
1660 # Create MAP file when Load Fix Address is enabled.
1661 if self.Target in ["", "all", "fds"]:
1662 for Arch in Wa.ArchList:
1663 GlobalData.gGlobalDefines['ARCH'] = Arch
1664 #
1665 # Check whether the set fix address is above 4G for 32bit image.
1666 #
1667 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1668 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")
1669 #
1670 # Get Module List
1671 #
1672 ModuleList = {}
1673 for Pa in Wa.AutoGenObjectList:
1674 for Ma in Pa.ModuleAutoGenList:
1675 if Ma == None:
1676 continue
1677 if not Ma.IsLibrary:
1678 ModuleList[Ma.Guid.upper()] = Ma
1679
1680 MapBuffer = StringIO('')
1681 if self.LoadFixAddress != 0:
1682 #
1683 # Rebase module to the preferred memory address before GenFds
1684 #
1685 self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1686 if self.Fdf:
1687 #
1688 # create FDS again for the updated EFI image
1689 #
1690 self._Build("fds", Wa)
1691 #
1692 # Create MAP file for all platform FVs after GenFds.
1693 #
1694 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1695 #
1696 # Save MAP buffer into MAP file.
1697 #
1698 self._SaveMapFile (MapBuffer, Wa)
1699
1700 ## Build active module for different build targets, different tool chains and different archs
1701 #
1702 def _BuildModule(self):
1703 for BuildTarget in self.BuildTargetList:
1704 GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1705 index = 0
1706 for ToolChain in self.ToolChainList:
1707 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1708 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1709 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
1710 index += 1
1711 #
1712 # module build needs platform build information, so get platform
1713 # AutoGen first
1714 #
1715 Wa = WorkspaceAutoGen(
1716 self.WorkspaceDir,
1717 self.PlatformFile,
1718 BuildTarget,
1719 ToolChain,
1720 self.ArchList,
1721 self.BuildDatabase,
1722 self.TargetTxt,
1723 self.ToolDef,
1724 self.Fdf,
1725 self.FdList,
1726 self.FvList,
1727 self.CapList,
1728 self.SkuId,
1729 self.UniFlag,
1730 self.Progress,
1731 self.ModuleFile
1732 )
1733 self.Fdf = Wa.FdfFile
1734 self.LoadFixAddress = Wa.Platform.LoadFixAddress
1735 Wa.CreateMakeFile(False)
1736 self.Progress.Stop("done!")
1737 MaList = []
1738 for Arch in Wa.ArchList:
1739 GlobalData.gGlobalDefines['ARCH'] = Arch
1740 Ma = ModuleAutoGen(Wa, self.ModuleFile, BuildTarget, ToolChain, Arch, self.PlatformFile)
1741 if Ma == None: continue
1742 MaList.append(Ma)
1743 self.BuildModules.append(Ma)
1744 if not Ma.IsBinaryModule:
1745 self._Build(self.Target, Ma, BuildModule=True)
1746
1747 self.BuildReport.AddPlatformReport(Wa, MaList)
1748 if MaList == []:
1749 EdkLogger.error(
1750 'build',
1751 BUILD_ERROR,
1752 "Module for [%s] is not a component of active platform."\
1753 " Please make sure that the ARCH and inf file path are"\
1754 " given in the same as in [%s]" % \
1755 (', '.join(Wa.ArchList), self.PlatformFile),
1756 ExtraData=self.ModuleFile
1757 )
1758 # Create MAP file when Load Fix Address is enabled.
1759 if self.Target == "fds" and self.Fdf:
1760 for Arch in Wa.ArchList:
1761 #
1762 # Check whether the set fix address is above 4G for 32bit image.
1763 #
1764 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1765 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")
1766 #
1767 # Get Module List
1768 #
1769 ModuleList = {}
1770 for Pa in Wa.AutoGenObjectList:
1771 for Ma in Pa.ModuleAutoGenList:
1772 if Ma == None:
1773 continue
1774 if not Ma.IsLibrary:
1775 ModuleList[Ma.Guid.upper()] = Ma
1776
1777 MapBuffer = StringIO('')
1778 if self.LoadFixAddress != 0:
1779 #
1780 # Rebase module to the preferred memory address before GenFds
1781 #
1782 self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1783 #
1784 # create FDS again for the updated EFI image
1785 #
1786 self._Build("fds", Wa)
1787 #
1788 # Create MAP file for all platform FVs after GenFds.
1789 #
1790 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1791 #
1792 # Save MAP buffer into MAP file.
1793 #
1794 self._SaveMapFile (MapBuffer, Wa)
1795
1796 ## Build a platform in multi-thread mode
1797 #
1798 def _MultiThreadBuildPlatform(self):
1799 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)
1800 for BuildTarget in self.BuildTargetList:
1801 GlobalData.gGlobalDefines['TARGET'] = BuildTarget
1802 index = 0
1803 for ToolChain in self.ToolChainList:
1804 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
1805 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
1806 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
1807 index += 1
1808 Wa = WorkspaceAutoGen(
1809 self.WorkspaceDir,
1810 self.PlatformFile,
1811 BuildTarget,
1812 ToolChain,
1813 self.ArchList,
1814 self.BuildDatabase,
1815 self.TargetTxt,
1816 self.ToolDef,
1817 self.Fdf,
1818 self.FdList,
1819 self.FvList,
1820 self.CapList,
1821 self.SkuId,
1822 self.UniFlag,
1823 self.Progress
1824 )
1825 self.Fdf = Wa.FdfFile
1826 self.LoadFixAddress = Wa.Platform.LoadFixAddress
1827 self.BuildReport.AddPlatformReport(Wa)
1828 Wa.CreateMakeFile(False)
1829
1830 # multi-thread exit flag
1831 ExitFlag = threading.Event()
1832 ExitFlag.clear()
1833 for Arch in Wa.ArchList:
1834 GlobalData.gGlobalDefines['ARCH'] = Arch
1835 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
1836 if Pa == None:
1837 continue
1838 ModuleList = []
1839 for Inf in Pa.Platform.Modules:
1840 ModuleList.append(Inf)
1841 # Add the INF only list in FDF
1842 if GlobalData.gFdfParser != None:
1843 for InfName in GlobalData.gFdfParser.Profile.InfList:
1844 Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)
1845 if Inf in Pa.Platform.Modules:
1846 continue
1847 ModuleList.append(Inf)
1848 for Module in ModuleList:
1849 # Get ModuleAutoGen object to generate C code file and makefile
1850 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)
1851
1852 if Ma == None:
1853 continue
1854 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
1855 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
1856 # for target which must generate AutoGen code and makefile
1857 if not self.SkipAutoGen or self.Target == 'genc':
1858 Ma.CreateCodeFile(True)
1859 if self.Target == "genc":
1860 continue
1861
1862 if not self.SkipAutoGen or self.Target == 'genmake':
1863 Ma.CreateMakeFile(True)
1864 if self.Target == "genmake":
1865 continue
1866 self.BuildModules.append(Ma)
1867 self.Progress.Stop("done!")
1868
1869 for Ma in self.BuildModules:
1870 # Generate build task for the module
1871 if not Ma.IsBinaryModule:
1872 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))
1873 # Break build if any build thread has error
1874 if BuildTask.HasError():
1875 # we need a full version of makefile for platform
1876 ExitFlag.set()
1877 BuildTask.WaitForComplete()
1878 Pa.CreateMakeFile(False)
1879 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1880 # Start task scheduler
1881 if not BuildTask.IsOnGoing():
1882 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)
1883
1884 # in case there's an interruption. we need a full version of makefile for platform
1885 Pa.CreateMakeFile(False)
1886 if BuildTask.HasError():
1887 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1888
1889 #
1890 # Save temp tables to a TmpTableDict.
1891 #
1892 for Key in Wa.BuildDatabase._CACHE_:
1893 if Wa.BuildDatabase._CACHE_[Key]._RawData and Wa.BuildDatabase._CACHE_[Key]._RawData._Table and Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table:
1894 if TemporaryTablePattern.match(Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table):
1895 TmpTableDict[Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Table] = Wa.BuildDatabase._CACHE_[Key]._RawData._Table.Cur
1896 #
1897 #
1898 # All modules have been put in build tasks queue. Tell task scheduler
1899 # to exit if all tasks are completed
1900 #
1901 ExitFlag.set()
1902 BuildTask.WaitForComplete()
1903 self.CreateAsBuiltInf()
1904
1905 #
1906 # Check for build error, and raise exception if one
1907 # has been signaled.
1908 #
1909 if BuildTask.HasError():
1910 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
1911
1912 # Create MAP file when Load Fix Address is enabled.
1913 if self.Target in ["", "all", "fds"]:
1914 for Arch in Wa.ArchList:
1915 #
1916 # Check whether the set fix address is above 4G for 32bit image.
1917 #
1918 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
1919 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")
1920 #
1921 # Get Module List
1922 #
1923 ModuleList = {}
1924 for Pa in Wa.AutoGenObjectList:
1925 for Ma in Pa.ModuleAutoGenList:
1926 if Ma == None:
1927 continue
1928 if not Ma.IsLibrary:
1929 ModuleList[Ma.Guid.upper()] = Ma
1930 #
1931 # Rebase module to the preferred memory address before GenFds
1932 #
1933 MapBuffer = StringIO('')
1934 if self.LoadFixAddress != 0:
1935 self._CollectModuleMapBuffer(MapBuffer, ModuleList)
1936
1937 if self.Fdf:
1938 #
1939 # Generate FD image if there's a FDF file found
1940 #
1941 LaunchCommand(Wa.GenFdsCommand, os.getcwd())
1942
1943 #
1944 # Create MAP file for all platform FVs after GenFds.
1945 #
1946 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
1947 #
1948 # Save MAP buffer into MAP file.
1949 #
1950 self._SaveMapFile(MapBuffer, Wa)
1951
1952 ## Generate GuidedSectionTools.txt in the FV directories.
1953 #
1954 def CreateGuidedSectionToolsFile(self):
1955 for BuildTarget in self.BuildTargetList:
1956 for ToolChain in self.ToolChainList:
1957 Wa = WorkspaceAutoGen(
1958 self.WorkspaceDir,
1959 self.PlatformFile,
1960 BuildTarget,
1961 ToolChain,
1962 self.ArchList,
1963 self.BuildDatabase,
1964 self.TargetTxt,
1965 self.ToolDef,
1966 self.Fdf,
1967 self.FdList,
1968 self.FvList,
1969 self.CapList,
1970 self.SkuId,
1971 self.UniFlag
1972 )
1973 FvDir = Wa.FvDir
1974 if not os.path.exists(FvDir):
1975 continue
1976
1977 for Arch in self.ArchList:
1978 # Build up the list of supported architectures for this build
1979 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)
1980
1981 # Look through the tool definitions for GUIDed tools
1982 guidAttribs = []
1983 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():
1984 if attrib.upper().endswith('_GUID'):
1985 split = attrib.split('_')
1986 thisPrefix = '_'.join(split[0:3]) + '_'
1987 if thisPrefix == prefix:
1988 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]
1989 guid = guid.lower()
1990 toolName = split[3]
1991 path = '_'.join(split[0:4]) + '_PATH'
1992 path = self.ToolDef.ToolsDefTxtDictionary[path]
1993 path = self.GetFullPathOfTool(path)
1994 guidAttribs.append((guid, toolName, path))
1995
1996 # Write out GuidedSecTools.txt
1997 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')
1998 toolsFile = open(toolsFile, 'wt')
1999 for guidedSectionTool in guidAttribs:
2000 print >> toolsFile, ' '.join(guidedSectionTool)
2001 toolsFile.close()
2002
2003 ## Returns the full path of the tool.
2004 #
2005 def GetFullPathOfTool (self, tool):
2006 if os.path.exists(tool):
2007 return os.path.realpath(tool)
2008 else:
2009 # We need to search for the tool using the
2010 # PATH environment variable.
2011 for dirInPath in os.environ['PATH'].split(os.pathsep):
2012 foundPath = os.path.join(dirInPath, tool)
2013 if os.path.exists(foundPath):
2014 return os.path.realpath(foundPath)
2015
2016 # If the tool was not found in the path then we just return
2017 # the input tool.
2018 return tool
2019
2020 ## Launch the module or platform build
2021 #
2022 def Launch(self):
2023 if not self.ModuleFile:
2024 if not self.SpawnMode or self.Target not in ["", "all"]:
2025 self.SpawnMode = False
2026 self._BuildPlatform()
2027 else:
2028 self._MultiThreadBuildPlatform()
2029 self.CreateGuidedSectionToolsFile()
2030 else:
2031 self.SpawnMode = False
2032 self._BuildModule()
2033
2034 if self.Target == 'cleanall':
2035 self.Db.Close()
2036 RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)
2037
2038 def CreateAsBuiltInf(self):
2039 for Module in self.BuildModules:
2040 Module.CreateAsBuiltInf()
2041 self.BuildModules = []
2042 ## Do some clean-up works when error occurred
2043 def Relinquish(self):
2044 OldLogLevel = EdkLogger.GetLevel()
2045 EdkLogger.SetLevel(EdkLogger.ERROR)
2046 #self.DumpBuildData()
2047 Utils.Progressor.Abort()
2048 if self.SpawnMode == True:
2049 BuildTask.Abort()
2050 EdkLogger.SetLevel(OldLogLevel)
2051
2052 def DumpBuildData(self):
2053 CacheDirectory = os.path.dirname(GlobalData.gDatabasePath)
2054 Utils.CreateDirectory(CacheDirectory)
2055 Utils.DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))
2056 Utils.DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))
2057
2058 def RestoreBuildData(self):
2059 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gFileTimeStampCache")
2060 if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):
2061 Utils.gFileTimeStampCache = Utils.DataRestore(FilePath)
2062 if Utils.gFileTimeStampCache == None:
2063 Utils.gFileTimeStampCache = {}
2064
2065 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gDependencyDatabase")
2066 if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):
2067 Utils.gDependencyDatabase = Utils.DataRestore(FilePath)
2068 if Utils.gDependencyDatabase == None:
2069 Utils.gDependencyDatabase = {}
2070
2071 def ParseDefines(DefineList=[]):
2072 DefineDict = {}
2073 if DefineList != None:
2074 for Define in DefineList:
2075 DefineTokenList = Define.split("=", 1)
2076 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):
2077 EdkLogger.error('build', FORMAT_INVALID,
2078 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
2079 ExtraData=DefineTokenList[0])
2080
2081 if len(DefineTokenList) == 1:
2082 DefineDict[DefineTokenList[0]] = "TRUE"
2083 else:
2084 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()
2085 return DefineDict
2086
2087 gParamCheck = []
2088 def SingleCheckCallback(option, opt_str, value, parser):
2089 if option not in gParamCheck:
2090 setattr(parser.values, option.dest, value)
2091 gParamCheck.append(option)
2092 else:
2093 parser.error("Option %s only allows one instance in command line!" % option)
2094
2095 ## Parse command line options
2096 #
2097 # Using standard Python module optparse to parse command line option of this tool.
2098 #
2099 # @retval Opt A optparse.Values object containing the parsed options
2100 # @retval Args Target of build command
2101 #
2102 def MyOptionParser():
2103 Parser = OptionParser(description=__copyright__, version=__version__, prog="build.exe", usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")
2104 Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32', 'X64', 'IPF', 'EBC', 'ARM', 'AARCH64'], dest="TargetArch",
2105 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.")
2106 Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,
2107 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")
2108 Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,
2109 help="Build the module specified by the INF file name argument.")
2110 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",
2111 action="append")
2112 Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",
2113 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")
2114 Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,
2115 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")
2116
2117 Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,
2118 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.")
2119
2120 Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,
2121 help="The name of the FDF file to use, which overrides the setting in the DSC file.")
2122 Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],
2123 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")
2124 Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],
2125 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")
2126 Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],
2127 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")
2128 Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")
2129 Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")
2130
2131 Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.")
2132
2133 Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")
2134 Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")
2135
2136 Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",
2137 help="Make use of silent mode of (n)make.")
2138 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
2139 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
2140 "including library instances selected, final dependency expression, "\
2141 "and warning messages, etc.")
2142 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
2143 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
2144
2145 Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")
2146 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=[],
2147 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]. "\
2148 "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]")
2149 Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",
2150 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. "\
2151 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\
2152 "will override the setting in [BuildOptions] section of platform DSC.")
2153 Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism")
2154 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")
2155 Parser.add_option("--check-usage", action="store_true", dest="CheckUsage", default=False, help="Check usage content of entries listed in INF file.")
2156 Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")
2157 Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
2158 Parser.add_option("-l", "--cmd-len", action="store", type="int", dest="CommandLength", help="Specify the maximum line length of build command. Default is 4096.")
2159
2160 (Opt, Args) = Parser.parse_args()
2161 return (Opt, Args)
2162
2163 ## Tool entrance method
2164 #
2165 # This method mainly dispatch specific methods per the command line options.
2166 # If no error found, return zero value so the caller of this tool can know
2167 # if it's executed successfully or not.
2168 #
2169 # @retval 0 Tool was successful
2170 # @retval 1 Tool failed
2171 #
2172 def Main():
2173 StartTime = time.time()
2174
2175 # Initialize log system
2176 EdkLogger.Initialize()
2177 GlobalData.gCommand = sys.argv[1:]
2178 #
2179 # Parse the options and args
2180 #
2181 (Option, Target) = MyOptionParser()
2182 GlobalData.gOptions = Option
2183 GlobalData.gCaseInsensitive = Option.CaseInsensitive
2184
2185 # Set log level
2186 if Option.verbose != None:
2187 EdkLogger.SetLevel(EdkLogger.VERBOSE)
2188 elif Option.quiet != None:
2189 EdkLogger.SetLevel(EdkLogger.QUIET)
2190 elif Option.debug != None:
2191 EdkLogger.SetLevel(Option.debug + 1)
2192 else:
2193 EdkLogger.SetLevel(EdkLogger.INFO)
2194
2195 if Option.LogFile != None:
2196 EdkLogger.SetLogFile(Option.LogFile)
2197
2198 if Option.WarningAsError == True:
2199 EdkLogger.SetWarningAsError()
2200
2201 if platform.platform().find("Windows") >= 0:
2202 GlobalData.gIsWindows = True
2203 else:
2204 GlobalData.gIsWindows = False
2205
2206 EdkLogger.quiet("Build environment: %s" % platform.platform())
2207 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));
2208 ReturnCode = 0
2209 MyBuild = None
2210 BuildError = True
2211 try:
2212 if len(Target) == 0:
2213 Target = "all"
2214 elif len(Target) >= 2:
2215 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",
2216 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))
2217 else:
2218 Target = Target[0].lower()
2219
2220 if Target not in gSupportedTarget:
2221 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,
2222 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))
2223
2224 #
2225 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH
2226 #
2227 CheckEnvVariable()
2228 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))
2229
2230 Workspace = os.getenv("WORKSPACE")
2231 #
2232 # Get files real name in workspace dir
2233 #
2234 GlobalData.gAllFiles = Utils.DirCache(Workspace)
2235
2236 WorkingDirectory = os.getcwd()
2237 if not Option.ModuleFile:
2238 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))
2239 FileNum = len(FileList)
2240 if FileNum >= 2:
2241 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),
2242 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")
2243 elif FileNum == 1:
2244 Option.ModuleFile = NormFile(FileList[0], Workspace)
2245
2246 if Option.ModuleFile:
2247 if os.path.isabs (Option.ModuleFile):
2248 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:
2249 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)
2250 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)
2251 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)
2252 if ErrorCode != 0:
2253 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
2254
2255 if Option.PlatformFile != None:
2256 if os.path.isabs (Option.PlatformFile):
2257 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:
2258 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)
2259 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)
2260
2261 if Option.FdfFile != None:
2262 if os.path.isabs (Option.FdfFile):
2263 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:
2264 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)
2265 Option.FdfFile = PathClass(Option.FdfFile, Workspace)
2266 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)
2267 if ErrorCode != 0:
2268 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)
2269
2270 if Option.Flag != None and Option.Flag not in ['-c', '-s']:
2271 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")
2272
2273 MyBuild = Build(Target, Workspace, Option)
2274 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)
2275 if not (MyBuild.LaunchPrebuildFlag and os.path.exists(MyBuild.PlatformBuildPath)):
2276 MyBuild.Launch()
2277 # Drop temp tables to avoid database locked.
2278 for TmpTableName in TmpTableDict:
2279 SqlCommand = """drop table IF EXISTS %s""" % TmpTableName
2280 TmpTableDict[TmpTableName].execute(SqlCommand)
2281 #MyBuild.DumpBuildData()
2282 #
2283 # All job done, no error found and no exception raised
2284 #
2285 BuildError = False
2286 except FatalError, X:
2287 if MyBuild != None:
2288 # for multi-thread build exits safely
2289 MyBuild.Relinquish()
2290 if Option != None and Option.debug != None:
2291 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2292 ReturnCode = X.args[0]
2293 except Warning, X:
2294 # error from Fdf parser
2295 if MyBuild != None:
2296 # for multi-thread build exits safely
2297 MyBuild.Relinquish()
2298 if Option != None and Option.debug != None:
2299 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2300 else:
2301 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)
2302 ReturnCode = FORMAT_INVALID
2303 except KeyboardInterrupt:
2304 ReturnCode = ABORT_ERROR
2305 if Option != None and Option.debug != None:
2306 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2307 except:
2308 if MyBuild != None:
2309 # for multi-thread build exits safely
2310 MyBuild.Relinquish()
2311
2312 # try to get the meta-file from the object causing exception
2313 Tb = sys.exc_info()[-1]
2314 MetaFile = GlobalData.gProcessingFile
2315 while Tb != None:
2316 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):
2317 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile
2318 Tb = Tb.tb_next
2319 EdkLogger.error(
2320 "\nbuild",
2321 CODE_ERROR,
2322 "Unknown fatal error when processing [%s]" % MetaFile,
2323 ExtraData="\n(Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!)\n",
2324 RaiseError=False
2325 )
2326 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())
2327 ReturnCode = CODE_ERROR
2328 finally:
2329 Utils.Progressor.Abort()
2330 Utils.ClearDuplicatedInf()
2331
2332 if ReturnCode == 0:
2333 try:
2334 MyBuild.LanuchPostbuild()
2335 Conclusion = "Done"
2336 except:
2337 Conclusion = "Failed"
2338 elif ReturnCode == ABORT_ERROR:
2339 Conclusion = "Aborted"
2340 else:
2341 Conclusion = "Failed"
2342 FinishTime = time.time()
2343 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))
2344 BuildDurationStr = ""
2345 if BuildDuration.tm_yday > 1:
2346 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)" % (BuildDuration.tm_yday - 1)
2347 else:
2348 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)
2349 if MyBuild != None:
2350 if not BuildError:
2351 MyBuild.BuildReport.GenerateReport(BuildDurationStr)
2352 MyBuild.Db.Close()
2353 EdkLogger.SetLevel(EdkLogger.QUIET)
2354 EdkLogger.quiet("\n- %s -" % Conclusion)
2355 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))
2356 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)
2357 return ReturnCode
2358
2359 if __name__ == '__main__':
2360 r = Main()
2361 ## 0-127 is a safe return range, and 1 is a standard default error
2362 if r < 0 or r > 127: r = 1
2363 sys.exit(r)
2364