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