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