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