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