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