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