]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/build/build.py
DynamicTablesPkg: Add SSDT Serial port for DBG2
[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
bfe36cb4 1220 mqueue.put((None,None,None,None,None,None,None))\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
bfe36cb4 2177 mqueue.put((None,None,None,None,None,None,None))\r
fc8b8dea 2178 autogen_rt, errorcode = self.StartAutoGen(mqueue, Pa.DataPipe, self.SkipAutoGen, PcdMaList, cqueue)\r
373298ca
FB
2179\r
2180 if not autogen_rt:\r
2181 self.AutoGenMgr.TerminateWorkers()\r
2182 self.AutoGenMgr.join(1)\r
2183 raise FatalError(errorcode)\r
fc8b8dea
SS
2184\r
2185 if GlobalData.gUseHashCache:\r
2186 for item in GlobalData.gModuleAllCacheStatus:\r
2187 (MetaFilePath, Arch, CacheStr, Status) = item\r
2188 Ma = ModuleAutoGen(Wa, PathClass(MetaFilePath, Wa), BuildTarget,\\r
2189 ToolChain, Arch, self.PlatformFile,Pa.DataPipe)\r
2190 if CacheStr == "PreMakeCache" and Status == False:\r
2191 self.PreMakeCacheMiss.add(Ma)\r
2192 if CacheStr == "PreMakeCache" and Status == True:\r
2193 self.PreMakeCacheHit.add(Ma)\r
2194 GlobalData.gModuleCacheHit.add(Ma)\r
2195 if CacheStr == "MakeCache" and Status == False:\r
2196 self.MakeCacheMiss.add(Ma)\r
2197 if CacheStr == "MakeCache" and Status == True:\r
2198 self.MakeCacheHit.add(Ma)\r
2199 GlobalData.gModuleCacheHit.add(Ma)\r
373298ca
FB
2200 self.AutoGenTime += int(round((time.time() - AutoGenStart)))\r
2201 AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt")\r
2202 with open(AutoGenIdFile,"w") as fw:\r
2203 fw.write("Arch=%s\n" % "|".join((Wa.ArchList)))\r
2204 fw.write("BuildDir=%s\n" % Wa.BuildDir)\r
2205 fw.write("PlatformGuid=%s\n" % str(Wa.AutoGenObjectList[0].Guid))\r
fc8b8dea
SS
2206\r
2207 if GlobalData.gBinCacheSource:\r
2208 BuildModules.extend(self.MakeCacheMiss)\r
2209 elif GlobalData.gUseHashCache and not GlobalData.gBinCacheDest:\r
2210 BuildModules.extend(self.PreMakeCacheMiss)\r
2211 else:\r
2212 BuildModules.extend(self.AllDrivers)\r
2213\r
373298ca
FB
2214 self.Progress.Stop("done!")\r
2215 return Wa, BuildModules\r
2216\r
52302d4d 2217 def _MultiThreadBuildPlatform(self):\r
f0dc69e6 2218 SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)\r
52302d4d 2219 for BuildTarget in self.BuildTargetList:\r
0d2711a6 2220 GlobalData.gGlobalDefines['TARGET'] = BuildTarget\r
40b4e21d 2221 index = 0\r
52302d4d 2222 for ToolChain in self.ToolChainList:\r
78fb6b0e 2223 resetFdsGlobalVariable()\r
0d2711a6 2224 GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain\r
4afd3d04 2225 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain\r
40b4e21d
YZ
2226 GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]\r
2227 index += 1\r
52302d4d
LG
2228 ExitFlag = threading.Event()\r
2229 ExitFlag.clear()\r
373298ca
FB
2230 if self.SkipAutoGen:\r
2231 Wa = self.VerifyAutoGenFiles()\r
2232 if Wa is None:\r
5a9db858 2233 self.SkipAutoGen = False\r
373298ca 2234 Wa, self.BuildModules = self.PerformAutoGen(BuildTarget,ToolChain)\r
0e7e7a26 2235 else:\r
373298ca
FB
2236 GlobalData.gAutoGenPhase = True\r
2237 self.BuildModules = self.SetupMakeSetting(Wa)\r
2238 else:\r
2239 Wa, self.BuildModules = self.PerformAutoGen(BuildTarget,ToolChain)\r
2240 Pa = Wa.AutoGenObjectList[0]\r
2241 GlobalData.gAutoGenPhase = False\r
0e7e7a26
SS
2242\r
2243 if GlobalData.gBinCacheSource:\r
fc8b8dea
SS
2244 EdkLogger.quiet("[cache Summary]: Total module num: %s" % len(self.AllModules))\r
2245 EdkLogger.quiet("[cache Summary]: PreMakecache miss num: %s " % len(self.PreMakeCacheMiss))\r
2246 EdkLogger.quiet("[cache Summary]: Makecache miss num: %s " % len(self.MakeCacheMiss))\r
0e7e7a26 2247\r
673d09a2 2248 for Arch in Wa.ArchList:\r
1b8eca8b 2249 MakeStart = time.time()\r
0e7e7a26 2250 for Ma in set(self.BuildModules):\r
52302d4d 2251 # Generate build task for the module\r
a0a2cd1e 2252 if not Ma.IsBinaryModule:\r
673d09a2 2253 Bt = BuildTask.New(ModuleMakeUnit(Ma, Pa.BuildCommand,self.Target))\r
52302d4d
LG
2254 # Break build if any build thread has error\r
2255 if BuildTask.HasError():\r
2256 # we need a full version of makefile for platform\r
2257 ExitFlag.set()\r
2258 BuildTask.WaitForComplete()\r
2259 Pa.CreateMakeFile(False)\r
2260 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
2261 # Start task scheduler\r
2262 if not BuildTask.IsOnGoing():\r
2263 BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)\r
2264\r
2265 # in case there's an interruption. we need a full version of makefile for platform\r
373298ca 2266\r
52302d4d
LG
2267 if BuildTask.HasError():\r
2268 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
1b8eca8b 2269 self.MakeTime += int(round((time.time() - MakeStart)))\r
52302d4d 2270\r
1b8eca8b 2271 MakeContiue = time.time()\r
64b2609f 2272 #\r
52302d4d
LG
2273 #\r
2274 # All modules have been put in build tasks queue. Tell task scheduler\r
2275 # to exit if all tasks are completed\r
2276 #\r
2277 ExitFlag.set()\r
2278 BuildTask.WaitForComplete()\r
a0a2cd1e 2279 self.CreateAsBuiltInf()\r
b8ac0b7f 2280 if GlobalData.gBinCacheDest:\r
fc8b8dea
SS
2281 self.GenDestCache()\r
2282 elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:\r
2283 # Only for --hash\r
2284 # Update PreMakeCacheChain files\r
2285 self.GenLocalPreMakeCache()\r
e0f8261a
FZ
2286 #\r
2287 # Get Module List\r
2288 #\r
2289 ModuleList = {ma.Guid.upper(): ma for ma in self.BuildModules}\r
b8ac0b7f 2290 self.BuildModules = []\r
1b8eca8b 2291 self.MakeTime += int(round((time.time() - MakeContiue)))\r
52302d4d
LG
2292 #\r
2293 # Check for build error, and raise exception if one\r
2294 # has been signaled.\r
2295 #\r
2296 if BuildTask.HasError():\r
2297 EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)\r
2298\r
2299 # Create MAP file when Load Fix Address is enabled.\r
636f2be6 2300 if self.Target in ["", "all", "fds"]:\r
0d2711a6 2301 for Arch in Wa.ArchList:\r
52302d4d
LG
2302 #\r
2303 # Check whether the set fix address is above 4G for 32bit image.\r
2304 #\r
2305 if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:\r
2306 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 2307\r
52302d4d
LG
2308 #\r
2309 # Rebase module to the preferred memory address before GenFds\r
2310 #\r
d943b0c3 2311 MapBuffer = []\r
636f2be6
LG
2312 if self.LoadFixAddress != 0:\r
2313 self._CollectModuleMapBuffer(MapBuffer, ModuleList)\r
52302d4d 2314\r
0d2711a6 2315 if self.Fdf:\r
f3decdc3
LG
2316 #\r
2317 # Generate FD image if there's a FDF file found\r
2318 #\r
1b8eca8b 2319 GenFdsStart = time.time()\r
370544d1
DL
2320 if GenFdsApi(Wa.GenFdsCommandDict, self.Db):\r
2321 EdkLogger.error("build", COMMAND_FAILURE)\r
3a3a3af4
FZ
2322 Threshold = self.GetFreeSizeThreshold()\r
2323 if Threshold:\r
2324 self.CheckFreeSizeThreshold(Threshold, Wa.FvDir)\r
03af2753 2325\r
52302d4d
LG
2326 #\r
2327 # Create MAP file for all platform FVs after GenFds.\r
2328 #\r
636f2be6 2329 self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)\r
1b8eca8b 2330 self.GenFdsTime += int(round((time.time() - GenFdsStart)))\r
52302d4d
LG
2331 #\r
2332 # Save MAP buffer into MAP file.\r
2333 #\r
2334 self._SaveMapFile(MapBuffer, Wa)\r
373298ca 2335 self.CreateGuidedSectionToolsFile(Wa)\r
3a3a3af4
FZ
2336\r
2337 ## GetFreeSizeThreshold()\r
2338 #\r
2339 # @retval int Threshold value\r
2340 #\r
2341 def GetFreeSizeThreshold(self):\r
2342 Threshold = None\r
2343 Threshold_Str = GlobalData.gCommandLineDefines.get('FV_SPARE_SPACE_THRESHOLD')\r
2344 if Threshold_Str:\r
2345 try:\r
2346 if Threshold_Str.lower().startswith('0x'):\r
2347 Threshold = int(Threshold_Str, 16)\r
2348 else:\r
2349 Threshold = int(Threshold_Str)\r
2350 except:\r
2351 EdkLogger.warn("build", 'incorrect value for FV_SPARE_SPACE_THRESHOLD %s.Only decimal or hex format is allowed.' % Threshold_Str)\r
2352 return Threshold\r
2353\r
2354 def CheckFreeSizeThreshold(self, Threshold=None, FvDir=None):\r
2355 if not isinstance(Threshold, int):\r
2356 return\r
2357 if not isinstance(FvDir, str) or not FvDir:\r
2358 return\r
2359 FdfParserObject = GlobalData.gFdfParser\r
2360 FvRegionNameList = [FvName for FvName in FdfParserObject.Profile.FvDict if FdfParserObject.Profile.FvDict[FvName].FvRegionInFD]\r
2361 for FvName in FdfParserObject.Profile.FvDict:\r
2362 if FvName in FvRegionNameList:\r
2363 FvSpaceInfoFileName = os.path.join(FvDir, FvName.upper() + '.Fv.map')\r
2364 if os.path.exists(FvSpaceInfoFileName):\r
2365 FileLinesList = getlines(FvSpaceInfoFileName)\r
2366 for Line in FileLinesList:\r
2367 NameValue = Line.split('=')\r
2368 if len(NameValue) == 2 and NameValue[0].strip() == 'EFI_FV_SPACE_SIZE':\r
2369 FreeSizeValue = int(NameValue[1].strip(), 0)\r
2370 if FreeSizeValue < Threshold:\r
2371 EdkLogger.error("build", FV_FREESIZE_ERROR,\r
2372 '%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
2373 FvName, FreeSizeValue, Threshold))\r
2374 break\r
2375\r
52302d4d
LG
2376 ## Generate GuidedSectionTools.txt in the FV directories.\r
2377 #\r
373298ca 2378 def CreateGuidedSectionToolsFile(self,Wa):\r
0d2711a6
LG
2379 for BuildTarget in self.BuildTargetList:\r
2380 for ToolChain in self.ToolChainList:\r
0d2711a6
LG
2381 FvDir = Wa.FvDir\r
2382 if not os.path.exists(FvDir):\r
2383 continue\r
2384\r
4afd3d04 2385 for Arch in self.ArchList:\r
52302d4d
LG
2386 # Build up the list of supported architectures for this build\r
2387 prefix = '%s_%s_%s_' % (BuildTarget, ToolChain, Arch)\r
4afd3d04 2388\r
52302d4d
LG
2389 # Look through the tool definitions for GUIDed tools\r
2390 guidAttribs = []\r
3a041437 2391 for (attrib, value) in self.ToolDef.ToolsDefTxtDictionary.items():\r
52302d4d
LG
2392 if attrib.upper().endswith('_GUID'):\r
2393 split = attrib.split('_')\r
2394 thisPrefix = '_'.join(split[0:3]) + '_'\r
2395 if thisPrefix == prefix:\r
2396 guid = self.ToolDef.ToolsDefTxtDictionary[attrib]\r
2397 guid = guid.lower()\r
2398 toolName = split[3]\r
2399 path = '_'.join(split[0:4]) + '_PATH'\r
2400 path = self.ToolDef.ToolsDefTxtDictionary[path]\r
8c944c93 2401 path = self.GetRealPathOfTool(path)\r
52302d4d 2402 guidAttribs.append((guid, toolName, path))\r
4afd3d04 2403\r
52302d4d
LG
2404 # Write out GuidedSecTools.txt\r
2405 toolsFile = os.path.join(FvDir, 'GuidedSectionTools.txt')\r
2406 toolsFile = open(toolsFile, 'wt')\r
2407 for guidedSectionTool in guidAttribs:\r
72443dd2 2408 print(' '.join(guidedSectionTool), file=toolsFile)\r
52302d4d
LG
2409 toolsFile.close()\r
2410\r
8c944c93 2411 ## Returns the real path of the tool.\r
52302d4d 2412 #\r
8c944c93 2413 def GetRealPathOfTool (self, tool):\r
52302d4d
LG
2414 if os.path.exists(tool):\r
2415 return os.path.realpath(tool)\r
52302d4d
LG
2416 return tool\r
2417\r
2418 ## Launch the module or platform build\r
2419 #\r
2420 def Launch(self):\r
fc8b8dea
SS
2421 self.AllDrivers = set()\r
2422 self.AllModules = set()\r
2423 self.PreMakeCacheMiss = set()\r
2424 self.PreMakeCacheHit = set()\r
2425 self.MakeCacheMiss = set()\r
2426 self.MakeCacheHit = set()\r
0d2711a6 2427 if not self.ModuleFile:\r
52302d4d
LG
2428 if not self.SpawnMode or self.Target not in ["", "all"]:\r
2429 self.SpawnMode = False\r
2430 self._BuildPlatform()\r
2431 else:\r
2432 self._MultiThreadBuildPlatform()\r
52302d4d
LG
2433 else:\r
2434 self.SpawnMode = False\r
2435 self._BuildModule()\r
2436\r
bcbdc755 2437 if self.Target == 'cleanall':\r
bcbdc755
YL
2438 RemoveDirectory(os.path.dirname(GlobalData.gDatabasePath), True)\r
2439\r
a0a2cd1e 2440 def CreateAsBuiltInf(self):\r
b8ac0b7f
BF
2441 for Module in self.BuildModules:\r
2442 Module.CreateAsBuiltInf()\r
2443\r
fc8b8dea
SS
2444 def GenDestCache(self):\r
2445 for Module in self.AllModules:\r
2446 Module.GenPreMakefileHashList()\r
2447 Module.GenMakefileHashList()\r
b8ac0b7f 2448 Module.CopyModuleToCache()\r
fc8b8dea
SS
2449\r
2450 def GenLocalPreMakeCache(self):\r
2451 for Module in self.PreMakeCacheMiss:\r
2452 Module.GenPreMakefileHashList()\r
2453\r
52302d4d
LG
2454 ## Do some clean-up works when error occurred\r
2455 def Relinquish(self):\r
2456 OldLogLevel = EdkLogger.GetLevel()\r
2457 EdkLogger.SetLevel(EdkLogger.ERROR)\r
52302d4d
LG
2458 Utils.Progressor.Abort()\r
2459 if self.SpawnMode == True:\r
2460 BuildTask.Abort()\r
2461 EdkLogger.SetLevel(OldLogLevel)\r
2462\r
52302d4d
LG
2463def ParseDefines(DefineList=[]):\r
2464 DefineDict = {}\r
4231a819 2465 if DefineList is not None:\r
52302d4d
LG
2466 for Define in DefineList:\r
2467 DefineTokenList = Define.split("=", 1)\r
0d2711a6
LG
2468 if not GlobalData.gMacroNamePattern.match(DefineTokenList[0]):\r
2469 EdkLogger.error('build', FORMAT_INVALID,\r
2470 "The macro name must be in the pattern [A-Z][A-Z0-9_]*",\r
2471 ExtraData=DefineTokenList[0])\r
4afd3d04 2472\r
52302d4d 2473 if len(DefineTokenList) == 1:\r
0d2711a6 2474 DefineDict[DefineTokenList[0]] = "TRUE"\r
52302d4d
LG
2475 else:\r
2476 DefineDict[DefineTokenList[0]] = DefineTokenList[1].strip()\r
2477 return DefineDict\r
2478\r
c60fb00f 2479\r
52302d4d 2480\r
1b8eca8b
YZ
2481def LogBuildTime(Time):\r
2482 if Time:\r
2483 TimeDurStr = ''\r
2484 TimeDur = time.gmtime(Time)\r
2485 if TimeDur.tm_yday > 1:\r
2486 TimeDurStr = time.strftime("%H:%M:%S", TimeDur) + ", %d day(s)" % (TimeDur.tm_yday - 1)\r
2487 else:\r
2488 TimeDurStr = time.strftime("%H:%M:%S", TimeDur)\r
2489 return TimeDurStr\r
2490 else:\r
2491 return None\r
1a624dd7 2492def ThreadNum():\r
4465cd12
FZ
2493 OptionParser = MyOptionParser()\r
2494 if not OptionParser.BuildOption and not OptionParser.BuildTarget:\r
2495 OptionParser.GetOption()\r
2496 BuildOption, BuildTarget = OptionParser.BuildOption, OptionParser.BuildTarget\r
1a624dd7 2497 ThreadNumber = BuildOption.ThreadNumber\r
4465cd12 2498 GlobalData.gCmdConfDir = BuildOption.ConfDirectory\r
1a624dd7 2499 if ThreadNumber is None:\r
4465cd12
FZ
2500 TargetObj = TargetTxtDict()\r
2501 ThreadNumber = TargetObj.Target.TargetTxtDictionary[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER]\r
1a624dd7
FB
2502 if ThreadNumber == '':\r
2503 ThreadNumber = 0\r
2504 else:\r
2505 ThreadNumber = int(ThreadNumber, 0)\r
1b8eca8b 2506\r
1a624dd7
FB
2507 if ThreadNumber == 0:\r
2508 try:\r
2509 ThreadNumber = multiprocessing.cpu_count()\r
2510 except (ImportError, NotImplementedError):\r
2511 ThreadNumber = 1\r
2512 return ThreadNumber\r
52302d4d
LG
2513## Tool entrance method\r
2514#\r
2515# This method mainly dispatch specific methods per the command line options.\r
2516# If no error found, return zero value so the caller of this tool can know\r
2517# if it's executed successfully or not.\r
2518#\r
2519# @retval 0 Tool was successful\r
2520# @retval 1 Tool failed\r
2521#\r
1a624dd7 2522LogQMaxSize = ThreadNum() * 10\r
52302d4d
LG
2523def Main():\r
2524 StartTime = time.time()\r
2525\r
636ed13a
FB
2526 #\r
2527 # Create a log Queue\r
2528 #\r
1a624dd7 2529 LogQ = mp.Queue(LogQMaxSize)\r
52302d4d 2530 # Initialize log system\r
636ed13a 2531 EdkLogger.LogClientInitialize(LogQ)\r
f0dc69e6 2532 GlobalData.gCommand = sys.argv[1:]\r
52302d4d
LG
2533 #\r
2534 # Parse the options and args\r
2535 #\r
4465cd12
FZ
2536 OptionParser = MyOptionParser()\r
2537 if not OptionParser.BuildOption and not OptionParser.BuildTarget:\r
2538 OptionParser.GetOption()\r
2539 Option, Target = OptionParser.BuildOption, OptionParser.BuildTarget\r
52302d4d
LG
2540 GlobalData.gOptions = Option\r
2541 GlobalData.gCaseInsensitive = Option.CaseInsensitive\r
2542\r
2543 # Set log level\r
636ed13a 2544 LogLevel = EdkLogger.INFO\r
4231a819 2545 if Option.verbose is not None:\r
52302d4d 2546 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
636ed13a 2547 LogLevel = EdkLogger.VERBOSE\r
4231a819 2548 elif Option.quiet is not None:\r
52302d4d 2549 EdkLogger.SetLevel(EdkLogger.QUIET)\r
636ed13a 2550 LogLevel = EdkLogger.QUIET\r
4231a819 2551 elif Option.debug is not None:\r
52302d4d 2552 EdkLogger.SetLevel(Option.debug + 1)\r
636ed13a 2553 LogLevel = Option.debug + 1\r
52302d4d
LG
2554 else:\r
2555 EdkLogger.SetLevel(EdkLogger.INFO)\r
2556\r
52302d4d
LG
2557 if Option.WarningAsError == True:\r
2558 EdkLogger.SetWarningAsError()\r
636ed13a
FB
2559 Log_Agent = LogAgent(LogQ,LogLevel,Option.LogFile)\r
2560 Log_Agent.start()\r
52302d4d
LG
2561\r
2562 if platform.platform().find("Windows") >= 0:\r
2563 GlobalData.gIsWindows = True\r
2564 else:\r
2565 GlobalData.gIsWindows = False\r
2566\r
6780eef1
LG
2567 EdkLogger.quiet("Build environment: %s" % platform.platform())\r
2568 EdkLogger.quiet(time.strftime("Build start time: %H:%M:%S, %b.%d %Y\n", time.localtime()));\r
52302d4d
LG
2569 ReturnCode = 0\r
2570 MyBuild = None\r
09ae0f11 2571 BuildError = True\r
52302d4d
LG
2572 try:\r
2573 if len(Target) == 0:\r
2574 Target = "all"\r
2575 elif len(Target) >= 2:\r
2576 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "More than one targets are not supported.",\r
47fea6af 2577 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))\r
52302d4d
LG
2578 else:\r
2579 Target = Target[0].lower()\r
2580\r
2581 if Target not in gSupportedTarget:\r
2582 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "Not supported target [%s]." % Target,\r
47fea6af 2583 ExtraData="Please select one of: %s" % (' '.join(gSupportedTarget)))\r
52302d4d 2584\r
52302d4d
LG
2585 #\r
2586 # Check environment variable: EDK_TOOLS_PATH, WORKSPACE, PATH\r
2587 #\r
2588 CheckEnvVariable()\r
0d2711a6
LG
2589 GlobalData.gCommandLineDefines.update(ParseDefines(Option.Macros))\r
2590\r
52302d4d
LG
2591 Workspace = os.getenv("WORKSPACE")\r
2592 #\r
2593 # Get files real name in workspace dir\r
2594 #\r
2595 GlobalData.gAllFiles = Utils.DirCache(Workspace)\r
2596\r
2597 WorkingDirectory = os.getcwd()\r
2598 if not Option.ModuleFile:\r
2599 FileList = glob.glob(os.path.normpath(os.path.join(WorkingDirectory, '*.inf')))\r
2600 FileNum = len(FileList)\r
2601 if FileNum >= 2:\r
2602 EdkLogger.error("build", OPTION_NOT_SUPPORTED, "There are %d INF files in %s." % (FileNum, WorkingDirectory),\r
2603 ExtraData="Please use '-m <INF_FILE_PATH>' switch to choose one.")\r
2604 elif FileNum == 1:\r
2605 Option.ModuleFile = NormFile(FileList[0], Workspace)\r
2606\r
2607 if Option.ModuleFile:\r
2608 if os.path.isabs (Option.ModuleFile):\r
2609 if os.path.normcase (os.path.normpath(Option.ModuleFile)).find (Workspace) == 0:\r
2610 Option.ModuleFile = NormFile(os.path.normpath(Option.ModuleFile), Workspace)\r
2611 Option.ModuleFile = PathClass(Option.ModuleFile, Workspace)\r
2612 ErrorCode, ErrorInfo = Option.ModuleFile.Validate(".inf", False)\r
2613 if ErrorCode != 0:\r
2614 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2615\r
4231a819 2616 if Option.PlatformFile is not None:\r
52302d4d
LG
2617 if os.path.isabs (Option.PlatformFile):\r
2618 if os.path.normcase (os.path.normpath(Option.PlatformFile)).find (Workspace) == 0:\r
2619 Option.PlatformFile = NormFile(os.path.normpath(Option.PlatformFile), Workspace)\r
2620 Option.PlatformFile = PathClass(Option.PlatformFile, Workspace)\r
52302d4d 2621\r
4231a819 2622 if Option.FdfFile is not None:\r
52302d4d
LG
2623 if os.path.isabs (Option.FdfFile):\r
2624 if os.path.normcase (os.path.normpath(Option.FdfFile)).find (Workspace) == 0:\r
2625 Option.FdfFile = NormFile(os.path.normpath(Option.FdfFile), Workspace)\r
2626 Option.FdfFile = PathClass(Option.FdfFile, Workspace)\r
2627 ErrorCode, ErrorInfo = Option.FdfFile.Validate(".fdf", False)\r
2628 if ErrorCode != 0:\r
2629 EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo)\r
2630\r
4231a819 2631 if Option.Flag is not None and Option.Flag not in ['-c', '-s']:\r
f3decdc3
LG
2632 EdkLogger.error("build", OPTION_VALUE_INVALID, "UNI flag must be one of -c or -s")\r
2633\r
636ed13a 2634 MyBuild = Build(Target, Workspace, Option,LogQ)\r
64b2609f 2635 GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)\r
f0dc69e6
YZ
2636 if not (MyBuild.LaunchPrebuildFlag and os.path.exists(MyBuild.PlatformBuildPath)):\r
2637 MyBuild.Launch()\r
2f818ed0 2638\r
09ae0f11
YL
2639 #\r
2640 # All job done, no error found and no exception raised\r
2641 #\r
2642 BuildError = False\r
5b0671c1 2643 except FatalError as X:\r
4231a819 2644 if MyBuild is not None:\r
52302d4d
LG
2645 # for multi-thread build exits safely\r
2646 MyBuild.Relinquish()\r
4231a819 2647 if Option is not None and Option.debug is not None:\r
52302d4d
LG
2648 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2649 ReturnCode = X.args[0]\r
5b0671c1 2650 except Warning as X:\r
52302d4d 2651 # error from Fdf parser\r
4231a819 2652 if MyBuild is not None:\r
52302d4d
LG
2653 # for multi-thread build exits safely\r
2654 MyBuild.Relinquish()\r
4231a819 2655 if Option is not None and Option.debug is not None:\r
52302d4d
LG
2656 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2657 else:\r
47fea6af 2658 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)\r
52302d4d
LG
2659 ReturnCode = FORMAT_INVALID\r
2660 except KeyboardInterrupt:\r
673d09a2
FB
2661 if MyBuild is not None:\r
2662\r
2663 # for multi-thread build exits safely\r
2664 MyBuild.Relinquish()\r
52302d4d 2665 ReturnCode = ABORT_ERROR\r
4231a819 2666 if Option is not None and Option.debug is not None:\r
52302d4d
LG
2667 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
2668 except:\r
4231a819 2669 if MyBuild is not None:\r
52302d4d
LG
2670 # for multi-thread build exits safely\r
2671 MyBuild.Relinquish()\r
2672\r
2673 # try to get the meta-file from the object causing exception\r
2674 Tb = sys.exc_info()[-1]\r
2675 MetaFile = GlobalData.gProcessingFile\r
4231a819 2676 while Tb is not None:\r
52302d4d
LG
2677 if 'self' in Tb.tb_frame.f_locals and hasattr(Tb.tb_frame.f_locals['self'], 'MetaFile'):\r
2678 MetaFile = Tb.tb_frame.f_locals['self'].MetaFile\r
2679 Tb = Tb.tb_next\r
2680 EdkLogger.error(\r
2681 "\nbuild",\r
2682 CODE_ERROR,\r
2683 "Unknown fatal error when processing [%s]" % MetaFile,\r
c1387446 2684 ExtraData="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR,\r
52302d4d
LG
2685 RaiseError=False\r
2686 )\r
d0acc87a 2687 EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
52302d4d
LG
2688 ReturnCode = CODE_ERROR\r
2689 finally:\r
2690 Utils.Progressor.Abort()\r
97fa0ee9 2691 Utils.ClearDuplicatedInf()\r
52302d4d
LG
2692\r
2693 if ReturnCode == 0:\r
f0dc69e6 2694 try:\r
91048b0d 2695 MyBuild.LaunchPostbuild()\r
f0dc69e6
YZ
2696 Conclusion = "Done"\r
2697 except:\r
2698 Conclusion = "Failed"\r
52302d4d
LG
2699 elif ReturnCode == ABORT_ERROR:\r
2700 Conclusion = "Aborted"\r
2701 else:\r
2702 Conclusion = "Failed"\r
2703 FinishTime = time.time()\r
4234283c
LG
2704 BuildDuration = time.gmtime(int(round(FinishTime - StartTime)))\r
2705 BuildDurationStr = ""\r
2706 if BuildDuration.tm_yday > 1:\r
47fea6af 2707 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration) + ", %d day(s)" % (BuildDuration.tm_yday - 1)\r
4234283c
LG
2708 else:\r
2709 BuildDurationStr = time.strftime("%H:%M:%S", BuildDuration)\r
4231a819 2710 if MyBuild is not None:\r
09ae0f11 2711 if not BuildError:\r
1b8eca8b 2712 MyBuild.BuildReport.GenerateReport(BuildDurationStr, LogBuildTime(MyBuild.AutoGenTime), LogBuildTime(MyBuild.MakeTime), LogBuildTime(MyBuild.GenFdsTime))\r
2f818ed0 2713\r
52302d4d 2714 EdkLogger.SetLevel(EdkLogger.QUIET)\r
6780eef1
LG
2715 EdkLogger.quiet("\n- %s -" % Conclusion)\r
2716 EdkLogger.quiet(time.strftime("Build end time: %H:%M:%S, %b.%d %Y", time.localtime()))\r
4234283c 2717 EdkLogger.quiet("Build total time: %s\n" % BuildDurationStr)\r
636ed13a
FB
2718 Log_Agent.kill()\r
2719 Log_Agent.join()\r
52302d4d
LG
2720 return ReturnCode\r
2721\r
2722if __name__ == '__main__':\r
673d09a2
FB
2723 try:\r
2724 mp.set_start_method('spawn')\r
2725 except:\r
2726 pass\r
52302d4d
LG
2727 r = Main()\r
2728 ## 0-127 is a safe return range, and 1 is a standard default error\r
2729 if r < 0 or r > 127: r = 1\r
2730 sys.exit(r)\r