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