]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - BaseTools/Source/Python/build/build.py
BaseTools: use dictionary.get() when we have value if not found
[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
19import Common.LongFilePathOs as os\r
20import re\r
21import StringIO\r
22import sys\r
23import glob\r
24import time\r
25import platform\r
26import traceback\r
27import encodings.ascii\r
28import itertools\r
29import multiprocessing\r
30\r
31from struct import *\r
32from threading import *\r
33from optparse import OptionParser\r
34from subprocess import *\r
35from Common import Misc as Utils\r
36\r
37from Common.LongFilePathSupport import OpenLongFilePath as open\r
38from Common.LongFilePathSupport import LongFilePath\r
39from Common.TargetTxtClassObject import *\r
40from Common.ToolDefClassObject import *\r
41from Common.DataType import *\r
42from Common.BuildVersion import gBUILD_VERSION\r
43from AutoGen.AutoGen import *\r
44from Common.BuildToolError import *\r
45from Workspace.WorkspaceDatabase import *\r
46from Common.MultipleWorkspace import MultipleWorkspace as mws\r
47\r
48from BuildReport import BuildReport\r
49from GenPatchPcdTable.GenPatchPcdTable import *\r
50from PatchPcdValue.PatchPcdValue import *\r
51\r
52import Common.EdkLogger\r
53import Common.GlobalData as GlobalData\r
54from GenFds.GenFds import GenFds\r
55\r
56from collections import OrderedDict\r
57\r
58# Version and Copyright\r
59VersionNumber = "0.60" + ' ' + gBUILD_VERSION\r
60__version__ = "%prog Version " + VersionNumber\r
61__copyright__ = "Copyright (c) 2007 - 2017, Intel Corporation All rights reserved."\r
62\r
63## standard targets of build command\r
64gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']\r
65\r
66## build configuration file\r
67gBuildConfiguration = "target.txt"\r
68gToolsDefinition = "tools_def.txt"\r
69\r
70TemporaryTablePattern = re.compile(r'^_\d+_\d+_[a-fA-F0-9]+$')\r
71TmpTableDict = {}\r
72\r
73## Check environment PATH variable to make sure the specified tool is found\r
74#\r
75# If the tool is found in the PATH, then True is returned\r
76# Otherwise, False is returned\r
77#\r
78def IsToolInPath(tool):\r
79 if os.environ.has_key('PATHEXT'):\r
80 extns = os.environ['PATHEXT'].split(os.path.pathsep)\r
81 else:\r
82 extns = ('',)\r
83 for pathDir in os.environ['PATH'].split(os.path.pathsep):\r
84 for ext in extns:\r
85 if os.path.exists(os.path.join(pathDir, tool + ext)):\r
86 return True\r
87 return False\r
88\r
89## Check environment variables\r
90#\r
91# Check environment variables that must be set for build. Currently they are\r
92#\r
93# WORKSPACE The directory all packages/platforms start from\r
94# EDK_TOOLS_PATH The directory contains all tools needed by the build\r
95# PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH\r
96#\r
97# If any of above environment variable is not set or has error, the build\r
98# will be broken.\r
99#\r
100def CheckEnvVariable():\r
101 # check WORKSPACE\r
102 if "WORKSPACE" not in os.environ:\r
103 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",\r
104 ExtraData="WORKSPACE")\r
105\r
106 WorkspaceDir = os.path.normcase(os.path.normpath(os.environ["WORKSPACE"]))\r
107 if not os.path.exists(WorkspaceDir):\r
108 EdkLogger.error("build", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData="%s" % WorkspaceDir)\r
109 elif ' ' in WorkspaceDir:\r
110 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path",\r
111 ExtraData=WorkspaceDir)\r
112 os.environ["WORKSPACE"] = WorkspaceDir\r
113 \r
114 # set multiple workspace\r
115 PackagesPath = os.getenv("PACKAGES_PATH")\r
116 mws.setWs(WorkspaceDir, PackagesPath)\r
117 if mws.PACKAGES_PATH:\r
118 for Path in mws.PACKAGES_PATH:\r
119 if not os.path.exists(Path):\r
120 EdkLogger.error("build", FILE_NOT_FOUND, "One Path in PACKAGES_PATH doesn't exist", ExtraData="%s" % Path)\r
121 elif ' ' in Path:\r
122 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in PACKAGES_PATH", ExtraData=Path)\r
123\r
124 #\r
125 # Check EFI_SOURCE (Edk build convention). EDK_SOURCE will always point to ECP\r
126 #\r
127 if "ECP_SOURCE" not in os.environ:\r
128 os.environ["ECP_SOURCE"] = mws.join(WorkspaceDir, GlobalData.gEdkCompatibilityPkg)\r
129 if "EFI_SOURCE" not in os.environ:\r
130 os.environ["EFI_SOURCE"] = os.environ["ECP_SOURCE"]\r
131 if "EDK_SOURCE" not in os.environ:\r
132 os.environ["EDK_SOURCE"] = os.environ["ECP_SOURCE"]\r
133\r
134 #\r
135 # Unify case of characters on case-insensitive systems\r
136 #\r
137 EfiSourceDir = os.path.normcase(os.path.normpath(os.environ["EFI_SOURCE"]))\r
138 EdkSourceDir = os.path.normcase(os.path.normpath(os.environ["EDK_SOURCE"]))\r
139 EcpSourceDir = os.path.normcase(os.path.normpath(os.environ["ECP_SOURCE"]))\r
140\r
141 os.environ["EFI_SOURCE"] = EfiSourceDir\r
142 os.environ["EDK_SOURCE"] = EdkSourceDir\r
143 os.environ["ECP_SOURCE"] = EcpSourceDir\r
144 os.environ["EDK_TOOLS_PATH"] = os.path.normcase(os.environ["EDK_TOOLS_PATH"])\r
145\r
146 if not os.path.exists(EcpSourceDir):\r
147 EdkLogger.verbose("ECP_SOURCE = %s doesn't exist. Edk modules could not be built." % EcpSourceDir)\r
148 elif ' ' in EcpSourceDir:\r
149 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in ECP_SOURCE path",\r
150 ExtraData=EcpSourceDir)\r
151 if not os.path.exists(EdkSourceDir):\r
152 if EdkSourceDir == EcpSourceDir:\r
153 EdkLogger.verbose("EDK_SOURCE = %s doesn't exist. Edk modules could not be built." % EdkSourceDir)\r
154 else:\r
155 EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE does not exist",\r
156 ExtraData=EdkSourceDir)\r
157 elif ' ' in EdkSourceDir:\r
158 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EDK_SOURCE path",\r
159 ExtraData=EdkSourceDir)\r
160 if not os.path.exists(EfiSourceDir):\r
161 if EfiSourceDir == EcpSourceDir:\r
162 EdkLogger.verbose("EFI_SOURCE = %s doesn't exist. Edk modules could not be built." % EfiSourceDir)\r
163 else:\r
164 EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE does not exist",\r
165 ExtraData=EfiSourceDir)\r
166 elif ' ' in EfiSourceDir:\r
167 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in EFI_SOURCE path",\r
168 ExtraData=EfiSourceDir)\r
169\r
170 # check those variables on single workspace case\r
171 if not PackagesPath:\r
172 # change absolute path to relative path to WORKSPACE\r
173 if EfiSourceDir.upper().find(WorkspaceDir.upper()) != 0:\r
174 EdkLogger.error("build", PARAMETER_INVALID, "EFI_SOURCE is not under WORKSPACE",\r
175 ExtraData="WORKSPACE = %s\n EFI_SOURCE = %s" % (WorkspaceDir, EfiSourceDir))\r
176 if EdkSourceDir.upper().find(WorkspaceDir.upper()) != 0:\r
177 EdkLogger.error("build", PARAMETER_INVALID, "EDK_SOURCE is not under WORKSPACE",\r
178 ExtraData="WORKSPACE = %s\n EDK_SOURCE = %s" % (WorkspaceDir, EdkSourceDir))\r
179 if EcpSourceDir.upper().find(WorkspaceDir.upper()) != 0:\r
180 EdkLogger.error("build", PARAMETER_INVALID, "ECP_SOURCE is not under WORKSPACE",\r
181 ExtraData="WORKSPACE = %s\n ECP_SOURCE = %s" % (WorkspaceDir, EcpSourceDir))\r
182\r
183 # check EDK_TOOLS_PATH\r
184 if "EDK_TOOLS_PATH" not in os.environ:\r
185 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",\r
186 ExtraData="EDK_TOOLS_PATH")\r
187\r
188 # check PATH\r
189 if "PATH" not in os.environ:\r
190 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",\r
191 ExtraData="PATH")\r
192\r
193 GlobalData.gWorkspace = WorkspaceDir\r
194 GlobalData.gEfiSource = EfiSourceDir\r
195 GlobalData.gEdkSource = EdkSourceDir\r
196 GlobalData.gEcpSource = EcpSourceDir\r
197\r
198 GlobalData.gGlobalDefines["WORKSPACE"] = WorkspaceDir\r
199 GlobalData.gGlobalDefines["EFI_SOURCE"] = EfiSourceDir\r
200 GlobalData.gGlobalDefines["EDK_SOURCE"] = EdkSourceDir\r
201 GlobalData.gGlobalDefines["ECP_SOURCE"] = EcpSourceDir\r
202 GlobalData.gGlobalDefines["EDK_TOOLS_PATH"] = os.environ["EDK_TOOLS_PATH"]\r
203 \r
204## Get normalized file path\r
205#\r
206# Convert the path to be local format, and remove the WORKSPACE path at the\r
207# beginning if the file path is given in full path.\r
208#\r
209# @param FilePath File path to be normalized\r
210# @param Workspace Workspace path which the FilePath will be checked against\r
211#\r
212# @retval string The normalized file path\r
213#\r
214def NormFile(FilePath, Workspace):\r
215 # check if the path is absolute or relative\r
216 if os.path.isabs(FilePath):\r
217 FileFullPath = os.path.normpath(FilePath)\r
218 else:\r
219 FileFullPath = os.path.normpath(mws.join(Workspace, FilePath))\r
220 Workspace = mws.getWs(Workspace, FilePath)\r
221\r
222 # check if the file path exists or not\r
223 if not os.path.isfile(FileFullPath):\r
224 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath)\r
225\r
226 # remove workspace directory from the beginning part of the file path\r
227 if Workspace[-1] in ["\\", "/"]:\r
228 return FileFullPath[len(Workspace):]\r
229 else:\r
230 return FileFullPath[(len(Workspace) + 1):]\r
231\r
232## Get the output of an external program\r
233#\r
234# This is the entrance method of thread reading output of an external program and\r
235# putting them in STDOUT/STDERR of current program.\r
236#\r
237# @param From The stream message read from\r
238# @param To The stream message put on\r
239# @param ExitFlag The flag used to indicate stopping reading\r
240#\r
241def ReadMessage(From, To, ExitFlag):\r
242 while True:\r
243 # read one line a time\r
244 Line = From.readline()\r
245 # empty string means "end"\r
246 if Line is not None and Line != "":\r
247 To(Line.rstrip())\r
248 else:\r
249 break\r
250 if ExitFlag.isSet():\r
251 break\r
252\r
253## Launch an external program\r
254#\r
255# This method will call subprocess.Popen to execute an external program with\r
256# given options in specified directory. Because of the dead-lock issue during\r
257# redirecting output of the external program, threads are used to to do the\r
258# redirection work.\r
259#\r
260# @param Command A list or string containing the call of the program\r
261# @param WorkingDir The directory in which the program will be running\r
262#\r
263def LaunchCommand(Command, WorkingDir):\r
264 BeginTime = time.time()\r
265 # if working directory doesn't exist, Popen() will raise an exception\r
266 if not os.path.isdir(WorkingDir):\r
267 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=WorkingDir)\r
268 \r
269 # Command is used as the first Argument in following Popen().\r
270 # It could be a string or sequence. We find that if command is a string in following Popen(),\r
271 # ubuntu may fail with an error message that the command is not found.\r
272 # So here we may need convert command from string to list instance.\r
273 if platform.system() != 'Windows':\r
274 if not isinstance(Command, list):\r
275 Command = Command.split()\r
276 Command = ' '.join(Command)\r
277\r
278 Proc = None\r
279 EndOfProcedure = None\r
280 try:\r
281 # launch the command\r
282 Proc = Popen(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir, bufsize=-1, shell=True)\r
283\r
284 # launch two threads to read the STDOUT and STDERR\r
285 EndOfProcedure = Event()\r
286 EndOfProcedure.clear()\r
287 if Proc.stdout:\r
288 StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure))\r
289 StdOutThread.setName("STDOUT-Redirector")\r
290 StdOutThread.setDaemon(False)\r
291 StdOutThread.start()\r
292\r
293 if Proc.stderr:\r
294 StdErrThread = Thread(target=ReadMessage, args=(Proc.stderr, EdkLogger.quiet, EndOfProcedure))\r
295 StdErrThread.setName("STDERR-Redirector")\r
296 StdErrThread.setDaemon(False)\r
297 StdErrThread.start()\r
298\r
299 # waiting for program exit\r
300 Proc.wait()\r
301 except: # in case of aborting\r
302 # terminate the threads redirecting the program output\r
303 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
304 if EndOfProcedure is not None:\r
305 EndOfProcedure.set()\r
306 if Proc is None:\r
307 if type(Command) != type(""):\r
308 Command = " ".join(Command)\r
309 EdkLogger.error("build", COMMAND_FAILURE, "Failed to start command", ExtraData="%s [%s]" % (Command, WorkingDir))\r
310\r
311 if Proc.stdout:\r
312 StdOutThread.join()\r
313 if Proc.stderr:\r
314 StdErrThread.join()\r
315\r
316 # check the return code of the program\r
317 if Proc.returncode != 0:\r
318 if type(Command) != type(""):\r
319 Command = " ".join(Command)\r
320 # print out the Response file and its content when make failure\r
321 RespFile = os.path.join(WorkingDir, 'OUTPUT', 'respfilelist.txt')\r
322 if os.path.isfile(RespFile):\r
323 f = open(RespFile)\r
324 RespContent = f.read()\r
325 f.close()\r
326 EdkLogger.info(RespContent)\r
327\r
328 EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir))\r
329 return "%dms" % (int(round((time.time() - BeginTime) * 1000)))\r
330\r
331## The smallest unit that can be built in multi-thread build mode\r
332#\r
333# This is the base class of build unit. The "Obj" parameter must provide\r
334# __str__(), __eq__() and __hash__() methods. Otherwise there could be build units\r
335# missing build.\r
336#\r
337# Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.\r
338#\r
339class BuildUnit:\r
340 ## The constructor\r
341 #\r
342 # @param self The object pointer\r
343 # @param Obj The object the build is working on\r
344 # @param Target The build target name, one of gSupportedTarget\r
345 # @param Dependency The BuildUnit(s) which must be completed in advance\r
346 # @param WorkingDir The directory build command starts in\r
347 #\r
348 def __init__(self, Obj, BuildCommand, Target, Dependency, WorkingDir="."):\r
349 self.BuildObject = Obj\r
350 self.Dependency = Dependency\r
351 self.WorkingDir = WorkingDir\r
352 self.Target = Target\r
353 self.BuildCommand = BuildCommand\r
354 if not BuildCommand:\r
355 EdkLogger.error("build", OPTION_MISSING,\r
356 "No build command found for this module. "\r
357 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
358 (Obj.BuildTarget, Obj.ToolChain, Obj.Arch),\r
359 ExtraData=str(Obj))\r
360\r
361\r
362 ## str() method\r
363 #\r
364 # It just returns the string representation of self.BuildObject\r
365 #\r
366 # @param self The object pointer\r
367 #\r
368 def __str__(self):\r
369 return str(self.BuildObject)\r
370\r
371 ## "==" operator method\r
372 #\r
373 # It just compares self.BuildObject with "Other". So self.BuildObject must\r
374 # provide its own __eq__() method.\r
375 #\r
376 # @param self The object pointer\r
377 # @param Other The other BuildUnit object compared to\r
378 #\r
379 def __eq__(self, Other):\r
380 return Other is not None and self.BuildObject == Other.BuildObject \\r
381 and self.BuildObject.Arch == Other.BuildObject.Arch\r
382\r
383 ## hash() method\r
384 #\r
385 # It just returns the hash value of self.BuildObject which must be hashable.\r
386 #\r
387 # @param self The object pointer\r
388 #\r
389 def __hash__(self):\r
390 return hash(self.BuildObject) + hash(self.BuildObject.Arch)\r
391\r
392 def __repr__(self):\r
393 return repr(self.BuildObject)\r
394\r
395## The smallest module unit that can be built by nmake/make command in multi-thread build mode\r
396#\r
397# This class is for module build by nmake/make build system. The "Obj" parameter\r
398# must provide __str__(), __eq__() and __hash__() methods. Otherwise there could\r
399# be make units missing build.\r
400#\r
401# Currently the "Obj" should be only ModuleAutoGen object.\r
402#\r
403class ModuleMakeUnit(BuildUnit):\r
404 ## The constructor\r
405 #\r
406 # @param self The object pointer\r
407 # @param Obj The ModuleAutoGen object the build is working on\r
408 # @param Target The build target name, one of gSupportedTarget\r
409 #\r
410 def __init__(self, Obj, Target):\r
411 Dependency = [ModuleMakeUnit(La, Target) for La in Obj.LibraryAutoGenList]\r
412 BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)\r
413 if Target in [None, "", "all"]:\r
414 self.Target = "tbuild"\r
415\r
416## The smallest platform unit that can be built by nmake/make command in multi-thread build mode\r
417#\r
418# This class is for platform build by nmake/make build system. The "Obj" parameter\r
419# must provide __str__(), __eq__() and __hash__() methods. Otherwise there could\r
420# be make units missing build.\r
421#\r
422# Currently the "Obj" should be only PlatformAutoGen object.\r
423#\r
424class PlatformMakeUnit(BuildUnit):\r
425 ## The constructor\r
426 #\r
427 # @param self The object pointer\r
428 # @param Obj The PlatformAutoGen object the build is working on\r
429 # @param Target The build target name, one of gSupportedTarget\r
430 #\r
431 def __init__(self, Obj, Target):\r
432 Dependency = [ModuleMakeUnit(Lib, Target) for Lib in self.BuildObject.LibraryAutoGenList]\r
433 Dependency.extend([ModuleMakeUnit(Mod, Target) for Mod in self.BuildObject.ModuleAutoGenList])\r
434 BuildUnit.__init__(self, Obj, Obj.BuildCommand, Target, Dependency, Obj.MakeFileDir)\r
435\r
436## The class representing the task of a module build or platform build\r
437#\r
438# This class manages the build tasks in multi-thread build mode. Its jobs include\r
439# scheduling thread running, catching thread error, monitor the thread status, etc.\r
440#\r
441class BuildTask:\r
442 # queue for tasks waiting for schedule\r
443 _PendingQueue = OrderedDict()\r
444 _PendingQueueLock = threading.Lock()\r
445\r
446 # queue for tasks ready for running\r
447 _ReadyQueue = OrderedDict()\r
448 _ReadyQueueLock = threading.Lock()\r
449\r
450 # queue for run tasks\r
451 _RunningQueue = OrderedDict()\r
452 _RunningQueueLock = threading.Lock()\r
453\r
454 # queue containing all build tasks, in case duplicate build\r
455 _TaskQueue = OrderedDict()\r
456\r
457 # flag indicating error occurs in a running thread\r
458 _ErrorFlag = threading.Event()\r
459 _ErrorFlag.clear()\r
460 _ErrorMessage = ""\r
461\r
462 # BoundedSemaphore object used to control the number of running threads\r
463 _Thread = None\r
464\r
465 # flag indicating if the scheduler is started or not\r
466 _SchedulerStopped = threading.Event()\r
467 _SchedulerStopped.set()\r
468\r
469 ## Start the task scheduler thread\r
470 #\r
471 # @param MaxThreadNumber The maximum thread number\r
472 # @param ExitFlag Flag used to end the scheduler\r
473 #\r
474 @staticmethod\r
475 def StartScheduler(MaxThreadNumber, ExitFlag):\r
476 SchedulerThread = Thread(target=BuildTask.Scheduler, args=(MaxThreadNumber, ExitFlag))\r
477 SchedulerThread.setName("Build-Task-Scheduler")\r
478 SchedulerThread.setDaemon(False)\r
479 SchedulerThread.start()\r
480 # wait for the scheduler to be started, especially useful in Linux\r
481 while not BuildTask.IsOnGoing():\r
482 time.sleep(0.01)\r
483\r
484 ## Scheduler method\r
485 #\r
486 # @param MaxThreadNumber The maximum thread number\r
487 # @param ExitFlag Flag used to end the scheduler\r
488 #\r
489 @staticmethod\r
490 def Scheduler(MaxThreadNumber, ExitFlag):\r
491 BuildTask._SchedulerStopped.clear()\r
492 try:\r
493 # use BoundedSemaphore to control the maximum running threads\r
494 BuildTask._Thread = BoundedSemaphore(MaxThreadNumber)\r
495 #\r
496 # scheduling loop, which will exits when no pending/ready task and\r
497 # indicated to do so, or there's error in running thread\r
498 #\r
499 while (len(BuildTask._PendingQueue) > 0 or len(BuildTask._ReadyQueue) > 0 \\r
500 or not ExitFlag.isSet()) and not BuildTask._ErrorFlag.isSet():\r
501 EdkLogger.debug(EdkLogger.DEBUG_8, "Pending Queue (%d), Ready Queue (%d)"\r
502 % (len(BuildTask._PendingQueue), len(BuildTask._ReadyQueue)))\r
503\r
504 # get all pending tasks\r
505 BuildTask._PendingQueueLock.acquire()\r
506 BuildObjectList = BuildTask._PendingQueue.keys()\r
507 #\r
508 # check if their dependency is resolved, and if true, move them\r
509 # into ready queue\r
510 #\r
511 for BuildObject in BuildObjectList:\r
512 Bt = BuildTask._PendingQueue[BuildObject]\r
513 if Bt.IsReady():\r
514 BuildTask._ReadyQueue[BuildObject] = BuildTask._PendingQueue.pop(BuildObject)\r
515 BuildTask._PendingQueueLock.release()\r
516\r
517 # launch build thread until the maximum number of threads is reached\r
518 while not BuildTask._ErrorFlag.isSet():\r
519 # empty ready queue, do nothing further\r
520 if len(BuildTask._ReadyQueue) == 0:\r
521 break\r
522\r
523 # wait for active thread(s) exit\r
524 BuildTask._Thread.acquire(True)\r
525\r
526 # start a new build thread\r
527 Bo = BuildTask._ReadyQueue.keys()[0]\r
528 Bt = BuildTask._ReadyQueue.pop(Bo)\r
529\r
530 # move into running queue\r
531 BuildTask._RunningQueueLock.acquire()\r
532 BuildTask._RunningQueue[Bo] = Bt\r
533 BuildTask._RunningQueueLock.release()\r
534\r
535 Bt.Start()\r
536 # avoid tense loop\r
537 time.sleep(0.01)\r
538\r
539 # avoid tense loop\r
540 time.sleep(0.01)\r
541\r
542 # wait for all running threads exit\r
543 if BuildTask._ErrorFlag.isSet():\r
544 EdkLogger.quiet("\nWaiting for all build threads exit...")\r
545 # while not BuildTask._ErrorFlag.isSet() and \\r
546 while len(BuildTask._RunningQueue) > 0:\r
547 EdkLogger.verbose("Waiting for thread ending...(%d)" % len(BuildTask._RunningQueue))\r
548 EdkLogger.debug(EdkLogger.DEBUG_8, "Threads [%s]" % ", ".join([Th.getName() for Th in threading.enumerate()]))\r
549 # avoid tense loop\r
550 time.sleep(0.1)\r
551 except BaseException, X:\r
552 #\r
553 # TRICK: hide the output of threads left runing, so that the user can\r
554 # catch the error message easily\r
555 #\r
556 EdkLogger.SetLevel(EdkLogger.ERROR)\r
557 BuildTask._ErrorFlag.set()\r
558 BuildTask._ErrorMessage = "build thread scheduler error\n\t%s" % str(X)\r
559\r
560 BuildTask._PendingQueue.clear()\r
561 BuildTask._ReadyQueue.clear()\r
562 BuildTask._RunningQueue.clear()\r
563 BuildTask._TaskQueue.clear()\r
564 BuildTask._SchedulerStopped.set()\r
565\r
566 ## Wait for all running method exit\r
567 #\r
568 @staticmethod\r
569 def WaitForComplete():\r
570 BuildTask._SchedulerStopped.wait()\r
571\r
572 ## Check if the scheduler is running or not\r
573 #\r
574 @staticmethod\r
575 def IsOnGoing():\r
576 return not BuildTask._SchedulerStopped.isSet()\r
577\r
578 ## Abort the build\r
579 @staticmethod\r
580 def Abort():\r
581 if BuildTask.IsOnGoing():\r
582 BuildTask._ErrorFlag.set()\r
583 BuildTask.WaitForComplete()\r
584\r
585 ## Check if there's error in running thread\r
586 #\r
587 # Since the main thread cannot catch exceptions in other thread, we have to\r
588 # use threading.Event to communicate this formation to main thread.\r
589 #\r
590 @staticmethod\r
591 def HasError():\r
592 return BuildTask._ErrorFlag.isSet()\r
593\r
594 ## Get error message in running thread\r
595 #\r
596 # Since the main thread cannot catch exceptions in other thread, we have to\r
597 # use a static variable to communicate this message to main thread.\r
598 #\r
599 @staticmethod\r
600 def GetErrorMessage():\r
601 return BuildTask._ErrorMessage\r
602\r
603 ## Factory method to create a BuildTask object\r
604 #\r
605 # This method will check if a module is building or has been built. And if\r
606 # true, just return the associated BuildTask object in the _TaskQueue. If\r
607 # not, create and return a new BuildTask object. The new BuildTask object\r
608 # will be appended to the _PendingQueue for scheduling later.\r
609 #\r
610 # @param BuildItem A BuildUnit object representing a build object\r
611 # @param Dependency The dependent build object of BuildItem\r
612 #\r
613 @staticmethod\r
614 def New(BuildItem, Dependency=None):\r
615 if BuildItem in BuildTask._TaskQueue:\r
616 Bt = BuildTask._TaskQueue[BuildItem]\r
617 return Bt\r
618\r
619 Bt = BuildTask()\r
620 Bt._Init(BuildItem, Dependency)\r
621 BuildTask._TaskQueue[BuildItem] = Bt\r
622\r
623 BuildTask._PendingQueueLock.acquire()\r
624 BuildTask._PendingQueue[BuildItem] = Bt\r
625 BuildTask._PendingQueueLock.release()\r
626\r
627 return Bt\r
628\r
629 ## The real constructor of BuildTask\r
630 #\r
631 # @param BuildItem A BuildUnit object representing a build object\r
632 # @param Dependency The dependent build object of BuildItem\r
633 #\r
634 def _Init(self, BuildItem, Dependency=None):\r
635 self.BuildItem = BuildItem\r
636\r
637 self.DependencyList = []\r
638 if Dependency is None:\r
639 Dependency = BuildItem.Dependency\r
640 else:\r
641 Dependency.extend(BuildItem.Dependency)\r
642 self.AddDependency(Dependency)\r
643 # flag indicating build completes, used to avoid unnecessary re-build\r
644 self.CompleteFlag = False\r
645\r
646 ## Check if all dependent build tasks are completed or not\r
647 #\r
648 def IsReady(self):\r
649 ReadyFlag = True\r
650 for Dep in self.DependencyList:\r
651 if Dep.CompleteFlag == True:\r
652 continue\r
653 ReadyFlag = False\r
654 break\r
655\r
656 return ReadyFlag\r
657\r
658 ## Add dependent build task\r
659 #\r
660 # @param Dependency The list of dependent build objects\r
661 #\r
662 def AddDependency(self, Dependency):\r
663 for Dep in Dependency:\r
664 if not Dep.BuildObject.IsBinaryModule:\r
665 self.DependencyList.append(BuildTask.New(Dep)) # BuildTask list\r
666\r
667 ## The thread wrapper of LaunchCommand function\r
668 #\r
669 # @param Command A list or string contains the call of the command\r
670 # @param WorkingDir The directory in which the program will be running\r
671 #\r
672 def _CommandThread(self, Command, WorkingDir):\r
673 try:\r
674 self.BuildItem.BuildObject.BuildTime = LaunchCommand(Command, WorkingDir)\r
675 self.CompleteFlag = True\r
676 except:\r
677 #\r
678 # TRICK: hide the output of threads left runing, so that the user can\r
679 # catch the error message easily\r
680 #\r
681 if not BuildTask._ErrorFlag.isSet():\r
682 GlobalData.gBuildingModule = "%s [%s, %s, %s]" % (str(self.BuildItem.BuildObject),\r
683 self.BuildItem.BuildObject.Arch,\r
684 self.BuildItem.BuildObject.ToolChain,\r
685 self.BuildItem.BuildObject.BuildTarget\r
686 )\r
687 EdkLogger.SetLevel(EdkLogger.ERROR)\r
688 BuildTask._ErrorFlag.set()\r
689 BuildTask._ErrorMessage = "%s broken\n %s [%s]" % \\r
690 (threading.currentThread().getName(), Command, WorkingDir)\r
691 # indicate there's a thread is available for another build task\r
692 BuildTask._RunningQueueLock.acquire()\r
693 BuildTask._RunningQueue.pop(self.BuildItem)\r
694 BuildTask._RunningQueueLock.release()\r
695 BuildTask._Thread.release()\r
696\r
697 ## Start build task thread\r
698 #\r
699 def Start(self):\r
700 EdkLogger.quiet("Building ... %s" % repr(self.BuildItem))\r
701 Command = self.BuildItem.BuildCommand + [self.BuildItem.Target]\r
702 self.BuildTread = Thread(target=self._CommandThread, args=(Command, self.BuildItem.WorkingDir))\r
703 self.BuildTread.setName("build thread")\r
704 self.BuildTread.setDaemon(False)\r
705 self.BuildTread.start()\r
706\r
707## The class contains the information related to EFI image\r
708#\r
709class PeImageInfo():\r
710 ## Constructor\r
711 #\r
712 # Constructor will load all required image information.\r
713 #\r
714 # @param BaseName The full file path of image.\r
715 # @param Guid The GUID for image.\r
716 # @param Arch Arch of this image.\r
717 # @param OutputDir The output directory for image.\r
718 # @param DebugDir The debug directory for image.\r
719 # @param ImageClass PeImage Information\r
720 #\r
721 def __init__(self, BaseName, Guid, Arch, OutputDir, DebugDir, ImageClass):\r
722 self.BaseName = BaseName\r
723 self.Guid = Guid\r
724 self.Arch = Arch\r
725 self.OutputDir = OutputDir\r
726 self.DebugDir = DebugDir\r
727 self.Image = ImageClass\r
728 self.Image.Size = (self.Image.Size / 0x1000 + 1) * 0x1000\r
729\r
730## The class implementing the EDK2 build process\r
731#\r
732# The build process includes:\r
733# 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf\r
734# 2. Parse DSC file of active platform\r
735# 3. Parse FDF file if any\r
736# 4. Establish build database, including parse all other files (module, package)\r
737# 5. Create AutoGen files (C code file, depex file, makefile) if necessary\r
738# 6. Call build command\r
739#\r
740class Build():\r
741 ## Constructor\r
742 #\r
743 # Constructor will load all necessary configurations, parse platform, modules\r
744 # and packages and the establish a database for AutoGen.\r
745 #\r
746 # @param Target The build command target, one of gSupportedTarget\r
747 # @param WorkspaceDir The directory of workspace\r
748 # @param BuildOptions Build options passed from command line\r
749 #\r
750 def __init__(self, Target, WorkspaceDir, BuildOptions):\r
751 self.WorkspaceDir = WorkspaceDir\r
752 self.Target = Target\r
753 self.PlatformFile = BuildOptions.PlatformFile\r
754 self.ModuleFile = BuildOptions.ModuleFile\r
755 self.ArchList = BuildOptions.TargetArch\r
756 self.ToolChainList = BuildOptions.ToolChain\r
757 self.BuildTargetList= BuildOptions.BuildTarget\r
758 self.Fdf = BuildOptions.FdfFile\r
759 self.FdList = BuildOptions.RomImage\r
760 self.FvList = BuildOptions.FvImage\r
761 self.CapList = BuildOptions.CapName\r
762 self.SilentMode = BuildOptions.SilentMode\r
763 self.ThreadNumber = BuildOptions.ThreadNumber\r
764 self.SkipAutoGen = BuildOptions.SkipAutoGen\r
765 self.Reparse = BuildOptions.Reparse\r
766 self.SkuId = BuildOptions.SkuId\r
767 if self.SkuId:\r
768 GlobalData.gSKUID_CMD = self.SkuId\r
769 self.ConfDirectory = BuildOptions.ConfDirectory\r
770 self.SpawnMode = True\r
771 self.BuildReport = BuildReport(BuildOptions.ReportFile, BuildOptions.ReportType)\r
772 self.TargetTxt = TargetTxtClassObject()\r
773 self.ToolDef = ToolDefClassObject()\r
774 self.AutoGenTime = 0\r
775 self.MakeTime = 0\r
776 self.GenFdsTime = 0\r
777 GlobalData.BuildOptionPcd = BuildOptions.OptionPcd if BuildOptions.OptionPcd else []\r
778 #Set global flag for build mode\r
779 GlobalData.gIgnoreSource = BuildOptions.IgnoreSources\r
780 GlobalData.gUseHashCache = BuildOptions.UseHashCache\r
781 GlobalData.gBinCacheDest = BuildOptions.BinCacheDest\r
782 GlobalData.gBinCacheSource = BuildOptions.BinCacheSource\r
783 GlobalData.gEnableGenfdsMultiThread = BuildOptions.GenfdsMultiThread\r
784\r
785 if GlobalData.gBinCacheDest and not GlobalData.gUseHashCache:\r
786 EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-destination must be used together with --hash.")\r
787\r
788 if GlobalData.gBinCacheSource and not GlobalData.gUseHashCache:\r
789 EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-source must be used together with --hash.")\r
790\r
791 if GlobalData.gBinCacheDest and GlobalData.gBinCacheSource:\r
792 EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-destination can not be used together with --binary-source.")\r
793\r
794 if GlobalData.gBinCacheSource:\r
795 BinCacheSource = os.path.normpath(GlobalData.gBinCacheSource)\r
796 if not os.path.isabs(BinCacheSource):\r
797 BinCacheSource = mws.join(self.WorkspaceDir, BinCacheSource)\r
798 GlobalData.gBinCacheSource = BinCacheSource\r
799 else:\r
800 if GlobalData.gBinCacheSource is not None:\r
801 EdkLogger.error("build", OPTION_VALUE_INVALID, ExtraData="Invalid value of option --binary-source.")\r
802\r
803 if GlobalData.gBinCacheDest:\r
804 BinCacheDest = os.path.normpath(GlobalData.gBinCacheDest)\r
805 if not os.path.isabs(BinCacheDest):\r
806 BinCacheDest = mws.join(self.WorkspaceDir, BinCacheDest)\r
807 GlobalData.gBinCacheDest = BinCacheDest\r
808 else:\r
809 if GlobalData.gBinCacheDest is not None:\r
810 EdkLogger.error("build", OPTION_VALUE_INVALID, ExtraData="Invalid value of option --binary-destination.")\r
811\r
812 if self.ConfDirectory:\r
813 # Get alternate Conf location, if it is absolute, then just use the absolute directory name\r
814 ConfDirectoryPath = os.path.normpath(self.ConfDirectory)\r
815\r
816 if not os.path.isabs(ConfDirectoryPath):\r
817 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE\r
818 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf\r
819 ConfDirectoryPath = mws.join(self.WorkspaceDir, ConfDirectoryPath)\r
820 else:\r
821 if "CONF_PATH" in os.environ:\r
822 ConfDirectoryPath = os.path.normcase(os.path.normpath(os.environ["CONF_PATH"]))\r
823 else:\r
824 # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf\r
825 ConfDirectoryPath = mws.join(self.WorkspaceDir, 'Conf')\r
826 GlobalData.gConfDirectory = ConfDirectoryPath\r
827 GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath))\r
828\r
829 if BuildOptions.DisableCache:\r
830 self.Db = WorkspaceDatabase(":memory:")\r
831 else:\r
832 self.Db = WorkspaceDatabase(GlobalData.gDatabasePath, self.Reparse)\r
833 self.BuildDatabase = self.Db.BuildObject\r
834 self.Platform = None\r
835 self.ToolChainFamily = None\r
836 self.LoadFixAddress = 0\r
837 self.UniFlag = BuildOptions.Flag\r
838 self.BuildModules = []\r
839 self.HashSkipModules = []\r
840 self.Db_Flag = False\r
841 self.LaunchPrebuildFlag = False\r
842 self.PlatformBuildPath = os.path.join(GlobalData.gConfDirectory,'.cache', '.PlatformBuild')\r
843 if BuildOptions.CommandLength:\r
844 GlobalData.gCommandMaxLength = BuildOptions.CommandLength\r
845\r
846 # print dot character during doing some time-consuming work\r
847 self.Progress = Utils.Progressor()\r
848 # print current build environment and configuration\r
849 EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))\r
850 if "PACKAGES_PATH" in os.environ:\r
851 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env. \r
852 EdkLogger.quiet("%-16s = %s" % ("PACKAGES_PATH", os.path.normcase(os.path.normpath(os.environ["PACKAGES_PATH"]))))\r
853 EdkLogger.quiet("%-16s = %s" % ("ECP_SOURCE", os.environ["ECP_SOURCE"]))\r
854 EdkLogger.quiet("%-16s = %s" % ("EDK_SOURCE", os.environ["EDK_SOURCE"]))\r
855 EdkLogger.quiet("%-16s = %s" % ("EFI_SOURCE", os.environ["EFI_SOURCE"]))\r
856 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))\r
857 if "EDK_TOOLS_BIN" in os.environ:\r
858 # Print the same path style with WORKSPACE env. \r
859 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os.path.normcase(os.path.normpath(os.environ["EDK_TOOLS_BIN"]))))\r
860 EdkLogger.quiet("%-16s = %s" % ("CONF_PATH", GlobalData.gConfDirectory))\r
861 self.InitPreBuild()\r
862 self.InitPostBuild()\r
863 if self.Prebuild:\r
864 EdkLogger.quiet("%-16s = %s" % ("PREBUILD", self.Prebuild))\r
865 if self.Postbuild:\r
866 EdkLogger.quiet("%-16s = %s" % ("POSTBUILD", self.Postbuild))\r
867 if self.Prebuild:\r
868 self.LaunchPrebuild()\r
869 self.TargetTxt = TargetTxtClassObject()\r
870 self.ToolDef = ToolDefClassObject()\r
871 if not (self.LaunchPrebuildFlag and os.path.exists(self.PlatformBuildPath)):\r
872 self.InitBuild()\r
873\r
874 EdkLogger.info("")\r
875 os.chdir(self.WorkspaceDir)\r
876\r
877 ## Load configuration\r
878 #\r
879 # This method will parse target.txt and get the build configurations.\r
880 #\r
881 def LoadConfiguration(self):\r
882 #\r
883 # Check target.txt and tools_def.txt and Init them\r
884 #\r
885 BuildConfigurationFile = os.path.normpath(os.path.join(GlobalData.gConfDirectory, gBuildConfiguration))\r
886 if os.path.isfile(BuildConfigurationFile) == True:\r
887 StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)\r
888\r
889 ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]\r
890 if ToolDefinitionFile == '':\r
891 ToolDefinitionFile = gToolsDefinition\r
892 ToolDefinitionFile = os.path.normpath(mws.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile))\r
893 if os.path.isfile(ToolDefinitionFile) == True:\r
894 StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)\r
895 else:\r
896 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)\r
897 else:\r
898 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)\r
899\r
900 # if no ARCH given in command line, get it from target.txt\r
901 if not self.ArchList:\r
902 self.ArchList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET_ARCH]\r
903 self.ArchList = tuple(self.ArchList)\r
904\r
905 # if no build target given in command line, get it from target.txt\r
906 if not self.BuildTargetList:\r
907 self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]\r
908\r
909 # if no tool chain given in command line, get it from target.txt\r
910 if not self.ToolChainList:\r
911 self.ToolChainList = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]\r
912 if self.ToolChainList is None or len(self.ToolChainList) == 0:\r
913 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")\r
914\r
915 # check if the tool chains are defined or not\r
916 NewToolChainList = []\r
917 for ToolChain in self.ToolChainList:\r
918 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:\r
919 EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)\r
920 else:\r
921 NewToolChainList.append(ToolChain)\r
922 # if no tool chain available, break the build\r
923 if len(NewToolChainList) == 0:\r
924 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
925 ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))\r
926 else:\r
927 self.ToolChainList = NewToolChainList\r
928\r
929 ToolChainFamily = []\r
930 ToolDefinition = self.ToolDef.ToolsDefTxtDatabase\r
931 for Tool in self.ToolChainList:\r
932 if TAB_TOD_DEFINES_FAMILY not in ToolDefinition or Tool not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \\r
933 or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool]:\r
934 EdkLogger.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool)\r
935 ToolChainFamily.append("MSFT")\r
936 else:\r
937 ToolChainFamily.append(ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool])\r
938 self.ToolChainFamily = ToolChainFamily\r
939\r
940 if self.ThreadNumber is None:\r
941 self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]\r
942 if self.ThreadNumber == '':\r
943 self.ThreadNumber = 0\r
944 else:\r
945 self.ThreadNumber = int(self.ThreadNumber, 0)\r
946\r
947 if self.ThreadNumber == 0:\r
948 try:\r
949 self.ThreadNumber = multiprocessing.cpu_count()\r
950 except (ImportError, NotImplementedError):\r
951 self.ThreadNumber = 1\r
952\r
953 if not self.PlatformFile:\r
954 PlatformFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM]\r
955 if not PlatformFile:\r
956 # Try to find one in current directory\r
957 WorkingDirectory = os.getcwd()\r
958 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))\r
959 FileNum = len(FileList)\r
960 if FileNum >= 2:\r
961 EdkLogger.error("build", OPTION_MISSING,\r
962 ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))\r
963 elif FileNum == 1:\r
964 PlatformFile = FileList[0]\r
965 else:\r
966 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
967 ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")\r
968\r
969 self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)\r
970\r
971 ## Initialize build configuration\r
972 #\r
973 # This method will parse DSC file and merge the configurations from\r
974 # command line and target.txt, then get the final build configurations.\r
975 #\r
976 def InitBuild(self):\r
977 # parse target.txt, tools_def.txt, and platform file\r
978 self.LoadConfiguration()\r
979\r
980 # Allow case-insensitive for those from command line or configuration file\r
981 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)\r
982 if ErrorCode != 0:\r
983 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
984\r
985 # create metafile database\r
986 if not self.Db_Flag:\r
987 self.Db.InitDatabase()\r
988\r
989 def InitPreBuild(self):\r
990 self.LoadConfiguration()\r
991 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)\r
992 if ErrorCode != 0:\r
993 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
994 if self.BuildTargetList:\r
995 GlobalData.gGlobalDefines['TARGET'] = self.BuildTargetList[0]\r
996 if self.ArchList:\r
997 GlobalData.gGlobalDefines['ARCH'] = self.ArchList[0]\r
998 if self.ToolChainList:\r
999 GlobalData.gGlobalDefines['TOOLCHAIN'] = self.ToolChainList[0]\r
1000 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = self.ToolChainList[0]\r
1001 if self.ToolChainFamily:\r
1002 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[0]\r
1003 if 'PREBUILD' in GlobalData.gCommandLineDefines.keys():\r
1004 self.Prebuild = GlobalData.gCommandLineDefines.get('PREBUILD')\r
1005 else:\r
1006 self.Db.InitDatabase()\r
1007 self.Db_Flag = True\r
1008 Platform = self.Db._MapPlatform(str(self.PlatformFile))\r
1009 self.Prebuild = str(Platform.Prebuild)\r
1010 if self.Prebuild:\r
1011 PrebuildList = []\r
1012 #\r
1013 # Evaluate all arguments and convert arguments that are WORKSPACE\r
1014 # relative paths to absolute paths. Filter arguments that look like\r
1015 # flags or do not follow the file/dir naming rules to avoid false\r
1016 # positives on this conversion.\r
1017 #\r
1018 for Arg in self.Prebuild.split():\r
1019 #\r
1020 # Do not modify Arg if it looks like a flag or an absolute file path\r
1021 #\r
1022 if Arg.startswith('-') or os.path.isabs(Arg):\r
1023 PrebuildList.append(Arg)\r
1024 continue\r
1025 #\r
1026 # Do not modify Arg if it does not look like a Workspace relative\r
1027 # path that starts with a valid package directory name\r
1028 #\r
1029 if not Arg[0].isalpha() or os.path.dirname(Arg) == '':\r
1030 PrebuildList.append(Arg)\r
1031 continue\r
1032 #\r
1033 # If Arg looks like a WORKSPACE relative path, then convert to an\r
1034 # absolute path and check to see if the file exists.\r
1035 #\r
1036 Temp = mws.join(self.WorkspaceDir, Arg)\r
1037 if os.path.isfile(Temp):\r
1038 Arg = Temp\r
1039 PrebuildList.append(Arg)\r
1040 self.Prebuild = ' '.join(PrebuildList)\r
1041 self.Prebuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)\r
1042\r
1043 def InitPostBuild(self):\r
1044 if 'POSTBUILD' in GlobalData.gCommandLineDefines.keys():\r
1045 self.Postbuild = GlobalData.gCommandLineDefines.get('POSTBUILD')\r
1046 else:\r
1047 Platform = self.Db._MapPlatform(str(self.PlatformFile))\r
1048 self.Postbuild = str(Platform.Postbuild)\r
1049 if self.Postbuild:\r
1050 PostbuildList = []\r
1051 #\r
1052 # Evaluate all arguments and convert arguments that are WORKSPACE\r
1053 # relative paths to absolute paths. Filter arguments that look like\r
1054 # flags or do not follow the file/dir naming rules to avoid false\r
1055 # positives on this conversion.\r
1056 #\r
1057 for Arg in self.Postbuild.split():\r
1058 #\r
1059 # Do not modify Arg if it looks like a flag or an absolute file path\r
1060 #\r
1061 if Arg.startswith('-') or os.path.isabs(Arg):\r
1062 PostbuildList.append(Arg)\r
1063 continue\r
1064 #\r
1065 # Do not modify Arg if it does not look like a Workspace relative\r
1066 # path that starts with a valid package directory name\r
1067 #\r
1068 if not Arg[0].isalpha() or os.path.dirname(Arg) == '':\r
1069 PostbuildList.append(Arg)\r
1070 continue\r
1071 #\r
1072 # If Arg looks like a WORKSPACE relative path, then convert to an\r
1073 # absolute path and check to see if the file exists.\r
1074 #\r
1075 Temp = mws.join(self.WorkspaceDir, Arg)\r
1076 if os.path.isfile(Temp):\r
1077 Arg = Temp\r
1078 PostbuildList.append(Arg)\r
1079 self.Postbuild = ' '.join(PostbuildList)\r
1080 self.Postbuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)\r
1081\r
1082 def PassCommandOption(self, BuildTarget, TargetArch, ToolChain, PlatformFile, Target):\r
1083 BuildStr = ''\r
1084 if GlobalData.gCommand and isinstance(GlobalData.gCommand, list):\r
1085 BuildStr += ' ' + ' '.join(GlobalData.gCommand)\r
1086 TargetFlag = False\r
1087 ArchFlag = False\r
1088 ToolChainFlag = False\r
1089 PlatformFileFlag = False\r
1090\r
1091 if GlobalData.gOptions and not GlobalData.gOptions.BuildTarget:\r
1092 TargetFlag = True\r
1093 if GlobalData.gOptions and not GlobalData.gOptions.TargetArch:\r
1094 ArchFlag = True\r
1095 if GlobalData.gOptions and not GlobalData.gOptions.ToolChain:\r
1096 ToolChainFlag = True\r
1097 if GlobalData.gOptions and not GlobalData.gOptions.PlatformFile:\r
1098 PlatformFileFlag = True\r
1099\r
1100 if TargetFlag and BuildTarget:\r
1101 if isinstance(BuildTarget, list) or isinstance(BuildTarget, tuple):\r
1102 BuildStr += ' -b ' + ' -b '.join(BuildTarget)\r
1103 elif isinstance(BuildTarget, str):\r
1104 BuildStr += ' -b ' + BuildTarget\r
1105 if ArchFlag and TargetArch:\r
1106 if isinstance(TargetArch, list) or isinstance(TargetArch, tuple):\r
1107 BuildStr += ' -a ' + ' -a '.join(TargetArch)\r
1108 elif isinstance(TargetArch, str):\r
1109 BuildStr += ' -a ' + TargetArch\r
1110 if ToolChainFlag and ToolChain:\r
1111 if isinstance(ToolChain, list) or isinstance(ToolChain, tuple):\r
1112 BuildStr += ' -t ' + ' -t '.join(ToolChain)\r
1113 elif isinstance(ToolChain, str):\r
1114 BuildStr += ' -t ' + ToolChain\r
1115 if PlatformFileFlag and PlatformFile:\r
1116 if isinstance(PlatformFile, list) or isinstance(PlatformFile, tuple):\r
1117 BuildStr += ' -p ' + ' -p '.join(PlatformFile)\r
1118 elif isinstance(PlatformFile, str):\r
1119 BuildStr += ' -p' + PlatformFile\r
1120 BuildStr += ' --conf=' + GlobalData.gConfDirectory\r
1121 if Target:\r
1122 BuildStr += ' ' + Target\r
1123\r
1124 return BuildStr\r
1125\r
1126 def LaunchPrebuild(self):\r
1127 if self.Prebuild:\r
1128 EdkLogger.info("\n- Prebuild Start -\n")\r
1129 self.LaunchPrebuildFlag = True\r
1130 #\r
1131 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script\r
1132 # and preserve them for the rest of the main build step, because the child process environment will\r
1133 # evaporate as soon as it exits, we cannot get it in build step.\r
1134 #\r
1135 PrebuildEnvFile = os.path.join(GlobalData.gConfDirectory,'.cache','.PrebuildEnv')\r
1136 if os.path.isfile(PrebuildEnvFile):\r
1137 os.remove(PrebuildEnvFile)\r
1138 if os.path.isfile(self.PlatformBuildPath):\r
1139 os.remove(self.PlatformBuildPath)\r
1140 if sys.platform == "win32":\r
1141 args = ' && '.join((self.Prebuild, 'set > ' + PrebuildEnvFile))\r
1142 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)\r
1143 else:\r
1144 args = ' && '.join((self.Prebuild, 'env > ' + PrebuildEnvFile))\r
1145 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)\r
1146\r
1147 # launch two threads to read the STDOUT and STDERR\r
1148 EndOfProcedure = Event()\r
1149 EndOfProcedure.clear()\r
1150 if Process.stdout:\r
1151 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))\r
1152 StdOutThread.setName("STDOUT-Redirector")\r
1153 StdOutThread.setDaemon(False)\r
1154 StdOutThread.start()\r
1155\r
1156 if Process.stderr:\r
1157 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))\r
1158 StdErrThread.setName("STDERR-Redirector")\r
1159 StdErrThread.setDaemon(False)\r
1160 StdErrThread.start()\r
1161 # waiting for program exit\r
1162 Process.wait()\r
1163\r
1164 if Process.stdout:\r
1165 StdOutThread.join()\r
1166 if Process.stderr:\r
1167 StdErrThread.join()\r
1168 if Process.returncode != 0 :\r
1169 EdkLogger.error("Prebuild", PREBUILD_ERROR, 'Prebuild process is not success!')\r
1170\r
1171 if os.path.exists(PrebuildEnvFile):\r
1172 f = open(PrebuildEnvFile)\r
1173 envs = f.readlines()\r
1174 f.close()\r
1175 envs = itertools.imap(lambda l: l.split('=',1), envs)\r
1176 envs = itertools.ifilter(lambda l: len(l) == 2, envs)\r
1177 envs = itertools.imap(lambda l: [i.strip() for i in l], envs)\r
1178 os.environ.update(dict(envs))\r
1179 EdkLogger.info("\n- Prebuild Done -\n")\r
1180\r
1181 def LaunchPostbuild(self):\r
1182 if self.Postbuild:\r
1183 EdkLogger.info("\n- Postbuild Start -\n")\r
1184 if sys.platform == "win32":\r
1185 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)\r
1186 else:\r
1187 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)\r
1188 # launch two threads to read the STDOUT and STDERR\r
1189 EndOfProcedure = Event()\r
1190 EndOfProcedure.clear()\r
1191 if Process.stdout:\r
1192 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))\r
1193 StdOutThread.setName("STDOUT-Redirector")\r
1194 StdOutThread.setDaemon(False)\r
1195 StdOutThread.start()\r
1196\r
1197 if Process.stderr:\r
1198 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))\r
1199 StdErrThread.setName("STDERR-Redirector")\r
1200 StdErrThread.setDaemon(False)\r
1201 StdErrThread.start()\r
1202 # waiting for program exit\r
1203 Process.wait()\r
1204\r
1205 if Process.stdout:\r
1206 StdOutThread.join()\r
1207 if Process.stderr:\r
1208 StdErrThread.join()\r
1209 if Process.returncode != 0 :\r
1210 EdkLogger.error("Postbuild", POSTBUILD_ERROR, 'Postbuild process is not success!')\r
1211 EdkLogger.info("\n- Postbuild Done -\n")\r
1212 ## Build a module or platform\r
1213 #\r
1214 # Create autogen code and makefile for a module or platform, and the launch\r
1215 # "make" command to build it\r
1216 #\r
1217 # @param Target The target of build command\r
1218 # @param Platform The platform file\r
1219 # @param Module The module file\r
1220 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
1221 # @param ToolChain The name of toolchain to build\r
1222 # @param Arch The arch of the module/platform\r
1223 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
1224 # for dependent modules/Libraries\r
1225 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
1226 # for dependent modules/Libraries\r
1227 #\r
1228 def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False, FfsCommand={}):\r
1229 if AutoGenObject is None:\r
1230 return False\r
1231\r
1232 # skip file generation for cleanxxx targets, run and fds target\r
1233 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1234 # for target which must generate AutoGen code and makefile\r
1235 if not self.SkipAutoGen or Target == 'genc':\r
1236 self.Progress.Start("Generating code")\r
1237 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
1238 self.Progress.Stop("done!")\r
1239 if Target == "genc":\r
1240 return True\r
1241\r
1242 if not self.SkipAutoGen or Target == 'genmake':\r
1243 self.Progress.Start("Generating makefile")\r
1244 AutoGenObject.CreateMakeFile(CreateDepsMakeFile, FfsCommand)\r
1245 self.Progress.Stop("done!")\r
1246 if Target == "genmake":\r
1247 return True\r
1248 else:\r
1249 # always recreate top/platform makefile when clean, just in case of inconsistency\r
1250 AutoGenObject.CreateCodeFile(False)\r
1251 AutoGenObject.CreateMakeFile(False)\r
1252\r
1253 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
1254 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
1255\r
1256 BuildCommand = AutoGenObject.BuildCommand\r
1257 if BuildCommand is None or len(BuildCommand) == 0:\r
1258 EdkLogger.error("build", OPTION_MISSING,\r
1259 "No build command found for this module. "\r
1260 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
1261 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
1262 ExtraData=str(AutoGenObject))\r
1263\r
1264 makefile = GenMake.BuildFile(AutoGenObject)._FILE_NAME_[GenMake.gMakeType]\r
1265\r
1266 # run\r
1267 if Target == 'run':\r
1268 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))\r
1269 Command = '.\SecMain'\r
1270 os.chdir(RunDir)\r
1271 LaunchCommand(Command, RunDir)\r
1272 return True\r
1273\r
1274 # build modules\r
1275 if BuildModule:\r
1276 BuildCommand = BuildCommand + [Target]\r
1277 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
1278 self.CreateAsBuiltInf()\r
1279 return True\r
1280\r
1281 # build library\r
1282 if Target == 'libraries':\r
1283 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1284 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']\r
1285 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1286 return True\r
1287\r
1288 # build module\r
1289 if Target == 'modules':\r
1290 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1291 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']\r
1292 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1293 for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
1294 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']\r
1295 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1296 self.CreateAsBuiltInf()\r
1297 return True\r
1298\r
1299 # cleanlib\r
1300 if Target == 'cleanlib':\r
1301 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1302 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))\r
1303 if os.path.exists(LibMakefile):\r
1304 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
1305 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1306 return True\r
1307\r
1308 # clean\r
1309 if Target == 'clean':\r
1310 for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
1311 ModMakefile = os.path.normpath(os.path.join(Mod, makefile))\r
1312 if os.path.exists(ModMakefile):\r
1313 NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']\r
1314 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1315 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1316 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))\r
1317 if os.path.exists(LibMakefile):\r
1318 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
1319 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1320 return True\r
1321\r
1322 # cleanall\r
1323 if Target == 'cleanall':\r
1324 try:\r
1325 #os.rmdir(AutoGenObject.BuildDir)\r
1326 RemoveDirectory(AutoGenObject.BuildDir, True)\r
1327 except WindowsError, X:\r
1328 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1329 return True\r
1330\r
1331 ## Build a module or platform\r
1332 #\r
1333 # Create autogen code and makefile for a module or platform, and the launch\r
1334 # "make" command to build it\r
1335 #\r
1336 # @param Target The target of build command\r
1337 # @param Platform The platform file\r
1338 # @param Module The module file\r
1339 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
1340 # @param ToolChain The name of toolchain to build\r
1341 # @param Arch The arch of the module/platform\r
1342 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
1343 # for dependent modules/Libraries\r
1344 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
1345 # for dependent modules/Libraries\r
1346 #\r
1347 def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):\r
1348 if AutoGenObject is None:\r
1349 return False\r
1350\r
1351 # skip file generation for cleanxxx targets, run and fds target\r
1352 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1353 # for target which must generate AutoGen code and makefile\r
1354 if not self.SkipAutoGen or Target == 'genc':\r
1355 self.Progress.Start("Generating code")\r
1356 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
1357 self.Progress.Stop("done!")\r
1358 if Target == "genc":\r
1359 return True\r
1360\r
1361 if not self.SkipAutoGen or Target == 'genmake':\r
1362 self.Progress.Start("Generating makefile")\r
1363 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)\r
1364 #AutoGenObject.CreateAsBuiltInf()\r
1365 self.Progress.Stop("done!")\r
1366 if Target == "genmake":\r
1367 return True\r
1368 else:\r
1369 # always recreate top/platform makefile when clean, just in case of inconsistency\r
1370 AutoGenObject.CreateCodeFile(False)\r
1371 AutoGenObject.CreateMakeFile(False)\r
1372\r
1373 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
1374 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
1375\r
1376 BuildCommand = AutoGenObject.BuildCommand\r
1377 if BuildCommand is None or len(BuildCommand) == 0:\r
1378 EdkLogger.error("build", OPTION_MISSING,\r
1379 "No build command found for this module. "\r
1380 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
1381 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
1382 ExtraData=str(AutoGenObject))\r
1383\r
1384 # build modules\r
1385 if BuildModule:\r
1386 if Target != 'fds':\r
1387 BuildCommand = BuildCommand + [Target]\r
1388 AutoGenObject.BuildTime = LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
1389 self.CreateAsBuiltInf()\r
1390 return True\r
1391\r
1392 # genfds\r
1393 if Target == 'fds':\r
1394 LaunchCommand(AutoGenObject.GenFdsCommand, AutoGenObject.MakeFileDir)\r
1395 return True\r
1396\r
1397 # run\r
1398 if Target == 'run':\r
1399 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))\r
1400 Command = '.\SecMain'\r
1401 os.chdir(RunDir)\r
1402 LaunchCommand(Command, RunDir)\r
1403 return True\r
1404\r
1405 # build library\r
1406 if Target == 'libraries':\r
1407 pass\r
1408\r
1409 # not build modules\r
1410\r
1411\r
1412 # cleanall\r
1413 if Target == 'cleanall':\r
1414 try:\r
1415 #os.rmdir(AutoGenObject.BuildDir)\r
1416 RemoveDirectory(AutoGenObject.BuildDir, True)\r
1417 except WindowsError, X:\r
1418 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1419 return True\r
1420\r
1421 ## Rebase module image and Get function address for the input module list.\r
1422 #\r
1423 def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):\r
1424 if ModeIsSmm:\r
1425 AddrIsOffset = False\r
1426 for InfFile in ModuleList:\r
1427 sys.stdout.write (".")\r
1428 sys.stdout.flush()\r
1429 ModuleInfo = ModuleList[InfFile]\r
1430 ModuleName = ModuleInfo.BaseName\r
1431 ModuleOutputImage = ModuleInfo.Image.FileName\r
1432 ModuleDebugImage = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')\r
1433 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1434 if not ModeIsSmm:\r
1435 BaseAddress = BaseAddress - ModuleInfo.Image.Size\r
1436 #\r
1437 # Update Image to new BaseAddress by GenFw tool\r
1438 #\r
1439 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
1440 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
1441 else:\r
1442 #\r
1443 # Set new address to the section header only for SMM driver.\r
1444 #\r
1445 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
1446 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
1447 #\r
1448 # Collect funtion address from Map file\r
1449 #\r
1450 ImageMapTable = ModuleOutputImage.replace('.efi', '.map')\r
1451 FunctionList = []\r
1452 if os.path.exists(ImageMapTable):\r
1453 OrigImageBaseAddress = 0\r
1454 ImageMap = open(ImageMapTable, 'r')\r
1455 for LinStr in ImageMap:\r
1456 if len (LinStr.strip()) == 0:\r
1457 continue\r
1458 #\r
1459 # Get the preferred address set on link time.\r
1460 #\r
1461 if LinStr.find ('Preferred load address is') != -1:\r
1462 StrList = LinStr.split()\r
1463 OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)\r
1464\r
1465 StrList = LinStr.split()\r
1466 if len (StrList) > 4:\r
1467 if StrList[3] == 'f' or StrList[3] == 'F':\r
1468 Name = StrList[1]\r
1469 RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress\r
1470 FunctionList.append ((Name, RelativeAddress))\r
1471 if ModuleInfo.Arch == 'IPF' and Name.endswith('_ModuleEntryPoint'):\r
1472 #\r
1473 # Get the real entry point address for IPF image.\r
1474 #\r
1475 ModuleInfo.Image.EntryPoint = RelativeAddress\r
1476 ImageMap.close()\r
1477 #\r
1478 # Add general information.\r
1479 #\r
1480 if ModeIsSmm:\r
1481 MapBuffer.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1482 elif AddrIsOffset:\r
1483 MapBuffer.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))\r
1484 else:\r
1485 MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1486 #\r
1487 # Add guid and general seciton section.\r
1488 #\r
1489 TextSectionAddress = 0\r
1490 DataSectionAddress = 0\r
1491 for SectionHeader in ModuleInfo.Image.SectionHeaderList:\r
1492 if SectionHeader[0] == '.text':\r
1493 TextSectionAddress = SectionHeader[1]\r
1494 elif SectionHeader[0] in ['.data', '.sdata']:\r
1495 DataSectionAddress = SectionHeader[1]\r
1496 if AddrIsOffset:\r
1497 MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))\r
1498 else:\r
1499 MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))\r
1500 #\r
1501 # Add debug image full path.\r
1502 #\r
1503 MapBuffer.write('(IMAGE=%s)\n\n' % (ModuleDebugImage))\r
1504 #\r
1505 # Add funtion address\r
1506 #\r
1507 for Function in FunctionList:\r
1508 if AddrIsOffset:\r
1509 MapBuffer.write(' -0x%010X %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))\r
1510 else:\r
1511 MapBuffer.write(' 0x%010X %s\n' % (BaseAddress + Function[1], Function[0]))\r
1512 ImageMap.close()\r
1513\r
1514 #\r
1515 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1516 #\r
1517 if ModeIsSmm:\r
1518 BaseAddress = BaseAddress + ModuleInfo.Image.Size\r
1519\r
1520 ## Collect MAP information of all FVs\r
1521 #\r
1522 def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):\r
1523 if self.Fdf:\r
1524 # First get the XIP base address for FV map file.\r
1525 GuidPattern = re.compile("[-a-fA-F0-9]+")\r
1526 GuidName = re.compile("\(GUID=[-a-fA-F0-9]+")\r
1527 for FvName in Wa.FdfProfile.FvDict.keys():\r
1528 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')\r
1529 if not os.path.exists(FvMapBuffer):\r
1530 continue\r
1531 FvMap = open(FvMapBuffer, 'r')\r
1532 #skip FV size information\r
1533 FvMap.readline()\r
1534 FvMap.readline()\r
1535 FvMap.readline()\r
1536 FvMap.readline()\r
1537 for Line in FvMap:\r
1538 MatchGuid = GuidPattern.match(Line)\r
1539 if MatchGuid is not None:\r
1540 #\r
1541 # Replace GUID with module name\r
1542 #\r
1543 GuidString = MatchGuid.group()\r
1544 if GuidString.upper() in ModuleList:\r
1545 Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)\r
1546 MapBuffer.write('%s' % (Line))\r
1547 #\r
1548 # Add the debug image full path.\r
1549 #\r
1550 MatchGuid = GuidName.match(Line)\r
1551 if MatchGuid is not None:\r
1552 GuidString = MatchGuid.group().split("=")[1]\r
1553 if GuidString.upper() in ModuleList:\r
1554 MapBuffer.write('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))\r
1555\r
1556 FvMap.close()\r
1557\r
1558 ## Collect MAP information of all modules\r
1559 #\r
1560 def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):\r
1561 sys.stdout.write ("Generate Load Module At Fix Address Map")\r
1562 sys.stdout.flush()\r
1563 PatchEfiImageList = []\r
1564 PeiModuleList = {}\r
1565 BtModuleList = {}\r
1566 RtModuleList = {}\r
1567 SmmModuleList = {}\r
1568 PeiSize = 0\r
1569 BtSize = 0\r
1570 RtSize = 0\r
1571 # reserve 4K size in SMRAM to make SMM module address not from 0.\r
1572 SmmSize = 0x1000\r
1573 IsIpfPlatform = False\r
1574 if 'IPF' in self.ArchList:\r
1575 IsIpfPlatform = True\r
1576 for ModuleGuid in ModuleList:\r
1577 Module = ModuleList[ModuleGuid]\r
1578 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)\r
1579\r
1580 OutputImageFile = ''\r
1581 for ResultFile in Module.CodaTargetList:\r
1582 if str(ResultFile.Target).endswith('.efi'):\r
1583 #\r
1584 # module list for PEI, DXE, RUNTIME and SMM\r
1585 #\r
1586 OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')\r
1587 ImageClass = PeImageClass (OutputImageFile)\r
1588 if not ImageClass.IsValid:\r
1589 EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)\r
1590 ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)\r
1591 if Module.ModuleType in ['PEI_CORE', 'PEIM', 'COMBINED_PEIM_DRIVER', 'PIC_PEIM', 'RELOCATABLE_PEIM', 'DXE_CORE']:\r
1592 PeiModuleList[Module.MetaFile] = ImageInfo\r
1593 PeiSize += ImageInfo.Image.Size\r
1594 elif Module.ModuleType in ['BS_DRIVER', 'DXE_DRIVER', 'UEFI_DRIVER']:\r
1595 BtModuleList[Module.MetaFile] = ImageInfo\r
1596 BtSize += ImageInfo.Image.Size\r
1597 elif Module.ModuleType in ['DXE_RUNTIME_DRIVER', 'RT_DRIVER', 'DXE_SAL_DRIVER', 'SAL_RT_DRIVER']:\r
1598 RtModuleList[Module.MetaFile] = ImageInfo\r
1599 #IPF runtime driver needs to be at 2 page alignment.\r
1600 if IsIpfPlatform and ImageInfo.Image.Size % 0x2000 != 0:\r
1601 ImageInfo.Image.Size = (ImageInfo.Image.Size / 0x2000 + 1) * 0x2000\r
1602 RtSize += ImageInfo.Image.Size\r
1603 elif Module.ModuleType in ['SMM_CORE', 'DXE_SMM_DRIVER', 'MM_STANDALONE', 'MM_CORE_STANDALONE']:\r
1604 SmmModuleList[Module.MetaFile] = ImageInfo\r
1605 SmmSize += ImageInfo.Image.Size\r
1606 if Module.ModuleType == 'DXE_SMM_DRIVER':\r
1607 PiSpecVersion = Module.Module.Specification.get('PI_SPECIFICATION_VERSION', '0x00000000')\r
1608 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.\r
1609 if int(PiSpecVersion, 16) < 0x0001000A:\r
1610 BtModuleList[Module.MetaFile] = ImageInfo\r
1611 BtSize += ImageInfo.Image.Size\r
1612 break\r
1613 #\r
1614 # EFI image is final target.\r
1615 # Check EFI image contains patchable FixAddress related PCDs.\r
1616 #\r
1617 if OutputImageFile != '':\r
1618 ModuleIsPatch = False\r
1619 for Pcd in Module.ModulePcdList:\r
1620 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:\r
1621 ModuleIsPatch = True\r
1622 break\r
1623 if not ModuleIsPatch:\r
1624 for Pcd in Module.LibraryPcdList:\r
1625 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_LIST:\r
1626 ModuleIsPatch = True\r
1627 break\r
1628\r
1629 if not ModuleIsPatch:\r
1630 continue\r
1631 #\r
1632 # Module includes the patchable load fix address PCDs.\r
1633 # It will be fixed up later.\r
1634 #\r
1635 PatchEfiImageList.append (OutputImageFile)\r
1636\r
1637 #\r
1638 # Get Top Memory address\r
1639 #\r
1640 ReservedRuntimeMemorySize = 0\r
1641 TopMemoryAddress = 0\r
1642 if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:\r
1643 TopMemoryAddress = 0\r
1644 else:\r
1645 TopMemoryAddress = self.LoadFixAddress\r
1646 if TopMemoryAddress < RtSize + BtSize + PeiSize:\r
1647 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")\r
1648 # Make IPF runtime driver at 2 page alignment.\r
1649 if IsIpfPlatform:\r
1650 ReservedRuntimeMemorySize = TopMemoryAddress % 0x2000\r
1651 RtSize = RtSize + ReservedRuntimeMemorySize\r
1652\r
1653 #\r
1654 # Patch FixAddress related PCDs into EFI image\r
1655 #\r
1656 for EfiImage in PatchEfiImageList:\r
1657 EfiImageMap = EfiImage.replace('.efi', '.map')\r
1658 if not os.path.exists(EfiImageMap):\r
1659 continue\r
1660 #\r
1661 # Get PCD offset in EFI image by GenPatchPcdTable function\r
1662 #\r
1663 PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)\r
1664 #\r
1665 # Patch real PCD value by PatchPcdValue tool\r
1666 #\r
1667 for PcdInfo in PcdTable:\r
1668 ReturnValue = 0\r
1669 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:\r
1670 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize / 0x1000))\r
1671 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:\r
1672 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize / 0x1000))\r
1673 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:\r
1674 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize / 0x1000))\r
1675 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:\r
1676 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize / 0x1000))\r
1677 if ReturnValue != 0:\r
1678 EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)\r
1679\r
1680 MapBuffer.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize / 0x1000))\r
1681 MapBuffer.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize / 0x1000))\r
1682 MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize / 0x1000))\r
1683 if len (SmmModuleList) > 0:\r
1684 MapBuffer.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize / 0x1000))\r
1685\r
1686 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize\r
1687 BtBaseAddr = TopMemoryAddress - RtSize\r
1688 RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize\r
1689\r
1690 self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)\r
1691 self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)\r
1692 self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)\r
1693 self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset=False, ModeIsSmm=True)\r
1694 MapBuffer.write('\n\n')\r
1695 sys.stdout.write ("\n")\r
1696 sys.stdout.flush()\r
1697\r
1698 ## Save platform Map file\r
1699 #\r
1700 def _SaveMapFile (self, MapBuffer, Wa):\r
1701 #\r
1702 # Map file path is got.\r
1703 #\r
1704 MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')\r
1705 #\r
1706 # Save address map into MAP file.\r
1707 #\r
1708 SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)\r
1709 MapBuffer.close()\r
1710 if self.LoadFixAddress != 0:\r
1711 sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath))\r
1712 sys.stdout.flush()\r
1713\r
1714 ## Build active platform for different build targets and different tool chains\r
1715 #\r
1716 def _BuildPlatform(self):\r
1717 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)\r
1718 for BuildTarget in self.BuildTargetList:\r
1719 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
1720 index = 0\r
1721 for ToolChain in self.ToolChainList:\r
1722 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
1723 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
1724 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1725 index += 1\r
1726 Wa = WorkspaceAutoGen(\r
1727 self.WorkspaceDir,\r
1728 self.PlatformFile,\r
1729 BuildTarget,\r
1730 ToolChain,\r
1731 self.ArchList,\r
1732 self.BuildDatabase,\r
1733 self.TargetTxt,\r
1734 self.ToolDef,\r
1735 self.Fdf,\r
1736 self.FdList,\r
1737 self.FvList,\r
1738 self.CapList,\r
1739 self.SkuId,\r
1740 self.UniFlag,\r
1741 self.Progress\r
1742 )\r
1743 self.Fdf = Wa.FdfFile\r
1744 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
1745 self.BuildReport.AddPlatformReport(Wa)\r
1746 self.Progress.Stop("done!")\r
1747\r
1748 # Add ffs build to makefile\r
1749 CmdListDict = {}\r
1750 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
1751 CmdListDict = self._GenFfsCmd()\r
1752\r
1753 for Arch in Wa.ArchList:\r
1754 GlobalData.gGlobalDefines['ARCH'] = Arch\r
1755 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
1756 for Module in Pa.Platform.Modules:\r
1757 # Get ModuleAutoGen object to generate C code file and makefile\r
1758 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1759 if Ma is None:\r
1760 continue\r
1761 self.BuildModules.append(Ma)\r
1762 self._BuildPa(self.Target, Pa, FfsCommand=CmdListDict)\r
1763\r
1764 # Create MAP file when Load Fix Address is enabled.\r
1765 if self.Target in ["", "all", "fds"]:\r
1766 for Arch in Wa.ArchList:\r
1767 GlobalData.gGlobalDefines['ARCH'] = Arch\r
1768 #\r
1769 # Check whether the set fix address is above 4G for 32bit image.\r
1770 #\r
1771 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1772 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
1773 #\r
1774 # Get Module List\r
1775 #\r
1776 ModuleList = {}\r
1777 for Pa in Wa.AutoGenObjectList:\r
1778 for Ma in Pa.ModuleAutoGenList:\r
1779 if Ma is None:\r
1780 continue\r
1781 if not Ma.IsLibrary:\r
1782 ModuleList[Ma.Guid.upper()] = Ma\r
1783\r
1784 MapBuffer = StringIO('')\r
1785 if self.LoadFixAddress != 0:\r
1786 #\r
1787 # Rebase module to the preferred memory address before GenFds\r
1788 #\r
1789 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
1790 if self.Fdf:\r
1791 #\r
1792 # create FDS again for the updated EFI image\r
1793 #\r
1794 self._Build("fds", Wa)\r
1795 #\r
1796 # Create MAP file for all platform FVs after GenFds.\r
1797 #\r
1798 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
1799 #\r
1800 # Save MAP buffer into MAP file.\r
1801 #\r
1802 self._SaveMapFile (MapBuffer, Wa)\r
1803\r
1804 ## Build active module for different build targets, different tool chains and different archs\r
1805 #\r
1806 def _BuildModule(self):\r
1807 for BuildTarget in self.BuildTargetList:\r
1808 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
1809 index = 0\r
1810 for ToolChain in self.ToolChainList:\r
1811 WorkspaceAutoGenTime = time.time()\r
1812 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
1813 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
1814 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1815 index += 1\r
1816 #\r
1817 # module build needs platform build information, so get platform\r
1818 # AutoGen first\r
1819 #\r
1820 Wa = WorkspaceAutoGen(\r
1821 self.WorkspaceDir,\r
1822 self.PlatformFile,\r
1823 BuildTarget,\r
1824 ToolChain,\r
1825 self.ArchList,\r
1826 self.BuildDatabase,\r
1827 self.TargetTxt,\r
1828 self.ToolDef,\r
1829 self.Fdf,\r
1830 self.FdList,\r
1831 self.FvList,\r
1832 self.CapList,\r
1833 self.SkuId,\r
1834 self.UniFlag,\r
1835 self.Progress,\r
1836 self.ModuleFile\r
1837 )\r
1838 self.Fdf = Wa.FdfFile\r
1839 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
1840 Wa.CreateMakeFile(False)\r
1841 # Add ffs build to makefile\r
1842 CmdListDict = None\r
1843 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
1844 CmdListDict = self._GenFfsCmd()\r
1845 self.Progress.Stop("done!")\r
1846 MaList = []\r
1847 ExitFlag = threading.Event()\r
1848 ExitFlag.clear()\r
1849 self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))\r
1850 for Arch in Wa.ArchList:\r
1851 AutoGenStart = time.time()\r
1852 GlobalData.gGlobalDefines['ARCH'] = Arch\r
1853 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
1854 for Module in Pa.Platform.Modules:\r
1855 if self.ModuleFile.Dir == Module.Dir and self.ModuleFile.Name == Module.Name:\r
1856 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
1857 if Ma is None: continue\r
1858 MaList.append(Ma)\r
1859 if Ma.CanSkipbyHash():\r
1860 self.HashSkipModules.append(Ma)\r
1861 continue\r
1862 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'\r
1863 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1864 # for target which must generate AutoGen code and makefile\r
1865 if not self.SkipAutoGen or self.Target == 'genc':\r
1866 self.Progress.Start("Generating code")\r
1867 Ma.CreateCodeFile(True)\r
1868 self.Progress.Stop("done!")\r
1869 if self.Target == "genc":\r
1870 return True\r
1871 if not self.SkipAutoGen or self.Target == 'genmake':\r
1872 self.Progress.Start("Generating makefile")\r
1873 if CmdListDict and self.Fdf and (Module.File, Arch) in CmdListDict:\r
1874 Ma.CreateMakeFile(True, CmdListDict[Module.File, Arch])\r
1875 del CmdListDict[Module.File, Arch]\r
1876 else:\r
1877 Ma.CreateMakeFile(True)\r
1878 self.Progress.Stop("done!")\r
1879 if self.Target == "genmake":\r
1880 return True\r
1881 self.BuildModules.append(Ma)\r
1882 self.AutoGenTime += int(round((time.time() - AutoGenStart)))\r
1883 MakeStart = time.time()\r
1884 for Ma in self.BuildModules:\r
1885 if not Ma.IsBinaryModule:\r
1886 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))\r
1887 # Break build if any build thread has error\r
1888 if BuildTask.HasError():\r
1889 # we need a full version of makefile for platform\r
1890 ExitFlag.set()\r
1891 BuildTask.WaitForComplete()\r
1892 Pa.CreateMakeFile(False)\r
1893 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1894 # Start task scheduler\r
1895 if not BuildTask.IsOnGoing():\r
1896 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
1897\r
1898 # in case there's an interruption. we need a full version of makefile for platform\r
1899 Pa.CreateMakeFile(False)\r
1900 if BuildTask.HasError():\r
1901 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1902 self.MakeTime += int(round((time.time() - MakeStart)))\r
1903\r
1904 MakeContiue = time.time()\r
1905 ExitFlag.set()\r
1906 BuildTask.WaitForComplete()\r
1907 self.CreateAsBuiltInf()\r
1908 self.MakeTime += int(round((time.time() - MakeContiue)))\r
1909 if BuildTask.HasError():\r
1910 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1911\r
1912 self.BuildReport.AddPlatformReport(Wa, MaList)\r
1913 if MaList == []:\r
1914 EdkLogger.error(\r
1915 'build',\r
1916 BUILD_ERROR,\r
1917 "Module for [%s] is not a component of active platform."\\r
1918 " Please make sure that the ARCH and inf file path are"\\r
1919 " given in the same as in [%s]" % \\r
1920 (', '.join(Wa.ArchList), self.PlatformFile),\r
1921 ExtraData=self.ModuleFile\r
1922 )\r
1923 # Create MAP file when Load Fix Address is enabled.\r
1924 if self.Target == "fds" and self.Fdf:\r
1925 for Arch in Wa.ArchList:\r
1926 #\r
1927 # Check whether the set fix address is above 4G for 32bit image.\r
1928 #\r
1929 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1930 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
1931 #\r
1932 # Get Module List\r
1933 #\r
1934 ModuleList = {}\r
1935 for Pa in Wa.AutoGenObjectList:\r
1936 for Ma in Pa.ModuleAutoGenList:\r
1937 if Ma is None:\r
1938 continue\r
1939 if not Ma.IsLibrary:\r
1940 ModuleList[Ma.Guid.upper()] = Ma\r
1941\r
1942 MapBuffer = StringIO('')\r
1943 if self.LoadFixAddress != 0:\r
1944 #\r
1945 # Rebase module to the preferred memory address before GenFds\r
1946 #\r
1947 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
1948 #\r
1949 # create FDS again for the updated EFI image\r
1950 #\r
1951 GenFdsStart = time.time()\r
1952 self._Build("fds", Wa)\r
1953 self.GenFdsTime += int(round((time.time() - GenFdsStart)))\r
1954 #\r
1955 # Create MAP file for all platform FVs after GenFds.\r
1956 #\r
1957 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
1958 #\r
1959 # Save MAP buffer into MAP file.\r
1960 #\r
1961 self._SaveMapFile (MapBuffer, Wa)\r
1962\r
1963 def _GenFfsCmd(self):\r
1964 CmdListDict = {}\r
1965 GenFfsDict = GenFds.GenFfsMakefile('', GlobalData.gFdfParser, self, self.ArchList, GlobalData)\r
1966 for Cmd in GenFfsDict:\r
1967 tmpInf, tmpArch = GenFfsDict[Cmd]\r
1968 if (tmpInf, tmpArch) not in CmdListDict.keys():\r
1969 CmdListDict[tmpInf, tmpArch] = [Cmd]\r
1970 else:\r
1971 CmdListDict[tmpInf, tmpArch].append(Cmd)\r
1972 return CmdListDict\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 >> toolsFile, ' '.join(guidedSectionTool)\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, 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, 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