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