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