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