]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/build/build.py
BaseTools/Common/Misc: Cleanup the imports
[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
29af38b0 5# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
370544d1 6# Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>\r
52302d4d 7#\r
40d841f6 8# This program and the accompanying materials\r
52302d4d
LG
9# are licensed and made available under the terms and conditions of the BSD License\r
10# which accompanies this distribution. The full text of the license may be found at\r
11# http://opensource.org/licenses/bsd-license.php\r
12#\r
13# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15#\r
16\r
17##\r
18# Import Modules\r
19#\r
1ccc4d89 20from __future__ import print_function\r
1be2ed90 21import Common.LongFilePathOs as os\r
52302d4d 22import re\r
1ccc4d89 23from io import BytesIO\r
52302d4d
LG
24import sys\r
25import glob\r
26import time\r
27import platform\r
28import traceback\r
4afd3d04 29import encodings.ascii\r
1ccc4d89 30import itertools\r
29af38b0 31import multiprocessing\r
52302d4d
LG
32\r
33from struct import *\r
34from threading import *\r
b2985672 35import threading\r
52302d4d
LG
36from optparse import OptionParser\r
37from subprocess import *\r
38from Common import Misc as Utils\r
39\r
1be2ed90 40from Common.LongFilePathSupport import OpenLongFilePath as open\r
938cf4c3
CJ
41from Common.TargetTxtClassObject import TargetTxtClassObject\r
42from Common.ToolDefClassObject import ToolDefClassObject\r
52302d4d 43from Common.DataType import *\r
b36d134f 44from Common.BuildVersion import gBUILD_VERSION\r
52302d4d
LG
45from AutoGen.AutoGen import *\r
46from Common.BuildToolError import *\r
2f818ed0 47from Workspace.WorkspaceDatabase import WorkspaceDatabase\r
05cc51ad 48from Common.MultipleWorkspace import MultipleWorkspace as mws\r
52302d4d
LG
49\r
50from BuildReport import BuildReport\r
51from GenPatchPcdTable.GenPatchPcdTable import *\r
52from PatchPcdValue.PatchPcdValue import *\r
53\r
54import Common.EdkLogger\r
55import Common.GlobalData as GlobalData\r
b3497bad 56from GenFds.GenFds import GenFds, GenFdsApi\r
52302d4d 57\r
ccaa7754 58from collections import OrderedDict, defaultdict\r
6e6d767e 59\r
52302d4d 60# Version and Copyright\r
4d10d18d 61VersionNumber = "0.60" + ' ' + gBUILD_VERSION\r
52302d4d 62__version__ = "%prog Version " + VersionNumber\r
f7496d71 63__copyright__ = "Copyright (c) 2007 - 2018, Intel Corporation All rights reserved."\r
52302d4d
LG
64\r
65## standard targets of build command\r
66gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']\r
67\r
68## build configuration file\r
97fa0ee9
YL
69gBuildConfiguration = "target.txt"\r
70gToolsDefinition = "tools_def.txt"\r
52302d4d 71\r
64b2609f
LG
72TemporaryTablePattern = re.compile(r'^_\d+_\d+_[a-fA-F0-9]+$')\r
73TmpTableDict = {}\r
74\r
b2985672
CJ
75## Make a Python object persistent on file system\r
76#\r
77# @param Data The object to be stored in file\r
78# @param File The path of file to store the object\r
79#\r
80def _DataDump(Data, File):\r
81 Fd = None\r
82 try:\r
83 Fd = open(File, 'wb')\r
84 pickle.dump(Data, Fd, pickle.HIGHEST_PROTOCOL)\r
85 except:\r
86 EdkLogger.error("", FILE_OPEN_FAILURE, ExtraData=File, RaiseError=False)\r
87 finally:\r
88 if Fd is not None:\r
89 Fd.close()\r
90\r
91## Restore a Python object from a file\r
92#\r
93# @param File The path of file stored the object\r
94#\r
95# @retval object A python object\r
96# @retval None If failure in file operation\r
97#\r
98def _DataRestore(File):\r
99 Data = None\r
100 Fd = None\r
101 try:\r
102 Fd = open(File, 'rb')\r
103 Data = pickle.load(Fd)\r
104 except Exception as e:\r
105 EdkLogger.verbose("Failed to load [%s]\n\t%s" % (File, str(e)))\r
106 Data = None\r
107 finally:\r
108 if Fd is not None:\r
109 Fd.close()\r
110 return Data\r
111\r
52302d4d
LG
112## Check environment PATH variable to make sure the specified tool is found\r
113#\r
114# If the tool is found in the PATH, then True is returned\r
115# Otherwise, False is returned\r
116#\r
117def IsToolInPath(tool):\r
27c4ceb4 118 if 'PATHEXT' in os.environ:\r
52302d4d
LG
119 extns = os.environ['PATHEXT'].split(os.path.pathsep)\r
120 else:\r
121 extns = ('',)\r
122 for pathDir in os.environ['PATH'].split(os.path.pathsep):\r
123 for ext in extns:\r
124 if os.path.exists(os.path.join(pathDir, tool + ext)):\r
125 return True\r
126 return False\r
127\r
128## Check environment variables\r
129#\r
130# Check environment variables that must be set for build. Currently they are\r
131#\r
132# WORKSPACE The directory all packages/platforms start from\r
133# EDK_TOOLS_PATH The directory contains all tools needed by the build\r
134# PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH\r
135#\r
136# If any of above environment variable is not set or has error, the build\r
137# will be broken.\r
138#\r
139def CheckEnvVariable():\r
140 # check WORKSPACE\r
141 if "WORKSPACE" not in os.environ:\r
142 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",\r
143 ExtraData="WORKSPACE")\r
144\r
145 WorkspaceDir = os.path.normcase(os.path.normpath(os.environ["WORKSPACE"]))\r
146 if not os.path.exists(WorkspaceDir):\r
caf74495 147 EdkLogger.error("build", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData=WorkspaceDir)\r
52302d4d
LG
148 elif ' ' in WorkspaceDir:\r
149 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path",\r
150 ExtraData=WorkspaceDir)\r
151 os.environ["WORKSPACE"] = WorkspaceDir\r
f7496d71 152\r
05cc51ad
LY
153 # set multiple workspace\r
154 PackagesPath = os.getenv("PACKAGES_PATH")\r
155 mws.setWs(WorkspaceDir, PackagesPath)\r
f6190a01
YZ
156 if mws.PACKAGES_PATH:\r
157 for Path in mws.PACKAGES_PATH:\r
158 if not os.path.exists(Path):\r
caf74495 159 EdkLogger.error("build", FILE_NOT_FOUND, "One Path in PACKAGES_PATH doesn't exist", ExtraData=Path)\r
f6190a01
YZ
160 elif ' ' in Path:\r
161 EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in PACKAGES_PATH", ExtraData=Path)\r
52302d4d 162\r
4afd3d04 163\r
52302d4d 164 os.environ["EDK_TOOLS_PATH"] = os.path.normcase(os.environ["EDK_TOOLS_PATH"])\r
4afd3d04 165\r
52302d4d
LG
166 # check EDK_TOOLS_PATH\r
167 if "EDK_TOOLS_PATH" not in os.environ:\r
168 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",\r
169 ExtraData="EDK_TOOLS_PATH")\r
170\r
171 # check PATH\r
172 if "PATH" not in os.environ:\r
173 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",\r
174 ExtraData="PATH")\r
175\r
176 GlobalData.gWorkspace = WorkspaceDir\r
52302d4d 177\r
0d2711a6 178 GlobalData.gGlobalDefines["WORKSPACE"] = WorkspaceDir\r
0d2711a6 179 GlobalData.gGlobalDefines["EDK_TOOLS_PATH"] = os.environ["EDK_TOOLS_PATH"]\r
f7496d71 180\r
52302d4d
LG
181## Get normalized file path\r
182#\r
183# Convert the path to be local format, and remove the WORKSPACE path at the\r
184# beginning if the file path is given in full path.\r
185#\r
186# @param FilePath File path to be normalized\r
187# @param Workspace Workspace path which the FilePath will be checked against\r
188#\r
189# @retval string The normalized file path\r
190#\r
191def NormFile(FilePath, Workspace):\r
192 # check if the path is absolute or relative\r
193 if os.path.isabs(FilePath):\r
194 FileFullPath = os.path.normpath(FilePath)\r
195 else:\r
05cc51ad
LY
196 FileFullPath = os.path.normpath(mws.join(Workspace, FilePath))\r
197 Workspace = mws.getWs(Workspace, FilePath)\r
52302d4d
LG
198\r
199 # check if the file path exists or not\r
200 if not os.path.isfile(FileFullPath):\r
47fea6af 201 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData="\t%s (Please give file in absolute path or relative to WORKSPACE)" % FileFullPath)\r
52302d4d
LG
202\r
203 # remove workspace directory from the beginning part of the file path\r
204 if Workspace[-1] in ["\\", "/"]:\r
205 return FileFullPath[len(Workspace):]\r
206 else:\r
207 return FileFullPath[(len(Workspace) + 1):]\r
208\r
209## Get the output of an external program\r
210#\r
211# This is the entrance method of thread reading output of an external program and\r
212# putting them in STDOUT/STDERR of current program.\r
213#\r
214# @param From The stream message read from\r
215# @param To The stream message put on\r
216# @param ExitFlag The flag used to indicate stopping reading\r
217#\r
218def ReadMessage(From, To, ExitFlag):\r
219 while True:\r
220 # read one line a time\r
221 Line = From.readline()\r
222 # empty string means "end"\r
1ccc4d89
LG
223 if Line is not None and Line != "":\r
224 To(Line.rstrip())\r
52302d4d
LG
225 else:\r
226 break\r
227 if ExitFlag.isSet():\r
228 break\r
229\r
230## Launch an external program\r
231#\r
232# This method will call subprocess.Popen to execute an external program with\r
233# given options in specified directory. Because of the dead-lock issue during\r
234# redirecting output of the external program, threads are used to to do the\r
235# redirection work.\r
236#\r
237# @param Command A list or string containing the call of the program\r
238# @param WorkingDir The directory in which the program will be running\r
239#\r
240def LaunchCommand(Command, WorkingDir):\r
1b8eca8b 241 BeginTime = time.time()\r
52302d4d
LG
242 # if working directory doesn't exist, Popen() will raise an exception\r
243 if not os.path.isdir(WorkingDir):\r
244 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=WorkingDir)\r
f7496d71 245\r
01ce3538
HC
246 # Command is used as the first Argument in following Popen().\r
247 # It could be a string or sequence. We find that if command is a string in following Popen(),\r
248 # ubuntu may fail with an error message that the command is not found.\r
249 # So here we may need convert command from string to list instance.\r
ed728046
HW
250 if platform.system() != 'Windows':\r
251 if not isinstance(Command, list):\r
df0cee8d 252 Command = Command.split()\r
ed728046 253 Command = ' '.join(Command)\r
df0cee8d 254\r
52302d4d
LG
255 Proc = None\r
256 EndOfProcedure = None\r
257 try:\r
258 # launch the command\r
71f5913e 259 Proc = Popen(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir, bufsize=-1, shell=True)\r
52302d4d
LG
260\r
261 # launch two threads to read the STDOUT and STDERR\r
262 EndOfProcedure = Event()\r
263 EndOfProcedure.clear()\r
264 if Proc.stdout:\r
265 StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure))\r
266 StdOutThread.setName("STDOUT-Redirector")\r
267 StdOutThread.setDaemon(False)\r
268 StdOutThread.start()\r
269\r
270 if Proc.stderr:\r
271 StdErrThread = Thread(target=ReadMessage, args=(Proc.stderr, EdkLogger.quiet, EndOfProcedure))\r
272 StdErrThread.setName("STDERR-Redirector")\r
273 StdErrThread.setDaemon(False)\r
274 StdErrThread.start()\r
275\r
276 # waiting for program exit\r
277 Proc.wait()\r
278 except: # in case of aborting\r
279 # terminate the threads redirecting the program output\r
790f60f2 280 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
4231a819 281 if EndOfProcedure is not None:\r
52302d4d 282 EndOfProcedure.set()\r
4231a819 283 if Proc is None:\r
0d1f5b2b 284 if not isinstance(Command, type("")):\r
52302d4d
LG
285 Command = " ".join(Command)\r
286 EdkLogger.error("build", COMMAND_FAILURE, "Failed to start command", ExtraData="%s [%s]" % (Command, WorkingDir))\r
287\r
288 if Proc.stdout:\r
289 StdOutThread.join()\r
290 if Proc.stderr:\r
291 StdErrThread.join()\r
292\r
293 # check the return code of the program\r
294 if Proc.returncode != 0:\r
0d1f5b2b 295 if not isinstance(Command, type("")):\r
52302d4d 296 Command = " ".join(Command)\r
725cdb8f
YZ
297 # print out the Response file and its content when make failure\r
298 RespFile = os.path.join(WorkingDir, 'OUTPUT', 'respfilelist.txt')\r
299 if os.path.isfile(RespFile):\r
300 f = open(RespFile)\r
301 RespContent = f.read()\r
302 f.close()\r
303 EdkLogger.info(RespContent)\r
304\r
52302d4d 305 EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir))\r
1b8eca8b 306 return "%dms" % (int(round((time.time() - BeginTime) * 1000)))\r
52302d4d
LG
307\r
308## The smallest unit that can be built in multi-thread build mode\r
309#\r
310# This is the base class of build unit. The "Obj" parameter must provide\r
311# __str__(), __eq__() and __hash__() methods. Otherwise there could be build units\r
312# missing build.\r
313#\r
314# Currently the "Obj" should be only ModuleAutoGen or PlatformAutoGen objects.\r
315#\r
316class BuildUnit:\r
317 ## The constructor\r
318 #\r
319 # @param self The object pointer\r
320 # @param Obj The object the build is working on\r
321 # @param Target The build target name, one of gSupportedTarget\r
322 # @param Dependency The BuildUnit(s) which must be completed in advance\r
323 # @param WorkingDir The directory build command starts in\r
324 #\r
325 def __init__(self, Obj, BuildCommand, Target, Dependency, WorkingDir="."):\r
326 self.BuildObject = Obj\r
327 self.Dependency = Dependency\r
328 self.WorkingDir = WorkingDir\r
329 self.Target = Target\r
330 self.BuildCommand = BuildCommand\r
0d2711a6
LG
331 if not BuildCommand:\r
332 EdkLogger.error("build", OPTION_MISSING,\r
333 "No build command found for this module. "\r
4afd3d04 334 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
0d2711a6 335 (Obj.BuildTarget, Obj.ToolChain, Obj.Arch),\r
52302d4d
LG
336 ExtraData=str(Obj))\r
337\r
0d2711a6 338\r
52302d4d
LG
339 ## str() method\r
340 #\r
08dd311f 341 # It just returns the string representation of self.BuildObject\r
52302d4d
LG
342 #\r
343 # @param self The object pointer\r
344 #\r
345 def __str__(self):\r
346 return str(self.BuildObject)\r
347\r
348 ## "==" operator method\r
349 #\r
350 # It just compares self.BuildObject with "Other". So self.BuildObject must\r
351 # provide its own __eq__() method.\r
352 #\r
353 # @param self The object pointer\r
354 # @param Other The other BuildUnit object compared to\r
355 #\r
356 def __eq__(self, Other):\r
b7b51025
CJ
357 return Other and self.BuildObject == Other.BuildObject \\r
358 and Other.BuildObject \\r
52302d4d
LG
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
6e6d767e 421 _PendingQueue = OrderedDict()\r
52302d4d
LG
422 _PendingQueueLock = threading.Lock()\r
423\r
424 # queue for tasks ready for running\r
6e6d767e 425 _ReadyQueue = OrderedDict()\r
52302d4d
LG
426 _ReadyQueueLock = threading.Lock()\r
427\r
428 # queue for run tasks\r
6e6d767e 429 _RunningQueue = OrderedDict()\r
52302d4d
LG
430 _RunningQueueLock = threading.Lock()\r
431\r
432 # queue containing all build tasks, in case duplicate build\r
6e6d767e 433 _TaskQueue = OrderedDict()\r
52302d4d
LG
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
1ccc4d89 484 BuildObjectList = BuildTask._PendingQueue.keys()\r
52302d4d
LG
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
ccaa7754 505 Bo, Bt = BuildTask._ReadyQueue.popitem()\r
52302d4d
LG
506\r
507 # move into running queue\r
508 BuildTask._RunningQueueLock.acquire()\r
509 BuildTask._RunningQueue[Bo] = Bt\r
510 BuildTask._RunningQueueLock.release()\r
511\r
512 Bt.Start()\r
513 # avoid tense loop\r
514 time.sleep(0.01)\r
515\r
516 # avoid tense loop\r
517 time.sleep(0.01)\r
518\r
519 # wait for all running threads exit\r
520 if BuildTask._ErrorFlag.isSet():\r
521 EdkLogger.quiet("\nWaiting for all build threads exit...")\r
522 # while not BuildTask._ErrorFlag.isSet() and \\r
523 while len(BuildTask._RunningQueue) > 0:\r
524 EdkLogger.verbose("Waiting for thread ending...(%d)" % len(BuildTask._RunningQueue))\r
8252e6bf 525 EdkLogger.debug(EdkLogger.DEBUG_8, "Threads [%s]" % ", ".join(Th.getName() for Th in threading.enumerate()))\r
52302d4d
LG
526 # avoid tense loop\r
527 time.sleep(0.1)\r
5b0671c1 528 except BaseException as X:\r
52302d4d
LG
529 #\r
530 # TRICK: hide the output of threads left runing, so that the user can\r
531 # catch the error message easily\r
532 #\r
533 EdkLogger.SetLevel(EdkLogger.ERROR)\r
534 BuildTask._ErrorFlag.set()\r
535 BuildTask._ErrorMessage = "build thread scheduler error\n\t%s" % str(X)\r
536\r
537 BuildTask._PendingQueue.clear()\r
538 BuildTask._ReadyQueue.clear()\r
539 BuildTask._RunningQueue.clear()\r
540 BuildTask._TaskQueue.clear()\r
541 BuildTask._SchedulerStopped.set()\r
542\r
543 ## Wait for all running method exit\r
544 #\r
545 @staticmethod\r
546 def WaitForComplete():\r
547 BuildTask._SchedulerStopped.wait()\r
548\r
549 ## Check if the scheduler is running or not\r
550 #\r
551 @staticmethod\r
552 def IsOnGoing():\r
553 return not BuildTask._SchedulerStopped.isSet()\r
554\r
555 ## Abort the build\r
556 @staticmethod\r
557 def Abort():\r
558 if BuildTask.IsOnGoing():\r
559 BuildTask._ErrorFlag.set()\r
560 BuildTask.WaitForComplete()\r
561\r
562 ## Check if there's error in running thread\r
563 #\r
564 # Since the main thread cannot catch exceptions in other thread, we have to\r
565 # use threading.Event to communicate this formation to main thread.\r
566 #\r
567 @staticmethod\r
568 def HasError():\r
569 return BuildTask._ErrorFlag.isSet()\r
570\r
571 ## Get error message in running thread\r
572 #\r
573 # Since the main thread cannot catch exceptions in other thread, we have to\r
574 # use a static variable to communicate this message to main thread.\r
575 #\r
576 @staticmethod\r
577 def GetErrorMessage():\r
578 return BuildTask._ErrorMessage\r
579\r
580 ## Factory method to create a BuildTask object\r
581 #\r
582 # This method will check if a module is building or has been built. And if\r
583 # true, just return the associated BuildTask object in the _TaskQueue. If\r
584 # not, create and return a new BuildTask object. The new BuildTask object\r
585 # will be appended to the _PendingQueue for scheduling later.\r
586 #\r
587 # @param BuildItem A BuildUnit object representing a build object\r
588 # @param Dependency The dependent build object of BuildItem\r
589 #\r
590 @staticmethod\r
591 def New(BuildItem, Dependency=None):\r
592 if BuildItem in BuildTask._TaskQueue:\r
593 Bt = BuildTask._TaskQueue[BuildItem]\r
594 return Bt\r
595\r
596 Bt = BuildTask()\r
597 Bt._Init(BuildItem, Dependency)\r
598 BuildTask._TaskQueue[BuildItem] = Bt\r
599\r
600 BuildTask._PendingQueueLock.acquire()\r
601 BuildTask._PendingQueue[BuildItem] = Bt\r
602 BuildTask._PendingQueueLock.release()\r
603\r
604 return Bt\r
605\r
606 ## The real constructor of BuildTask\r
607 #\r
608 # @param BuildItem A BuildUnit object representing a build object\r
609 # @param Dependency The dependent build object of BuildItem\r
610 #\r
611 def _Init(self, BuildItem, Dependency=None):\r
612 self.BuildItem = BuildItem\r
613\r
614 self.DependencyList = []\r
4231a819 615 if Dependency is None:\r
52302d4d
LG
616 Dependency = BuildItem.Dependency\r
617 else:\r
618 Dependency.extend(BuildItem.Dependency)\r
619 self.AddDependency(Dependency)\r
620 # flag indicating build completes, used to avoid unnecessary re-build\r
621 self.CompleteFlag = False\r
622\r
623 ## Check if all dependent build tasks are completed or not\r
624 #\r
625 def IsReady(self):\r
626 ReadyFlag = True\r
627 for Dep in self.DependencyList:\r
628 if Dep.CompleteFlag == True:\r
629 continue\r
630 ReadyFlag = False\r
631 break\r
632\r
633 return ReadyFlag\r
634\r
635 ## Add dependent build task\r
636 #\r
637 # @param Dependency The list of dependent build objects\r
638 #\r
639 def AddDependency(self, Dependency):\r
640 for Dep in Dependency:\r
97fa0ee9
YL
641 if not Dep.BuildObject.IsBinaryModule:\r
642 self.DependencyList.append(BuildTask.New(Dep)) # BuildTask list\r
52302d4d
LG
643\r
644 ## The thread wrapper of LaunchCommand function\r
645 #\r
646 # @param Command A list or string contains the call of the command\r
647 # @param WorkingDir The directory in which the program will be running\r
648 #\r
649 def _CommandThread(self, Command, WorkingDir):\r
650 try:\r
1b8eca8b 651 self.BuildItem.BuildObject.BuildTime = LaunchCommand(Command, WorkingDir)\r
52302d4d
LG
652 self.CompleteFlag = True\r
653 except:\r
654 #\r
655 # TRICK: hide the output of threads left runing, so that the user can\r
656 # catch the error message easily\r
657 #\r
658 if not BuildTask._ErrorFlag.isSet():\r
659 GlobalData.gBuildingModule = "%s [%s, %s, %s]" % (str(self.BuildItem.BuildObject),\r
660 self.BuildItem.BuildObject.Arch,\r
661 self.BuildItem.BuildObject.ToolChain,\r
662 self.BuildItem.BuildObject.BuildTarget\r
663 )\r
664 EdkLogger.SetLevel(EdkLogger.ERROR)\r
665 BuildTask._ErrorFlag.set()\r
666 BuildTask._ErrorMessage = "%s broken\n %s [%s]" % \\r
667 (threading.currentThread().getName(), Command, WorkingDir)\r
668 # indicate there's a thread is available for another build task\r
669 BuildTask._RunningQueueLock.acquire()\r
670 BuildTask._RunningQueue.pop(self.BuildItem)\r
671 BuildTask._RunningQueueLock.release()\r
672 BuildTask._Thread.release()\r
673\r
674 ## Start build task thread\r
675 #\r
676 def Start(self):\r
677 EdkLogger.quiet("Building ... %s" % repr(self.BuildItem))\r
678 Command = self.BuildItem.BuildCommand + [self.BuildItem.Target]\r
679 self.BuildTread = Thread(target=self._CommandThread, args=(Command, self.BuildItem.WorkingDir))\r
680 self.BuildTread.setName("build thread")\r
681 self.BuildTread.setDaemon(False)\r
682 self.BuildTread.start()\r
683\r
684## The class contains the information related to EFI image\r
685#\r
686class PeImageInfo():\r
687 ## Constructor\r
688 #\r
689 # Constructor will load all required image information.\r
690 #\r
4afd3d04 691 # @param BaseName The full file path of image.\r
52302d4d
LG
692 # @param Guid The GUID for image.\r
693 # @param Arch Arch of this image.\r
f3decdc3
LG
694 # @param OutputDir The output directory for image.\r
695 # @param DebugDir The debug directory for image.\r
52302d4d
LG
696 # @param ImageClass PeImage Information\r
697 #\r
f3decdc3 698 def __init__(self, BaseName, Guid, Arch, OutputDir, DebugDir, ImageClass):\r
52302d4d
LG
699 self.BaseName = BaseName\r
700 self.Guid = Guid\r
701 self.Arch = Arch\r
f3decdc3
LG
702 self.OutputDir = OutputDir\r
703 self.DebugDir = DebugDir\r
52302d4d 704 self.Image = ImageClass\r
1ccc4d89 705 self.Image.Size = (self.Image.Size / 0x1000 + 1) * 0x1000\r
52302d4d
LG
706\r
707## The class implementing the EDK2 build process\r
708#\r
709# The build process includes:\r
710# 1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf\r
711# 2. Parse DSC file of active platform\r
712# 3. Parse FDF file if any\r
713# 4. Establish build database, including parse all other files (module, package)\r
714# 5. Create AutoGen files (C code file, depex file, makefile) if necessary\r
715# 6. Call build command\r
716#\r
717class Build():\r
718 ## Constructor\r
719 #\r
720 # Constructor will load all necessary configurations, parse platform, modules\r
721 # and packages and the establish a database for AutoGen.\r
722 #\r
723 # @param Target The build command target, one of gSupportedTarget\r
724 # @param WorkspaceDir The directory of workspace\r
0d2711a6
LG
725 # @param BuildOptions Build options passed from command line\r
726 #\r
727 def __init__(self, Target, WorkspaceDir, BuildOptions):\r
728 self.WorkspaceDir = WorkspaceDir\r
52302d4d 729 self.Target = Target\r
0d2711a6
LG
730 self.PlatformFile = BuildOptions.PlatformFile\r
731 self.ModuleFile = BuildOptions.ModuleFile\r
732 self.ArchList = BuildOptions.TargetArch\r
733 self.ToolChainList = BuildOptions.ToolChain\r
734 self.BuildTargetList= BuildOptions.BuildTarget\r
735 self.Fdf = BuildOptions.FdfFile\r
736 self.FdList = BuildOptions.RomImage\r
737 self.FvList = BuildOptions.FvImage\r
738 self.CapList = BuildOptions.CapName\r
739 self.SilentMode = BuildOptions.SilentMode\r
740 self.ThreadNumber = BuildOptions.ThreadNumber\r
741 self.SkipAutoGen = BuildOptions.SkipAutoGen\r
742 self.Reparse = BuildOptions.Reparse\r
743 self.SkuId = BuildOptions.SkuId\r
e651d06c
LG
744 if self.SkuId:\r
745 GlobalData.gSKUID_CMD = self.SkuId\r
97fa0ee9 746 self.ConfDirectory = BuildOptions.ConfDirectory\r
52302d4d 747 self.SpawnMode = True\r
0d2711a6 748 self.BuildReport = BuildReport(BuildOptions.ReportFile, BuildOptions.ReportType)\r
52302d4d
LG
749 self.TargetTxt = TargetTxtClassObject()\r
750 self.ToolDef = ToolDefClassObject()\r
1b8eca8b
YZ
751 self.AutoGenTime = 0\r
752 self.MakeTime = 0\r
753 self.GenFdsTime = 0\r
b854e2bf 754 GlobalData.BuildOptionPcd = BuildOptions.OptionPcd if BuildOptions.OptionPcd else []\r
fae62ff2
HC
755 #Set global flag for build mode\r
756 GlobalData.gIgnoreSource = BuildOptions.IgnoreSources\r
36d083ef
YZ
757 GlobalData.gUseHashCache = BuildOptions.UseHashCache\r
758 GlobalData.gBinCacheDest = BuildOptions.BinCacheDest\r
759 GlobalData.gBinCacheSource = BuildOptions.BinCacheSource\r
37de70b7 760 GlobalData.gEnableGenfdsMultiThread = BuildOptions.GenfdsMultiThread\r
36d083ef
YZ
761\r
762 if GlobalData.gBinCacheDest and not GlobalData.gUseHashCache:\r
763 EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-destination must be used together with --hash.")\r
764\r
765 if GlobalData.gBinCacheSource and not GlobalData.gUseHashCache:\r
766 EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-source must be used together with --hash.")\r
767\r
768 if GlobalData.gBinCacheDest and GlobalData.gBinCacheSource:\r
769 EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-destination can not be used together with --binary-source.")\r
770\r
771 if GlobalData.gBinCacheSource:\r
772 BinCacheSource = os.path.normpath(GlobalData.gBinCacheSource)\r
773 if not os.path.isabs(BinCacheSource):\r
774 BinCacheSource = mws.join(self.WorkspaceDir, BinCacheSource)\r
775 GlobalData.gBinCacheSource = BinCacheSource\r
f21547ff 776 else:\r
4231a819 777 if GlobalData.gBinCacheSource is not None:\r
f21547ff 778 EdkLogger.error("build", OPTION_VALUE_INVALID, ExtraData="Invalid value of option --binary-source.")\r
36d083ef
YZ
779\r
780 if GlobalData.gBinCacheDest:\r
781 BinCacheDest = os.path.normpath(GlobalData.gBinCacheDest)\r
782 if not os.path.isabs(BinCacheDest):\r
783 BinCacheDest = mws.join(self.WorkspaceDir, BinCacheDest)\r
784 GlobalData.gBinCacheDest = BinCacheDest\r
f21547ff 785 else:\r
4231a819 786 if GlobalData.gBinCacheDest is not None:\r
f21547ff 787 EdkLogger.error("build", OPTION_VALUE_INVALID, ExtraData="Invalid value of option --binary-destination.")\r
97fa0ee9
YL
788\r
789 if self.ConfDirectory:\r
790 # Get alternate Conf location, if it is absolute, then just use the absolute directory name\r
791 ConfDirectoryPath = os.path.normpath(self.ConfDirectory)\r
792\r
793 if not os.path.isabs(ConfDirectoryPath):\r
794 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE\r
795 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf\r
05cc51ad 796 ConfDirectoryPath = mws.join(self.WorkspaceDir, ConfDirectoryPath)\r
97fa0ee9 797 else:\r
00bcb5c2
YZ
798 if "CONF_PATH" in os.environ:\r
799 ConfDirectoryPath = os.path.normcase(os.path.normpath(os.environ["CONF_PATH"]))\r
800 else:\r
801 # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf\r
802 ConfDirectoryPath = mws.join(self.WorkspaceDir, 'Conf')\r
97fa0ee9
YL
803 GlobalData.gConfDirectory = ConfDirectoryPath\r
804 GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath))\r
805\r
2f818ed0 806 self.Db = WorkspaceDatabase()\r
97fa0ee9
YL
807 self.BuildDatabase = self.Db.BuildObject\r
808 self.Platform = None\r
40b4e21d 809 self.ToolChainFamily = None\r
52302d4d 810 self.LoadFixAddress = 0\r
0d2711a6 811 self.UniFlag = BuildOptions.Flag\r
a0a2cd1e 812 self.BuildModules = []\r
83397f95 813 self.HashSkipModules = []\r
f0dc69e6
YZ
814 self.Db_Flag = False\r
815 self.LaunchPrebuildFlag = False\r
ccaa7754 816 self.PlatformBuildPath = os.path.join(GlobalData.gConfDirectory, '.cache', '.PlatformBuild')\r
725cdb8f
YZ
817 if BuildOptions.CommandLength:\r
818 GlobalData.gCommandMaxLength = BuildOptions.CommandLength\r
819\r
e56468c0 820 # print dot character during doing some time-consuming work\r
52302d4d 821 self.Progress = Utils.Progressor()\r
52302d4d 822 # print current build environment and configuration\r
0d2711a6 823 EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))\r
f25da33d 824 if "PACKAGES_PATH" in os.environ:\r
f7496d71 825 # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.\r
f25da33d 826 EdkLogger.quiet("%-16s = %s" % ("PACKAGES_PATH", os.path.normcase(os.path.normpath(os.environ["PACKAGES_PATH"]))))\r
0d2711a6 827 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))\r
f25da33d 828 if "EDK_TOOLS_BIN" in os.environ:\r
f7496d71 829 # Print the same path style with WORKSPACE env.\r
f25da33d 830 EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os.path.normcase(os.path.normpath(os.environ["EDK_TOOLS_BIN"]))))\r
00bcb5c2 831 EdkLogger.quiet("%-16s = %s" % ("CONF_PATH", GlobalData.gConfDirectory))\r
f0dc69e6
YZ
832 self.InitPreBuild()\r
833 self.InitPostBuild()\r
af9c4e5e
MK
834 if self.Prebuild:\r
835 EdkLogger.quiet("%-16s = %s" % ("PREBUILD", self.Prebuild))\r
836 if self.Postbuild:\r
837 EdkLogger.quiet("%-16s = %s" % ("POSTBUILD", self.Postbuild))\r
838 if self.Prebuild:\r
f0dc69e6 839 self.LaunchPrebuild()\r
a0c9ce31
YZ
840 self.TargetTxt = TargetTxtClassObject()\r
841 self.ToolDef = ToolDefClassObject()\r
f0dc69e6
YZ
842 if not (self.LaunchPrebuildFlag and os.path.exists(self.PlatformBuildPath)):\r
843 self.InitBuild()\r
52302d4d 844\r
f0dc69e6 845 EdkLogger.info("")\r
52302d4d 846 os.chdir(self.WorkspaceDir)\r
52302d4d
LG
847\r
848 ## Load configuration\r
849 #\r
850 # This method will parse target.txt and get the build configurations.\r
851 #\r
852 def LoadConfiguration(self):\r
853 #\r
854 # Check target.txt and tools_def.txt and Init them\r
855 #\r
97fa0ee9 856 BuildConfigurationFile = os.path.normpath(os.path.join(GlobalData.gConfDirectory, gBuildConfiguration))\r
52302d4d
LG
857 if os.path.isfile(BuildConfigurationFile) == True:\r
858 StatusCode = self.TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)\r
859\r
938cf4c3 860 ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TOOL_CHAIN_CONF]\r
52302d4d
LG
861 if ToolDefinitionFile == '':\r
862 ToolDefinitionFile = gToolsDefinition\r
05cc51ad 863 ToolDefinitionFile = os.path.normpath(mws.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile))\r
52302d4d
LG
864 if os.path.isfile(ToolDefinitionFile) == True:\r
865 StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)\r
866 else:\r
867 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=ToolDefinitionFile)\r
868 else:\r
869 EdkLogger.error("build", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)\r
870\r
871 # if no ARCH given in command line, get it from target.txt\r
0d2711a6 872 if not self.ArchList:\r
938cf4c3 873 self.ArchList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET_ARCH]\r
0d2711a6 874 self.ArchList = tuple(self.ArchList)\r
52302d4d
LG
875\r
876 # if no build target given in command line, get it from target.txt\r
0d2711a6 877 if not self.BuildTargetList:\r
938cf4c3 878 self.BuildTargetList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET]\r
52302d4d
LG
879\r
880 # if no tool chain given in command line, get it from target.txt\r
0d2711a6 881 if not self.ToolChainList:\r
938cf4c3 882 self.ToolChainList = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TOOL_CHAIN_TAG]\r
4231a819 883 if self.ToolChainList is None or len(self.ToolChainList) == 0:\r
52302d4d
LG
884 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.\n")\r
885\r
886 # check if the tool chains are defined or not\r
887 NewToolChainList = []\r
888 for ToolChain in self.ToolChainList:\r
889 if ToolChain not in self.ToolDef.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]:\r
890 EdkLogger.warn("build", "Tool chain [%s] is not defined" % ToolChain)\r
891 else:\r
892 NewToolChainList.append(ToolChain)\r
893 # if no tool chain available, break the build\r
894 if len(NewToolChainList) == 0:\r
895 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
896 ExtraData="[%s] not defined. No toolchain available for build!\n" % ", ".join(self.ToolChainList))\r
897 else:\r
898 self.ToolChainList = NewToolChainList\r
899\r
40b4e21d
YZ
900 ToolChainFamily = []\r
901 ToolDefinition = self.ToolDef.ToolsDefTxtDatabase\r
902 for Tool in self.ToolChainList:\r
903 if TAB_TOD_DEFINES_FAMILY not in ToolDefinition or Tool not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \\r
904 or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool]:\r
688c7d21 905 EdkLogger.warn("build", "No tool chain family found in configuration for %s. Default to MSFT." % Tool)\r
94c04559 906 ToolChainFamily.append(TAB_COMPILER_MSFT)\r
40b4e21d
YZ
907 else:\r
908 ToolChainFamily.append(ToolDefinition[TAB_TOD_DEFINES_FAMILY][Tool])\r
909 self.ToolChainFamily = ToolChainFamily\r
910\r
4231a819 911 if self.ThreadNumber is None:\r
938cf4c3 912 self.ThreadNumber = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]\r
52302d4d
LG
913 if self.ThreadNumber == '':\r
914 self.ThreadNumber = 0\r
915 else:\r
916 self.ThreadNumber = int(self.ThreadNumber, 0)\r
917\r
918 if self.ThreadNumber == 0:\r
29af38b0
YF
919 try:\r
920 self.ThreadNumber = multiprocessing.cpu_count()\r
921 except (ImportError, NotImplementedError):\r
922 self.ThreadNumber = 1\r
52302d4d
LG
923\r
924 if not self.PlatformFile:\r
938cf4c3 925 PlatformFile = self.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_ACTIVE_PLATFORM]\r
52302d4d
LG
926 if not PlatformFile:\r
927 # Try to find one in current directory\r
928 WorkingDirectory = os.getcwd()\r
929 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.dsc')))\r
930 FileNum = len(FileList)\r
931 if FileNum >= 2:\r
932 EdkLogger.error("build", OPTION_MISSING,\r
933 ExtraData="There are %d DSC files in %s. Use '-p' to specify one.\n" % (FileNum, WorkingDirectory))\r
934 elif FileNum == 1:\r
935 PlatformFile = FileList[0]\r
936 else:\r
937 EdkLogger.error("build", RESOURCE_NOT_AVAILABLE,\r
938 ExtraData="No active platform specified in target.txt or command line! Nothing can be built.\n")\r
939\r
940 self.PlatformFile = PathClass(NormFile(PlatformFile, self.WorkspaceDir), self.WorkspaceDir)\r
52302d4d
LG
941\r
942 ## Initialize build configuration\r
943 #\r
944 # This method will parse DSC file and merge the configurations from\r
945 # command line and target.txt, then get the final build configurations.\r
946 #\r
947 def InitBuild(self):\r
0d2711a6 948 # parse target.txt, tools_def.txt, and platform file\r
4afd3d04 949 self.LoadConfiguration()\r
0d2711a6
LG
950\r
951 # Allow case-insensitive for those from command line or configuration file\r
952 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)\r
52302d4d
LG
953 if ErrorCode != 0:\r
954 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
955\r
f0dc69e6
YZ
956\r
957 def InitPreBuild(self):\r
958 self.LoadConfiguration()\r
d429fcd0
YZ
959 ErrorCode, ErrorInfo = self.PlatformFile.Validate(".dsc", False)\r
960 if ErrorCode != 0:\r
961 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
f0dc69e6
YZ
962 if self.BuildTargetList:\r
963 GlobalData.gGlobalDefines['TARGET'] = self.BuildTargetList[0]\r
964 if self.ArchList:\r
965 GlobalData.gGlobalDefines['ARCH'] = self.ArchList[0]\r
966 if self.ToolChainList:\r
967 GlobalData.gGlobalDefines['TOOLCHAIN'] = self.ToolChainList[0]\r
968 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = self.ToolChainList[0]\r
40b4e21d
YZ
969 if self.ToolChainFamily:\r
970 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[0]\r
9eb87141 971 if 'PREBUILD' in GlobalData.gCommandLineDefines:\r
f0dc69e6
YZ
972 self.Prebuild = GlobalData.gCommandLineDefines.get('PREBUILD')\r
973 else:\r
f0dc69e6 974 self.Db_Flag = True\r
71cac3f7 975 Platform = self.Db.MapPlatform(str(self.PlatformFile))\r
f0dc69e6
YZ
976 self.Prebuild = str(Platform.Prebuild)\r
977 if self.Prebuild:\r
af9c4e5e
MK
978 PrebuildList = []\r
979 #\r
980 # Evaluate all arguments and convert arguments that are WORKSPACE\r
981 # relative paths to absolute paths. Filter arguments that look like\r
982 # flags or do not follow the file/dir naming rules to avoid false\r
983 # positives on this conversion.\r
984 #\r
985 for Arg in self.Prebuild.split():\r
986 #\r
987 # Do not modify Arg if it looks like a flag or an absolute file path\r
988 #\r
989 if Arg.startswith('-') or os.path.isabs(Arg):\r
990 PrebuildList.append(Arg)\r
991 continue\r
992 #\r
993 # Do not modify Arg if it does not look like a Workspace relative\r
994 # path that starts with a valid package directory name\r
995 #\r
996 if not Arg[0].isalpha() or os.path.dirname(Arg) == '':\r
997 PrebuildList.append(Arg)\r
998 continue\r
999 #\r
1000 # If Arg looks like a WORKSPACE relative path, then convert to an\r
1001 # absolute path and check to see if the file exists.\r
1002 #\r
1003 Temp = mws.join(self.WorkspaceDir, Arg)\r
1004 if os.path.isfile(Temp):\r
1005 Arg = Temp\r
1006 PrebuildList.append(Arg)\r
1007 self.Prebuild = ' '.join(PrebuildList)\r
1008 self.Prebuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)\r
52302d4d 1009\r
f0dc69e6 1010 def InitPostBuild(self):\r
9eb87141 1011 if 'POSTBUILD' in GlobalData.gCommandLineDefines:\r
f0dc69e6
YZ
1012 self.Postbuild = GlobalData.gCommandLineDefines.get('POSTBUILD')\r
1013 else:\r
71cac3f7 1014 Platform = self.Db.MapPlatform(str(self.PlatformFile))\r
f0dc69e6
YZ
1015 self.Postbuild = str(Platform.Postbuild)\r
1016 if self.Postbuild:\r
af9c4e5e
MK
1017 PostbuildList = []\r
1018 #\r
1019 # Evaluate all arguments and convert arguments that are WORKSPACE\r
1020 # relative paths to absolute paths. Filter arguments that look like\r
1021 # flags or do not follow the file/dir naming rules to avoid false\r
1022 # positives on this conversion.\r
1023 #\r
1024 for Arg in self.Postbuild.split():\r
1025 #\r
1026 # Do not modify Arg if it looks like a flag or an absolute file path\r
1027 #\r
1028 if Arg.startswith('-') or os.path.isabs(Arg):\r
1029 PostbuildList.append(Arg)\r
1030 continue\r
1031 #\r
1032 # Do not modify Arg if it does not look like a Workspace relative\r
1033 # path that starts with a valid package directory name\r
1034 #\r
1035 if not Arg[0].isalpha() or os.path.dirname(Arg) == '':\r
1036 PostbuildList.append(Arg)\r
1037 continue\r
1038 #\r
1039 # If Arg looks like a WORKSPACE relative path, then convert to an\r
1040 # absolute path and check to see if the file exists.\r
1041 #\r
1042 Temp = mws.join(self.WorkspaceDir, Arg)\r
1043 if os.path.isfile(Temp):\r
1044 Arg = Temp\r
1045 PostbuildList.append(Arg)\r
1046 self.Postbuild = ' '.join(PostbuildList)\r
1047 self.Postbuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList, self.PlatformFile, self.Target)\r
1048\r
1049 def PassCommandOption(self, BuildTarget, TargetArch, ToolChain, PlatformFile, Target):\r
f0dc69e6
YZ
1050 BuildStr = ''\r
1051 if GlobalData.gCommand and isinstance(GlobalData.gCommand, list):\r
1052 BuildStr += ' ' + ' '.join(GlobalData.gCommand)\r
1053 TargetFlag = False\r
1054 ArchFlag = False\r
1055 ToolChainFlag = False\r
af9c4e5e 1056 PlatformFileFlag = False\r
f0dc69e6
YZ
1057\r
1058 if GlobalData.gOptions and not GlobalData.gOptions.BuildTarget:\r
1059 TargetFlag = True\r
1060 if GlobalData.gOptions and not GlobalData.gOptions.TargetArch:\r
1061 ArchFlag = True\r
1062 if GlobalData.gOptions and not GlobalData.gOptions.ToolChain:\r
1063 ToolChainFlag = True\r
af9c4e5e
MK
1064 if GlobalData.gOptions and not GlobalData.gOptions.PlatformFile:\r
1065 PlatformFileFlag = True\r
f0dc69e6
YZ
1066\r
1067 if TargetFlag and BuildTarget:\r
1068 if isinstance(BuildTarget, list) or isinstance(BuildTarget, tuple):\r
1069 BuildStr += ' -b ' + ' -b '.join(BuildTarget)\r
1070 elif isinstance(BuildTarget, str):\r
1071 BuildStr += ' -b ' + BuildTarget\r
1072 if ArchFlag and TargetArch:\r
1073 if isinstance(TargetArch, list) or isinstance(TargetArch, tuple):\r
1074 BuildStr += ' -a ' + ' -a '.join(TargetArch)\r
1075 elif isinstance(TargetArch, str):\r
1076 BuildStr += ' -a ' + TargetArch\r
1077 if ToolChainFlag and ToolChain:\r
1078 if isinstance(ToolChain, list) or isinstance(ToolChain, tuple):\r
1079 BuildStr += ' -t ' + ' -t '.join(ToolChain)\r
1080 elif isinstance(ToolChain, str):\r
1081 BuildStr += ' -t ' + ToolChain\r
af9c4e5e
MK
1082 if PlatformFileFlag and PlatformFile:\r
1083 if isinstance(PlatformFile, list) or isinstance(PlatformFile, tuple):\r
1084 BuildStr += ' -p ' + ' -p '.join(PlatformFile)\r
1085 elif isinstance(PlatformFile, str):\r
1086 BuildStr += ' -p' + PlatformFile\r
1087 BuildStr += ' --conf=' + GlobalData.gConfDirectory\r
1088 if Target:\r
1089 BuildStr += ' ' + Target\r
f0dc69e6
YZ
1090\r
1091 return BuildStr\r
1092\r
1093 def LaunchPrebuild(self):\r
1094 if self.Prebuild:\r
1095 EdkLogger.info("\n- Prebuild Start -\n")\r
1096 self.LaunchPrebuildFlag = True\r
134bbe88
YZ
1097 #\r
1098 # The purpose of .PrebuildEnv file is capture environment variable settings set by the prebuild script\r
1099 # and preserve them for the rest of the main build step, because the child process environment will\r
1100 # evaporate as soon as it exits, we cannot get it in build step.\r
1101 #\r
ccaa7754 1102 PrebuildEnvFile = os.path.join(GlobalData.gConfDirectory, '.cache', '.PrebuildEnv')\r
f0dc69e6
YZ
1103 if os.path.isfile(PrebuildEnvFile):\r
1104 os.remove(PrebuildEnvFile)\r
1105 if os.path.isfile(self.PlatformBuildPath):\r
1106 os.remove(self.PlatformBuildPath)\r
1107 if sys.platform == "win32":\r
1108 args = ' && '.join((self.Prebuild, 'set > ' + PrebuildEnvFile))\r
b926f2f2 1109 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)\r
f0dc69e6
YZ
1110 else:\r
1111 args = ' && '.join((self.Prebuild, 'env > ' + PrebuildEnvFile))\r
34816e7e 1112 Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True)\r
f0dc69e6
YZ
1113\r
1114 # launch two threads to read the STDOUT and STDERR\r
1115 EndOfProcedure = Event()\r
1116 EndOfProcedure.clear()\r
1117 if Process.stdout:\r
1118 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))\r
1119 StdOutThread.setName("STDOUT-Redirector")\r
1120 StdOutThread.setDaemon(False)\r
1121 StdOutThread.start()\r
1122\r
1123 if Process.stderr:\r
1124 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))\r
1125 StdErrThread.setName("STDERR-Redirector")\r
1126 StdErrThread.setDaemon(False)\r
1127 StdErrThread.start()\r
1128 # waiting for program exit\r
1129 Process.wait()\r
1130\r
1131 if Process.stdout:\r
1132 StdOutThread.join()\r
1133 if Process.stderr:\r
1134 StdErrThread.join()\r
1135 if Process.returncode != 0 :\r
1136 EdkLogger.error("Prebuild", PREBUILD_ERROR, 'Prebuild process is not success!')\r
1137\r
1138 if os.path.exists(PrebuildEnvFile):\r
1139 f = open(PrebuildEnvFile)\r
1140 envs = f.readlines()\r
1141 f.close()\r
1ccc4d89
LG
1142 envs = itertools.imap(lambda l: l.split('=', 1), envs)\r
1143 envs = itertools.ifilter(lambda l: len(l) == 2, envs)\r
1144 envs = itertools.imap(lambda l: [i.strip() for i in l], envs)\r
f0dc69e6
YZ
1145 os.environ.update(dict(envs))\r
1146 EdkLogger.info("\n- Prebuild Done -\n")\r
1147\r
91048b0d 1148 def LaunchPostbuild(self):\r
f0dc69e6
YZ
1149 if self.Postbuild:\r
1150 EdkLogger.info("\n- Postbuild Start -\n")\r
1151 if sys.platform == "win32":\r
b926f2f2 1152 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)\r
f0dc69e6 1153 else:\r
34816e7e 1154 Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True)\r
f0dc69e6
YZ
1155 # launch two threads to read the STDOUT and STDERR\r
1156 EndOfProcedure = Event()\r
1157 EndOfProcedure.clear()\r
1158 if Process.stdout:\r
1159 StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure))\r
1160 StdOutThread.setName("STDOUT-Redirector")\r
1161 StdOutThread.setDaemon(False)\r
1162 StdOutThread.start()\r
1163\r
1164 if Process.stderr:\r
1165 StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure))\r
1166 StdErrThread.setName("STDERR-Redirector")\r
1167 StdErrThread.setDaemon(False)\r
1168 StdErrThread.start()\r
1169 # waiting for program exit\r
1170 Process.wait()\r
1171\r
1172 if Process.stdout:\r
1173 StdOutThread.join()\r
1174 if Process.stderr:\r
1175 StdErrThread.join()\r
1176 if Process.returncode != 0 :\r
1177 EdkLogger.error("Postbuild", POSTBUILD_ERROR, 'Postbuild process is not success!')\r
1178 EdkLogger.info("\n- Postbuild Done -\n")\r
52302d4d
LG
1179 ## Build a module or platform\r
1180 #\r
08dd311f 1181 # Create autogen code and makefile for a module or platform, and the launch\r
52302d4d
LG
1182 # "make" command to build it\r
1183 #\r
1184 # @param Target The target of build command\r
1185 # @param Platform The platform file\r
1186 # @param Module The module file\r
1187 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
1188 # @param ToolChain The name of toolchain to build\r
1189 # @param Arch The arch of the module/platform\r
1190 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
1191 # for dependent modules/Libraries\r
1192 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
1193 # for dependent modules/Libraries\r
1194 #\r
37de70b7 1195 def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False, FfsCommand={}):\r
4231a819 1196 if AutoGenObject is None:\r
52302d4d
LG
1197 return False\r
1198\r
1199 # skip file generation for cleanxxx targets, run and fds target\r
1200 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1201 # for target which must generate AutoGen code and makefile\r
1202 if not self.SkipAutoGen or Target == 'genc':\r
1203 self.Progress.Start("Generating code")\r
1204 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
1205 self.Progress.Stop("done!")\r
1206 if Target == "genc":\r
1207 return True\r
1208\r
1209 if not self.SkipAutoGen or Target == 'genmake':\r
1210 self.Progress.Start("Generating makefile")\r
37de70b7 1211 AutoGenObject.CreateMakeFile(CreateDepsMakeFile, FfsCommand)\r
52302d4d
LG
1212 self.Progress.Stop("done!")\r
1213 if Target == "genmake":\r
1214 return True\r
1215 else:\r
1216 # always recreate top/platform makefile when clean, just in case of inconsistency\r
1217 AutoGenObject.CreateCodeFile(False)\r
1218 AutoGenObject.CreateMakeFile(False)\r
1219\r
1220 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
1221 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
1222\r
1223 BuildCommand = AutoGenObject.BuildCommand\r
4231a819 1224 if BuildCommand is None or len(BuildCommand) == 0:\r
0d2711a6
LG
1225 EdkLogger.error("build", OPTION_MISSING,\r
1226 "No build command found for this module. "\r
4afd3d04 1227 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
0d2711a6
LG
1228 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
1229 ExtraData=str(AutoGenObject))\r
52302d4d 1230\r
03af2753
HC
1231 makefile = GenMake.BuildFile(AutoGenObject)._FILE_NAME_[GenMake.gMakeType]\r
1232\r
03af2753
HC
1233 # run\r
1234 if Target == 'run':\r
997a5d1b 1235 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))\r
03af2753
HC
1236 Command = '.\SecMain'\r
1237 os.chdir(RunDir)\r
1238 LaunchCommand(Command, RunDir)\r
1239 return True\r
1240\r
1241 # build modules\r
1242 if BuildModule:\r
1243 BuildCommand = BuildCommand + [Target]\r
1244 LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
a0a2cd1e 1245 self.CreateAsBuiltInf()\r
03af2753
HC
1246 return True\r
1247\r
1248 # build library\r
1249 if Target == 'libraries':\r
1250 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1251 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']\r
1252 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1253 return True\r
1254\r
1255 # build module\r
1256 if Target == 'modules':\r
1257 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1258 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']\r
1259 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1260 for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
1261 NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']\r
1262 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
a0a2cd1e 1263 self.CreateAsBuiltInf()\r
03af2753
HC
1264 return True\r
1265\r
1266 # cleanlib\r
1267 if Target == 'cleanlib':\r
1268 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1269 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))\r
1270 if os.path.exists(LibMakefile):\r
1271 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
1272 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1273 return True\r
1274\r
1275 # clean\r
1276 if Target == 'clean':\r
1277 for Mod in AutoGenObject.ModuleBuildDirectoryList:\r
1278 ModMakefile = os.path.normpath(os.path.join(Mod, makefile))\r
1279 if os.path.exists(ModMakefile):\r
1280 NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']\r
1281 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1282 for Lib in AutoGenObject.LibraryBuildDirectoryList:\r
1283 LibMakefile = os.path.normpath(os.path.join(Lib, makefile))\r
1284 if os.path.exists(LibMakefile):\r
1285 NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']\r
1286 LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)\r
1287 return True\r
1288\r
1289 # cleanall\r
1290 if Target == 'cleanall':\r
1291 try:\r
1292 #os.rmdir(AutoGenObject.BuildDir)\r
1293 RemoveDirectory(AutoGenObject.BuildDir, True)\r
5b0671c1 1294 except WindowsError as X:\r
03af2753
HC
1295 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1296 return True\r
1297\r
1298 ## Build a module or platform\r
1299 #\r
1300 # Create autogen code and makefile for a module or platform, and the launch\r
1301 # "make" command to build it\r
1302 #\r
1303 # @param Target The target of build command\r
1304 # @param Platform The platform file\r
1305 # @param Module The module file\r
1306 # @param BuildTarget The name of build target, one of "DEBUG", "RELEASE"\r
1307 # @param ToolChain The name of toolchain to build\r
1308 # @param Arch The arch of the module/platform\r
1309 # @param CreateDepModuleCodeFile Flag used to indicate creating code\r
1310 # for dependent modules/Libraries\r
1311 # @param CreateDepModuleMakeFile Flag used to indicate creating makefile\r
1312 # for dependent modules/Libraries\r
1313 #\r
1314 def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):\r
4231a819 1315 if AutoGenObject is None:\r
03af2753
HC
1316 return False\r
1317\r
1318 # skip file generation for cleanxxx targets, run and fds target\r
1319 if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1320 # for target which must generate AutoGen code and makefile\r
1321 if not self.SkipAutoGen or Target == 'genc':\r
1322 self.Progress.Start("Generating code")\r
1323 AutoGenObject.CreateCodeFile(CreateDepsCodeFile)\r
1324 self.Progress.Stop("done!")\r
1325 if Target == "genc":\r
1326 return True\r
1327\r
1328 if not self.SkipAutoGen or Target == 'genmake':\r
1329 self.Progress.Start("Generating makefile")\r
1330 AutoGenObject.CreateMakeFile(CreateDepsMakeFile)\r
1331 #AutoGenObject.CreateAsBuiltInf()\r
1332 self.Progress.Stop("done!")\r
1333 if Target == "genmake":\r
1334 return True\r
1335 else:\r
1336 # always recreate top/platform makefile when clean, just in case of inconsistency\r
1337 AutoGenObject.CreateCodeFile(False)\r
1338 AutoGenObject.CreateMakeFile(False)\r
1339\r
1340 if EdkLogger.GetLevel() == EdkLogger.QUIET:\r
1341 EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))\r
1342\r
1343 BuildCommand = AutoGenObject.BuildCommand\r
4231a819 1344 if BuildCommand is None or len(BuildCommand) == 0:\r
03af2753
HC
1345 EdkLogger.error("build", OPTION_MISSING,\r
1346 "No build command found for this module. "\r
1347 "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %\r
1348 (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),\r
1349 ExtraData=str(AutoGenObject))\r
1350\r
b0e23cf3
YL
1351 # build modules\r
1352 if BuildModule:\r
1353 if Target != 'fds':\r
1354 BuildCommand = BuildCommand + [Target]\r
1b8eca8b 1355 AutoGenObject.BuildTime = LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)\r
b0e23cf3
YL
1356 self.CreateAsBuiltInf()\r
1357 return True\r
1358\r
03af2753
HC
1359 # genfds\r
1360 if Target == 'fds':\r
370544d1
DL
1361 if GenFdsApi(AutoGenObject.GenFdsCommandDict, self.Db):\r
1362 EdkLogger.error("build", COMMAND_FAILURE)\r
03af2753
HC
1363 return True\r
1364\r
1365 # run\r
1366 if Target == 'run':\r
997a5d1b 1367 RunDir = os.path.normpath(os.path.join(AutoGenObject.BuildDir, GlobalData.gGlobalDefines['ARCH']))\r
03af2753
HC
1368 Command = '.\SecMain'\r
1369 os.chdir(RunDir)\r
1370 LaunchCommand(Command, RunDir)\r
1371 return True\r
1372\r
03af2753
HC
1373 # build library\r
1374 if Target == 'libraries':\r
1375 pass\r
1376\r
1377 # not build modules\r
1378\r
1379\r
1380 # cleanall\r
52302d4d
LG
1381 if Target == 'cleanall':\r
1382 try:\r
1383 #os.rmdir(AutoGenObject.BuildDir)\r
1384 RemoveDirectory(AutoGenObject.BuildDir, True)\r
5b0671c1 1385 except WindowsError as X:\r
52302d4d
LG
1386 EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))\r
1387 return True\r
1388\r
6780eef1 1389 ## Rebase module image and Get function address for the input module list.\r
52302d4d
LG
1390 #\r
1391 def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):\r
1392 if ModeIsSmm:\r
1393 AddrIsOffset = False\r
98120f5f 1394 for InfFile in ModuleList:\r
da92f276
LG
1395 sys.stdout.write (".")\r
1396 sys.stdout.flush()\r
52302d4d
LG
1397 ModuleInfo = ModuleList[InfFile]\r
1398 ModuleName = ModuleInfo.BaseName\r
f3decdc3
LG
1399 ModuleOutputImage = ModuleInfo.Image.FileName\r
1400 ModuleDebugImage = os.path.join(ModuleInfo.DebugDir, ModuleInfo.BaseName + '.efi')\r
52302d4d
LG
1401 ## for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1402 if not ModeIsSmm:\r
1403 BaseAddress = BaseAddress - ModuleInfo.Image.Size\r
1404 #\r
1405 # Update Image to new BaseAddress by GenFw tool\r
1406 #\r
f3decdc3 1407 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
47fea6af 1408 LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
52302d4d
LG
1409 else:\r
1410 #\r
1411 # Set new address to the section header only for SMM driver.\r
1412 #\r
f3decdc3 1413 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir)\r
47fea6af 1414 LaunchCommand(["GenFw", "--address", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir)\r
52302d4d
LG
1415 #\r
1416 # Collect funtion address from Map file\r
1417 #\r
f3decdc3 1418 ImageMapTable = ModuleOutputImage.replace('.efi', '.map')\r
52302d4d
LG
1419 FunctionList = []\r
1420 if os.path.exists(ImageMapTable):\r
1421 OrigImageBaseAddress = 0\r
47fea6af 1422 ImageMap = open(ImageMapTable, 'r')\r
52302d4d
LG
1423 for LinStr in ImageMap:\r
1424 if len (LinStr.strip()) == 0:\r
1425 continue\r
1426 #\r
1427 # Get the preferred address set on link time.\r
1428 #\r
1429 if LinStr.find ('Preferred load address is') != -1:\r
1430 StrList = LinStr.split()\r
1431 OrigImageBaseAddress = int (StrList[len(StrList) - 1], 16)\r
1432\r
1433 StrList = LinStr.split()\r
1434 if len (StrList) > 4:\r
47fea6af 1435 if StrList[3] == 'f' or StrList[3] == 'F':\r
52302d4d
LG
1436 Name = StrList[1]\r
1437 RelativeAddress = int (StrList[2], 16) - OrigImageBaseAddress\r
1438 FunctionList.append ((Name, RelativeAddress))\r
39879ef2 1439\r
52302d4d
LG
1440 ImageMap.close()\r
1441 #\r
1442 # Add general information.\r
1443 #\r
1444 if ModeIsSmm:\r
1445 MapBuffer.write('\n\n%s (Fixed SMRAM Offset, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1446 elif AddrIsOffset:\r
1447 MapBuffer.write('\n\n%s (Fixed Memory Offset, BaseAddress=-0x%010X, EntryPoint=-0x%010X)\n' % (ModuleName, 0 - BaseAddress, 0 - (BaseAddress + ModuleInfo.Image.EntryPoint)))\r
1448 else:\r
1449 MapBuffer.write('\n\n%s (Fixed Memory Address, BaseAddress=0x%010X, EntryPoint=0x%010X)\n' % (ModuleName, BaseAddress, BaseAddress + ModuleInfo.Image.EntryPoint))\r
1450 #\r
1451 # Add guid and general seciton section.\r
1452 #\r
1453 TextSectionAddress = 0\r
1454 DataSectionAddress = 0\r
1455 for SectionHeader in ModuleInfo.Image.SectionHeaderList:\r
1456 if SectionHeader[0] == '.text':\r
1457 TextSectionAddress = SectionHeader[1]\r
1458 elif SectionHeader[0] in ['.data', '.sdata']:\r
1459 DataSectionAddress = SectionHeader[1]\r
1460 if AddrIsOffset:\r
4afd3d04 1461 MapBuffer.write('(GUID=%s, .textbaseaddress=-0x%010X, .databaseaddress=-0x%010X)\n' % (ModuleInfo.Guid, 0 - (BaseAddress + TextSectionAddress), 0 - (BaseAddress + DataSectionAddress)))\r
52302d4d 1462 else:\r
4afd3d04 1463 MapBuffer.write('(GUID=%s, .textbaseaddress=0x%010X, .databaseaddress=0x%010X)\n' % (ModuleInfo.Guid, BaseAddress + TextSectionAddress, BaseAddress + DataSectionAddress))\r
f3decdc3
LG
1464 #\r
1465 # Add debug image full path.\r
1466 #\r
1467 MapBuffer.write('(IMAGE=%s)\n\n' % (ModuleDebugImage))\r
52302d4d
LG
1468 #\r
1469 # Add funtion address\r
1470 #\r
1471 for Function in FunctionList:\r
1472 if AddrIsOffset:\r
1473 MapBuffer.write(' -0x%010X %s\n' % (0 - (BaseAddress + Function[1]), Function[0]))\r
1474 else:\r
1475 MapBuffer.write(' 0x%010X %s\n' % (BaseAddress + Function[1], Function[0]))\r
1476 ImageMap.close()\r
1477\r
1478 #\r
1479 # for SMM module in SMRAM, the SMRAM will be allocated from base to top.\r
1480 #\r
1481 if ModeIsSmm:\r
1482 BaseAddress = BaseAddress + ModuleInfo.Image.Size\r
1483\r
1484 ## Collect MAP information of all FVs\r
1485 #\r
636f2be6 1486 def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):\r
0d2711a6 1487 if self.Fdf:\r
52302d4d 1488 # First get the XIP base address for FV map file.\r
636f2be6 1489 GuidPattern = re.compile("[-a-fA-F0-9]+")\r
f3decdc3 1490 GuidName = re.compile("\(GUID=[-a-fA-F0-9]+")\r
9eb87141 1491 for FvName in Wa.FdfProfile.FvDict:\r
52302d4d
LG
1492 FvMapBuffer = os.path.join(Wa.FvDir, FvName + '.Fv.map')\r
1493 if not os.path.exists(FvMapBuffer):\r
1494 continue\r
1be2ed90 1495 FvMap = open(FvMapBuffer, 'r')\r
52302d4d
LG
1496 #skip FV size information\r
1497 FvMap.readline()\r
1498 FvMap.readline()\r
1499 FvMap.readline()\r
1500 FvMap.readline()\r
636f2be6
LG
1501 for Line in FvMap:\r
1502 MatchGuid = GuidPattern.match(Line)\r
4231a819 1503 if MatchGuid is not None:\r
636f2be6
LG
1504 #\r
1505 # Replace GUID with module name\r
1506 #\r
1507 GuidString = MatchGuid.group()\r
1508 if GuidString.upper() in ModuleList:\r
1509 Line = Line.replace(GuidString, ModuleList[GuidString.upper()].Name)\r
caf74495 1510 MapBuffer.write(Line)\r
f3decdc3
LG
1511 #\r
1512 # Add the debug image full path.\r
1513 #\r
1514 MatchGuid = GuidName.match(Line)\r
4231a819 1515 if MatchGuid is not None:\r
f3decdc3
LG
1516 GuidString = MatchGuid.group().split("=")[1]\r
1517 if GuidString.upper() in ModuleList:\r
1518 MapBuffer.write('(IMAGE=%s)\n' % (os.path.join(ModuleList[GuidString.upper()].DebugDir, ModuleList[GuidString.upper()].Name + '.efi')))\r
1519\r
52302d4d
LG
1520 FvMap.close()\r
1521\r
1522 ## Collect MAP information of all modules\r
1523 #\r
1524 def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):\r
da92f276
LG
1525 sys.stdout.write ("Generate Load Module At Fix Address Map")\r
1526 sys.stdout.flush()\r
52302d4d
LG
1527 PatchEfiImageList = []\r
1528 PeiModuleList = {}\r
1529 BtModuleList = {}\r
1530 RtModuleList = {}\r
1531 SmmModuleList = {}\r
1532 PeiSize = 0\r
1533 BtSize = 0\r
1534 RtSize = 0\r
1535 # reserve 4K size in SMRAM to make SMM module address not from 0.\r
1536 SmmSize = 0x1000\r
636f2be6
LG
1537 for ModuleGuid in ModuleList:\r
1538 Module = ModuleList[ModuleGuid]\r
52302d4d 1539 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (Module.MetaFile, Module.Arch, Module.ToolChain, Module.BuildTarget)\r
4afd3d04 1540\r
52302d4d
LG
1541 OutputImageFile = ''\r
1542 for ResultFile in Module.CodaTargetList:\r
1543 if str(ResultFile.Target).endswith('.efi'):\r
1544 #\r
1545 # module list for PEI, DXE, RUNTIME and SMM\r
1546 #\r
1547 OutputImageFile = os.path.join(Module.OutputDir, Module.Name + '.efi')\r
1548 ImageClass = PeImageClass (OutputImageFile)\r
1549 if not ImageClass.IsValid:\r
1550 EdkLogger.error("build", FILE_PARSE_FAILURE, ExtraData=ImageClass.ErrorInfo)\r
f3decdc3 1551 ImageInfo = PeImageInfo(Module.Name, Module.Guid, Module.Arch, Module.OutputDir, Module.DebugDir, ImageClass)\r
0c60e60b 1552 if Module.ModuleType in [SUP_MODULE_PEI_CORE, SUP_MODULE_PEIM, EDK_COMPONENT_TYPE_COMBINED_PEIM_DRIVER, EDK_COMPONENT_TYPE_PIC_PEIM, EDK_COMPONENT_TYPE_RELOCATABLE_PEIM, SUP_MODULE_DXE_CORE]:\r
52302d4d
LG
1553 PeiModuleList[Module.MetaFile] = ImageInfo\r
1554 PeiSize += ImageInfo.Image.Size\r
0c60e60b 1555 elif Module.ModuleType in [EDK_COMPONENT_TYPE_BS_DRIVER, SUP_MODULE_DXE_DRIVER, SUP_MODULE_UEFI_DRIVER]:\r
52302d4d
LG
1556 BtModuleList[Module.MetaFile] = ImageInfo\r
1557 BtSize += ImageInfo.Image.Size\r
0c60e60b 1558 elif Module.ModuleType in [SUP_MODULE_DXE_RUNTIME_DRIVER, EDK_COMPONENT_TYPE_RT_DRIVER, SUP_MODULE_DXE_SAL_DRIVER, EDK_COMPONENT_TYPE_SAL_RT_DRIVER]:\r
52302d4d 1559 RtModuleList[Module.MetaFile] = ImageInfo\r
52302d4d 1560 RtSize += ImageInfo.Image.Size\r
8bb63e37 1561 elif Module.ModuleType in [SUP_MODULE_SMM_CORE, SUP_MODULE_DXE_SMM_DRIVER, SUP_MODULE_MM_STANDALONE, SUP_MODULE_MM_CORE_STANDALONE]:\r
52302d4d
LG
1562 SmmModuleList[Module.MetaFile] = ImageInfo\r
1563 SmmSize += ImageInfo.Image.Size\r
8bb63e37 1564 if Module.ModuleType == SUP_MODULE_DXE_SMM_DRIVER:\r
888d7f19 1565 PiSpecVersion = Module.Module.Specification.get('PI_SPECIFICATION_VERSION', '0x00000000')\r
52302d4d 1566 # for PI specification < PI1.1, DXE_SMM_DRIVER also runs as BOOT time driver.\r
da92f276 1567 if int(PiSpecVersion, 16) < 0x0001000A:\r
52302d4d
LG
1568 BtModuleList[Module.MetaFile] = ImageInfo\r
1569 BtSize += ImageInfo.Image.Size\r
1570 break\r
1571 #\r
1572 # EFI image is final target.\r
1573 # Check EFI image contains patchable FixAddress related PCDs.\r
1574 #\r
1575 if OutputImageFile != '':\r
1576 ModuleIsPatch = False\r
1577 for Pcd in Module.ModulePcdList:\r
eece4292 1578 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:\r
52302d4d
LG
1579 ModuleIsPatch = True\r
1580 break\r
1581 if not ModuleIsPatch:\r
1582 for Pcd in Module.LibraryPcdList:\r
eece4292 1583 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE and Pcd.TokenCName in TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET:\r
52302d4d
LG
1584 ModuleIsPatch = True\r
1585 break\r
4afd3d04 1586\r
52302d4d
LG
1587 if not ModuleIsPatch:\r
1588 continue\r
1589 #\r
1590 # Module includes the patchable load fix address PCDs.\r
4afd3d04 1591 # It will be fixed up later.\r
52302d4d
LG
1592 #\r
1593 PatchEfiImageList.append (OutputImageFile)\r
4afd3d04 1594\r
52302d4d
LG
1595 #\r
1596 # Get Top Memory address\r
1597 #\r
1598 ReservedRuntimeMemorySize = 0\r
1599 TopMemoryAddress = 0\r
1600 if self.LoadFixAddress == 0xFFFFFFFFFFFFFFFF:\r
1601 TopMemoryAddress = 0\r
1602 else:\r
1603 TopMemoryAddress = self.LoadFixAddress\r
1604 if TopMemoryAddress < RtSize + BtSize + PeiSize:\r
1605 EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS is too low to load driver")\r
52302d4d
LG
1606\r
1607 #\r
1608 # Patch FixAddress related PCDs into EFI image\r
1609 #\r
4afd3d04 1610 for EfiImage in PatchEfiImageList:\r
52302d4d
LG
1611 EfiImageMap = EfiImage.replace('.efi', '.map')\r
1612 if not os.path.exists(EfiImageMap):\r
1613 continue\r
1614 #\r
1615 # Get PCD offset in EFI image by GenPatchPcdTable function\r
1616 #\r
4afd3d04 1617 PcdTable = parsePcdInfoFromMapFile(EfiImageMap, EfiImage)\r
52302d4d
LG
1618 #\r
1619 # Patch real PCD value by PatchPcdValue tool\r
1620 #\r
1621 for PcdInfo in PcdTable:\r
1622 ReturnValue = 0\r
1623 if PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE:\r
1ccc4d89 1624 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE, str (PeiSize / 0x1000))\r
52302d4d 1625 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE:\r
1ccc4d89 1626 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE, str (BtSize / 0x1000))\r
52302d4d 1627 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE:\r
1ccc4d89 1628 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE, str (RtSize / 0x1000))\r
52302d4d 1629 elif PcdInfo[0] == TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE and len (SmmModuleList) > 0:\r
1ccc4d89 1630 ReturnValue, ErrorInfo = PatchBinaryFile (EfiImage, PcdInfo[1], TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE, str (SmmSize / 0x1000))\r
52302d4d
LG
1631 if ReturnValue != 0:\r
1632 EdkLogger.error("build", PARAMETER_INVALID, "Patch PCD value failed", ExtraData=ErrorInfo)\r
4afd3d04 1633\r
1ccc4d89
LG
1634 MapBuffer.write('PEI_CODE_PAGE_NUMBER = 0x%x\n' % (PeiSize / 0x1000))\r
1635 MapBuffer.write('BOOT_CODE_PAGE_NUMBER = 0x%x\n' % (BtSize / 0x1000))\r
1636 MapBuffer.write('RUNTIME_CODE_PAGE_NUMBER = 0x%x\n' % (RtSize / 0x1000))\r
52302d4d 1637 if len (SmmModuleList) > 0:\r
1ccc4d89 1638 MapBuffer.write('SMM_CODE_PAGE_NUMBER = 0x%x\n' % (SmmSize / 0x1000))\r
4afd3d04
LG
1639\r
1640 PeiBaseAddr = TopMemoryAddress - RtSize - BtSize\r
52302d4d 1641 BtBaseAddr = TopMemoryAddress - RtSize\r
4afd3d04 1642 RtBaseAddr = TopMemoryAddress - ReservedRuntimeMemorySize\r
52302d4d
LG
1643\r
1644 self._RebaseModule (MapBuffer, PeiBaseAddr, PeiModuleList, TopMemoryAddress == 0)\r
1645 self._RebaseModule (MapBuffer, BtBaseAddr, BtModuleList, TopMemoryAddress == 0)\r
1646 self._RebaseModule (MapBuffer, RtBaseAddr, RtModuleList, TopMemoryAddress == 0)\r
47fea6af 1647 self._RebaseModule (MapBuffer, 0x1000, SmmModuleList, AddrIsOffset=False, ModeIsSmm=True)\r
52302d4d 1648 MapBuffer.write('\n\n')\r
da92f276
LG
1649 sys.stdout.write ("\n")\r
1650 sys.stdout.flush()\r
4afd3d04 1651\r
52302d4d
LG
1652 ## Save platform Map file\r
1653 #\r
1654 def _SaveMapFile (self, MapBuffer, Wa):\r
1655 #\r
1656 # Map file path is got.\r
1657 #\r
1658 MapFilePath = os.path.join(Wa.BuildDir, Wa.Name + '.map')\r
1659 #\r
1660 # Save address map into MAP file.\r
1661 #\r
40d841f6 1662 SaveFileOnChange(MapFilePath, MapBuffer.getvalue(), False)\r
da92f276
LG
1663 MapBuffer.close()\r
1664 if self.LoadFixAddress != 0:\r
47fea6af 1665 sys.stdout.write ("\nLoad Module At Fix Address Map file can be found at %s\n" % (MapFilePath))\r
da92f276 1666 sys.stdout.flush()\r
52302d4d
LG
1667\r
1668 ## Build active platform for different build targets and different tool chains\r
1669 #\r
1670 def _BuildPlatform(self):\r
f0dc69e6 1671 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)\r
52302d4d 1672 for BuildTarget in self.BuildTargetList:\r
0d2711a6 1673 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
40b4e21d 1674 index = 0\r
52302d4d 1675 for ToolChain in self.ToolChainList:\r
0d2711a6
LG
1676 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
1677 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
40b4e21d
YZ
1678 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1679 index += 1\r
52302d4d
LG
1680 Wa = WorkspaceAutoGen(\r
1681 self.WorkspaceDir,\r
0d2711a6 1682 self.PlatformFile,\r
52302d4d
LG
1683 BuildTarget,\r
1684 ToolChain,\r
1685 self.ArchList,\r
1686 self.BuildDatabase,\r
1687 self.TargetTxt,\r
1688 self.ToolDef,\r
1689 self.Fdf,\r
1690 self.FdList,\r
1691 self.FvList,\r
4234283c 1692 self.CapList,\r
f3decdc3 1693 self.SkuId,\r
9508d0fa
LG
1694 self.UniFlag,\r
1695 self.Progress\r
52302d4d 1696 )\r
0d2711a6
LG
1697 self.Fdf = Wa.FdfFile\r
1698 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
52302d4d
LG
1699 self.BuildReport.AddPlatformReport(Wa)\r
1700 self.Progress.Stop("done!")\r
37de70b7
YZ
1701\r
1702 # Add ffs build to makefile\r
1703 CmdListDict = {}\r
1704 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
1705 CmdListDict = self._GenFfsCmd()\r
1706\r
03af2753
HC
1707 for Arch in Wa.ArchList:\r
1708 GlobalData.gGlobalDefines['ARCH'] = Arch\r
1709 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
a0a2cd1e
FB
1710 for Module in Pa.Platform.Modules:\r
1711 # Get ModuleAutoGen object to generate C code file and makefile\r
1712 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
4231a819 1713 if Ma is None:\r
a0a2cd1e
FB
1714 continue\r
1715 self.BuildModules.append(Ma)\r
37de70b7 1716 self._BuildPa(self.Target, Pa, FfsCommand=CmdListDict)\r
4afd3d04 1717\r
52302d4d 1718 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 1719 if self.Target in ["", "all", "fds"]:\r
0d2711a6
LG
1720 for Arch in Wa.ArchList:\r
1721 GlobalData.gGlobalDefines['ARCH'] = Arch\r
52302d4d
LG
1722 #\r
1723 # Check whether the set fix address is above 4G for 32bit image.\r
1724 #\r
1725 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
0d2711a6 1726 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
1727 #\r
1728 # Get Module List\r
1729 #\r
636f2be6 1730 ModuleList = {}\r
52302d4d
LG
1731 for Pa in Wa.AutoGenObjectList:\r
1732 for Ma in Pa.ModuleAutoGenList:\r
4231a819 1733 if Ma is None:\r
52302d4d
LG
1734 continue\r
1735 if not Ma.IsLibrary:\r
636f2be6 1736 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d 1737\r
1ccc4d89 1738 MapBuffer = BytesIO('')\r
636f2be6
LG
1739 if self.LoadFixAddress != 0:\r
1740 #\r
1741 # Rebase module to the preferred memory address before GenFds\r
1742 #\r
1743 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
0d2711a6 1744 if self.Fdf:\r
b0e23cf3
YL
1745 #\r
1746 # create FDS again for the updated EFI image\r
1747 #\r
1748 self._Build("fds", Wa)\r
52302d4d
LG
1749 #\r
1750 # Create MAP file for all platform FVs after GenFds.\r
1751 #\r
636f2be6 1752 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1753 #\r
1754 # Save MAP buffer into MAP file.\r
1755 #\r
1756 self._SaveMapFile (MapBuffer, Wa)\r
1757\r
1758 ## Build active module for different build targets, different tool chains and different archs\r
1759 #\r
1760 def _BuildModule(self):\r
1761 for BuildTarget in self.BuildTargetList:\r
0d2711a6 1762 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
40b4e21d 1763 index = 0\r
52302d4d 1764 for ToolChain in self.ToolChainList:\r
1b8eca8b 1765 WorkspaceAutoGenTime = time.time()\r
0d2711a6 1766 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
4afd3d04 1767 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
40b4e21d
YZ
1768 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1769 index += 1\r
52302d4d
LG
1770 #\r
1771 # module build needs platform build information, so get platform\r
1772 # AutoGen first\r
1773 #\r
1774 Wa = WorkspaceAutoGen(\r
1775 self.WorkspaceDir,\r
0d2711a6 1776 self.PlatformFile,\r
52302d4d
LG
1777 BuildTarget,\r
1778 ToolChain,\r
1779 self.ArchList,\r
1780 self.BuildDatabase,\r
1781 self.TargetTxt,\r
1782 self.ToolDef,\r
1783 self.Fdf,\r
1784 self.FdList,\r
1785 self.FvList,\r
4234283c 1786 self.CapList,\r
f3decdc3 1787 self.SkuId,\r
9508d0fa
LG
1788 self.UniFlag,\r
1789 self.Progress,\r
1790 self.ModuleFile\r
52302d4d 1791 )\r
0d2711a6
LG
1792 self.Fdf = Wa.FdfFile\r
1793 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
52302d4d 1794 Wa.CreateMakeFile(False)\r
37de70b7
YZ
1795 # Add ffs build to makefile\r
1796 CmdListDict = None\r
1797 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
1798 CmdListDict = self._GenFfsCmd()\r
52302d4d
LG
1799 self.Progress.Stop("done!")\r
1800 MaList = []\r
1b8eca8b
YZ
1801 ExitFlag = threading.Event()\r
1802 ExitFlag.clear()\r
1803 self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))\r
0d2711a6 1804 for Arch in Wa.ArchList:\r
1b8eca8b 1805 AutoGenStart = time.time()\r
0d2711a6 1806 GlobalData.gGlobalDefines['ARCH'] = Arch\r
16bad1fb
YZ
1807 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
1808 for Module in Pa.Platform.Modules:\r
fbe53845 1809 if self.ModuleFile.Dir == Module.Dir and self.ModuleFile.Name == Module.Name:\r
16bad1fb 1810 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
4231a819 1811 if Ma is None: continue\r
19bf8314
YZ
1812 MaList.append(Ma)\r
1813 if Ma.CanSkipbyHash():\r
1814 self.HashSkipModules.append(Ma)\r
1815 continue\r
119d8c42
YZ
1816 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'\r
1817 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1818 # for target which must generate AutoGen code and makefile\r
1819 if not self.SkipAutoGen or self.Target == 'genc':\r
cd498216 1820 self.Progress.Start("Generating code")\r
119d8c42 1821 Ma.CreateCodeFile(True)\r
cd498216
YZ
1822 self.Progress.Stop("done!")\r
1823 if self.Target == "genc":\r
1824 return True\r
119d8c42 1825 if not self.SkipAutoGen or self.Target == 'genmake':\r
cd498216 1826 self.Progress.Start("Generating makefile")\r
37de70b7
YZ
1827 if CmdListDict and self.Fdf and (Module.File, Arch) in CmdListDict:\r
1828 Ma.CreateMakeFile(True, CmdListDict[Module.File, Arch])\r
1829 del CmdListDict[Module.File, Arch]\r
1830 else:\r
1831 Ma.CreateMakeFile(True)\r
cd498216
YZ
1832 self.Progress.Stop("done!")\r
1833 if self.Target == "genmake":\r
1834 return True\r
16bad1fb 1835 self.BuildModules.append(Ma)\r
1b8eca8b
YZ
1836 self.AutoGenTime += int(round((time.time() - AutoGenStart)))\r
1837 MakeStart = time.time()\r
1838 for Ma in self.BuildModules:\r
1839 if not Ma.IsBinaryModule:\r
1840 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))\r
1841 # Break build if any build thread has error\r
1842 if BuildTask.HasError():\r
1843 # we need a full version of makefile for platform\r
1844 ExitFlag.set()\r
1845 BuildTask.WaitForComplete()\r
1846 Pa.CreateMakeFile(False)\r
1847 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1848 # Start task scheduler\r
1849 if not BuildTask.IsOnGoing():\r
1850 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
1851\r
1852 # in case there's an interruption. we need a full version of makefile for platform\r
1853 Pa.CreateMakeFile(False)\r
1854 if BuildTask.HasError():\r
1855 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1856 self.MakeTime += int(round((time.time() - MakeStart)))\r
1857\r
1858 MakeContiue = time.time()\r
1859 ExitFlag.set()\r
1860 BuildTask.WaitForComplete()\r
1861 self.CreateAsBuiltInf()\r
1862 self.MakeTime += int(round((time.time() - MakeContiue)))\r
1863 if BuildTask.HasError():\r
1864 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
d5d56f1b
LG
1865\r
1866 self.BuildReport.AddPlatformReport(Wa, MaList)\r
52302d4d
LG
1867 if MaList == []:\r
1868 EdkLogger.error(\r
1869 'build',\r
1870 BUILD_ERROR,\r
1871 "Module for [%s] is not a component of active platform."\\r
1872 " Please make sure that the ARCH and inf file path are"\\r
47fea6af 1873 " given in the same as in [%s]" % \\r
0d2711a6 1874 (', '.join(Wa.ArchList), self.PlatformFile),\r
52302d4d
LG
1875 ExtraData=self.ModuleFile\r
1876 )\r
1877 # Create MAP file when Load Fix Address is enabled.\r
0d2711a6
LG
1878 if self.Target == "fds" and self.Fdf:\r
1879 for Arch in Wa.ArchList:\r
52302d4d
LG
1880 #\r
1881 # Check whether the set fix address is above 4G for 32bit image.\r
1882 #\r
1883 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
1884 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
1885 #\r
1886 # Get Module List\r
1887 #\r
636f2be6 1888 ModuleList = {}\r
52302d4d
LG
1889 for Pa in Wa.AutoGenObjectList:\r
1890 for Ma in Pa.ModuleAutoGenList:\r
4231a819 1891 if Ma is None:\r
52302d4d
LG
1892 continue\r
1893 if not Ma.IsLibrary:\r
636f2be6 1894 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d 1895\r
1ccc4d89 1896 MapBuffer = BytesIO('')\r
636f2be6
LG
1897 if self.LoadFixAddress != 0:\r
1898 #\r
1899 # Rebase module to the preferred memory address before GenFds\r
1900 #\r
1901 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
b0e23cf3
YL
1902 #\r
1903 # create FDS again for the updated EFI image\r
1904 #\r
1b8eca8b 1905 GenFdsStart = time.time()\r
b0e23cf3 1906 self._Build("fds", Wa)\r
1b8eca8b 1907 self.GenFdsTime += int(round((time.time() - GenFdsStart)))\r
52302d4d
LG
1908 #\r
1909 # Create MAP file for all platform FVs after GenFds.\r
1910 #\r
636f2be6 1911 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
52302d4d
LG
1912 #\r
1913 # Save MAP buffer into MAP file.\r
1914 #\r
1915 self._SaveMapFile (MapBuffer, Wa)\r
1916\r
37de70b7 1917 def _GenFfsCmd(self):\r
f7496d71 1918 # convert dictionary of Cmd:(Inf,Arch)\r
9eb87141
CJ
1919 # to a new dictionary of (Inf,Arch):Cmd,Cmd,Cmd...\r
1920 CmdSetDict = defaultdict(set)\r
37de70b7
YZ
1921 GenFfsDict = GenFds.GenFfsMakefile('', GlobalData.gFdfParser, self, self.ArchList, GlobalData)\r
1922 for Cmd in GenFfsDict:\r
1923 tmpInf, tmpArch = GenFfsDict[Cmd]\r
9eb87141
CJ
1924 CmdSetDict[tmpInf, tmpArch].add(Cmd)\r
1925 return CmdSetDict\r
37de70b7 1926\r
52302d4d
LG
1927 ## Build a platform in multi-thread mode\r
1928 #\r
1929 def _MultiThreadBuildPlatform(self):\r
f0dc69e6 1930 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)\r
52302d4d 1931 for BuildTarget in self.BuildTargetList:\r
0d2711a6 1932 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
40b4e21d 1933 index = 0\r
52302d4d 1934 for ToolChain in self.ToolChainList:\r
1b8eca8b 1935 WorkspaceAutoGenTime = time.time()\r
0d2711a6 1936 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
4afd3d04 1937 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
40b4e21d
YZ
1938 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
1939 index += 1\r
52302d4d
LG
1940 Wa = WorkspaceAutoGen(\r
1941 self.WorkspaceDir,\r
0d2711a6 1942 self.PlatformFile,\r
52302d4d
LG
1943 BuildTarget,\r
1944 ToolChain,\r
1945 self.ArchList,\r
1946 self.BuildDatabase,\r
1947 self.TargetTxt,\r
1948 self.ToolDef,\r
1949 self.Fdf,\r
1950 self.FdList,\r
1951 self.FvList,\r
4234283c 1952 self.CapList,\r
f3decdc3 1953 self.SkuId,\r
9508d0fa
LG
1954 self.UniFlag,\r
1955 self.Progress\r
52302d4d 1956 )\r
0d2711a6
LG
1957 self.Fdf = Wa.FdfFile\r
1958 self.LoadFixAddress = Wa.Platform.LoadFixAddress\r
52302d4d
LG
1959 self.BuildReport.AddPlatformReport(Wa)\r
1960 Wa.CreateMakeFile(False)\r
1961\r
37de70b7
YZ
1962 # Add ffs build to makefile\r
1963 CmdListDict = None\r
1964 if GlobalData.gEnableGenfdsMultiThread and self.Fdf:\r
1965 CmdListDict = self._GenFfsCmd()\r
1966\r
52302d4d
LG
1967 # multi-thread exit flag\r
1968 ExitFlag = threading.Event()\r
1969 ExitFlag.clear()\r
1b8eca8b 1970 self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))\r
0d2711a6 1971 for Arch in Wa.ArchList:\r
1b8eca8b 1972 AutoGenStart = time.time()\r
0d2711a6 1973 GlobalData.gGlobalDefines['ARCH'] = Arch\r
52302d4d 1974 Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)\r
4231a819 1975 if Pa is None:\r
52302d4d 1976 continue\r
a0a2cd1e
FB
1977 ModuleList = []\r
1978 for Inf in Pa.Platform.Modules:\r
1979 ModuleList.append(Inf)\r
1980 # Add the INF only list in FDF\r
4231a819 1981 if GlobalData.gFdfParser is not None:\r
a0a2cd1e
FB
1982 for InfName in GlobalData.gFdfParser.Profile.InfList:\r
1983 Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch)\r
1984 if Inf in Pa.Platform.Modules:\r
1985 continue\r
1986 ModuleList.append(Inf)\r
1987 for Module in ModuleList:\r
52302d4d
LG
1988 # Get ModuleAutoGen object to generate C code file and makefile\r
1989 Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile)\r
f7496d71 1990\r
4231a819 1991 if Ma is None:\r
52302d4d 1992 continue\r
36d083ef 1993 if Ma.CanSkipbyHash():\r
83397f95 1994 self.HashSkipModules.append(Ma)\r
36d083ef
YZ
1995 continue\r
1996\r
52302d4d
LG
1997 # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'\r
1998 if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:\r
1999 # for target which must generate AutoGen code and makefile\r
2000 if not self.SkipAutoGen or self.Target == 'genc':\r
2001 Ma.CreateCodeFile(True)\r
2002 if self.Target == "genc":\r
2003 continue\r
2004\r
2005 if not self.SkipAutoGen or self.Target == 'genmake':\r
37de70b7
YZ
2006 if CmdListDict and self.Fdf and (Module.File, Arch) in CmdListDict:\r
2007 Ma.CreateMakeFile(True, CmdListDict[Module.File, Arch])\r
2008 del CmdListDict[Module.File, Arch]\r
2009 else:\r
2010 Ma.CreateMakeFile(True)\r
52302d4d
LG
2011 if self.Target == "genmake":\r
2012 continue\r
a0a2cd1e 2013 self.BuildModules.append(Ma)\r
e8a47801 2014 self.Progress.Stop("done!")\r
1b8eca8b
YZ
2015 self.AutoGenTime += int(round((time.time() - AutoGenStart)))\r
2016 MakeStart = time.time()\r
a0a2cd1e 2017 for Ma in self.BuildModules:\r
52302d4d 2018 # Generate build task for the module\r
a0a2cd1e
FB
2019 if not Ma.IsBinaryModule:\r
2020 Bt = BuildTask.New(ModuleMakeUnit(Ma, self.Target))\r
52302d4d
LG
2021 # Break build if any build thread has error\r
2022 if BuildTask.HasError():\r
2023 # we need a full version of makefile for platform\r
2024 ExitFlag.set()\r
2025 BuildTask.WaitForComplete()\r
2026 Pa.CreateMakeFile(False)\r
2027 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
2028 # Start task scheduler\r
2029 if not BuildTask.IsOnGoing():\r
2030 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
2031\r
2032 # in case there's an interruption. we need a full version of makefile for platform\r
2033 Pa.CreateMakeFile(False)\r
2034 if BuildTask.HasError():\r
2035 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1b8eca8b 2036 self.MakeTime += int(round((time.time() - MakeStart)))\r
52302d4d 2037\r
1b8eca8b 2038 MakeContiue = time.time()\r
2f818ed0 2039\r
64b2609f 2040 #\r
52302d4d
LG
2041 #\r
2042 # All modules have been put in build tasks queue. Tell task scheduler\r
2043 # to exit if all tasks are completed\r
2044 #\r
2045 ExitFlag.set()\r
2046 BuildTask.WaitForComplete()\r
a0a2cd1e 2047 self.CreateAsBuiltInf()\r
1b8eca8b 2048 self.MakeTime += int(round((time.time() - MakeContiue)))\r
52302d4d
LG
2049 #\r
2050 # Check for build error, and raise exception if one\r
2051 # has been signaled.\r
2052 #\r
2053 if BuildTask.HasError():\r
2054 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
2055\r
2056 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 2057 if self.Target in ["", "all", "fds"]:\r
0d2711a6 2058 for Arch in Wa.ArchList:\r
52302d4d
LG
2059 #\r
2060 # Check whether the set fix address is above 4G for 32bit image.\r
2061 #\r
2062 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
2063 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
2064 #\r
2065 # Get Module List\r
2066 #\r
636f2be6 2067 ModuleList = {}\r
52302d4d
LG
2068 for Pa in Wa.AutoGenObjectList:\r
2069 for Ma in Pa.ModuleAutoGenList:\r
4231a819 2070 if Ma is None:\r
52302d4d
LG
2071 continue\r
2072 if not Ma.IsLibrary:\r
636f2be6 2073 ModuleList[Ma.Guid.upper()] = Ma\r
52302d4d
LG
2074 #\r
2075 # Rebase module to the preferred memory address before GenFds\r
2076 #\r
1ccc4d89 2077 MapBuffer = BytesIO('')\r
636f2be6
LG
2078 if self.LoadFixAddress != 0:\r
2079 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
52302d4d 2080\r
0d2711a6 2081 if self.Fdf:\r
f3decdc3
LG
2082 #\r
2083 # Generate FD image if there's a FDF file found\r
2084 #\r
1b8eca8b 2085 GenFdsStart = time.time()\r
370544d1
DL
2086 if GenFdsApi(Wa.GenFdsCommandDict, self.Db):\r
2087 EdkLogger.error("build", COMMAND_FAILURE)\r
03af2753 2088\r
52302d4d
LG
2089 #\r
2090 # Create MAP file for all platform FVs after GenFds.\r
2091 #\r
636f2be6 2092 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
1b8eca8b 2093 self.GenFdsTime += int(round((time.time() - GenFdsStart)))\r
52302d4d
LG
2094 #\r
2095 # Save MAP buffer into MAP file.\r
2096 #\r
2097 self._SaveMapFile(MapBuffer, Wa)\r
2098\r
2099 ## Generate GuidedSectionTools.txt in the FV directories.\r
2100 #\r
2101 def CreateGuidedSectionToolsFile(self):\r
0d2711a6
LG
2102 for BuildTarget in self.BuildTargetList:\r
2103 for ToolChain in self.ToolChainList:\r
2104 Wa = WorkspaceAutoGen(\r
2105 self.WorkspaceDir,\r
2106 self.PlatformFile,\r
2107 BuildTarget,\r
2108 ToolChain,\r
2109 self.ArchList,\r
2110 self.BuildDatabase,\r
2111 self.TargetTxt,\r
2112 self.ToolDef,\r
2113 self.Fdf,\r
2114 self.FdList,\r
2115 self.FvList,\r
2116 self.CapList,\r
2117 self.SkuId,\r
2118 self.UniFlag\r
2119 )\r
2120 FvDir = Wa.FvDir\r
2121 if not os.path.exists(FvDir):\r
2122 continue\r
2123\r
4afd3d04 2124 for Arch in self.ArchList:\r
52302d4d
LG
2125 # Build up the list of supported architectures for this build\r
2126 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)\r
4afd3d04 2127\r
52302d4d
LG
2128 # Look through the tool definitions for GUIDed tools\r
2129 guidAttribs = []\r
1ccc4d89 2130 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.iteritems():\r
52302d4d
LG
2131 if attrib.upper().endswith('_GUID'):\r
2132 split = attrib.split('_')\r
2133 thisPrefix = '_'.join(split[0:3]) + '_'\r
2134 if thisPrefix == prefix:\r
2135 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]\r
2136 guid = guid.lower()\r
2137 toolName = split[3]\r
2138 path = '_'.join(split[0:4]) + '_PATH'\r
2139 path = self.ToolDef.ToolsDefTxtDictionary[path]\r
2140 path = self.GetFullPathOfTool(path)\r
2141 guidAttribs.append((guid, toolName, path))\r
4afd3d04 2142\r
52302d4d
LG
2143 # Write out GuidedSecTools.txt\r
2144 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')\r
2145 toolsFile = open(toolsFile, 'wt')\r
2146 for guidedSectionTool in guidAttribs:\r
72443dd2 2147 print(' '.join(guidedSectionTool), file=toolsFile)\r
52302d4d
LG
2148 toolsFile.close()\r
2149\r
2150 ## Returns the full path of the tool.\r
2151 #\r
2152 def GetFullPathOfTool (self, tool):\r
2153 if os.path.exists(tool):\r
2154 return os.path.realpath(tool)\r
2155 else:\r
2156 # We need to search for the tool using the\r
2157 # PATH environment variable.\r
2158 for dirInPath in os.environ['PATH'].split(os.pathsep):\r
2159 foundPath = os.path.join(dirInPath, tool)\r
2160 if os.path.exists(foundPath):\r
2161 return os.path.realpath(foundPath)\r
2162\r
2163 # If the tool was not found in the path then we just return\r
2164 # the input tool.\r
2165 return tool\r
2166\r
2167 ## Launch the module or platform build\r
2168 #\r
2169 def Launch(self):\r
0d2711a6 2170 if not self.ModuleFile:\r
52302d4d
LG
2171 if not self.SpawnMode or self.Target not in ["", "all"]:\r
2172 self.SpawnMode = False\r
2173 self._BuildPlatform()\r
2174 else:\r
2175 self._MultiThreadBuildPlatform()\r
2176 self.CreateGuidedSectionToolsFile()\r
2177 else:\r
2178 self.SpawnMode = False\r
2179 self._BuildModule()\r
2180\r
bcbdc755 2181 if self.Target == 'cleanall':\r
bcbdc755
YL
2182 RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)\r
2183\r
a0a2cd1e
FB
2184 def CreateAsBuiltInf(self):\r
2185 for Module in self.BuildModules:\r
2186 Module.CreateAsBuiltInf()\r
83397f95
YZ
2187 for Module in self.HashSkipModules:\r
2188 Module.CreateAsBuiltInf(True)\r
a0a2cd1e 2189 self.BuildModules = []\r
83397f95 2190 self.HashSkipModules = []\r
52302d4d
LG
2191 ## Do some clean-up works when error occurred\r
2192 def Relinquish(self):\r
2193 OldLogLevel = EdkLogger.GetLevel()\r
2194 EdkLogger.SetLevel(EdkLogger.ERROR)\r
2195 #self.DumpBuildData()\r
2196 Utils.Progressor.Abort()\r
2197 if self.SpawnMode == True:\r
2198 BuildTask.Abort()\r
2199 EdkLogger.SetLevel(OldLogLevel)\r
2200\r
2201 def DumpBuildData(self):\r
97fa0ee9 2202 CacheDirectory = os.path.dirname(GlobalData.gDatabasePath)\r
52302d4d 2203 Utils.CreateDirectory(CacheDirectory)\r
b2985672
CJ
2204 Utils._DataDump(Utils.gFileTimeStampCache, os.path.join(CacheDirectory, "gFileTimeStampCache"))\r
2205 Utils._DataDump(Utils.gDependencyDatabase, os.path.join(CacheDirectory, "gDependencyDatabase"))\r
52302d4d
LG
2206\r
2207 def RestoreBuildData(self):\r
97fa0ee9 2208 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gFileTimeStampCache")\r
52302d4d 2209 if Utils.gFileTimeStampCache == {} and os.path.isfile(FilePath):\r
b2985672 2210 Utils.gFileTimeStampCache = Utils._DataRestore(FilePath)\r
4231a819 2211 if Utils.gFileTimeStampCache is None:\r
52302d4d
LG
2212 Utils.gFileTimeStampCache = {}\r
2213\r
97fa0ee9 2214 FilePath = os.path.join(os.path.dirname(GlobalData.gDatabasePath), "gDependencyDatabase")\r
52302d4d 2215 if Utils.gDependencyDatabase == {} and os.path.isfile(FilePath):\r
b2985672 2216 Utils.gDependencyDatabase = Utils._DataRestore(FilePath)\r
4231a819 2217 if Utils.gDependencyDatabase is None:\r
52302d4d
LG
2218 Utils.gDependencyDatabase = {}\r
2219\r
2220def ParseDefines(DefineList=[]):\r
2221 DefineDict = {}\r
4231a819 2222 if DefineList is not None:\r
52302d4d
LG
2223 for Define in DefineList:\r
2224 DefineTokenList = Define.split("=", 1)\r
0d2711a6
LG
2225 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):\r
2226 EdkLogger.error('build', FORMAT_INVALID,\r
2227 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",\r
2228 ExtraData=DefineTokenList[0])\r
4afd3d04 2229\r
52302d4d 2230 if len(DefineTokenList) == 1:\r
0d2711a6 2231 DefineDict[DefineTokenList[0]] = "TRUE"\r
52302d4d
LG
2232 else:\r
2233 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()\r
2234 return DefineDict\r
2235\r
2236gParamCheck = []\r
2237def SingleCheckCallback(option, opt_str, value, parser):\r
2238 if option not in gParamCheck:\r
2239 setattr(parser.values, option.dest, value)\r
2240 gParamCheck.append(option)\r
2241 else:\r
2242 parser.error("Option %s only allows one instance in command line!" % option)\r
2243\r
1b8eca8b
YZ
2244def LogBuildTime(Time):\r
2245 if Time:\r
2246 TimeDurStr = ''\r
2247 TimeDur = time.gmtime(Time)\r
2248 if TimeDur.tm_yday > 1:\r
2249 TimeDurStr = time.strftime("%H:%M:%S", TimeDur) + ", %d day(s)" % (TimeDur.tm_yday - 1)\r
2250 else:\r
2251 TimeDurStr = time.strftime("%H:%M:%S", TimeDur)\r
2252 return TimeDurStr\r
2253 else:\r
2254 return None\r
2255\r
52302d4d
LG
2256## Parse command line options\r
2257#\r
2258# Using standard Python module optparse to parse command line option of this tool.\r
2259#\r
2260# @retval Opt A optparse.Values object containing the parsed options\r
2261# @retval Args Target of build command\r
2262#\r
2263def MyOptionParser():\r
47fea6af 2264 Parser = OptionParser(description=__copyright__, version=__version__, prog="build.exe", usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]")\r
39879ef2
FB
2265 Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32', 'X64', 'EBC', 'ARM', 'AARCH64'], dest="TargetArch",\r
2266 help="ARCHS is one of list: IA32, X64, ARM, AARCH64 or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.")\r
52302d4d
LG
2267 Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback,\r
2268 help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.")\r
2269 Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback,\r
2270 help="Build the module specified by the INF file name argument.")\r
64b2609f
LG
2271 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.",\r
2272 action="append")\r
52302d4d
LG
2273 Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain",\r
2274 help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.")\r
2275 Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback,\r
2276 help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.")\r
2277\r
2278 Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback,\r
2052cb67
YZ
2279 help="Build the platform using multi-threaded compiler. The value overrides target.txt's MAX_CONCURRENT_THREAD_NUMBER. When value is set to 0, tool automatically detect number of "\\r
2280 "processor threads, set value to 1 means disable multi-thread build, and set value to more than 1 means user specify the threads number to build.")\r
52302d4d
LG
2281\r
2282 Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback,\r
2283 help="The name of the FDF file to use, which overrides the setting in the DSC file.")\r
2284 Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[],\r
2285 help="The name of FD to be generated. The name must be from [FD] section in FDF file.")\r
2286 Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[],\r
2287 help="The name of FV to be generated. The name must be from [FV] section in FDF file.")\r
4234283c
LG
2288 Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[],\r
2289 help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.")\r
52302d4d
LG
2290 Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.")\r
2291 Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.")\r
2292\r
0d2711a6 2293 Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.")\r
52302d4d
LG
2294\r
2295 Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.")\r
2296 Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.")\r
2297\r
2298 Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode",\r
2299 help="Make use of silent mode of (n)make.")\r
2300 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
2301 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\\r
2302 "including library instances selected, final dependency expression, "\\r
2303 "and warning messages, etc.")\r
2304 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
2305 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
2306\r
2307 Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")\r
ccaa7754 2308 Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD', 'LIBRARY', 'FLASH', 'DEPEX', 'BUILD_FLAGS', 'FIXED_ADDRESS', 'HASH', 'EXECUTION_ORDER'], dest="ReportType", default=[],\r
eca5be7a 2309 help="Flags that control the type of build report to generate. Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, HASH, EXECUTION_ORDER]. "\\r
302860bf 2310 "To specify more than one flag, repeat this option on the command line and the default flag set is [PCD, LIBRARY, FLASH, DEPEX, HASH, BUILD_FLAGS, FIXED_ADDRESS]")\r
f3decdc3
LG
2311 Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",\r
2312 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
2313 "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\\r
2314 "will override the setting in [BuildOptions] section of platform DSC.")\r
0d2711a6 2315 Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism")\r
97fa0ee9
YL
2316 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")\r
2317 Parser.add_option("--check-usage", action="store_true", dest="CheckUsage", default=False, help="Check usage content of entries listed in INF file.")\r
fae62ff2 2318 Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")\r
d7cd3356 2319 Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")\r
725cdb8f 2320 Parser.add_option("-l", "--cmd-len", action="store", type="int", dest="CommandLength", help="Specify the maximum line length of build command. Default is 4096.")\r
36d083ef
YZ
2321 Parser.add_option("--hash", action="store_true", dest="UseHashCache", default=False, help="Enable hash-based caching during build process.")\r
2322 Parser.add_option("--binary-destination", action="store", type="string", dest="BinCacheDest", help="Generate a cache of binary files in the specified directory.")\r
2323 Parser.add_option("--binary-source", action="store", type="string", dest="BinCacheSource", help="Consume a cache of binary files from the specified directory.")\r
37de70b7 2324 Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=False, help="Enable GenFds multi thread to generate ffs file.")\r
47fea6af 2325 (Opt, Args) = Parser.parse_args()\r
52302d4d
LG
2326 return (Opt, Args)\r
2327\r
2328## Tool entrance method\r
2329#\r
2330# This method mainly dispatch specific methods per the command line options.\r
2331# If no error found, return zero value so the caller of this tool can know\r
2332# if it's executed successfully or not.\r
2333#\r
2334# @retval 0 Tool was successful\r
2335# @retval 1 Tool failed\r
2336#\r
2337def Main():\r
2338 StartTime = time.time()\r
2339\r
2340 # Initialize log system\r
2341 EdkLogger.Initialize()\r
f0dc69e6 2342 GlobalData.gCommand = sys.argv[1:]\r
52302d4d
LG
2343 #\r
2344 # Parse the options and args\r
2345 #\r
2346 (Option, Target) = MyOptionParser()\r
2347 GlobalData.gOptions = Option\r
2348 GlobalData.gCaseInsensitive = Option.CaseInsensitive\r
2349\r
2350 # Set log level\r
4231a819 2351 if Option.verbose is not None:\r
52302d4d 2352 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
4231a819 2353 elif Option.quiet is not None:\r
52302d4d 2354 EdkLogger.SetLevel(EdkLogger.QUIET)\r
4231a819 2355 elif Option.debug is not None:\r
52302d4d
LG
2356 EdkLogger.SetLevel(Option.debug + 1)\r
2357 else:\r
2358 EdkLogger.SetLevel(EdkLogger.INFO)\r
2359\r
4231a819 2360 if Option.LogFile is not None:\r
52302d4d
LG
2361 EdkLogger.SetLogFile(Option.LogFile)\r
2362\r
2363 if Option.WarningAsError == True:\r
2364 EdkLogger.SetWarningAsError()\r
2365\r
2366 if platform.platform().find("Windows") >= 0:\r
2367 GlobalData.gIsWindows = True\r
2368 else:\r
2369 GlobalData.gIsWindows = False\r
2370\r
6780eef1
LG
2371 EdkLogger.quiet("Build environment: %s" % platform.platform())\r
2372 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));\r
52302d4d
LG
2373 ReturnCode = 0\r
2374 MyBuild = None\r
09ae0f11 2375 BuildError = True\r
52302d4d
LG
2376 try:\r
2377 if len(Target) == 0:\r
2378 Target = "all"\r
2379 elif len(Target) >= 2:\r
2380 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",\r
47fea6af 2381 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))\r
52302d4d
LG
2382 else:\r
2383 Target = Target[0].lower()\r
2384\r
2385 if Target not in gSupportedTarget:\r
2386 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,\r
47fea6af 2387 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))\r
52302d4d 2388\r
52302d4d
LG
2389 #\r
2390 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH\r
2391 #\r
2392 CheckEnvVariable()\r
0d2711a6
LG
2393 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))\r
2394\r
52302d4d
LG
2395 Workspace = os.getenv("WORKSPACE")\r
2396 #\r
2397 # Get files real name in workspace dir\r
2398 #\r
2399 GlobalData.gAllFiles = Utils.DirCache(Workspace)\r
2400\r
2401 WorkingDirectory = os.getcwd()\r
2402 if not Option.ModuleFile:\r
2403 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))\r
2404 FileNum = len(FileList)\r
2405 if FileNum >= 2:\r
2406 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),\r
2407 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")\r
2408 elif FileNum == 1:\r
2409 Option.ModuleFile = NormFile(FileList[0], Workspace)\r
2410\r
2411 if Option.ModuleFile:\r
2412 if os.path.isabs (Option.ModuleFile):\r
2413 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:\r
2414 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)\r
2415 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)\r
2416 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)\r
2417 if ErrorCode != 0:\r
2418 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2419\r
4231a819 2420 if Option.PlatformFile is not None:\r
52302d4d
LG
2421 if os.path.isabs (Option.PlatformFile):\r
2422 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:\r
2423 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)\r
2424 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)\r
52302d4d 2425\r
4231a819 2426 if Option.FdfFile is not None:\r
52302d4d
LG
2427 if os.path.isabs (Option.FdfFile):\r
2428 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:\r
2429 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)\r
2430 Option.FdfFile = PathClass(Option.FdfFile, Workspace)\r
2431 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)\r
2432 if ErrorCode != 0:\r
2433 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2434\r
4231a819 2435 if Option.Flag is not None and Option.Flag not in ['-c', '-s']:\r
f3decdc3
LG
2436 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")\r
2437\r
0d2711a6 2438 MyBuild = Build(Target, Workspace, Option)\r
64b2609f 2439 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)\r
f0dc69e6
YZ
2440 if not (MyBuild.LaunchPrebuildFlag and os.path.exists(MyBuild.PlatformBuildPath)):\r
2441 MyBuild.Launch()\r
2f818ed0 2442\r
52302d4d 2443 #MyBuild.DumpBuildData()\r
09ae0f11
YL
2444 #\r
2445 # All job done, no error found and no exception raised\r
2446 #\r
2447 BuildError = False\r
5b0671c1 2448 except FatalError as X:\r
4231a819 2449 if MyBuild is not None:\r
52302d4d
LG
2450 # for multi-thread build exits safely\r
2451 MyBuild.Relinquish()\r
4231a819 2452 if Option is not None and Option.debug is not None:\r
52302d4d
LG
2453 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2454 ReturnCode = X.args[0]\r
5b0671c1 2455 except Warning as X:\r
52302d4d 2456 # error from Fdf parser\r
4231a819 2457 if MyBuild is not None:\r
52302d4d
LG
2458 # for multi-thread build exits safely\r
2459 MyBuild.Relinquish()\r
4231a819 2460 if Option is not None and Option.debug is not None:\r
52302d4d
LG
2461 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2462 else:\r
47fea6af 2463 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)\r
52302d4d
LG
2464 ReturnCode = FORMAT_INVALID\r
2465 except KeyboardInterrupt:\r
2466 ReturnCode = ABORT_ERROR\r
4231a819 2467 if Option is not None and Option.debug is not None:\r
52302d4d
LG
2468 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2469 except:\r
4231a819 2470 if MyBuild is not None:\r
52302d4d
LG
2471 # for multi-thread build exits safely\r
2472 MyBuild.Relinquish()\r
2473\r
2474 # try to get the meta-file from the object causing exception\r
2475 Tb = sys.exc_info()[-1]\r
2476 MetaFile = GlobalData.gProcessingFile\r
4231a819 2477 while Tb is not None:\r
52302d4d
LG
2478 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):\r
2479 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile\r
2480 Tb = Tb.tb_next\r
2481 EdkLogger.error(\r
2482 "\nbuild",\r
2483 CODE_ERROR,\r
2484 "Unknown fatal error when processing [%s]" % MetaFile,\r
3a0f8bde 2485 ExtraData="\n(Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!)\n",\r
52302d4d
LG
2486 RaiseError=False\r
2487 )\r
d0acc87a 2488 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
52302d4d
LG
2489 ReturnCode = CODE_ERROR\r
2490 finally:\r
2491 Utils.Progressor.Abort()\r
97fa0ee9 2492 Utils.ClearDuplicatedInf()\r
52302d4d
LG
2493\r
2494 if ReturnCode == 0:\r
f0dc69e6 2495 try:\r
91048b0d 2496 MyBuild.LaunchPostbuild()\r
f0dc69e6
YZ
2497 Conclusion = "Done"\r
2498 except:\r
2499 Conclusion = "Failed"\r
52302d4d
LG
2500 elif ReturnCode == ABORT_ERROR:\r
2501 Conclusion = "Aborted"\r
2502 else:\r
2503 Conclusion = "Failed"\r
2504 FinishTime = time.time()\r
4234283c
LG
2505 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))\r
2506 BuildDurationStr = ""\r
2507 if BuildDuration.tm_yday > 1:\r
47fea6af 2508 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)" % (BuildDuration.tm_yday - 1)\r
4234283c
LG
2509 else:\r
2510 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)\r
4231a819 2511 if MyBuild is not None:\r
09ae0f11 2512 if not BuildError:\r
1b8eca8b 2513 MyBuild.BuildReport.GenerateReport(BuildDurationStr, LogBuildTime(MyBuild.AutoGenTime), LogBuildTime(MyBuild.MakeTime), LogBuildTime(MyBuild.GenFdsTime))\r
2f818ed0 2514\r
52302d4d 2515 EdkLogger.SetLevel(EdkLogger.QUIET)\r
6780eef1
LG
2516 EdkLogger.quiet("\n- %s -" % Conclusion)\r
2517 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))\r
4234283c 2518 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)\r
52302d4d
LG
2519 return ReturnCode\r
2520\r
2521if __name__ == '__main__':\r
2522 r = Main()\r
2523 ## 0-127 is a safe return range, and 1 is a standard default error\r
2524 if r < 0 or r > 127: r = 1\r
2525 sys.exit(r)\r
2526\r