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